嵌入式 ------ 串口与 UART 深入详解 ------ i.MX6ULL 实战
一句话总结:串口(UART)是一种"发一条线、收一条线、不要时钟"的异步串行通信方式------发送方和接收方各自按约定好的速率(波特率)收发数据,通过起始位、数据位、校验位、停止位组成一帧数据。
第 1 章 · 串口通信基本概念
1.1 核心概念
一句话总结:串口通信 = 数据按位(bit)逐根线发送,一条线发、一条线收、一条共地,双方约定好速度(波特率)和格式(数据位/停止位/校验位)。
生活类比 :串口通信就像两个人隔着一道墙用对讲机通话------你按一下按钮(起始位)开始说话,说完松开(停止位)。双方需要提前说好用多快的语速讲(波特率),讲中文还是英文(数据格式),否则对方听不懂。而且不存在"同步时钟线",全靠各自掌握节奏(异步)。
1.2 串口 vs 并口
| 对比维度 | 串口(UART) | 并口 |
|---|---|---|
| 传输方式 | 逐位发送(1 根数据线) | 多位同时发送(8/16 根数据线) |
| 传输距离 | 远(可达几十米) | 近(通常 < 1 米) |
| 抗干扰能力 | 强(线少) | 弱(线多,易串扰) |
| 硬件成本 | 低(2 根数据线 + GND) | 高(多根线) |
| 典型应用 | 嵌入式调试、传感器、GPS | 打印机、老式硬盘 |
第 2 章 · 串口通信协议
2.1 核心概念
一句话总结:串口通信协议定义了一帧数据的结构------先拉低电平说"我要开始发了"(起始位),然后从低位到高位逐位发出数据(数据位),可选一个校验位检查错误,最后拉高电平说"发完了"(停止位)。
生活类比:就像打电话------先拨号(起始位),然后说话内容(数据位),最后说"再见"挂断(停止位)。双方还要约定好语速(波特率)和语言(数据格式)。
2.2 数据帧格式
一帧数据的组成
| 字段 | 长度 | 电平 | 说明 |
|---|---|---|---|
| 空闲位 | 任意 | 高电平 | 没有数据传输时,线路保持高电平 |
| 起始位 | 1 位 | 低电平 | 通知接收方"准备接收数据" |
| 数据位 | 5~8 位 | 高/低 | 实际数据,低位(LSB)先发 |
| 校验位 | 0/1 位 | 高/低 | 可选奇校验、偶校验、0 校验、1 校验 |
| 停止位 | 1~2 位 | 高电平 | 通知接收方"数据发送完毕" |
常见配置
css
波特率:115200
数据位:8 位
校验位:无(NONE)
停止位:1 位
简写:115200-8-N-1
2.3 波特率
一句话总结:波特率 = 每秒传输的位数(bit/s),双方必须一致,否则数据乱码。
生活类比:两个人用对讲机通话------一个人说得飞快(高波特率),另一个人听得很慢(低波特率),听到的就是"叽里呱啦"(乱码)。
常见波特率
| 波特率 | 每秒传输位数 | 传输 1 字节所需时间 |
|---|---|---|
| 9600 | 9600 bit/s | ≈ 1.04 ms |
| 38400 | 38400 bit/s | ≈ 0.26 ms |
| 115200 | 115200 bit/s | ≈ 0.087 ms |
| 921600 | 921600 bit/s | ≈ 0.011 ms |
注意:1 字节 = 8 位数据 + 1 位起始 + 1 位停止 = 10 位(无校验时)
2.4 校验位
| 校验方式 | 规则 | 能否检测错误 |
|---|---|---|
| 无校验(NONE) | 不发送校验位 | ❌ 不能 |
| 奇校验(ODD) | 数据位 + 校验位中 1 的总数为奇数 | ✅ 单比特错误 |
| 偶校验(EVEN) | 数据位 + 校验位中 1 的总数为偶数 | ✅ 单比特错误 |
| 0 校验(SPACE) | 校验位固定为 0 | ❌ 不能 |
| 1 校验(MARK) | 校验位固定为 1 | ❌ 不能 |
示例 :数据位 8 位 = 0101 1010(4 个 1)
- 奇校验:1 的总数应为奇数 → 4 已是偶数 → 校验位 = 1
- 偶校验:1 的总数应为偶数 → 4 已是偶数 → 校验位 = 0
实际开发中 :奇偶校验只能检测单比特错误,通常不开启校验位,数据完整性由更高层协议(如 CRC)保证。
第 3 章 · 串口电平标准
3.1 核心概念
一句话总结:TTL、RS232、RS485、RS422 是四种不同的串口电平标准------TTL 是芯片内部用的,RS232 是早期电脑串口,RS485/RS422 是工业总线。

