Комментарии 35
Как то сложно. Если надо передавать всего 16 команд, то куда проще передать пакет:
5 единиц --> 1 ноль -> код команды (4 бита) -> 1 ноль
Всё. В коде команды 5 единиц быть не может, поэтому 5 единиц однозначно будет синхропакетом
В вашем варианте сообщение получается 11 бит. Буфер в SPI PIC16F18346 размером 8 бит. В предложенном вами варианте я буду вынужден постоянно записывать в буфер SPI. В моем варианте записал и забыл (SDI соединен с SDO в SPI SLAVE) и команда сама отправляется с каждой пачкой тактовых импульсов.
А зачем постоянно записывать что-то в буфер? Или это постановка задачи такая - команда должна передаваться непрерывно? Для разовой передачи команды достаточно послать два байта - 0x1F и второй с командой.
То есть ваша идея понятна - сколько можно сформировать уникальных последовательностей с периодом 8 бит. Ок, оказалось, что таковых 34 (что-то у меня в голове крутится, что что-то подобное я где-то читал). Но вот в данном конкретном случае сложность реализации приёмной стороны, как мне кажется, довольно существенна и заметно нивелирует простоту реализации передающей стороны.
Как вы убедитесь что приемник принял сигнал без ошибки? После отправки какого количества команд вы сможете достоверно сказать, ну да, сейчас точно принял. Точно, точно..
Я не понимаю источника ошибок в вашем понимании. Если я принял 5 единиц подряд, то через 4 бита придёт команда. Всё. Какие тут еще ошибки? Если очень хочется то в этих двух байтах можно даже что-то типа контроля чётности организовать. Вот только зачем?
Кстати, в вашей реализации вместо 0x80-0x8F с тем же успехом можно использовать 0x10-0x1F - я правильно понимаю?
Любая линия связи подвержена воздействию помех. Поэтому ошибки точно будут, а их количество будет зависеть от электромагнитной обстановки вокруг.
Угу. Понятно. Понимаете, дело в том, что ваше решение не является в полном смысле этого слова самосинхронизирующимся кодом. Так как такие коды должны иметь возможность однозначного декодирования позиции в потоке. В вашем же случае при передаче кода 0x88 декодер может принять его как с правильным позиционированием, так и принять синхрослово (в вашем случае это 0x8 в верхнем ниббле) за полезные данные.
Да, в вашей конкретной задаче это неважно - ну вот задача такая - очень уж специфичная.
У меня нет синхрослова как такового, у меня все что передается это полезные данные.
Это не совсем так - в вашей реализации при пересылке каждого ниббла полезной нагрузки на него навешивается ниббл 0x8, который в данном случае и является синхрословом в его классическом понимании.
"Кстати, в вашей реализации вместо 0x80-0x8F с тем же успехом можно использовать 0x10-0x1F - я правильно понимаю? "
Да вы правы, эта последовательность тоже обладает данными свойствами.
;*********************************************************************
;Выхлоп в сдвиговые регистры
SEND_DATA:
movlw SEND_DATA_2
movwf FSR
movlw SEND_MASK_INI
movwf MASK_SEND_REG
movlw NUM_SEND_BYTES
movwf CNT_SEND_BYTES
movlw NUM_SEND_BITS
movwf CNT_SEND_BITS
SEND_DATA_CIRCLE:
rlf RX_DATA_NEW,f
movf INDF,w
andwf MASK_SEND_REG,w
btfss STATUS,STATUS_Z_POSITION
goto SEND_HIGH
bcf LATA,SER
goto SEND_SET_CLK
SEND_HIGH:
bsf LATA,SER
SEND_SET_CLK:
bsf LATA,SCK
bcf STATUS,STATUS_C_POSITION
rrf MASK_SEND_REG,f
nop
nop
nop
nop ;Нопы чтобы удлинить фронт так как на входе стоит резистор 4.7К
nop ;Для защиты драйвера при программировании микроконтроллера.
nop
nop
nop
bcf RX_DATA_NEW,RX_BIT
btfsc PORTA,RX
bsf RX_DATA_NEW,RX_BIT
bcf LATA,SCK
decfsz CNT_SEND_BITS,f
goto SEND_DATA_CIRCLE
;***Сохраняем принятые данные в буфер****
movlw RX_DATA_0 - SEND_DATA_0
addwf FSR,f
movf RX_DATA_NEW,w
movwf INDF
movlw RX_DATA_0 - SEND_DATA_0
subwf FSR,f
;**********************************
movlw NUM_SEND_BITS
movwf CNT_SEND_BITS
movlw SEND_MASK_INI
movwf MASK_SEND_REG
decf FSR,f
decfsz CNT_SEND_BYTES,f
goto SEND_DATA_CIRCLE
bsf LATA,RCK
bcf LATA,RCK
;Конец функции отправки данных в сдвиговые регистры
;Передача закончена декодируем принятые данные
;Проверяем на одинаковость
movf RX_DATA_0,w
xorwf RX_DATA_1,w
btfss STATUS,STATUS_Z_POSITION
goto CLEAR_WDT
movf RX_DATA_0,w
xorwf RX_DATA_2,w
btfss STATUS,STATUS_Z_POSITION
goto CLEAR_WDT
;Проверяем на диапазон 0x80-0x8F
movlw NUM_SEND_BITS-1
movwf CNT_SEND_BITS
RX_DATA_TEST_RANGE:
movlw RX_CODE_BEGIN
subwf RX_DATA_1,w
btfss STATUS,STATUS_C_POSITION
goto RX_CODE_TEST_RLF
movf RX_DATA_1,w
sublw RX_CODE_END
btfss STATUS,STATUS_C_POSITION
goto RX_CODE_TEST_RLF
;Данные в диапазоне 0x80-0x8F декодируем
movlw MASK_RX_DATA
andwf RX_DATA_1,f
movf RX_DATA_1,w
xorwf MODE_REG,w
btfsc STATUS,STATUS_Z_POSITION
goto CLEAR_WDT//Данные уже в регистре режима
movf RX_DATA_1,w
movf RX_DATA_1,w
xorwf MODE_REG,w
andlw MASK_MODE_DATA
btfss STATUS,STATUS_Z_POSITION
bsf SYSTEM_FLAGS,MODE_INI
movf RX_DATA_1,w
movwf MODE_REG
goto CLEAR_WDT//Данные уже в регистре режима
;Данные не в диапазоне 0x80-0x8F сдвигаем влево
RX_CODE_TEST_RLF:
movf CNT_SEND_BITS,w
btfsc STATUS,STATUS_Z_POSITION
goto CLEAR_WDT//данные приняты с ошибкой
decf CNT_SEND_BITS,f
rlf RX_DATA_0,f
rlf RX_DATA_1,f
goto RX_DATA_TEST_RANGE
CLEAR_WDT:
clrwdt
goto WAIT_TMR2
Это вся реализация на приемной стороне, включая отправку на сдвиговые регистры, и декодирование команды. Как видите она не очень сложная.
Неплохо, но если пакетами передачу делать, то поделить пакет на кадры, к примеру, кадр 8 бит, начале каждого кадра 1 бит всегда установлен - т.е. оповещает что начался новый кадр. Тогда синхра это получить как минимум 8 нулей(нет кадра).
Если знать что вещатель каждые 10мс отправляет такой пакет, а время передачи такого пакета 5мс, то минимальное время чтобы принять каждый раз хоть 1 пакет - 10 + 5мс
Ваше предложение усложнит обработку на передающей и приемной стороне и при этом не принесет никаких улучшений. Изначально я делал пакет из трёх байт, 0xFF, 0x00, "байт с данными", но затем перешёл к описанном в статье варианту так как это сильно упростило обработку пакета с обоих сторон.
Толчком для переделки послужило то, что время между задним и передним фронтом тактовых импульсов чуть меньше 2мкс. И даже если микроконтроллер в базовом блоке ничего не делает, а только ждёт прерывания от SPI, то он все равно не успевает. И SPI входит в коллизию, так как передача байта уже началась, судя по переднему фронту тактового импульса, а тут происходит запись в буфер передатчика.
Ну это для передачи нормального числа данных, в общем случае. С ограниченным набором хоть кодировать по пропускам/заполненности бит можно. 11 - одно, 111 второе, 1111 третье. Или лучше 10 - одно, 100 - второе, 1000 - третье, тогда 11(конец)
Я не понимаю что такое "в общем случае". В разработке всегда решается конкретная задача исходя из ТЗ. Если будет задача передавать большее количество данных или поток данных (например аудио или видео поток) , то естественно будет использоваться другой протокол и другое железо. Можно придумать миллион вариантов синхросигналов и контроля целостности данных, но в данном конкретном случае описанном в статье, они будут хуже, так как не принесут улучшений, а только усложнят обработку.
Я такие коды точно изучал в университете. И самосинхрон и самоисправление и достаточность. Жаль не пригодилось только, и забылось. Но математическое обоснование модемной скорости 33.6 помню всех поразило. Когда сплошная математика, причем чисто умозрительная, бумажная, а тут вдруг раз и пример из реальной жизни....
Я тоже пытался вспоминать, но во-первых тридцать лет прошло с момента окончания политеха, во вторых специальность "Радиоэлектроника". Кроме кодов типа Манчестер и кодов Хэмминга вспомнить ничего не смог.
В общем-то, предложенное - это действительно некая разновидность канального кодирования, но только уж очень специфичная разновидность - с огромной избыточностью и отсутствием полноценной самосинхронизации. Не припомню ничего подобного в институте :) А так да - канальных кодов куча, начиная от простейшего манчестера и заканчивая довольно сложными типа 8/14 (EFM) и т.д.
Вы так и не пояснили почему отсутствует полноценная самосинхронизация. Устройство управления блоком света можно реализовать на одном 8 битном сдвиговом регистре с параллельными входами и все будет работать без микроконтроллера, в какой момент не включи такой пульт. А на счет огромной избыточности, вы выше предлагали еще большую избыточность 11бит на сообщение и вас это не смущало. К тому же меньше 8 бит передавать не получиться так как регистр передатчика 8 битный.
почему отсутствует полноценная самосинхронизация
Пояснил. Потому-что полноценный самосинхронизирующийся код позволяет однозначно определить положение в потоке. А в вашем случае при передаче 0x88 приёмник может встать как в правильное положение, так и со сдвигом на 4 бита.
А на счет огромной избыточности
Под избыточностью канального кодирования понимается - сколько бит необходимо передать для правильного приёма единичной посылки. В вашем случае единичная посылка - это 4 бита. Для того, чтобы её правильно принять вам надо передать 3 байта.То есть соотношение именно такое - для передачи 4 бит надо отправить 24.
При предложенном же мною варианте достаточно один раз отправить 5 бит синхропакета и далее достаточно отправлять 5 бит на каждые 4 входных. Ну, желательно время от времени повторять синхропакет. И даже в худшем варианте при отправке синхропакета на каждый пакет данных соотношение - 10 бит в канале на 4 бита данных (ноль после данных ставить совсем не нужно, это я ошибся).
При приеме со сдвигом на любое количество бит команда декодируется корректно.
На счет избыточности, во многих ситуациях , в том числе и в данной конструкции, время потраченное на передачу команды на много важнее. Как я уже сказал передатчик 8 битный, команда записывается в буфер только в момент смены режима и до следующей смены режима микроконтроллер со SPI буфером никаких действий не производит. Поэтому о какой избыточности вы говорите я не понимаю, наоборот присутсвует красивый минимализм.
Идельных решений подходящих для всех случаев жизни не существует, чтобы принять правильное решение надо исходить из ограничений накладываемых конструкцией, и только потом, если такая возможность осталась, из любви к исскуству.
так и со сдвигом на 4 бита.
У автора любой из возможных байт полученных сдвигом интерпретируется как одна команда
т. е. при чтении 0х88 или 0х11 или 0х22 или 0х44 - можно определить, что в регистре циклически сдвигается код команды х11
А если использовать 31 код (простое число), можно воспользоваться (не на микроконтроллере, конечно!) этой предельно лайтовой реализацией Рида-Соломона с говорящим названием, намекающим на происхождение:
Насколько я понимаю, коды Рида-Соломона используются для обнаружения и коррекции ошибок за счет избыточности. Но для того чтобы их использовать данные уже должны быть корректно приняты в виде кадра, после этого надо потратить заметное по меркам 8 битного микроконтроллера время чтобы обработать этот кадр по соответствующему алгоритму.
Это хорошо для большого количества данных в подверженной ошибкам среде, но задачу синхронизации и выделение кадра данных из битового потока они не решают, эта задача перекладывается на железо ближе к физическому протоколу обмена.
Именно так, это для тех случаев, когда кадр не коверкается до потери осязаемости границ, но пара-тройка символов в нём по жизни покорёженные. То есть уже после этого селектора, возможно, даже настроенного допускать при синхронизации несоответствие пары-тройки бит где-то внутри тела.
Но это явно уже не для таких микро-задач, как я сразу и оговорился :) Даже микро-Рид-Соломон уже очень жирный :)
А к любой комбинации последовательности разных кодов набор устойчив? Что будет, скажем, если приёмник получит произвольную часть битов команды X, а оставшуюся - Y? Ни одна такая комбинация не может быть воспринята, как валидная команда из множества?
В моей реализации все три принятых подряд байта должны быть одинаковыми, если это не так, смена команды, помеха - пакет отбрасывается.
На самом деле, я не понимаю, почему Вас ругают - на мой взгляд, задача решена минималистично-красиво - особенно в условиях, когда критичны ресурсы передатчика (обычно бывает наоборот). Вот бы ещё найти способ красиво делать индексный джамп по коду команды прямо из ее сырого представления (чтобы не крутить цикл 7 раз)..
В приемнике с процессорным временем проблем нет, поэтому я не стал делать поиск кода по индексу. Еще одна причина в том, что из доступных 512 программных слов использовано 433, т.е. в лоб табличка просто не влезет.
Ну я точно не ругаю — у меня просто сразу смежная генерация идей заработала, что ещё можно подкинуть в копилку «на будущее», вдруг на производные проекты пригодится. А это решение действительно идеальное.
Подозреваю, что с остальными примерно то же самое — сразу генераторы идей заработали :)
Хм, cделали бы сразу, хоть DALI мастера, хоть слэйва. Тут и манчестерский код прямо в стандарте и сам стандарт для управления светом и памяти МК хватает для Си на XC8 (это уже по вкусу, мне лично ассемблер неудобен).
В данном проекте не требовалась совместимость ни с какими другими устройствами, смысла использовать более "тяжелый" протокол не было никакого.
И ассемблер для разработки мне кажется неудобен буквально всем. Но приходится его использовать если необходимо чтобы программа работала быстро или занимала маленький объем. Для базового блока программа кстати тоже написана на ассемблере. Памяти программ там было достаточно, а вот со временем обработки был большой напряг.
Интересно получаетcя, что в электронике (да и наверно и других областях ), что одни и те же задачи можно решить кучей способов и выбор решений зависит не только от цены но и от цепочек поставок и от личных предпочтений разработчиков.
Потому очень хочется узнать почему именно такой МК был выбран, а не что то другое.
Просто на вскидку он не такой уж и дешевый и размер тут явно не был определяющим фактором, поскольку на плате есть еще и сдвиговые регистры (а может и нет, слишком мало данных).
Вот первый пример на вскидку HC32L110C6UA-SFN20TR , корпус 3x3мм , ценник в полтора-два раза ниже. Документация конечно на китайском, хотя на гитхабе есть готовые проекты на нем, но если заказчик ставил требования удешевления конечного устройства (а не оплаты труда разработчика) , то время на изучение нового камня он бы компенсировал.
Причины можно перечислять долго, список получается большой, вот первые несколько:
— Прибор разрабатывался год назад, в тот момент на рынке еще не было такого количества микроконтроллеров китайского производства.
— Партия устройств предполагалась не очень большой и тратить время на освоение нового микроконтроллера смысла не было.
— Устройство достаточно ответственное, микроконтроллеры microchip применять в проде как то спокойнее, чем микроконтроллер который ты за месяц освоил.
— Даже с microchip микроконтроллерами много нюансов при достаточно подробном даташите и наличие errata. С новым микроконтроллером всякого рода "неожиданности" могут на порядок увеличить время разработки.
Но микроконтроллер интересный, спасибо за наводку, правда на Али он заметно дороже PIC10F322
Самосинхронизирующиеся коды для связи через SPI интерфейс