STM32模块化调试技巧
2014-10-24 09:50
316 查看
通过 《STM32串口向世界问好》介绍了如何重定向后,利用printf打印出信息,这个在程序调试中很有用。
但当一个项目软件代码多了以后,尤其是分了很多模块后,这样打印就不方便了,因为有时我只想看本模块的打印的信息,而又不想被其他模块信息干扰,怎么办呢?
一种简单直观的方法是为本模块单独写一个打印信息的函数来调用。然而当模块很多时,这样做就效率就不高了,并显得冗余。下面介绍我设计的一个可配置的模块打印信息的方法(此适用于裸机程序) 。
在此我单独写了一个debug模块,包含debug.c和debug.h两文件,.c定义了所要调用打印信息函数等, .h可配置,以方便地选择性打印你需要的模块信息。
如我一个工程中包含有系统模块、温度检测模块、电机控制模块,则首先在debug.c中定义如下字符串数组
在.h中作如下定义
其中通过最上面几个宏定义你就可以选择性地打印需要的模块的调试信息,不要打印的直接屏蔽掉就好了,如果再增加模块,只需再多定义一个宏,然把模块数量增加,并在字符串数组里依次添加此模块要打印出名称。
下面介绍如何对以上配置进行解析并按要求打印出来,在.c里如下实现代码
此函数用于检测要打印的模块是否开启,如开启则返回模块对应的偏移量,以方便打印字符串数组中对应的模块名,若没找到,则返回0。
下面就是调试信息打印函数了,其实只需模仿printf函数的实现,并作简单的修改就可实现模块化打印。如下
至此,模块化信息打印方法就实现了。
要进行打印信息调试,如温度检测模块可以如下调用
电机控制模块可如此调用:
如若要屏蔽掉所有的电机模块打印消息,只需要.h文件中作如下修改:
这样是不是就很方便了?!
但当一个项目软件代码多了以后,尤其是分了很多模块后,这样打印就不方便了,因为有时我只想看本模块的打印的信息,而又不想被其他模块信息干扰,怎么办呢?
一种简单直观的方法是为本模块单独写一个打印信息的函数来调用。然而当模块很多时,这样做就效率就不高了,并显得冗余。下面介绍我设计的一个可配置的模块打印信息的方法(此适用于裸机程序) 。
在此我单独写了一个debug模块,包含debug.c和debug.h两文件,.c定义了所要调用打印信息函数等, .h可配置,以方便地选择性打印你需要的模块信息。
如我一个工程中包含有系统模块、温度检测模块、电机控制模块,则首先在debug.c中定义如下字符串数组
char *DEBUG_MODULE_MSG[] = { "NOTHING", "SYS", "TEMP", "MOTOR", };
在.h中作如下定义
#if 1 #define SYS_DEBUG #define TEMP_DEBUG #define MOTOR_DEBUG #endif //------- #ifdef SYS_DEBUG #define SYS (1<<0) #else #define SYS 0 #endif //------- #ifdef TEMP_DEBUG #define TEMP (1<<1) #else #define TEMP 0 #endif //------- #ifdef MOTOR_DEBUG #define MOTOR (1<<2) #else #define MOTOR 0 #endif #define DEBUG_MODULE_NUM 3 //-------
其中通过最上面几个宏定义你就可以选择性地打印需要的模块的调试信息,不要打印的直接屏蔽掉就好了,如果再增加模块,只需再多定义一个宏,然把模块数量增加,并在字符串数组里依次添加此模块要打印出名称。
下面介绍如何对以上配置进行解析并按要求打印出来,在.c里如下实现代码
/** * @brief 检测询要打印的模块 * @param module: 宏定义模块名 * @retval 对应模块字符串偏移量 */ static u16 check_debug_sw(u module) { u16 i ; if (0 == module) { return 0; } else { for (i = 0; i < DEBUG_MODULE_NUM ; i++) { if (module & (1 << i)) { return (i + 1); } } } return 0; }
此函数用于检测要打印的模块是否开启,如开启则返回模块对应的偏移量,以方便打印字符串数组中对应的模块名,若没找到,则返回0。
下面就是调试信息打印函数了,其实只需模仿printf函数的实现,并作简单的修改就可实现模块化打印。如下
/** * @brief 可进行模块选择的可变参数的打印调试函数 * @param module: 宏定义模块名 ... * @retval None */ void Debug_Msg_Module_Printf(u16 module, char *fmt, ...) { va_list ap; char *p = NULL , *sval = NULL; int ival; unsigned uval; double dval; u16 flag = 0 ; if (0 != (flag = check_debug_sw(module))) { printf("[ %s ]", DEBUG_MODULE_MSG[flag]); va_start(ap, fmt); for (p = fmt; *p; p++) { if (*p != '%') { putchar(*p); continue; } switch (*++p) { case 'd': case 'i': ival = va_arg(ap, int); printf("%d", ival); break; case 'c': ival = va_arg(ap, int); putchar(ival); break; case 'u': uval = va_arg(ap, unsigned); printf("%u", uval); break; case 'x': uval = va_arg(ap, unsigned); printf("%x", uval); break; case 'X': uval = va_arg(ap, unsigned); printf("%X", uval); break; case 'o': uval = va_arg(ap, unsigned); printf("%o", uval); break; case 'e': dval = va_arg(ap, double); printf("%e", dval); break; case 'f': dval = va_arg(ap, double); printf("%f", dval); break; case 'g': dval = va_arg(ap, double); printf("%g", dval); break; case 's': for (sval = va_arg(ap, char *); *sval; sval++) { putchar(*sval); } break; default : putchar(*p); break; } } va_end(ap); } }
至此,模块化信息打印方法就实现了。
要进行打印信息调试,如温度检测模块可以如下调用
Debug_Msg_Module_Printf(TEMP,"Temp is %d \n",temp);
电机控制模块可如此调用:
Debug_Msg_Module_Printf(MOTOR,"Motor Running \n"); Debug_Msg_Module_Printf(MOTOR,"Motor Stopped \n");
如若要屏蔽掉所有的电机模块打印消息,只需要.h文件中作如下修改:
#if 1 #define SYS_DEBUG #define TEMP_DEBUG //#define MOTOR_DEBUG //注释掉此行宏定义 #endif
这样是不是就很方便了?!
相关文章推荐
- stm32 的cc3000驱动调试成功第一步,纪念一下
- Android Studio你不知道的调试技巧
- 一些开发心得与调试技巧
- STM32 MDK3.8在SRAM中调试
- 反调试技巧总结-原理和实现
- Intellij IDEA Debug调试技巧
- vc2008调试技巧之输出重定向
- iOS 开发调试技巧总结
- Java程序员应该知道的10个调试技巧
- 深入探索Linux coredump调试技巧
- iOS开发之Xcode常用调试技巧总结
- 02、老徐教你学C语言基础篇2——C语言摩拳擦掌齐上阵(环境篇)——调试工具及调试技巧
- VS2010 调试技巧
- MapReducer程序调试技巧
- 14 个你可能不知道的 JavaScript 调试技巧
- [Cocoa]XCode的一些调试技巧
- Xcode调试技巧之二 crash之后的定位问题
- Android Studio 掌握这些调试技巧,Debug能力不能再高啦
- 11个高效的VS调试技巧
- 开源代码分析技巧之二——gdb单步调试