STM32 библиотека работы с ИК пультом (NEC)
-
Ican
- Встал на лапы
- Сообщения: 94
- Зарегистрирован: Вт янв 31, 2012 20:55:18
- Откуда: Екатеринбург
- Контактная информация:
STM32 библиотека работы с ИК пультом (NEC)
Здравствуйте, читатели форума:)
13 страниц форума и ни одного вопроса по управлению с пульта ДУ=)
Уже много времени хотелось разобраться и найти библиотеку декодирования сигналов NEC пультов.
Прочитал теорию, вроде бы всё хорошо и понятно.
С помощью программы RCExplorer (кстати, она сейчас бесплатная. Связался с её автором и он через некоторое время сделал её бесплатной) и давным-давно собранного WinLirc убедился что мой пульт использует NEC протокол. Даже не расширенный.
НО, найденная библиотека почему-то не работает корректно. Зато, как ни странно, декодирует сигналы протокола SANYO (похож на NEC).
Прикладываю "осциллограммы" кнопок пультов. В коде реализуется прием 32 байт. У sanyo их явно больше, но принимаются же!!! а у NEC идет какое-то недополучение (байт 10 не успевают проскочить) Может посмотрите в чём дело? Прикладываю проект в CooCox. Или поделитесь библиотекой для декодирования NEC протокола?
Описание проекта:
Используется таймер TIM2, ИК-фотоприемник подключен по типовой схеме, сигнальный вывод к ножке GPIOA0 (TIM2_CH1).
К отладочной плате подключен 1602 дисплей по четырёхбитной шине.
Добавлю. Принятый код с SANYO на картинке RCExplorer Как мы видим, теряются 10 байт. Что делать - не знаю)
13 страниц форума и ни одного вопроса по управлению с пульта ДУ=)
Уже много времени хотелось разобраться и найти библиотеку декодирования сигналов NEC пультов.
Прочитал теорию, вроде бы всё хорошо и понятно.
С помощью программы RCExplorer (кстати, она сейчас бесплатная. Связался с её автором и он через некоторое время сделал её бесплатной) и давным-давно собранного WinLirc убедился что мой пульт использует NEC протокол. Даже не расширенный.
НО, найденная библиотека почему-то не работает корректно. Зато, как ни странно, декодирует сигналы протокола SANYO (похож на NEC).
Прикладываю "осциллограммы" кнопок пультов. В коде реализуется прием 32 байт. У sanyo их явно больше, но принимаются же!!! а у NEC идет какое-то недополучение (байт 10 не успевают проскочить) Может посмотрите в чём дело? Прикладываю проект в CooCox. Или поделитесь библиотекой для декодирования NEC протокола?
Описание проекта:
Используется таймер TIM2, ИК-фотоприемник подключен по типовой схеме, сигнальный вывод к ножке GPIOA0 (TIM2_CH1).
К отладочной плате подключен 1602 дисплей по четырёхбитной шине.
Добавлю. Принятый код с SANYO на картинке RCExplorer Как мы видим, теряются 10 байт. Что делать - не знаю)
- Вложения
-
- RemoteC.rar
- CooCox IDE 1.7.5
- (265.2 КБ) 439 скачиваний
- Реклама
- AVI-crak
- Прорезались зубы
- Сообщения: 202
- Зарегистрирован: Сб янв 09, 2016 15:51:17
- Контактная информация:
Re: STM32 библиотека работы с ИК пультом (NEC)
Очень странная библиотека, в своё время у меня не завелась, пришлось стряпать своё.
Вся обработка в прерывании по месту события, в последнем правильно принятом бите - вызов задачи декодирования из спячки. Тупой перебор до совпадения.
При зажатой кнопке и верности принимаемых таймингов - декодируется повтор. В случае посторонних помех - декодирование срывается но не искажается, то-есть ложных срабатываний - ноль. Чего собственно мне и требовалось.
Для иной частоты мк -проще менять TIM2->PSC = 720; в пересчёте процентах от 72мгц.
Ось своя собственная,http://forum.ixbt.com/topic.cgi?id=48:11735. Хотя здесь она применяется всего в одном месте sTask_wake(&table_simvol_bits) , можно заменить на свой метод. Но не рекомендую использование без оси - тупой метод перебора жрёт много времени мк.
Вся обработка в прерывании по месту события, в последнем правильно принятом бите - вызов задачи декодирования из спячки. Тупой перебор до совпадения.
При зажатой кнопке и верности принимаемых таймингов - декодируется повтор. В случае посторонних помех - декодирование срывается но не искажается, то-есть ложных срабатываний - ноль. Чего собственно мне и требовалось.
Для иной частоты мк -проще менять TIM2->PSC = 720; в пересчёте процентах от 72мгц.
Ось своя собственная,http://forum.ixbt.com/topic.cgi?id=48:11735. Хотя здесь она применяется всего в одном месте sTask_wake(&table_simvol_bits) , можно заменить на свой метод. Но не рекомендую использование без оси - тупой метод перебора жрёт много времени мк.
Код: Выделить всё
/*
/// таймер TIM2 72мгц - IR , вход CH1 + CH4
TIM2->PSC = 720;
TIM2->CCMR1|=TIM_CCMR1_CC1S_0 | TIM_CCMR1_IC2F_3; //TI1FP1+фильтр
TIM2->CCMR1 |= (TIM_CCMR1_OC2M_2|TIM_CCMR1_OC2M_1);
TIM2->CCMR2|=TIM_CCMR2_CC4S_1 | TIM_CCMR2_IC4F_3; //TI1FP2+фильтр
TIM2->CCR2 = 15800 ; // детектор тишины
TIM2->SMCR = (5<<4) | 4; //TI1FP1+Reset Mode
TIM2->CCER|= TIM_CCER_CC1E | TIM_CCER_CC4P | TIM_CCER_CC4E | TIM_CCER_CC2E;
TIM2->DIER = TIM_DIER_CC1IE | TIM_DIER_CC2IE; // прерывание от захвата и тишины
TIM2->CR1 = TIM_CR1_CEN;
*/
volatile uint32_t data_IR;
volatile char *time2_data;
_bitFlag table_simvol_bits;
_bitFlag time2_data_IR_RE;
#define IR_ZERO_L 56 // время передачи нуля
void TIM2_IRQHandler (void)
{
uint16_t tmp_H;
uint16_t tmp_L;
static uint8_t nomer_bit = 32;
static uint8_t status_bit = 0;
static uint32_t time2_data_IR;
if (TIM2->SR & TIM_SR_CC2IF)
{ TIM2->SR = 0; nomer_bit = 32;status_bit = 0; return;}
else
{
tmp_L = TIM2-> CCR4; tmp_H = (TIM2->CCR1) - tmp_L;
if (status_bit ==0 )
{ if ((tmp_H < ((uint16_t)IR_ZERO_L * 1.25)) && (tmp_L > ((uint16_t)IR_ZERO_L * 7.75))
&& (tmp_L < ((uint16_t)IR_ZERO_L * 8.25)))
{ nomer_bit = 32; time2_data_IR =0;status_bit++;}else; return; }else;
if (status_bit == 1 )
{ if (tmp_H < ((uint16_t)IR_ZERO_L * 1.25))
{ if (tmp_L < ((uint16_t)IR_ZERO_L * 1.25)) nomer_bit--;
else
{ if (tmp_L < ((uint16_t)IR_ZERO_L * 3.25))
{ nomer_bit--; time2_data_IR |= (uint32_t) 1 << nomer_bit;} else;
}
} else status_bit = 0;
if (nomer_bit == 0)
{data_IR = time2_data_IR; sTask_wake(&table_simvol_bits); status_bit++; return;} else;
}else;
if (status_bit == 2 ) // H903-L4000; (H56-L224; H900-L9627;) // (H900-L4000; H56-L228) lg
{ if ((tmp_H > ((uint16_t)IR_ZERO_L * 15.75)) && (tmp_L > ((uint16_t)IR_ZERO_L * 69))
&& (tmp_L < ((uint16_t)IR_ZERO_L * 73))) status_bit++;
else status_bit = 0; return;
}else;
if (status_bit == 3 )
{ if ((tmp_H < ((uint16_t)IR_ZERO_L * 1.25)) && (tmp_L > ((uint16_t)IR_ZERO_L * 3.75))
&& (tmp_L < ((uint16_t)IR_ZERO_L * 4.25))) status_bit++;
else status_bit = 0; return;
}else;
if (status_bit == 4 )
{ if ((tmp_H > ((uint16_t)IR_ZERO_L * 15.75)) && (tmp_L > ((uint16_t)IR_ZERO_L * 166))
&& (tmp_L < ((uint16_t)IR_ZERO_L * 176)))
{status_bit = 3; time2_data_IR_RE = 1;}
else status_bit = 0; return;
}else;
}
}
void table_simvol (void)
{
for(;;)
{
if (data_IR == 0) {time2_data = ".........."; } else;
if (( data_IR >> 16) == 0x00FF) // пульт от плеера
{
data_IR = data_IR & 0xFFFF;
if (data_IR == 0x38c7) {time2_data = "POWER"; } else;
if (data_IR == 0xd22d) {time2_data = "LCD_ON/OF"; } else;
if (data_IR == 0xda25) {time2_data = "MODE"; } else;
if (data_IR == 0x20df) {time2_data = "3D"; } else;
if (data_IR == 0x5aa5) {time2_data = "PROG"; } else;
if (data_IR == 0x50af) {time2_data = "MITE"; } else;
if (data_IR == 0x00ff) {time2_data = "REPEAT"; } else;
if (data_IR == 0x08f7) {time2_data = "A-B"; } else;
if (data_IR == 0xa25d) {time2_data = "1"; } else;
if (data_IR == 0xe817) {time2_data = "2"; } else;
if (data_IR == 0x48b7) {time2_data = "3"; } else;
if (data_IR == 0xb847) {time2_data = "TITLE"; } else;
if (data_IR == 0x28d7) {time2_data = "4"; } else;
if (data_IR == 0xe01f) {time2_data = "5"; } else;
if (data_IR == 0xb04f) {time2_data = "6"; } else;
if (data_IR == 0x1ae5) {time2_data = "ANGLE"; } else;
if (data_IR == 0xd827) {time2_data = "7"; } else;
if (data_IR == 0x926d) {time2_data = "8"; } else;
if (data_IR == 0x22dd) {time2_data = "9"; } else;
if (data_IR == 0x3ac5) {time2_data = "SUBTITLE"; } else;
if (data_IR == 0x9867) {time2_data = "+10"; } else;
if (data_IR == 0x7887) {time2_data = "0"; } else;
if (data_IR == 0x7a85) {time2_data = "MENU"; } else;
if (data_IR == 0xc837) {time2_data = "OSD"; } else;
if (data_IR == 0xf00f) {time2_data = "ZOOM"; } else;
if (data_IR == 0x728d) {time2_data = "CH+"; } else;
if (data_IR == 0x629d) {time2_data = "PBC"; } else;
if (data_IR == 0x9a65) {time2_data = "SLOW"; } else;
if (data_IR == 0x30cf) {time2_data = "<<-"; } else;
if (data_IR == 0x609f) {time2_data = "ENTER"; } else;
if (data_IR == 0xa05f) {time2_data = "->>"; } else;
if (data_IR == 0xc23d) {time2_data = "RETURN"; } else;
if (data_IR == 0xf20d) {time2_data = "AUDIO"; } else;
if (data_IR == 0xb24d) {time2_data = "CH-"; } else;
if (data_IR == 0x32cd) {time2_data = "GOTO"; } else;
if (data_IR == 0xe21d) {time2_data = "SETUP"; } else;
if (data_IR == 0x10ef) {time2_data = "VOL+"; } else;
if (data_IR == 0x42bd) {time2_data = "<<"; } else;
if (data_IR == 0x02fd) {time2_data = ">>"; } else;
if (data_IR == 0xc03f) {time2_data = "STOP"; } else;
if (data_IR == 0x0af5) {time2_data = "VOL-"; } else;
if (data_IR == 0x807f) {time2_data = "|<<"; } else;
if (data_IR == 0x40bf) {time2_data = ">>|"; } else;
if (data_IR == 0x8877) {time2_data = "PLEY"; } else;
}else;
if (( data_IR >> 16) == 0x20DF) // пульт от телека LG
{
data_IR = data_IR & 0xFFFF;
if (data_IR == 0x10ef) {time2_data = "POWER"; } else;
if (data_IR == 0x0ff0) {time2_data = "TV/RADIO"; } else;
if (data_IR == 0x9c63) {time2_data = "SUBTITLE"; } else;
if (data_IR == 0x06f9) {time2_data = "AD(PIP/*)"; } else;
if (data_IR == 0xd926) {time2_data = "TV/PC"; } else;
if (data_IR == 0xd02f) {time2_data = "INPUT"; } else;
if (data_IR == 0x8877) {time2_data = "1"; } else;
if (data_IR == 0x48b7) {time2_data = "2"; } else;
if (data_IR == 0xc837) {time2_data = "3"; } else;
if (data_IR == 0x28d7) {time2_data = "4"; } else;
if (data_IR == 0xa857) {time2_data = "5"; } else;
if (data_IR == 0x6897) {time2_data = "6"; } else;
if (data_IR == 0xe817) {time2_data = "7"; } else;
if (data_IR == 0x18e7) {time2_data = "8"; } else;
if (data_IR == 0x9867) {time2_data = "9"; } else;
if (data_IR == 0xca35) {time2_data = "LIST"; } else;
if (data_IR == 0x08f7) {time2_data = "0"; } else;
if (data_IR == 0x58a7) {time2_data = "Q.VIEW"; } else;
if (data_IR == 0x40bf) {time2_data = "VOL+"; } else;
if (data_IR == 0x7887) {time2_data = "FAV"; } else;
if (data_IR == 0x00ff) {time2_data = "CH+"; } else;
if (data_IR == 0xd52a) {time2_data = "GUIDE"; } else;
if (data_IR == 0xc03f) {time2_data = "VOL-"; } else;
if (data_IR == 0x906f) {time2_data = "MITE"; } else;
if (data_IR == 0x807f) {time2_data = "CH-"; } else;
if (data_IR == 0x4fb) {time2_data = "TEXT"; } else;
if (data_IR == 0x55aa) {time2_data = "INFO"; } else;
if (data_IR == 0x847b) {time2_data = "T.OPT"; } else;
if (data_IR == 0xc23d) {time2_data = "SETTINGS"; } else;
if (data_IR == 0x02fd) {time2_data = "TOP"; } else;
if (data_IR == 0xa25d) {time2_data = "Q.MENU"; } else;
if (data_IR == 0xe01f) {time2_data = "LEFT"; } else;
if (data_IR == 0x22dd) {time2_data = "OK"; } else;
if (data_IR == 0x609f) {time2_data = "RIGHT"; } else;
if (data_IR == 0x14eb) {time2_data = "BACK"; } else;
if (data_IR == 0x827d) {time2_data = "BOTTOM"; } else;
if (data_IR == 0xda25) {time2_data = "EXIT"; } else;
if (data_IR == 0x7e81) {time2_data = "smplink"; } else;
if (data_IR == 0xbd42) {time2_data = "RES/*"; } else;
if (data_IR == 0x8d72) {time2_data = "STOP"; } else;
if (data_IR == 0xf10e) {time2_data = "<<"; } else;
if (data_IR == 0x0df2) {time2_data = "PLEY"; } else;
if (data_IR == 0x5da2) {time2_data = "PAUSE"; } else;
if (data_IR == 0x718e) {time2_data = ">>"; } else;
if (data_IR == 0x4eb1) {time2_data = "RED"; } else;
if (data_IR == 0x8e71) {time2_data = "GREEN"; } else;
if (data_IR == 0xc639) {time2_data = "YELLOW"; } else;
if (data_IR == 0x8679) {time2_data = "BLUE"; } else;
}else;
sTask_wait (&table_simvol_bits);
}- ARV
- Ум, честь и совесть. И скромность.
- Сообщения: 18547
- Зарегистрирован: Чт дек 28, 2006 08:19:56
- Откуда: Новочеркасск
- Контактная информация:
Re: STM32 библиотека работы с ИК пультом (NEC)
трындец какой-то 
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
-
Ican
- Встал на лапы
- Сообщения: 94
- Зарегистрирован: Вт янв 31, 2012 20:55:18
- Откуда: Екатеринбург
- Контактная информация:
Re: STM32 библиотека работы с ИК пультом (NEC)
А у меня не работаетAVI-crak писал(а):У меня работает, а у вас?
Правда, я про свой найденный код. С ОС сталкиваться ой как не хочется - это ж дебри. Если я с портами и таймерами еще не совсем освоился, куда уж ОС....
Ну вот почему он может пропускать 10 байт-то?
Код: Выделить всё
NEC remote power button
NC 0xF4 Инверсия комманды
C 0x0B Комманда
NA 0xF7 инверсия адреса
A 0x08 адрес
received bites | LOST Bites |
F 4 | 0 B | F X | X X
1111 0100 | 0000 1011 | 1111 01LL | LLLL LLLL
- Вложения
-
- NEC1.png
- (14.82 КБ) 451 скачивание
- Реклама
- AVI-crak
- Прорезались зубы
- Сообщения: 202
- Зарегистрирован: Сб янв 09, 2016 15:51:17
- Контактная информация:
Re: STM32 библиотека работы с ИК пультом (NEC)
Ну собственно это и есть проблема, ик передача начинается со старших битов посылки. И первыми есно прилетают 16 бит кода фирмы - уникальный идентификатор принадлежности пульта к железяке, а уже после летит код команды кнопки. Игнорировать идентификатор не желательно, с его помощью можно различать разные пульты.Ican писал(а):А у меня не работаетAVI-crak писал(а):У меня работает, а у вас?
Заполнение идет с конца, т.е. потерянные байты L находятся после стартовой посылки и паузы.
У меня void TIM2_IRQHandler (void) - это банальное прерывание из cmsis, и не имеет зависимости от ос. На выхлопе volatile uint32_t data_IR; - готовая посылка пульта.
Защита от сбоев, левых пультов, засветок и так далее. При любом отклонении от стандарта - процесс декодирования прерывается. Флагами выставляется состояние декодирования: table_simvol_bits - новые данные, time2_data_IR_RE - повтор команды (зажатая кнопка).
Весь список кнопок - это просто вариант, без ос нужно просто опрашивать флаг table_simvol_bits в бесконечном цикле, и проверять на совместимость чего там прилетело.
Хотя бесконечные циклы - огромное зло, и прежде всего в плане энергопотребления.
Алгоритм? - Дык его итак видно, в коде сплошные IF - куда уж проще.
Тут главное понять, что прилетевший на ик датчик тон 38кгц - событие в прошедшем времени, его нельзя отменить каким-либо образом. Это не радиоприёмник, где можно селекцией отстроится от помехи, тут всё топорно и прямолинейно. Есть тон - ик датчик роняет выход в ноль.
Собственно по этому принципу работает счётчик таймера, в момент прерывания по спаду - мы уже имеем на компараторах 1и4 - два значения, общее время и время единицы. Это тоже событие в прошедшем времени, остаётся просто проверить - насколько оно подходит под наши условия. Компаратор таймера CH2 для того - чтобы поймать событие: "кнопка больше не нажата". Это тоже в прошедшем времени, потому как общее время при не нажимании кнопок получается огромным, есть шанс пропустить стартовую посылку. Число в CH2 - это 1,5 максимального времени в посылке, а именно - задержка перед повтором символа "кнопка зажата". Если срабатывает компаратор CH2 - то процесс декодирования устанавливается в начальное время, и так до момента пока не прилетит первая корректная посылка.
Несколько свободных ик библиотек, в том числе и аурдино - все они измеряют время единицы и нуля в реальном времени, собственно мартышкин труд. Особо упорные измеряют время программными задержками. Причём эти библиотеки живут ещё со времён восмибитных пиков, практически без изменений.
-
Ican
- Встал на лапы
- Сообщения: 94
- Зарегистрирован: Вт янв 31, 2012 20:55:18
- Откуда: Екатеринбург
- Контактная информация:
Re: STM32 библиотека работы с ИК пультом (NEC)
Разобрался. Нашел место, где грабли лежат.
было
pos = -10; // change (ТЕРЯЛОСЬ 10 первых байт!!!!)
стало
pos = 0; // change принимается все на ура. Неоптимально, зато принимается.
Всем спасибо, расходимся)
было
pos = -10; // change (ТЕРЯЛОСЬ 10 первых байт!!!!)
стало
pos = 0; // change принимается все на ура. Неоптимально, зато принимается.
Всем спасибо, расходимся)
- Andry_67
- Первый раз сказал Мяу!
- Сообщения: 23
- Зарегистрирован: Пн дек 15, 2014 19:04:08
- Откуда: г. Пермь
Re: STM32 библиотека работы с ИК пультом (NEC)
Внесу свои 5 копеек. Мне тоже понадобилось подключить пульт ДУ. Я все сделал через захват таймера. У меня плата stm32 Mini, там был свободный вход PA8. Это канал захвата №1 таймера 1. Я видел ваши и другие библиотеки и мягко говоря в шоке. Декодирование пульта это довольно простая задача. У меня больше времени ушло на настройку таймера и прерывания.
Выкладываю здесь свой вариант декодирования (только основные моменты). На выходе имеем переменную NecEnd которая равна нулю или 32-битному коду принятому от пульта. После чтения переменной ее необходимо снова сбросить в 0.
uint16_t NecData, NecDataOld, NecD;
uint8_t NecA;
// Пример обработки кода пульта
// Хотя бы 10 раз в секунду выполнять этот код
switch (NecEnd) {
case 0: // Ничего не принято
break;
case 2653519744: // 0x9E297F80
// Обработка клавиши "1"
NecEnd=0; // Обнуляем переменную NecEnd
break;
case 2653536064: // 0x9E29BF40
// Обработка клавиши "2"
NecEnd=0;
break;
case 2653503424: // 0x9E293FC0
// Обработка клавиши "3"
NecEnd=0;
break;
default:
NecEnd=0;
}
// ======================
// Настройка таймера
void TIM1_Configuration(void)
{
// создаём переменную (структуру) для определения режима работы таймера
TIM_TimeBaseInitTypeDef Timert1_Base;
TIM_ICInitTypeDef Timert1_ICI;
// TIM1 clock enable
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
// Базовые настройки таймера
TIM_TimeBaseStructInit(&Timert1_Base);
Timert1_Base.TIM_CounterMode = TIM_CounterMode_Up; // Выбираем режим работы счетчика
Timert1_Base.TIM_Prescaler = 720 - 1; // пред делитель
Timert1_Base.TIM_Period = 0xFFFF; // Коэффициент деления таймера
Timert1_Base.TIM_ClockDivision = TIM_CKD_DIV1; // Определяем частоту для фильтров (tDTS)
Timert1_Base.TIM_RepetitionCounter = 0; // Этот параметр только для Т1 и Т8
TIM_TimeBaseInit(TIM1, &Timert1_Base); // Записываем настройки в регистры
// Настройки каналов таймера на захват
Timert1_ICI.TIM_Channel = TIM_Channel_1; // Выбираем канал (1-4)
Timert1_ICI.TIM_ICPolarity = TIM_ICPolarity_Falling; // Определяем полярность входа
Timert1_ICI.TIM_ICSelection = TIM_ICSelection_DirectTI; // источник: напрямую со входа
Timert1_ICI.TIM_ICPrescaler = TIM_ICPSC_DIV1; // Значение предделителя канала (отключен)
Timert1_ICI.TIM_ICFilter = 15; // Значение фильтра от 0x0 до 0xF
TIM_ICInit(TIM1, &Timert1_ICI); // Записываем настройки в регистры
// На всякий случай сбрасываем флаги
TIM_ClearFlag(TIM1, TIM_IT_CC1);
// Разрешаем таймеру генерировать прерывание по захвату 1ый канал
TIM_ITConfig(TIM1, TIM_IT_CC1, ENABLE);
// Разрешаем ядру принимать прерывания
NVIC_EnableIRQ(TIM1_CC_IRQn);
// ЗАПУСК таймера TIM1
TIM_Cmd(TIM1, ENABLE);
}
// ======================
// Настройка прерывания
void TIM1_CC_IRQHandler(void)
{
// Смотрим что прерывание от таймера именно по событию захвата 1-ого канала
if (TIM_GetITStatus(TIM1, TIM_IT_CC1) != RESET)
{
NecDataOld = NecData;
NecData = TIM_GetCapture1(TIM1); // Читаем значение из регистра захвата
TIM_ClearITPendingBit(TIM1, TIM_IT_CC1); // Очищаем флаг этого прерывания
NecD=NecData-NecDataOld;
switch (NecA) {
case 0:
if (1115<NecD && 1135>NecD){ // повтор
// NecEnd=1; // Раскомментировать строку если нужен повтор
}
else
{
if (1340<NecD && 1360>NecD) NecA=1; // стартовый импульс
}
break;
case 1:
if (100<NecD && 235>NecD){
NecA=2;
}
else
{
NecA=0;
return; // ошибка выходим
}
default:
if (100<NecD && 235>NecD){
NecA++;
NecB = (NecB<<1)+NecD/175; // принимаем 32 бита данных
if (NecA==34){
NecEnd=NecB; // данные приняты успешно
NecA=0;
}
}
else
{
NecA=0;
return; // ошибка выходим
}
}
}
}
Выкладываю здесь свой вариант декодирования (только основные моменты). На выходе имеем переменную NecEnd которая равна нулю или 32-битному коду принятому от пульта. После чтения переменной ее необходимо снова сбросить в 0.
Спойлер
uint32_t NecEnd, NecB; // Эти переменные нужно объявить в началеuint16_t NecData, NecDataOld, NecD;
uint8_t NecA;
// Пример обработки кода пульта
// Хотя бы 10 раз в секунду выполнять этот код
switch (NecEnd) {
case 0: // Ничего не принято
break;
case 2653519744: // 0x9E297F80
// Обработка клавиши "1"
NecEnd=0; // Обнуляем переменную NecEnd
break;
case 2653536064: // 0x9E29BF40
// Обработка клавиши "2"
NecEnd=0;
break;
case 2653503424: // 0x9E293FC0
// Обработка клавиши "3"
NecEnd=0;
break;
default:
NecEnd=0;
}
// ======================
// Настройка таймера
void TIM1_Configuration(void)
{
// создаём переменную (структуру) для определения режима работы таймера
TIM_TimeBaseInitTypeDef Timert1_Base;
TIM_ICInitTypeDef Timert1_ICI;
// TIM1 clock enable
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
// Базовые настройки таймера
TIM_TimeBaseStructInit(&Timert1_Base);
Timert1_Base.TIM_CounterMode = TIM_CounterMode_Up; // Выбираем режим работы счетчика
Timert1_Base.TIM_Prescaler = 720 - 1; // пред делитель
Timert1_Base.TIM_Period = 0xFFFF; // Коэффициент деления таймера
Timert1_Base.TIM_ClockDivision = TIM_CKD_DIV1; // Определяем частоту для фильтров (tDTS)
Timert1_Base.TIM_RepetitionCounter = 0; // Этот параметр только для Т1 и Т8
TIM_TimeBaseInit(TIM1, &Timert1_Base); // Записываем настройки в регистры
// Настройки каналов таймера на захват
Timert1_ICI.TIM_Channel = TIM_Channel_1; // Выбираем канал (1-4)
Timert1_ICI.TIM_ICPolarity = TIM_ICPolarity_Falling; // Определяем полярность входа
Timert1_ICI.TIM_ICSelection = TIM_ICSelection_DirectTI; // источник: напрямую со входа
Timert1_ICI.TIM_ICPrescaler = TIM_ICPSC_DIV1; // Значение предделителя канала (отключен)
Timert1_ICI.TIM_ICFilter = 15; // Значение фильтра от 0x0 до 0xF
TIM_ICInit(TIM1, &Timert1_ICI); // Записываем настройки в регистры
// На всякий случай сбрасываем флаги
TIM_ClearFlag(TIM1, TIM_IT_CC1);
// Разрешаем таймеру генерировать прерывание по захвату 1ый канал
TIM_ITConfig(TIM1, TIM_IT_CC1, ENABLE);
// Разрешаем ядру принимать прерывания
NVIC_EnableIRQ(TIM1_CC_IRQn);
// ЗАПУСК таймера TIM1
TIM_Cmd(TIM1, ENABLE);
}
// ======================
// Настройка прерывания
void TIM1_CC_IRQHandler(void)
{
// Смотрим что прерывание от таймера именно по событию захвата 1-ого канала
if (TIM_GetITStatus(TIM1, TIM_IT_CC1) != RESET)
{
NecDataOld = NecData;
NecData = TIM_GetCapture1(TIM1); // Читаем значение из регистра захвата
TIM_ClearITPendingBit(TIM1, TIM_IT_CC1); // Очищаем флаг этого прерывания
NecD=NecData-NecDataOld;
switch (NecA) {
case 0:
if (1115<NecD && 1135>NecD){ // повтор
// NecEnd=1; // Раскомментировать строку если нужен повтор
}
else
{
if (1340<NecD && 1360>NecD) NecA=1; // стартовый импульс
}
break;
case 1:
if (100<NecD && 235>NecD){
NecA=2;
}
else
{
NecA=0;
return; // ошибка выходим
}
default:
if (100<NecD && 235>NecD){
NecA++;
NecB = (NecB<<1)+NecD/175; // принимаем 32 бита данных
if (NecA==34){
NecEnd=NecB; // данные приняты успешно
NecA=0;
}
}
else
{
NecA=0;
return; // ошибка выходим
}
}
}
}
- AVI-crak
- Прорезались зубы
- Сообщения: 202
- Зарегистрирован: Сб янв 09, 2016 15:51:17
- Контактная информация:
Re: STM32 библиотека работы с ИК пультом (NEC)
Andry_67
Нет защиты от помех.
Поиграйся двумя разными пультами одновременно, должно быть либо честное декодирование - либо сброс посылки.
Нет защиты от помех.
Поиграйся двумя разными пультами одновременно, должно быть либо честное декодирование - либо сброс посылки.
- Andry_67
- Первый раз сказал Мяу!
- Сообщения: 23
- Зарегистрирован: Пн дек 15, 2014 19:04:08
- Откуда: г. Пермь
Re: STM32 библиотека работы с ИК пультом (NEC)
Защита от помех есть. В строке
if (100<NecD && 235>NecD){
проверяется длительность между двумя импульсами и если длительность выходит за пределы то декодирование прекращается и ожидается новый стартовый импульс.
if (100<NecD && 235>NecD){
проверяется длительность между двумя импульсами и если длительность выходит за пределы то декодирование прекращается и ожидается новый стартовый импульс.
А не надо одновременно жать на разные пульты, в этом случае ни у кого ничего работать не будет.Поиграйся двумя разными пультами одновременно
- AVI-crak
- Прорезались зубы
- Сообщения: 202
- Зарегистрирован: Сб янв 09, 2016 15:51:17
- Контактная информация:
Re: STM32 библиотека работы с ИК пультом (NEC)
Допрограмировался, в поисках нахожу своё старое.
В гитхаб теперь только через телефон, bitbucket.org просто стёр всё мои каракули, ещё парочка репозитариев успела пять раз в прыжке переобуться, а один уникальный склад кода - умудрился буквально сгореть, вместе с датацентром.
А тут даже пылью не покрылось.
ik_nec.с
ik_nec.h
Написано для мелкого stm32f030f, требует таймера с поддержкой PWM Input и одним свободным контактом CH1. По протоколу NEC - необходимо выполнить реверс битов в каждом байте, с сохранением порядка байтов. Но мне лень.
В гитхаб теперь только через телефон, bitbucket.org просто стёр всё мои каракули, ещё парочка репозитариев успела пять раз в прыжке переобуться, а один уникальный склад кода - умудрился буквально сгореть, вместе с датацентром.
А тут даже пылью не покрылось.
ik_nec.с
Спойлер
Код: Выделить всё
/// IK protocol NEC
/// TIMx->PSC = clock frequency of the timer / 50526
#include <stdint.h>
#include "ik_nec.h"
#include "stm32f030x6.h"
#define IK_N 0xFFU /* unnamed china */
//#define IK_N 0xDFU /* LG */
#define DECODER ((uint16_t)((~IK_N)<<8)|IK_N)
volatile uint8_t ik_out;
const uint16_t range_z[] ={
628,1167,35,66,35,66,634,1177,0,0,
76,278,76,278,2890,12759,798,1483,2890,12759,949,1764};
void TIM3_IRQHandler (void) //220
{
uint32_t tmp;
static uint8_t status = 0;
static uint8_t poz;
static uint32_t stor;
if ((TIM3->SR & (TIM_SR_CC1IF | TIM_SR_CC2IF | TIM_SR_CC3IF | TIM_SR_CC4IF))
!= (TIM_SR_CC1IF | TIM_SR_CC2IF | TIM_SR_CC3IF)) goto uno;
tmp = TIM3->CCR2;
if (tmp < range_z[status << 1]) goto uno;
if (tmp > range_z[(status << 1) + 1]) goto uno;
switch (status)
{
case 0: status = 1; poz = 32; stor = 0; tmp = 10; break;
case 1: tmp = stor << 1;
if (TIM3->CCR1 > 170) tmp |= 1;
stor = tmp; poz--; tmp = 12;
if (poz == 0)
{
/// watch raw IR code
/// stor = (~IK_N<<24)|(IK_N<<16)|(~ik_out<<8)|(ik_out)
if ((DECODER == (stor >> 16)) && ((((stor >> 8) ^ stor) & 0xFF) == 0xFF))
{
stor &= 0xFF; ik_out = stor; tmp = 14; status = 2;
}else goto uno;
}; break;
case 2: status = 3; tmp = 16; break;
case 3: status = 2; tmp = 18; ik_out = stor; break;
default: uno: status = 0; tmp = 20; break;
};
TIM3->SR = 0;
TIM3->CCR3 = range_z[tmp++];
TIM3->CCR4 = range_z[tmp];
};
void ik_tim_init(void)
{
RCC->APB1ENR |= RCC_APB1ENR_TIM3EN;
RCC->AHBENR |= RCC_AHBENR_GPIOAEN;
GPIOA->MODER |= _VAL2FLD(GPIO_MODER_MODER6, 2); //Alternate function mode
GPIOA->AFR[0] |= _VAL2FLD(GPIO_AFRL_AFSEL6, 1);
TIM3->PSC = 950; /// clock frequency of the timer / 50526 (509us = 51L)
TIM3->CCMR1 = _VAL2FLD(TIM_CCMR1_CC1S, 1)|
_VAL2FLD(TIM_CCMR1_CC2S, 2);
TIM3->CCER = _VAL2FLD(TIM_CCER_CC1P, 1)|
_VAL2FLD(TIM_CCER_CC2P, 0)|
_VAL2FLD(TIM_CCER_CC1E, 1)|
_VAL2FLD(TIM_CCER_CC2E, 1);
TIM3->SMCR = _VAL2FLD(TIM_SMCR_TS, 5)| // Filtered Timer Input 1 (TI1FP1)
_VAL2FLD(TIM_SMCR_SMS, 4); // Reset Mode (TRGI)
TIM3->CCMR2 = _VAL2FLD(TIM_CCMR2_OC3M,6)|
_VAL2FLD(TIM_CCMR2_OC4M,6);
TIM3->CCR3 = 949; // 1357 start P
TIM3->CCR4 = 1764;
TIM3->DIER = TIM_DIER_CC1IE;
TIM3->CR1 |= TIM_CR1_CEN;
NVIC_EnableIRQ(TIM3_IRQn);
}
Спойлер
Код: Выделить всё
/// #include "ik_nec.h"
#ifdef _ik_nec_
extern "C" {
#endif /* _ik_nec_ */
extern volatile uint8_t ik_out;
void ik_tim_init(void);
#ifdef _ik_nec_
}
#endif /* _ik_nec_ */
#define _ik_nec_
- zenon
- Сверлит текстолит когтями
- Сообщения: 1274
- Зарегистрирован: Вт окт 23, 2007 10:01:42
- Откуда: Волгоград
- Контактная информация:
Re: STM32 библиотека работы с ИК пультом (NEC)
AVI-crak, спасибо тебе добрый человек за рабочий код для cmsis!
Оно заработало.
Дефайны только дёрнул, не знаю можно так?
В моей cmsis их не нашлось, надо бы обновить, только не разобрался откуда правильно взять.
И TIM3->PSC = 570; поставить для 48MHz пришлось.
У тебя 950 стоит, с таким значением попадаю только при 80MHz (RCC_CFGR_PLLMUL10) .
STM32F030K6T6.
А, вот ещё, сырой код (stor) без декодирования не получилось принять , поковыряю ещё...
Оно заработало.
Дефайны только дёрнул, не знаю можно так?
Спойлер
Код: Выделить всё
#define _VAL2FLD(field, value) (((uint32_t)(value) << field ## _Pos) & field ## _Msk)
//
#define GPIO_MODER_MODER6_Pos (12U)
#define GPIO_MODER_MODER6_Msk (0x3U << GPIO_MODER_MODER6_Pos) /*!< 0x00003000 */
#define GPIO_AFRL_AFSEL6_Pos (24U)
#define GPIO_AFRL_AFSEL6_Msk (0xFU << GPIO_AFRL_AFSEL6_Pos) /*!< 0x0F000000 */
//
#define TIM_SMCR_TS_Pos (4U)
#define TIM_SMCR_TS_Msk (0x7UL << TIM_SMCR_TS_Pos) /*!< 0x00000070 */
#define TIM_CCMR1_CC1S_Pos (0U)
#define TIM_CCMR1_CC1S_Msk (0x3UL << TIM_CCMR1_CC1S_Pos) /*!< 0x00000003 */
#define TIM_CCMR1_CC2S_Pos (8U)
#define TIM_CCMR1_CC2S_Msk (0x3UL << TIM_CCMR1_CC2S_Pos) /*!< 0x00000300 */
#define TIM_CCER_CC1P_Pos (1U)
#define TIM_CCER_CC1P_Msk (0x1UL << TIM_CCER_CC1P_Pos) /*!< 0x00000002 */
#define TIM_CCER_CC2P_Pos (5U)
#define TIM_CCER_CC2P_Msk (0x1UL << TIM_CCER_CC2P_Pos) /*!< 0x00000020 */
#define TIM_CCER_CC1E_Pos (0U)
#define TIM_CCER_CC1E_Msk (0x1UL << TIM_CCER_CC1E_Pos) /*!< 0x00000001 */
#define TIM_CCER_CC2E_Pos (4U)
#define TIM_CCER_CC2E_Msk (0x1UL << TIM_CCER_CC2E_Pos) /*!< 0x00000010 */
#define TIM_SMCR_SMS_Pos (0U)
#define TIM_SMCR_SMS_Msk (0x7UL << TIM_SMCR_SMS_Pos) /*!< 0x00000007 */
#define TIM_CCMR2_OC3M_Pos (4U)
#define TIM_CCMR2_OC3M_Msk (0x7UL << TIM_CCMR2_OC3M_Pos) /*!< 0x00000070 */
#define TIM_CCMR2_OC4M_Pos (12U)
#define TIM_CCMR2_OC4M_Msk (0x7UL << TIM_CCMR2_OC4M_Pos) /*!< 0x00007000 */
И TIM3->PSC = 570; поставить для 48MHz пришлось.
У тебя 950 стоит, с таким значением попадаю только при 80MHz (RCC_CFGR_PLLMUL10) .
STM32F030K6T6.
А, вот ещё, сырой код (stor) без декодирования не получилось принять , поковыряю ещё...
Re: STM32 библиотека работы с ИК пультом (NEC)
На правах рекламы, можно сказать, тоже предложу вариант решения (подсмотрено на easyelectronics)
Использовать максимально просто, вот пример:
Спойлер
Код: Выделить всё
/**
* @brief Class for IR receiver
*
* @tparam _Timer GP timer instance
* @tparam _Pin Input pin
* @tparam _Decoder Decoder
*/
template <typename _Timer, typename _Pin, typename _Decoder>
class IrReceiver
{
using InputCaptureFalling = typename _Timer::InputCapture<0>;
using InputCaptureRising = typename _Timer::InputCapture<1>;
using TimeoutOCChannel = typename _Timer::OutputCompare<2>;
public:
/**
* @brief Init receiver
*
* @par Returns
* Nothing
*/
static void Init()
{
_Timer::Enable();
_Timer::SetPrescaler(_Timer::GetClockFreq() / 1000000 * 2 - 1); // 1us period
_Timer::SetPeriod(0xffff);
_Timer::SlaveMode::SelectTrigger(_Timer::SlaveMode::Trigger::FilteredTimerInput1);
_Timer::SlaveMode::EnableSlaveMode(_Timer::SlaveMode::Mode::ResetMode);
InputCaptureFalling::SetCapturePolarity(InputCaptureFalling::CapturePolarity::FallingEdge);
InputCaptureFalling::SetCaptureMode(InputCaptureFalling::CaptureMode::Direct);
InputCaptureFalling::EnableInterrupt();
InputCaptureFalling::Enable();
InputCaptureRising::SetCapturePolarity(InputCaptureRising::CapturePolarity::RisingEdge);
InputCaptureRising::SetCaptureMode(InputCaptureRising::CaptureMode::Indirect);
InputCaptureRising::EnableInterrupt();
InputCaptureRising::Enable();
TimeoutOCChannel::SetPulse(15'000);
_Pin::Port::Enable();
_Pin::template SetConfiguration<_Pin::Configuration::In>();
_Pin::template SetPullMode<_Pin::PullMode::PullUp>();
_Timer::Start();
}
/**
* @brief Timer IRQ handler (call this method in TIMx_IRQHandler)
*
* @par Returns
* Nothing
*/
static void IRQHandler()
{
static bool idleState = true;
if(InputCaptureFalling::IsInterrupt()) {
InputCaptureFalling::ClearInterruptFlag();
uint16_t width = InputCaptureFalling::GetValue();
uint16_t pulse = InputCaptureRising::GetValue();
if(idleState) {
idleState = false;
TimeoutOCChannel::EnableInterrupt();
}
else {
if(IsSimilar<_Decoder::StartWidth>(width) && IsSimilar<_Decoder::StartPulse>(pulse)) {
_Decoder::Start();
}
else if(IsSimilar<_Decoder::Width0>(width) && IsSimilar<_Decoder::Pulse0>(pulse)) {
_Decoder::Add0();
}
else if(IsSimilar<_Decoder::Width1>(width) && IsSimilar<_Decoder::Pulse1>(pulse)) {
_Decoder::Add1();
}
else {
idleState = true;
}
}
}
if (TimeoutOCChannel::IsInterrupt()) {
TimeoutOCChannel::DisableInterrupt();
TimeoutOCChannel::ClearInterruptFlag();
if(!idleState) {
idleState = true;
_Decoder::Handle();
}
}
}
private:
/**
* @brief Compare received value with decoder constant with given accuracy
*
* @tparam _TargetValue Constant
* @param value Received value
*
* @return true If value ~ _TargetValue
* @return false If value != _TargetValue
*/
template<uint16_t _TargetValue>
inline static bool IsSimilar(uint16_t value)
{
return ((_TargetValue * (100 - _Decoder::EpsilonInPercent) / 100) < value) && (value < (_TargetValue * (100 + _Decoder::EpsilonInPercent) / 100));
}
};
/**
* @brief NEC decoder
*/
class NecDecoder
{
public:
static const uint16_t StartWidth = 13500;
static const uint16_t StartPulse = 9000;
static const uint16_t Width0 = 1125;
static const uint16_t Pulse0 = 562;
static const uint16_t Width1 = 2250;
static const uint16_t Pulse1 = 562;
static const uint16_t EpsilonInPercent = 20;
/// Command
/// @todo Add commands
enum Command : uint16_t
{
NoCommand = 0
};
using Callback = std::add_pointer_t<void(Command command)>;
/**
* @brief Set the callback for command receive
*
* @param callback Callback
*
* @par Returns
* Nothing
*/
static void SetCallback(Callback callback)
{
_callback = callback;
}
/**
* @brief Start new frame
*
* @par Returns
* Nothing
*/
static void Start()
{
_frame = 0;
}
/**
* @brief Add bit 0 to frame
*
* @par Returns
* Nothing
*/
static void Add0()
{
_frame >>= 1;
}
/**
* @brief Add bit 1 to frame
*
* @par Returns
* Nothing
*/
static void Add1()
{
_frame = (_frame >> 1) | 0x80000000;
}
/**
* @brief End of frame (pause detect) handler
*
* @par Returns
* Nothing
*/
static void Handle()
{
if ((_frame & 0xff000000) != ( (~(_frame) & 0x00ff0000) << 8)) {
return;
}
if ((_frame & 0xff00) != (((~_frame) & 0x00ff) << 8)) {
return;
}
uint16_t command = ((_frame & 0xff000000) >> 16) | ((_frame & 0xff00) >> 8);
if(_callback)
_callback(static_cast<Command>(command));
}
private:
static uint32_t _frame;
static Callback _callback;
};
uint32_t NecDecoder::_frame;
NecDecoder::Callback NecDecoder::_callback;
Спойлер
Код: Выделить всё
#include <clock.h>
#include <iopins.h>
#include <timer.h>
#include <drivers/ir.h>
using namespace Zhele;
using namespace Zhele::Drivers;
using namespace Zhele::IO;
using namespace Zhele::Timers;
using namespace Zhele::Clock;
void ConfigureClock();
void ConfigureOutputPwm();
void ConfigureInputCapture();
using Receiver = IrReceiver<Timer4, Pb6, NecDecoder>;
int main()
{
ConfigureClock();
Receiver::Init();
NecDecoder::SetCallback([](NecDecoder::Command command) {
// Do smth
});
for (;;)
{
}
}
void ConfigureClock()
{
PllClock::SelectClockSource(PllClock::ClockSource::External);
PllClock::SetMultiplier(9);
Apb1Clock::SetPrescaler(Apb1Clock::Div2);
SysClock::SelectClockSource(SysClock::Pll);
}
extern "C"
{
void TIM4_IRQHandler()
{
Receiver::IRQHandler();
}
}
- AVI-crak
- Прорезались зубы
- Сообщения: 202
- Зарегистрирован: Сб янв 09, 2016 15:51:17
- Контактная информация:
Re: STM32 библиотека работы с ИК пультом (NEC)
[uquote="zenon",url="/forum/viewtopic.php?p=4336639#p4336639"]Дефайны только дёрнул, не знаю можно так?[/uquote]
Раньше-бы посоветовал дёрнуть из кубика от st, но сейчас всё свежее приходится искать на гитхабе.
https://github.com/STMicroelectronics/c ... er/Include
Раньше-бы посоветовал дёрнуть из кубика от st, но сейчас всё свежее приходится искать на гитхабе.
https://github.com/STMicroelectronics/c ... er/Include
- zenon
- Сверлит текстолит когтями
- Сообщения: 1274
- Зарегистрирован: Вт окт 23, 2007 10:01:42
- Откуда: Волгоград
- Контактная информация:
Re: STM32 библиотека работы с ИК пультом (NEC)
А можно ли перекинуть на другой таймер?
Попробовал в лоб изменить на 14 или 16 ... не вышло.
Инит:
Обработчик:
Попробовал в лоб изменить на 14 или 16 ... не вышло.
Инит:
Код: Выделить всё
del
Код: Выделить всё
del
Последний раз редактировалось zenon Вс янв 22, 2023 09:49:04, всего редактировалось 1 раз.
Re: STM32 библиотека работы с ИК пультом (NEC)
Если контроллер F100RB, то у таймера 16 всего 1 канал (у 15 их два, если что), так что эта реализация неприменима.
- zenon
- Сверлит текстолит когтями
- Сообщения: 1274
- Зарегистрирован: Вт окт 23, 2007 10:01:42
- Откуда: Волгоград
- Контактная информация:
Re: STM32 библиотека работы с ИК пультом (NEC)
Хм. У меня F030K6T6, о 32-х ногах, те, если я правильно понял на PA2 можно повесить?
фиг там, нет у меня 15-го
фиг там, нет у меня 15-го
- AVI-crak
- Прорезались зубы
- Сообщения: 202
- Зарегистрирован: Сб янв 09, 2016 15:51:17
- Контактная информация:
Re: STM32 библиотека работы с ИК пультом (NEC)
[uquote="zenon",url="/forum/viewtopic.php?p=4358383#p4358383"]А можно ли перекинуть на другой таймер?[/uquote]
При работе с st чипами необходимо иметь STM32Cube, скачивать любым доступным способом. Это приложение необходимо для наглядного выбора периферии, и ротации ног. Что-бы не гадать на чайной гуще, и не курить тонны документации в поиске доступного варианта решения.
Таймер должен уметь работать в режиме "PWM input", и иметь контакт на ногу чипа.
При работе с st чипами необходимо иметь STM32Cube, скачивать любым доступным способом. Это приложение необходимо для наглядного выбора периферии, и ротации ног. Что-бы не гадать на чайной гуще, и не курить тонны документации в поиске доступного варианта решения.
Таймер должен уметь работать в режиме "PWM input", и иметь контакт на ногу чипа.
Re: STM32 библиотека работы с ИК пультом (NEC)
[uquote="AVI-crak",url="/forum/viewtopic.php?p=4358494#p4358494"]Таймер должен уметь работать в режиме "PWM input", и иметь контакт на ногу чипа.[/uquote]
У меня все ограничения в либах прописаны, по старинке обхожуcь без кубов
Скомпилируется только если подставить подходящий таймер, канал и пин.
У меня все ограничения в либах прописаны, по старинке обхожуcь без кубов
Спойлер
Код: Выделить всё
template<TimCh Channel>
class Remote
{
using Tim = Channel::Timer;
static constexpr uint32_t chNum = Channel::number();
static_assert(chNum <= 3);
static_assert(Tim::hasFeatures(TimFeature::SlaveCtrl), "TimFeature::SlaveCtrl is Required!");
static_assert(chNum == 1 || Tim::hasFeatures(TimFeature::Xor), "TimFeature::Xor is Required!");
.........
};
Remote<Tim3Ch2<PA7>> remote;
- zenon
- Сверлит текстолит когтями
- Сообщения: 1274
- Зарегистрирован: Вт окт 23, 2007 10:01:42
- Откуда: Волгоград
- Контактная информация:
Re: STM32 библиотека работы с ИК пультом (NEC)
AVI-crak, да ну его этот куб, у меня от него зуд... лучше покопашусь по-своему, задач каких-то у меня нет, так потихоньку то с одним, то с другим разобраться...
Ноги поменять глянув в даташит вообще труда не составляет.
В общем на TIM1 перекинул, теперь TIM3 освободился для энкодера.
TIM14 вроде умеет PWM Input, но на него не перекинуть.
Ноги поменять глянув в даташит вообще труда не составляет.
В общем на TIM1 перекинул, теперь TIM3 освободился для энкодера.
TIM14 вроде умеет PWM Input, но на него не перекинуть.
Спойлер
Код: Выделить всё
void ik_tim_init(void) {
RCC->APB2ENR |= RCC_APB2ENR_TIM1EN; // 1-й таймер
// TIM1_CH1 PA8 AF2
RCC->AHBENR |= RCC_AHBENR_GPIOAEN;
GPIOA->MODER |= _VAL2FLD(GPIO_MODER_MODER8, 2); // Ногу в альтернативную функцию
GPIOA->AFR[1] |= _VAL2FLD(GPIO_AFRH_AFSEL8, 2); //
TIM1->PSC = 480;//340;//950;//400; //950; /// clock frequency of the timer / 50526 (509us = 51L) // TIM prescaler register
TIM1->CCMR1 = _VAL2FLD(TIM_CCMR1_CC1S, 1)|
_VAL2FLD(TIM_CCMR1_CC2S, 2);
TIM1->CCER = _VAL2FLD(TIM_CCER_CC1P, 1)|
_VAL2FLD(TIM_CCER_CC2P, 0)|
_VAL2FLD(TIM_CCER_CC1E, 1)|
_VAL2FLD(TIM_CCER_CC2E, 1);
TIM1->SMCR = _VAL2FLD(TIM_SMCR_TS, 5)| // Filtered Timer Input 1 (TI1FP1)
_VAL2FLD(TIM_SMCR_SMS, 4); // Reset Mode (TRGI)
TIM1->CCMR2 = _VAL2FLD(TIM_CCMR2_OC3M,6)|
_VAL2FLD(TIM_CCMR2_OC4M,6);
TIM1->CCR3 = 949; //949; // 1357 start P
TIM1->CCR4 = 1764;
TIM1->DIER = TIM_DIER_CC1IE;
TIM1->CR1 |= TIM_CR1_CEN;
NVIC_EnableIRQ(TIM1_CC_IRQn);
}
Код: Выделить всё
void TIM1_CC_IRQHandler(void) { //
uint32_t tmp;
static uint8_t status = 0;
static uint8_t poz;
static uint32_t stor;
if ((TIM1->SR & (TIM_SR_CC1IF | TIM_SR_CC2IF | TIM_SR_CC3IF | TIM_SR_CC4IF))
!= (TIM_SR_CC1IF | TIM_SR_CC2IF | TIM_SR_CC3IF)) goto uno;
tmp = TIM1->CCR2;
if (tmp < range_z[status << 1]) goto uno;
if (tmp > range_z[(status << 1) + 1]) goto uno;
switch (status) {
case 0: status = 1; poz = 32; stor = 0; tmp = 10; break;
case 1: tmp = stor << 1;
if (TIM1->CCR1 > 170) tmp |= 1;
stor = tmp; poz--; tmp = 12;
if (poz == 0) {
/// watch raw IR code
/// stor = (~IK_N<<24)|(IK_N<<16)|(~ik_out<<8)|(ik_out)
//if ((DECODER == (stor >> 16)) && ((((stor >> 8) ^ stor) & 0xFF) == 0xFF)) {
stor &= 0xFF; ik_out = stor; tmp = 14; status = 2;
//} else goto uno;
}; break;
case 2: status = 3; tmp = 16; break;
case 3: status = 2; tmp = 18; ik_out = stor; break;
default: uno: status = 0; tmp = 20; break;
};
TIM1->SR = 0;
TIM1->CCR3 = range_z[tmp++];
TIM1->CCR4 = range_z[tmp];
}
Для TIM14 и TIM16 у меня компилируется норм, даже не ругается не на что, но не заводится... наверное всё-так потому что одноканальные, как сказали выше, только не понял зачем два канала?Reflector писал(а):Скомпилируется только если подставить подходящий таймер, канал и пин.


