1. 串口通信基础:RS232/RS485/TTL电平区别、波特率、数据位、停止位、校验位详解
做嵌入式开发这么多年,串口通信是我打交道最多的接口之一。说实话,很多新手一上来就被RS232、RS485、TTL这几个名词搞晕了。今天咱们就把这些概念掰开揉碎了讲清楚。
1.1 三种电平标准:RS232、RS485、TTL
这三种东西,说白了就是信号电压的"方言"。同一个数据,用不同的电压范围去表示,就成了不同的标准。
| 标准 | 逻辑1(高电平) | 逻辑0(低电平) | 传输距离 | 典型应用 |
|---|---|---|---|---|
| TTL | 2.4V ~ 5V | 0V ~ 0.5V | <1米 | 板级通信、MCU调试 |
| RS232 | -3V ~ -15V | +3V ~ +15V | 约15米 | 老式PC串口、工控设备 |
| RS485 | A-B 电压差>+0.2V | A-B 电压差<-0.2V | 可达1200米 | 工业总线、多机通信 |
关键点:TTL和RS232不能直接对接!我曾经见过有人直接把USB转TTL模块插到工控机的RS232口上,结果烧了芯片。必须用MAX232这类电平转换芯片。
TTL电平是单片机最常用的。5V或3.3V代表1,0V代表0。简单直接,但抗干扰能力差,线长了就不行。
RS232用了负逻辑,电压范围还翻了个倍。我记得第一次用示波器看RS232波形时还纳闷——怎么高电平是负电压?后来才明白,这是为了抗干扰故意设计的。
RS485是差分信号,用两根线(A和B)的电压差来表示数据。为什么能传1200米?因为差分信号对共模干扰不敏感。我在工厂调试时,几十米的RS485总线从来没出过问题。
1.2 波特率:通信的"节拍"
波特率就是每秒传输的符号数。单位是bps(bits per second)。
常见的波特率有:9600、19200、38400、115200、921600。
为什么是这些数字?因为它们都是时钟分频出来的整数倍。我习惯用115200做调试,速度快,大多数USB转串口芯片都支持。
经验之谈:波特率越高,传输越快,但误码率也会上升。长距离通信时,我一般降到9600或19200。曾经在一条50米的RS232线上试过115200,数据全是乱码——降回9600就稳了。
1.3 数据位:一帧里装多少数据
数据位就是每个数据帧里实际传输的数据位数。通常是7位或8位。
- 7位数据位:老式ASCII通信常用,因为ASCII字符只需要7位
- 8位数据位:现在最常用,一个字节正好8位
你想想看,如果传二进制数据,7位就装不下一个完整的字节。所以现在绝大多数场景都用8位数据位。
1.4 停止位:帧与帧之间的"间隔"
停止位是一帧数据结束后的空闲时间。常见的有1位、1.5位、2位。
为什么需要停止位?因为接收端需要时间处理刚收到的数据。停止位越长,容错性越好,但传输效率越低。
我个人的习惯:
- 短距离、高可靠场景:1位停止位
- 长距离、干扰大的场景:2位停止位
- 1.5位?说实话我几乎没用过,太冷门了
1.5 校验位:数据对不对?
校验位用来检测传输过程中有没有出错。常见的有:
| 校验方式 | 原理 | 特点 |
|---|---|---|
| 无校验(None) | 不添加校验位 | 效率最高,无检错能力 |
| 奇校验(Odd) | 使1的个数为奇数 | 能检测奇数位错误 |
| 偶校验(Even) | 使1的个数为偶数 | 能检测奇数位错误 |
| 标记校验(Mark) | 校验位固定为1 | 基本不用,兼容老设备 |
| 空格校验(Space) | 校验位固定为0 | 基本不用,兼容老设备 |
避坑指南:我曾经调试一个设备,怎么都对不上数据。查了半天,发现发送端设的是奇校验,接收端设的是偶校验。两边校验位不一致,数据全被当成错误丢弃了。记住:通信双方的所有参数必须完全一致!
1.6 知识体系总览
下面这张图把串口通信的核心知识点串起来了,方便你理解它们之间的关系:
1.7 实际配置示例
假设我们要用Python的pyserial库配置一个串口,参数是:115200波特率、8位数据位、1位停止位、无校验。代码很简单:
import serial
ser = serial.Serial(
port='COM3', # Windows下端口号
baudrate=115200, # 波特率
bytesize=8, # 数据位
stopbits=1, # 停止位
parity='N', # 校验位:N=无,E=偶校验,O=奇校验
timeout=1 # 超时时间(秒)
)
# 发送数据
ser.write(b'Hello, World!')
# 接收数据
data = ser.read(10) # 读取10个字节
ser.close()
小技巧:调试时先用串口助手确认参数能通,再写代码。我习惯用SSCOM或Putty先测一遍,省得代码写完了才发现参数不对。