Освоение Атмеги или кипит наш разум

Pavel_E

Камрады!

Решил тут воспользоваться кризисом и освоить программирование МК, конкретно - Atmega8. Задача оказалась не столь сложной, благо лет 10 назад программировал на C. Но и не столь простой - не хватает знаний собственно по схемотехнике и методов обработки сигналов при помощи МК. Прочитал 3 самоучителя. Регистры с прерываниями понятны в частности, но в целом наводят грусть. Посмотрел кучу чужих проектов. Теперь в мозгах полный 😵. Собрал макетку с атмегой. Научился прошивать. Умею зажигать светодиод и гудеть зуммером морзянку. А дальше пока картина в мозге не складывается.

Собственно, учебную задачу сформулировал себе так:

  1. взять сигнал с приемника (например, положение газа);
  2. дешифровать его и присвоить некой переменной значение в % от 0 до 100. За ноль принять длительность импульса 1 мс, за 100 - 2мс;
  3. выдать на индикацию значение переменной (например, линейка из 10 светодиодов или двухсегментный цифровой индикатор);
  4. обработать эту переменную (например - инвертировать: 0 считать за 100, 100 - за 0);
  5. сгенерировать сигнал после обработки и подать его на выход (серву).

Сейчас мои мысли (прошу прокомментировать):
п. 1 - делаем любую ногу входом и подаем туда сигнал с приемника через резистор 10к чтобы не пожечь. Землю с приемника соединяем с землей схемы. А что с “+” приемника? Не хотелось бы наводок от серв на МК, но плодить раздельное питание МК и приемника с сервами тоже не очень хочется.
п. 2 - ??? Читаем состояние ноги. Пока оно “0”, ничего не делаем, ждем, крутим цикл, опрашивая ногу. Как только стало “1”, засекаем время. Ждем, крутим цикл. Как только оно стало “0”, отсекаем время и смотрим сколько миллисекунд прошло. Сравниваем с эталоном (не может быть больше 2.5мс, и меньше 0.5 мс). Если влезает в диапазон, присваиваем переменной нужное значение, выдаем на индикацию.
п. 3. - пока не сделал, но разберусь. Буду благодарен, если есть примеры кода для случая с цифровым индикатором.
п. 4 - все понятно (temp=100-temp);
п. 5 - широко описан в проектах сервотестеров. Но не понятен алгоритм, сам принцип. Кто-то делает, используя прерывание по переполнению таймера. Кто-то на функции delay_us() в каких-то сложных циклах. Как лучше? Почему? Как организовать параллельную работу с п.2?

В общем, пока наиболее непонятны п. 2 и 5 Буду рад любым комментариям.
Заранее мерси!

Aleksey_Gorelikov

Используйте прерывания. Есть же прерывания по изменению состояния на ноге. Время тоже удобно таймером считать, а не циклом. Отображать значение - ну это на выбор. Самое простое для “поиграться” - выводить в компорт (да и при отладке пригодится). Нужен будет шнурок от мобильника и терминалка на компе. Сервой рулить лучше тоже таймером. Тем самым и получится “паралельная работа” по прерываниям (точнее контроллер ерундой не страдает). А в основном цикле контроллер может и чем-нибудь менее полезным заниматься. Выводить что-либо куда-либо, или обрабатывать результаты измерений того ж импульса и готовить данные для таймера. Тратить время на опрос ноги “пока 0-курим, ждем” - как то нелогично, хотя иногда и необходимо. Старайтесь по максимуму использовать “железо” а не програмные навороты - эффективнее получится.

Пример кода для случая с цифровым индикатором (символьным) - есть как в примерах, так и в хелпах самого компилятора.

Pavel_E

Спасибо за ответ!

Aleksey_Gorelikov:

Используйте прерывания. Есть же прерывания по изменению состояния на ноге.

Вот в этом-то и хочу разобраться 😃

