Пт мар 22, 2013 02:06:05
//***************************************************************************************************************************
//БИБЛИОТЕКА ОБРАБОТКИ СИГНАЛА ИК ПУЛЬТА ДИСТАНЦИОННОГО УПРАВЛЕНИЯ СТАНДАРТА 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; //флаг переполнения
}
//***************************************************************************************************************************
Пт мар 22, 2013 10:45:32
Пт мар 22, 2013 13:11:39
Дело в том, что в вашем коде реализован и прием и передача, и 36000 нужны только для передачи.....Alkarax писал(а):У вас тут получается частота 8мгц/256/1024=30Гц? Разве не нужно чтобы было 36кГц? или я что-то не так понял
Пт мар 22, 2013 16:20:03
Чуть нижеAlkarax писал(а):где обработчик прерывания?
//Внешнее прерывание INT0 (по спаду сигнала)
ISR (INT0_vect)
Ды не сложно на несколько ходовых частот рассчитать..... сделаем.Alkarax писал(а):кварц в приемнике у меня 12МГц((
Я пишу в AVRStudio4, советую тоже перейти на студию.....Alkarax писал(а):В какой программе вы пишите? Я начал с codevision и там по-мойму биты в байте задаются самостоятельно, т.е. нельзя вписать просто его название и что он устанавливается в 1, нужно знать его номер и там уже ставить единичку. Или я просто еще не дошел до урока где это описывается))
Именно так и попробую заварганить.....Alkarax писал(а):Вообще если в 2 словах то принцип передачи по ик таков: на ножке задаем шим несущей частоты и потом для передачи делаем так, что он то есть определенный промежуток времени, когда идет передача определенной команды команды, то его нет, когда ничего не передается?
Пт мар 22, 2013 17:37:19
Пт мар 22, 2013 20:01:45
Пт мар 22, 2013 20:38:45
Скорее всего, это нормальное явление, т.к. частота 36000 должна модулировать полезный сигнал, тогда сенсор его обрабатывает нормально, а если постоянно подать 36000 то я чет так смутно припоминаю сто сенсор так и должен себя вести.....Alkarax писал(а):У меня почему то при его заливке светодиод на приемнике 1 раз моргает ярко, хорошо и гаснет. Если сбросить мк пульта, на приемнике опять 1 раз моргает и все.
Пт мар 22, 2013 20:56:15
Пт мар 22, 2013 21:06:19
Alkarax писал(а):А как ее теперь сделать полезной, то есть вклчить на 20мкс например? Или вообще как ее включать только по требованию на определенный промежуток времени?
Пт мар 22, 2013 21:52:18
Пт мар 22, 2013 22:18:37
Alkarax писал(а):не хочу париться с разными протоколами для 4х кнопок, просто на каждую разную длительность сигнала повешу и все.
Пт мар 22, 2013 22:59:15
Пт мар 22, 2013 23:38:53
Пт мар 22, 2013 23:43:48
//файлы
#define F_CPU 8000000
#include <util/delay.h>
#include <avr/io.h>
#include <avr/interrupt.h>
//настройка портов
#define IR_PORT PORTB
#define IR_DDR DDRB
#define IR_HF_Line (1<<3)
//объявления функций
void FreqOn (void);
void FreqOff (void);
//основная программа
int main (void)
{
IR_DDR |= (IR_HF_Line);
while (1){
FreqOn (); //включить генерацию
_delay_us (500); //ждем 0,5мс
FreqOff (); //выключить генерацию
_delay_us (500); //ждем 0,5мс
}
}
//включение частоты 36000 Hz
void FreqOn (void)
{
TCCR2 = (1<<FOC2) //принудительное изменение состояния вывода при совпадении
|(1<<CS20)|(0<<CS21)|(0<<CS22) //прямое тактирование от генератора
|(1<<COM20)|(0<<COM21) //состояние вывода меняется на противоположное
|(0<<WGM20)|(1<<WGM21); //режим CTC (сброс при совпадении)
TCNT2 = 0; //просто обнулил счетный регистр
OCR2 = 0b01101111; //при достижении этого значения(111) в счетном регистре будет сброс и переключение ОС2
}
//выключение частоты 36000 Hz
void FreqOff (void)
{
TCCR2 = 0; //выключить генератор 36000 Hz
IR_PORT &= ~IR_HF_Line; //высокочастотный вывод сбросить
}
Пт мар 22, 2013 23:46:13
Пт мар 22, 2013 23:51:46
Alkarax писал(а):Все, с передачей понятно стало, прям по полочкам разложилось все сразу.
Только не пойму
IR_PORT &= ~IR_Line; //сбросить прямой вывод
IR_PORT |= IR_Line; //установить прямой вывод
это что и зачем вообще?
Сб мар 23, 2013 00:00:29
Сб мар 23, 2013 00:18:11
Alkarax писал(а):Теперь про прием:
Сб мар 23, 2013 00:22:03
Сб мар 23, 2013 00:38:29
Alkarax писал(а):Это конечно понятно, что ничего так сразу не понять, поэтому я и задал вопрос-основу. Как считать тики? Внутри внешнего прерывания? Между прерываниями? Или еще как-нибудь?