Кто любит RISC в жизни, заходим, не стесняемся.
Ответить

STM32 библиотека работы с ИК пультом (NEC)

Пн мар 07, 2016 21:26:17

Здравствуйте, читатели форума:)
13 страниц форума и ни одного вопроса по управлению с пульта ДУ=)
Уже много времени хотелось разобраться и найти библиотеку декодирования сигналов NEC пультов.
Прочитал теорию, вроде бы всё хорошо и понятно.
С помощью программы RCExplorer (кстати, она сейчас бесплатная. Связался с её автором и он через некоторое время сделал её бесплатной) и давным-давно собранного WinLirc убедился что мой пульт использует NEC протокол. Даже не расширенный.
НО, найденная библиотека почему-то не работает корректно. Зато, как ни странно, декодирует сигналы протокола SANYO (похож на NEC).
Прикладываю "осциллограммы" кнопок пультов. В коде реализуется прием 32 байт. У sanyo их явно больше, но принимаются же!!! а у NEC идет какое-то недополучение (байт 10 не успевают проскочить)
SANYO.PNG
(13.89 KiB) Скачиваний: 1135
NEC.PNG
(12.51 KiB) Скачиваний: 844

Может посмотрите в чём дело? Прикладываю проект в CooCox. Или поделитесь библиотекой для декодирования NEC протокола?

Описание проекта:
Используется таймер TIM2, ИК-фотоприемник подключен по типовой схеме, сигнальный вывод к ножке GPIOA0 (TIM2_CH1).
К отладочной плате подключен 1602 дисплей по четырёхбитной шине.



Добавлю. Принятый код с SANYO на картинке RCExplorer
SANYO1.png
(20.57 KiB) Скачиваний: 551

Как мы видим, теряются 10 байт. Что делать - не знаю)
Вложения
RemoteC.rar
CooCox IDE 1.7.5
(265.2 KiB) Скачиваний: 335

Re: STM32 библиотека работы с ИК пультом (NEC)

Вт мар 08, 2016 01:29:42

Очень странная библиотека, в своё время у меня не завелась, пришлось стряпать своё.
Вся обработка в прерывании по месту события, в последнем правильно принятом бите - вызов задачи декодирования из спячки. Тупой перебор до совпадения.
При зажатой кнопке и верности принимаемых таймингов - декодируется повтор. В случае посторонних помех - декодирование срывается но не искажается, то-есть ложных срабатываний - ноль. Чего собственно мне и требовалось.
Для иной частоты мк -проще менять 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);
 }

Re: STM32 библиотека работы с ИК пультом (NEC)

Вт мар 08, 2016 11:12:41

трындец какой-то :(

Re: STM32 библиотека работы с ИК пультом (NEC)

Вт мар 08, 2016 13:35:17

У меня работает, а у вас?

Re: STM32 библиотека работы с ИК пультом (NEC)

Вт мар 08, 2016 13:46:03

AVI-crak писал(а):У меня работает, а у вас?

А у меня не работает :cry:
Правда, я про свой найденный код. С ОС сталкиваться ой как не хочется - это ж дебри. Если я с портами и таймерами еще не совсем освоился, куда уж ОС....
Ну вот почему он может пропускать 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


Заполнение идет с конца, т.е. потерянные байты L находятся после стартовой посылки и паузы.
Вложения
NEC1.png
(14.82 KiB) Скачиваний: 368

Re: STM32 библиотека работы с ИК пультом (NEC)

Вт мар 08, 2016 14:50:53

Ican писал(а):
AVI-crak писал(а):У меня работает, а у вас?

А у меня не работает :cry:
Заполнение идет с конца, т.е. потерянные байты L находятся после стартовой посылки и паузы.

Ну собственно это и есть проблема, ик передача начинается со старших битов посылки. И первыми есно прилетают 16 бит кода фирмы - уникальный идентификатор принадлежности пульта к железяке, а уже после летит код команды кнопки. Игнорировать идентификатор не желательно, с его помощью можно различать разные пульты.

У меня 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 - то процесс декодирования устанавливается в начальное время, и так до момента пока не прилетит первая корректная посылка.

Несколько свободных ик библиотек, в том числе и аурдино - все они измеряют время единицы и нуля в реальном времени, собственно мартышкин труд. Особо упорные измеряют время программными задержками. Причём эти библиотеки живут ещё со времён восмибитных пиков, практически без изменений.

Re: STM32 библиотека работы с ИК пультом (NEC)

Чт мар 10, 2016 21:39:57

Разобрался. Нашел место, где грабли лежат.
было
pos = -10; // change (ТЕРЯЛОСЬ 10 первых байт!!!!)
стало
pos = 0; // change принимается все на ура. Неоптимально, зато принимается.

Всем спасибо, расходимся)

Re: STM32 библиотека работы с ИК пультом (NEC)

Чт апр 07, 2016 13:49:45

Внесу свои 5 копеек. Мне тоже понадобилось подключить пульт ДУ. Я все сделал через захват таймера. У меня плата stm32 Mini, там был свободный вход PA8. Это канал захвата №1 таймера 1. Я видел ваши и другие библиотеки и мягко говоря в шоке. Декодирование пульта это довольно простая задача. У меня больше времени ушло на настройку таймера и прерывания.
Выкладываю здесь свой вариант декодирования (только основные моменты). На выходе имеем переменную NecEnd которая равна нулю или 32-битному коду принятому от пульта. После чтения переменной ее необходимо снова сбросить в 0.

