文章目录
- 前言
- [1. UART协议基础](#1. UART协议基础)
- [2. STM32F103RCT6的UART配置](#2. STM32F103RCT6的UART配置)
- [3. HAL库代码实现](#3. HAL库代码实现)
-
- [3.1 UART初始化](#3.1 UART初始化)
- [3.2 发送数据(阻塞模式)](#3.2 发送数据(阻塞模式))
- [3.3 接收数据(中断模式)](#3.3 接收数据(中断模式))
- [3.4 DMA传输(高效大数据量)](#3.4 DMA传输(高效大数据量))
- [4. 自定义协议设计](#4. 自定义协议设计)
-
- [4.1 帧格式示例](#4.1 帧格式示例)
- [4.2 帧解析代码](#4.2 帧解析代码)
- [5. 常见问题与调试](#5. 常见问题与调试)
- [6. 完整示例:与PC通信](#6. 完整示例:与PC通信)
- 7.总结
前言
UART(Universal Asynchronous Receiver/Transmitter)是一种异步串行通信协议 ,广泛应用于嵌入式设备与传感器、蓝牙模块、GPS等外设的通信。以下是UART协议的详细解析及在STM32F103RCT6上的完整代码实现。
1. UART协议基础
1.1 物理层特性
两根信号线
TX(Transmit):数据发送线(输出)。
RX(Receive):数据接收线(输入)。
无时钟信号
无时钟信号:依赖预定义的波特率(Baud Rate)同步。
电平标准
TTL UART
TTL UART:0V(逻辑0),3.3V/5V(逻辑1)。
RS-232
RS-232:±12V(需电平转换芯片如MAX232)。
1.2 数据帧格式
起始位\] \[数据位(5-9位)\] \[校验位(可选)\] \[停止位(1-2位)
起始位:1位低电平(逻辑0)。
数据位:通常8位(如ASCII字符)。
校验位(可选):
奇校验:数据位中1的个数为奇数时置1。
偶校验:数据位中1的个数为偶数时置1。
停止位:1或2位高电平(逻辑1)。
1.3 波特率计算
波特率
波特率(Baud Rate)表示每秒传输的符号数(1符号=1位)。
常见波特率:9600、115200等。
STM32的UART时钟源为APB2(默认72MHz),波特率计算公式:
波特率=APB2时钟USARTDIV
其中USARTDIV是一个16位寄存器值(整数部分 + 小数部分)。
2. STM32F103RCT6的UART配置
2.1 硬件连接
UART信号 STM32引脚 说明
USART1_TX PA9 发送数据
USART1_RX PA10 接收数据GND 共地 确保电平参考一致
2.2 CubeMX配置
启用USART1
模式:Asynchronous(异步模式)。
波特率:115200。
数据位:8位。
校验位:None。
停止位:1位。
引脚分配
PA9 → USART1_TX
PA10 → USART1_RX
中断启用(可选)
接收中断(RXNE)。
3. HAL库代码实现
3.1 UART初始化
c
#include "stm32f1xx_hal.h"
UART_HandleTypeDef huart1;
void MX_USART1_UART_Init(void) {
huart1.Instance = USART1;
huart1.Init.BaudRate = 115200;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(&huart1) != HAL_OK) {
Error_Handler();
}
}
3.2 发送数据(阻塞模式)
c
void UART_SendString(uint8_t *str) {
HAL_UART_Transmit(&huart1, str, strlen((char *)str), 100); // 阻塞式发送
}
// 示例:发送"Hello World!"
UART_SendString((uint8_t *)"Hello World!\r\n");
3.3 接收数据(中断模式)
c
uint8_t rx_data;
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
if (huart == &huart1) {
// 处理接收到的数据(如回显)
HAL_UART_Transmit(&huart1, &rx_data, 1, 100);
HAL_UART_Receive_IT(&huart1, &rx_data, 1); // 重新启用接收中断
}
}
// 主函数中启用接收中断
int main(void) {
HAL_Init();
MX_USART1_UART_Init();
HAL_UART_Receive_IT(&huart1, &rx_data, 1); // 启动接收中断
while (1) { /* 其他任务 */ }
}
3.4 DMA传输(高效大数据量)
c
uint8_t dma_tx_buffer[] = "DMA Transmission Test!\r\n";
// 初始化DMA
void MX_DMA_Init(void) {
__HAL_RCC_DMA1_CLK_ENABLE();
}
// 通过DMA发送数据
HAL_UART_Transmit_DMA(&huart1, dma_tx_buffer, sizeof(dma_tx_buffer));
4. 自定义协议设计
4.1 帧格式示例
字段 长度 说明
帧头 2字节 0xAA 0x55
数据长度 1字节 后续数据长度(N)
数据 N字节 有效载荷
CRC校验 1字节 校验和(数据字节累加和)
4.2 帧解析代码
c
uint8_t rx_buffer[64];
uint8_t frame_state = 0;
uint8_t data_len = 0;
uint8_t crc = 0;
void Process_UART_Byte(uint8_t byte) {
static uint8_t idx = 0;
switch (frame_state) {
case 0: // 等待帧头1
if (byte == 0xAA) frame_state = 1;
break;
case 1: // 等待帧头2
if (byte == 0x55) frame_state = 2;
else frame_state = 0;
break;
case 2: // 读取数据长度
data_len = byte;
idx = 0;
crc = byte;
frame_state = 3;
break;
case 3: // 读取数据
rx_buffer[idx++] = byte;
crc += byte;
if (idx >= data_len) frame_state = 4;
break;
case 4: // 校验CRC
if (crc == byte) {
// 帧处理(如控制LED)
if (rx_buffer[0] == 0x01) HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
}
frame_state = 0;
break;
}
}
// 在中断回调中调用
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
Process_UART_Byte(rx_data);
HAL_UART_Receive_IT(&huart1, &rx_data, 1);
}
5. 常见问题与调试
5.1 通信失败原因
波特率不匹配
波特率不匹配:确保双方波特率一致(如115200)。
电平不兼容
电平不兼容:TTL UART不能直接接RS-232设备。
接线错误
接线错误:检查TX/RX是否交叉连接。
中断为启用
中断未启用:若使用中断接收 ,需调用HAL_UART_Receive_IT()。
5.2 逻辑分析仪抓包
使用工具(如Saleae Logic)观察:
- 起始位是否为低电平?
- 数据位是否符合预期?
- 停止位是否为高电平?
6. 完整示例:与PC通信
STM32代码
c
int main(void) {
HAL_Init();
MX_USART1_UART_Init();
HAL_UART_Receive_IT(&huart1, &rx_data, 1); // 启用接收中断
while (1) {
// 每隔1秒发送数据
UART_SendString((uint8_t *)"STM32 UART Test\r\n");
HAL_Delay(1000);
}
}
PC端(Python脚本)
python
import serial
ser = serial.Serial('COM3', 115200, timeout=1) # 根据实际端口修改
while True:
if ser.in_waiting:
data = ser.readline().decode('utf-8').strip()
print("Received:", data)
7.总结
基本配置
基本配置:波特率、数据位、停止位需匹配。
通信模式
通信模式:阻塞、中断、DMA按需选择。
协议设计
协议设计:自定义帧格式提升可靠性。
调试工具
调试工具:逻辑分析仪、串口助手 是关键。
通过上述代码,STM32F103RCT6可实现稳定的UART通信,适用于传感器数据采集、无线模块控制等场景。