Интерфейсы 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, а также оптимизации между ними. Вы должны быстро увидеть, какой из них лучше всего подходит как с вашим стилем кодирования, так и с инструментами/процессорами, а также с проблемой, которую нужно решить.
Спасибо! Ваши ответы и ответы shodanex были для меня наиболее полезными. Конечный автомат кажется правильным выбором, хотя он не так интуитивен, как модульный подход. И, да, интерфейсы ASCII являются уродливыми. Не мой выбор: P – Pav