Проекты :: Цифра :: Декодер для пультов Samsung

Декодер для пультов Samsung30/07/2006

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

Для реализации самодельного декодера нам понадобится:

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
Комментарии

Здесь никто ничего не написал. Вы можете быть первым.

Оставить сообщение
Имя:                                                        E-mail:
 

Сообщение

Антибот (введите 11*1*11, заменив "*" на "-"):