第2章:显示接口协议基础
做嵌入式显示驱动,说白了就是跟各种接口协议打交道。我刚开始接触这块时,总觉得协议就是一堆时序图,看着就头疼。后来踩的坑多了,才明白——搞懂协议,就是搞懂怎么跟外设「说话」。
这一章,咱们重点聊三个最常见的显示接口:SPI、I2C、LVDS。嗯,一个一个来。
2.1 SPI协议详解
SPI,全称Serial Peripheral Interface。我习惯叫它「四线制」协议。为什么?因为它至少需要四根线:
- SCLK:时钟线,由主机控制
- MOSI:主机输出,从机输入
- MISO:主机输入,从机输出
- CS:片选线,低电平有效
你想想看,四根线就能搞定全双工通信,效率确实高。我在项目中遇到过用SPI驱动128×64的OLED屏,刷新率能做到30fps以上,完全够用。
2.1.1 SPI的四种模式
这里有个坑,我刚开始做时经常搞混——SPI有四种工作模式。区别在于时钟极性(CPOL)和时钟相位(CPHA)的组合:
| 模式 | CPOL | CPHA | 特点 |
|---|---|---|---|
| 模式0 | 0 | 0 | 空闲时低电平,上升沿采样 |
| 模式1 | 0 | 1 | 空闲时低电平,下降沿采样 |
| 模式2 | 1 | 0 | 空闲时高电平,下降沿采样 |
| 模式3 | 1 | 1 | 空闲时高电平,上升沿采样 |
我个人习惯的做法是:先看从机数据手册,找到它支持的SPI模式。如果手册没写,就用模式0试,因为大部分器件默认就是模式0。
2.1.2 SPI驱动OLED的代码示例
以SSD1306 OLED驱动为例,初始化时序是这样的:
// SPI初始化
void SPI_Init(void) {
// 设置SCLK、MOSI为推挽输出
// 设置CS为推挽输出
// 设置MISO为浮空输入
// 时钟频率设为4MHz(OLED一般支持到10MHz)
}
// 写一个字节
void SPI_WriteByte(uint8_t data) {
for(uint8_t i = 0; i < 8; i++) {
SCLK_LOW();
if(data & 0x80) MOSI_HIGH();
else MOSI_LOW();
data <<= 1;
SCLK_HIGH(); // 上升沿采样
}
}
// 写命令
void OLED_WriteCmd(uint8_t cmd) {
DC_LOW(); // 命令模式
CS_LOW();
SPI_WriteByte(cmd);
CS_HIGH();
}
// 写数据
void OLED_WriteData(uint8_t data) {
DC_HIGH(); // 数据模式
CS_LOW();
SPI_WriteByte(data);
CS_HIGH();
}
2.2 I2C协议详解
I2C跟SPI最大的区别是什么?它只需要两根线:SDA(数据线)和SCL(时钟线)。但代价是速度慢一些,而且协议更复杂。
我刚开始用I2C时,最头疼的就是那个「起始条件」和「停止条件」。说白了就是:
- 起始条件:SCL高电平时,SDA从高变低
- 停止条件:SCL高电平时,SDA从低变高
嗯,记住这个口诀就行:「高高低低是起始,低低高高是停止」。
2.2.1 I2C的地址和读写
每个I2C从设备都有一个7位或10位地址。以SSD1306为例,它的7位地址是0x3C(如果DC引脚接地)。读写操作是这样的:
| 操作 | 发送数据 | 说明 |
|---|---|---|
| 写命令 | 0x00 + 命令字节 | 控制字节最低位为0 |
| 写数据 | 0x40 + 数据字节 | 控制字节最低位为1 |
| 读数据 | 先写地址,再读数据 | 需要重新发送起始条件 |
2.2.2 I2C的速率选择
I2C有三种标准速率:
- 标准模式:100kHz,最常用,兼容性最好
- 快速模式:400kHz,大多数器件支持
- 高速模式:3.4MHz,需要特殊硬件支持
我个人习惯:调试阶段先用100kHz,等通信稳定了再往上提。为什么?因为速率越高,对PCB走线和上拉电阻的要求越严格。我曾经在快速模式下遇到数据错位,最后发现是上拉电阻从4.7kΩ换到2.2kΩ就解决了。
2.3 LVDS协议简介
LVDS,Low-Voltage Differential Signaling。说白了就是「低压差分信号」。跟SPI、I2C的单端信号不同,LVDS用两根线传一个信号,一根正、一根负。
为什么这么做?抗干扰能力强。你想想看,外部噪声同时耦合到两根线上,接收端一相减,噪声就抵消了。这就是差分信号的优势。
2.3.1 LVDS在显示中的应用
LVDS主要用于大尺寸、高分辨率的显示屏。比如7寸以上的TFT屏,分辨率1024×600或更高。我做过一个项目,用LVDS驱动10.1寸的屏,分辨率1280×800,刷新率60Hz,效果非常流畅。
LVDS的典型信号组包括:
- 4对数据线:传输RGB数据和控制信号
- 1对时钟线:提供像素时钟
- 可选的第5对数据线:用于更高色深(如8位色)
2.3.2 LVDS的电气特性
| 参数 | 典型值 | 说明 |
|---|---|---|
| 差分电压 | 350mV | 正负线之间的电压差 |
| 共模电压 | 1.2V | 两根线对地的平均电压 |
| 传输速率 | 可达1Gbps | 每对数据线 |
| 功耗 | 约100mW | 每对线,远低于TTL电平 |
2.3.3 什么时候选LVDS?
我一般这样判断:
- 分辨率超过800×480,用LVDS
- 传输距离超过30cm,用LVDS
- 对EMI有严格要求,用LVDS
- 否则,用SPI或RGB接口更简单
嗯,说白了就是:小屏用SPI,中屏用RGB,大屏用LVDS。这个经验法则在我做过的十几个项目中都适用。
下一章,咱们聊聊RGB接口和MIPI DSI。这两个在嵌入式显示驱动里也经常用到,特别是MIPI DSI,现在手机和平板上几乎都是它了。