Главная :: Цифра:: Декодер для пультов Samsung2006-07-30
Удобно оснастить свои самодельные конструкции пультом дистанционного управления. Имеющиеся в продаже наборы не всегда удовлетворяют потребностям - ограниченное кол-во команд, неудобный пульт и т.д.
Для реализации самодельного декодера нам понадобится:
1. Собственно пульт, который мы хотим пристроить - может быть любой, от телека, видика ... центра ... протокол там используется один, отличаются лишь коды, которые мы снимем в процессе.
2. Любой микроконтроллер AVR фирмы Atmel (отличия лишь в мощности и в наличии перефирии). В зависимости от ваших потребностей. Я экспериментировал с ATmega162.
3. Фотоприемник TSOP1736, или подобный.
4. 8 светодиодов (для отображения кода полученной команды).
4. Любой программатор для AVR.
6. Кучка мелочевки.
7. Компилятор WinAvr.
Итак, для началя собираем простенькую конструкцию - на COM-порт вешаем фотоприемник, и с помощью программки-эксплорера смотрим что нам приходит с пульта. Эту увлекательную работу я уже проделал - так что предлагаю результат:
Из графика видно, что вначале приходит длинный стартовый импульс. С помощью осциллографа можно посмотреть, что его длительность примерно 4.8мс - точнее мой осциллограф не дает измерить. Далее идет пауза такой же длительности, и собственно сами данные.
Формат данных довольно прост. Это так называемый Pulse Distance код. Информация - 0 или 1 кодируется длинной промежутков между импульсами. Короткая пауза соответствует нулю, втрое больший - единица. Алгоритм работы прост:
- при срабатывании прерывания проверить был ли стартовый импульс, если нет - то является ли текущий импульс стартовым, или это просто помеха (такое бывает часто), сбросить все счетчики в ноль если помеха.
- если стартовый импульс был - то запускаем счетчик - измеряем паузу - проверяем 0 или 1
- вся логика работы основана на счетчике, и изменении срабатывания прерывания - спад импульса либо подъем. В листинге исходного кода все подробно закомментировано.
Макетка собрана что называется "на коленке", поэтому нарисованной схемки нет
. На словах: к прерыванию INT0 прицеплена кнопка - для принудительного сброса всех счетчиков. На прерывание INT1 - сигнал с фотоприемника. Обвязка стандартная. На PORTA прицеплены 8 светодиодов для отображения кода полученной команды.
Еще в данной программе реализовано переключение режимов - либо отображать код кнопки на светодиодах, либо показывать аналог уровня (например громкости) - т.е. последовательное увеличение\уменьшение кол-ва включенных светодиодов - регулируется клавишами громкости на пульте, режим переключается кнопкой MENU.
Ниже представлен листинг исходного кода.
#include // Most basic include files
#include // Add the necessary ones
#include // here
// Define here the global static variables
//
unsigned char Start, // флаг прихода стартового импульса
Start_now, // флаг прихода старта в текущей сессии прерывания
data, // данные побайтно
bit_count, // кол-во полученных бит
command, // команда (двоичная форма)
status, // режим отображения (0 - код, 1 - уровень)
volume; // уровень
void start_pulse(void); // проверка длительности стартового импульса
void no_packet(void); // помеха, обнуление данных
void data_in(void); // проверка получаемых бит
void data_end(void); // проверка полученных данных побайтно
//******************
//******************
SIGNAL (SIG_OVERFLOW1) // обработка прерывания таймера1
{
no_packet(); // обнуление данных
}
//******************
SIGNAL(SIG_INTERRUPT0) // обработка прерывания0 (кнопка)
{
PORTA=0xFF; // выключить светодиоды
TCNT0=0; // сброс таймера0
TCCR0=5; // запуск таймера0
while (!(TIFR&0x02)); // ждать прерывания от таймера0
TIFR = 0x02; // сброс флага прерывания таймера0
TCCR0=0; // останов таймера0
PORTA=0x00; // включить светодиоды
no_packet(); // обнулить данные
}
//******************
SIGNAL(SIG_INTERRUPT1) // обработка прерывания1 (фотоприемник)
{
TCCR1B=0; // остановить таймер
if (Start==0) // если старта не было
{
// ждем стартового импульса
if (MCUCR==0x0A) // и прерывание стоит на спад
{
TCNT1=0; // обнулить таймер
TCCR1B=0x4; // запустить таймер
MCUCR=0x0E;
}
else // иначе
{
start_pulse(); // вычисление интервала полученного импульса
if (Start==0) // если старт не получен
{
no_packet (); // обнуление всех данных
}
else // если старт был
{
MCUCR=0x0E; // прерывание на фронт
Start_now=1; // стартовый импульс пришел
в текущей сессии прерывания
}
}
}
// старт получен принимаем данные
if ((Start==1)&(Start_now==0))
{
if (MCUCR==0x0E) // если старт был не сейчас
и прерывание стоит на фронт
{
TCNT1=0; // обнулить таймер
TCCR1B=0x3; // запустить таймер
MCUCR=0x0A; // прерывание на спад
}
else // иначе
{
data_in(); // проверка полученного бита
MCUCR=0x0E; // прерывание на фронт
if (bit_count==32) // если получено 32 бит данных
{
data_end(); // проверка кода полученной команды
}
}
}
if (Start_now==1) // если стартовый импульс
пришел в текущей сессии прерывания
{
Start_now=0; // обнулить
}
}
//******************
void start_pulse(void) // вычисление стартового импульса
{
if (TCNT1L>17) // если получен стартовый импульс 4.8милисек
{
if (TCNT1L<21)
{
Start=1; // установить флаг
}
}
}
//******************
void no_packet(void) // импульсы помехи, обнуление всех данных
{
Start=0;
Start_now=0;
MCUCR=0x0A;
TCCR1B=0;
TCNT1=0;
data=0;
bit_count=0;
}
//******************
void data_in(void) // проверка полученного бита
{
if (TCNT1L>=2) // от 10 до 100 = 0
{
if (TCNT1L<20) // здесь влом было подбирать
точные значения для 0 и для 1
{ // итак все работает
data<<=1;
bit_count++;
}
else
if (TCNT1L>=20) // от 150 до 250 = 1
{
if (TCNT1L<=30)
{
data<<=1;
data=data+1;
bit_count++;
}
else
{
no_packet(); // обнуление данных если помеха импульсная
}
}
}
else
{
no_packet(); // обнуление данных если помеха импульсная
}
}
//******************
void data_end(void) // обработка полученного байта
{
command=data; // первый байт - код устройства
(пока не используется, просто зарезервировано временно)
if (command==167) // кнопка MENU
{
if (status==0)
{
status=1; // сменить режим
}
else
{
status=0;
}
}
if (status==1) // если статус=1 то
{
if (command==31) // VOL+
{
if (volume<8)
{
volume++;
}
}
if (command==47) // VOL-
{
if (volume>0)
{
volume--;
}
}
switch (volume) // выбрать значение уровня и показать на светодиоды
{
case 0:
PORTA=0xFF; // 255
break;
case 1:
PORTA=0xFE; // 254
break;
case 2:
PORTA=0xFC; // 252
break;
case 3:
PORTA=0xF8; // 248
break;
case 4:
PORTA=0xF0; // 240
break;
case 5:
PORTA=0xE0; // 224
break;
case 6:
PORTA=0xC0; // 192
break;
case 7:
PORTA=0x80; // 128
break;
case 8:
PORTA=0x00; // 0
break;
}
}
else
PORTA=command; // иначе показать коды кнопок
no_packet(); // обнуление данных
TCNT0=0; // сброс таймера0
TCCR0=4; // запуск таймера0
// небольшая пауза,
чтоб нажатая кнопка и удерживаемая
слишком быстро не "нажималась"
while (!(TIFR&0x02)); // ждать прерывания от таймера0
// паузу подобрать под конкретную задачу
TIFR = 0x02; // сброс флага прерывания таймера0
TCCR0=0; // останов таймера0
}
// ***********************************************************
// Main program
// s
int main(void)
{
// инициализация проца
DDRA=0xFF; // out
PORTA=0x00;
DDRB=0xFF; // out
PORTB=0x00;
DDRD=0x00; // in
PORTD=0x00;
// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0x82; // обработка прерываний от таймеров 0,1
ETIMSK=0x00;
TCCR1B=0x00;
MCUCR=0x0A; // прерывания 0 и 1 на спад импульса
EMCUCR=0x00;
GICR=0xC0; // включить обработку прерываний 0 и 1
Start=0;
Start_now=0;
data=0;
command=0;
status=0;
volume=0;
asm ("sei"); // включить обработку всех прерываний
while(1)
{ // рабочий цикл
asm ("nop");
}
}
|
Проект под эмулятор AVR VmLab с компилятором WinAvr лежит здесь.
Ну вот и все. Думаю вопросов нет, если есть - пишите на форум.
написал: webmaster
Комментарии
Здесь никто ничего не написал. Вы можете быть первым.