Печать

Декодирование сигналов протокола RC5

Автор: AntonChip Опубликовано . Опубликовано в Программирование на Си

Рейтинг:   / 23
ПлохоОтлично 

Система инфракрасного дистанционного управления RC5 была разработана фирмой Philips для нужд управления бытовой аппаратурой. Когда мы нажимаем кнопку пульта, микросхема передатчика активизируется и генерирует последовательность импульсов, которые имеют заполнение частотой 36 кГц. Светодиоды преобразуют эти сигналы в ИК-излучение. Излученный сигнал принимается фотодиодом, который снова преобразует ИК-излучение в электрические импульсы. Эти импульсы усиливаются и демодулируются микросхемой приемника. Затем они подаются на декодер. Декодирование обычно осуществляется программно с помощью микроконтроллера. Код RC-5 поддерживает 2048 команд. Эти команды составляют 32 группы (системы) по 64 команды в каждой. Каждая система используется для управления определенным устройством, таким как телевизор, видеоплеер и т. д.

Команда согласно протоколу RC5 показана на рис. 1. Кодовая последовательность (красный цвет) состоит из 14 тактовых интервалов длительностью по 1,78 мс (64 периода частоты 36 кГц), в каждом из которых передают один разряд двоичного кода. Лог. 1 соответствует положительный перепад уровня в середине тактового интервала, лог. 0 — отрицательный.

Кодовая последовательность RC5

Рисунок 1

Два первых разряда (St1, St2) — стартовые. Они всегда имеют значение 1, что позволяет приемнику опознать начало команды. Третий разряд — служебный. Его значение сменяется противоположным при каждом нажатии на кнопку ПДУ, что позволяет отличить новую команду от автоматического (каждые 114 мс при удержании кнопки нажатой) повторения ранее поданной. В разрядах S4—S0 указан адрес устройства (системы), которому предназначена команда. Приведенный в примере адрес 0x05 (00000101) закреплен за видеомагнитофонами.

Номера систем для некоторых видов бытовой аппаратуры приведены ниже:
О - Телевизор (TV);
2 - Телетекст;
3 - Видеоданные;
4 - Видеопроигрыватель(VLP);
5 - Кассетный видеомагнитофон (VCR);
8 - Видео тюнер (Sat.TV);
9 - Видеокамера;
16 - Аудио предусилитель;
17 - Тюнер;
18 - Магнитофон;
20 - Проигрыватель компакт-дисков (CD);
21 - Проигрыватель (LP);
29 - Освещение;
Остальные номера систем зарезервированы для будущей стандартизации или для экспериментального использования.

В шести разрядах С5—С0 записан собственно код команды, в данном случае 0x35 (00110101), "Воспроизведение".

Коды команд для некоторых функций приведены ниже:
О - 9 - Цифровые величины 0 - 9;
12 - Дежурный режим;
15 - Дисплей;
13 - Пауза;
16 - Громкость"+";
17 - Громкость
30 - Поиск вперед;
31 - Поискназад;
45 - Выброс;
48 - Пауза;
50 - Перемотка назад;
51 - Перемотка вперед;
53 - Воспроизведение;
54 - Стоп;
55 - Запись;

Протокол RC5 позволяет с помощью одного пульта подавать по 64 команды независимо на 32 различных устройства Если этого недостаточно, используют "расширенный" протокол RC5, согласно которому еще один разряд команды (С6) занимает место второго стартового (St2). Таким образом, число возможных команд возрастает до 128.

При передаче команд по ИК каналу связи сформированной кодовой последовательностью RC5 модулируют несущую частоту 36 кГц, в результате чего ПДУ излучает пачки ИК импульсов этой частоты (черный цвет). Для их приема обычно применяют специализированные фотоприемники, импульсная последовательность на выходе которых (зеленый цвет) инверсна исходной.

Закрепим теоретические знания практикой. Соберем декодер сигнала RC5. Прибор будет принимать команды с пульта дистанционного управления и декодировать их, выводя их коды в десятичной системе на семисегментный индикатор. Как всегда используем микроконтроллер Atmega8, который будет тактироваться от внутреннего генератора частотой 8МГц. Индикатор двухразрядный с общим анодом. Схема прибора показана на рисунке 2.

Декодирование сигналов протокола RC5

Рисунок 2

Сигнал, принятый и демодулированный ИК приемником IC2, поступает на вывод 4 (PD2) микроконтроллера IC1, сконфигурированный как вход с внутренним "подтягивающим" резистором. Не помешает и внешний подтягивающий резистор. Блокировочный конденсатор С1 должен быть расположен как можно ближе к выводам питания ИК приемника.

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

Первое, что нужно сделать в процедуре обработки прерывания - это запомнить показания таймера, обнулить таймер и запустить его снова. Так, как прерывание у нас первое, то просто обнуляем и запускаем таймер. Считываем уровень на входе и запоминаем его в нулевом бите переменной. Сдвигаем переменную влево. Устанавливаем признак того, что произошла запись и увеличиваем на 1 счётчик принятых бит. По приходу второго прерывания так же запоминаем показания таймера, перезапускаем его и смотрим, сколько прошло времени. Если интервал получился длиной в период, то импульс был "длинный". А это значит, что в любом случае мы прервались в середине периода и надо производить запись уровня на входе в переменную, снова сдвигать её влево и снова увеличивать счётчик.

