Работаем с ИК пультом

Давно хотел собрать приемник сигналов с ИК-пультов, точнее сказать интересовала только возможность выключать свет ИК-пультом от телевизора. Окончательно загорелся когда прочитал несколько статей на сайте GetChip. Вот только повторять один к одному не интересно, решил заменить микроконтроллер на STM8.
ИК Пульт 00

Анализ сигналов ИК-пульта
Первым делом проверил “какие” сигналы генерирует имеющийся у меня пульт. Для анализа очень удобно и просто записать сигналы с помощью звуковой карты ПК. Как это сделать читаем тут Запись сигналов IR-пульта на звуковую карту.
Вот что у меня получилось:
image
Больше всего формат посылок похож на Extended NEC protocol:
image

ИК-приемник
Долго мудрить не стал, выбрал самый дешевый и способный работать при низком напряжении питании (от 2,5 до 5,5 В) TSOP31326 (26 рублей):
image
Пришел только вчера, ждал почти три недели :(

Прием и обработка сигналов
Самый простой алгоритм анализа сигнала на мой взгляд является измерение длительности импульсов.
Из доступной периферии для измерения длительности лучше всего использовать 16-ти битный таймер общего назначения, в связи с наличием его во всей линейке STM8 (и STM32), что позволит в дальнейшем использовать один и то же код.
Можно было бы использовать и расширенный таймер, но он слишком “вкусный” для такой простой задачи. А восьми битные таймера не имеют внешних входов.
Как правило таймер общего назначение реализован под номером 2 (TIM2).
Проанализировав все доступные режимы работы таймера я выбрал режим “PWM input signal measurement”.
Данный режим работы предназначен для измерения длительности импульса и периода ШИМ сигнала.
В этом режиме к одному внешнему входу подключены два канала “захвата”. Каналы настроены на выделение разных фронтов входного сигнала (нарастающий и спадающий). В примере на рисунке ниже, канал IC1 настроен на выделение нарастающего фронта сигнала, канал IC2 – спадающий фронт:
image
Так как самый функциональный всегда расширенный таймер 1 (TIM1), а все остальные являются его упрощенными версиями, следовательно описание всех режимов работы дано для таймера 1. Поэтому хоть я и рассматриваю таймер 2 на рисунке выше указанно TIM1.
При детектировании нарастающего фронта происходит запоминание текущего значения (в данном случае это значение является периодом входного сигнала), сброс счетного регистра и одновременное генерирование соответствующего прерывания. Аналогичные действия происходят и при детектировании спадающего фронта во втором канале, за исключением сброса счетного регистра.
Как видим всё довольно просто. Остается только в обработчиках прерываний считывать длительности и анализировать их.
По моему мнению для сигналов моего пульта нет смысла измерять все длительности подряд. Объясню почему.
Можно выделить три пары длительности сигналов:
Сигнал Длительность ИК-излучения, мс Длительность паузы, мс Начало посылки 9 4,5 Логическая единица 0,56 1,69 Логический ноль 0,56 0,56 Как видим информация о длительности пауз достаточно для однозначного определения различных типов сигнала.

Программная реализация Для простоты буду использовать стандартные библиотеки, конечно это не оптимально, но более универсально.
Схему подключения ИК-приемника использовал типовую (см. рисунок выше). Сигнал на выходе ИК-приемника инверсный, т.е. когда нет излучения на выходе всегда высокий логический уровень. Подан на линию TIM2_CH1.
И так настраиваем настраиваем таймер согласно описанному выше режиму:
// разрешаем тактирование
CLK_PeripheralClockConfig(CLK_Peripheral_TIM2, ENABLE);

// режим работы
TIM2_TimeBaseInit(TIM2_Prescaler_64, TIM2_CounterMode_Up, 0xFFFF);

TIM2_ICInit(TIM2_Channel_1, TIM2_ICPolarity_Rising,
		TIM2_ICSelection_DirectTI, TIM2_ICPSC_DIV1, 0);
TIM2_ICInit(TIM2_Channel_2, TIM2_ICPolarity_Falling,
		TIM2_ICSelection_IndirectTI, TIM2_ICPSC_DIV1, 0);
TIM2_SelectInputTrigger(TIM2_TRGSelection_TI1FP1);
TIM2_SelectSlaveMode(TIM2_SlaveMode_Reset);

// разрешаем прерывания
TIM2_ClearFlag(TIM2_FLAG_CC2);
TIM2_ITConfig(TIM2_IT_CC2, ENABLE);

// разрешаем работу
TIM2_Cmd(ENABLE);


Собственно всё, теперь только анализировать длительности сигналов. Согласитесь очень просто :)

Пример обработчика (написан на скорую руку, поэтому оптимальностью не пахнет, плюс ошибся в порядке следования битов :)):

volatile uint8_t ir_rx_buffer[4];
volatile uint8_t step;
volatile uint8_t number;

#define IR_START_LENGTH	120
#define IR_ONE_LENGTH	30

