Страница 1 из 2

Uart и дерево команд

Добавлено: Ср мар 10, 2010 01:03:25
Negor
Дерево команд - это когда в МК летит 5 байтов и каждый байт соответствует какому то шагу. Например
РАБОТА с ЕПРОМ - ЗАПИСЬ БАЙТА - АДРЕС ЯЧЕЙКИ - БАЙТ
или
РАБОТА С ЕПРОМ - НАЙТИ ПОСЛЕДОВАТЕЛЬНОСТЬ - 3х БАЙТ - 3 байта - ОТСЮДА ЗАПИСАТЬ 5 байт - 5 байт.
ну и т.д. например
РАБОТА С IO - ПОРТ А - ЗАПИСАТЬ БАЙТ - байт
Итак в сети куча библиотек и реализаций приёма и передачи байтов по UART для МК. Причём встречаются как обычные - ждём пока сработает RXC или UDRE и идём дальше, до "с использование преывания и буфера" когда все байты складываются в RAM прерываниями(рассматривается приём) а программа только выуживает их из буфера в нужное время. Но встаёт такой вопрос. Рассмотрим случай с обычным методом.
Но и с теми и другими я не могу сделать задуманное. Код получается каким то топорным. Все посылки ж надо как то отделять + контролировать правильность посылок и целостность. И кроме того - как быть если затык случится посередине дерева? МК станет и будет ждать байтов а комп их не пришлёт ибо что-то пошло не так. Как организовать таймаут и выход с дерева? Я подумывал о жмене флагов но потом отказался от этой идеи. Или она - то что мне надо?

Добавлено: Ср мар 10, 2010 01:21:22
hex32
в формате команды первый байт установи какую нибудь константу, типа начало последовательности, до нее мк просто небудет реагировать. ну и завершить команду тоже можно какойто константой и после нее байт crc. тогда мк точно будет знать что вот ета последовательность байтов ето именно команда, а не ты дотронулся к выводу или какойто случайный поток в результате сбоя. можно немного усложнить и ввести еще подтверждение приема и/или запрос на повтор, таймаут если надо тоже можно добавить

Добавлено: Ср мар 10, 2010 01:22:05
Секретный кот
У меня вот это:
РАБОТА с ЕПРОМ - ЗАПИСЬ БАЙТА - АДРЕС ЯЧЕЙКИ - БАЙТ
дополняется спереди ДЛИНОЙ ПАКЕТА, а сзади CRC8 и шлётся в виде пакета. Получение пакета подтверждается простыми сообщениями, типа ОК. Если подтверждение не получено, отправка пакета повторяется. Если на приёмном конце CRC пакета не сходится, команда не исполняется.

Добавлено: Ср мар 10, 2010 07:18:45
Negor
Из советов я так понял что нужно переписать код, который будет на прерываниях и принимать байты с заданного по заданный(начало и конец посылки). А потом где то выставлять флаг о приходе новой команды. Это понятно,- остался невыясненым вопрос о выходе из дерева команд.
Да - дерево команд - сам придумал) Дерево команд - это граф, в котором вершины соответствуют какому либо пункту или подпункту. Когда мы находимся в самой нижней вершине - это конкретная операция. Все остальные операции - уточнения. Проход по графу осуществляется командами с ПК по uart. Так вот как быть если МК остановился посередине графа и новая команда не приходит. Граф этот реализуется контсрукциями
switch() case
вложенными одна в другую. В начале каждой конструкции ждём команды. Как вывалится из такого места в основной цикл, если работают только прерывания?

Добавлено: Ср мар 10, 2010 08:16:23
ARV
Negor писал(а):Как вывалится из такого места в основной цикл, если работают только прерывания?
не надо делать в прерывании слишком многое! это идеологически неверный подход.

вам надо переписать код, разгрузив обработчик прерывания и нагрузив основной цикл. то есть прерывание только принимает пакеты, а когда пакет принят целиком и без ошибок, то ставится флаг готовности пакета, и в основном цикле начинается разбор принятой команды.

термин ваш - дерево - не удачный, скорее речь идет о команде с параметрами. многоступенчатые switch() рекомендую заменить на нужное количество функций:

