本帖最后由 HonestQiao 于 2022-7-28 09:28 编辑

Rt-Thread系统,提供了一个命令行组件----FinSH,通过FinSH能够提供一个串口控制台。
在上位机上,可与串口监听工具,或者使用Putty,来连接到该串口控制台。
image.png

发送help指令(勾选回车),可以看到系统自带的一些指令:
image.png

在工程根目录下面的rtconfig.h,有关于FinSH的配置选项:
image.png

上述配置,具体的作用如下:
image.png
  1. /* 开启 FinSH */
  2. #define RT_USING_FINSH

  3. /* 将线程名称定义为 tshell */
  4. #define FINSH_THREAD_NAME "tshell"

  5. /* 开启历史命令 */
  6. #define FINSH_USING_HISTORY
  7. /* 记录 5 行历史命令 */
  8. #define FINSH_HISTORY_LINES 5

  9. /* 开启使用 Tab 键 */
  10. #define FINSH_USING_SYMTAB
  11. /* 开启描述功能 */
  12. #define FINSH_USING_DESCRIPTION

  13. /* 定义 FinSH 线程优先级为 20 */
  14. #define FINSH_THREAD_PRIORITY 20
  15. /* 定义 FinSH 线程的栈大小为 4KB */
  16. #define FINSH_THREAD_STACK_SIZE 4096
  17. /* 定义命令字符长度为 80 字节 */
  18. #define FINSH_CMD_SIZE 80

  19. /* 开启 msh 功能 */
  20. #define FINSH_USING_MSH
  21. /* 默认使用 msh 功能 */
  22. #define FINSH_USING_MSH_DEFAULT
  23. /* 最大输入参数数量为 10 个 */
  24. #define FINSH_ARG_MAX 10


除了FinSH自带的系统指令,我们也可以自定义新的指令。
通过下面的宏:
  1. MSH_CMD_EXPORT(name, desc);
就可以对应到下面的指令:
  1. command [arg1] [arg2] [...]
参数的输入方式,与我们通常的命令行c程序类似。

下面以一个简单的实例说明:
  1. void <b style="color: rgb(0, 0, 0); font-family: Helvetica; font-size: 11px;">helloworld</b>(void)
  2. {
  3.     rt_kprintf("hello RT-Thread!\n");
  4. }

  5. MSH_CMD_EXPORT(<b style="color: rgb(0, 0, 0); font-family: Helvetica; font-size: 11px;">helloworld</b> , say hello to RT-Thread);
MSH_CMD_EXPORT定义指令的时候,第一个占位是命令名称,对应函数命令,第二个是命令说明,直接写,不用引号。


编译下载后,输入helloworld,就能够执行调用了。
image.png

根据模板建立的代码,提供了一个led指令,我们可以写一个test指令,能够输出参数信息,如果指令后面的参数是led,还可以调用这个led指令对应的函数:

  1. /*********************************************************************
  2. * @fn      led
  3. *
  4. * @brief   gpio operation by pins driver.
  5. *
  6. * @return  none
  7. */
  8. int led(void)
  9. {
  10.     rt_uint8_t count;
  11.     rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT);
  12.     rt_kprintf("led_SP:%08x\r\n",__get_SP());
  13.     for(count = 0 ; count < 10 ;count++)
  14.     {
  15.         rt_pin_write(LED0_PIN, PIN_LOW);
  16.         rt_kprintf("led on, count : %d\r\n", count);
  17.         rt_thread_mdelay(500);

  18.         rt_pin_write(LED0_PIN, PIN_HIGH);
  19.         rt_kprintf("led off\r\n");
  20.         rt_thread_mdelay(500);
  21.     }
  22.     return 0;
  23. }

  24. static void test(int argc, char**argv)
  25. {
  26.     if (argc < 2)
  27.     {
  28.         rt_kprintf("Please input'test param'\n");
  29.         return;
  30.     }

  31.     for(int i=1;i<argc;i++) {
  32.         rt_kprintf("param%d is %s\n", i, argv[i]);
  33.     }

  34.     if (rt_strcmp(argv[1], "led")==0)
  35.     {
  36.         rt_kprintf("run LED command!\n");
  37.         led();
  38.     }
  39. }

  40. MSH_CMD_EXPORT(test, test command: test param);
  41. MSH_CMD_EXPORT(led,  led sample by using I/O drivers);


编译下载后,执行test,会提示要输入参数;
输入test 参数1 参数2 。。。,则会打印出参数信息;
如果输入test led,则会调用led指令对应的函数,使得对应的LED点亮。
image.png

通过上面的test指令,我们可以接收到参数了,但是这些参数,都是字符串形式的,我们可以从中提取需要的数据。
例如,下面在test指令中,如果第一个参数是led_set,则顺位读取第二个参数为led的序号,第三个参数为0和1表示关闭或者开启led
  1. /*********************************************************************
  2. * @fn      led_set
  3. *
  4. * @brief   use pins driver to set gpio
  5. *
  6. * @return  none
  7. */
  8. int led_set(int index, int value)
  9. {
  10.     rt_base_t pin = index==1 ? 1 : 0;
  11.     rt_base_t val = value == 1 ? PIN_LOW : PIN_HIGH;

  12.     rt_pin_mode(pin, PIN_MODE_OUTPUT);
  13.     rt_pin_write(pin, val);
  14.     return 0;
  15. }

  16. static void test(int argc, char**argv)
  17. {
  18.     if (argc < 2)
  19.     {
  20.         rt_kprintf("Please input'test param'\n");
  21.         return;
  22.     }

  23.     for(int i=1;i<argc;i++) {
  24.         rt_kprintf("param%d is %s\n", i, argv[i]);
  25.     }

  26.     if (rt_strcmp(argv[1], "led")==0)
  27.     {
  28.         rt_kprintf("run LED command!\n");
  29.         led();
  30.     }
  31.     if (rt_strcmp(argv[1], "led_set")==0 && argc==4)
  32.     {
  33.         int index = 0;
  34.         int value = 0;
  35.         sscanf(argv[2], "%d", &index);
  36.         sscanf(argv[3], "%d", &value);

  37.         rt_kprintf("led_set %d %d\n", index, value);
  38.         led_set(index, value);
  39.     }
  40. }

  41. MSH_CMD_EXPORT(test, test command: test param);

在上述代码中,使用了sscanf,来从对应的参数中,获取输入的数值,再去调用led_set(int index, int value),从而控制LED对应的GPIO。
image.png

需要注意的是,ch32v307的板载的LED1、LED2是低电平触发的,所以设置值value为1的时候,实际使用PIN_LOW,反之则用PIN_HIGH。

通过上面的实例,我们参考来构建自己需要的指令,以及合适的参数。
在串口终端中调试好了,还可以使用其他设备,通过串口来连接,并根据指令格式发送数据,就能够调用和执行对应的指令了。