本帖最后由 aple0807 于 2022-12-15 18:36 编辑
开发MCU软件最常用的调试方式就是利用调试工具在线调试,打断点观察程序运行数据。但在部分场合不方便一直连接调试工具,特别是产测阶段或者现场维护等操作。此时为程序添加SHELL接口可以极大改善调试速度。
本次使用MM32L0136开发板的串口实现SHELL功能。
本程序SHELL的原理主要借助与编译工具 section 属性特征实现,即链接器会按照section属性值的字符顺序来排列变量。
SHELL核心宏如下:
- typedef struct
- {
- const char *name;
- int (*func)(int, void *[]);
- } func_info_type;
- #define DBG_FUN_BASE_EXPORT(fn, level) \
- extern int fn(int argc, void *argv[]); \
- OBJ_USED const func_info_type __dbg_func_##fn OBJ_SECTION(".app_fn.dbg." level) = \
- { \
- #fn, \
- (void *)fn, \
- }
- #if DBG_EN > 0
- #define DBG_FUN_EXPORT(fn) DBG_FUN_BASE_EXPORT(fn, "2." #fn)
- #else
- #define DBG_FUN_EXPORT(...)
- #endif
- #define SHELL_FUN_EXPORT(fn) DBG_FUN_BASE_EXPORT(fn, "2." #fn)
使用SHELL_FUN_EXPORT处理的函数,会创建一个结构,包括函数地址和函数名。串口接收到一行数据后会搜索函数名,命中则使用绝对地址调用该函数。
- /*******************************************************************************
- * [url=home.php?mod=space&uid=247401]@brief[/url] 搜索指令索引
- * @param cmd
- * [url=home.php?mod=space&uid=266161]@return[/url] 目标索引,-1标示未搜索到
- ******************************************************************************/
- int dbg_fun_list_find(const char *cmd)
- {
- int low, high, mid, des = -1;
- volatile const func_info_type *volatile funlist_start = &__dbg_func_dbg_fun_list_start;
- volatile const func_info_type *volatile funlist_end = &__dbg_func_dbg_fun_list_end;
- low = 1;
- high = (funlist_end - funlist_start);
- while (low <= high)
- {
- ii8 cval;
- mid = (low + high) >> 1;
- cval = comp_string(cmd, (funlist_start + mid)->name, 256);
- if (cval > 0)
- {
- low = mid + 1;
- }
- else if (cval < 0)
- {
- high = mid - 1;
- }
- else
- {
- des = mid;
- break;
- }
- }
- return des;
- }
- /*******************************************************************************
- * @brief: 执行命令
- * @param *cmd
- * [url=home.php?mod=space&uid=266161]@return[/url] {*}
- ******************************************************************************/
- int dbg_fun_list_exe(const char *cmd)
- {
- int argc, site;
- char *argv[10];
- char cbuff[256];
- volatile const func_info_type *volatile funlist_start = &__dbg_func_dbg_fun_list_start;
- copy_str(cmd, cbuff, sizeof(cbuff) - 1);
- str_remove_l20_ascii(cbuff);
- argc = str_split(cbuff, ' ', argv, arr_len(argv));
- site = dbg_fun_list_find(argv[0]);
- if (site > 0)
- {
- (funlist_start + site)->func(argc, (void **)argv);
- }
- return site;
- }
经过以上处理后,如下书写函数就可以在串口助手调用程序的函数了:
- int sh_func1(int argc, void *argv[])
- {
- printf("shell fun1 is called\n");
- return 0;
- }
- SHELL_FUN_EXPORT(sh_func1);
- int sh_func2(int argc, void *argv[])
- {
- printf("shell fun2 is called\n");
- return 0;
- }
- SHELL_FUN_EXPORT(sh_func2);
下面附上工程,有兴趣的小伙伴可以一起研究,改善功能!
L0136DEMO.rar
(1.43 MB, 下载次数: 1)
示例程序使用UART2作为SHELL串口,演示如下:
|