Re: STM32 библиотека работы с ИК пультом (NEC)

Чт апр 07, 2016 19:55:58

Andry_67
Нет защиты от помех.
Поиграйся двумя разными пультами одновременно, должно быть либо честное декодирование - либо сброс посылки.

Re: STM32 библиотека работы с ИК пультом (NEC)

Пт апр 08, 2016 13:36:05

Защита от помех есть. В строке
if (100<NecD && 235>NecD){
проверяется длительность между двумя импульсами и если длительность выходит за пределы то декодирование прекращается и ожидается новый стартовый импульс.
Поиграйся двумя разными пультами одновременно

А не надо одновременно жать на разные пульты, в этом случае ни у кого ничего работать не будет.

Re: STM32 библиотека работы с ИК пультом (NEC)

Сб май 14, 2022 21:44:41

Допрограмировался, в поисках нахожу своё старое.
В гитхаб теперь только через телефон, bitbucket.org просто стёр всё мои каракули, ещё парочка репозитариев успела пять раз в прыжке переобуться, а один уникальный склад кода - умудрился буквально сгореть, вместе с датацентром.
А тут даже пылью не покрылось.
ik_nec.с

ik_nec.h


Написано для мелкого stm32f030f, требует таймера с поддержкой PWM Input и одним свободным контактом CH1. По протоколу NEC - необходимо выполнить реверс битов в каждом байте, с сохранением порядка байтов. Но мне лень.

Re: STM32 библиотека работы с ИК пультом (NEC)

Ср дек 14, 2022 18:22:21

AVI-crak, спасибо тебе добрый человек за рабочий код для cmsis!
Оно заработало.
Дефайны только дёрнул, не знаю можно так?

В моей cmsis их не нашлось, надо бы обновить, только не разобрался откуда правильно взять.
И TIM3->PSC = 570; поставить для 48MHz пришлось.
У тебя 950 стоит, с таким значением попадаю только при 80MHz (RCC_CFGR_PLLMUL10) .
STM32F030K6T6.
А, вот ещё, сырой код (stor) без декодирования не получилось принять , поковыряю ещё...

Re: STM32 библиотека работы с ИК пультом (NEC)

Ср дек 14, 2022 20:53:16

На правах рекламы, можно сказать, тоже предложу вариант решения (подсмотрено на easyelectronics)


Использовать максимально просто, вот пример:

Re: STM32 библиотека работы с ИК пультом (NEC)

Чт дек 15, 2022 01:02:21

Дефайны только дёрнул, не знаю можно так?

Раньше-бы посоветовал дёрнуть из кубика от st, но сейчас всё свежее приходится искать на гитхабе.
https://github.com/STMicroelectronics/c ... er/Include

Re: STM32 библиотека работы с ИК пультом (NEC)

Сб янв 21, 2023 22:04:22

А можно ли перекинуть на другой таймер?
Попробовал в лоб изменить на 14 или 16 ... не вышло.
Инит:
Код:
del

Обработчик:
Код:
del
Последний раз редактировалось zenon Вс янв 22, 2023 09:49:04, всего редактировалось 1 раз.

Re: STM32 библиотека работы с ИК пультом (NEC)

Сб янв 21, 2023 22:20:53

Если контроллер F100RB, то у таймера 16 всего 1 канал (у 15 их два, если что), так что эта реализация неприменима.

Re: STM32 библиотека работы с ИК пультом (NEC)

Сб янв 21, 2023 22:31:07

Хм. У меня F030K6T6, о 32-х ногах, те, если я правильно понял на PA2 можно повесить?
фиг там, нет у меня 15-го

Re: STM32 библиотека работы с ИК пультом (NEC)

Вс янв 22, 2023 01:22:41

А можно ли перекинуть на другой таймер?

При работе с st чипами необходимо иметь STM32Cube, скачивать любым доступным способом. Это приложение необходимо для наглядного выбора периферии, и ротации ног. Что-бы не гадать на чайной гуще, и не курить тонны документации в поиске доступного варианта решения.
Таймер должен уметь работать в режиме "PWM input", и иметь контакт на ногу чипа.

Re: STM32 библиотека работы с ИК пультом (NEC)

Вс янв 22, 2023 04:00:44

Таймер должен уметь работать в режиме "PWM input", и иметь контакт на ногу чипа.

У меня все ограничения в либах прописаны, по старинке обхожуcь без кубов :)

Скомпилируется только если подставить подходящий таймер, канал и пин.

Re: STM32 библиотека работы с ИК пультом (NEC)

Вс янв 22, 2023 09:58:40

AVI-crak, да ну его этот куб, у меня от него зуд... лучше покопашусь по-своему, задач каких-то у меня нет, так потихоньку то с одним, то с другим разобраться...
Ноги поменять глянув в даташит вообще труда не составляет.
В общем на TIM1 перекинул, теперь TIM3 освободился для энкодера.
TIM14 вроде умеет PWM Input, но на него не перекинуть.


Reflector писал(а):Скомпилируется только если подставить подходящий таймер, канал и пин.

Для TIM14 и TIM16 у меня компилируется норм, даже не ругается не на что, но не заводится... наверное всё-так потому что одноканальные, как сказали выше, только не понял зачем два канала?
Ответить