Если интервал получился длиной в полпериода, то импульс был "коротким". А это значит, что мы могли прерваться как в середине, так и на границе периода. Тогда проверяем  признак записи.

Если по прошлому прерыванию запись происходила, то мы на границе периода и запись в переменную не производим. Сбрасываем признак записи и ждём следующего прерывания.

Если-же признак записи не установлен, то мы прервались в середине периода. Производим запись, сдвигаем переменную, устанавливаем признак записи и увеличиваем счётчик бит на 1.

Таким образом принимаем все 14 бит, останавливаем  таймер, сбрасываем счётчик бит и признак записи. Переходим к процедуре обработки принятого слова.

Так-же необходимо предусмотреть прерывание от измеряющего таймера, если временной интервал превысит полтора периода. По этому прерыванию следует сбросить все переменные и счётчики ибо произошла ошибка при приёме команды. начения времени для  "длинного" и "короткого" интервалов следует взять с запасом плюс-минус 20%, т.к. не во всех пультах ДУ задающий генератор стабилизирован кварцевым резонатором. Иногда он выполняется на RC цепочке и частота его не стабильна. Исходный код полностью представлен ниже:

// Декодирование сигналов протокола RC5
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h> 

// Временные пределы
#define Tmin 40 // длинный промежуток
#define Tmax 68
#define TminK 22 // короткий промежуток
#define TmaxK 34

//------------------0-----1-----2-----3-----4                      
char SEGMENTE[] = {0x3F, 0x06, 0x5B, 0x4F, 0x66,
//------------------5-----6-----7-----8-----9
                   0x6D, 0x7D, 0x07, 0x7F, 0x6F};

volatile unsigned char segcounter = 0;
volatile int display1 = 0;
volatile int display2 = 0;

unsigned char sct_bit = 0; // Счетчик битов RC5
unsigned char RC5_buffer [14]; // Буфер RC5
unsigned char centre =  0; // Флаг центра 
unsigned char not_korr = 0; // Флаг попадания в промежутки
unsigned char Timer = 0; // число в счетчике таймера
unsigned char command = 0; // переменная для команды

// Функция очистки буфера
void rc5_cl_buf(void)
{
unsigned  char i = 0;      
for (i=0; i<14; i++)
{
RC5_buffer [i] = 0;
}
}   

// функция остановки таймера
void rc5_ti_stop(void)
{
GICR = 0x00;
TCCR0 = 0x00;
TCNT0 = 0;
sct_bit = 0;
} 

// Обработчик прерывния по переполнению Т0 
ISR (TIMER0_OVF_vect)
{   
rc5_ti_stop(); //останавливаем таймер
rc5_cl_buf(); //очищаем буфер
GICR |= (1 << INT0); // разрешаем прерывания по входу INT0
GIFR |= (1 << INTF0); // сбрасываем флаг прерывания
                            // (если произошло) 
} 

// Обработчик прерывния по переполнению Т1
// Динамическая индикация
ISR (TIMER1_OVF_vect)
{	
PORTB = 0xFF;
PORTD = (1 << segcounter);
	
switch (segcounter)
{	
case 0:
PORTB = ~(SEGMENTE[display1]);
break;
case 1:
PORTB = ~(SEGMENTE[display2]);
break;	
}
if ((segcounter++) > 0) 
segcounter = 0;	
}

// Обработчик внешнего прерывания INT0
ISR(INT0_vect)
{
Timer = TCNT0; // запоминаем значение счетчика   
TCNT0 = 0;     // обнуляем счетчик
not_korr = 1;                         

if(sct_bit==0)
{
TCCR0 |= (1 << CS02); // запускаем таймер (31.250 KHz)
//записываем в эл.массива
RC5_buffer [sct_bit] = !(PIND&(1 << PD2));
sct_bit++; // +1 к счётчику принятых битов
centre = 1;           
}
else
{
// Проверка короткого промежутка
if ((Timer > TminK)&&(Timer < TmaxK))
{
if (centre) 
{
centre = 0;
not_korr = 0; 
}
else
{
centre = 1;
RC5_buffer [sct_bit] = !(PIND&(1 << PD2));
sct_bit++;
not_korr = 0;
}
}
// проверка длинного промежутка
if ((Timer > Tmin)&&(Timer < Tmax))
{
RC5_buffer [sct_bit] = !(PIND&(1 << PD2));
sct_bit++;
not_korr = 0;
}

if (not_korr == 1)
{              // если не попали ни в один из промежутков то  
rc5_ti_stop(); // останавливаем таймер
rc5_cl_buf(); // очищаем буфер
}

if (sct_bit == 14)
{              // если бит последний то 
rc5_ti_stop(); // останавливаем таймер

// Формируем код команды
command = (RC5_buffer [8] << 5)|(RC5_buffer [9] << 4)|
          (RC5_buffer [10] << 3 )|(RC5_buffer [11] << 2)|
		  (RC5_buffer [12] << 1)|RC5_buffer [13];
		                      
// Выводим данные на дисплей   
display1 = command%10; // преобразование для 1 цифры
command = command/10; // преобразование кода команды 
display2 = command%10; // преобразование для 2 цифры 
}
GICR |= (1 << INT0); // разрешаем прерывания по входу INT0
GIFR |= (1 << INTF0); // сбрасываем флаг прерывания по входу INT0                                                                         
}    
}

