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.