Sample IR NEC protocol

General discussion on mikroPascal PRO for AVR.
Post Reply
Author
Message
Kordal
Posts: 3
Joined: 18 Dec 2013 18:45

Sample IR NEC protocol

#1 Post by Kordal » 19 Dec 2013 01:19

Hello, all! I give an example of library of the decoder for work with IR control panels according to the NEC protocol.

We connect the IR receiver to a pin of INT0 and expose frequency of the MK on 8 MHz.

Tested at ATTiny2313, IR - TSOP xx36.

Code: Select all

unit IR_NEC;

// ---------------------------------------------------
// IR Decoder of the NEC standard
// ---------------------------------------------------
// Converted C to MikroPascal K. Andrey (Kordal), 2013
// HomePage: delphiprog.it-fg.ru
//----------------------------------------------------
// для частоты контроллера 8000000 Hz, Freq = 8 MHz
// при работе IR_NEC задействован таймер\счетчик T0.
// выход IR сенсора подать на внешнее прерывание INT0

// НАСТРОЙКА ПОРТА И ВЫВОДА IR СЕНСОРА
// SETUP PORT
// -----------------------------------
var IR_PORT : sbit at PORTD2_bit;
var IR_DDR  : sbit at DDD2_Bit;
// -----------------------------------

procedure IRNEC_Init();
function  IRNEC_IsDataReady: Byte;
function  IRNEC_GetDevice : ^Char;
function  IRNEC_GetCommand: ^Char;

implementation

var
  // переменные и флаги библиотеки
  NEC_Data: array [4] of char; // Массив байтов для приема данных
  NecCountBites: Byte;         // Счетчик принятых битов данных
  NecFlags: Byte; volatile;    // Байт флагов

const
  bIrNecStreamEnb = (1 shl 0);   // Флаг наличия запущеннного процесса приема серии
  bIrNecRcvCmpltd = (1 shl 1);   // Флаг завершения приема данных
  bIrNecTimerOvf  = (1 shl 2);   // Флаг фиксации переполнения счетчика\таймера

// ----------------------------
// Инициализация
procedure IRNEC_Init();
begin
  //Настройка порта
  IR_DDR  := 0;   // Пин на ввод
  IR_PORT := 1;   // Включить подтягивающий резистор
  //Настройка таймера/счетчика T0
  TCCR0B := 0x05;                   // настройка тактирования T0 (0x01-clk, 0x02-clk/8, 0x03-clk/64, 0x04-clk/256, 0x05-clk/1024)
  TIMSK  := TIMSK or (1 shl TOIE0); // включить прерывание по переполнению T0
  //Настройка внешнего прерывания
  GIMSK := GIMSK or (1 shl INT0);  // включить внешнее прерывание с вывода INT0
  MCUCR := MCUCR or (1 shl ISC01); // генерация прерывания по спадающему фронту
end;

// ----------------------------
// Проверка готовности данных IR NEC
// ЗНАЧЕНИЕ - результат проверки на готовность принятых данных к чтению (0x00 - данные не готовы, 0xFF - данные готовы)
// ВАЖНО!!!!! если с помощью этой функции определено что имеются поступившие данные, то следом необходимо вызвать
// функцию чтения команды IrNec_GetCommand (), (или сначала IrNec_GetDevice (), а потом IrNec_GetCommand ()),
// только после этого может быть принята следующая команда.
function IRNEC_IsDataReady: Byte;
begin
  Result := 0x00;
  if (NecFlags and bIrNecRcvCmpltd) then
    Result := 0xff;
end;

// ----------------------------
// Чтение данных адреса IR NEC
// ЗНАЧЕНИЕ - номер адресуемого устройства.
function IRNEC_GetDevice: ^Char;
//var
  //pAddr: ^Char; volatile;
begin
  //pAddr^ := NecData[0]; // адрес байта номера устройства в буфере данных
  //Result := pAddr;
  Result := @NEC_Data[0];
end;

