一、串口通信的基本概念
1. 通信:在嵌入式系统中,通信是指两个或两个以上的主机之间的数据互交,这里的主机可以是计算机也可以是嵌入式主机,甚至可以是芯片。
2.通信的分类:
串行**:**将数据的每一个二进制位(bit)依次、逐位通过一条传输线路进行发送和接收。
并行:将数据的多个二进制位(bit)同时通过多条独立的传输线路进行发送和接收。
核心对比表
| 对比维度 | 串行 | 并行 |
|---|---|---|
| 传输方式 | 逐位、顺序传输 | 多位,同时传输 |
| 线路数量 | 少(TX/RX/GND) | 多(n条数据需要n条数据线) |
| 传输速度 | 相对较慢 | 相对较快 |
| 抗干扰能力 | 强 | 弱 |
3.传输方式
| 通信模式 | 定义 | 数据传方向 |
|---|---|---|
| 单工 | 数据只能在一个固定方向上传输,一个只能发,一个只能收 | 单项不可逆 |
| 半双工 | 数据可以双向传输,但同一时刻只能有一个方向传输,收发不能同时进行 | 双向可逆,但不同时 |
| 全双工 | 数据可以同时在两个方向上传输,收发互不影响 | 双向可逆且同时 |
4.数据传输模式
| 对比维度 | 异步 | 同步 |
|---|---|---|
| 时钟 | 无共享时钟,靠波特率同步 | 有共享时钟 |
| 数据格式 | 起始位+数据+停止位 | 连续数据流,无起始位 |
| 传输效率 | 较低 | 较高 |
| 硬件连线 | 简单(通常:TX/RX) | 复杂(需要时钟线) |
| 典型协议 | UART | SPI |
异步通信波特率的计算:

二、数据传输格式图

数据格式:1个起始位+8个数据位+1个校验位+1个停止位
三、UART通信的流程
3.1 UART1初始化
| 步骤 | 操作内容 | 调用函数 / 寄存器 | 参数 / 值 | 说明 |
|---|---|---|---|---|
| 1.1 | 配置 UART1_TX 引脚复用 | IOMUXC_SetPinMux() |
IOMUXC_UART1_TX_DATA_UART1_TX, 0 |
设置为 ALT5(UART1_TX 功能) |
| 1.2 | 配置 UART1_RX 引脚复用 | IOMUXC_SetPinMux() |
IOMUXC_UART1_RX_DATA_UART1_RX, 0 |
设置为 ALT5(UART1_RX 功能) |
| 1.3 | 配置 TX 引脚电气特性 | IOMUXC_SetPinConfig() |
IOMUXC_UART1_TX_DATA_UART1_TX, 0x10B0 |
100K 上拉、高速、中等驱动强度 |
| 1.4 | 配置 RX 引脚电气特性 | IOMUXC_SetPinConfig() |
IOMUXC_UART1_RX_DATA_UART1_RX, 0x10B0 |
同上,确保信号完整性 |
3.2 UART1 初始化 --- 模块控制寄存器配置
| 步骤 | 操作内容 | 寄存器 | 位操作 | 说明 |
|---|---|---|---|---|
| 2.1 | 关闭 UART1 模块 | UCR1 |
UCR1[0] = 0 |
确保在配置期间模块禁用 |
| 2.2 | 配置 UCR2 | UCR2 |
` | = (1<<14)<br>&= ~(1<<8)<br>&= ~(1<<6)<br> |
| 2.3 | 配置 UCR3 | UCR3 |
` | = (1<<2)` |
| 2.4 | 使能 UART1 | UCR1 |
` | = (1<<0)` |
3.3 UART1 初始化 --- FIFO 与波特率配置
| 步骤 | 操作内容 | 寄存器 | 值 / 操作 | 说明 |
|---|---|---|---|---|
| 3.1 | 清除接收触发级别 | UFCR |
&= ~(7 << 7) |
清除原触发阈值 |
| 3.2 | 设置接收触发级别 | UFCR |
` | = (5 << 7)` |
| 3.3 | 设置波特率整数部分 | UBIR |
= 999 |
Baud Rate Integer Register |
| 3.4 | 设置波特率模数部分 | UBMR |
= 43401 |
Baud Rate Modulator Register 配合 UBIR 实现 ≈115200 bps(参考时钟 80 MHz) |
3.4 发送数据流程
| 步骤 | 操作内容 | 函数 / 寄存器 | 条件 / 操作 | 说明 |
|---|---|---|---|---|
| 4.1 | 等待发送 FIFO 可用 | USR2 |
轮询 USR2[3] == 1(TXFE) |
TXFE=1 表示 FIFO 空,可写入 |
| 4.2 | 写入发送数据 | UTXD |
UTXD = d |
写入后硬件自动移位发送 |
| 4.3 | 发送字符串 | puts() |
循环调用 putc() |
逐字符发送,末尾追 |
3.5 接收数据流程
| 步骤 | 操作内容 | 函数 / 寄存器 | 条件 / 操作 | 说明 |
|---|---|---|---|---|
| 5.1 | 等待接收数据就绪 | USR2 |
轮询 USR2[0] == 0(RXFE=0) |
RXFE=0 表示 FIFO 非空 |
| 5.2 | 读取接收数据 | URXD |
return (unsigned char)URXD |
读操作会清除部分状态位(如帧错) |
四、标准库的兼容
4.1添加Raise()函数
原因 :即使使用 -nostdlib,某些 C 库函数(如 assert()、异常处理路径)仍可能引用 raise()。若未定义,链接时报错:undefined reference to 'raise'。
void raise(int n) {
// 空函数,仅用于满足链接器要求
}
4.2汇编文件扩展名改为大写 .S
原因:
.s:直接汇编,不经过 C 预处理器(无法使用 #include, #define, 条件编译等)。
.S:先经 C 预处理器 处理,再汇编(支持宏、头文件包含等)。
#include "imx6ull.h"
.equ STACK_TOP, 0x80200000
4.3 修改 Makefile 以支持 stdio
# 头文件搜索路径(含 stdio 头文件)
incdirs = bsp imx6ull stdio/include
# 源文件目录(含 stdio 实现)
srcdirs = bsp project stdio/lib
4.4 更新链接命令
# 指定 GCC 内部库路径(如 libgcc.a)
libpath = -lgcc -L/usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/lib/gcc/arm-linux-gnueabihf/4.9.4
$ (target).elf: $ (objs)
$ (ld) -T imx6ull.lds -o $ @ $ ^ $ (libpath)
4.5 确保编译命令支持预处理
# 编译 .c 文件
%.o: %.c
$ (cc) -Wall -Wa,-mimplicit-it=thumb -nostdlib -fno-builtin $ (include) -c -o $ @ $ <
# 编译 .S 文件(会自动预处理)
%.o: %.S
$ (cc) -Wall -Wa,-mimplicit-it=thumb -nostdlib -fno-builtin $ (include) -c -o $ @ $ <