Введение

PC-ОС

БП

Дисплей

Координатор

Если вы интересуетесь обучаемым проектом дистанционного управления компьютером (который, после обучения, может работать и автономно в качестве IR-выключателя) зайдите также сюда.

Немного теории

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

У этой технологии только одна проблема - единственный канал связи. Т.е. буквально - единственный провод. И как хочешь с ним, так и крутись. Т.е. как по этому проводу передать разные команды ? Лет 20-40 назад ответ был бы очевиден - разной частотой модуляции. Но в современной цифровой технике удобнее оказалось использовать цифровое кодирование команды. Вот отсюда и начинаются хитрости.

Канал один. Только один. Передать по нему последовательный код (как в com-портах) можно, но нужна, во первых - хорошая синхронизация приемника и передатчика, во вторых - приёмник должен точно найти начало передаваемого слова. В com-портах это делается передачей длительной логической "1", но в ИК-связи ничего длительного быть не может - датчик ловит только быстроменяющийся сигнал, в противном случае (если сигнал долгое время остается постоянным) он начинает его путать с фоновой засветкой. Другая проблема (пожалуй, в нынешних пультах это не очень актуально) - частотозадающие цепи приёмника и передатчика могут иметь существенное, заранее неизвестное, расхождение и приёмник должен налету подстраиваться под темп передатчика. Поэтому в ИК-пультах используется более сложное кодирование.

В общем и целом идея проста: нужно сделать так, чтобы любой бит кодировался некоей последовательностью, которая бы содержала как "0" так и "1". Особенно жестко подобная задача стоит в дисководах (их проблемы аналогичны пультовым), которые прошли FM, MFM, RLE и прочие этапы эволюции, в пультах же все проще. Мне попадалось два решения.

Первое, подробности которого вы легко найдете в инете по ключевому слову "rc5" - это предложенная фирмой Philips схема: любой бит передается в течение некоторого времени t. Причем в первую половину периода t/2 передается реальное значение бита, а во вторую - его инверсия. Т.е. или "10" или "01". Длительность периода t фиксирована.

Второе решение (мне кажется - гораздо более простое для програмного декодера), используется в куче других пультов (не Philips), состоит в следующем: каждый бит передается как импульс фиксированного времени ("1") и затем пауза ("0"), время которой зависит от значения передаваемого бита. Например, "0" передается как импульс длинной t и пауза длинной t, а "1" - импульс длинной t и пауза длинной 3*t.

Последний бит в этом случае не определен - стоп-бит. У него есть импульс, но пауза (он же последний!) имеет бесконечную длительность. Его назначение единственно в том, чтобы обозначить паузу предыдущего бита.

Для контроля передачи иногда предусмотрен либо бит четности, либо двухкратная пересылка (иногда инвертированная) сообщения.

Для определения начала посылки часто передается один или несколько импульсов фиксированной длительности, существенно превышающей длительность (>3t) других импульсов в посылке. Будем называть это старт-битом.

Описания нескольких конкретных пультов

Исследования проводились под ms-dos-совместимой системой, с использованием небольшой самописной проги (своего рода осцилограф) и ИК-датчика на lpt-порту. Длительности сигналов определялись только относительные (относительно некоего условного интервала t, для разных пультов он может быть различным). Эксперименты с аппаратурой, управляемой этими пультами, показали, что она (т.е. ее декодеры) допускает отклонения временных промежутков в интервале около +-10%.

Кроме того, часто пульты используют амплитудную модуляцию сигналов частотой, например, 36 КГц. Если эту частоту изменять, датчики могут перестать реагировать на пульт. Это происходит не резко (т.е. используется аналоговая фильтрация несущей), просто по мере ухода от 36 КГц постепенно уменьшается дальность работы системы. Причем сверху это ограничение выражено более сильно, чем снизу: переход за 42 КГц практически закрывает канал, в то время как 28 КГц еще может приниматься на расстоянии около метра (это оценка двух, наугад взятых приёмников из различной аппаратуры).

RC-812. Shivaky

Кодирование методом переменной паузы, старт-бит - 1430..1470t, пауза старт-бита - 1370..1410t, затем следует 32 значащих бита и стоп-бит. Импульс бита - 190..220t, пауза "0" - 140..170t, пауза "1" - 490..510t.

Если первый бит = "1", за ним сразу следует стоп-бит - это специальная команда "повтор" - т.е. пользователь удерживает клавишу нажатой.

Если первый бит = "0", за ним следует еще 31 бит. Все вместе они образуют четыре байта, ранними передаются младшие биты. Первые два байта = const = 0x0E, затем идет код клавиши, затем его инверия.

