STM32模块化调试技巧 原 荐

通过 《STM32串口向世界问好》介绍了如何重定向后,利用printf打印出信息,这个在程序调试中很有用。

但当一个项目软件代码多了以后,尤其是分了很多模块后,这样打印就不方便了,因为有时我只想看本模块的打印的信息,而又不想被其他模块信息干扰,怎么办呢?
一种简单直观的方法是为本模块单独写一个打印信息的函数来调用。然而当模块很多时,这样做就效率就不高了,并显得冗余。下面介绍我设计的一个可配置的模块打印信息的方法(此适用于裸机程序) 。

在此我单独写了一个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

这样是不是就很方便了?! 


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章