Проблемы с покупкой микроконтроллеров в России, плюс моя любовь к минимализму и желание заказчика сделать стоимость изделия минимальной, привели к разработке показанного на блок схеме устройства.
Спустя короткий промежуток времени, была поставлена задача — малой кровью сделать управление по линии связи устройством (назовем его «Блок управлением светом») на микроконтроллере PIC10F322, где большая часть из 512 программных слов уже было занято управлением светодиодами. Причем у PIC10F322 свободным для связи оставался только один вывод, который может работать только в режиме входа.
Сложность еще заключалась в том, что у микроконтроллера в блоке управления единственный UART был занят связью с панелью управления, поэтому замена в блоке управления светом микроконтроллера на более мощный с аппаратным UART, требовала так же замены микроконтроллера на более мощный с двумя UART в блоке управления. Захотелось найти более простое решение, не требующее замены микроконтроллеров, тем более заказчик утверждал, что дальнейшее увеличение функционала не предвидится.
Так как PIC10F322 управлял светодиодами через три сдвиговых регистра 74HC595, то каждые 320мкс он выдавал три пачки по восемь импульсов тактового сигнала и появилась идея организовать удаленный SPI интерфейс через микросхемы драйверов RS485.
PIC10F322 работает в режиме мастера, выдавая тактовый сигнал в линию, а базовый блок работает как подчиненный передатчик, выдавая обратно битовый поток команды. Так как между блоком управления и блоком света нет синхронизации, то PIC10F322 должен как-то понять где начало байта. Контроль ошибок делается за счет избыточности, если полученные три байта одинаковые, то значит ошибки нет. Так как битовый поток идет постоянно, то можно смело отбрасывать ошибочные кадры.
Стоит заметить, что блок управления управляет двухтактным преобразователем напряжения и ШИМ формирователем усилителя класса D, формируя звуковые сигналы оповещения, а также аналого-цифровое преобразование и простейшую обработку сигнала с микрофона. Поэтому времени у него просто в обрез и работать на прерываниях по SPI, где промежуток между байтами в кадре 10мкс не представляется возможным.
Хотелось бы найти решение, в котором записал байт в буфер и забыл. Так как синхронизация между блоками отсутствует, то базовый блок может начать передачу в произвольный момент времени. Вот так я пришел к тому, что нужны коды, которые при сдвиге не пересекаются с другими кодами.
Идея в следующем — если байт 0x01 циклически сдвигать по кругу, то его никогда не перепутаешь с так же циклически сдвинутым байтом 0x03 или 0x05 или 0x07.
Стало интересно, а сколько всего таких кодов в восьми битах? Оказалось таких кодов - 34, причем 16 из них идут подряд (0x80-0x8F), поэтому декодировать их очень легко.
В связи с тем, что мне нужно всего лишь 16 команд, программа получилась очень простая. Формирую тактовый сигнал, по заднему фронту считываю состояние входа и записываю в регистр. Полученный байт сохраняю в буфер. После заполнения буфера сравниваю значения элементов буфера, если одинаковые, то проверяю на попадание в диапазон 0x80 – 0x8F, если не попали, то сдвигаю два соседних байта в буфере и снова сравниваю, и так до семи раз. В случае любой ошибки пакет отбрасывается. Затем просто обнуляю старший бит и команда получена.
Полный список кодов которые, при сдвиге не принимают значение другого кода:
от 0x80 до 0x8F, 0x92, 0x93, 0x95, 0x96, 0x97, 0x99, 0x9A, 0x9B, 0x9D, 0x9E, 0x9F, 0xAA, 0xAB, 0xAD, 0xAF, 0xB7, 0xBB, 0xBF.
На КДПВ одинаковым цветом отмечены варианты сдвинутого числа, числа в рамочке, те которые я выбрал как «родителей» последовательности вариантов.
Вполне возможно, что такое давным давно придумали еще во времена Чарлза Бэббиджа, но беглый поиск по «самосинхронизирующиеся коды» интересующего меня результата не дал.
Автор: Ермаков Алексей