Похожую задачу решает декодер RC-5, ресурсов при этом тратит минимум: //----------------------------------------------------------------------------
//Декодер RC-5
//----------------------------------------------------------------------------
//Декодер использует два прерывания: внешнее от фотоприемника и
//прерывание по переполнению таймера 0.
//После того, как обнаружен стартовый бит (переход из единицы
//в ноль на входе прерывания), в обработчике внешнего прерывания
//разрешается прерывание таймера 0 и загружается интервал до первой
//выборки T_SAMPLE. В прерывании таймера 0 делаются выборки для
//каждной половинки бита. Подсчет выборок ведется в переменной SampCnt.
//Количество выборок задается константой SAMPLE_COUNT.
//Логический уровень для каждой половинки бита вычисляется по
//мажоритарному принципу. Для этого вычисляется сумма выборок
//в переменной SampVal. Если на входе обнаруживается ВЫСОКИЙ уровень,
//то к этой переменной добавляется единица, если НИЗКИЙ - вычитается.
//Значение суммы не может быть равно нулю, так как общее количество
//выборок всегда задается нечетным. По первой половине текущего бита
//принимается решение о значении принятого бита. Для проверки
//корректности кода Манчестер этот уровень сравнивается со значением
//второй половины предыдущего бита, которое сохраняется в переменной
//PreVal. Если значения совпадают, была ошибка, и прием начинается
//с начала. То же самое происходит, если очередной переход на входе
//не обнаружен через время T_SAMPLE * 2 после последней выборки
//(ошибка таймаута). Принятые биты вдвигаются в переменную Rc5Code.
//Подсчет принятых битов осуществляется в переменной BitCounter.
//Когда принято RC5_LENGTH битов, прием завершен, номер системы
//копируется в переменную SysVar, а код команды - в переменную ComVar.
//Декодер поддерживает Extended RC-5 Code, второй стартовый бит
//интерпретируется как бит F (Field). Бит F представляет собой
//инвертированный дополнительный (старший) бит кода команды,
//в результате количество команд удваивается.
//----------------------------------------------------------------------------
#include "Main.h"
#include "RC5.h"
//----------------------------- Константы: -----------------------------------
#define PRE 64 //предделитель таймера 0
#define RC5_SLOT 1778 //длительность слота RC-5, мкс
#define RC5_LENGTH 14 //количество принимаемых битов
#define SAMPLE_COUNT 3 //количество выборок (должно быть нечетным)
#define T_SAMPLE_US (RC5_SLOT / ((SAMPLE_COUNT + 1) * 2))
#define T_SAMPLE (T_SAMPLE_US * F_CLK / PRE + 0.5)
//----------------------------- Переменные: ----------------------------------
static char SampCnt; //счетчик выборок
static signed char SampVal; //сумма выборок
static bool PreVal; //значение предыдущего полуинтервала
static int RC5Code; //принятый код
static char BitCounter; //счетчик принятых битов
static char SysVar; //номер системы
static char ComVar; //код команды
//-------------------------- Прототипы функций: ------------------------------
#pragma vector = INT0_vect
__interrupt void EdgeIR(void); //прерывание по сигналу фотоприемника
#pragma vector = TIMER0_OVF_vect
__interrupt void TimerIR(void); //прерывание таймера 0
//----------------- Инициализация модуля декодера RC-5: ----------------------
void RC5_Init(void)
{
BitCounter = RC5_LENGTH; //инициализация счетчика битов
PreVal = 1; //перед стартовым битом была единица
SysVar = 0xFF; //неиспользуемый код системы
ComVar = 0xFF; //неиспользуемый код команды
TCCR0 = (1<<CS00) | (1<<CS01); //прескалер CK/64 для таймера 0
MCUCR = (1<<ISC01); //INT0 по спаду
GIFR = (1<<INTF0); //очистка отложенных прерываний
GICR |= (1<<INT0); //разрешение INT0
}
//------------- Обработчик прерывания по сигналу фотоприемника: --------------
#pragma vector = INT0_vect
__interrupt void EdgeIR(void)
{
Port_LED_1;
GICR &= ~(1<<INT0); //запрещение INT0
TCNT0 = 256 - T_SAMPLE; //интервал до первой выборки
TIFR = (1<<TOV0); //очистка отложенных прерываний
TIMSK |= (1<<TOIE0); //разрешение прерываний таймера 0
SampCnt = SAMPLE_COUNT * 2; //общее количесто выборок
SampVal = 0; //очистка принятого значения
}
//------------------ Обработчик прерывания таймера 0: ------------------------
#pragma vector = TIMER0_OVF_vect
__interrupt void TimerIR(void)
{
if(SampCnt) //проверка таймаута
{
if(Pin_RC5) SampVal++; //если на входе единица, инкремент суммы,
else SampVal--; //иначе декремент суммы
if(--SampCnt) //декремент количества выборок
{
if(SampCnt != SAMPLE_COUNT)
{
TCNT0 = 256 - T_SAMPLE; //продолжаем опрашивать
return;
}
else //первая половина интервала закончилась:
{
TCNT0 = 256 - T_SAMPLE * 2; //загрузка интервала между сериями выборок
bool Val = (SampVal > 0); //оценка бита
if(Val != PreVal) //проверка корректности кода Манчестер
{
RC5Code <<= 1; //сдвиг принятого кода
if(!Val) RC5Code |= 1; //первая половина = 0, бит = 1
SampVal = 0; //очистка счетчика выборок
return;
}
}
}
else //вторая половина интервала закончилась:
{
TCNT0 = 256 - T_SAMPLE * 2; //загрузка интервала таймаута
PreVal = (SampVal > 0); //оценка второй половины бита
if(PreVal) //обнаружена единица,
MCUCR &= ~(1<<ISC00); //INT0 по спаду,
else MCUCR |= (1<<ISC00); //иначе INT0 по фронту
GICR |= (1<<INT0); //разрешение INT0
if(--BitCounter) //декремент счетчика битов
return; //переход к приему следующего бита
SysVar = (RC5Code >> 6) & 0x3F; //номер системы
ComVar = RC5Code & 0x3F; //код команды
if(!(RC5Code & 0x1000)) //добавление бита F
ComVar |= 0x40;
}
}
BitCounter = RC5_LENGTH; //загрузка счетчика битов
PreVal = 1; //перед стартовым битом была единица
TIMSK &= ~(1<<TOIE0); //запрещение прерываний таймера 0
MCUCR &= ~(1<<ISC00); //INT0 по спаду
GICR |= (1<<INT0); //разрешение INT0
Port_LED_0;
}
//------------------------- Чтение номера системы: ---------------------------
char RC5_GetSys(void)
{
return(SysVar);
}
//-------------------------- Чтение кода команды: ----------------------------
char RC5_GetCom(void)
{
return(ComVar);
}
//----------------------------------------------------------------------------