Т.е. принцип будет примерно такой:

  1. Устанавливаем прерывание по изменению состояния на входной ноге. В функцию-обработчик пишем включение таймера в случае, если состояние стало 1 и выключение таймера, если состояние стало 0 (с вычислением и сохранением времени работы в переменную длины импульса);
  2. в основном цикле программы постоянно даем на вывод то, что в переменной и вычисляем то, что хотим.
  3. Устанавливаем прерывание по другому таймеру - для параллельной выдачи на выходную ногу сигнала на серву. Работает это так: устанавливается “1” на выходной ноге и запускается таймер с настройками, чтобы переполниться в нужный момент (или сработать по достижению нужного значения) и запустить обработчик. Нужный момент соответствует длинне выходного импульса. Запускается обработчик и ставит “0” на выходную ногу.

Я правильно понял принцип?

PigTail
  1. Посмотрите работу таймера в режиме PWM,будете подсовывать ему значения длительности, а он сам буде ногу дрыгать.
Andrey73
Pavel_E:

Камрады!

присвоить некой переменной значение в % от 0 до 100. За ноль принять длительность импульса 1 мс, за 100 - 2мс;

При программировании постарайтесь забыть десятичное исчисление и научится играючи оперировать двоичными и шестнадцатиричными значениями, желательно в уме. Программки получатся красивее и писать будет легче. ATMEGA серия очень богата периферией - таймеры 8-ми и 16-ти битные с кучей режимов работы, прерывания разнообразные, АЦП и т.д. Большой грех делать программно то, что может сделать аппаратный модуль в чипе. Документация правда, на мой придирчивый взгляд, немножко коряво составлена. Но при желании разобраться можно.

Boroda

10к резистор будет уже заметно резать фронты, вполне достаточно 100 ом для чистоты фронта, а для надёжной защиты от сквозного тока 470 ом. Ограничение по ноге 20мА.

У 8 меги есть регистр захвата ширины импульса, работающий с первым таймером. Самое оно, чтоб ловить PPM в фоновом режиме. Как уже заметили выше, мощный PWM механизм таймеров позволит легко сформировать выходной сервосигнал. И опять-же аппаратно.
Изучайте документацию!
А всё остальное зависит от вашей фантазии и типа индикатора, который соберётесь использовать.

msv

Все так, конечно, но имхо есть одна тонкость…
Если с приемника попрет шум, есть шанс повесить МК, завалив прерываниями.
Может поэтому во всех декодерах на МК которые видел ( правда на PIC, да и смотрел исходники по диагонали) не используются прерывания вовсе?

ЗЫ Тоже вынашиваю идею сделать интегрированное устройство декодер+поисковую сиренку+контроль акков борта. Пока не определился на PIC или меге. Буду с интересом следить за темой.

Boroda
msv:


Если с приемника попрет шум, есть шанс повесить МК, завалив прерываниями.

А программная обработка шума на ноге его не повесит? Шумы несложно давить как схемотехникой, так и логикой самой прошивки.

BelMik
msv:

Все так, конечно, но имхо есть одна тонкость…
Если с приемника попрет шум, есть шанс повесить МК, завалив прерываниями.
Может поэтому во всех декодерах на МК которые видел ( правда на PIC, да и смотрел исходники по диагонали) не используются прерывания вовсе?
.

Прикиньте время обработки прерывания, и ширину полосы пропускания приемника, между импульсами шума, AVR успеет выспаться.

msv

А программная обработка шума на ноге его не повесит?

Ну опрашивать то можно так часто, сколько нужно. И даже специально делать паузы игнорируя возможные помехи (как это сделано в популярном SmartDecoder).
2BelMik Если полоса 3кгц, то надо быть готовым обрабатывать за ~0.16ms. Это дествительно без проблем пережует МК? (Пока не смотрел сколько тактов занимает процедура входа/выхода из прерываний, но готов вам поверить).
Еще, немного офф, где-то попадалось что в приемнике не желательно применять мегу, тк они более шумные чем пики. Это действительно так?

Pavel_E
Andrey73:

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

Именно поэтому тема и создана. Чтобы разобраться. Так что все советы всячески приветствуются!

За вчера думал попробовать прерывания и генерацию ШИМ. А успел освоить только вывод десятичной цифры на светодиодный индикатор. Осознал, что решительно не хватает ног на амтеге8 - индикация всего двух знаков отжирает 9 выводов! На все прочее остается маааало…