INTERRUPT_HANDLER(TIM2_CC_USART2_RX_IRQHandler,20)
{
	uint8_t i;
	uint16_t time;

	if(TIM2_GetFlagStatus(TIM2_FLAG_CC2))
	{
		time = TIM2_GetCapture2();

		// детектирование начала посылки
		if (time > IR_START_LENGTH)
		{
			number = 0;
			step = 1;
		}
		else
		{
			if (step & BIT(7))
			{
				step <<= 1;
				if (time > IR_ONE_LENGTH)
				{
					step |= 1;
				}
				//
				ir_rx_buffer[number] = step;
				//
				if (number < ARRAY_LENGHT(ir_rx_buffer) - 1)
				{
					number++;
				}
				//
				step = 1;
			}
			else
			{
				step <<= 1;
				if (time > IR_ONE_LENGTH)
				{
					step |= 1;
				}
			}
		}

		// сбрасываем флаг
		TIM2_ClearITPendingBit(TIM2_FLAG_CC2);
	}
}


Для тестирование выводил данные из приемного буфера на ЖКИ:

while (1)
	{
		lcd_2x16_set_position(0, 0);
		for (i = 0; i < 4; i++)
		{
			lcd_2x16_print_hex_xx(ir_rx_buffer[i]);
			lcd_2x16_print_char(' ');
		}
	}


Видео работы:

  • +7
  • 12 августа 2011, 21:03
  • ZiB

Комментарии (16)

RSS свернуть / развернуть
38-мегагерцовый приемник тоже нормально работает с пультами.
0
«38 кГц» :)
Ну у меня что было доступно, то и купил.
0
Спасибо, давно искал такую подробную статью.
0
не за что, она уже давно у меня в блоге, но он у меня не сильно раскрученный ;)
+1
Сейчас почитаем-с Ваш блог. =)
0
Добавил в закладки. Кстати, я пару раз попадал в Ваш блог, так что не стоит говорить что он не раскручен. =)
0
Ваш блог у меня в закладках уже давненько ))). Так что раскрутка это дело специфичное.
0
А что за либа использутся для работы с экранчиком?
0
полулиба собственного производства, без всяких оптимизаций обычно использую её для отладки, можно взять тут
ziblog.ru/2011/01/09/pervyiy-start-s-stm32-discovery-chast-6-ndash-linii-vvoda-vyivoda/
0
Пульт для магнитолы FIAST TCD-1123 выдает такую посылку.
В посылке всего 32 бита.
Последовательность предварительная <pre-pulse>: 4,44+4,44=8,88мс.
Последовательность логической единицы: 0,612+1,59=2,202мс.
Последовательность логического нуля: 0,612+0,453=1,065мс.

в конце посылки 0,612+(~9,000)=~9,0612мс. Если кнопка удерживается, то сразу же за

Кнопка Play/Pause: <pre-pulse>10000001/10000001/10000000/01111111<after-pulse>
Кнопка STOP:<pre-pulse><after-pulse>
Кнопка Prew:<pre-pulse><after-pulse>
Кнопка Next:<pre-pulse><after-pulse>
Сигнал повтора кнопки: <pre-pulse>0<after-pulse>

Первая часть посылки, состоящая из 16 бит, похожа на протокол JVC, однако вторая часть из 16 бит меня смущает.
0
  • avatar
  • Rita
  • 27 декабря 2011, 21:12
Пульт для магнитолы FIAST TCD-1123 выдает такую посылку.
В посылке всего 32 бита.

Последовательность предварительная <pre-pulse>: 4,44+4,44=8,88мс.
Последовательность логической единицы: 0,612+1,59=2,202мс.
Последовательность логического нуля: 0,612+0,453=1,065мс.
Последовательность окончательная: 0,612+(~9,000)=~9,0612мс.
Последовательность повтора кнопки <reply-pulse>: <pre-pulse>+0+<after-pulse>.

Если кнопка удерживается, то сразу же за <after-pulse> предыдущей посылки циклически повторяется посылка <reply-pulse>.

Кнопка Play/Pause: <pre-pulse>10000001/10000001/10000000/01111111<after-pulse>
Кнопка STOP:<pre-pulse>10000001/10000001/10010000/01101111<after-pulse>
Кнопка Prew:<pre-pulse>10000001/10000001/10001000/01110111<after-pulse>
Кнопка Next:<pre-pulse>10000001/10000001/10011000/01100111<after-pulse>
Сигнал повтора кнопки: <pre-pulse>0<after-pulse>

Помогите распознать протокол.
0
  • avatar
  • Rita
  • 27 декабря 2011, 21:17
Сдесь второй байт равен первому, а четвертый инвертирован относительно третьего. Если выкинуть второй и четвертый байты посылки, то получается протокол JVC, включая временные показатели. Однако меня смущает тот факт, что в посылке первый байт дублируется, а второй — инвертируется. Т.е. это получается как-минимум «JVC c перепроверкой».
0
Также смущает то, что в протоколе JVC сигнал повтора не отделяется сигналом <pre-pulse> от предыдущей посылки.
0
А сигнал повтора команды состоит из всех 16 бит, а в моем пульте первый бит означает сигнал повтора.
0
Все это конечно инересно, вот только в STM8S в таймере 2 отсутствует контроллер и, соответственно отсутствует регистр TIM2_SMCR где можно задать действие при захвате. Поэтому чистить счетчик придется ручками в обработчике прерывания по захвату. А вы видимо используете STM8L. Там регистр TIM2_SMCR присутствует и ваш пример прокатит.
0
Используйте первый таймер. Давно было дело, 2011 год.
Если необходимо работать с Ик пультом посмотрите более свежую статью ziblog.ru/2013/05/14/distantsionnoe-upravlenie-ot-ik-pulta.html
0
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.