1. 接口协议基础与验证环境搭建:SPI、I2C、UART 协议对比,验证平台架构设计,Python 与 C 混合编程环境配置
各位同学,咱们今天正式开课。做硬件验证和驱动开发,第一件事不是写代码,而是把三个最常用的接口协议搞清楚。SPI、I2C、UART,这三兄弟你几乎天天见。我见过不少工程师,代码写得飞起,结果连 I2C 的起始条件都画错——嗯,这种坑咱们今天一次性填平。
1.1 三大协议核心差异:一张表说清楚
先别急着看波形。我个人习惯,上手之前先做横向对比。你想想看,选协议就像选工具——拧螺丝用扳手,剪电线用钳子,各有各的活法。
| 特性 | UART | SPI | I2C |
|---|---|---|---|
| 信号线数 | 2(TX、RX) | 4(SCLK、MOSI、MISO、CS) | 2(SCL、SDA) |
| 通信方式 | 异步,无时钟线 | 同步,主设备提供时钟 | 同步,主设备提供时钟 |
| 数据方向 | 全双工 | 全双工 | 半双工 |
| 从设备选择 | 点对点 | 片选线(CS) | 地址寻址(7位或10位) |
| 速度范围 | 典型 9600~115200 bps | 典型 1~50 MHz | 标准 100 kHz,快速 400 kHz |
| 抗干扰能力 | 弱(无时钟同步) | 强(差分可选) | 中等(开漏输出) |
| 典型应用 | 调试日志、GPS 模块 | ADC、SD 卡、显示屏 | 传感器、EEPROM、RTC |
这张表我建议你存下来。每次选型的时候拿出来对照一下,能省不少事。我在项目中遇到过有人用 UART 接 10 个从设备,结果搞了个复杂的轮询协议——其实换个 I2C 就解决了。
1.2 协议细节与避坑指南
UART:最老实的那个
UART 说白了就是两根线,一发一收。没有时钟线,所以两边得提前约定好波特率。我刚开始做嵌入式的时候,经常遇到乱码——后来发现是波特率对不上。嗯,这里要注意:波特率误差不能超过 ±2%,否则数据就飘了。
我曾经踩过的坑:用 8 MHz 内部振荡器跑 115200 波特率,结果误差 3.5%,数据全错。后来换成外部晶振才稳定。所以,高频 UART 一定要用高精度时钟源。
SPI:快,但线多
SPI 是速度之王。四根线:时钟、主出从入、主入从出、片选。每个从设备独占一根片选线,所以从设备多了,GPIO 就不够用。我见过一个项目接了 8 个 SPI 从设备,光片选就占了 8 个引脚——后来改用 I2C 了。
SPI 有四种模式,由时钟极性(CPOL)和时钟相位(CPHA)组合决定。很多人在这里翻车。我教你一个记忆方法:CPOL=0 时空闲低电平,CPOL=1 时空闲高电平;CPHA=0 时第一个边沿采样,CPHA=1 时第二个边沿采样。记不住?那就直接看数据手册,别猜。
I2C:线少,但协议复杂
I2C 只有两根线,靠地址寻址。起始条件、停止条件、应答信号——这些时序要求很严格。我调试 I2C 的时候,最喜欢用逻辑分析仪抓波形。为什么?因为 I2C 的时序问题用肉眼很难看出来。
小技巧:I2C 总线上拉电阻选 4.7 kΩ 是通用值。如果总线电容大(比如线很长),换成 2.2 kΩ。如果功耗敏感,用 10 kΩ。这个经验值我用了十年,基本没出过问题。
1.3 验证平台架构设计
协议搞清楚了,接下来搭验证平台。我个人习惯把平台分成三层:硬件抽象层、协议驱动层、测试用例层。这样分层的好处是——你换硬件平台,只需要改最下面一层。
这个架构的好处是——你写测试用例的时候,根本不用关心底层寄存器怎么配。我见过很多团队把测试代码和驱动代码混在一起,结果换了个芯片,全部重写。你说这得多折腾?
1.4 Python 与 C 混合编程环境配置
做验证测试,C 语言跑在目标板上,Python 跑在 PC 上。Python 负责发指令、收数据、做分析;C 负责执行底层操作。两者通过串口或网络通信。
我推荐的环境配置如下:
- PC 端:Python 3.8+,安装
pyserial、numpy、matplotlib用于数据分析和可视化 - 目标板:C 语言(GCC 或 ARMCC),实现底层驱动和通信协议
- 通信桥梁:UART 转 USB(如 CH340、FT232),波特率 115200 或更高
核心思路:Python 发命令字符串(如 "SPI_READ 0x10 4"),C 端解析后执行,返回结果。这样你可以在 Python 里写循环、做统计、画波形——C 端只管干活。
下面是一个简单的通信协议示例:
// C 端(目标板)命令解析框架
void process_command(char *cmd) {
if (strncmp(cmd, "SPI_READ", 8) == 0) {
uint8_t addr = (uint8_t)atoi(cmd + 9);
uint8_t len = (uint8_t)atoi(cmd + 13);
spi_read(addr, buffer, len);
uart_send(buffer, len);
} else if (strncmp(cmd, "I2C_SCAN", 8) == 0) {
i2c_scan_devices();
}
}
# Python 端(PC)发送与接收
import serial
ser = serial.Serial('COM3', 115200, timeout=1)
ser.write(b'SPI_READ 0x10 4\n')
data = ser.read(4)
print(f"Received: {data.hex()}")
个人经验:Python 端一定要加超时处理。我遇到过目标板死机,Python 一直阻塞等待,整个测试流程卡死。加个 timeout=1,再配合重试机制,稳得很。
1.5 环境搭建检查清单
最后,给你一个检查清单。每次搭建新环境,按这个走一遍,基本不会漏东西:
- Python 环境:确认
pyserial安装成功,import serial不报错 - C 编译环境:确认交叉编译器路径正确,能编译一个空工程
- 串口通信:用串口助手测试 PC 和目标板能否收发数据
- 逻辑分析仪:连接 SPI/I2C 信号线,确认波形正确
- 电源:确认目标板供电稳定,尤其是 SPI 高速模式时
好了,这一章的内容就到这里。协议对比、平台架构、环境配置——这三块是后面所有章节的基础。你把这些搞扎实了,后面的调试才不会手忙脚乱。