Реклама ⓘ
Главная » ИК техника
Призовой фонд
на апрель 2024 г.
1. 100 руб.
От пользователей

Реклама ⓘ

Распознавание ИК команд с помощью UART на AVR

Введение

О распознавании команд с инфракрасного пульта написано много статей. В-основном, речь идёт о протоколе RC5 от пультов Philips [1]. Этот протокол не единственный и не самый распространённый. Хорошее описание других форматов на русском языке можно найти в документе [2]. 

Во всех найденных мною статьях распознавание производится чтением состояния датчика TSOP в строго определённые моменты времени ( в обработчике прерывания от таймера или в основном цикле программы ). Однако в моём последнем проекте мне нужно общаться с внешним устройством со строгими временными задержками, из-за чего приходится запрещать прерывания на периоды до 2мс. Этот факт делает невозможным опрос состояния датчика TSOP с требуемой точностью ( раз в 560мкс  +-100мкс ).  

Так родилась идея использовать UART как “хитрый” сдвиговый регистр. В полученной реализации при декодировании NEC-подобного протокола необходимо неспешно опрашивать состояние датчика лишь раз в 4мс, при этом сам микроконтроллер может находиться в idle mode или даже в power down mode!

Пульты ДУ

ИК протоколы

Не вижу смысла повторять описание протоколов ИК пультов - они описаны достаточно хорошо в статье [2].  Обозначу лишь основные моменты:

ИК-посылка на примере протокола NEC

ИК-посылка на примере протокола NEC состоит из Mark pulse(9мс), Space pulse(4.5мс) и последовательности импульсов данных.

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

Следует отметить, что на выходе датчика TSOP показанный сигнал будет инвертирован: 

Осциллограмма ИК сигнала пульта

Для декодирования команды необходимо синхронизироваться с фронтом первого импульса данных, подождать его середины (280мкс), и продолжить опрос состояния датчика  каждые 560мкс:

Моменты опроса датчика должны быть соблюдены достаточно точно (не более +-100мкс). 

Если временнЫе промежутки соблюсти невозможно, то программное декодирование работать не будет. Нужно искать какое-то другое решение. Решением “в лоб” было бы использовать второй микроконтроллер, или специализированную микросхему-декодер. 

Однако стоит вспомнить, что “на борту” у AVR есть масса устройств, которые можно попробовать применить не по назначению :)

UART протокол

UART использует простой последовательный протокол [3]:

Последовательный протокол UART

При простое линия держится в стоянии “1”. Начало передачи определяется спадающим фронтом “стартового” бита (0). Далее следуют биты данных, далее -  бит четности (может не использоваться ), далее - один или два стоповых бита (1) . То есть после передачи байта линия возвращается в состояние 1, и цикл передачи начинается снова. Длины всех битов одинаковы и равны 1/Baud rate.

Протокол UART  не совместим с ИК протоколами.

Однако, если забыть о UART протоколе и рассматривать приёмник UART как сдвиговый регистр с таймером и синхронизацией по спадающему фронту, то окажется, что он подходит для распознавания (почти) любых последовательностей.

О том, как именно работает приёмник UART , можно прочесть в даташите на AT90USB162[4]. 

После определения спадающего фронта приёмник делает паузу длинной ½ бита, после чего проверяет, что линия всё еще в “0” ( valid start bit detection). 

После этого начинается цикл приёма битов данных, без всяких проверок, через промежутки, равные длине бита. Биты данных “заезжают” в сдвиговый регистр приёмника, а первый стоповый бит - в флаг FE в инвертированном виде. 

Если описать весь этот процесс упрощенно, то в режиме 7N1 приемник ждёт спадающего фронта, после чего читает вход 8 раз через равные промежутки времени. Но именно так и работает программное декодирование ИК протокола, описанное выше!

Распознавание ИК команд с помощью UART

Давайте посмотрим что будет, если “скормить” сигнал с ИК приёмника в UART.

Мой пульт использует протокол с временнЫми промежутками как в протоколе NEC[2], хотя сам формат команды отличается. 

