Здравствуйте, читатели форума:) 13 страниц форума и ни одного вопроса по управлению с пульта ДУ=) Уже много времени хотелось разобраться и найти библиотеку декодирования сигналов NEC пультов. Прочитал теорию, вроде бы всё хорошо и понятно. С помощью программы RCExplorer (кстати, она сейчас бесплатная. Связался с её автором и он через некоторое время сделал её бесплатной) и давным-давно собранного WinLirc убедился что мой пульт использует NEC протокол. Даже не расширенный. НО, найденная библиотека почему-то не работает корректно. Зато, как ни странно, декодирует сигналы протокола SANYO (похож на NEC). Прикладываю "осциллограммы" кнопок пультов. В коде реализуется прием 32 байт. У sanyo их явно больше, но принимаются же!!! а у NEC идет какое-то недополучение (байт 10 не успевают проскочить)
Может посмотрите в чём дело? Прикладываю проект в CooCox. Или поделитесь библиотекой для декодирования NEC протокола?
Описание проекта: Используется таймер TIM2, ИК-фотоприемник подключен по типовой схеме, сигнальный вывод к ножке GPIOA0 (TIM2_CH1). К отладочной плате подключен 1602 дисплей по четырёхбитной шине.
Добавлю. Принятый код с SANYO на картинке RCExplorer
Очень странная библиотека, в своё время у меня не завелась, пришлось стряпать своё. Вся обработка в прерывании по месту события, в последнем правильно принятом бите - вызов задачи декодирования из спячки. Тупой перебор до совпадения. При зажатой кнопке и верности принимаемых таймингов - декодируется повтор. В случае посторонних помех - декодирование срывается но не искажается, то-есть ложных срабатываний - ноль. Чего собственно мне и требовалось. Для иной частоты мк -проще менять TIM2->PSC = 720; в пересчёте процентах от 72мгц. Ось своя собственная,http://forum.ixbt.com/topic.cgi?id=48:11735. Хотя здесь она применяется всего в одном месте sTask_wake(&table_simvol_bits) , можно заменить на свой метод. Но не рекомендую использование без оси - тупой метод перебора жрёт много времени мк.
Приглашаем 3 декабря 2024 на вебинар, посвященный силовым модулям ведущего китайского производителя SUNCO - одного из мировых лидеров по производству дискретных полупроводниковых компонентов. На вебинаре вы узнаете о новинках, включая модули 17 класса в корпусе E3, и контроле качества на всех этапах производства. Вы также узнаете о новейших продуктах – IGBT-, SiC-, диодных и тиристорных модулях, погрузитесь в современные топологии, сравните характеристики IGBT-чипов разных поколений.
А у меня не работает Правда, я про свой найденный код. С ОС сталкиваться ой как не хочется - это ж дебри. Если я с портами и таймерами еще не совсем освоился, куда уж ОС.... Ну вот почему он может пропускать 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 находятся после стартовой посылки и паузы.
Всплески перенапряжения являются серьезной угрозой надежности работы радиоэлектронных устройств. Причины их появления различны, это могут быть коммутационные переходные процессы в системе электропитания устройств, разряды молний, электростатические разряды. Для создания эффективной и современной системы защиты от ЭСР компания SUNCO разработала надежные и качественные супрессоры, представляющие собой TVS- и ESD-диоды, а также сборки на их основе. Компоненты SUNCO не только не уступают, но часто превосходят по характеристикам аналогичную продукцию других брендов.
А у меня не работает Заполнение идет с конца, т.е. потерянные байты 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 - то процесс декодирования устанавливается в начальное время, и так до момента пока не прилетит первая корректная посылка.
Несколько свободных ик библиотек, в том числе и аурдино - все они измеряют время единицы и нуля в реальном времени, собственно мартышкин труд. Особо упорные измеряют время программными задержками. Причём эти библиотеки живут ещё со времён восмибитных пиков, практически без изменений.
Разобрался. Нашел место, где грабли лежат. было pos = -10; // change (ТЕРЯЛОСЬ 10 первых байт!!!!) стало pos = 0; // change принимается все на ура. Неоптимально, зато принимается.
Заголовок сообщения: Re: STM32 библиотека работы с ИК пультом (NEC)
Добавлено: Чт апр 07, 2016 13:49:45
Первый раз сказал Мяу!
Зарегистрирован: Пн дек 15, 2014 19:04:08 Сообщений: 22 Откуда: г. Пермь
Рейтинг сообщения:0
Внесу свои 5 копеек. Мне тоже понадобилось подключить пульт ДУ. Я все сделал через захват таймера. У меня плата stm32 Mini, там был свободный вход PA8. Это канал захвата №1 таймера 1. Я видел ваши и другие библиотеки и мягко говоря в шоке. Декодирование пульта это довольно простая задача. У меня больше времени ушло на настройку таймера и прерывания. Выкладываю здесь свой вариант декодирования (только основные моменты). На выходе имеем переменную 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;
// Базовые настройки таймера 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; // ошибка выходим } } } }
Заголовок сообщения: Re: STM32 библиотека работы с ИК пультом (NEC)
Добавлено: Пт апр 08, 2016 13:36:05
Первый раз сказал Мяу!
Зарегистрирован: Пн дек 15, 2014 19:04:08 Сообщений: 22 Откуда: г. Пермь
Рейтинг сообщения:0
Защита от помех есть. В строке if (100<NecD && 235>NecD){ проверяется длительность между двумя импульсами и если длительность выходит за пределы то декодирование прекращается и ожидается новый стартовый импульс.
Цитата:
Поиграйся двумя разными пультами одновременно
А не надо одновременно жать на разные пульты, в этом случае ни у кого ничего работать не будет.
Допрограмировался, в поисках нахожу своё старое. В гитхаб теперь только через телефон, bitbucket.org просто стёр всё мои каракули, ещё парочка репозитариев успела пять раз в прыжке переобуться, а один уникальный склад кода - умудрился буквально сгореть, вместе с датацентром. А тут даже пылью не покрылось. ik_nec.с Спойлер
Код:
/// IK protocol NEC /// TIMx->PSC = clock frequency of the timer / 50526
Написано для мелкого stm32f030f, требует таймера с поддержкой PWM Input и одним свободным контактом CH1. По протоколу NEC - необходимо выполнить реверс битов в каждом байте, с сохранением порядка байтов. Но мне лень.
В моей cmsis их не нашлось, надо бы обновить, только не разобрался откуда правильно взять. И TIM3->PSC = 570; поставить для 48MHz пришлось. У тебя 950 стоит, с таким значением попадаю только при 80MHz (RCC_CFGR_PLLMUL10) . STM32F030K6T6. А, вот ещё, сырой код (stor) без декодирования не получилось принять , поковыряю ещё...
При работе с st чипами необходимо иметь STM32Cube, скачивать любым доступным способом. Это приложение необходимо для наглядного выбора периферии, и ротации ног. Что-бы не гадать на чайной гуще, и не курить тонны документации в поиске доступного варианта решения. Таймер должен уметь работать в режиме "PWM input", и иметь контакт на ногу чипа.
AVI-crak, да ну его этот куб, у меня от него зуд... лучше покопашусь по-своему, задач каких-то у меня нет, так потихоньку то с одним, то с другим разобраться... Ноги поменять глянув в даташит вообще труда не составляет. В общем на 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
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]; }
Reflector писал(а):
Скомпилируется только если подставить подходящий таймер, канал и пин.
Для TIM14 и TIM16 у меня компилируется норм, даже не ругается не на что, но не заводится... наверное всё-так потому что одноканальные, как сказали выше, только не понял зачем два канала?
Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 8
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения