2. SPI 通信协议基础

SPI(Serial Peripheral Interface,串行外设接口)是驱动 LCD TFT 屏幕最常用的同步串行通信协议。它由 Motorola 公司提出,采用主从(Master-Slave)架构,以全双工、高速率的特点在嵌入式显示领域占据主导地位。理解 SPI 的四线工作机制和时钟配置是驱动 LCD 屏幕的基石。

2.1 SPI 四线工作原理

标准的 SPI 接口使用四条信号线完成数据交换,每条线都有明确的职责:

信号线 全称 方向(主→从) 功能描述
SCLK Serial Clock 主→从 由主机产生的同步时钟,决定数据传输速率和时序
MOSI Master Out Slave In 主→从 主机发送数据给从机(如 LCD 驱动 IC)
MISO Master In Slave Out 从→主 从机发送数据给主机(LCD 读操作时使用)
CS Chip Select 主→从 片选信号,低电平有效,选中对应的从机设备
LCD 驱动要点: 多数 LCD TFT 模块仅需 SCLK、MOSI、CS 三线即可完成写操作(MISO 可悬空)。但若需读取屏幕 ID 或状态寄存器,则必须连接 MISO 线。

SPI 通信的基本流程如下:

  1. 片选使能: 主机将 CS 引脚拉低,选中目标从机(LCD 控制器)。
  2. 时钟产生: 主机在 SCLK 线上输出连续的时钟脉冲。
  3. 数据移位: 在每个时钟周期,主机通过 MOSI 线发送 1 bit 数据,同时从机通过 MISO 线返回 1 bit 数据(全双工)。
  4. 片选释放: 数据传输完成后,主机将 CS 引脚拉高,结束本次通信。
提示: SPI 没有像 I2C 那样的设备地址机制,完全依靠 CS 线进行设备选择。因此,多个从机共享 SCLK、MOSI、MISO 线时,必须确保同一时刻只有一个 CS 被拉低。
SPI 四线连接与数据流示意图 主机 (MCU) 从机 (LCD 驱动 IC) SCLK MOSI MISO CS 数据流向:MOSI → 从机,MISO → 主机 CS 低电平有效,选中从机

2.2 时钟极性(CPOL)与时钟相位(CPHA)

SPI 协议的灵活性体现在时钟配置上。通过组合 CPOL(Clock Polarity,时钟极性)和 CPHA(Clock Phase,时钟相位),可以定义四种不同的工作模式。主从双方必须使用相同的模式才能正常通信。

2.2.1 CPOL:时钟极性

CPOL 决定 SCLK 在空闲状态(无数据传输时)的电平:

  • CPOL = 0: 空闲时 SCLK 为低电平(0)。
  • CPOL = 1: 空闲时 SCLK 为高电平(1)。

2.2.2 CPHA:时钟相位

CPHA 决定数据采样发生在 SCLK 的哪个边沿:

  • CPHA = 0: 在 SCLK 的第一个边沿(上升沿或下降沿)采样数据。
  • CPHA = 1: 在 SCLK 的第二个边沿采样数据。
常见误区: 初学者常将 CPOL 和 CPHA 混淆。记住:CPOL 只决定空闲电平,CPHA 决定采样边沿。两者独立配置,组合出四种模式。

2.2.3 四种 SPI 模式对照表

SPI 模式 CPOL CPHA 空闲时钟电平 数据采样边沿 数据输出边沿
模式 0 0 0 低电平 上升沿(第一个边沿) 下降沿
模式 1 0 1 低电平 下降沿(第二个边沿) 上升沿
模式 2 1 0 高电平 下降沿(第一个边沿) 上升沿
模式 3 1 1 高电平 上升沿(第二个边沿) 下降沿
LCD 驱动经验: 绝大多数 LCD TFT 驱动 IC(如 ILI9341、ST7789、ST7735)默认使用 SPI 模式 0(CPOL=0, CPHA=0) 或 模式 3(CPOL=1, CPHA=1)。这两种模式的数据采样边沿都是上升沿,区别仅在于空闲电平。实际调试时,建议先从模式 0 开始尝试。
四种 SPI 模式时序对比图 模式 0 (CPOL=0, CPHA=0) SCLK 采样↑ 采样↑ 采样↑ 模式 1 (CPOL=0, CPHA=1) SCLK 采样↓ 采样↓ 采样↓ 模式 2 (CPOL=1, CPHA=0) SCLK 采样↓ 采样↓ 采样↓ 模式 3 (CPOL=1, CPHA=1) SCLK 采样↑ 采样↑ 采样↑

2.3 实际配置示例(STM32 HAL 库)

以下代码展示如何在 STM32 平台上使用 HAL 库配置 SPI 接口为模式 0,驱动 LCD 屏幕:

// SPI 句柄定义
SPI_HandleTypeDef hspi1;

// SPI 初始化函数
void MX_SPI1_Init(void)
{
    hspi1.Instance = SPI1;
    hspi1.Init.Mode = SPI_MODE_MASTER;          // 主机模式
    hspi1.Init.Direction = SPI_DIRECTION_2LINES; // 全双工
    hspi1.Init.DataSize = SPI_DATASIZE_8BIT;     // 8 位数据
    hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;   // CPOL = 0
    hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;       // CPHA = 0
    hspi1.Init.NSS = SPI_NSS_SOFT;               // 软件控制 CS
    hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4; // 时钟分频
    hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;      // 高位先行
    hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
    hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
    hspi1.Init.CRCPolynomial = 10;

    if (HAL_SPI_Init(&hspi1) != HAL_OK)
    {
        Error_Handler(); // 初始化失败处理
    }
}

// 发送一字节数据(CS 由外部 GPIO 控制)
void LCD_WriteByte(uint8_t data)
{
    HAL_GPIO_WritePin(LCD_CS_GPIO_Port, LCD_CS_Pin, GPIO_PIN_RESET); // CS 拉低
    HAL_SPI_Transmit(&hspi1, &data, 1, HAL_MAX_DELAY);              // 发送数据
    HAL_GPIO_WritePin(LCD_CS_GPIO_Port, LCD_CS_Pin, GPIO_PIN_SET);   // CS 拉高
}
调试建议: 如果 LCD 屏幕无显示或显示异常,首先使用逻辑分析仪或示波器抓取 SCLK 和 MOSI 波形,确认时钟极性、相位以及数据位顺序是否正确。这是排查 SPI 通信问题最有效的方法。