- Родительская категория: Статьи
- Категория: Программирование
- Автор: ARV
- Просмотров: 34277
Алгоритм приема кодов RC5
Встраивание в любительские конструкции функций дистанционного управления вынуждает очень многих любителей "изобретать" свои собственные алгоритмы приема кодов, передаваемых пультами ДУ. Чаще всего берутся за прием кодов RC5, однако усилия, затрачиваемые на эту элементарную задачу, порой приводят в ужас.
Универсальный алгоритм, ранее описанный мною, почему-то не снискал популярности, видимо, из-за того, что не позволяет обеспечить совпадение со "стандартными" кодами команд. Поэтому я решил познакомить с одним очень простым алгоритмом, позволяющем принимать RC5-коды "по-настоящему".
{ads1}
Прежде всего, капельку теории, которую возьмем
Биты кода RC5 кодируются следующим образом:
Как видите, метод кодирования прост: логический 0 от логичесой единицы отличается фазой активного сигнала (то есть пачки излучаемых модулирующих импульсов) внутри интервала передачи одного бита. Отметим, что длительность одного бита всегда равна 1778 мкс.
Сам код состоит из 14 бит, и его передача в целом выглядит так:
Не вдаваясь в смысл каждого отдельного бита, можно сказать следующее: первый бит всегда равен единице, а остальные могут меняться.
В некоторых публикациях описывается алгоритм приема и декодирования этого кода с использованием прерываний, таймеров, сложного анализа каждого принятого бита с учетом предыдущего и т.п. В целом получается непросто, что ставит начинающего программиста в тупик.
Но на самом деле прием кода очень прост, ну просто до смешного прост! Взгляните на следующий рисунок (t=1778 мкс):
Стрелками показаны моменты, когда следует произвести "опрос" выхода ИК-приемника для определения уровня принимаемого бита. Видно, что всего-навсего нужно каждые 1778 микросекунд считывать очередной бит кода, важно лишь вовремя начать это делать! А начинать надо спустя 1333 микросекунды от конца стартового бита, "принимать" который нет нужды - он всегда равен единице. И никаких сложных анализов!
{ads1}
То есть алгоритм приема таков:
- ждем прихода стартового импульса
- дожидаемся его конца
- отсчитываем 1333 микросекунды, вводим второй бит кода (первый - стартовый, всегда равен 1)
- отсчитываем 1778 микросекунд и вводим третий бит, через следующие 1778 микросекунд - четвертый и т.д. до приема всех 14 бит.
Реализовать этот алгоритм можно, конечно, и с помощью всяких прерываний, таймеров и т.п. наворотов, но для начинающих вполне можно рекомендовать самый простой способ - с использованием опроса и программными задержками (в нижеследующем коде учтен факт инверсии битов на выходе приемника ИК-сигнала):
{codecitation style="brush: cpp;"}#include <avr/io.h>
#include <util/delay.h>
#define TSOP_PIN (PIND & _BV(PD2)) /* так опрашивается выход ИК-приемника */
#define BIT_DELAY 1778
#define START_DELAY (BIT_DELAY * 3 / 4)
#define CODE_LEN 13 /* количество принимаемых битов кода */
uint16_t get_rc5(void){
uint16_t code = 1;
while(TSOP_PIN == 1); // ждем прихода стартового импульса
while(TSOP_PIN == 0); // ждем конца стартового импульса
_delay_us(START_DELAY); // выжидаем первый интервал
// организуем цикл приема битов кода
for(uint8_t i=0; i<CODE_LEN; i++){
code <<= 1; // сдвигаем код влево
if(TSOP_PIN == 0) // если на выходе приемника 0,
code |= 1; // это означает прием единицы
_delay_us(BIT_DELAY); // ждем следующий момент опроса
}
return code; // возвращаем полученный код
}{/codecitation}
Как видите, все очень просто. Однако, нужно четко осознавать, что работа алгоритма целиком и полностью зависит от точности выдержки программных задержек. Естественно, необходимо обязательно использовать максимальную оптимизацию кода (опция -Os). Функция приема возвращает управление в программу только после приема кода, что может "тормозить" работу главного цикла программы. Чтобы это не мешало работе, следует вынести все прочие задачи в "фон", т.е. выполнять их по прерываниям. Однако, из-за прерываний точность программных задержек снижается...
Разорвать этот порочный круг можно следующим образом. При помощи симулятора ISIS Proteus определяем фактическую длительность задержек, которая из-за прерываний будет больше требуемой, вычисляем поправочный коэффициент и корректируем константу BIT_DELAY, т.е. уменьшаем ее, "вгоняя" задержку в нужную точность.
{ads1}
Не смотря на некоторую неопределенность с задержками, данный алгоритм отлично работает в проекте RGB-светильник с ДУ, а так же неплохо себя показал в ряде других проектов. Тем более что точность задержек легко обеспечивается при использовании таймера, но это тема для другого разговора.
Комментарии
ИМХО все подобные проекты, выложенные бесплатно в интернете, страдают именно этим
RSS лента комментариев этой записи