Алгоритм приема кодов RC5

Пульт ДУВстраивание в любительские конструкции функций дистанционного управления вынуждает очень многих любителей "изобретать" свои собственные алгоритмы приема кодов, передаваемых пультами ДУ. Чаще всего берутся за прием кодов RC5, однако усилия, затрачиваемые на эту элементарную задачу, порой приводят в ужас.

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

{ads1}

Прежде всего, капельку теории, которую возьмем отсюда.

Биты кода RC5 кодируются следующим образом:  

Формат посылок кода RC5
Как видите, метод кодирования прост: логический 0 от логичесой единицы отличается фазой активного сигнала (то есть пачки излучаемых модулирующих импульсов) внутри интервала передачи одного бита. Отметим, что длительность одного бита всегда равна 1778 мкс.

Сам код состоит из 14 бит, и его передача в целом выглядит так:

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

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

Но на самом деле прием кода очень прост, ну просто до смешного прост! Взгляните на следующий рисунок (t=1778 мкс):

Пояснение к алгоритму приема кода RC5
Стрелками показаны моменты, когда следует произвести "опрос" выхода ИК-приемника для определения уровня принимаемого бита. Видно, что всего-навсего нужно каждые 1778 микросекунд считывать очередной бит кода, важно лишь вовремя начать это делать! А начинать надо спустя 1333 микросекунды от конца стартового бита, "принимать" который нет нужды - он всегда равен единице. И никаких сложных анализов!

{ads1}

То есть алгоритм приема таков:

  1. ждем прихода стартового импульса
  2. дожидаемся его конца
  3. отсчитываем 1333 микросекунды, вводим второй бит кода (первый - стартовый, всегда равен 1)
  4. отсчитываем 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-светильник с ДУ, а так же неплохо себя показал в ряде других проектов. Тем более что точность задержек легко обеспечивается при использовании таймера, но это тема для другого разговора.

Комментарии   

+1 #1 ploop 03.10.2011 13:39
А что делать, если частота пульта поплывёт? Это не редкость...
#2 ARV 03.10.2011 23:47
поплывет? у меня вроде как не плывет пока... редкость или нет - не могу судить, т.к. имею всего один пульт RC5... ну и кроме всего, изменить алгоритм, например, добавив после семпла ожидание конца текущего бита, совсем не сложно... правда, уже так красиво не получится :)
#3 idima 02.12.2011 15:35
TSOP работает не идеально. В зависимости от освещения, происходят ложные срабатывания. То есть - на выходе TSOP не чистая единица, а есть иголки. Это приводит к нестабильной работе данного алгоритма.
#4 ARV 02.12.2011 22:50
Цитирую idima:
TSOP работает не идеально. В зависимости от освещения, происходят ложные срабатывания. То есть - на выходе TSOP не чистая единица, а есть иголки. Это приводит к нестабильной работе данного алгоритма.
разумеется, всяко бывает. но вы забываете о том, что ложно принятый код не будет никак обработан. в конце концов, все коды повторяются непрерывно, так что первый исказится - следующий примется правильно. не смотря на недостатки, которые я не отрицаю, этот алгоритм работает более чем удовлетворитель но. тем более что более простых альтернатив я просто не встречал.
#5 idima 03.12.2011 22:47
Сразу оговорюсь, что способ мне нравится, проще не придумаешь. Но при свете люминисцентной лампы приходится по три раза жать на кнопку. Тогда как существуют алгоритмы определяющие посылку идеально. Проверено на практике.
#6 ARV 04.12.2011 02:45
Цитирую idima:
Но при свете люминисцентной лампы приходится по три раза жать на кнопку. Тогда как существуют алгоритмы определяющие посылку идеально.
у меня в RGB-светильнике с ДУ используется этот принцип - работает удовлетворитель но, хотя и сам светодиод светится пульсирующим светом, и в комнате сплошь всюду энергосберегайк и... может, у вас плохо работает из-за чего-то иного, а не из-за алгоритма :)
#7 Carobey 18.01.2012 13:07
опция -Os - Это оптимизация по размеру, а не по скорости! -О3 - максимальная оптимизация по скорости. Для особых извращенцев есть -О99 но это тестовые алгоритмы оптимизации!
#8 Георгий 09.10.2014 00:46
алгоритм прост и плох, так как придётся подбирать длительность импульса от пульта к пульту (разброс параметров резонаторов в пульте + разброс частоты внутреннего генератора МЕГИ) и корректировать по мере разряда батареек в пульте
ИМХО все подобные проекты, выложенные бесплатно в интернете, страдают именно этим
#9 ARV 15.10.2014 01:45
Георгий, Вы не правы. В пультах телеков стоят керамические резонаторы для стабилизации частоты и они обеспечивают формирование длительностей импульсов в соответствии со стандартом. Очень маловероятно, что плавание длительностей будет более 5%, с учетом того, что частота встроенного генератора AVR стабильна на уровне 1%, не вижу никаких проблем. Без какого бы то ни было подбора данный код с первой прошивки принимает сигналы с любых доступных мне пультов. Ну а для надежности не помешает применить микроконтроллер с кварцевым резонатором - хуже не будет точно :-)
#10 Dmitrij Vavilov 12.05.2016 01:26
Здравствуйте! Пытаюсь декодировать манчестер для радиоуправления и хотел взять за основу описанный метод, но понял, что он лишён главной "фишки", что не может быть три подряд полупериода в манчестере. Буду думать дальше.

Добавить комментарий

Обсудить на форуме (0 комментариев).

Copyright 2011 © simple-defices.ru.
При использовании материалов ссылка на www.simple-devices.ru обязательна.