// ----------------------------
// Чтение данных команды IR NEC
// ЗНАЧЕНИЕ - принятая команда.
// ВАЖНО!!!!! также тут происходит сброс флага наличия готовых данных bIrNecRcvCmpltd,
// если с помощью функции I_DataCheck() определено, что данные готовы,
// то пока не будет вызвана функция IRNEC_GetCommand (), новые данные не будут приниматся!
function IRNEC_GetCommand: ^Char;
//var
  //pCommand: ^Char; volatile;
begin
  //pCommand^ := NecData[2];  // адрес байта команды в буфере данных
  NecFlags := NecFlags and (not bIrNecRcvCmpltd);  // сброс флага окончания приема данных
  //Result := pCommand;
  Result := @NEC_Data[2];
end;

procedure Timer0_Ovf(); iv IVT_ADDR_TIMER0_OVF; ics ICS_AUTO;
begin
  NecFlags := NecFlags or bIrNecTimerOvf;
end;

procedure Ext_Int0(); iv IVT_ADDR_INT0; ics ICS_AUTO;
var
  val: Byte;
  flags: Byte;
  BitNum: Byte;
  pNEC_Data: ^Char;
begin
  val := TCNT0;                         // копируем и обнуляем счетчик таймера
  TCNT0 := 0;
  flags := NecFlags;                 // копия флагов из волатильной переменной (для увеличения скорости работы )
  if (flags and bIrNecRcvCmpltd) then  //если предыдущие данные не обработаны - выход
    Exit;                              //флаг сбрасывается функцией забирающей данные
  //PIND.6 := 1;
  // Проверка на переполнение
  if (flags and bIrNecTimerOvf) then
  begin
    // Сбросить флаги переполнения и приема (т.е. начать с начала)
    flags := flags and not (bIrNecTimerOvf or bIrNecStreamEnb);
    NecFlags := flags;
    Exit;
  end;

  // Проверка на заголовок пакета
  if ((val > 70) and (val < 140)) then  // 105 - длительность периода импульса старта (берем шире 70 - 140)
  begin
    NecCountBites := 0;                // обнулить счетчик принятых битов
    flags := flags or bIrNecStreamEnb; // установить флаг приема
    NecFlags := flags;
    Exit;
  end;

  // Если прием активен (т.е. заголовок пакета уже был)
  if (flags and bIrNecStreamEnb) then
  begin
    // Проверка на правильность длины импульса
    if ((val < 6) or (val >= 24)) then           // ошибочный размер периода
    begin
      flags := flags and (not bIrNecStreamEnb);  // сбросить флаг приема (т.е. начать с начала)
      NecFlags := flags;
      Exit;
    end;

    // Вычисляем место в буфере, куда поместим принятый бит
    pNEC_Data := @NEC_Data + (NecCountBites shr 3);
    BitNum := 0x80 shr (NecCountBites and 0x07);
    if (val >= 12) then
      pNEC_Data^ := pNEC_Data^ or BitNum         // принятый бит = 1 (бит = 1 если значение 12-23)
    else
      pNEC_Data^ := pNEC_Data^ and (not BitNum); // принятый бит = 0 (бит = 0 если значение 6-11)

    // Проверка, принята ли вся серия IR NEC
    Inc(NecCountBites);
    if (NecCountBites = 32) then
    begin                // Если приняты все 32 бита
      if (not NEC_Data[0] = NEC_Data[1]) then   // сравниваем прямую и инверсную части адреса устройства
        if (not NEC_Data[2] = NEC_Data[3]) then // сравниваем прямую и инверсную части команды
          // данные верны, установить флаг наличия готовых данных
          flags := flags or bIrNecRcvCmpltd;

      flags := flags and (not bIrNecStreamEnb);   // сбросить флаг приема (т.е. начать с начала)
      NecFlags := flags;
    end;
  end;
end;

end.

User avatar
filip
mikroElektronika team
Posts: 11874
Joined: 25 Jan 2008 09:56

Re: Sample IR NEC protocol

#2 Post by filip » 20 Dec 2013 15:33

Hi,

Thank you for this contribution, please share this project on the LibStock as well :)

Regards,
Filip.

Post Reply

Return to “mikroPascal PRO for AVR General”