Код: Выделить всё

my_packet *data;
if get_uart_packet(data)  // если пришел пакет
   switch(data->command){ // начинаем его разбор
   case cmd_program: 
      program_flash(data);
      break;
   case cmd_erase:
      erase_all(data);
      break;
   case cmv_verify:
      verify(data);
      break;
   }
в этом случае исключена ситуация с "разбором" н6е до конца принятого пакета, а так же путаница с выходом из обработки, если в пакете пришли какие-то неверные данные.

Добавлено: Ср мар 10, 2010 08:51:18
ARV
_noise писал(а):* уже есть... понеслось...
а че - понеслось-то? чем постить сообщения с беллетристикой на полтора экрана проще написать пять строк кода на Си - программист поймет, а непрограммисту и слова не помогут :)

Добавлено: Ср мар 10, 2010 11:41:42
Negor
ARV, в данный момент я использую прерывание по RXC лишь для складывания байтов в буфер. С начала посылается от ПК к МК приветствие. МК ожидает приветствие(В главном цикле ожидаЕтся Прием байта).После п иема приветствия МК ожидает размер пакета. Вот тут если ПК не пришлет размер пакета то МК будет ждат его Вечно. Програмно это глядить как while((chr=uartgetc())and(UARTNOCHAR));Функция uartgetc возвращает int в котором старший байт - статус. Так вот после того как ринято количество байт в посылке МК ожидает этого количества байт. noise, твоего метода организации таймаута я не понял. Опиши подробный словесный алгоритм. МК ожидает посылку сравнивая хвост и голову буфера(кол-во необработанных байт в буфере) таким же циклом. тупо ждет пока прилетит заданное количество байт. Это второе место где может случиться зарык и МК останется там нвечно. Еще раз повторяю - прерывания UDRE и RXC используються исключительно для передачи и приема байтов из\в буфер. О том что остаются прерывания я имелввиду что во время ожидания размера или самого пакета основная программа висит и помочь ей выйти оттуда может лиш рерывание по таймеру. При программировании на ассемблере я бы предпринял попытку в прерывании по таймеру положить другой адрес возврата в стек. Как реализовать это на Си я не знаю и не уверен что имеет смысл. В основной программе кроме приема команд от ПК и работы с епром есть обработка кнопок, формирование строк для дисплея и их вывод и работа с шаговыми двигателями. Такой себе станочек должен получиться.

Добавлено: Ср мар 10, 2010 12:24:28
ARV
Negor, все решается протоколом обмена. разработайте свой собственный или используйте готовые решения. для собственного вам надо:
1. "стандартизировать" пакет для обмена
2. всегда вести обмен пакетами, исключив передачу "внепакетных" данных.
3. определить максимальное время ожидания пакета и сбрасывать все уже данные, если время ожидания пакета истекло, а пакет не принят целиком.

собственно, все просто:
- пакет, предположим, всегда начинается с символа 'S', после которого следует байт, определяющий кол-во "полезных данных (байтов)", затем следует байт контрольной суммы (в число полезных не входит).
- в прерывании по приему байта вы смотрите на следующее: был ли начат прием пакета или нет? если не был, то проверяете принятый символ. если он 'S' - начинаете прием пакета. если принят иной символ - просто сбрасываете его без последствий. так как у вас может быть максимум 256 байтов в пакете (реально может быть и меньше - вам виднее), вы всегда можете заранее вычислить время, которое нужно для полного его приема. допустим, вам хватит 100 мс. значит, вы начинаете прием пакета с запуска таймера на 100 мс. после этого каждый принятый байт в прерывании вы складываете в приемный буфер с одновременным подсчетом контрольной суммы и количества принятых байт. разумеется, когда вы приняли нужное кол-во, вы получаете контрольную сумму и сравниваете ее с рассчитанной. если они не совпали - вы просто переводите систему в состояние "прием не начат", т.е. очищаете буфер и сбрасываете таймер. если же пакет пришел без ошибок, вы останавливаете таймер и устанавливаете флаг "пакет пришел". да, пока флаг "пакет пришел" стоит, желательно игнорировать любые приходящие данные, чтобы исключить "наложение".
- если срабатывает прерывание по таймеру приема пакета, вы опять же переводите все в состояние "прием не начат", как и ранее.
- в основном цикле программы вы иной раз смотрите состояние флага "пакет пришел". если флаг установлен - начинаете разбор буфера - там ваша команда. когда все разобрали - сбрасываете флаг "пакет пришел", чтобы разрешить прием следующего пакета.