int main(void)
{
DDRB = 0xFF; // выход
PORTB = 0x00;
DDRD |= (1 << PD1)|(1 << PD0); // выход
DDRD &= ~(1 << PD2);  // вход ИК
PORTD = 0x00;

TIMSK |= (1 << TOIE0); // разрешение прерывания по таймеру0
TIMSK |= (1 << TOIE1); // разрешение прерывания по таймеру1
TCCR1B |= (1 << CS10); // без предделителя 

GICR |= (1 << INT0); // разрешаем прерывания по входу INT0
MCUCR |= (1 << ISC00); // прерывание по любому фронту
GIFR |= (1 << INTF0); // сбрасываем флаг прерывания

sei(); // глобально разрешаем прерывания

while(1){} // бесконечный цикл
}

Демонстрация работы декодера RC5

Файлы:
Проект AVRStudio4
Дата 14.12.2015 Размер файла 17.9 KB Закачек 301

Комментарии  

0 #21 Геолргий 08.10.2014 07:15
у меня Codevision 2.05 ругается на
Код:
avr/io.h
util/delay.h
avr/interrupt.h

говорит не могу открыть
где их взять?
какова частота чипа в проекте?
Сообщить модератору
0 #22 AntonChip 12.10.2014 20:25
Цитирую Геолргий:
у меня Codevision 2.05 ругается на
Код:
avr/io.h
util/delay.h
avr/interrupt.h

говорит не могу открыть
где их взять?
какова частота чипа в проекте?

Таких файлов нет в CV, вот и ругается, смотрите отличия в синтаксисе в компиляторах
Сообщить модератору
0 #23 andrey83 16.01.2015 11:33
Здравствуйте,чт о нужно изменить в исходном коде, что бы подключить семи сегментный индикатор с ОК?
Сообщить модератору
0 #24 Philips 17.04.2015 13:55
Напишите модель семисегментного индикатора, используемого в этой схеме.
Сообщить модератору
+1 #25 AntonChip 19.04.2015 10:33
Цитирую Philips:
Напишите модель семисегментного индикатора, используемого в этой схеме.

RL-D3620
Сообщить модератору
+1 #26 phillsir 20.05.2015 11:19
А есть схема дорожек в sprint layout'е ? Скиньте, если есть.
Сообщить модератору
0 #27 art 10.08.2015 21:12
А можно после первого прерывания
включить таймер с частотой в пол периода
этого кода (1.78/2) и проверять уровень напряжения
на ноге int0 по прерыванию таймера?
Сообщить модератору
0 #28 Gosha 13.10.2015 13:31
А не могли бы привести практический пример декодирование для более популярного протокола NEC? Спасибо.
Сообщить модератору
+2 #29 Sergey F 13.10.2015 13:52
Цитирую Gosha:
А не могли бы привести практический пример декодирование для более популярного протокола NEC? Спасибо.

Присоединяюсь к вопросу.
Сообщить модератору
0 #30 AntonChip 14.10.2015 19:32
Цитирую Gosha:
А не могли бы привести практический пример декодирование для более популярного протокола NEC? Спасибо.

Код написать не проблема, а какой марки купить пульт чтоб там был именно протокол NEC
Сообщить модератору
-1 #31 Sergi 15.10.2015 17:24
Встречается в аппаратуре таких фирм, как Funai, Akai, Fisher, Goldstar, Hitachi, Kenwood, Onkio, Teac, Yamaha, Sanyo, Canon, Orion, Apex, Eltax, и много других.
Сообщить модератору
+1 #32 Aleshqa 16.11.2015 18:44
К каким ножкам индикатора, подключаются 2 и 3 вывод микросхемы?
Сообщить модератору
0 #33 AntonChip 17.11.2015 10:31
Цитирую Aleshqa:
К каким ножкам индикатора, подключаются 2 и 3 вывод микросхемы?

К выводам 2,3 микроконтроллер а подключаются общие аноды индикатора
Сообщить модератору
0 #34 Aleshqa 18.11.2015 11:05
А как питание подключается?
GND к 1 ножке TSOP1736, а + 5V к 2 ножке tsop1736 ?
Сообщить модератору
0 #35 userr 14.12.2015 09:26
Выложите файл прошивки.
Сообщить модератору
0 #36 122222222222222224 18.12.2015 08:59
Какие фьюзы выставлять?
Сообщить модератору

Рекомендуем посмотреть