章节列表

命令解释器设计

2018-03-12 11:36:28 +0000 李述铜

该部分主要实现命令解释器,该解释器读取串口交互中的命令输入,解析,然后调用相应的操作。

主要内容

命令解释器的实现较为简单,流程简单归纳为:

  • 打印命令提示符
  • 读取一行字符串
  • 解析命令,执行操作,必要时打印结果

具体执行的操作,大多是调用驱动来完成相应的操作。

重点难点

该设计中使用了两个C库函数:strstr, strtok,这两个函数的说明如下。

strtok说明

从串口中读取的是一行字符串,借助该函数中可以命令行进行解析,分割出命令、参数1、参数2等。

函数原型为:char * strtok ( char * str, const char * delimiters );

该函数会对字符串进行逐个扫描,然后分解为一个个子串。分解的依据为任何包含在delimiters字符数组中的字符。以” ab cd e “为例,可以看到字符串中空白符为” “,所以只需要对delimiters设置为仅包含’ ‘的数组。

  • 第一次调用时,向str传递一个字符串,函数会进行扫描,扫描到第一个不在delimiters中的字符。具体来说,对” ab cd e “扫描,开头有几个’ ‘,该字符在delimiters数组中,所以会扫描到’a’开头,然后将’a’处地址返回。
  • 之后的每次调用, str传递NULL进去,无需再传递原字符串,因为该函数内部会自动记录上次扫描的位置和状态。扫描时,则会继续从上次获得的位置,’a’处开始继续扫,当遇到一个在delimiters的字符串后(如’ ‘),认为上一个字符串结束。然后再继续往下扫,扫描到一个不在delimiters的字符(’c’),认为一个新字符串开始,然后将’c’的地址返回。

这样通过连续不断地调用,就能将字符串分解为一个个小的子串,” ab cd e “分解为”ab”, “cd”, “e”。

注意:

  • 每次调用该函数都会对原始字符串str进行修改,所以这个被字符串不能位于不可写的存储区,如flash
  • 该函数非线程安全。由于函数内部有记录上次扫描的结果,所以多个任务同时调用该函数时,该内部状态就可能被多个任务同时修改,造成冲突。如果有多个任务调用,需要使用strtok_r,由任务自行提供状态记录变量。

提供一个简单的示例strtok,也可直接看课程的使用示例:

#include <stdio.h>
#include <string.h>

int main ()
{
  char str[] ="- This, a sample string.";
  char * pch;
  printf ("Splitting string \"%s\" into tokens:\n",str);
  pch = strtok (str," ,.-");
  while (pch != NULL)
  {
    printf ("%s\n",pch);
    pch = strtok (NULL, " ,.-");
  }
  return 0;
}

输出:
Splitting string "- This, a sample string." into tokens:
This
a
sample
string

strstr说明

在使用strtok解析命令串后,有时需要判断命令是什么,这时就需要使用到比较字符串。字符串的比较,可以使用的strcmp/strncmp,不过课程中所用的是strstr。

函数原型:const char * strstr ( const char * str1, const char * str2 );
功能:在str1中查找子串str2,并返回其起始位置;如果str2不在str1中,返回NULL

该函数区别于strcmp之处在于:strcmp仅能从字符串开始处比较,判断是是否相同。strstr不限定起始位置查找,返回出现的起始位置。

可见在这门课程中的应用,如果使用strcmp,比较更严格些,只能从开始处比较;使用strstr则不那么严格。

应用示例,来源strstr

/* strstr example */
#include <stdio.h>
#include <string.h>

int main ()
{
  char str[] ="This is a simple string";
  char * pch;
  pch = strstr (str,"simple");
  strncpy (pch,"sample",6);
  puts (str);
  return 0;
}

输出:This is a sample string

注意事项

常见问题