Читал даташит. Вроде все написано, а че-та непонятно. Объясните темному, что лучше использовать для срабатывания прерывания по сигналу от приемника?
Варианты: PD2 (INT0 - внешнее прерывание), PD3 (INT1- внешнее прерывание), PB0 (ICP1 - Timer/Counter1 Input Capture Pin), еще что-то? Как я это вижу - по изменению сигнала на ноге с 0 на 1 или с 1 на 0 включается прерывание, которое запускает или останавливает таймер. Если останавливает, то выдает в программу значение счетчика таймера.

Так?

msv:

ЗЫ Тоже вынашиваю идею сделать интегрированное устройство декодер+поисковую сиренку+контроль акков борта. Пока не определился на PIC или меге. Буду с интересом следить за темой.

Могу предложить поучаствовать 😃 Например по коду программы в части контроля акков борта. Пока не видел грамотных индикаторов липолек, которые бы кричали и моргали при просадке ЛЮБОГО элемента батареи ниже 2в. Индицировать-то все индицируют, а надо орать в голос.

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

Поисковая сиренка + фотовспышка (чтоб моргала в темное время суток) у меня тоже в планах.

sht0p0r
Pavel_E:

Читал даташит. Вроде все написано, а че-та непонятно. Объясните темному, что лучше использовать для срабатывания прерывания по сигналу от приемника?
Варианты: PD2 (INT0 - внешнее прерывание), PD3 (INT1- внешнее прерывание), PB0 (ICP1 - Timer/Counter1 Input Capture Pin), еще что-то? Как я это вижу - по изменению сигнала на ноге с 0 на 1 или с 1 на 0 включается прерывание, которое запускает или останавливает таймер. Если останавливает, то выдает в программу значение счетчика таймера.

Так?

нет не так
int 0,1 генерируют прерывания и запускают обработчик события (что в нем будет ваша проблема 😃 )
ICP1 может генерировать прерывание, а может и нет (только поднять флаг, что ICR1 обновлен) в любом случае в регистре ICR1 доступно положение счетчика таймера 1 в момент срабатывания ICP1.
таймеры при этом не перезапускаются пока вы это несделаете в ручную.
у вас 2 пути …
я сделал 2 канала с приемника по int и один, с датчика хола, по ICP

Pavel_E
sht0p0r:

int 0,1 генерируют прерывания и запускают обработчик события (что в нем будет ваша проблема )

Тогда так:
Вариант 1: на int0 или int1 заведен сигнал с приемника. Биты ISC11 и ISC10 регистра MCU установлены в значения 0 и 1 соответственно. Это должно установить режим “Any logical change on INT1 generates an interrupt request.” Т.е. любое изменение логического состояния вызывает прерывание. Правильно я понимаю? Тогда останется в обработчике прерывания посчитать время между его срабатываниями по нулю и по единице. Это можно сделать, запустив любой таймер по единице и остановив по нулю. Потом обнулить и снова в путь.

или Вариант 2:
Использовать ICP1. Установить прерывание по изменению состояния ноги и при срабатывании оного читать из регистра ICR1 сколько там натикало. И никаких таймеров запускать не надо.

А?

P.S.Я тоже вдруг сильно захотел 2 канала приемника и 1 датчик холла для контроля что вал крутится…

sht0p0r

я немного не так сделал
1 прерыванийе ставим на фронт
ждем
обработчик
1.1 берем timestamp с таймера 1 (он 16 бит)
1.2 проверяем что за прерывание пришло фронт или спад
1.3 пишем timestamp в timestamp_R или в timestamp_F (соответственно)
1.4 переключаем прерывание на определение фронта или спада (в зависсимости от того что пришло)
1.5 если пришел спад то поднимаем флаг(готово время для рассчета ширины импульса)
2 в основной программе
while(1){
2.1 если поднят флаг то рассчитываем ширину импулса (с учетом длинны счета таймера и переполнения, если таковое было между фронтом и спадом )
все можно наслаждаться.
2.2 если поднят флагг…
2.3 если поднят флаггг…
2.4 если поднят флаггггг…
2.n придушить бешеную собаку!!!
}
как использовать icp1 для тахометра попробуйте придумать сами
главное не перегружайте прерывания.
есть 2 пути
1 разрешить прерывание внутри преывания результаттом может стать stack overflow 😃
2 написать прерывания максимально короткими и быстрыми. таким образом быть почти уверенным, что прерывания не произойдут во время обработки другого.
тут опять же решать вам.
зы попробуйте написать сами экспириенс просто попрет…

