2010-08-23 3 views
4

Я хотел бы интерпретировать командную строку, полученную микроконтроллером (PIC16f877A, если это имеет значение) через последовательный порт.Интерпретатор последовательной команды микроконтроллера в C/C++; Способы сделать это;

Струны имеют довольно простой и прямой Foward форматирование: $ AABBCCDDEE (5 «блоки» 2 chracters + «$» для 11 символов в общей сложности), где: $ AA = фактическое имя команды (может буквы, цифры, оба; обязательные); BB-EE = параметры (номера; опционально);

Я хотел бы написать код на C/C++.

Я полагаю, что я мог бы просто захватить строку через последовательный порт, взломать его на блоки, switch() {case} и memcmp в командный блок ($ AA). Тогда я мог бы иметь двоичное дерево решений, чтобы использовать блоки BB DD и EE.

Я хотел бы знать, правильно ли это сделать (это кажется мне уродливым, конечно, должен быть менее утомительный способ сделать это!).

ответ

3

Интерфейсы ASCII являются уродливыми по определению. В идеале у вас есть какая-то структура кадров, которая, возможно, у вас есть, $ указывает на разделение между кадрами, и вы говорите, что они имеют длину 11 символов. Если всегда 11 хорошо, если только иногда это сложнее, мы надеемся, что в начале есть $ и 0x0A и 0x0D/0x0A в конце (CR/LF). Обычно у меня есть один модуль кода, который просто извлекает байты из последовательного порта и помещает их в (круговой) буфер. Буферизация, относящаяся к дням, когда на последовательных портах было очень мало никакого буфера на борту, но даже сегодня, esp с микроконтроллерами, это все еще так. Затем еще один модуль кода, который отслеживает поиск буфера для фреймов. В идеале этот буфер достаточно велик, чтобы оставить рамку там и иметь место для следующего кадра и не требует другого буфера для хранения копий полученных кадров. используя круговой буфер, этот второй модуль может перемещаться (отбрасывая, если необходимо, по мере его поступления) указатель на начало маркера кадра и ждет полной информации о кадрах. Как только появляется полный кадр, он вызывает другую функцию, которая обрабатывает этот кадр. Эта функция может быть той, о которой вы просите. И «просто код» может быть ответом, вы находитесь в микроконтроллере, поэтому вы не можете использовать ленивое настольное приложение высокого уровня для решений операционной системы. Вам понадобится какая-то функция strcmp, если она создана или доступна вам через библиотеку или не зависит от вашего решения. Грубая сила if (strncmp (& frame [1], «bob», 3) == 0) then else else if (strncmp (& frame [1], «ted», 3), тогда, если ... Конечно работает, но вы можете пережевывать свой ролик с помощью такого рода вещей или нет. Буферизация, требуемая для такого подхода, может пережевывать много барана. Этот подход очень читабельен и удобен в обслуживании и переносится. (поддерживаемый обычно конфликтует с надежностью и/или производительностью), но это может и не быть проблемой, если вы можете обработать это до следующего следующего, и до того, как необработанные данные выпадут из кругового буфера. задача проверки фрейма может просто проверить, что кадр хорош, я обычно ставил маркеры начала и конца, длину и некоторую арифметическую контрольную сумму, а если это плохой фрейм, он отбрасывается, это экономит много кода, проверяя на плохое/поврежденные данные. Когда процедура обработки кадров возвращается к поиску подпрограмм фрейма, ves указатель головы, чтобы очистить кадр, поскольку он больше не нужен, хороший кадр или плохой. Контроллер кадра может только проверять фрейм и передать его еще одной функции, которая выполняет синтаксический анализ. Каждый блок lego в этой компоновке имеет очень простую задачу и работает в предположении, что блок lego под ним выполнил свою задачу должным образом. Модульный, объектно-ориентированный, любой термин, который вы хотите использовать, значительно упрощает проектирование, кодирование, обслуживание, отладку. (ценой исполнения и ресурсов). Этот подход хорошо подходит для любого потока серийного типа, будь то последовательный порт в микроконтроллере (с достаточным количеством ресурсов), а также приложения на рабочем столе, которые ищут последовательные данные из последовательного порта или TCP-данных, которые также являются ориентированными на серию и НЕ.

Если ваш микрофон не имеет ресурсов для всего этого, то подход государственного аппарата также работает достаточно хорошо. Каждый байт, который прибывает, фиксирует состояние конечного автомата в одном состоянии. Начать с ожидания ожидания первого байта, это первый байт a $? не отбрасывайте его и не возвращайтесь в режим ожидания. если первый байт равен $, перейдите в следующее состояние. Если бы вы искали команды «и», «добавить», «или» и «xor», то второе состояние сравнивалось бы с «a», «o» и «x», если ни одно из них тогда перейдите в режим ожидания. если a затем переходит в состояние, которое сравнивается для n и d, если o затем переходит в состояние, которое ищет r. Если поиск r in или state не видит r, тогда перейдите в режим ожидания, если он затем обработает команду, а затем перейдет в режим ожидания. Код читается в том смысле, что вы можете смотреть на машину состояний и видеть слова a, n, d, a, d, d, o, r, x, o, r и где они в конечном итоге приводят, но в целом не считается читаемым кодом. Этот подход использует очень мало баранов, опирается на ром немного больше, но в целом может использовать наименьшее количество ромов, а также по сравнению с другими подходами синтаксического анализа.И здесь снова очень портативно, за пределами микроконтроллеров, но за пределами микроконтроллеров люди могут подумать, что вы сумасшедшие с таким кодом (ну, конечно, если это были verilog или vhdl, конечно). Этот подход сложнее поддерживать, труднее читать, но он очень быстрый и надежный и использует наименьшее количество ресурсов.

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

Интерфейсы в нижней строке ascii всегда уродливы, код для них, независимо от того, сколько слоев библиотек вы используете, чтобы упростить работу, полученные инструкции, которые выполняются, являются уродливыми. И один размер не подходит никому по определению. Просто начните кодирование, попробуйте машину состояний и попробуйте if-then-else-strncmp, а также оптимизации между ними. Вы должны быстро увидеть, какой из них лучше всего подходит как с вашим стилем кодирования, так и с инструментами/процессорами, а также с проблемой, которую нужно решить.

+0

Спасибо! Ваши ответы и ответы shodanex были для меня наиболее полезными. Конечный автомат кажется правильным выбором, хотя он не так интуитивен, как модульный подход. И, да, интерфейсы ASCII являются уродливыми. Не мой выбор: P – Pav

2

Это зависит от того, какую фантазию вы хотите получить, сколько различных команд есть и могут ли новые команды чаще всего добавляться.

Вы можете создать структуру данных, которая связывает каждую действительную командную строку с соответствующим указателем функции. Сортированный список, к которому обращаются с bsearch(), вероятно, прекрасен, хотя хеш-таблица является альтернативой, которая может иметь лучшую производительность (поскольку набор действительных команды известны заранее, вы можете построить идеальный хеш с помощью инструмента, такого как gperf).

bsearch() подход может выглядеть следующим образом:

void func_aa(char args[11]); 
void func_cc(char args[11]); 
void func_xy(char args[11]); 

struct command { 
    char *name; 
    void (*cmd_func)(char args[11]); 
} command_tbl[] = { 
    { "AA", func_aa }, 
    { "CC", func_cc }, 
    { "XY", func_xy } 
}; 

#define N_CMDS (sizeof command_tbl/sizeof command_tbl[0]) 

static int comp_cmd(const void *c1, const void *c2) 
{ 
    const struct command *cmd1 = c1, *cmd2 = c2; 

    return memcmp(cmd1->name, cmd2->name, 2); 
} 

static struct command *get_cmd(char *name) 
{ 
    struct command target = { name, NULL }; 

    return bsearch(&target, command_tbl, N_CMDS, sizeof command_tbl[0], comp_cmd); 
} 

Тогда, если у вас есть command_str указывая на строку из последовательного порта, вы могли бы сделать это, чтобы послать правильную функцию:

struct command *cmd = get_cmd(command_str + 1); 

if (cmd) 
    cmd->cmd_func(command_str); 
+0

Спасибо! Мне нужно будет читать хэш-таблицы и хэш-функции: D – Pav

5

Не задумывайтесь над дизайном! Это не означает, что нужно вслепую кодировать, но как только вы разработали что-то, похожее на то, что оно может выполнить эту работу, вы можете начать ее реализовывать. Реализация даст вам отзывы о вашей архитектуре.

Например, при написании вашего корпуса коммутатора вы можете переписать код, очень похожий на тот, который вы только что написали для предыдущего случая. Фактически запись алгоритма поможет вам увидеть некоторые проблемы, которые вы не придумали, или некоторое упрощение, которое вы не видели.

Не стремитесь к лучшему коду с первой попытки. Стремитесь

  • легко читать
  • легко отлаживать

Возьмите Litlle шаги. Вам не нужно выполнять все это за один раз.

  • Возьмите строку из последовательного порта. Выглядит просто, не так ли? Ну, давайте сделаем это сначала, просто распечатав команды.
  • Отделите команду от параметров.
  • Извлечь параметры. Будет ли извлечение одинаковым для каждой команды?Можете ли вы создать структуру данных, действующую для каждой команды?

Как только вы это исправите, вы можете начать думать о лучшем решении.

+0

Спасибо! Я собирался сделать именно это. Старт кодирования вслепую, то есть: D – Pav

0

Не знаете, продолжаете ли вы по-прежнему работать над этим. Но я работаю над подобным проектом и нашел встроенный интерпретатор командной строки http://sourceforge.net/projects/ecli/?source=recommended. Правильно, у них были встроенные приложения.

Функция cli_engine действительно помогает принимать входные данные из командной строки.

Предупреждение: кроме файла readme нет документации. Я все еще работаю над некоторыми ошибками, интегрирующими структуру, но это определенно дало мне начало. Вам придется иметь дело со сравнением строк (т. Е. С использованием strcmp) самостоятельно.

 Смежные вопросы

  • Нет связанных вопросов^_^