【嵌入式】开源shell命令行的移植和使用(1)——nr_micro_shell

目录

一 背景说明

二 移植准备

三 移植过程

四 实际使用


一 背景说明

        在进行调试和维护时,常常需要与单片机进行交互,获取、设置某些参数或执行某些操作,nr_micro_shell正是为满足这一需求,针对资源较少的MCU编写的基本命令行工具。虽然RT_Thread组件中已经提供了强大的finsh命令行交互工具,但对于ROM、RAM资源较少的单片机,finsh还是略显的庞大,在这些平台上,若仍想保留基本的命令行交互功能,nr_micro_shell是一个不错的选择。

【嵌入式】开源shell命令行的移植和使用(1)——nr_micro_shell_第1张图片

        nr_micro_shell具有以下优点:

        1.占用资源少,使用简单,灵活方便。使用过程只涉及两个shell_init()和shell()两个函数,无论是使用RTOS还是裸机都可以方便的应用该工具,不需要额外的编码工作。

        2.交互体验好。完全类似于linux shell命令行,当串口终端支持ANSI(如Hypertrm终端)时,其不仅支持基本的命令行交互,还提供Tab键命令补全,查询历史命令,方向键移动光标修改功能。

        3.扩展性好。nr_micro_shell为用户提供自定义命令的标准函数原型,只需要按照命令编写命令函数,并注册命令函数,即可使用命令。

二 移植准备

【1】nr_micro_shell下载地址:

nr_micro_shell: shell for MCU. 单片机命令行交互。

【2】文件目录结构:

名称 说明
docs 文档目录,包含演示的GIF图片等
examples 例子目录,包括命令函数示例: nr_micro_shell_commands.c 和RT_Thread下使用示例 nr_micro_shell_thread.c
inc 头文件目录
src 源代码目录

【3】提前准备好芯片UART串口的初始化以及收发接口;

三 移植过程

【1】目录移植:将下载好的nr_micro_shell文件解压到自己的工程目录下,并在IDE中包含所需的src源文件以及inc头文件(其中 nr_micro_shell_commands.c 文件位于examples文件夹中,也一并移过来方便移植)

【嵌入式】开源shell命令行的移植和使用(1)——nr_micro_shell_第2张图片

【嵌入式】开源shell命令行的移植和使用(1)——nr_micro_shell_第3张图片

【嵌入式】开源shell命令行的移植和使用(1)——nr_micro_shell_第4张图片

        此时编译一下,会出现报错,这就需要修改以下配置

【2】修改配置文件 nr_micro_shell_config.h :

        (i)把下面第44、45行包含了 RT-Thread 的头文件给注释掉,或者自己定义 NR_MICRO_SHELL_SIMULATOR 这个宏进行头文件包含屏蔽也可以:

        (ii)根据自己的shell运行终端配置 NR_SHELL_END_OF_LINE 宏,这个宏配置的是指令是以空格结尾还是换行结尾有效。我这边用的SecureCRT,这边改成1:

【嵌入式】开源shell命令行的移植和使用(1)——nr_micro_shell_第5张图片

        (iii)将上面 shell_printf 宏 改成自己的 printf 打印或者重定向fputc使得printf输出用的是串口的输出接口,我这边用的后一种方式:

int32_t fputc(int32_t ch, FILE *f)
{
    (void)f;  /* Prevent unused argument compilation warning */
    return (Ok == Uart_SendDataPollTimeOut(M0P_UART0, (char)ch, SystemCoreClock/DBG_PRINTF_BAUDRATE)) ? ch: -1;
}

        (iv)可以修改 NR_SHELL_USER_NAME 以使用自定义的用户名。

【3】基本配置完成之后,就完成输出了。下面接着实现串口接收的移植:要实现交互,就需要串口接收中断函数调用 shell() 这个宏(根据自己程序,在串口接收中断函数处接收数据,传递给 shell() 这个宏,也可以使用轮询的机制),我这边是在串口中断中调用的

/**************************************************************************
* 函数名称: Uart0_IRQHandler
* 功能描述: 串口接收中断
**************************************************************************/
void Uart0_IRQHandler(void)
{
    uint8_t ch;

    if(Uart_GetStatus(M0P_UART0, UartRC))       //UART0数据接收
    {
        Uart_ClrStatus(M0P_UART0, UartRC);      //清中断状态位
        ch = Uart_ReceiveData(M0P_UART0);       //接收数据字节
        shell(ch);
    }
    
    if(Uart_GetStatus(M0P_UART0, UartTC))         //UART0数据发送
    {
        Uart_ClrStatus(M0P_UART0, UartTC);        //清中断状态位
    }
}

【4】在程序初始化的时候调用串口的初始化以及shell初始化接口(shell_init()),上电之后即可看到shell的logo,按TAB键即可看到注册的几个命令:

#include "nr_micro_shell.h"

int main(void)
{
    //串口初始化
    Dbg_Init();
    Dbg_Cfg();

    //命令行初始化
    shell_init();

    while(1)
    {
        
    }
}

【5】自定义命令的注册:

        参考 nr_micro_shell_commands.c 中的命令模板,实现自定义的命令,并放在 static_cmd 中进行注册(注意:这边的 {"\0", NULL} 不能删除)。

void shell_show_cmd(char argc, char *argv)
{
    shell_printf("show cmd \r\n");
}

void shell_set_cmd(char argc, char *argv)
{
    shell_printf("set cmd \r\n");
}

#ifdef NR_SHELL_USING_EXPORT_CMD
NR_SHELL_CMD_EXPORT(ls, shell_ls_cmd);
NR_SHELL_CMD_EXPORT(test, shell_test_cmd);
#else
const static_cmd_st static_cmd[] =
	{
		{"ls", shell_ls_cmd},
		{"show", shell_show_cmd},
        {"set", shell_set_cmd},
		{"\0", NULL}};
#endif

        至此,移植结束。

四 实际使用

        实际使用的效果如下:

【嵌入式】开源shell命令行的移植和使用(1)——nr_micro_shell_第6张图片

补充几个别人遇到的问题以及自己遇到的问题待查:

(i)nr_micro_shell 还不支持一些特殊的按键,如果按下了这些特殊按键会导致程序崩溃。而且在使用方向键获取历史命令的时候,会把前导符 ”:“ 给覆盖掉,所以还是有些需要完善的地方的;

(ii)在xshell终端输入指令,nr_micro_shell没有反馈回来指令字母,需要完成一条指令按回车才有反馈,输入指令过程中没有反馈,查看了一下源码,需要在此处修改一下代码,将上面NR_MICRO_SHELL_SIMULATOR这个宏判断去掉,如下:

【嵌入式】开源shell命令行的移植和使用(1)——nr_micro_shell_第7张图片

(iii)在使用TAB键补充的时候,会出现程序崩溃,需要在TAB处理函数处加入一下代码:

【嵌入式】开源shell命令行的移植和使用(1)——nr_micro_shell_第8张图片

(iv)自己调试的时候遇到一个问题:实际使用shell的时候,有时候按空格或者退格键会使得程序直接重启,更换了串口波特率9600为115200之后,问题解决。具体原因不明,希望有大神看到能够帮忙解惑。

你可能感兴趣的:(嵌入式,开源,嵌入式硬件,单片机,shell,命令模式)