自定义printf格式化输出


很多时候,我们需要使用printf打印日志,数据,在嵌入式中,往往需要将串口输出、USB输出、屏幕打印重定向到C标准的printf中,在不同的编译器上重定向的方式不同,移植起来有些麻烦。所以直接定义一个属于自己的printf,可以套用在USB,串口,屏幕等通信上。

代码

#include "main.h"
#include "usbd_cdc_if.h"
#include <string.h> // 包含字符串处理函数声明
#include <stdarg.h> // 包含可变参数函数处理宏声明

//myprintf相关
#define DMA_MODE 0
#define USB_DEBUG 1
#define UART_HANDLER huart3
#define BUFFER_SIZE 100 // 定义缓冲区大小为100字节

void my_printf(const char *fmt, ...); 

void my_printf(const char *fmt, ...) 
{
    static uint8_t debug_buffer[BUFFER_SIZE];
    va_list args; // 定义一个变量参数列表
    int len; // 用于存储格式化后的字符串长度

    // 初始化变量参数列表,使其指向fmt后面的参数
    va_start(args, fmt);

    // 使用vsnprintf函数将格式化的字符串写入debug_buffer,BUFFER_SIZE作为最大长度限制以防止溢出
    len = vsnprintf((char*)debug_buffer, BUFFER_SIZE, fmt, args);
    
    // 检查是否发生缓冲区溢出
    if(len >= BUFFER_SIZE) {
        // 处理潜在的缓冲区溢出错误,这里可以选择记录警告信息
        len = BUFFER_SIZE - 1; // 确保字符串被正确终止
    }

    // 确保字符串以空字符终止
    debug_buffer[len] = '\0';

    // 通过CDC接口发送格式化后的数据,len为实际发送的字节数(不包括末尾的'\0')
    #if USB_DEBUG
        CDC_Transmit_FS(debug_buffer, len);
    #elif DMA_MODE
        HAL_UART_Transmit_DMA(&UART_HANDLER,debug_buffer,len);
    #else
        HAL_UART_Transmit(&UART_HANDLER,debug_buffer,len,HAL_MAX_DELAY);
    #endif

    // 清理变量参数列表,释放相关资源
    va_end(args);
}

便于移植。

AI提供的分析

代码功能

格式化字符串输出:

使用 vsnprintf 将可变参数格式化为字符串并存储在缓冲区 debug_buffer 中。

多种输出模式:

根据宏定义选择不同的输出方式:

USB_DEBUG: 使用 USB CDC 接口发送数据。
DMA_MODE: 使用 DMA 模式通过 UART 发送数据。
默认:通过阻塞模式的 UART 发送数据。

防止缓冲区溢出:

使用 BUFFER_SIZE 限制 vsnprintf 的最大输出长度,避免内存访问越界。

动态参数支持:

使用可变参数(va_list)机制支持灵活的格式化输出。


文章作者: biubiu选手
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 biubiu选手 !
评论
  目录