Pavel_E

Тов. Штопор, мерси за алгоритм! Вроде вкурил что и как, пора в железо воплощать.

sht0p0r:

1 разрешить прерывание внутри преывания результаттом может стать stack overflow

В одной умной книжке прочитал, что, это типа невозможно и прерывания выполняются по очереди.

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

Я еще подумал, может плюнуть на это дело и тупо мерить усредненное конденсатором напряжение выхода приемника? Но эта мысль вредная, пока отгоняю.

sht0p0r

во время исполнения прерывания мега на внешние раздрожители не реагирует. если не разрешить их програмно внутри обработчика в конце за собой надо подчистить 😃

последняя мысль очень вредная. имхо
книжка товарища Шпака “порограмирование на С авр и пик” как то так называется. вам поможет освоить это б…ство.

valera_o

если будете покупать, купите мегу88, для внешних прерываний можно использовать практически все ноги портов, памяти столько же, опять же мега8 снята с производства.
Книга “Микроконтроллеры AVR семейства Mega” А.В.Евстифеев 2007
тоже хороша для освоения устройсва контроллеров.

Boroda
Pavel_E:

или Вариант 2:
Использовать ICP1. Установить прерывание по изменению состояния ноги и при срабатывании оного читать из регистра ICR1 сколько там натикало. И никаких таймеров запускать не надо.

Надо. В регистр ICP записывается значение из РАБОТАЮЩЕГО tcnt1 именно в
момент прихода сигнала на ногу. Таймер при этом не останавливается. Когда ICP будет прочитан в прерывании или основном теле, вам не надо будет задумываться о том сколько тиков прошло с момента прихода фронта до момента чтения регистра таймера.

PigTail
valera_o:

… опять же мега8 снята с производства.

И где это такие сведения? 😉 www.atmel.com/dyn/products/devices.asp?Status=Matu…® 8-Bit RISC
Если топикстартеру ща еще подсунуть 88 с разницей в регистрах после 8, то он точно закипит 😃

Pavel_E

м-да…
😵
надо выспаться. может уложится по полочкам и будет просто 😃

Слушайте, как вы женам объясняете, чем занимаетесь, а?

Aleksey_Gorelikov

ну объясните ей, что вот такая мелкая микросхемка - ни что иное, как полноценный компутер, что такая штука может являться брелком к авто сигнализации, самой сигнализацией, что авто, что домашней, “мозгами” стиральной машины, пультом от телека, часами с будильником и т.д. и т.п. Что все зависит от того, какую программу для нее написать. Глядишь, попросит мк с акселерометром в утюг встроить, чтоб отключался сам, если его на любимых трусах забыли и дырку не прожег. 😃

Pavel_E

Новости с фронтов.
Убит вечер пятницы, вся суббота и воскресенье. Поставленная задача решена на 70%. Умею управлять сервой и выводить произвольную информацию на четырехразрядный светодиодный индикатор. Осталось научиться расшифровывать сигнал с приемника, но вроде уже понятно как.

Не хватило ножек. Мигрировал на 40ногую атмегу16. Зверь.

Заодно вопрос-восклицание. 8-и битный таймер не может достойно управлять сервой в режиме PWM. Расчет простой - максимум на период 20мс (50Гц) приходится 256 отсчетов таймера. Т.е. 12,8 отсчета на одну миллисекунду. Нам нужен регулируемый импульс длительностью в диапазоне от 0,8 до 2,2 мс. Т.е. в лучшем случае - 18 отсчетов. Если рабочий угол сервы 180градусов, то получается можем задавать не точнее 10 градусов! Короче, в сад или в 16 бит. А 16 бит жалко на такое дело транжирить…

msv

Для декодирования по алгоритму sht0p0r можно и 8-разрядный таймер программно наростить и брать с него timestamp. А 16-разрядный использовать для ШИМА.
А что собственно за девайс изобретаете?
Если это декодер, никак не врублюсь как аппаратным PWM можно раздать импульсы на 8 каналов…