Настроим UART в режим 7N1 ( 7 бит данных, без битов чётности, 1 стоповый бит). Baud rate установим в 1.000.000 / 560мкс = 1786 бод. 

Импульс Mark длиной 9мс (“0” на выходе датчика TSOP ) будет принят приёмником как 0000000b с ошибочным стоповым битом:

После этого приёмник будет ждать следующего спадающего фронта (пропустит до конца Mark и весь Space ). С началом ИК посылки приёмник синхронизируется на середину бита (560мкс / 2 = 280 мкс ) и прочитает 7 бит данных + стоповый бит:

После приёма 7+1 бит, UART будет ждать следующего спадающего фронта, причём если последний бит был “0”, то линия должна сначала вернуться в “1”. В этот момент у нас происходит некий “пробел” в приёме, что делает невозможным точное декодирование ИК протоколов, в которых биты кодируются длиной импульсов. Но даже в этом случае уникальный пакет будет формировать уникальные данные в приёмнике UART. Поскольку задачей является не декодирование содержания команды, а распознавание посылки, такая ситуация нас полностью устраивает.

Реализация

Пример написан на Codevision AVR 2.05 для ATMega8A, кварцевый резонатор 8МГц.

Основной цикл программы опрашивает состояние UART каждые 4мс и записывает полученные данные в циклический буфер длиной 12 байт. Длина буфера выбирается исходя из длины ИК посылки.

У моего пульта посылка имеет длину 54мс. 54000 / 560 = 96 бит или 12 полных байт. Выбираем 11 байт и +1 для стартового нулевого (разбирать всю посылку не обязательно, но очень важно, чтобы посылка привела к зацикливанию буфера). Для пультов, у которых длина посылки отличается в зависимости от кнопки, алгоритм будет чуть сложнее ( здесь обсуждаться не будет).

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

Пример выводит на терминал( 9600N1 ) CRC32 полученной команды, байты команды и символьное представление посылки:

После получения кодов можно уменьшить ложные срабатывания, раскомментировав секцию:

   ( readCMDBuffer( s_cmdBufferIndex ) == 0 ) &&
   ( readCMDBuffer( s_cmdBufferIndex + 1 ) == 0x95 ) &&
   ( readCMDBuffer( s_cmdBufferIndex + 2 ) == 0x95 ) &&
   ( readCMDBuffer( s_cmdBufferIndex + 3 ) == 0xB7 ) &&
   ( readCMDBuffer( s_cmdBufferIndex + 4 ) == 0xB7 ) &&
   ( readCMDBuffer( s_cmdBufferIndex + 5 ) == 0xB7 )

   (выше вставить заголовок кодов своего пульта)

Под “ложными срабатываниями” здесь подразумевается определение помех как команды с каким-то кодом, а не ложное срабатывание правильной кнопки.

Улучшения

1. Если использовать UART в режиме 9 бит данных, 1 паритет и 1 стоп, то период опроса можно ещё увеличить.

2. Приведённый алгоритм не проверяет время, прошедшее между приёмом байтов. Проверяя, можно уменьшить ложные срабатывания.

3. Во время ожидания команды микроконтроллер может находиться в idle mode и просыпаться по прерыванию от UART. 

4. В Power down mode UART не работает. Но если соединить RX с INT0, то это даст возможность выводить микроконтроллер в нормальный режим для приёма команды.

Заключение

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

Материалы

1. RC-5
2. Инфракрасное дистанционное управление (PDF)
3. UART 
4. AT90USB162 datasheet (PDF)

Прикрепленные файлы:

Теги:

Опубликована: 27.12.2013 0 0
Я собрал 0 2
x

Оценить статью

  • Техническая грамотность
  • Актуальность материала
  • Изложение материала
  • Полезность устройства
  • Повторяемость устройства
  • Орфография
0

Средний балл статьи: 4.5 Проголосовало: 2 чел.

Комментарии (7) | Я собрал (0) | Подписаться

