一,问题
在进行嵌入式开发的时候,用一些必要的LED或者printf之类的语句输出调试信息能极大的提升开发效率——“所见即所得”,但是printf语句却也有些很不方便的地方,这需要引起注意 ???
- 1,大量的打印输出会占用硬件资源(如时钟,GPIO等)
- 2,增加一定的功耗
- 3,影响其他输出(如单片机的TX脚(打印脚)还接到了外设的RX脚,导致外设故障等)
- 4,影响美观(发布版程序应该不包含这些调试代码)
介于这一问题,选择使用宏定义的方式来输出调试语句便是一种很好的解决方法 ???
二,解决
方案1:简洁的“#define ”宏定义 ●●●●●
//完整的调试信息:设备类型,当前源文件名,当前源函数名,当前源代码行号,格式化输出内容,格式化参数
#define DEBUG_L(format,argent...) printf("Node:S, File: "__FILE__", Func: %s(), Line: %03d: "format"", __func__, __LINE__, ##argent)
//简洁的调试信息:设备类型,当前源函数名,格式化输出内容,格式化参数
#define DEBUG_M(format,argent...) printf("Node:S, Func: %s(), "format"", __func__, ##argent)
//最简洁的调试信息:格式化输出内容,格式化参数
#define DEBUG_S(format,argent...) printf(""format"",##argent)
eg1:
使用:DEBUG_L(“SysTime:d:d:dn”,hour,min,sec);
打印:Node:S,File:main.c,Func:main(),Line:066,SysTime:22:30:11
eg2:
使用:DEBUG_M(“SysTime:d:d:dn”,hour,min,sec);
打印:Node:S,Func:main(),SysTime:22:30:11
eg3:
使用:DEBUG_S(“SysTime:d:d:dn”,hour,min,sec);
打印:SysTime:22:30:11
DEBUG_完全取代了printf,所有的DEBUG_(…)都被完全的替换成了printf(…),当需要关闭调试信息时,只需要在printf
前面加上//
即可注释掉所有的打印信息。
ANSI C标准中有几个常用的标准预定义宏:
- __LINE__:在源代码中插入当前源代码行号;
- __FILE__:在源文件中插入当前源文件名;
- __DATE__:在源文件中插入当前的编译日期
- __TIME__:在源文件中插入当前编译时间;
- __STDC__:当要求程序严格遵循ANSI C标准时该标识被赋值为1;
- __cplusplus:当编写C++程序时该标识符被定义。
- __func__:在源代码中插入当前源函数名称;
方案2:专业的“#define,#ifdef,#ifend ”宏定义 ●●●○○
#ifdef __DEBUG
#define DEBUG_L(format,argent...) printf("Node:S, File: "__FILE__", Func: %s(), Line: %03d: "format"", __func__, __LINE__, ##argent)
#define DEBUG_M(format,argent...) printf("Node:S, Func: %s(), "format"", __func__, ##argent)
#define DEBUG_S(format,argent...) printf(""format"",##argent)
#endif
使用时候,需要先在.c文件
或者.h文件
的开头加#define __DEBUG
,然后就可以直接使用DEBUG_L();
或DEBUG_M();
或DEBUG_S();
来打印调试信息了,要想关闭,就直接删除#define __DEBUG
即可。
当然了,这种方法的灵活性没有第一种好,但关闭时候更简单粗暴 ??
三、开启printf功能
//加入以下代码,支持printf函数,而不需要选择use MicroLIB
#if 1
#pragma import(__use_no_semihosting)
//标准库需要的支持函数
struct __FILE
{
int handle;
};
FILE __stdout;
//定义_sys_exit()以避免使用半主机模式
_sys_exit(int x)
{
x = x;
}
//重定向c库函数printf到USART1
int fputc(int ch, FILE *f)
{
/* 发送一个字节数据到USART1 */
USART_SendData(USART1, (uint8_t) ch);
/* 等待发送完毕 */
while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
return (ch);
}
#endif
对于STM32单片机来说,一般使用USART1的PA9引脚打印调试信息,故将上代码加入到USART1的c文件即可。???