很多时候,我们需要使用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)机制支持灵活的格式化输出。