ARM——UART串口通信

一、串口通信的基本概念

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  $ @  $ <
相关推荐
VekiSon31 分钟前
Linux内核驱动——杂项设备驱动与内核模块编译
linux·c语言·arm开发·嵌入式硬件
AI+程序员在路上1 小时前
Nand Flash与EMMC区别及ARM开发板中的应用对比
arm开发
17(无规则自律)7 小时前
深入浅出 Linux 内核模块,写一个内核版的 Hello World
linux·arm开发·嵌入式硬件
梁洪飞20 小时前
内核的schedule和SMP多核处理器启动协议
linux·arm开发·嵌入式硬件·arm
代码游侠1 天前
学习笔记——Linux字符设备驱动
linux·运维·arm开发·嵌入式硬件·学习·架构
syseptember2 天前
Linux网络基础
linux·网络·arm开发
代码游侠2 天前
学习笔记——Linux字符设备驱动开发
linux·arm开发·驱动开发·单片机·嵌入式硬件·学习·算法
程序猿阿伟2 天前
《Apple Silicon与Windows on ARM:引擎原生构建与模拟层底层运作深度解析》
arm开发·windows
wkm9562 天前
在arm64 ubuntu系统安装Qt后编译时找不到Qt3DExtras头文件
开发语言·arm开发·qt
unicrom_深圳市由你创科技2 天前
基于ARM+DSP+FPGA异构计算架构的高速ADC采集卡定制方案
arm开发·fpga开发