uart_tx.h

发布时间:2026/7/30 4:23:00
uart_tx.h /********************************************************************************* file uart_tx.h* brief 基于 CubeMX 生成 USART 的常用阻塞式串口发送封装。** 依赖CubeMX 已生成并初始化 usart.c / usart.h例如 huart1。* 本文件只声明函数不重新配置波特率、引脚、中断或 DMA。** 最小使用在 main.c 的 USER CODE BEGIN Includes 中包含本文件在* MX_USART1_UART_Init() 执行完成后调用例如* code* UART_Tx_SendLine(huart1, UART ready, 100U);* UART_Tx_SendU32(huart1, 13U, 100U); // 串口显示13不自动换行* UART_Tx_SendLine(huart1, , 100U); // 单独补一个换行* endcode** --------------------------------------------------------------------------* 【全部公开接口的集中调用案例】** 以下代码只用于说明如何在 main.c 中调用。把 #include uart_tx.h 放入* USER CODE BEGIN Includes全部调用均应在 MX_USART1_UART_Init() 之后进行。* huart1 是 CubeMX 在 usart.c / usart.h 中生成的串口句柄。* code* // ---------- 1. 准备测试数据与一个限速器对象 ----------* static UART_Tx_RateLimiter_t log_limiter; // 只定义一次不能放进 while(1)* uint8_t raw_data[] {0xAAU, 0x55U, 0x01U, 0xFFU};* uint8_t frame_payload[] {0x01U, 0x02U};** // ---------- 2. 初始化区USER CODE BEGIN 2 ----------* // 限制为每 500 ms 最多打印一次第一次 AllowSend() 会立即允许。* UART_Tx_RateLimiter_Init(log_limiter, 500U);** // 若调试中要改为每秒一次* UART_Tx_RateLimiter_SetPeriod(log_limiter, 1000U);** // ---------- 3. 主循环USER CODE BEGIN 3 / while(1) ----------* if (UART_Tx_RateLimiter_AllowSend(log_limiter) ! 0U)* {* // (1) 原始二进制实际发出 AA 55 01 FF终端应切换为十六进制显示。* UART_Tx_SendBytes(huart1, raw_data, sizeof(raw_data), 100U);** // (2) ASCII 文本不换行终端接着显示 hello。* UART_Tx_SendString(huart1, hello, 100U);** // (3) ASCII 文本并换行终端显示 UART ready 后跳到下一行。* UART_Tx_SendLine(huart1, UART ready, 100U);** // (4) 无符号整数终端显示 13它发送的是字符 1、3不是 0x0D。* UART_Tx_SendU32(huart1, 13U, 100U);* UART_Tx_SendLine(huart1, , 100U); // 给上一个整数补换行** // (5) 有符号整数终端显示 -123 并换行。* UART_Tx_SendI32(huart1, -123, 100U);* UART_Tx_SendLine(huart1, , 100U);** // (6) 浮点数终端显示 3.2873U 是保留三位小数。* UART_Tx_SendFloat(huart1, 3.287f, 3U, 100U);* UART_Tx_SendLine(huart1, , 100U);** // (7) 十六进制“文本”显示终端显示 AA 55 01 FF 并换行。* // 与 SendBytes 不同此处发送的是 ASCII 字符 A、A、空格……* UART_Tx_SendHex(huart1, raw_data, sizeof(raw_data), 1U, 100U);** // (8) 键值浮点数终端显示 voltage3.287 并换行。* UART_Tx_SendKeyValueFloat(huart1, voltage, 3.287f, 3U, 100U);** // (9) 两列 CSV终端显示 3.287,0.120 并换行适合上位机按逗号分列。* UART_Tx_SendCsv2Float(huart1, 3.287f, 0.120f, 3U, 100U);** // (10) 二进制协议帧实际发送 AA 55 02 01 02 05 0D 0A。* UART_Tx_SendFrame(huart1, frame_payload, sizeof(frame_payload), 100U);** // (11) printf 风格文本终端显示 adc1234 并换行。* UART_Tx_Printf(huart1, 100U, adc%lu\r\n, 1234UL);* }* endcode** note SendBytes()/SendFrame() 是二进制发送SendString()/SendLine()/SendHex()* 等是人可读 ASCII 文本发送。二进制数据不要用普通文本显示结果判断对错。* UART_Tx_Printf() 若使用 %f工程必须开启 printf 浮点链接支持。** warning 全部函数使用 HAL_UART_Transmit() 阻塞发送。不要在中断服务函数、* DMA 回调、高频 ADC/PWM 回调中调用否则等待串口会影响实时性。*******************************************************************************/#ifndef UART_TX_H#define UART_TX_H#ifdef __cplusplusextern C {#endif#include usart.h/** brief UART 发送函数的返回状态。 */typedef enum{UART_TX_STATUS_OK 0,UART_TX_STATUS_INVALID_ARG,UART_TX_STATUS_HAL_ERROR,UART_TX_STATUS_FORMAT_ERROR} UART_Tx_Status_t;/*** brief 串口打印限速器对象。** 每一路需要独立限速的日志各定义一个对象。例如电压日志和接收调试日志分别* 使用两个对象二者不会相互影响。*/typedef struct{uint32_t period_ms; /** 两次允许发送之间的最小间隔单位 ms。 */uint32_t last_tick_ms; /** 上一次获准发送时的 HAL_GetTick() 值。 */uint8_t initialized; /** 0未初始化非 0已经初始化。 */} UART_Tx_RateLimiter_t;/*** brief 初始化一个串口发送限速器。* param limiter 用户定义的限速器变量地址例如 voltage_log。* param period_ms 最小发送间隔单位 ms500U 表示最多每 500 ms 发送一次。** note 初始化后第一次 UART_Tx_RateLimiter_AllowSend() 会立即返回 1方便* 上电马上打印第一条信息。period_ms 为 0U 表示不限制频率。* code* static UART_Tx_RateLimiter_t voltage_log;* UART_Tx_RateLimiter_Init(voltage_log, 500U);* endcode*/void UART_Tx_RateLimiter_Init(UART_Tx_RateLimiter_t *limiter, uint32_t period_ms);/*** brief 修改已经初始化的限速器周期。* param limiter 已由 UART_Tx_RateLimiter_Init() 初始化的对象地址。* param period_ms 新的间隔单位 ms0U 表示关闭限速。* return 1U设置成功0Ulimiter 为 NULL 或尚未初始化。** code* UART_Tx_RateLimiter_SetPeriod(voltage_log, 1000U); // 改为每秒最多一次* endcode*/uint8_t UART_Tx_RateLimiter_SetPeriod(UART_Tx_RateLimiter_t *limiter, uint32_t period_ms);/*** brief 判断本次是否允许发送并在允许时记录当前发送时刻。* param limiter 已初始化的限速器对象地址。* return 1U现在可以发送0U尚未到周期或对象无效。** details 在 while(1) 内调用本函数只有返回 1U 时才发送数据避免串口输出* 太快占满 CPU。函数可正确处理 HAL_GetTick() 回绕。* code* if (UART_Tx_RateLimiter_AllowSend(voltage_log) ! 0U)* {* UART_Tx_SendKeyValueFloat(huart1, voltage, 3.287f, 3U, 100U);* }* endcode*/uint8_t UART_Tx_RateLimiter_AllowSend(UART_Tx_RateLimiter_t *limiter);/*** brief 原样发送一段二进制字节不转换成文字。* param huart CubeMX 生成的串口句柄地址例如 huart1。* param data 待发送数组首地址例如 data不能为 NULL。* param length 要发送的字节数例如 sizeof(data)。* param timeout_ms 最长阻塞等待时间单位 ms例如 100U。* return UART_TX_STATUS_OK 表示发送成功其余值表示参数、超时或 HAL 错误。** note 本函数不添加 \0、空格或换行。发送 {0xAA,0x55} 后真正在线上的字节* 就是 AA 55普通文本串口助手未必能直观看到应使用“十六进制显示”。* code* uint8_t command[] {0xAAU, 0x55U, 0x01U};* UART_Tx_SendBytes(huart1, command, sizeof(command), 100U);* endcode*/UART_Tx_Status_t UART_Tx_SendBytes(UART_HandleTypeDef *huart, const uint8_t *data,uint16_t length, uint32_t timeout_ms);/*** brief 发送以 \0 结尾的 ASCII 文本不自动换行。* param huart 串口句柄地址例如 huart1。* param text C 字符串地址例如 hello必须以 \0 结束。* param timeout_ms 最长阻塞等待时间单位 ms。* return UART_TX_STATUS_OK 表示成功。** 例如 UART_Tx_SendString(huart1, hello, 100U) 后串口终端显示 hello* 光标仍在同一行。要换行请使用 UART_Tx_SendLine()。*/UART_Tx_Status_t UART_Tx_SendString(UART_HandleTypeDef *huart, const char *text,uint32_t timeout_ms);/*** brief 发送一行 ASCII 文本文本后自动补上 \r\n。* param huart 串口句柄地址例如 huart1。* param text C 字符串地址例如 UART ready必须以 \0 结束。* param timeout_ms 最长阻塞等待时间单位 ms。* return UART_TX_STATUS_OK 表示成功。** 例如 UART_Tx_SendLine(huart1, UART ready, 100U) 发送的字节为* U...y、0x0D、0x0A终端显示 UART ready 后跳到下一行。* 传入空字符串 时只发送换行。*/UART_Tx_Status_t UART_Tx_SendLine(UART_HandleTypeDef *huart, const char *text,uint32_t timeout_ms);/*** brief 将无符号整数转换为 ASCII 十进制文字后发送不自动换行。* param huart 串口句柄地址例如 huart1。* param value 待发送数值例如 13U。* param timeout_ms 最长阻塞等待时间单位 ms。* return UART_TX_STATUS_OK 表示成功。** 例UART_Tx_SendU32(huart1, 13U, 100U) 在线上发送 ASCII 字节 0x31、0x33* 终端看到 13它不是发送一个数值字节 0x0D。需要二进制数值请自行组帧后使用* UART_Tx_SendBytes()。*/UART_Tx_Status_t UART_Tx_SendU32(UART_HandleTypeDef *huart, uint32_t value,uint32_t timeout_ms);/*** brief 将有符号整数转换为 ASCII 十进制文字后发送不自动换行。* param huart 串口句柄地址例如 huart1。* param value 待发送有符号数例如 -123。* param timeout_ms 最长阻塞等待时间单位 ms。* return UART_TX_STATUS_OK 表示成功。** 例UART_Tx_SendI32(huart1, -123, 100U) 后终端显示 -123。*/UART_Tx_Status_t UART_Tx_SendI32(UART_HandleTypeDef *huart, int32_t value,uint32_t timeout_ms);/*** brief 将浮点数转换为 ASCII 十进制文字后发送不自动换行。* param huart 串口句柄地址例如 huart1。* param value 待发送浮点数例如 3.287f。* param precision 小数位数只能是 0U~6U3U 表示保留三位小数。* param timeout_ms 最长阻塞等待时间单位 ms。* return UART_TX_STATUS_OK 表示成功precision 超范围时返回格式错误。** 例UART_Tx_SendFloat(huart1, 3.287f, 3U, 100U) 后终端显示 3.287。* 本函数不依赖 printf 的浮点支持发送电压、ADC 换算值时优先使用它。*/UART_Tx_Status_t UART_Tx_SendFloat(UART_HandleTypeDef *huart, float value,uint8_t precision, uint32_t timeout_ms);/*** brief 将字节数组转换为“AA 55 01 FF”形式的 ASCII 十六进制文本后发送。* param huart 串口句柄地址例如 huart1。* param data 待显示的原始字节数组首地址。* param length 数组中待显示的字节数例如 sizeof(data)。* param append_crlf 1U末尾补 \r\n 并换行0U不换行。* param timeout_ms 最长阻塞等待时间单位 ms。* return UART_TX_STATUS_OK 表示成功。** 例data{0xAA,0x55,0x01,0xFF}append_crlf1U 时终端显示* AA 55 01 FF* 本函数适合调试协议帧、EEPROM 数据等它与 UART_Tx_SendBytes() 的原样二进制发送不同。*/UART_Tx_Status_t UART_Tx_SendHex(UART_HandleTypeDef *huart, const uint8_t *data,uint16_t length, uint8_t append_crlf,uint32_t timeout_ms);/*** brief 发送“名称浮点数\r\n”格式的一行可读日志。* param huart 串口句柄地址例如 huart1。* param key 名称字符串例如 voltage。* param value 数值例如 3.287f。* param precision 小数位数0U~6U。* param timeout_ms 最长阻塞等待时间单位 ms。* return UART_TX_STATUS_OK 表示成功。** 例UART_Tx_SendKeyValueFloat(huart1, voltage, 3.287f, 3U, 100U)* 后终端显示voltage3.287并自动换行。*/UART_Tx_Status_t UART_Tx_SendKeyValueFloat(UART_HandleTypeDef *huart, const char *key,float value, uint8_t precision,uint32_t timeout_ms);/*** brief 发送两个浮点数的 CSV 文本行格式为“value1,value2\r\n”。* param huart 串口句柄地址例如 huart1。* param value1 第一个数据例如电压。* param value2 第二个数据例如电流。* param precision 两个数共用的小数位数0U~6U。* param timeout_ms 最长阻塞等待时间单位 ms。* return UART_TX_STATUS_OK 表示成功。** 例UART_Tx_SendCsv2Float(huart1, 3.287f, 0.120f, 3U, 100U) 后终端显示* 3.287,0.120。可用于上位机按逗号分列绘图或保存数据。*/UART_Tx_Status_t UART_Tx_SendCsv2Float(UART_HandleTypeDef *huart, float value1,float value2, uint8_t precision,uint32_t timeout_ms);/*** brief 发送本模块定义的简单二进制协议帧。* param huart 串口句柄地址例如 huart1。* param payload 用户数据首地址length 非 0U 时不能为 NULL。* param length 用户数据长度单位字节范围 0U~255U。* param timeout_ms 最长阻塞等待时间单位 ms。* return UART_TX_STATUS_OK 表示成功。** 帧格式为AA 55 LEN DATA... SUM 0D 0A。* AA 55 是帧头LEN 是 payload 长度SUM 是 LEN 和全部 DATA 的低 8 位累加和* 0D 0A 是帧尾。例payload{0x01,0x02} 时发送* AA 55 02 01 02 05 0D 0A。** note 这是原始二进制帧普通文字终端可能看不懂串口助手请开启十六进制接收。*/UART_Tx_Status_t UART_Tx_SendFrame(UART_HandleTypeDef *huart, const uint8_t *payload,uint8_t length, uint32_t timeout_ms);/*** brief 按 printf 风格格式化为文本后发送。* param huart 串口句柄地址例如 huart1。* param timeout_ms 最长阻塞等待时间单位 ms。* param format 格式字符串例如 adc%lu\\r\\n。* param ... 与 format 中 %d、%lu、%s 等占位符对应的参数。* return UART_TX_STATUS_OK 表示成功文本太长或格式化失败时返回格式错误。** 例UART_Tx_Printf(huart1, 100U, adc%lu\\r\\n, adc_value) 后终端显示* adc1234 并换行。* warning 若 format 使用 %f工程链接选项必须启用 printf 浮点支持。比赛调试浮点* 数据时推荐使用 UART_Tx_SendFloat()它不依赖该链接选项。*/UART_Tx_Status_t UART_Tx_Printf(UART_HandleTypeDef *huart, uint32_t timeout_ms,const char *format, ...);#ifdef __cplusplus}#endif#endif /* UART_TX_H */