вот, примерно так. по-моему, все довольно просто, и никаких "вечных" циклов нет.

P.S. Да, вот что еще хотел сказать: идея со складыванием в стек другого адреса возврата - это идея из области программистского трюкачества, я не побоюсь назвать ее порочной в корне и недопустимой. ничего общего с нормальным программированием это не имеет. причем не зависимо от того, на асме или Си вы это решите сотворить. не делайте так никогда, даже если вы умеете это делать.

Добавлено: Ср мар 10, 2010 13:04:43
Negor
Если я правильно понял, то всем этим делом(ожидание старта, слежение за пакетом, таймаут) занимается прерывание RXC(речь о риеме команд). так? В основной программе лиш обработка принятого пакета по флагу ПАКЕТ ПРИШЕЛ. Так?

Добавлено: Ср мар 10, 2010 13:45:58
Секретный кот
Что-то _шума на форуме становится всё больше и больше :lol:, а вся полезная информация как раз заключается в совете обрабатывать только целиком принятые (через прерывания) пакеты.

Добавлено: Ср мар 10, 2010 14:03:19
ARV
Negor писал(а):Если я правильно понял, то всем этим делом(ожидание старта, слежение за пакетом, таймаут) занимается прерывание RXC(речь о риеме команд). так? В основной программе лиш обработка принятого пакета по флагу ПАКЕТ ПРИШЕЛ. Так?
да, именно так.
но в принципе возможно все это делать и без прерываний - это уже тонкости подходов.

Добавлено: Ср мар 10, 2010 14:05:35
Negor
Все уже решено - по совету ARV расширяю прерывание RXC от приема йтов до приема конкретных пакетов(если я правильно понял его совет). noise, проблема в том что я не знал как правильно сделать обработку пакетов или байтов. из этого вытекала вторая проблема - реализация ограничения времени для ожидания пакета или части пакета. Вот такая история.

Re: Uart и дерево команд

Добавлено: Чт мар 18, 2010 14:45:50
Liv
Посмотрите мой протокол WAKE, может быть, подойдет в готовом виде: http://digit-el.com/files/open/wake/wake.html

Re: Uart и дерево команд

Добавлено: Чт мар 18, 2010 19:08:56
ARV
:shock: ВАУ!!! какие люди среди нас!!! :beer:

Re: Uart и дерево команд

Добавлено: Пт мар 19, 2010 14:42:27
Negor
Спасибо - посмотрю. Интересно поучится

Re: Uart и дерево команд

Добавлено: Чт апр 08, 2010 19:41:49
marsden
Liv писал(а):Посмотрите мой протокол WAKE, может быть, подойдет в готовом виде: http://digit-el.com/files/open/wake/wake.html
Интересная вещь... Только вот я не понял, в ассемблерном коде в каком месте становится понятно, что прием пакета завершен? Или сравнивать два байта в Rx_Str? Протрассировал в avrstudio - после окончания передачи вроде как туда записываются CRC. И еще такой вопрос - для чего в обработчике прерываний разрешаются прерывания?

Re: Uart и дерево команд

Добавлено: Сб апр 10, 2010 02:11:26
Negor
Сам код не использовал, не разобрался до конца. Но идея с esc-последовательностями позволила допилить свой вариант :)

Re: Uart и дерево команд

Добавлено: Вс май 02, 2010 20:35:31
Liv
marsden писал(а):Только вот я не понял, в ассемблерном коде в каком месте становится понятно, что прием пакета завершен? Или сравнивать два байта в Rx_Str?
Нет. основная программа мониторит CMD. Как там появляется команда, выполняет её и сбрасывает код команды. Пример проекта присоединяю.
marsden писал(а):для чего в обработчике прерываний разрешаются прерывания?
Это нужно только в том случае, если в проекте есть другие прерывания, откладывать которые на долгое время нельзя.