Коды клавиш (hex): mute - 14, sleep - 15, power - 0b, "1".."9" - 00..08, "0"/av - 09, -/-- - 0a, tv/video - 0f, Up - 11, Down - 10, Left - 12, Right - 13, Menu - 1c, sys - 0c, picmode - 0e, pic - 1d, disp - 16, calendar - 1f. Есть еще другая версия для схожего по кодированию пульта (название, к сожалению, не сохранилось): disp - 19, prev - 1a, sleep - 1f, picsel - 1e, chan - 10/11, vol - 1c/1d, standby - 14, mute - 15.

105-210a. GoldStar

Кодирование методом переменной паузы, старт-бит - 2880t (7.88мс), пауза старт-бита - 1400t (3.6мс), затем следует 32 значащих бита и стоп-бит. Импульс бита - 200t (570мкс), пауза "0" - 160t (400мкс), пауза "1" - 503t (1250мкс).

Если пауза старт-бита уменьшается до 685t (1.7мс) - это признак команды "повтор", после такой паузы передается только стоп-бит.

Четыре байта посылки (ранними передаются младшие биты): первый const = 0x04, второй const = not 0x04 = 0xFB, третий - код клавиши, четвертый - его инверсия.

Коды клавиш (hex): pwr - 08, mute - 09, "0".."9" - 10..19, -/-- - 1c, rec - 1b, Up - 00, Down - 01, Left - 03, Right - 02, Ok - 44, tv/av - 0b, menu - 43, psm - 4f, sleep - 0e, qv - 1a, pic - 0c.

6710 v00008a. LG

Кодирование по rc5, но по сравнению с имеющимся в наличии philips'овым пультом (от VCR), вся посылка сильно отличается по темпу передачи. Может это дефект конкретного пульта, может специально так сделано, но телек, к которому этот пульт прилагался, ловит его легко. Также как и видак легко ловит свой philips'oвый пульт. Но пульт от видака хотя и может управлять телевизором, но не дальше чем с 1.5-2 метров...

Код системы: 0.

Коды клавиш (hex): pwr - 0c, mute - 0d, "0".."9" - 0..9, -/-- - 0a, ok - 25, tv/av - 38, menu - 3b, psm - 0e, qview - 22, sleep - 26, sys - 0f, pseudo - 24, dial - 23, eye - 12, ssm - 16, Up - 20, Down - 21, Left - 11, Right - 10.

rmt-cz130. Sony

Кодирование методом переменного импульса (аналогично переменной паузе, но наоборот - длительность импульса зависит от значения бита, а паузы - фиксирована). Старт-бит - 780t, пауза старт-бита 190t, импульс "0" бита - 195t, импульс "1" бита - 390t, пауза бита - 190t.

Значащих бит в посылке 14, затем идет стоп-бит (или я вру и его нет ? зачем он в этом методе ?). Все биты образуют слово, первым идет младший бит.

Коды клавиш (hex): "1".."9" - 3200..3208, mode - 2211, 0/10 - 320c, >10 - 320d, >> - 3232, || - 3239, [] - 3238. Клавиши << и >> при кратковременном нажатии дают коды 3230 и 3231 соответственно, при удержании код меняется (т.е. эти клавиши отправляют код не сразу после нажатия - сначала анализируется длительность) на 323a и 323b.

Любая посылка трижды повторяется. Длительное удержание клавиш вызывает периодическую отправку их кода без изменения формата сообщения.

rc-tc400. Aiwa

Кодирование методом переменной паузы, старт-бит - 16t, пауза старт-бита - 8t, импульс бита - 1t, пауза нулевого бита - 1t, пауза единичного бита - 3t.

Всего передается 42 бита + стоп-бит. 7 единиц, 13 нулей, 6 единиц, 8 бит команды, 8 бит контроля (инверсия команды). Биты команды и контроля образуют байт, первым передается младший бит.

Коды клавиш (hex): power - 00, eject - 48, auto - 5c, track+ - 47, track- - 46, rec - 14, << - 12, > - 15, >> - 11, || - 17, [] - 1a, repeat - 5f.

Схожее кодирование у duraband dv-100, но перед кодом команды передается меньше бит.

nv-mv20, gcu-s. Panasonic=Matsushita

Кодирование методом переменной паузы, старт-бит - 1440t, пауза старт-бита - 720t, импульс бита - 163t, пауза нулевого бита - 155t, пауза единичного бита - 512t.

Всего передается 48 бит + стоп-бит. Биты образуют 6 байт, первым передается младший бит. Байты: 0, 1 = 0x02, 0x20; 2 - система: 0x90 - vcr, 0x80 - tv; 3, 4 - команда, 5 - контрольная сумма, вычисляется как исключающее ИЛИ по байтам 2 xor 3 xor 4.

