Просмотр сообщений

В этом разделе можно просмотреть все сообщения, сделанные этим пользователем.


Темы - mim

Страницы: [1] 2
1
В FlowCodeAVR при использовании компонента Delay, а также любого компонента, который в своей работе может использовать процедуры delay_us() (это как правило реализация различных программных интерфейсов обмена, например вопрос Пост 14938.) могут возникать ошибки из-за неправильного расчета пауз (задержек) delay. Ошибки в паузах могут достигать 50 процентов.

Стандартная библиотека AVR-GCC включает каталог «util» в котором размешены файлы   и  .
Матриксы переписали файл и поместили его в свой каталог «MX_util», на который и ссылаются в своих программах.
Файл оставили там же и без изменений.
При написании файла Матриксы допустили ошибку.

Вот как Матриксы описали паузу delay_us();
void delay_us(uint8_t __us)
{
   _delay_loop_2(US_COUNT2 * __us);
}

Процедура delay_us() вызывает другую процедуру _delay_loop_2().
Обратите внимание на заголовок описания паузы, которая была в стандартной библиотеке void _delay_us(double __us). Переменная __us определена как double (Float), перемнная с плавающей точкой. Рассматривать внутренности этой функции мы не будем.
Мы обратим внимание на внутренности функции от Матриксов.
   _delay_loop_2(US_COUNT2 * __us);
Переменная __us определена как беззнаковая восьми битная uint8_t, то есть типа char.
Константа US_COUNT2 получает значение равное F_CPU / 4000000.

В функцию _delay_loop_2() передается значение равное произведению US_COUNT2 * __us, где __us должно быть равно количеству микросекунд. Например, в нашем случае 104 мкс (пример из ссылки напост). Таким образом, это выглядит так
void delay_us(104)
{
   _delay_loop_2(US_COUNT2 * 104);
}


Что такое функция _delay_loop_2?