3.2 先看对比:四大电平标准
3.3 知识对比表:四大电平标准
| 对比维度 | TTL | RS232 | RS485 | RS422 |
|---|---|---|---|---|
| 信号类型 | 单端 | 单端 | 差分 | 差分 |
| 电压范围 | 0~3.3V/5V | -15V~+15V | -6V~+6V(差) | -6V~+6V(差) |
| 逻辑 1 | 2V~5V | -15V~-3V | A-B > 200mV | A-B > 200mV |
| 逻辑 0 | 0~0.8V | +3V~+15V | A-B < -200mV | A-B < -200mV |
| 传输距离 | < 1m | < 15m | > 1200m | > 1200m |
| 传输速率 | 最高(可达 10Mbps) | 低(通常 115200) | 高(可达 10Mbps) | 高(可达 10Mbps) |
| 通信方式 | 全双工 | 全双工 | 半双工 | 全双工 |
| 导线数量 | 2 线 + GND | 3 线 + GND | 2 线(A/B) | 4 线(两对) |
| 抗干扰能力 | 弱 | 中 | 强 | 强 |
| 多设备通信 | ❌ 点对点 | ❌ 点对点 | ✅ 一对多 | ✅ 一对多 |
| 典型场景 | 芯片间通信 | 老式电脑串口 | 工业总线、PLC | 工业设备、仪表 |
关键类比
| 标准 | 一句话类比 |
|---|---|
| TTL | 两个人面对面说话(声音小,距离近) |
| RS232 | 用扩音器喊话(声音大,但需要转换器) |
| RS485 | 一群人用对讲机轮流说话(半双工,距离远,抗干扰) |
| RS422 | 一群人用电话会议(全双工,两对线各说各的) |
全双工 vs 半双工 vs 单工
一句话总结:全双工 = 两个人同时说同时听(电话),半双工 = 一个人说另一个人听,说完再换(对讲机),单工 = 一个人说另一个人只能听(广播)。
三种模式对比
| 对比维度 | 单工 | 半双工 | 全双工 |
|---|---|---|---|
| 数据流向 | 单向固定 | 双向交替 | 双向同时 |
| 导线数量 | 1 根 | 1 对(2 根) | 2 对(4 根) |
| 通信效率 | 低 | 中 | 高 |
| 硬件复杂度 | 低 | 中 | 高 |
| 典型应用 | 广播、电视 | 对讲机、RS485 | 电话、RS232、RS422 |
| 串口举例 | 无 | RS485 | RS232、RS422、TTL |
第 4 章 · UART 硬件原理
4.1 核心概念
一句话总结:UART(Universal Asynchronous Receiver/Transmitter)是 SOC 内部集成的串口控制器------负责把 CPU 的并行数据转成串行波形发送,以及把接收到的串行波形转成并行数据交给 CPU。
生活类比 :UART 就像翻译官------CPU 说"并行语"(8 位同时说),UART 翻译成"串行语"(一位一位说),对方设备的 UART 再翻译回"并行语"交给对方的 CPU。
4.2 串口 vs UART:到底有什么区别?
一句话总结 :**串口(Serial Port)**是通信协议和接口标准(第 1~3 章讲的内容),UART 是实现串口协议的硬件控制器------串口是"规矩",UART 是"执行规矩的人"。
生活类比 :串口协议就像交通规则 (红灯停绿灯行、靠右行驶),UART 就像交警(负责执行交通规则、指挥车辆通行)。没有交通规则,交警不知道该怎么指挥;没有交警,交通规则没人执行。
两者的关系
区别对比
| 对比维度 | 串口(Serial Port) | UART |
|---|---|---|
| 本质 | 通信协议和接口标准 | 实现协议的具体硬件 |
| 包含内容 | 波特率、数据位、校验位、停止位、电平标准 | 发送器、接收器、波特率发生器、寄存器 |
| 是否可见 | 逻辑概念(软件层面) | 物理硬件(芯片内部) |
| 举例 | "115200-8-N-1" 是串口协议配置 | i.MX6ULL 芯片内部的 UART1~UART8 是硬件 |
| 能否独立存在 | 可以(用 GPIO 模拟"软件串口") | 可以(但需要外部引脚连接) |
为什么分开说?
| 原因 | 说明 |
|---|---|
| 串口是协议,UART 是硬件 | 第 1~3 章讲的是"串口通信的规则是什么",第 4 章开始讲"UART 硬件怎么实现这些规则" |
| 串口可以用其他方式实现 | 不一定要 UART------可以用 GPIO 配合定时器模拟串口协议(俗称"软件串口"或"bit-banging"),但 UART 是专用的硬件实现,效率更高、更准确 |
| UART 也可以做其他事 | UART 硬件除了标准串口协议,还支持红外模式、9 位数据模式(RS485 多机通信)等扩展功能 |
总结
4.3 UART vs USART
| 对比维度 | UART | USART |
|---|---|---|
| 全称 | 通用异步收发器 | 通用同步/异步收发器 |
| 时钟线 | ❌ 不需要 | ✅ 有单独的时钟线 |
| 通信方式 | 仅异步 | 支持同步和异步 |
| 硬件复杂度 | 低 | 高 |
| 传输速度 | 受限于波特率精度 | 同步模式可更快 |
| 典型芯片 | i.MX6ULL UART | STM32 USART |
4.3 UART 数据流
第 5 章 · i.MX6ULL UART
5.1 核心概念
一句话总结:i.MX6ULL 内部集成了 8 个 UART 模块,每个都支持多种电平标准(通过外部转换芯片),UART1 通常用于串口调试(通过 CH340 转 USB)。