Pavel_E
sht0p0r:

я немного не так сделал
1 прерыванийе ставим на фронт
ждем
обработчик
1.1 берем timestamp с таймера 1 (он 16 бит)
1.2 проверяем что за прерывание пришло фронт или спад
1.3 пишем timestamp в timestamp_R или в timestamp_F (соответственно)
1.4 переключаем прерывание на определение фронта или спада (в зависсимости от того что пришло)
1.5 если пришел спад то поднимаем флаг(готово время для рассчета ширины импульса)
2 в основной программе
while(1){
2.1 если поднят флаг то рассчитываем ширину импулса (с учетом длинны счета таймера и переполнения, если таковое было между фронтом и спадом )
все можно наслаждаться.
2.2 если поднят флагг…
2.3 если поднят флаггг…
2.4 если поднят флаггггг…
2.n придушить бешеную собаку!!!
}

А вот вопрос. Под “поднятием флага” понимается просто запись значения в какую-нибудь переменную для обработки программой? А как оно будет работать, если программа сложная и быстродействия не хватит, чтобы успевать между импульсами (20мс)?. Т.е. может быть, что флаг поднят, но значение по фронту уже перезаписалось другим импульсом, не успев быть учтенным в программе. И тут она начнет его учитывать…

msv:

Для декодирования по алгоритму sht0p0r можно и 8-разрядный таймер программно наростить и брать с него timestamp. А 16-разрядный использовать для ШИМА.

Наверно так и сделаю. Но уж очень удобна автоматизация работы внешних прерываний именно с 16-битным таймером. Тем более, на атмеге16 внешних прерываний 3.

Альтернативная мысль: “наростить программно” ШИМ на 8-битном таймере. Т.е. в цикл таймера загнать время импульса, а скважность считать по количеству циклов, используя для хранения количества переменные в программе. По переполнению таймера проверять сколько циклов натикало и если хватит, обнуляться и пускать сигнал заново.

А можно и не парить мозг, а оставить этот режим для того, для чего он и предназначен. Т.е. генерировать ШИМ для управления, например, коллекторным двигателем.

msv:

А что собственно за девайс изобретаете?

Да пока просто разобраться хочу что такое микроконтроллер, что он может и что я на нем могу. Вообще хочется научиться брать любой сигнал, обрабатывать программно и генерировать свой сигнал. Ну а в частности - написать приблуду для автоматического управления комнатной автомашинкой, чтобы при попадании в препятствие давала задний ход, разворачивлась и т.п. Лампочками моргала и сиреной гудела. И о разряде липолек информировала. И каналы управления инвертировала если ее перевернуть вверх ногами. Сына веселить.

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

Еще хочу брать NMEA с GPS, углы с гироскопов, высоту с бародатчиков и обороты с винта. И фигачить все это по радиоканалу в цифровом виде на землю. На земле принимать и выдавать на ноутбук в красивой графической форме в виде авиационных приборов.

И чтобы если стемнело, то включалась поисковая фотовспышка хотя бы раз в минуту.

Еще много чего хочу 😃 Вопрос, в какой момент это надоест или когда снова начнется работа…

sht0p0r

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

Pavel_E:

А вот вопрос. Под “поднятием флага”…

да

Pavel_E:

А как оно будет работать, если программа сложная и быстродействия не хватит, чтобы успевать между импульсами (20мс)?

просто не обработаете управляющий импульс.
добавте проверку флага в прерывании int(0,1) если не сброшен то return из прерывания.
ног там более чем достаточно что-то вы включаете не рационально. повесте вашу схемку, думаю ее можно опримизировать.
что мешает гнерировать 16 битным таймером pwm и паралельно брать со счетчика значения?
что мешает програмно, по прерыванию генерировать pwm на нескольких ногах процессора?
включаете прерывание по переполнению таймера, в преравании поднимаете флаг, в основной программе генерируете импульс(ы) задонной длительности с периудом переполнений таймера.во время генерации импульса можно с пользой для дела использовать время процессора (например вывести на индикатор, что нибудь).
активней пользуйтесь аппаратной частью процессора тогда и программа будет обрабатываться быстро.

все уже сделано до вас 😃 www.dmd.es/osd.htm