嵌入式开发中的断言与日志调试方法

167 阅读3分钟

嵌入式 DEBUG 方法

嵌入式开发中,调试手段相对有限,因此通过合适的代码结构和日志系统,可以帮助开发者快速定位问题。以下介绍两种常用的 DEBUG 方法:断言机制彩色日志系统


一、断言机制(Assertion)

断言是一种调试时用于验证程序运行时状态的工具。当条件不满时,程序会打印错信息并停在错误位置,便于开发者定位问题。

示例代码:

#include <stdio.h>

#ifndef assert_printf
#error need define assert_printf
#else

#ifndef NDEBUG

#if __STDC_VERSION__ < 199901L && !defined(__func__)
# if __GNUC__ >= 2
#  define __func__ __FUNCTION__
# else
#  define __func__ "<unknown>"
# endif
#endif

#define vassert(condition, format, ...) do {                           \
        if(!(condition)) {                                             \
            assert_printf("WARNING: %s:%d: %s:"                         \
                          " Assertion \"%s\" failed.\r\n",             \
                          __FILE__, __LINE__, __func__, #condition);   \
            while(1){};                                                \
        } else {                                                       \
            assert_printf(format, ##__VA_ARGS__);                      \
        }                                                              \
    } while(0)

#else

#define vassert(condition, format, ...) do {} while(0)

#endif

#endif

使用说明:

  • 使用 vassert(cond, fmt, ...) 代替传统 assert
  • 如果 cond 不满足,会输出断言失败信息(包括文件名、函数名、行号和条件)。
  • 如枟满足条件,可选择输出调试信息。
  • 需用在项目中定义 assert_printf 实现,如使用 printf

二、彩色日志系统(带级别)

彩色日志系统通过串口输出不同级别、不同颜色的日志信息,便于区分信息、警告、错误等内容。

示例代码:

#include <stdio.h>

#define DBG_UART printf

#ifdef CONFIG_DEBUG

extern int log_num;

#ifdef CONFIG_DEBUG_COLOR_MODE
#define COLOR_SET(dis_mode, fwd_color, bak_color) DBG_UART("\033[%d;%d;%dm", dis_mode, fwd_color, bak_color)
#else
#define COLOR_SET(dis_mode, fwd_color, bak_color) (NULL)
#endif

#define DBG_LOG(x, y, z, str, ...)    \
    {                                 \
        COLOR_SET(x, y, z);           \
        DBG_UART(str, ##__VA_ARGS__); \
        COLOR_SET(0, 0, 0);           \
    }

/*
 *  I:INFO W:WARN E:ERR F:FLAG
 *  log_num: 每条日志的编号
 *  DBG_NAME: 当前模块名(需要在使用前定义)
 */

#if CONFIG_DEBUG_LEVEL >= 0x01
#define DBG_E(str, ...)                                   \
    {                                                     \
        COLOR_SET(31, 31, 1);                             \
        DBG_UART("[%05d] E/%-4s: ", log_num++, DBG_NAME); \
        DBG_UART(str, ##__VA_ARGS__);                     \
        COLOR_SET(0, 0, 0);                               \
    }
#else
#define DBG_E(str, ...) while(0)
#endif

#if CONFIG_DEBUG_LEVEL >= 0x02
#define DBG_W(str, ...)                                   \
    {                                                     \
        COLOR_SET(33, 33, 1);                             \
        DBG_UART("[%05d] W/%-4s: ", log_num++, DBG_NAME); \
        DBG_UART(str, ##__VA_ARGS__);                     \
        COLOR_SET(0, 0, 0);                               \
    }
#else
#define DBG_W(str, ...) while(0)
#endif

#if CONFIG_DEBUG_LEVEL >= 0x03
#define DBG_F(str, ...)                                   \
    {                                                     \
        COLOR_SET(36, 36, 1);                             \
        DBG_UART("[%05d] F/%-4s: ", log_num++, DBG_NAME); \
        DBG_UART(str, ##__VA_ARGS__);                     \
        COLOR_SET(0, 0, 0);                               \
    }
#else
#define DBG_F(str, ...) while(0)
#endif

#if CONFIG_DEBUG_LEVEL >= 0x04
#define DBG_I(str, ...)                                   \
    {                                                     \
        DBG_UART("[%05d] I/%-4s: ", log_num++, DBG_NAME); \
        DBG_UART(str, ##__VA_ARGS__);                     \
    }
#else
#define DBG_I(str, ...) while(0)
#endif

#else
#define DBG_I(str, ...) while(0)
#define DBG_W(str, ...) while(0)
#define DBG_E(str, ...) while(0)
#define DBG_F(str, ...) while(0)
#endif

使用说明:

  • 在不同模块中定义 DBG_NAME 作为模块标识。
  • 日志级别由 CONFIG_DEBUG_LEVEL 控制(例如:0x01 只输出错误,0x04 全部输出)。
  • CONFIG_DEBUG_COLOR_MODE 控制是否启用彩色输出(需终端支持 ANSI 转义)。
  • 常用颜色:
    • 红色:错误 (E)
    • 黄色:警告 (W)
    • 青色:标志 (F)
    • 默认颜色:信息 (I)