一、通信方式基础
1. 串行 vs 并行通信
- 串行通信:数据一位一位传输(如 UART),仅需 1 根数据线,适用于远距离低速率场景。
例:电脑与开发板通过 UART 传输数据,每次发送 1bit。 - 并行通信:多位数据同时传输(如 8 位数据线),速率快但布线复杂,适用于短距离(如 CPU 与内存)。
2. 同步 vs 异步通信
- 同步通信:双方使用同一时钟源(频率一致),无需额外同步信号(如 IIC、SPI)。
例:开发板与传感器时钟均为 100Hz,每秒传输 100bit 数据,无丢失。 - 异步通信:双方时钟独立,通过波特率同步(如 UART)。
例:UART 通信中,电脑与开发板需约定相同波特率(如 115200),否则数据乱码。
3. 单工 / 半双工 / 全双工
- 单工:仅单向传输(如麦克风→扬声器)。
- 半双工:双向但同一时刻只能单方向(如对讲机)。
- 全双工:双向同时传输(如打电话、UART)。
二、UART 总线核心特性
UART 是串行、异步、全双工总线,物理层存在,用于设备间通信(如 PC 与开发板)。
- 硬件连接:3 根线
- TXD:发送线(开发板 TXD 接 PC RXD,交叉连接)
- RXD:接收线(开发板 RXD 接 PC TXD)
- GND:共地线(确保电平参考一致)
- 应用场景:程序烧录、调试信息打印(类似
printf
输出到串口工具)。
三、硬件连接与电平转换
1. 本质连接
PC 与开发板的 TXD/RXD 交叉连接,GND 共地(如下图):
plaintext
PC 开发板
TXD ←→ RXD
RXD ←→ TXD
GND ←→ GND
2. 电平转换
- 开发板用TTL 电平:0~0.8V(逻辑 0),2~5V(逻辑 1)。
- 电脑 USB 用USB 电平:-2~-6V(0),2~6V(1)。
- CH340 芯片:实现 USB 与 TTL 电平转换,是 PC 与开发板通信的 “翻译官”。
3. 工业级衍生协议(基于 UART)
协议 | 电平范围 | 通信距离 | 特性 | 转换芯片 |
---|---|---|---|---|
UART | TTL(0~5V) | ~1m | 全双工 | 无需 |
RS232 | -15~15V(负逻辑) | ~10m | 全双工,抗干扰强 | MAX232 |
RS485 | 1.5~6V(差分信号 A/B 线) | ~1000m | 半双工,适合长距离 | MAX485 |
四、UART 协议格式与波特率
1. 协议格式(一帧数据)
plaintext
起始位(1bit,0) + 数据位(5~9bit) + 校验位(可选) + 停止位(1/1.5/2bit,1)
- 起始位:低电平(下降沿),标志通信开始。
- 数据位:实际传输数据(常用 8 位)。
- 校验位:奇偶校验(可选,实际开发中多禁用)。
- 停止位:高电平(上升沿),标志通信结束。
常用格式:8N1(8 数据位,无校验,1 停止位)。
2. 波特率
- 定义:单位时间传输的位数(bps),如 9600bps 表示每秒传 9600bit。
- 作用:异步通信中,双方必须约定相同波特率(如 115200),否则数据错位。
- 计算示例:
时钟频率 160MHz,16 倍采样模式下,波特率 115200 对应的寄存器值:
USARTDIV = 160,000,000 / 115200 ≈ 1388 → 0x056C
(写入 USART_BRR 寄存器)。
五、STM32 中 UART 配置(以 USART1 为例)
1. 引脚映射
- USART1_TX → PA9(发送)
- USART1_RX → PA10(接收)
2. 硬件初始化步骤
(1)GPIO 配置(复用为 UART 功能)
- 模式:PA9/PA10 设为复用功能模式(GPIOA_MODER 寄存器 [19:18] 和 [21:20] 写 0b10)。
- 复用功能:PA9/PA10 映射到 USART1(GPIOA_AFRH 寄存器 [7:4] 和 [11:8] 写 0b0111,即 AF7)。
(2)USART 配置(8N1,115200 波特率)
- 禁用 USART(UE=0),配置数据位:8 位(CR1 寄存器 M1:M0=0b00)。
- 禁用校验(CR1 寄存器 PCE=0)。
- 停止位:1 位(CR2 寄存器 STOP [1:0]=0b00)。
- 采样模式:16 倍(CR1 寄存器 OVER8=0)。
- 波特率:115200(BRR 寄存器写 0x056C)。
- 使能发送(TE=1)、接收(RE=1)和 USART 全局(UE=1)。
六、代码实现示例
1. 标准库:字符收发
c
运行
// 发送字符(判断TXE标志位,确保发送寄存器为空)
void put_char(unsigned char data) {
while (!(USART1->ISR & (1 << 7))); // 等待TXE=1(发送寄存器空)
USART1->TDR = data; // 写入数据
}
// 接收字符(判断RXNE标志位,确保接收完成)
unsigned char get_char() {
while (!(USART1->ISR & (1 << 5))); // 等待RXNE=1(接收寄存器满)
return USART1->RDR; // 读取数据
}
// 主循环:接收字符+1后回传
int main() {
unsigned char c;
while (1) {
c = get_char();
put_char(c + 1); // 如接收'a',返回'b'
}
}
2. HAL 库:字符串定长收发
c
运行
uint8_t buf[10] = {0}; // 接收缓冲区
int main() {
MX_USART1_UART_Init(); // 初始化USART1(115200,8N1)
while (1) {
// 接收10字节数据(超时100s)
HAL_UART_Receive(&huart1, buf, sizeof(buf), 100000);
// 回传接收的数据
HAL_UART_Transmit(&huart1, buf, sizeof(buf), 5);
memset(buf, 0, sizeof(buf)); // 清空缓冲区
HAL_Delay(1000);
}
}
3. printf 重定向(串口打印调试信息)
重写fputc
函数,将printf
输出定向到串口:
c
运行
#include "stdio.h"
int fputc(int ch, FILE *stream) {
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 5); // 发送单个字符
return ch;
}
// 使用示例:每秒打印计数
int main() {
int i = 0;
while (1) {
printf("count: %d\n", i++); // 输出到串口工具
HAL_Delay(1000);
}
}
七、任务解析
- 标准库寄存器操作:取消 CubeMX 自动配置,手动编写 GPIO 复用、USART 初始化代码(参考 “硬件初始化步骤”)。
- 串口控制外设:
- 接收缓冲区
buf[6]
存储指令(如 "FAN_ON" 或 "FAN_OF")。 - 匹配指令后控制 GPIO 输出高低电平,驱动风扇转动 / 停止:
c
运行
if (strcmp((char*)buf, "FAN_ON") == 0) { GPIOA->ODR |= (1 << 5); // 假设PA5接风扇,置高电平启动 } else if (strcmp((char*)buf, "FAN_OF") == 0) { GPIOA->ODR &= ~(1 << 5); // 置低电平停止 }
- 接收缓冲区
通过以上整理,可清晰理解 UART 的理论基础、硬件配置及代码实现,结合示例能快速上手调试。