Чт дек 22, 2016 09:35:00
#define F_CPU 16000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#define PORT_output 0
#define on(X) PORTB|=(1<<(X))
#define off(X) PORTB&=~(1<<(X))
#define invert(X) PORTB^=(1<<(X))
#define pin_on(X) (PINB&(1<<(X)))
//#define ID_code 0xB9
unsigned char i,j;
unsigned char buf_NEC[4] = {0xB9, 0x46, 0, 0};
void timer_1204_init(void);
void transmit_NEC(unsigned char comands);
void timer_off(void);
void decode_bit(void);
void decode_bit(void)
{
if (pin_on(PORT_output) != 0)
{
OCR2 = 70; //560us
}
else
{
if (((buf_NEC[i-1]&(1<<j++)) != 0)&&(pin_on(PORT_output) == 0))
{
OCR2 = 211; //1690us
}
else
{
OCR2 = 70; //560us
}
}
if (j > 7)
{
i++;
j = 0;
}
}
//прерывание сравнения
ISR(TIMER2_COMP_vect)
{
invert(PORT_output);
switch (i)
{
case 0:
OCR2 = 70; //4,5ms
i++;
break;
case 1:
TCCR2&=~(1<<CS21); //предделитель 128
decode_bit();
break;
case 2:
decode_bit();
break;
case 3:
decode_bit();
break;
case 4:
decode_bit();
break;
case 5:
if (pin_on(PORT_output) != 0)
{
OCR2 = 70; //560us
}
else
{
j = 0;
i = 0;
timer_off();
}
break;
}
}
void timer_1204_init(void)
{
TCCR2 |= (1<<CS20)|(1<<CS21)|(1<<CS22)|(1<<WGM21); //предделитель 1024
TIMSK |= (1<<OCIE2); //прерывание по переполнению
sei();
}
void timer_off(void)
{
TCCR2&=~((1<<CS20)|(1<<CS21)|(1<<CS22)); //предделитель 1024
TIMSK&=~(1<<OCIE2); //прерывание по переполнению
}
void transmit_NEC(unsigned char comands)
{
buf_NEC[2] = comands;
buf_NEC[3] = ~comands;
on(PORT_output);
timer_1204_init(); //запускаем счетчик
OCR2 = 140; //9ms
i = 0;
}
int main(void)
{
DDRB|=(1<<0);
off(PORT_output); //выход на транзистор IrDa
/* Replace with your application code */
while (1)
{
transmit_NEC(0x12);
_delay_ms(200);
transmit_NEC(0x13);
_delay_ms(400);
}
}
Ср фев 08, 2017 09:11:17
Вс фев 12, 2017 10:41:33
RIMUS1989i писал(а):shads, А как обработать длинное нажатие?
Вт фев 14, 2017 14:13:01
Пт дек 22, 2017 16:50:03
RIMUS1989i писал(а):shads, А как обработать длинное нажатие?
Вт май 14, 2019 07:16:36
//***************************************************************************************************************************
//БИБЛИОТЕКА ОБРАБОТКИ СИГНАЛА ИК ПУЛЬТА ДИСТАНЦИОННОГО УПРАВЛЕНИЯ СТАНДАРТА NEC
//для частоты контроллера 8000000 Hz
//при работе IR NEC задействован таймер\счетчик T0.
//выход IR сенсора подать на внешнее прерывание INT0
//программа создана SHADS
//НАСТРОЙКА ПОРТА И ВЫВОДА IR СЕНСОРА
#define IR_NEC_PORT PORTD
#define IR_NEC_DDR DDRD
#define IR_NEC_Line (1<<2)
//***************************************************************************************************************************
//переменные и флаги библиотеки
char IrNecData [4]; //массив байтов для приема данных
char IrNecCounBites; //счетчик принятых битов данных
volatile char IrNecFlags; //байт флагов
#define bIrNecStreamEnb (1<<0) /*флаг наличия запущеннного процесса приема серии*/
#define bIrNecRcvCmpltd (1<<1) /*флаг завершения приема данных*/
#define bIrNecTmrOvf (1<<2) /*флаг фиксации переполнения счетчика\таймера*/
//***************************************************************************************************************************
//инициализация работы библиотеки
void IrNecInit (void)
{
//настройка порта
IR_NEC_DDR &= ~IR_NEC_Line; //линия на ввод
IR_NEC_PORT |= IR_NEC_Line; //включить подтяжку
//Настройка таймера/счетчика T0
TCCR0 = 0x05; //настройка тактирования T0 (0x01-clk, 0x02-clk/8, 0x03-clk/64, 0x04-clk/256, 0x05-clk/1024)
TIMSK |= (1<<TOIE0); //включить прерывание по переполнению T0
//Настройка внешнего прерывания
GICR |= (1<<INT0); //включить внешнее прерывание с вывода INT0
MCUCR |= (1<<ISC01); //генерация прерывания по спадающему фронту
}
//***************************************************************************************************************************
//проверка готовности данных IR NEC
//ЗНАЧЕНИЕ - результат проверки на готовность принятых данных к чтению (0x00 - данные не готовы, 0xFF - данные готовы)
//ВАЖНО!!!!! если с помощью этой функции определено что имеются поступившие данные, то следом необходимо вызвать
//функцию чтения команды IrNecCommandGet (), (или сначала IrNecDevNumGet (), а потом IrNecCommandGet ()),
//только после этого может быть принята следующая команда.
char IrNecDataCheck (void)
{
if (IrNecFlags & bIrNecRcvCmpltd)
return 0xff;
return 0x00;
}
//***************************************************************************************************************************
//чтение данных адреса IR NEC
//ЗНАЧЕНИЕ - номер адресуемого устройства.
unsigned char IrNecDevNumGet (void)
{
volatile char* pAddr = &IrNecData[0]; //адрес байта номера устройства в буфере данных
return *pAddr;
}
//***************************************************************************************************************************
//чтение данных команды IR NEC
//ЗНАЧЕНИЕ - принятая команда.
//ВАЖНО!!!!! также тут происходит сброс флага наличия готовых данных bIrNecRcvCmpltd,
//если с помощью функции IrNecDataCheck() определено, что данные готовы,
//то пока не будет вызвана функция IrNecCommandGet (), новые данные не будут приниматся!
unsigned char IrNecCommandGet (void)
{
volatile char* pCommand = &IrNecData[2]; //адрес байта команды в буфере данных
IrNecFlags &= ~bIrNecRcvCmpltd; //сброс флага окончания приема данных
return *pCommand;
}
//***************************************************************************************************************************
//Внешнее прерывание INT0 (по спаду сигнала)
ISR (INT0_vect)
{
uint8_t val = TCNT0; //копируем и обнуляем счетчик таймера
TCNT0 = 0;
char flags = IrNecFlags; //копия флагов из волатильной переменной (для увеличения скорости работы )
if (flags & bIrNecRcvCmpltd) //если предыдущие данные не обработаны - выход
return; //флаг сбрасывается функцией забирающей данные
//проверка на переполнение
if (flags & bIrNecTmrOvf){
flags &= ~(bIrNecTmrOvf | bIrNecStreamEnb); //сбросить флаги переполнения и приема (т.е. начать с начала)
IrNecFlags = flags;
return;
}
//проверка на заголовок пакета
if ((val > 70) && (val < 140)){ //105 - длительность периода импульса старта (берем шире 70 - 140)
IrNecCounBites = 0; //обнулить счетчик принятых битов
flags |= bIrNecStreamEnb; //установить флаг приема
IrNecFlags = flags;
return;
}
//если прием активен (т.е. заголовок пакета уже был)
if (flags & bIrNecStreamEnb){
//проверка на правильность длины импульса
if ((val < 6) || (val >= 24)){ //ошибочный размер периода
flags &= ~bIrNecStreamEnb; //сбросить флаг приема (т.е. начать с начала)
IrNecFlags = flags;
return;
}
//вычисляем место в буфере, куда поместим принятый бит
char* pIrNecData = IrNecData + (IrNecCounBites >> 3);
char BitNum = 0x80 >> (IrNecCounBites & 0x07);
if (val >= 12)
*pIrNecData |= BitNum; //принятый бит = 1 (бит = 1 если значение 12-23)
else
*pIrNecData &= ~BitNum; //принятый бит = 0 (бит = 0 если значение 6-11)
//проверка, принята ли вся серия IR NEC
if (++IrNecCounBites == 32){ //приняты все 32 бита
if ((char)~IrNecData[0] == IrNecData[1]){ //сравниваем прямую и инверсную части адреса устройства
if ((char)~IrNecData[2] == IrNecData[3]) //сравниваем прямую и инверсную части команды
//данные верны - установить флаг наличия готовых данных
flags |= bIrNecRcvCmpltd;
}
flags &= ~bIrNecStreamEnb; //сбросить флаг приема (т.е. начать с начала)
IrNecFlags = flags;
}
}
}
//***************************************************************************************************************************
//Прерывание по переполнению T0
ISR (TIMER0_OVF_vect)
{
IrNecFlags |= bIrNecTmrOvf; //флаг переполнения
}
//***************************************************************************************************************************
Вт май 14, 2019 15:08:58
Чт апр 08, 2021 22:25:00
Пт апр 09, 2021 01:46:59
Пт апр 09, 2021 19:25:22
Сб апр 10, 2021 23:45:35
Пока что для одной частоты (8000000) и константы заданы жестко.
Пт фев 10, 2023 12:36:59
Пт фев 10, 2023 12:45:08
Пт фев 10, 2023 13:11:07
Пт фев 10, 2023 13:15:31
Пт фев 10, 2023 16:26:58
Пт фев 10, 2023 17:35:20
Пт фев 10, 2023 21:37:09
Пт фев 10, 2023 23:42:20