一、HAL 库三种数据发送模式详解
HAL 库提供了阻塞、中断和 DMA 三种机制来实现数据的串口发送。假设您的 USART1 句柄为 huart1。
1. 阻塞式发送 (Polling Mode)
这是最简单、最直接的方式。程序会进入一个等待循环,直到所有数据发送完毕或达到设定的超时时间才会返回。
- 函数原型:C
HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout);- 优点: 使用简单,代码逻辑清晰,适合发送少量数据。
- 缺点: 在发送过程中,CPU 一直处于等待状态(阻塞),不能处理其他任务。
- 代码示例:C
char *message = "Using Blocking Mode\r\n"; // HAL_MAX_DELAY 表示无限等待,直到发送完成 HAL_UART_Transmit(&huart1, (uint8_t *)message, strlen(message), HAL_MAX_DELAY);
2. 中断式发送 (Interrupt Mode)
发送任务会被交给 UART 外设和中断系统处理,函数调用会立即返回。发送过程由 TxE(发送寄存器空)中断驱动。
- 函数原型:C
HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);- 优点: 函数调用后立即返回,CPU 可以继续执行主循环任务(非阻塞)。
- 缺点: 频繁进出中断会增加 CPU 切换开销。
- 关键回调函数:发送完成后,HAL 库会调用回调函数:C
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) { if(huart->Instance == USART1) { // 数据已全部发送完毕,可以在这里进行后续处理 } }
3. DMA 传输发送 (DMA Mode)
DMA(直接内存访问)允许外设直接与内存之间传输数据,完全不需要 CPU 干预。这是最高效的传输方式,函数调用是非阻塞的。
- 配置要求: 必须在 CubeMX 或代码中为 USART1 配置 DMA 传输通道(TX 通道)。
- 函数原型:C
- HAL_StatusTypeDef HAL_UART_Transmit_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
- 优点: 传输效率极高,CPU 占用极低,最适合大数据量和高波特率传输。
- 缺点: 配置相对复杂,需要配置 DMA 控制器。
- 关键回调函数:DMA 传输完成后,也会调用与中断方式相同的回调函数:C
- void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) { if(huart->Instance == USART1) { // DMA 传输已完成,可以准备下一次 DMA 传输 } }
二、printf 重定向:调试的利器
为了方便地像在 PC 上一样使用 printf 格式化输出,我们需要重定向标准 C 库的 fputc 函数,让其底层调用我们的串口发送函数。
步骤 1: 实现 fputc 函数
在您的项目文件中(如 usart.c),添加以下 fputc 函数的实现。推荐使用阻塞式发送来实现 fputc,因为它简单可靠。
C
#include <stdio.h>
// 声明外部的 UART 句柄(请根据您的项目名称修改)
extern UART_HandleTypeDef huart1;
/**
* @brief 将 fputc 重定向到 USART1
* * printf 最终会调用 fputc 来发送每一个字符。
*/
int fputc(int ch, FILE *f)
{
uint8_t temp[1] = {(uint8_t)ch};
// 使用阻塞式发送单个字节,确保字符被发送
HAL_UART_Transmit(&huart1, temp, 1, 0xFFFF);
// [可选] 兼容 Windows 终端:将换行符 '\n' 自动转换为回车换行 "\r\n"
if (ch == '\n') {
uint8_t carriage_return = '\r';
HAL_UART_Transmit(&huart1, &carriage_return, 1, 0xFFFF);
}
return ch;
}
步骤 2: 在程序中调用 printf
完成重定向后,只需确保您的文件包含了 <stdio.h>,即可在任何地方使用 printf 函数:
C
#include "stdio.h"
#include "main.h" // 确保包含了 HAL_GetTick() 等必要的头文件
// ...
uint32_t ms_tick = HAL_GetTick();
// 现在,这条格式化输出会通过串口发送出去!
printf("System running! Current Tick: %lu ms.\r\n", ms_tick);
总结
掌握这三种 HAL 库发送模式,您就可以灵活应对不同的应用需求:
printf重定向 + 阻塞式发送:最佳调试方案,简单可靠。- 中断式/DMA 方式:用于正式通信协议,追求高效率和低 CPU 占用。

Comments NOTHING