1 前言
经常调试MCU的时候都是通过简单的发布命令a,b,c让MCU执行一些特定的功能,但是这样不是特别的方便,后来接触到了Linux的控制台,原来世界上还有这么好的东西,用在MCU上也是非常好的,所以我就在网上找资源,结果大神无处不在啊,很快就找到了一个大神的shell源码,于是我就是对其裁剪了一下,然后就移植了一下,并且稍微的小小的封装了一下,以后移植就省事了。源码地址:https://gitee.com/somebug/atomlib。站在大神的肩膀上真的香。
2 下载
我处理后的代码可以在链接下下载:https://download.csdn.net/download/Oushuwen/14890835,下载后解压,文件如下:
引用一下原作者的一些介绍:
其中shell_io.c和cmd.c是我添加的文件。
shell_io.c:移植的接口文件
cmd.c:放了一些demo命令
将其中文件全部添加进项目中,如下:
3 移植
(1)添加shell初始化函数
移植就更加简单了。在main函数中调用ShellInit函数,参数为控制台名称:
/*参数为控制台名称*/
ShellInit("~#:");
(2)添加UART中断回调函数
在UART中断调用回调函数,这里分两种情况:
第一种就是你的UART有类似IDLE中断这样的完整包接收机制,也就确保整包接收完毕。在这种情况下,在UART接收中断调用ShellIdelHandleCallBack(data, RX_BYTE_HANDLE),其中data为UART的数据寄存器的值; 在完整包接收后(或者IDEL中断)调用ShellIdelHandleCallBack(NULL, IDELE_HANDLE)。如下是我的UART中断处理函数:
void DEMO_LPUART_IRQHandler(void)
{
uint8_t data;
/* If new data arrived. */
if ((kLPUART_RxDataRegFullFlag)&LPUART_GetStatusFlags(DEMO_LPUART))
{
data = LPUART_ReadByte(DEMO_LPUART);
ShellIdelHandleCallBack(data, RX_BYTE_HANDLE);
LPUART_ClearStatusFlags(DEMO_LPUART, kLPUART_RxDataRegFullFlag);
}
if ((kLPUART_IdleLineFlag)&LPUART_GetStatusFlags(DEMO_LPUART))
{
ShellIdelHandleCallBack(NULL, IDELE_HANDLE);
LPUART_ClearStatusFlags(DEMO_LPUART, kLPUART_IdleLineFlag);
}
SDK_ISR_EXIT_BARRIER;
}
第二种情况就是没有完整包处理机制的情况下,则可以直接在UART接收中断中调用ShellNoIdelHandleCallBack(uint8_t data)函数,其中data为UART接收字节数据,如下:
void DEMO_LPUART_IRQHandler(void)
{
uint8_t data;
/* If new data arrived. */
if ((kLPUART_RxDataRegFullFlag)&LPUART_GetStatusFlags(DEMO_LPUART))
{
data = LPUART_ReadByte(DEMO_LPUART);
ShellNoIdelHandleCallBack(data);
LPUART_ClearStatusFlags(DEMO_LPUART, kLPUART_RxDataRegFullFlag);
}
}
在这种情况下,shell则会丧失插入输入,翻看历史的功能,但是不影响使用。
(3)添加输出UART发送接口
找到shell_io.c文件,修改SerialPuts函数,实现shell输出,示例如下:
void SerialPuts(char * data, unsigned short len)
{
UARTSendBytes(USART1, (uint8_t*) data, len);
}
这样就移植成功了,效果如下:
4 添加自己的命令
添加命令也非常简单,在shell_io.c中的ShellCommandInit函数中使用用函数shell_register_command(name,func)注册命令,其中name为命令的名字,func则是注册服务函数,比如我想注册一个LED_Control的命令,示例如下:
void LED_Control(void * arg)
{
char * argv[4];
int argc = cmdline_strtok((char*)arg,argv,4);
if(strcmp(argv[1], "ON") == NULL)
{
printk("LED IS ON NOW\r\n", argc);
}
else if(strcmp(argv[1], "OFF") == NULL)
{
printk("LED IS OFF NOW\r\n", argc);
}
else
{
printk("Param error, please check it\r\n");
}
}
void ShellCommandInit(void)
{
shell_register_command("hello-world",helloworld);
shell_register_confirm("hello-world2",helloworld,"sure to test this command?");
shell_register_command("param2int",demo_cmd);
shell_register_command("param-get",demo2_cmd);
shell_register_command("getopt-demo",demo3_cmd);
shell_register_command("LED_Control", LED_Control);
}
这样一个新的命令就注册好了,效果如下:
另外在cmd.c中有许多命令处理demo,比如处理有参数的命令,处理有限制符的命令,大家自行体会。