目标:串口发送 + 中断接收控制 LED 闪烁速度
USART 使用异步串行通信,无时钟线,双方约定相同波特率:
空闲状态:TX 保持高电平
传输 1 字节 (115200-8-N-1):
┌──────┬──────┬──────┬──────┬──────┬──────┬──────┬──────┬──────┬──────┬──────┐
│ 空闲 │START │ D0 │ D1 │ D2 │ D3 │ D4 │ D5 │ D6 │ D7 │ STOP │ 空闲
│ (H) │ (L) │ │ │ │ │ │ │ │ │ (H) │ (H)
└──────┴──────┴──────┴──────┴──────┴──────┴──────┴──────┴──────┴──────┴──────┘
TTL 电平连线:
STM32 (PA9 TX) ────────→ USB-TTL (RX)
STM32 (PA10 RX) ←────── USB-TTL (TX)
STM32 (GND) ──────── USB-TTL (GND) ← 共地必须!
HAL_UART_Transmit() 内部做三件事:
初学者容易混淆:TXE 表示"发送寄存器空了(可以填下一个)";TC 表示"整个字节包括停止位发完了"。
HAL_UART_Transmit内部两种标志都处理了,不需要手动轮询。
| 函数 | 说明 |
|---|---|
HAL_UART_Transmit(&huart, pData, Size, Timeout) |
阻塞发送(等待 TXE+TC) |
HAL_UART_Receive(&huart, pData, Size, Timeout) |
阻塞接收(等待 RXNE) |
HAL_UART_Receive_IT(&huart, pData, Size) |
中断接收(推荐,不阻塞) |
HAL_UART_RxCpltCallback(huart) |
接收完成回调(用户重写) |
参数说明:
huart:UART 句柄(如 huart1)pData:数据缓冲区指针(注意类型是 uint8_t *)Size:期望收发字节数Timeout:超时 ms(HAL_MAX_DELAY = 无限等待)#include <string.h>
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART1_UART_Init();
while (1)
{
char msg[] = "Hello STM32!\r\n";
HAL_UART_Transmit(&huart1, (uint8_t *)msg, strlen(msg), HAL_MAX_DELAY);
HAL_Delay(1000);
}
}
中断接收的核心模式:先调用 HAL_UART_Receive_IT 注册接收 → 硬件收到 1 字节触发中断 → HAL 自动调用回调 → 回调里处理完数据后再调用一次 HAL_UART_Receive_IT 重新注册:
/* 全局变量 */
static uint32_t blinkInterval = 1000;
static uint8_t dataRcvd;
/* 回调函数 —— 每次接收完成自动调用(由 HAL 在中断上下文调用) */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart == &huart1)
{
// 根据接收到的字符修改闪烁间隔
if (dataRcvd == '1') blinkInterval = 1000;
else if (dataRcvd == '2') blinkInterval = 300;
else if (dataRcvd == '3') blinkInterval = 50;
HAL_UART_Receive_IT(&huart1, &dataRcvd, 1); // 重新开启接收(否则只收一次)
}
}
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART1_UART_Init();
/* 第一次启动中断接收 —— 注册回调 */
HAL_UART_Receive_IT(&huart1, &dataRcvd, 1);
while (1)
{
HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
HAL_Delay(blinkInterval);
}
}
Keil 中使用 MicroLIB 时,重写 fputc 即可让 printf 输出到串口:
#include <stdio.h>
/* 在 uart.c 或 main.c 中重写 fputc */
int fputc(int ch, FILE *f)
{
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, HAL_MAX_DELAY);
return ch;
}
使用前提:
<stdio.h>printf("ADC=%d, V=%.2f\r\n", val, voltage);HAL_UART_Transmit 的 pData 类型是 uint8_t *,传 char * 字符串时必须强转HAL_UART_Receive_IT,否则只收一次就停了HAL_UART_Receive(阻塞版)会一直等到收到指定字节数或超时,不要在中断中调用