单片机shell命令_MCU调试大法:使用串口实现简单shell功能

MCU调试大法:使用串口实现简单shell功能

[复制链接]

MCU程序调试方法有很多,比如软/硬件仿真、添加数据打印等。

像Keil MDK就支持不少单片机的软件仿真,在没有拿到单片机的情况下,就可以先仿真调试部分功能,查看代码逻辑是否正确。硬件仿真则需要借助仿真器,如调试Cortex内核MCU常用的J-Link/ST-Link等。通过watch窗口可以查看变量的值:

在代码中添加数据的打印,则需要借助MCU的串口功能,将运行时的关键数据通过串口打印至PC,便于观察。这是我调试时非常喜欢使用的一个功能,因为需要打印哪些数据完全自主可控,而且可以做到基本不影响程序正常运行。

这里顺便把如何使用printf的方法讲一下,比较简单,会的同学可以直接略过:

/@@* 头文件不能少 */

#include <stdio.h>

/@@* 平台的选择 */

#ifdef __GNUC__

#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)

#else

#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)

#endif /@@* __GNUC__ */

PUTCHAR_PROTOTYPE

{

/@@* 这里只需要实现一个字符ch的发送即可,以下以ST为例 */

HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 1000);

return ch;

}

可交互的调试方法—shell

有了串口数据打印,寻找BUG方便了不少;但是随着使用场景的增多:比如我需要在某个时刻打印某些数据、需要控制程序进入某个分支、调试算法时需要经常修改某些变量的值。此时光有打印就不行了,我需要一个可以实时和MCU进行交互的系统,那就是shell。

这里介绍一个体积极小的嵌入式shell,功能如下:

命令自动补全,使用tab键补全命令

命令长帮助,使用help [command]显示命令长帮助

长帮助补全,输入命令后双击tab键补全命令长帮助指令

快捷键,支持使用Ctrl + A~Z组合按键直接调用函数

shell变量,支持在shell中查看和修改变量值,支持变量作为命令参数

开始移植

1. 下载源码并添加至工程中:

360截图20191106140620843.jpg (5.14 KB, 下载次数: 0)

2019-11-6 14:06 上传

360截图20191106140437649.jpg (11.25 KB, 下载次数: 2)

2019-11-6 14:06 上传

算上h文件,也就5个。

2. 初始化shell

定义shell全局实体:

SHELL_TypeDef shell;

在main中初始化,这里需要提供write函数,即字符发送函数:

/@@* 初始化shell */

shell.read = NULL; //采用中断方式,所以不需要提供read方法

shell.write = user_shellWrite;

shellInit(&shell);

/@@* shell write定义 */

void user_shellWrite(const char ch)

{

/@@* 实现一个字符ch的发送功能,使用阻塞方式发送 */

HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 1000);

}

3. shell调用

在串口接收中断中,调用shellHandler处理函数:

void USART1_IRQHandler(void)

{

HAL_UART_IRQHandler(&huart1);

//将收到的字符实时送入shell处理

shellHandler(&shell, uart1_it_buf);

HAL_UART_Receive_IT(&huart1, (uint8_t *)&uart1_it_buf, 1);

}

4. 配置

将SHELL_DISPLAY_RETURN关闭,不然会打印shell函数返回值;SHELL_USING_CMD_EXPORT则根据个人喜好来,我这里将其关闭,所以以下将使用命令表来添加命令:

/@@**

*  是否显示命令调用函数返回值

* 使能此宏,则每次调用shell命令之后会以整形和十六进制的方式打印函数的返回值

*/

#define SHELL_DISPLAY_RETURN 0

/@@**

* @brief 是否使用命令导出方式

* 使能此宏后,可以使用`SHELL_EXPORT_CMD()`或者`SHELL_EXPORT_CMD_EX()`

* 定义shell命令,关闭此宏的情况下,需要使用命令表的方式

*/

#define SHELL_USING_CMD_EXPORT 0

5. 添加命令

因为定义了SHELL_USING_CMD_EXPORT为0,所以我们使用命令表来添加命令。在shell.c中,这里我们可以看到默认实现了两个命令help和cls:

const SHELL_CommandTypeDef shellDefaultCommandList[] =

{

SHELL_CMD_ITEM_EX(help, shellHelp, command help, help [command] --show help info of command),

SHELL_CMD_ITEM(cls, shellClear, clear command line),

/@@* 在这里按照格式添加自己的命令,如显示版本 */

SHELL_CMD_ITEM(version, shell_showVersion, show current version),

};

shell_showVersion的实现,可以在其他C文件中实现

/@@**

* @brief shell显示当前软件版本

*

*/

void shell_showVersion(void)

{

SHELL_TypeDef *shell = shellGetCurrent();

if (!shell)

{

return;

}

shellDisplay(shell, "\r\n V1.0.0\r\n");

shellDisplay(shell, "\r\n Build: "__DATE__" "__TIME__"\r\n");

return;

}

6. run

实际效果如下:

按TAB可以显示所有命令,在输入命令时按TAB还可以自动补全。

其他

这里只是完成了最基础的移植工作,还有一些高级的功能就等着大家自行摸索啦。

有了shell调试起来肯定如虎添翼,呼呼哈哈!

还有一点,给客户演示demo的时候,逼格也高了很多,哈哈哈!

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值