Коды клавиш (hex):

  • Управление TV: power - 3d, av - 5, volume+ - 20, volume- - 21, ch+ - 34, ch- - 35.
  • Управление VCR: power - 3d, disp - 15f, reset/clear - 54, tr+ - 34, tr- - 35, pic - 529, osd - 57, inp - c0, <I - 49, i> - 4a, || - 06, Rec - 8, menu - 156, > - a, prog - 53a, << - 2, ok - 158, >> - 3, jet - 52f, [] - 0, nav - 528, progr - 101, guide - 530, speed - 10a, timer - b4, date+/- - 192/193, chprog+/- - 190/191, dataon+/- - 194/195, dataoff+/- - 196/197.

Анализ этого магнитофона и его пульта также позволил обнаружить ряд скрытых функций: eject - 1, "1".."9" - 10..18, "0" - 19, poweron - 3e, poweroff - 3f, "re" <-> "count" - 55, timeron - b5, timeroff - b6, clear_all_program - 109, "standart" - 3a1, "dyn" - 3a2, "soft" - 3a3, "cart" - 3a4, clear_all_memory - 3fa. Часть этих функций, несомненно, предназначена просто для отладки, настройки, диагностики - в общем не для пользователя. Но тем не менее, мне кажется, если бы выброс кассеты был сделан отдельной кнопкой на пульте (раз уж в протоколе контролера она есть) - это было бы удобнее, чем держать "стоп" три секунды. Тем не менее, некоторыми из этих кодов я стал пользоваться в компьютерной программе, которая позволяет программировать видак на запись без длительного юзанья пульта.

Есть еще ряд кодов, на которые магнитофон реагирует, но я не понял смысл: например, на индикаторе зажигается две точки ... и что ? Явно это указывает на какой-то специальный режим, но в чем он проявляется я не понял.

rc-5. Philips 296

Здесь используется система rc5, но есть одна тонкость, которую я не встречал в популярной (и не очень популярной) литературе: второй передаваемый бит, который везде указывается как const = 1, в данном пульте передается как "0" для клавиш tr+ и tr-. Другие клавиши передают его как положено - единицей.

Коды клавиш (hex):

  • Управление TV (sys=00): power - 0c, mute - 0d, volume+ - 10, volume- - 11, ch+ - 20, ch- - 21.
  • Управление VCR (sys=05): power - 0c, eject - 2d, tv/vcr - 3e, speed - 3a, mem - 3b, 2x - 2a, "0".."9" - 0..9, ch+ - 20, ch- - 21, tr+ - d, tr- - 0e, ex/st - 0f, menu - 1d, > - 35, slow - 28, clear - 31, << - 32, || - 29, >> - 34, rec - 37, [] - 36.

Приёмники

Не углубляясь в теорию, скажу коротко: приёмники для ИК пультов - это интегральные детали - фотодиод, усилитель и демодулятор 36 КГц в одном неразборном флаконе (нет, разобрать, конечно, можно, но вряд ли удастся собрать).

Теоретически существуют дискретные схемы, как на транзисторах, так и на микрухах, они даже будут работать с нынешними пультами (с модуляцией), но дальность такой комбинации будет метра 2-а (вероятно, из-за того, что такие схемы делались для пультов без модуляции). Подобные схемы использовались, например, в советских телевизорах 3-4 с пультами без модуляции. Пульты неплохие, но постепенно становятся труднодоступными.

Интегральный приемник - как правило это деталька 1x1.5 см, называется TSOP1736. Именно эту марку рекомендуют в литературе, но она не единственная. Я однажды купил приёмник BRI BRM-1020, по ценнику в магазине он на 38 КГц, но он отлично работает с пультами на 36 КГц, имеет размер раза в полтора меньше TSOP-а, да еще и стоит раза в полтора дешевле. Именно его я использовал в плейере.

Выход приёмника - открытый коллектор, нагруженный на большой (около 100 кОм) резистор. Кушает приёмник около 5 вольт, но допускает и более другие напряжения - см. документацию. Параллельно выходному резистору допускается подключать другие, с более низким сопротивлением - выходной транзистор допускает заметную нагрузку. При появлении сигнала, опознаваемого приёмником (т.е. включенный светодиод пульта) транзистор открывается, на выходе появляется логический "0". Т.е. выходной сигнал приёмника инверсный ! Как правило, микроконтроллеры имеют возможность перехода на обработчик прерывания по перепаду уровня на одной из своих лапок с "1" в "0" - это очень удобно, т.к. позволяет подключить ИК-приёмник непосредственно к такой лапке. При появлении ИК-сигнала управляющая программа сразу бросит все и будет его анализировать.

