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

31 Июля 2011 К комментариям

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

ИК Пульт 00

Анализ сигналов ИК-пульта

Первым делом проверил “какие” сигналы генерирует имеющийся у меня пульт. Для анализа очень удобно и просто записать сигналы с помощью звуковой карты ПК. Как это сделать читаем тут Запись сигналов IR-пульта на звуковую карту.

Вот что у меня получилось:

image

Больше всего формат посылок похож на Extended NEC protocol:

image

ИК-приемник

Долго мудрить не стал, выбрал самый дешевый и способный работать при низком напряжении питании (от 2,5 до 5,5 В) TSOP31236 (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(' ');
		}
	}

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


Categories: Проекты Tags: ИК пульт

comments powered by Disqus