А когда-то давно вот такой приемник RC5 сотворил. Настройка периферии не показана. Потом этот код (правда уже вынесенный из обработчиков прерываний) скрестил с AVR-CDC (на меге8) - работает отлично...
Код
//TSOP подключен к INT0
#include <mega16.h>
#include <stdio.h>
//МАКРОСЫ
#define RC5_SIZE 14
#define PIN_RC 2 /*приемный пин (номер в порту)*/
#define RC5_BIT !(PORTD&(1<<PIN_RC))
//Временные пределы
#define T_MIN 20 /*длинный промежуток (корректируются в соответствии с частотой*/
#define T_MAX 34 /* тактирования таймера Т0)*/
#define T_MIN_SH 11 /*короткий промежуток*/
#define T_MAX_SH 17
//Глобальные переменные (используются в обработчиках и основном цикле, либо для скорости)
unsigned char sct_bit;//Счетчик битов RC5
unsigned char rc5_buffer[RC5_SIZE];//буфер RC5
unsigned char fl_recieve_rc5; //флаг события приема
//структура принятого кода
struct rc5_str{
unsigned char startbit2;
unsigned char trigger;
unsigned char device;
unsigned char command;
}rc5_code;
//--------------Обработчик прерывания по ИЗМЕНЕНИЮ уровня на int0------------------------//
interrupt [EXT_INT0] void ext_int0_isr(void)
{
static unsigned char centre;//флаг центра
unsigned char error=1; //выставляем флаг ошибки, сбросим в теле обработчика, если все ОК...
unsigned char timer_rc5=TCNT0;//запоминаем значение счетчика
TCNT0=0;
switch (sct_bit){
case 0:
TCCR0=0x05; //запускаем таймер (15.625 KHz)
rc5_buffer[sct_bit]=RC5_BIT;//записываем в эл.массива
sct_bit++;
centre=1;
break;
default:
if ((timer_rc5>T_MIN_SH)&&(timer_rc5<T_MAX_SH))//проверка кор. промежутка
{
if (centre){
centre=0;
error=0;
}
else {
centre=1;
rc5_buffer[sct_bit]=RC5_BIT;
sct_bit++;
error=0;
}
}
if ((timer_rc5>T_MIN)&&(timer_rc5<T_MAX)){//проверка длинного промежутка
rc5_buffer [sct_bit]=RC5_BIT;
sct_bit++;
error=0;
}
if (error){// если не попали ни в один из промежутков то
char i;
GICR|=0x00; //запрещаем прерывания по изм. по входу
TCCR0=0x00; //(разрешим в обр. прер. по переполнению счетчика)
TCNT0=0;
sct_bit=0;
//очищаем буффер
for (i=0;i<RC5_SIZE;i++)rc5_buffer[i]=0;
}
if (sct_bit==14){// если бит последний то:
TCCR0 = 0x00; //останавливаем таймер
TCNT0=0;
sct_bit = 0;
//формируем из массива соответствующие коды
rc5_code.startbit2=rc5_buffer[1];
rc5_code.trigger=rc5_buffer[2];
rc5_code.device=(rc5_buffer[3]<<4)|(rc5_buffer[4]<<3)|(rc5_buffer[5]<<2)|(rc5_buffer[6]<<1)|rc5_buffer[7];
rc5_code.command=(rc5_buffer[8]<<5)|(rc5_buffer[9]<<4)|(rc5_buffer[10]<<3)|(rc5_buffer[11]<<2)|(rc5_buffer[12]<<1)|rc5_buffer[13];
fl_recieve_rc5=1; //установили флаг приема
GIFR=0x40; // сбрасываем флаг прерывания по входу INT0
}
}
}
//=============================================================//
//------------ Обработчик прерывания по переполнению Т0 (таймаут)-----------------------//
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
unsigned char i = 0;
GICR|=0x00;
TCCR0=0x00; //останавливаем таймер
TCNT0=0;
sct_bit=0;
//очищаем буффер (его очищать необязательно)
for (i=0;i<RC5_SIZE;i++) rc5_buffer[i]=0;
GICR|=0x40; //разрешаем прерывания по входу
GIFR=0x40;
}
//=============================================================//
...
//пример использования:
//отправляем по UART данные в случае приема кода
if (fl_recieve_rc5){
printf ("StartBit2 %d Trigger %d Device %d Command %d",rc5_code.startbit2, rc5_code.trigger, rc5_code.device, rc5_code.command);
fl_recieve_rc5=0;}
...
P.S. Код чуть подправил для красоты, поэтому могут остаться артефакты...
Любой, заслуживающий внимания, опыт приобретается себе в убыток...