5.2 8 个 UART 资源
| UART 编号 | 用途 | 备注 |
|---|---|---|
| UART1 | 调试串口(默认) | 通过 CH340 转 USB 连接电脑 |
| UART2~8 | 通用串口 | 连接外部设备(GPS、传感器等) |
5.3 核心寄存器
| 寄存器 | 作用 | 关键位 |
|---|---|---|
| UART1_URXD | 数据接收寄存器 | bit0:7 = 接收到的 8 位数据 |
| UART1_UTXD | 数据发送寄存器 | 写入 bit0:7 即可发送 |
| UART1_UCR1 | 控制寄存器 1 | bit0 = UART 使能 |
| UART1_UCR2 | 控制寄存器 2 | 配置数据位、停止位、校验位、收发使能 |
| UART1_UCR3 | 控制寄存器 3 | 其他控制 |
| UART1_USR1 | 状态寄存器 1 | bit3 = 发送完成标志(TRDY) |
| UART1_USR2 | 状态寄存器 2 | bit0 = 数据接收就绪(RDR) |
| UART1_UFCR | 分频控制寄存器 | bit7:9 = 分频系数 |
| UART1_UBIR | 波特率整数寄存器 | 波特率计算 |
| UART1_UBMR | 波特率小数寄存器 | 波特率计算 |
5.4 波特率计算公式
scss
波特率 = 时钟频率 / (16 × (UBMR + 1) / (UBIR + 1))
示例:时钟频率 80 MHz,目标波特率 115200
scss
80 × 10^6 / (16 × 115200) = 43.4
选择 UBMR = 433,UBIR = 9
验证:80 × 10^6 / (16 × (433+1) / (9+1)) = 115,207 ≈ 115200 ✅
第 6 章 · 串口编程实现
6.1 核心概念
一句话总结:串口编程 = 开时钟 → 设引脚 → 配参数(波特率/数据位/停止位/校验位)→ 打开发送接收 → 读写数据寄存器。
6.2 初始化流程
6.3 完整代码实现
c
#include "imx6ul.h"
// ① UART1 初始化:115200-8-N-1
void uart1_init(void) {
// 1. 开启 UART1 时钟
CCM_CCGR5 |= (3 << 0); // CG15: UART1 时钟使能
// 2. 配置 GPIO 引脚复用为 UART1
// TXD: GPIOE_16, RXD: GPIOE_17
IOMUXC_SW_MUX_CTL_PAD_GPIOE16 = 3; // ALT3 = UART1_TXD
IOMUXC_SW_MUX_CTL_PAD_GPIOE17 = 3; // ALT3 = UART1_RXD
// 3. 复位 UART1
UART1_UCR2 = 0; // 先禁用 UART
while (UART1_UCR2 & (1 << 0)); // 等待复位完成
// 4. 配置通信参数
// UCR2: 8 位数据位, 1 位停止位, 无校验, 使能收发
UART1_UCR2 = (1 << 1) // RXEN: 使能接收
| (1 << 2) // TXEN: 使能发送
| (1 << 5) // WS: 8 位数据位(与 bit6 配合)
| (1 << 6) // WS: 8 位数据位
| (0 << 7); // STPB: 1 位停止位
// 5. 配置波特率:115200(时钟 80 MHz)
UART1_UFCR = (5 << 7); // 分频系数 = 5(不分频)
// 公式:80MHz / (16 × (UBMR+1) / (UBIR+1)) = 115200
UART1_UBIR = 9; // UBIR = 9
UART1_UBMR = 433; // UBMR = 433
// 6. 使能 UART1
UART1_UCR1 |= (1 << 0); // UARTEN = 1
}
// ② 发送一个字节
void uart1_putchar(char c) {
// 等待发送缓冲区为空(TRDY 标志位置位)
while (!(UART1_USR1 & (1 << 3)));
// 写入发送寄存器
UART1_UTXD = c;
}
// ③ 发送字符串
void uart1_puts(const char *str) {
while (*str) {
uart1_putchar(*str++);
}
}
// ④ 接收一个字节
char uart1_getchar(void) {
// 等待数据接收就绪(RDR 标志位置位)
while (!(UART1_USR2 & (1 << 0)));
// 读取接收寄存器
return UART1_URXD & 0xFF;
}
// ⑤ 主函数:串口回显测试
int main(void) {
uart1_init(); // 初始化 UART1
uart1_puts("Hello i.MX6ULL!\r\n");
while (1) {
char c = uart1_getchar(); // 接收一个字符
uart1_putchar(c); // 回发(回显)
}
return 0;
}
执行结果(串口终端):
css
Hello i.MX6ULL!
a ← 在键盘上输入 'a'
a ← 回显显示 'a'
b ← 输入 'b'
b ← 回显 'b'
(每按一个键,立即回显)
6.4 支持 printf 格式化输出
为了让串口像 printf 一样支持格式化输出(%d、%x、%s 等),需要实现 fputc 重定向或使用 vsprintf。
c
#include <stdarg.h>
#include <string.h>
// 缓冲区
static char printf_buf[256];
// 格式化打印(支持 %d, %x, %s, %c)
void uart1_printf(const char *fmt, ...) {
va_list args;
va_start(args, fmt);
// vsprintf 将格式化字符串写入缓冲区
vsprintf(printf_buf, fmt, args);
va_end(args);
// 通过串口发送缓冲区内容
uart1_puts(printf_buf);
}
// 使用示例
int main(void) {
uart1_init();
int val = 100;
uart1_printf("整数: %d\r\n", val);
uart1_printf("十六进制: 0x%X\r\n", val);
uart1_printf("字符串: %s\r\n", "Hello UART");
while (1) {
char c = uart1_getchar();
uart1_printf("收到: %c (0x%02X)\r\n", c, c);
}
return 0;
}
执行结果:
less
整数: 100
十六进制: 0x64
字符串: Hello UART
a ← 输入 'a'
收到: a (0x61)
b ← 输入 'b'
收到: b (0x62)
第 7 章 · Linux 下的串口编程
7.1 核心概念
一句话总结 :Linux 把串口设备当作文件来操作------open("/dev/ttyXXX") 打开串口,用 tcsetattr 配置参数,用 read/write 收发数据。
7.2 串口设备文件
| 设备 | 路径 | 说明 |
|---|---|---|
| USB 转串口 | /dev/ttyUSB0 |
CH340/CP2102/PL2303 |
| 原生串口 | /dev/ttyS0 |
主板上的串口 |
| 虚拟串口 | /dev/pts/0 |
伪终端 |
7.3 完整 C 代码示例
c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <string.h>
// 打开串口
int open_serial(const char *dev) {
int fd = open(dev, O_RDWR | O_NOCTTY);
if (fd < 0) {
perror("open");
return -1;
}
return fd;
}
// 配置串口:115200-8-N-1
int config_serial(int fd) {
struct termios opt;
// 获取当前配置
tcgetattr(fd, &opt);
// 设置波特率:115200
cfsetispeed(&opt, B115200);
cfsetospeed(&opt, B115200);
// 控制模式标志
opt.c_cflag &= ~CSIZE; // 清除数据位设置
opt.c_cflag |= CS8; // 8 位数据位
opt.c_cflag &= ~CSTOPB; // 1 位停止位
opt.c_cflag &= ~PARENB; // 无校验
opt.c_cflag |= CREAD | CLOCAL; // 使能接收,忽略调制解调器控制
// 本地模式标志
opt.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // 原始模式
// 输出模式标志
opt.c_oflag &= ~OPOST; // 原始输出
// 输入模式标志
opt.c_iflag &= ~(IXON | IXOFF | IXANY); // 关闭软件流控
opt.c_iflag &= ~(INLCR | ICRNL); // 不转换换行符
// 超时设置
opt.c_cc[VMIN] = 1; // 至少读取 1 个字节
opt.c_cc[VTIME] = 0; // 不等待
// 应用配置
tcsetattr(fd, TCSANOW, &opt);
return 0;
}
// 发送数据
int send_data(int fd, const char *data, int len) {
return write(fd, data, len);
}
// 接收数据
int recv_data(int fd, char *buf, int max_len) {
return read(fd, buf, max_len);
}
int main(int argc, char *argv[]) {
const char *dev = "/dev/ttyUSB0"; // 根据实际情况修改
int fd = open_serial(dev);
if (fd < 0) return 1;
config_serial(fd);
printf("串口 %s 已打开,115200-8-N-1\n", dev);
// 发送数据
send_data(fd, "Hello from Linux!\r\n", 19);
// 接收并回显
char buf[256];
while (1) {
int n = recv_data(fd, buf, sizeof(buf) - 1);
if (n > 0) {
buf[n] = '\0';
printf("收到: %s", buf);
send_data(fd, buf, n); // 回显
}
}
close(fd);
return 0;
}
编译与运行:
bash
# 编译
gcc serial_linux.c -o serial_linux
# 运行(需要 root 权限或加入 dialout 组)
sudo ./serial_linux
# 输出:
# 串口 /dev/ttyUSB0 已打开,115200-8-N-1
# 收到: hello
# 收到: world
第 8 章 · Linux 常用串口库
除了直接使用 termios 系统调用,Linux 生态中有多个封装好的串口库,提供更简洁的 API。
8.1 常用库一览
| 库名 | 语言 | 特点 | 适用场景 | 典型项目 |
|---|---|---|---|---|
| termios | C | 系统标准 API,零依赖 | 底层串口编程 | 嵌入式 Linux 系统 |
| libserialport | C | 跨平台,sigrok 项目维护 | 需要跨平台支持 | PulseView、sigrok-cli |
| Boost.Asio | C++ | 现代 C++ 异步框架 | C++ 项目串口通信 | 大量 C++ 后端 |
| libserial | C++ | 轻量级 C++ 串口封装 | 简单的 C++ 串口需求 | 机器人、工控 |
| Qt SerialPort | C++ | Qt 框架模块 | Qt 项目串口通信 | QSerialPort 终端 |
| pyserial | Python | 简单易用,生态丰富 | 快速原型、测试脚本 | 串口调试工具 |
8.2 libserialport(C 语言,跨平台首选)
libserialport 是 sigrok 项目开发的跨平台串口库,支持 Linux、Windows、macOS,API 简洁稳定。
c
#include <stdio.h>
#include <stdlib.h>
#include <libserialport.h>
int main(void) {
struct sp_port *port;
char buf[256];
// ① 获取串口列表并选择第一个
struct sp_port **port_list;
sp_list_ports(&port_list);
if (port_list[0] == NULL) {
fprintf(stderr, "没有找到串口\n");
return 1;
}
printf("找到串口: %s\n", sp_get_port_name(port_list[0]));
// ② 打开串口
sp_open(port_list[0], SP_MODE_READ_WRITE);
// ③ 配置参数:115200-8-N-1
sp_set_baudrate(port_list[0], 115200);
sp_set_bits(port_list[0], 8);
sp_set_parity(port_list[0], SP_PARITY_NONE);
sp_set_stopbits(port_list[0], 1);
sp_set_flowcontrol(port_list[0], SP_FLOWCONTROL_NONE);
printf("串口已配置:115200-8-N-1\n");
// ④ 发送数据
sp_nonblocking_write(port_list[0], "Hello from libserialport!\r\n", 27);
// ⑤ 接收数据
int n = sp_nonblocking_read(port_list[0], buf, sizeof(buf) - 1);
if (n > 0) {
buf[n] = '\0';
printf("收到: %s\n", buf);
}
// ⑥ 关闭
sp_close(port_list[0]);
sp_free_port_list(port_list);
return 0;
}
编译与运行:
bash
# 安装
sudo apt install libserialport-dev
# 编译
gcc serial_libserialport.c -o serial_libserialport -lserialport
# 运行
./serial_libserialport
# 输出:
# 找到串口: /dev/ttyUSB0
# 串口已配置:115200-8-N-1
8.3 Boost.Asio(C++ 项目首选)
cpp
#include <iostream>
#include <boost/asio.hpp>
int main(void) {
boost::asio::io_context io;
boost::asio::serial_port serial(io);
try {
// ① 打开串口
serial.open("/dev/ttyUSB0");
// ② 配置参数:115200-8-N-1
serial.set_option(boost::asio::serial_port::baud_rate(115200));
serial.set_option(boost::asio::serial_port::character_size(8));
serial.set_option(boost::asio::serial_port::parity(
boost::asio::serial_port::parity::none));
serial.set_option(boost::asio::serial_port::stop_bits(
boost::asio::serial_port::stop_bits::one));
serial.set_option(boost::asio::serial_port::flow_control(
boost::asio::serial_port::flow_control::none));
std::cout << "串口已打开:115200-8-N-1" << std::endl;
// ③ 发送数据
std::string msg = "Hello from Boost.Asio!\r\n";
boost::asio::write(serial, boost::asio::buffer(msg));
// ④ 接收数据
char buf[256];
size_t n = boost::asio::read(serial,
boost::asio::buffer(buf, sizeof(buf)));
buf[n] = '\0';
std::cout << "收到: " << buf << std::endl;
} catch (std::exception &e) {
std::cerr << "错误: " << e.what() << std::endl;
return 1;
}
serial.close();
return 0;
}
编译与运行:
bash
# 安装
sudo apt install libboost-dev
# 编译
g++ serial_boost.cpp -o serial_boost -lboost_system -lpthread
# 运行
./serial_boost
8.4 pyserial(Python 快速原型)
python
import serial
import time
# 打开串口
ser = serial.Serial(
port='/dev/ttyUSB0',
baudrate=115200,
bytesize=8,
parity='N',
stopbits=1,
timeout=1
)
print(f"串口已打开: {ser.port} 115200-8-N-1")
# 发送数据
ser.write(b"Hello from Python!\r\n")
# 接收数据
data = ser.readline()
print(f"收到: {data.decode().strip()}")
# 循环收发
while True:
if ser.in_waiting > 0:
data = ser.read(ser.in_waiting)
print(f"收到: {data.decode().strip()}")
# 回显
ser.write(data)
time.sleep(0.1)
运行:
bash
# 安装
pip install pyserial
# 运行
python3 serial_python.py
8.5 知识对比表
| 对比维度 | termios(系统 API) | libserialport | Boost.Asio | pyserial |
|---|---|---|---|---|
| 语言 | C | C | C++ | Python |
| 安装 | 无需安装 | apt install libserialport-dev |
apt install libboost-dev |
pip install pyserial |
| 代码量 | 多(需手动配置 termios) | 中 | 中 | 少(几行搞定) |
| 跨平台 | 仅 Linux | ✅ Linux/Win/Mac | ✅ Linux/Win/Mac | ✅ Linux/Win/Mac |
| 学习曲线 | 中高 | 低 | 中 | 极低 |
| 性能 | 最高 | 高 | 高 | 中 |
| 推荐场景 | 嵌入式 Linux 底层 | 跨平台 C 项目 | C++ 项目 | 测试脚本、快速原型 |
附录 · 核心概念速查
| 概念 | 一句话总结 | 生活类比 |
|---|---|---|
| 串口 | 一根线发、一根线收、不要时钟 | 对讲机通话 |
| UART | 把并行数据转串行发送的硬件 | 翻译官 |
| 波特率 | 每秒传输的位数 | 说话语速 |
| 起始位 | 拉低电平说"准备开始" | 按下对讲机按钮 |
| 停止位 | 拉高电平说"说完了" | 松开对讲机按钮 |
| TTL | 0~3.3V,芯片内部用 | 面对面说话 |
| RS232 | -15V~+15V,负逻辑,电脑串口 | 用扩音器喊话 |
| RS485 | 差分信号,半双工,工业总线 | 一群人用对讲机轮流说 |
| RS422 | 差分信号,全双工,两对线 | 电话会议 |
一句话总结:串口通信 = 约定好波特率(速度)和帧格式(起始位 + 数据位 + 校验位 + 停止位),通过 TXD 和 RXD 两根线异步收发数据。不同电平标准(TTL/RS232/RS485/RS422)决定了电压范围和传输距离,通过外部转换芯片实现互联。