目录
一 背景说明
二 移植准备
三 移植过程
四 实际使用
一 背景说明
在进行调试和维护时,常常需要与单片机进行交互,获取、设置某些参数或执行某些操作,nr_micro_shell正是为满足这一需求,针对资源较少的MCU编写的基本命令行工具。虽然RT_Thread组件中已经提供了强大的finsh命令行交互工具,但对于ROM、RAM资源较少的单片机,finsh还是略显的庞大,在这些平台上,若仍想保留基本的命令行交互功能,nr_micro_shell是一个不错的选择。
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文件夹中,也一并移过来方便移植)。
此时编译一下,会出现报错,这就需要修改以下配置
【2】修改配置文件 nr_micro_shell_config.h :
(i)把下面第44、45行包含了 RT-Thread 的头文件给注释掉,或者自己定义 NR_MICRO_SHELL_SIMULATOR 这个宏进行头文件包含屏蔽也可以:
(ii)根据自己的shell运行终端配置 NR_SHELL_END_OF_LINE 宏,这个宏配置的是指令是以空格结尾还是换行结尾有效。我这边用的SecureCRT,这边改成1:
(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
至此,移植结束。
四 实际使用
实际使用的效果如下:
补充几个别人遇到的问题以及自己遇到的问题待查:
(i)nr_micro_shell 还不支持一些特殊的按键,如果按下了这些特殊按键会导致程序崩溃。而且在使用方向键获取历史命令的时候,会把前导符 ”:“ 给覆盖掉,所以还是有些需要完善的地方的;
(ii)在xshell终端输入指令,nr_micro_shell没有反馈回来指令字母,需要完成一条指令按回车才有反馈,输入指令过程中没有反馈,查看了一下源码,需要在此处修改一下代码,将上面NR_MICRO_SHELL_SIMULATOR这个宏判断去掉,如下:
(iii)在使用TAB键补充的时候,会出现程序崩溃,需要在TAB处理函数处加入一下代码:
(iv)自己调试的时候遇到一个问题:实际使用shell的时候,有时候按空格或者退格键会使得程序直接重启,更换了串口波特率9600为115200之后,问题解决。具体原因不明,希望有大神看到能够帮忙解惑。