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

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

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

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

上述配置,具体的作用如下:
image.png
/* 开启 FinSH */
  • #define RT_USING_FINSH
  • /* 将线程名称定义为 tshell */
  • #define FINSH_THREAD_NAME "tshell"
  • /* 开启历史命令 */
  • #define FINSH_USING_HISTORY
  • /* 记录 5 行历史命令 */
  • #define FINSH_HISTORY_LINES 5
  • /* 开启使用 Tab 键 */
  • #define FINSH_USING_SYMTAB
  • /* 开启描述功能 */
  • #define FINSH_USING_DESCRIPTION
  • /* 定义 FinSH 线程优先级为 20 */
  • #define FINSH_THREAD_PRIORITY 20
  • /* 定义 FinSH 线程的栈大小为 4KB */
  • #define FINSH_THREAD_STACK_SIZE 4096
  • /* 定义命令字符长度为 80 字节 */
  • #define FINSH_CMD_SIZE 80
  • /* 开启 msh 功能 */
  • #define FINSH_USING_MSH
  • /* 默认使用 msh 功能 */
  • #define FINSH_USING_MSH_DEFAULT
  • /* 最大输入参数数量为 10 个 */
  • #define FINSH_ARG_MAX 10
  • 复制代码

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

    下面以一个简单的实例说明:
    void <b style="color: rgb(0, 0, 0); font-family: Helvetica; font-size: 11px;">helloworld</b>(void)
  • {
  •     rt_kprintf("hello RT-Thread!\n");
  • }
  • 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指令对应的函数:
  • /*********************************************************************
  • * @fn      led
  • *
  • * @brief   gpio operation by pins driver.
  • *
  • * @return  none
  • */
  • int led(void)
  • {
  •     rt_uint8_t count;
  •     rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT);
  •     rt_kprintf("led_SP:%08x\r\n",__get_SP());
  •     for(count = 0 ; count < 10 ;count++)
  •     {
  •         rt_pin_write(LED0_PIN, PIN_LOW);
  •         rt_kprintf("led on, count : %d\r\n", count);
  •         rt_thread_mdelay(500);
  •         rt_pin_write(LED0_PIN, PIN_HIGH);
  •         rt_kprintf("led off\r\n");
  •         rt_thread_mdelay(500);
  •     }
  •     return 0;
  • }
  • static void test(int argc, char**argv)
  • {
  •     if (argc < 2)
  •     {
  •         rt_kprintf("Please input'test param'\n");
  •         return;
  •     }
  •     for(int i=1;i<argc;i++) {
  •         rt_kprintf("param%d is %s\n", i, argv[i]);
  •     }
  •     if (rt_strcmp(argv[1], "led")==0)
  •     {
  •         rt_kprintf("run LED command!\n");
  •         led();
  •     }
  • }
  • MSH_CMD_EXPORT(test, test command: test param);
  • 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
    /*********************************************************************
  • * @fn      led_set
  • *
  • * @brief   use pins driver to set gpio
  • *
  • * @return  none
  • */
  • int led_set(int index, int value)
  • {
  •     rt_base_t pin = index==1 ? 1 : 0;
  •     rt_base_t val = value == 1 ? PIN_LOW : PIN_HIGH;
  •     rt_pin_mode(pin, PIN_MODE_OUTPUT);
  •     rt_pin_write(pin, val);
  •     return 0;
  • }
  • static void test(int argc, char**argv)
  • {
  •     if (argc < 2)
  •     {
  •         rt_kprintf("Please input'test param'\n");
  •         return;
  •     }
  •     for(int i=1;i<argc;i++) {
  •         rt_kprintf("param%d is %s\n", i, argv[i]);
  •     }
  •     if (rt_strcmp(argv[1], "led")==0)
  •     {
  •         rt_kprintf("run LED command!\n");
  •         led();
  •     }
  •     if (rt_strcmp(argv[1], "led_set")==0 && argc==4)
  •     {
  •         int index = 0;
  •         int value = 0;
  •         sscanf(argv[2], "%d", &index);
  •         sscanf(argv[3], "%d", &value);
  •         rt_kprintf("led_set %d %d\n", index, value);
  •         led_set(index, value);
  •     }
  • }
  • 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。

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