void _delay_loop_2(uint16_t __count)
{
   __asm__ volatile (
      "1: sbiw %0,1" "nt"
      "brne 1b"
      : "=w" (__count)
      : "0" (__count)
   );


После компиляции это выглядит так

48:   88 e6          ldi   r24, 0x68   ; 104
4a:   90 e0          ldi   r25, 0x00   ; 0
4c:   01 97          sbiw   r24, 0x01   ; 1
4e:   f1 f7          brne   .-4         ; 0x4c <__SREG__+0xd>

ldi – это загрузка параметров функции в регистровую пару
sbiw – вычитание единицы
brne – организация цикла по условию (типа goto).

Пауза строится на двух командах sbiw и brne, каждая длительностью два машцикла, только в последнем цикле команда brne выполняется за один машцикл.
Командой sbiw мы вычитаем единицу из регистровой пары.
Команда brne осуществляет переход, если результат предыдущей операции не был равен нолю. Таким образом, пока в регистровой паре не будет значение 0, процессор будет «крутится» в пустом цикле, обеспечивая задержку.

Если в программе пауза стоит между какими-то действиями или в программном цикле, то компилятор, по возможности, выносит загрузку пары регистров ldi выше выполняемых действий, а значение для паузы (пару регистров) копирует одной командой movw r24, r№. (так быстрее).
Например.
  48:   20 e2          ldi   r18, 0x20   ; 32
  4a:   31 e0          ldi   r19, 0x01   ; 1
   //Loop: While 1
   while (1)
   {
      //C Code
      //C Code:
      PORTB = (PORTB & 0xfe) | 0x01;

  4c:   c0 9a          sbi   0x18, 0   ; 24
      delay_us(120);
  4e:   c9 01          movw   r24, r18
  50:   01 97          sbiw   r24, 0x01   ; 1
  52:   f1 f7          brne   .-4         ; 0x50 <__SREG__+0x11>


Что делают Матриксы, чтобы рассчитать паузу?

Матриксы находят коэффициент, который показывает зависимость количества циклов в паузе за единицу времени относительно реализации паузы – четырех машциклов в цикле (вот такая тафтология).

По простому.
Всегда удобно подставлять число в паузу, которое будет соответствовать сразу значению в микросекундах (миллисекундах, секундах) и больше ни о чем не думать.
Длительность одного машцикла АВР это 1/F_CPU.
Например 1/9 600 000 = 1,0416e-7 = 0,00000010416 секунды. Приблизительно 104 наносекунды.
Таким образом, за 4 машцикла это будет 0,000000416 = 416 наносекунд. Для получения паузы в 104 мкс нужно крутнуться в цикле 250 раз  (104 мкс/416 нс = 250) по четыре.
То есть 250*4*(1/9 600 000) = 1000*0,000000104= 104 мкс.
Но рассчитывать каждый раз значения паузы таким способом весьма не удобно.
Но если 250 разделить на 104, мы получим масштабный коэффициент 2,4, он будет постоянным для данной частоты для значений паузы в микросекундах.
Теперь передача значения паузы в подпрограмму _delay_loop_2(), будет выглядеть следующим образом
_delay_loop_2(2,4 * 104);

Константу US_COUNT2, мы заменили на 2,4.
Константа US_COUNT2 – это и есть масштабный коэффициент.
Матриксы его рассчитывают следующим образом (смотри )
#define US_COUNT2 F_CPU / 4000000
Это означает что, определяется константа US_COUNT2 и ей присваивается значение F_CPU / 4000000. Частоту процессора делят на 4 (количество машциклов в паузе) и на 1000000 (это все равно, что умножить на 0,000001, то есть на разрядную сетку микросекунд).

Вот здесь Матриксы и допустили ошибку!!!

Компилятор может автоматически присвоить тип переменной по результату действия, но компилятору нужно намекнуть, какой же тип переменной мы хотим получить.
Если F_CPU / 4000000 = 9 600 000 / 4000000 = 2.4, то компилятор видит, что одно целое число делится на другое целое число, тогда результат должен быть присвоен тоже целому числу, а значит константа US_COUNT2 будет равна 2. Таким образом, мы потеряли 0,4, а это 42 цикла программы паузы (нефига себе). Потеря составляет 42*4*0,000000104 = 0,000017472 = 17 мкс. А если теряем 0,99???
Намекнуть компилятору на правильный тип константы US_COUNT2 поможет следующая запись.
#define US_COUNT2 F_CPU / 4000000.0
На форуме я уже описывал, что при математических действиях значения с плавающей точкой всегда должны содержать дробную часть (мантиссу). При такой записи константе US_COUNT2 будет присвоено значение 2,4.
Вспомните, что я обращал ваше внимание на то, что в процедуре delay_us(double __us) присутствует переменная с плавающей точкой. Вот теперь и у нас будет передача (косвенная) в delay_us переменной с плавающей точкой.


Зайдите в файл  и внесите изменения.
// Define number of counts per time period using _delay_loop_2
#define MS_COUNT2 F_CPU / 4000.0
#define US10_COUNT2 F_CPU / 400000.0
#define US_COUNT2 F_CPU / 4000000.0


Вот теперь наступит счастье и паузы будут считаться правильно.

2
Flowcode + Proteus / USB+18F2550+rs232+16F886+4 Step
« : Ноябрь 19, 2011, 21:50:38 »
Как говорят "Спешиал фо Henych" Ответ на вопрос  - пост №#12299

Небольшой пример управления шаговыми двигателями.
Для моделирования шаговики подключены напрямую к МК.
На тупые вопросы по поводу их включения и почему так, я не отвечаю....(учите матчасть, моделирование и подключайте как хотите).
Главное в примере это взаимодействие двух МК и интерфейсов USB и RS232.
Протокол управления самый примитивный, поэтому имеет недостатки (например, команды управления нельзя подавать раньше чем шаговики отработают).
Формат кодограммы управления.
Кодограмма имеет длинну 5 байтов.
1 - байт направление вращения. Например 0b00001111 (15) все двигатели против часовой, 0и00001110 (14) три двигателя против часовой, один по часовой.
2,3,4,5 байты - количество шагов.
Формат кодограммы для выдачи через программу терминал (смотрите Хелп на программу) - #000#012#005#010#020 (все двигатели по часовой, первый на 120гр (12 шагов), второй на 50 гр (5 шагов), третий на 100 гр (10 шагов), четвертый на 200гр (20 шагов)). В протеусе я поставил движки на десяти градусный шаг. В программе Шаг - полный шаг.

Если читали тему про USB, то поставить драйвера и запустить не будет проблем.
ЖКИ подключите сами.

 

3
2-Wire LCD Interface на 74LS174

Когда применяют контроллер стараются отдать ему все функции и уменьшить периферийный обвес. Применение ЖКИ всегда требует как минимум 6 портов. Но иногда возникает необходимость применить МК с минимальными ресурсами (и портами) или сделать выносной индикатор. В этом случае можно применить, хорошо всем известные, схемы расширения портов на сдвиговых регистрах. Смотрите в Интернете подобные статьи.

Возможно кому-то это пригодится.

На сайте Матриксов я обнаружил такое же решение. Там же есть и фото рабочего проекта.
 
 




Желающие применить оригинальное решение Матриксов могут воспользоваться их файлом PIC_LCD.c (заменив на время работы оригинальный).

Однако, я не удержался от возможности внести в него свои, пусть не существенные, но правки. Это коснулось всего лишнего и временных задержек (но все задержки соответствуют ДАТЕ на HD44780). Временные задержки, как правило, придется подбирать в железе (а может и нет). Где они находятся – хорошо видно по закомментированным строчкам (или сравните с Матриксовским). По поводу конденсатора С1 – его необходимость покажет реальная работа.

Если вы захотите повторить этот проект с нуля или включит в свои проекты, вы должны в свойствах ЖКИ через «Импорт» подгрузить макрос LCD_74LS174.fcc (заменять PIC_LCD.c в этом случае не нужно).
Поскольку, для работы с ЖКИ нужно определить только два порта, то при компиляции, не обращайте внимание на сообщение ФК, что не все порты подключены.

 

PS При моделировании я заметил, что иногда происходит срыв изображения на ЖКИ, причем на компе, который на работе, а дома такого нет. Думаю, что только в железе, в чем причина, это можно прочувствовать реально. Может это глюки Протеуса.

4
Мне понравилась тема, которую поднял  Сергей - Пост 11593.
Я подумал что он не будет в обиде, если я создам отдельную тему и попрошу его эту тему продолжить (если у него будет желание).

Это варианта программы Сергея, но модернизированный мной.
 
или так
 
 
Это как можно упростить.
 

Этот вариант использует сигнал SD «длительность сигнала DTMF».
 

Кроме того, для ускорения отработки различных вариантов программы предлагаю воспользоваться симулятором, который я написал для Протеуса.
 

Схема в Протеусе только эмулирует коды DTMF. Нет смысла писать полный DTMF сигнал (в Протеусе нет библиотек для микросхем работающих с DTMF), но, несмотря на это, я думаю что такой симулятор может быть полезен.

ЗЫ. Хотелось бы чтобы Сергей проверил программы в железе, ну и модернизировал их, если что не так... Успехов ему.

5
Для желающих поупражняться в кодировке сегментных индикаторов.
Вот пример, в котором изменен код цифры 9.
 


По правой кнопке войдите в контекстное меню компонента и выберите «Свой код».







Если войти в Определения, через Редактирование,







то можно увидеть, как определены сегменты индикатора.








Далее входим в макрос ShowDigit








Видим определения сегментов в массиве (цифра 1).
Обратите внимание на закомментированную строчку (цифра 2), комментарий нужно снять. Эта строчка гасит знакоместа.









Компилируем проект и смотрим получившийся код на Си.








Находим место, где в массиве уже означены коды сегментов. Копируем их в макрос ShowDigit.








Вместо последней цифры 152 (код девятки) пишем цифру 144.







Компилируем еще раз и пользуемся.

6
Вот реализация примера пост 10378
 

Входной импульс формирует выходной. Длительность выходного показана в таблице.
вход   выход

1,0----   0,0
1,05----0,1
1,1----   0,2
1,15----   0,3
1,2----   0,4
1,25----   0,5
1,3----   0,6
1,35----   0,7
1,4----   0,8
1,45----   0,9
1,5----   1,0
1,55----   1,1
1,6----   1,2
1,65----   1,3
1,7----   1,4
1,75----   1,5
1,8----   1,6
1,85----   1,7
1,9----   1,8
1,95----   1,9
2,0----   2,0
2,05----   2,1
2,1----   2,2
2,15----   2,3
2,2----   2,4
2,25----   2,5
2,3----   2,6
2,35----   2,7
2,4----   2,8
2,45----   2,9
2,5----   3,0

В пределах от 1,5 мс до 2 мс происходит заданная растяжка от 1 до 2 мс.

Для примера на вход подается меандр, поэтому на выходе происходит пропуск импульса когда длинна его превышает полупериод меандра. Но в данной задаче входные импульсы будут идти редко (смотри условие), и пропусов не будет.

7
Предлагаю всем выкладывать различные попытки создания меню на ЖКИ.
Я думаю идеи и прототипы могут пригодится.

Менюшка создавалась для сортировки номеров градусников после их определения.
(сам проект "совершенно секретный").
 

Ну, а это баловство...
 

8
Вот пример счетчика (на вычитание) для намоточного станка. С предварительной установкой количества витков.
 

9
В инете существует множество проектов, связанных с формированием сигналов произвольной формы - синус, меандр, пила и т.д. только с применением микроконтроллеров . Например   пианино формирование "многоголосной" (поли) синусоиды через ШИМ, а также множество различных генераторов формирующих сигналы по принципу DDS.
Все эти принципы можно реализовать на ФК.  Вот я и подумал, а не сделать ли примеры как для PIC, так и для AVR???, таким образом можно будет сравнить возможности одних и других. Естественно не обойдется без двух-трех строчек на Си и Ассемблере, но я думаю это не вызовет большого неудобства.

Для поиска "синусоида", "синус на AVR", "синус на PIC", "DDS", "Генератор НЧ PIC", "Генератор НЧ AVR", "Генератор НЧ на МК", "синус на микроконтроллере", "AVR DDS signal".

10
Преамбула…
Поводом к открытию темы послужило неописуемое желание одного из форумчан измерить скорость неопознанного летающего объекта…, но… объекта очень маленького и скорость которого не превышает скорости пули.
И начал он скромно, с вопроса об измерении временного интервала периода входного сигнала. То есть, его заинтересовал вопрос, как измерить время между двумя входными импульсами на базе МК PIC16F84A. Вопросы связанные с подсчетом входных импульсов и измерением частоты на форуме обсуждались неоднократно (для поиска - частотомер, тахометр), однако, ситуация в этой области показывает, что применить уже накопленный опыт и готовые решения, к возникающим задачам с похожей тематикой, могут не все.
Постановка задачи….
Разработать устройство, позволяющее измерять скорость летящего предмета (пули) на эталонном участке равном 1 метру.
Скорость, которая будет измеряться, может лежать в пределах от 10 до 1000 м/с.
Реализации датчиков (контактные, оптические, индукционные) меня не волнует. Главное – на вход МК должны поступить два коротких импульса (длительность первого импульса не должна превышать длительность периода измерения). Лучше если это будут импульсы не более 10 мкс.
Принцип измерения скорости основывается на измерении длительности периода между импульсами. Длительность периода вычисляется методом подсчета количества прерываний между импульсами.
Отсюда скорость V=S/t, где S =1 м; t (время) – рассчитывается по количеству импульсов прерывания.
Точность измерения напрямую зависит от количества импульсов заполняющих интервал измерения. Чем выше частота заполнения, тем выше точность измерения.
Однако вернемся к преамбуле.
И для начала все-таки рассмотрим вопрос об измерении периода входного сигнала.
Изначально задача выглядела как измерение периода от 1 мс до 1 с (1000 мс) с точностью (я бы сказал с шагом, потому что точность это вопрос отдельный) 1 мс.
Мной было предложено решение (как прототип), которое я выложил в «Примерах программ», к сожалению, оно не принесло ростков прогресса…
Зато нашлись критиканы и нравоучители …
Хотя я думал, что кроме меня, найдутся желающие помочь в этом вопросе.
Интересно…, а если бы я не ввязался в эту задачу, взял бы кто смелость довести ее до ума???? (про «Чипа и Дейла» я молчу, нет более сердечной души на форуме, кстати, неплохой ник…).
В дальнейшем, я предполагал модернизацию этого устройства силами самого желающего разработать такое устройство, однако мои возжелания оказались безуспешными, и я сам доработал его, и оно приобрело вот такой вид…

 



Сразу оговорюсь, поскольку МК это PIC16F84A, то были исключены библиотеки с плавающей точкой (как это делать я писал ранее). Ниже приведен файл включения. Им нужно (на время компиляции) заменить исходный.


 

Страницы: [1] 2