Декодирование команд на примере дешифратора пульта Sony RMT-cz130

Дальнейший текст этой главы подразумевает владение ассемблером 8051. Ну а как иначе это объяснить ? :)

Приведённый здесь фрагмент кода - это слегка урезанный кусок реального кода, используемого в плейере. Он изначально писался под приёмник без демодулятора (и даже работает с ним), поэтому анализ сигнала у него немного усложненный.

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

;
; В этом коде прерывания не используются, просто в цикле опрашивается выход приёмника
; и если там что нибудь шебуршится, выполняется переход на "MN_6:". В случае приёма
; внятной команды, она отдается процедуре SendByte. В конце концов управление возвращается
; на "MN_3:" - основной цикл.
;
; Получение команды от ДУ
;

MN_6:
 clr	EA		; Прерывания подождут

; Вводные "1" и "0" [старт-бит и его пауза]

MN_7:
 acall	GetIRState	; Сначала пропускаем длинный калибровочный бит
 jnz	MN_7
 acall	GetIRZero	; Ожидаем синхропаузу
 jnc	MN_8

; Получаем первые 8 бит в регистр B

 mov	R4, #8
 acall	GetIRByte
 jnc	MN_8
 mov	IRByte, B

; Получаем хвост (6 бит)

 mov	R4, #6
 acall	GetIRByte
 jnc	MN_8

; Проверяем хвост и в случае успеха отсылаем первый принятый байт

 mov	A, B
 anl	A, #0b10111100	; Хвост должен быть либо 0x32 либо 0x22 сдвинутых на два отсутствующих бита
 xrl	A, #0b10001000
 jnz	MN_8
 acall	SendByte	; Эта процедура будет рассмотрена в другом разделе
			; Она отсылает принятый код команды на com-порт.

MN_8:
 setb	EA		; Разрешить прерывания
 ajmp	MN_3		; Возврат к основному циклу
;
; Получает R4 бит в B. Успешное завершение: C = 1
; Нулевой бит передается в два раза быстрее единичного
;
GetIRByte:		; r3 должно быть 7, но попробуем иное
 mov	R3, #8		; t0 = 4..5 * GetIRState, t1 = 8..10 * GetIRState
GIB_1:
 acall	GetIRState
 jnz	GIB_1

 mov	A, R3
 mov	C, ACC.7
 mov	A, B
 rrc	A
 mov	B, A

 acall	GetIRZero
 jnc	GIB_2
 djnz	R4, GetIRByte
GIB_2:
 ret
;
;  28 мкс - период частоты 36 кГц
; 500 мкс - один таймерный отсчет ДУ
; Значит в один таймерный отсчет происходит примерно 18 колебаний несущей.
; Если предположить, что фиксироваться должен, как минимум, 1 из четырех периодов,
; то GetIRState должна ожидать 111 мкс (159 тактов) и при наличии хотя бы одного 0 возвращать A <> 0
; 7 + 5*x = 159 -> x = 30
;
GetIRState:		; 2
 mov	R2, #30		; 1
 clr	A		; 1
GIR_1:
 mov	C, IRData	; 1
 cpl	C		; 1
 addc	A, #0		; 1
 djnz	R2, GIR_1	; 2
 dec	R3		; 1
 ret			; 2
;
; Процедура пытается получить паузу между битами
; Ее длина всегда фиксирована и равна 4-6 вызов GetIRState с результатом = 0
; Если требуется иное количество GetIRState - это говорит о сбое в синхронизации (возвращается C = 0)
;
GetIRZero:
 mov	R3, #7
GIZ_1:
 acall	GetIRState
 jnz	GIZ_2
 mov	A, R3
 jnz	GIZ_1
 clr	C
 ret
GIZ_2:
 mov	A, R3
 clr	C
 subb	A, #4
 ret

Если захотите использовать код один-в-один, не думая, помните, что он исполняется в реальном времени, но знает об это времени только от тактового генератора контроллера: кварц 18 027 800 Гц = такт 0.7 мкс (1 502 316.(6) Гц).

Также обратите внимание на тот факт, что константы с префиксом "0b" (двоично представленные) не всегда обрабатываются корректно. Например, as31 for ms-dos (версию не помню, но она, предположительно, не важна, так как обработкой таких констант должен заведовать не код ассемблера, а системная libc или какой-то её функциональный эквивалент) тихо подставляет вместо правильной цифры ноль. Хотя тот же as31 для FreeBSD все делает верно.

Владимир