嵌入式系统通信基础及i.MX6ULL串口开发笔记
一、通信基本概念
1.1 通信定义
嵌入式系统中的通信是指两个或两个以上的主机之间的数据交互过程。
1.2 通信分类
异步通信 vs 同步通信
| 类型 | 特点 | 示例 |
|---|---|---|
| 异步通信 | 无需时钟信号同步,依靠起始位、停止位、校验位等标志位 | UART、RS-232 |
| 同步通信 | 需要时钟信号同步,发送和接收方使用同一时钟 | SPI、I2C、USB |
串行通信 vs 并行通信
| 类型 | 特点 | 优缺点 | 示例 |
|---|---|---|---|
| 串行通信 | 逐位顺序传输 | 优点:节省引脚、抗干扰 缺点:速度相对慢 | UART、I2C、SPI |
| 并行通信 | 多位同时传输 | 优点:速度快 缺点:引脚多、干扰大 | 8086总线、打印机接口 |
单工/半双工/全双工
| 类型 | 特点 | 示意图 | 示例 |
|---|---|---|---|
| 单工 | 单向传输 | A → B | 广播、电视 |
| 半双工 | 双向但不同时 | A ↔ B(分时) | 对讲机、RS-485 |
| 全双工 | 双向同时传输 | A ⇄ B | 电话、UART |
1.3 电气标准
TTL电平
-
逻辑0:0V
-
逻辑1:3.3V/5V
-
传输距离短(<1m)
RS-232
-
逻辑0:+3V ~ +15V
-
逻辑1:-3V ~ -15V
-
传输距离:15米
-
点对点通信
RS-485
-
差分信号传输
-
逻辑0:A-B < -0.2V
-
逻辑1:A-B > +0.2V
-
传输距离:1200米
-
支持多点通信
差分传输
-
使用两根信号线传输相位相反的信号
-
优点:抗干扰能力强,传输距离远
-
缺点:需要两根线传输一位数据
二、原理图分析
2.1 参考文档

2.2 USB转串口模块
┌─────────────────────┐
│ USB接口 │
│ (USB Type-B) │
└─────────┬───────────┘
│
▼
┌─────────────────────┐
│ CH340G │
│ (USB转TTL芯片) │
└─────────┬───────────┘
│
▼
┌─────────────────────┐
│ UART1_TX/RX │
│ (TTL电平) │
└─────────┬───────────┘
│
▼
┌─────────────────────┐
│ i.MX6ULL SOC │
└─────────────────────┘
2.3 关键组件说明
(1)USB接口(USB_TTL)
-
用于PC与开发板通信
-
注意:不建议使用USB作为电源供电,会导致板子发热
(2)CH340芯片(U8)
-
功能:USB转串口(TTL电平)
-
将USB信号转换为UART信号
(3)DCDC电源稳压模块(U12 U13)
-
功能:电源稳压
-
特点:防抖、抗干扰设计
三、代码编写
3.1 参考文档
IMX6ULL参考手册.pdf
3.2 初始化步骤
(1)时钟初始化
// 基准时钟80MHz,预分频1分频
void uart_clk_init(void)
{
// UART1时钟配置
CCM->CSCDR1 &= ~(0x3F << 0); // 清空中断
CCM->CSCDR1 |= (1 << 0); // 1分频
}
(2)引脚初始化
void uart_pin_init(void)
{
// UART1_TX引脚配置
IOMUXC_SetPinMux(IOMUXC_UART1_TX_DATA_UART1_TX, 0);
IOMUXC_SetPinConfig(IOMUXC_UART1_TX_DATA_UART1_TX, 0x10B0);
// UART1_RX引脚配置
IOMUXC_SetPinMux(IOMUXC_UART1_RX_DATA_UART1_RX, 0);
IOMUXC_SetPinConfig(IOMUXC_UART1_RX_DATA_UART1_RX, 0x10B0);
}
3.3 寄存器配置
(1)接收寄存器(UARTx_URXD)
-
地址:只读寄存器
-
功能:保存接收到的字符
-
位说明:
-
RX_DATA[7:0]:已接收数据
-
7位模式:MSB强制为0
-
8位模式:所有位都有效
-
(2)发送寄存器(UARTx_UTXD)
-
地址:可写寄存器
-
功能:写入需要发送的数据
-
特性:写入后自动开始发送
(3)控制寄存器1(UARTx_UCR1)
// 重要位说明
UARTx_UCR1:
[UARTEN] b0:UART模块总使能位(1=使能,0=关闭)
(4)控制寄存器2(UARTx_UCR2)
// 位说明
[UARTEN] b0:软件复位(写1复位,持续4个时钟周期)
[RXEN] b1:接收器使能
[TXEN] b2:发送器使能
[WS] b5:字长选择(0=8位,1=7位)
[STPB] b6:停止位数量(0=1位,1=2位)
[PREN] b8:奇偶校验使能
[IRTS] b14:忽略RTS流控(设置为1)
(5)控制寄存器3(UARTx_UCR3)
[RXDMUXSEL] b2:必须设置为1(MUXED模式)
(6)FIFO控制寄存器(UARTx_UFCR)
[RFDIV] b7-b9:参考时钟分频器
// 000 = 6分频,001 = 5分频,010 = 4分频
// 011 = 3分频,100 = 2分频,101 = 1分频
(7)状态寄存器2(UARTx_USR2)
[TXDC] b3:发送完成标志位(1=完成)
[RDR] b0:接收数据就绪标志位(1=有数据)
(8)波特率配置
// 波特率计算公式
BaudRate = Ref_Freq / (16 × ((UBMR + 1) / (UBIR + 1)))
// 寄存器配置
UARTx_UBIR:增量寄存器
UARTx_UBMR:模数寄存器
3.4 UART驱动函数实现
(1)发送函数
// 发送单个字符
void putc(unsigned char d)
{
// 等待发送完成标志
while ((UART1->USR2 & (1 << 3)) == 0);
// 写入发送寄存器
UART1->UTXD = d;
}
// 发送字符串
void puts(const char *pStr)
{
while (*pStr)
{
putc(*pStr++);
}
putc('\n'); // 添加换行
}
(2)接收函数
// 接收单个字符
unsigned char getc(void)
{
// 等待接收数据就绪
while ((UART1->USR2 & (1 << 0)) == 0);
// 读取数据
return (unsigned char)UART1->URXD & 0xFF;
}
3.5 移植标准输入输出(stdio)
步骤说明
-
添加空函数(解决编译错误)
void raise(int n) { // 空函数体 } -
修改汇编文件扩展名
-
将
start.s改为start.S -
注意:大写S会进行预处理,小写s则不会
-
-
修改Makefile
# 库路径配置 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 # 包含目录 incdirs = bsp imx6ull stdio/include # 源码目录 srcdirs = bsp project stdio/lib # 链接选项 $(ld) -Timx6ull.lds -o$(target).elf $^ $(libpath) # 编译选项 $(cc) -Wall -Wa,-mimplicit-it=thumb -nostdlib -fno-builtin -c $(include) -o $@ $<