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 */

相关新闻

STM32定时器HAL库实战:从原理到PWM、编码器、ADC触发应用

STM32定时器HAL库实战:从原理到PWM、编码器、ADC触发应用

1. 项目概述:为什么定时器是STM32的“心脏”?如果你玩过一阵子STM32,肯定会发现一个现象:无论是点个灯、读个传感器,还是搞个复杂的电机控制,几乎都绕不开一个东西——定时器。它不像GPIO那样直观&#xff…

2026/10/23 2:34:22 阅读更多 →
Python图像批处理实战:Pillow库构建自动化工具全流程

Python图像批处理实战:Pillow库构建自动化工具全流程

在实际图像处理项目中,我们经常需要处理批量图像,进行格式转换、尺寸调整、滤镜应用等操作。这类任务如果手动处理,不仅效率低下,还容易出错。本文将基于常见的图像处理需求,构建一个完整的图像批处理项目,…

2026/10/22 12:33:11 阅读更多 →
Sim2Real技术解析:从仿真训练到现实部署的完整指南

Sim2Real技术解析:从仿真训练到现实部署的完整指南

如果你正在研究机器人控制、自动驾驶或者任何需要让AI在真实世界中可靠工作的领域,那么"仿真到现实"这个技术瓶颈一定让你头疼不已。在仿真环境中训练出的模型表现完美,一到真实世界就"翻车"——这几乎是每个AI工程师都会遇到的经典…

2026/10/21 13:12:16 阅读更多 →

最新新闻

Electron桌面应用开发实战:从环境搭建到打包发布全流程

Electron桌面应用开发实战:从环境搭建到打包发布全流程

做前端这些年,我大部分时间都在跟浏览器标签页打交道,直到第一次把桌面应用跑起来,才发现原来自己一直被限制在地址栏和刷新按钮围起来的框框里。Electron这个词,最开始是在某段时间频繁出现在同事的讨论里,一个用HTML…

2026/10/22 10:18:38 阅读更多 →
滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

简介:亚太天能T109滑盖智能锁产品说明书是一份PDF格式的官方技术文档,主要面向智能锁安装人员、终端用户及售后维护者,帮助快速掌握产品安装、配置与常见故障处理。全包仅1个PDF文件,大小4.37MB,内容结构清晰&#xff…

2026/10/22 11:01:53 阅读更多 →
PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

上个月我在调试一台高速AGV的驱动系统,整车要求空载跑到8m/s,电机转速已经拉到额定点,驱动器的输出电压也顶到了母线电压极限附近。再往上踩速度指令,转速纹丝不动,三相电流反而开始震荡。那会儿我的第一反应就是&…

2026/10/22 9:44:47 阅读更多 →
C++核心知识点:从内存管理到STL的实战指南

C++核心知识点:从内存管理到STL的实战指南

C 这门语言我前前后后折腾了十几年,用它写过嵌入式驱动、做过游戏服务端,也搭过基础组件库。每次看到新人一头扎进"C 核心知识点"这个搜索词,我其实挺感慨的——这门语言的难点从来不是语法多,而是知识点之间的耦合太深…

2026/10/22 10:42:00 阅读更多 →
T109滑盖智能锁怎么装?安装调试与故障排查全攻略

T109滑盖智能锁怎么装?安装调试与故障排查全攻略

简介:亚太天能T109滑盖智能锁产品说明书以PDF格式发布,适合智能锁用户、安装人员与售后维修人员阅读。内容围绕T109系列指纹密码刷卡锁展开,先介绍前面板、后面板、锁体、机械钥匙、电池盒盖等部件名称与功能,再给出完整安装步骤&…

2026/10/22 10:40:08 阅读更多 →
LLM知识降熵:从信息垄断到理解权下放

LLM知识降熵:从信息垄断到理解权下放

你有没有过这种经历:翻开源码注释、论文摘要或者一份专业报告,每个字都认识,连在一起却像天书。想找人聊聊,身边要么没人懂,要么懂的懒得跟你解释。后来我试着把同一段内容丢给一个大语言模型,几秒钟之后&a…

2026/10/22 10:56:37 阅读更多 →

日新闻

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/22 1:47:45 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/22 21:33:42 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/22 5:12:39 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/22 22:56:44 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/22 22:56:12 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/22 19:06:46 阅读更多 →