Дерево команд - это когда в МК летит 5 байтов и каждый байт соответствует какому то шагу. Например
РАБОТА с ЕПРОМ - ЗАПИСЬ БАЙТА - АДРЕС ЯЧЕЙКИ - БАЙТ
или
РАБОТА С ЕПРОМ - НАЙТИ ПОСЛЕДОВАТЕЛЬНОСТЬ - 3х БАЙТ - 3 байта - ОТСЮДА ЗАПИСАТЬ 5 байт - 5 байт.
ну и т.д. например
РАБОТА С IO - ПОРТ А - ЗАПИСАТЬ БАЙТ - байт
Итак в сети куча библиотек и реализаций приёма и передачи байтов по UART для МК. Причём встречаются как обычные - ждём пока сработает RXC или UDRE и идём дальше, до "с использование преывания и буфера" когда все байты складываются в RAM прерываниями(рассматривается приём) а программа только выуживает их из буфера в нужное время. Но встаёт такой вопрос. Рассмотрим случай с обычным методом.
Но и с теми и другими я не могу сделать задуманное. Код получается каким то топорным. Все посылки ж надо как то отделять + контролировать правильность посылок и целостность. И кроме того - как быть если затык случится посередине дерева? МК станет и будет ждать байтов а комп их не пришлёт ибо что-то пошло не так. Как организовать таймаут и выход с дерева? Я подумывал о жмене флагов но потом отказался от этой идеи. Или она - то что мне надо?
There is only 10 kind of people: those who understands binary code and those who dont!!!
в формате команды первый байт установи какую нибудь константу, типа начало последовательности, до нее мк просто небудет реагировать. ну и завершить команду тоже можно какойто константой и после нее байт crc. тогда мк точно будет знать что вот ета последовательность байтов ето именно команда, а не ты дотронулся к выводу или какойто случайный поток в результате сбоя. можно немного усложнить и ввести еще подтверждение приема и/или запрос на повтор, таймаут если надо тоже можно добавить
РАБОТА с ЕПРОМ - ЗАПИСЬ БАЙТА - АДРЕС ЯЧЕЙКИ - БАЙТ
дополняется спереди ДЛИНОЙ ПАКЕТА, а сзади CRC8 и шлётся в виде пакета. Получение пакета подтверждается простыми сообщениями, типа ОК. Если подтверждение не получено, отправка пакета повторяется. Если на приёмном конце CRC пакета не сходится, команда не исполняется.
Даже остановленные часы два раза в сутки показывают правильное время.
Из советов я так понял что нужно переписать код, который будет на прерываниях и принимать байты с заданного по заданный(начало и конец посылки). А потом где то выставлять флаг о приходе новой команды. Это понятно,- остался невыясненым вопрос о выходе из дерева команд.
Да - дерево команд - сам придумал) Дерево команд - это граф, в котором вершины соответствуют какому либо пункту или подпункту. Когда мы находимся в самой нижней вершине - это конкретная операция. Все остальные операции - уточнения. Проход по графу осуществляется командами с ПК по uart. Так вот как быть если МК остановился посередине графа и новая команда не приходит. Граф этот реализуется контсрукциями
switch() case
вложенными одна в другую. В начале каждой конструкции ждём команды. Как вывалится из такого места в основной цикл, если работают только прерывания?
There is only 10 kind of people: those who understands binary code and those who dont!!!
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е до конца принятого пакета, а так же путаница с выходом из обработки, если в пакете пришли какие-то неверные данные.
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
а че - понеслось-то? чем постить сообщения с беллетристикой на полтора экрана проще написать пять строк кода на Си - программист поймет, а непрограммисту и слова не помогут
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
ARV, в данный момент я использую прерывание по RXC лишь для складывания байтов в буфер. С начала посылается от ПК к МК приветствие. МК ожидает приветствие(В главном цикле ожидаЕтся Прием байта).После п иема приветствия МК ожидает размер пакета. Вот тут если ПК не пришлет размер пакета то МК будет ждат его Вечно. Програмно это глядить как while((chr=uartgetc())and(UARTNOCHAR));Функция uartgetc возвращает int в котором старший байт - статус. Так вот после того как ринято количество байт в посылке МК ожидает этого количества байт. noise, твоего метода организации таймаута я не понял. Опиши подробный словесный алгоритм. МК ожидает посылку сравнивая хвост и голову буфера(кол-во необработанных байт в буфере) таким же циклом. тупо ждет пока прилетит заданное количество байт. Это второе место где может случиться зарык и МК останется там нвечно. Еще раз повторяю - прерывания UDRE и RXC используються исключительно для передачи и приема байтов из\в буфер. О том что остаются прерывания я имелввиду что во время ожидания размера или самого пакета основная программа висит и помочь ей выйти оттуда может лиш рерывание по таймеру. При программировании на ассемблере я бы предпринял попытку в прерывании по таймеру положить другой адрес возврата в стек. Как реализовать это на Си я не знаю и не уверен что имеет смысл. В основной программе кроме приема команд от ПК и работы с епром есть обработка кнопок, формирование строк для дисплея и их вывод и работа с шаговыми двигателями. Такой себе станочек должен получиться.
Negor, все решается протоколом обмена. разработайте свой собственный или используйте готовые решения. для собственного вам надо:
1. "стандартизировать" пакет для обмена
2. всегда вести обмен пакетами, исключив передачу "внепакетных" данных.
3. определить максимальное время ожидания пакета и сбрасывать все уже данные, если время ожидания пакета истекло, а пакет не принят целиком.
собственно, все просто:
- пакет, предположим, всегда начинается с символа 'S', после которого следует байт, определяющий кол-во "полезных данных (байтов)", затем следует байт контрольной суммы (в число полезных не входит).
- в прерывании по приему байта вы смотрите на следующее: был ли начат прием пакета или нет? если не был, то проверяете принятый символ. если он 'S' - начинаете прием пакета. если принят иной символ - просто сбрасываете его без последствий. так как у вас может быть максимум 256 байтов в пакете (реально может быть и меньше - вам виднее), вы всегда можете заранее вычислить время, которое нужно для полного его приема. допустим, вам хватит 100 мс. значит, вы начинаете прием пакета с запуска таймера на 100 мс. после этого каждый принятый байт в прерывании вы складываете в приемный буфер с одновременным подсчетом контрольной суммы и количества принятых байт. разумеется, когда вы приняли нужное кол-во, вы получаете контрольную сумму и сравниваете ее с рассчитанной. если они не совпали - вы просто переводите систему в состояние "прием не начат", т.е. очищаете буфер и сбрасываете таймер. если же пакет пришел без ошибок, вы останавливаете таймер и устанавливаете флаг "пакет пришел". да, пока флаг "пакет пришел" стоит, желательно игнорировать любые приходящие данные, чтобы исключить "наложение".
- если срабатывает прерывание по таймеру приема пакета, вы опять же переводите все в состояние "прием не начат", как и ранее.
- в основном цикле программы вы иной раз смотрите состояние флага "пакет пришел". если флаг установлен - начинаете разбор буфера - там ваша команда. когда все разобрали - сбрасываете флаг "пакет пришел", чтобы разрешить прием следующего пакета.
вот, примерно так. по-моему, все довольно просто, и никаких "вечных" циклов нет.
P.S. Да, вот что еще хотел сказать: идея со складыванием в стек другого адреса возврата - это идея из области программистского трюкачества, я не побоюсь назвать ее порочной в корне и недопустимой. ничего общего с нормальным программированием это не имеет. причем не зависимо от того, на асме или Си вы это решите сотворить. не делайте так никогда, даже если вы умеете это делать.
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
Если я правильно понял, то всем этим делом(ожидание старта, слежение за пакетом, таймаут) занимается прерывание RXC(речь о риеме команд). так? В основной программе лиш обработка принятого пакета по флагу ПАКЕТ ПРИШЕЛ. Так?
Что-то _шума на форуме становится всё больше и больше , а вся полезная информация как раз заключается в совете обрабатывать только целиком принятые (через прерывания) пакеты.
Даже остановленные часы два раза в сутки показывают правильное время.
Negor писал(а):Если я правильно понял, то всем этим делом(ожидание старта, слежение за пакетом, таймаут) занимается прерывание RXC(речь о риеме команд). так? В основной программе лиш обработка принятого пакета по флагу ПАКЕТ ПРИШЕЛ. Так?
да, именно так.
но в принципе возможно все это делать и без прерываний - это уже тонкости подходов.
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
Все уже решено - по совету ARV расширяю прерывание RXC от приема йтов до приема конкретных пакетов(если я правильно понял его совет). noise, проблема в том что я не знал как правильно сделать обработку пакетов или байтов. из этого вытекала вторая проблема - реализация ограничения времени для ожидания пакета или части пакета. Вот такая история.
Интересная вещь... Только вот я не понял, в ассемблерном коде в каком месте становится понятно, что прием пакета завершен? Или сравнивать два байта в Rx_Str? Протрассировал в avrstudio - после окончания передачи вроде как туда записываются CRC. И еще такой вопрос - для чего в обработчике прерываний разрешаются прерывания?
marsden писал(а):Только вот я не понял, в ассемблерном коде в каком месте становится понятно, что прием пакета завершен? Или сравнивать два байта в Rx_Str?
Нет. основная программа мониторит CMD. Как там появляется команда, выполняет её и сбрасывает код команды. Пример проекта присоединяю.
marsden писал(а):для чего в обработчике прерываний разрешаются прерывания?
Это нужно только в том случае, если в проекте есть другие прерывания, откладывать которые на долгое время нельзя.