【问题标题】:Processing ASCII commands via RS232 in embedded c在嵌入式 c 中通过 RS232 处理 ASCII 命令
【发布时间】:2013-05-15 17:55:51
【问题描述】:

我的微控制器有一个带有预定义命令集的 RS232 接口。有数百个命令,例如PRESSURE 50可以设置压力为50; LIMIT 60 可以设置一些限制为 60。

目前,这是使用一系列嵌套的 switch 语句处理的,但这似乎是一个不雅的解决方案。

处理这些命令的推荐/最有效/最易读的方法是什么? LUT 将是最整洁的,但肯定会有很多不存在的字母组合的空条目(不理想..)。

感谢您的任何想法..

【问题讨论】:

  • 过去我把这个任务分成两部分:词法扫描和语法分析。词法扫描器将输入文本转换为标记。每个以空格分隔的单词按顺序与按字母顺序排列的相同长度关键字列表进行比较。匹配产生一个标记值。数字被转换为数字标记和二进制值。解析使用switchif 语句查看how-to-write-a-compiler book 以了解其他想法。
  • 这听起来会优化效率,但实际上会牺牲可维护性——我想让它尽可能地防止开发人员出错,因此按命令字符串长度排序的单独数组听起来像是自找麻烦。 .
  • 为了解决您的还原论之痒,请参阅Boyer-Moorelexer 基本上会生成 256 个入口状态机的表。我想strnstr() 正在做类似的事情。 Boyer-Moorebsearch() 快,因为您可以跳过字符。考虑 catcabcar。如果第一个字符匹配 c,则检查第三个字符并跳过第二个字符。 lexer 也可以对多个字符串执行此操作。
  • "...但确实会牺牲可维护性" -- 关键是将词法(字符串比较)与语法处理分开。单独的词法扫描允许命令的国际化或同义词。重点是代币。组织/维护字符串数组很简单。也许如果您计划解析的所有内容都是 的形式,那么这有点过头了。

标签: c serial-port embedded


【解决方案1】:
  1. 运行时建议:

    带有结构体{字符串,函数指针)的排序数组

    我希望 qsort()bsearch() 在您的平台上可用 (stdlib.h)

  2. 设计时提案:

    正如 cmets 建议的那样,最好在设计时对数组初始化的条目进行排序。存在很多方法,从代码生成(豪华)到宏处理(差)。

    申报建议,一对多:

    typedef unsigned char byte;
    
    typedef char commandId_t[40];
    
    typedef void (*commandHandler_t)( const byte * payload );
    
    typedef struct command_s {
       const commandId_t      commandId;
       const commandHandler_t handler;
    } command_t;
    
    static const command_t commands[] = {
    #include "sortedCommandInitializers"
    };
    

    文件sortedCommandInitializers{"command-name", function-name},的列表,可以通过Makefile中的命令sort CommandInitializers.c > sortedCommandInitializers进行排序。

    对于make,它与其他任何依赖项一样:

    sortedCommandInitializers: CommandInitializers.c
        sort CommandInitializers.c > sortedCommandInitializers
    
    myProgram.o: myProgram.c myProgram.h sortedCommandInitializers
    

【讨论】:

  • 看起来你应该能够在编译时进行排序,或者在启动时只失败一次,所以速度并不重要。
  • 没错,在设计时排序效率更高,但需要一个好的过程,在启动时它可能是可以接受的。
  • 这看起来确实是一个不错的、易于阅读的解决方案 - 您将如何在 C 语言中在编译时实现排序?
  • 这是我最后选择的选项,因为它似乎也增强了可读性。非常感谢所有贡献想法的人!
【解决方案2】:

试过 strnstr 函数吗?它真的非常快。对于 100 个单词,它可能会比 8 或 9 个单独的 strcmp() 更快,中间有一些额外的代码来遍历一棵树,并且需要更少的内存来存储。

我会尝试以下方法

a) 建立一个命令列表并将最常用的放在开头,并为每个命令添加一个唯一编号,即

char command_names[] =

"PRESSURE 1"
"LIMIT 2"

;
int command_names_len = sizeof(command_names_str)

C 编译器应该为您附加这些字符串,因此很容易将它们移动到另一个位置

b) 添加的这些数字是函数指针数组的索引,每个函数都应该具有相同的签名,当您允许某些函数具有未使用的参数时,这可能是可能的吗? 即

/* just an example */
void (command*)(int a, int b, int c, int d);

void command_pressure (int a, int b, int c, int d) { }
void command_limit(int a, int b, int c, int d) { }

command commands[] =
( /*notused*/ NULL

, /*     1 */ command_pressure
, /*     2 */ command_limit

);

两个列表在视觉上也会相互匹配,从而更容易控制和维护。 cmets 中的数字仅用于帮助,应与大字符串构建中的数字与函数名称匹配

那么处理传入的命令就是字符串格式就很简单了

char search_command[20]; /* or whatever the longest command name is */
char* position_of_command = NULL;
int number_of_command = -1;

strncpy( search_command, incomming_command, sizeof(search_command) );
strcat( search_command, " " );  /* must end with blank */

command_position = strnstr( command_names, search_command, command_names_len );
if( command_position != NULL ) {
  position_of_command += strlen(s earch_command) ; /* at beginning of number */
  number_of_command = atoi( position_of_command );
}

if( number_of_command > 0 ) {
  (*commands[number_of_command])(a,0,0,d);
} else {
  /* unknown */
}

前段时间我写了普通的旧 C,所以它可能包含语法错误,但这是我的想法。

优点:

a) 小内存打印:没有额外的指针或其他额外的结构开销来查找命令,很少的编程行

b) 易于维护:它是“表格”组织的

c) 最常用的命令处理速度最快!

缺点:

a) 请记住,不允许以相同字符串结尾的命令。可以通过在名称开头和 search_command 中添加空格来克服。即

" PRESSURE 1"
" LIMIT 2"

【讨论】:

  • 哇,非常详细和有趣的解决方案。谢谢!我不会想到这一点。我唯一有点担心的是必须在命令旁边保留数字。如果我可以自动插入这些数字,那就太好了。我认为这是不可能的,但我确实喜欢与this post 或类似的结合的想法。 .
  • 命令旁边的数字可以不连续,只要它们与命令表中函数指针的位置匹配即可。所以添加名称可以在任何地方,而在最后添加函数指针是最简单的。但我会先让两张桌子都匹配它们的位置,然后随着时间的推移逐渐转移。
  • 如果可以在运行时构建这两个表,那么您只需要维护一个函数调用表,其中包含两个参数:名称和指向函数的指针。在该函数内部,可以连接字符串并将命令添加到正在构建的表的末尾。如果你把它放在一个单独的包含文件中,你可以在嵌入式系统之外编译和运行它,只是为了看看分配的表是否足够大等等。也许在它周围放一个宏以避免所有命令函数都必须可用 -只需忽略宏中的那个参数。
  • 我认为这根本行不通,当然命令的数字部分不能是命令的静态名称的一部分?这意味着LIMIT 1 不同于LIMIT 2 等等,这看起来非常浪费而且非常烦人。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-15
  • 2014-06-02
  • 1970-01-01
  • 1970-01-01
  • 2013-01-22
相关资源
最近更新 更多