通過 《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
這樣是不是就很方便了?!