0
thebonix #
Оригинальное решение, респект за статью.
Ответить
0
Дмитрий #
Как только люди не извращаются.
"...распознавание производится чтением состояния датчика TSOP в строго определённые моменты времени..." Зачем опрашивать? Есть же внешнее прерывание. Хотя, если стоит задача запрета всех прерываний на долгое время, то, возможно, это единственный способ. Только вот, если UART не увидит стоп, пропустит байт, как тогда код проверять? Если задача: реагировать на любую кнопку любого пульта - фотоприемник частенько ловит помехи в виде одного-двух импульсов.
Ответить
0

[Автор]
hax #
Мне нужно было управлять RGB лентой на чипах WS2811. Биты в такую ленту засовываются единой посылкой, с жестким таймингом, без прерываний. Во время посылки можно пропустить половину ИК комманды. UART блок, по сути - это сдвиговый регистр, который может запускаться по фронту и семплировать вход с установленной частотой. Идеально подходит для распознавания комманд.
Ответить
0
Руслан #
Пытаюсь повторить данный метод распознавания команд с пульта на Attiny2313 на BAscom AVR. Поясните пожалуйста, я должен объявить переменную куда буду складывать посылку размером 12 байт?
И что должен делать контроллер после приема Mark (тот что 9 мс).
Задумал делать устройство, которое бы записывало две кнопки пульта любого ду (просто как уникальные команды) и после обучения устройство могло вкл или откл нагрузку именно с этих кнопок
Ответить
0

[Автор]
hax #
Настройте Baud Rate UART на длину импульса в посылке с вашего пульта, у меня для 560 мкс : 1000000 / 560 = 1786 baud. Нажимайте кнопки пульта и смотрите, какие байты "принимает" UART. У меня одна кнопка "передает" 12 байт, уникальные для каждой кнопки.
Ответить
0
Руслан #
Я делал сначала так чтобы тини2313 отправляла по UART то что я ей прислал через Hyper Terminal, но ввиду того, что UART записывал в переменную размером в 1 байт, то программа зависала.
Я решил напрямую подключить к переходнику usb-ttl ик приемник и посветить в него пультом, я тем самым вижу в терминале какие-то данные и причем свойственные конкретной кнопке, но не пойму как узнать сколько эти данные занимают места в памяти.
Причем если нажимать на кнопку непрерывно, видно что сначала идут какие то определенные символы, а дальше уже идут одинаковые данные (наверное что-то типа Mark) - как в описании одного из протоколов
Ответить
0
Руслан #
И снова здравствуйте!
В общем с помощью программы Terminal v. 1.9b мне удалось увидеть код кнопок моего пульта ду.
Выглядит он примерно так:
Кнопка Up:
00 55 D5 77 DD D7 77 5D D5 D7 и далее непрерывно FF 00 FF 00..
Кнопка Down:
00 55 D5 77 DD D7 D7 5D 75 D7 и далее непрерывно FF 00 FF 00...
Скорость обмена 1786 бод

Далее я в Bascom Avr наваял простейшую программу для Attiny2313, которая записывает принятое через UART сообщение в переменную длиной 12 байт и сразу же его отправляет в терминал.
Потом все это дело на макетной плате подключил через переходник usb-com и увидел что мк отправляет почти тоже самое что и напрямую (когда ик приемник был напрямую к переходнику usb-com).
Почти.. дело в том что после заполнения моего буфера в 12 байт, мк отправляет данные в терминал, а uart успевает принять новые данные, например последовательность FF 00, а потом получается, что полезный код в буфер пишется не полностью, а только в оставшееся место.
Вопрос, как понять хотя бы начало посылки. Что делать с первым байтом 00?
Ответить
Добавить комментарий
Имя:
E-mail:
не публикуется
Текст:
Защита от спама:
В чем измеряется электрическое сопротивление?
Файлы:
 
Для выбора нескольких файлов использйте CTRL

Лазерный модуль 650нм 5мВт
Лазерный модуль 650нм 5мВт
Конструктор: DDS генератор сигналов Металлоискатель MD3010II
вверх