UART — UART1 轮询收发(UART1_Poll)
固件库: CIU32F003_STDLib V1.0.3
芯片: CIU32F003(Cortex-M0)
源文件: CIU32/CIU32F003_STDLib_V1.0.3/Projects/UART/UART1_Poll/Source/
一、功能简介
本示例把 UART1 配置为 115200-8-N-1(波特率 115200、8 位数据、无校验、1 位停止),
采用查询(轮询)方式工作:主循环里先等收到 8 个字节存入缓冲区,
再把这 8 个字节原样发回去,最后等待发送完成。这就是最经典的串口回显(echo)。
查询方式逻辑简单,但收发期间 CPU 会被 while 占用,适合入门与低速通信。
二、硬件准备
- CIU32F003 开发板
- USB 转串口模块(如 CH340 / CP2102)
- 接线:开发板 TX(PA3) → 模块 RX,开发板 RX(PA4) → 模块 TX,并共地
- 电脑端打开串口助手(如 SSCOM、XCOM),波特率设为 115200
引脚映射:
| UART1 |
引脚 |
复用 |
| TX |
PA3 |
AF1_UART1 |
| RX |
PA4 |
AF1_UART1 |
三、完整代码
3.1 主流程 main.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
#include "main.h"
#define BUF_LEN 8
uint8_t buffer[BUF_LEN] = {0};
int main(void)
{
system_clock_config(); /* 系统时钟 RCH 48MHz */
gpio_init(); /* PA3/PA4 复用为 UART1 */
uart_init(); /* 配置波特率等并使能 UART1 */
while (1)
{
/* ① 查询接收 BUF_LEN 个字节 */
for (int i = 0; i < BUF_LEN; i++)
{
while (!std_uart_get_flag(UART1, UART_FLAG_RXNE)); /* 等收到数据 */
buffer[i] = std_uart_rx_read_data(UART1); /* 读 1 字节 */
}
/* ② 查询发送 BUF_LEN 个字节 */
for (int i = 0; i < BUF_LEN; i++)
{
while (!std_uart_get_flag(UART1, UART_FLAG_TXE)); /* 等发送寄存器空 */
std_uart_tx_write_data(UART1, buffer[i]); /* 发 1 字节 */
}
/* ③ 等待整帧发送完成(TC = Transmission Complete) */
while (!std_uart_get_flag(UART1, UART_FLAG_TC));
}
}
|
3.2 引脚与串口初始化 common.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
/* GPIO:PA3(TX)/PA4(RX) 复用为 UART1 */
void gpio_init(void)
{
std_gpio_init_t gpio_config = {0};
std_rcc_gpio_clk_enable(RCC_PERIPH_CLK_GPIOA);
gpio_config.pin = GPIO_PIN_3 | GPIO_PIN_4;
gpio_config.mode = GPIO_MODE_ALTERNATE;
gpio_config.pull = GPIO_PULLUP; /* 上拉,空闲时线为高 */
gpio_config.output_type = GPIO_OUTPUT_PUSHPULL;
gpio_config.alternate = GPIO_AF1_UART1; /* 复用功能 1 = UART1 */
std_gpio_init(GPIOA, &gpio_config);
}
/* UART1 初始化 */
void uart_init(void)
{
std_uart_init_t uart_confg = {0};
std_rcc_apb2_clk_enable(RCC_PERIPH_CLK_UART1); /* 使能 UART1 时钟(APB2) */
uart_confg.baudrate = 115200; /* 波特率 */
uart_confg.direction = UART_DIRECTION_SEND_RECEIVE; /* 收发双向 */
uart_confg.wordlength = UART_WORDLENGTH_8BITS; /* 8 位数据 */
uart_confg.stopbits = UART_STOPBITS_1; /* 1 位停止 */
uart_confg.parity = UART_PARITY_NONE; /* 无校验 */
std_uart_init(UART1, &uart_confg);
std_uart_enable(UART1); /* 使能 UART1 */
}
|
四、代码分段讲解
① 引脚复用
UART 的 TX/RX 由 GPIO 复用功能提供,本例 GPIO_AF1_UART1 把 PA3/PA4 映射给 UART1。
复用功能号(AF1)是芯片规定的,查数据手册/复用表可得。
② 串口参数
115200-8-N-1 是最通用配置:波特率 115200、8 数据位、无校验、1 停止位。
双方必须完全一致才能正确通信。奇偶校验位可选,但开启后收发都要配。
③ 查询收发
- 接收:
while 等 UART_FLAG_RXNE(接收寄存器非空)后读 std_uart_rx_read_data;
- 发送:等
UART_FLAG_TXE(发送数据寄存器空)后写 std_uart_tx_write_data;
UART_FLAG_TC(发送完成):一帧所有位都移出后才置位,用于确认“已全部发出”。
④ 轮询的代价
全程 while 等待标志,CPU 不能做别的事。数据量大或要求不阻塞时,应改用中断或 DMA(见 UART1_Interrupt)。
五、实验现象
- 串口助手发送任意 8 个字节,开发板会原样回显这 8 个字节;
- 例如发送
01 02 03 04 05 06 07 08,收到同样的 8 字节。
六、常见问题
| 现象 |
可能原因 |
解决办法 |
| 串口助手乱码 |
波特率不一致 |
双方都设为 115200 |
| 完全收不到 |
TX/RX 接反 |
开发板 TX 接模块 RX,RX 接模块 TX |
| 偶发丢字节 |
没共地 |
开发板与模块必须共 GND |
| 收不齐 8 字节 |
发送间隔/缓冲 |
一次发满 8 字节,或改中断方式 |
七、小结
UART 轮询收发流程:开时钟 → 配引脚为对应 AF → 配波特率/帧格式并使能 → 等 RXNE 读、等 TXE 写、等 TC 收尾。
记住“TX 接 RX、交叉连接、必须共地、波特率一致”四句话,串口就通了。
八、拓展应用
- 用
printf 重定向到 UART,方便打印调试信息(实现 _write/fputc);
- 改用中断接收,避免 CPU 空等(见
UART1_Interrupt);
- 单线半双工:省一根线,用于简单总线(见
UART_HalfDuplex)。