单⽚机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.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命令,关闭此宏的情况下,需要使⽤命令表的⽅式
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的时候,逼格也⾼了很多,哈哈哈!

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。