ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

STM32驱动ST7567型12864 LCD的SPI时序与初始化详解

2026/9/13 9:33:10 拓冰建站 浏览量
STM32驱动ST7567型12864 LCD的SPI时序与初始化详解 简介本资源是面向嵌入式开发初学者与STM32项目实践者的ST7567驱动解决方案专为驱动128×64点阵单色LCDLCD12864设计解决在无专用LCD库或硬件SPI受限场景下的显示控制难题。压缩包仅含2个核心文件C语言实现的LcdDriver.c封装初始化、指令/数据写入、屏幕刷新等关键函数和配套头文件LcdDriver.h定义寄存器地址、命令宏及接口声明总大小11KB轻量易集成。已有307人学习下载适用于STM32平台同时兼容标准SPI与软件模拟SPI——后者特别适配引脚资源紧张或无硬件SPI外设的MCU型号。读者可直接移植至Keil/STM32CubeIDE工程结合ST7567控制器时序手册快速完成显示适配代码结构清晰、注释完整便于理解SPI通信机制、LCD底层驱动逻辑及图形显示原理是嵌入式GUI入门与硬件接口实战的实用参考。1. 用 STM32 驱动 12864 LCDST7567 控制器SPI 协议不是“接上就能亮”时序、片选、初始化序列缺一不可你手头有一块常见的 12864 图形点阵液晶屏背面丝印写着 ST7567引脚标着 VDD、VSS、CS、RS、SCLK、SDA —— 这不是一块能靠“写几个 GPIO 拉高拉低”就点亮的模块。它依赖严格的 SPI 通信协议且 ST7567 的初始化流程包含至少 12 条寄存器写入指令顺序错一条屏幕就黑屏或显示乱码。很多工程师在 CubeMX 里配好 SPI 外设、生成 HAL 代码后仍无法驱动问题往往出在CS片选信号未按 ST7567 数据手册要求在每个字节传输前后精确置低/置高SPI 模式被误设为 Mode 0 而非必需的 Mode 3CPOL1, CPHA0或未在初始化前执行关键的“电子复位”即拉低 RES 引脚 10ms 以上。本文面向已掌握 STM32 基础外设但卡在 LCD 驱动环节的嵌入式开发者不讲抽象协议只拆解从硬件连接到首帧图像渲染的完整链路覆盖 cubemx spi 配置陷阱、ST7567 初始化参数表、SPI 硬件片选与软件片选的实际取舍以及如何用逻辑分析仪验证 spi 时序是否达标。2. ST7567 控制器与 12864 LCD 的硬件绑定关系及 SPI 接口选型依据2.1 为什么必须是 ST7567它和常见 SSD1306/OLED 的根本差异12864 LCD 是一种 128×64 像素的单色图形液晶模组其核心控制器型号直接决定驱动方式。ST7567 是 Epson 推出的 COGChip-on-Glass型 LCD 控制器专为段码/点阵 LCD 设计支持 1/65 偏压、内置 64×128 显存、提供 8-bit 并行与 4-wire SPI 两种接口。它与 SSD1306OLED、ST7735TFT存在本质区别ST7567 不支持自动地址递增需手动更新 RAM 地址指针无硬件滚动功能且所有命令/数据均需通过“指令模式”与“数据模式”切换发送——这正是 RSRegister Select引脚存在的意义。若误用 SSD1306 的驱动代码加载到 ST7567 屏上最典型现象是全屏白块或垂直条纹因为显存映射方式page/column 寻址 vs. x/y 坐标寻址完全不同。网络热词中频繁出现的 “spi协议” 在此处具象化为ST7567 要求 SCLK 在空闲时为高电平CPOL1数据在 SCLK 下降沿采样CPHA0即 SPI Mode 3而多数默认配置为 Mode 0这是导致通信失败的第一高频原因。2.2 STM32 端 SPI 外设选型硬件片选NSSvs 软件控制 GPIOST7567 的 CSChip Select引脚功能是使能当前设备参与 SPI 总线通信。STM32 提供两种控制方式硬件 NSS由 SPI 外设自动管理需将 CS 连接到对应 SPI 的 NSS 引脚如 SPI1_NSS并在 CubeMX 中启用NSS Hardware。优点是时序精准、释放 CPU缺点是仅限固定引脚且部分 STM32 型号如 F103C8T6的 SPI1_NSS 与 SWDIO 冲突调试时易被占用。软件 GPIO 片选推荐用于 12864将 CS 连接到任意 GPIO如 PB0初始化时设为推挽输出并置高每次传输前拉低、传输后拉高。优势在于引脚自由、可精确控制 CS 电平宽度ST7567 要求 CS 低电平持续时间 ≥ 100ns且在 SCLK 边沿前后需稳定便于适配多设备共用 SPI 总线场景。提示ST7567 数据手册明确要求“CS must be low during data transfer and high otherwise”。若使用硬件 NSS需确认 CubeMX 生成的HAL_SPI_Transmit()是否在函数入口/出口自动操作 NSSHAL 库默认行为是不自动管理 NSS即使配置为 Hardware必须手动调用HAL_SPI_EnableNss()或在SPI_HandleTypeDef中设置Init.NSS SPI_NSS_SOFT并全程用 GPIO 控制。2.3 关键引脚连接与电平匹配验证ST7567 引脚STM32 引脚示例功能说明注意事项VDD3.3V电源必须 3.3V5V 会击穿VSSGND地共地避免噪声CSPB0GPIO 输出片选上电默认高电平RSPB1GPIO 输出寄存器/数据选择指令RS0数据RS1SCLKPA5SPI1_SCKSPI 时钟频率 ≤ 10MHzST7567 最大支持SDAMOSIPA7SPI1_MOSI主机输出无需 MISOST7567 为单向写入RESPB10GPIO 输出复位上电后需拉低 ≥10ms再拉高实际布线中SCLK 与 SDA 走线长度应尽量相等远离高频干扰源如开关电源、电机驱动。若使用长排线连接建议在 SDA 和 SCLK 线上各串接 33Ω 电阻抑制振铃——这是排查“偶发乱码”的关键物理层措施。3. CubeMX 配置与 HAL 库驱动代码实现绕过初始化陷阱的最小可行路径3.1 CubeMX 中 SPI1 的精确配置步骤以 STM32F103C8T6 为例开启 SPI1在 Connectivity → SPI1 中勾选Mode 选择Full-Duplex Master参数设置Prescaler设为2对应 APB2 时钟 36MHz → SCLK 18MHz但 ST7567 实际用 4MHz 更稳妥Data Size8 BitsClock Polarity (CPOL)High即 CPOL1Clock Phase (CPHA)1 Edge即 CPHA0注意 HAL 库文档中 1 Edge 对应下降沿采样NSS SignalSoftware强制禁用硬件 NSSBaud Rate Prescaler8最终 SCLK 36MHz / 8 4.5MHz在 ST7567 的 10MHz 范围内且留有余量GPIO 分配PA5 → SPI1_SCKAlternate Function Push-PullPA7 → SPI1_MOSIAlternate Function Push-PullPB0 → CSGPIO Output Push-PullInitial State HighPB1 → RSGPIO Output Push-PullInitial State HighPB10 → RESGPIO Output Push-PullInitial State High生成代码勾选Generate peripheral initialization as a pair of .c/.h files点击 Generate。注意CubeMX 生成的MX_SPI1_Init()函数中hi2s1.Init.NSS默认为SPI_NSS_HARD必须手动改为SPI_NSS_SOFT否则 HAL 库会尝试控制硬件 NSS 引脚导致 CS 电平失控。3.2 ST7567 初始化序列12 条指令的执行逻辑与参数表ST7567 上电后需执行严格顺序的初始化指令任何跳过或颠倒都将导致显存未就绪。以下为最小必要序列基于官方 datasheet Rev.1.1步骤指令字节Hex参数字节Hex功能说明关键约束10xE2—软件复位必须第一条RES 硬复位后仍需此指令20xA2—设置偏压比为 1/9若为 1/7 则对比度异常30xA0—设置 SEG 方向正常0xA1为镜像40xC0—设置 COM 方向正常0xC8为镜像50x40—设置起始行0~63通常为0x40第 0 行60x280x00设置放大倍率1x0x012x,0x023x70x2C—退出放大模式必须紧跟0x28后执行80x26—设置 V5 电压调节启用内部电阻分压90x810x20设置电子音量0x00~0x3F0x20为中等亮度100xAF—开启显示屏幕在此步后才可能亮起110xB0—设置页地址Page 0后续写入从 Page 0 开始120x10—设置列地址高位Column 0与0x00组合为列 0// st7567_init.c - 初始化函数需在 HAL_SPI_MspInit() 后调用 void ST7567_Init(void) { // 1. 硬件复位拉低 RES 10ms HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_RESET); HAL_Delay(10); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_SET); // 2. 发送初始化序列 uint8_t init_cmds[] {0xE2, 0xA2, 0xA0, 0xC0, 0x40, 0x28, 0x2C, 0x26, 0x81, 0xAF, 0xB0, 0x10}; uint8_t init_params[] {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00}; for (int i 0; i 12; i) { HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET); // CS low HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_RESET); // RS 0 (command) HAL_SPI_Transmit(hspi1, init_cmds[i], 1, HAL_MAX_DELAY); if (init_params[i] ! 0x00) { HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_SET); // RS 1 (data) HAL_SPI_Transmit(hspi1, init_params[i], 1, HAL_MAX_DELAY); } HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET); // CS high HAL_Delay(1); // 每条指令间加 1ms 延时确保控制器响应 } }代码逻辑说明HAL_GPIO_WritePin()控制 CS 和 RS确保每条指令前 CS 拉低、RS 根据指令/数据切换HAL_SPI_Transmit()发送单字节因 ST7567 的 SPI 接口为 4-wire 模式无 MISO无需接收HAL_Delay(1)是安全冗余ST7567 内部指令执行时间最长为 100μs1ms 可覆盖所有情况参数0x81后必须跟0x20否则电子音量为 0屏幕全黑这是新手最常忽略的坑。3.3 绘制单个像素显存地址计算与逐页写入机制ST7567 的显存为 64×128 bit按“页Page”组织每页 8 行0~7共 8 页Page 0~7每页含 128 字节对应 128 列。要点亮坐标 (x, y) 的像素需计算页号page y / 8计算页内行偏移bit_pos y % 8计算字节地址byte_index x构造掩码mask 1 bit_pos读-改-写读出当前字节置位对应 bit写回。但 ST7567不支持随机读取显存无 MISO 引脚因此实际采用“全页擦写”策略先发送0xB0 page设置页地址再发送0x10 (x4)设置列高位0x00 (x0x0F)设置列低位然后连续发送 128 字节数据。以下为绘制单点的简化版假设已清屏// 绘制点 (x, y)x∈[0,127], y∈[0,63] void ST7567_DrawPixel(uint8_t x, uint8_t y) { uint8_t page y / 8; uint8_t bit y % 8; uint8_t mask 1 bit; // 设置页地址 HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_RESET); uint8_t cmd_page 0xB0 | page; HAL_SPI_Transmit(hspi1, cmd_page, 1, HAL_MAX_DELAY); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET); // 设置列地址高位低位 HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_RESET); uint8_t cmd_col_h 0x10 | (x 4); HAL_SPI_Transmit(hspi1, cmd_col_h, 1, HAL_MAX_DELAY); uint8_t cmd_col_l x 0x0F; HAL_SPI_Transmit(hspi1, cmd_col_l, 1, HAL_MAX_DELAY); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET); // 发送 128 字节数据仅第 x 字节置位 HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_SET); uint8_t buffer[128] {0}; buffer[x] | mask; HAL_SPI_Transmit(hspi1, buffer, 128, HAL_MAX_DELAY); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET); }参数说明cmd_page0xB0是页地址设置指令| page将页号嵌入低 3 位cmd_col_h/l列地址分高低 4 位发送0x10为高位指令0x00为低位指令buffer[x] | mask构造单点数据其余字节为 0实现“点亮一个像素”此函数效率低每次写 128 字节实际应用中应维护本地显存缓冲区批量修改后再刷屏。4. 调试与验证用逻辑分析仪抓取 SPI 时序定位 CS/RS 电平错误4.1 使用 Saleae Logic 16 抓取真实 SPI 波形的关键设置当屏幕无反应时最高效的方式是用逻辑分析仪验证物理层信号。针对 ST7567 的 SPI 通信需捕获四路信号SCLK、MOSI、CS、RS。设置要点如下采样率≥ 50MS/s确保能解析 4.5MHz SCLK 的边沿触发条件设置CS Falling触发因为每次传输始于 CS 下降沿协议解码在 Saleae 软件中添加SPI解码器手动配置Clock polarityActive HighCPOL1Clock phaseSample on FallingCPHA0Bit orderMSB firstCS pin选择 CS 通道观察重点CS 低电平宽度是否 ≥ 100nsSCLK 空闲状态是否为高电平MOSI 数据是否在 SCLK 下降沿稳定即 CPHA0 成立RS 电平是否在每字节传输前正确切换指令前 RS0数据前 RS1。若解码结果显示“Unknown”或数据错乱90% 概率为 CPOL/CPHA 配置错误。此时需返回 CubeMX 修改 SPI 参数并重新生成代码。4.2 常见故障现象与对应排查表现象可能原因验证方法解决方案屏幕全黑无任何反应RES 未正确复位或0xAF开启显示未发送用万用表测 RES 引脚上电后是否经历低→高跳变逻辑分析仪查0xAF是否发出检查 PB10 硬件连接确认初始化序列包含0xAF屏幕全白或灰屏电子音量0x81参数过小如0x00或偏压比0xA2错为0xA3逻辑分析仪查0x81后是否跟0x20查0xA2是否误发0xA3修改 init_params[8] 0x20确保指令为0xA2显示垂直条纹或错位列地址设置错误0x10/0x00未发送或页地址0xB0后未发送数据抓取波形看0xB0后是否有连续 128 字节 MOSI 数据确保ST7567_DrawPixel()中列地址指令完整发送画面闪烁或间歇性消失CS 电平在传输中意外变高或 SCLK 频率超限逻辑分析仪查 CS 在 SCLK 期间是否保持低电平测 SCLK 频率优化 GPIO 控制时序避免中断打断降低 Baud Rate Prescaler4.3 用 STM32CubeIDE 的 SWV ITM 输出实时调试信息在初始化函数中插入 ITM 调试语句可免接逻辑分析仪快速定位卡点// 在 MX_GPIO_Init() 后添加 CoreDebug-DEMCR | CoreDebug_DEMCR_TRCENA_Msk; ITM-LAR 0xC5ACCE55; // 解锁 ITM ITM-TCR | ITM_TCR_ITMENA_Msk; // 使能 ITM ITM-TER[0] | 1; // 使能端口 0 // 在 ST7567_Init() 中每步后添加 ITM_SendChar(1); // 步骤1完成 ITM_SendChar(2); // 步骤2完成 // ...在 STM32CubeIDE 的Console视图中启用SWV ITM Data Console若看到12345...连续输出说明初始化执行到某步中断结合字符停止位置即可精确定位失败指令。5. 进阶技巧构建轻量级显存缓冲区与中文字符渲染5.1 本地显存Frame Buffer设计1KB 内存换取 10 倍刷新效率前述ST7567_DrawPixel()每次操作都写入 128 字节效率极低。实际项目中应申请 1KB 内存作为显存镜像// 定义全局显存缓冲区64×128 bit 1024 bytes uint8_t lcd_buffer[1024] {0}; // 初始化为全 0黑屏 // 更新缓冲区后一次性刷屏 void ST7567_Refresh(void) { for (uint8_t page 0; page 8; page) { HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_RESET); uint8_t cmd_page 0xB0 | page; HAL_SPI_Transmit(hspi1, cmd_page, 1, HAL_MAX_DELAY); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_SET); HAL_SPI_Transmit(hspi1, lcd_buffer[page * 128], 128, HAL_MAX_DELAY); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET); } }优势CPU 修改lcd_buffer无需 SPI 通信ST7567_Refresh()仅在需要时调用适合动画、菜单等场景。5.2 16×16 点阵中文字符渲染GB2312 编码与字模提取12864 屏幕常用于显示中文需处理 GB2312 编码。一个实用技巧是将常用汉字字模16×1632 bytes预存在 Flash 中通过查表渲染// 示例汉字“测”GB2312 区位码 10-21 → 0x2A35 const uint8_t hanzi_cha[32] { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }; // 实际字模需从字库文件提取 // 在 lcd_buffer 中绘制汉字左上角 x,y void ST7567_DrawHanzi(uint8_t x, uint8_t y, const uint8_t *font) { for (uint8_t row 0; row 16; row) { for (uint8_t col 0; col 2; col) { // 每行 2 字节 uint8_t byte font[row * 2 col]; for (uint8_t bit 0; bit 8; bit) { uint8_t px_x x col * 8 bit; uint8_t px_y y row; if (px_x 128 px_y 64) { uint8_t page px_y / 8; uint8_t bit_pos px_y % 8; uint8_t mask 1 bit_pos; if (byte (1 (7 - bit))) { // MSB 在前 lcd_buffer[page * 128 px_x] | mask; } else { lcd_buffer[page * 128 px_x] ~mask; } } } } } }参数说明hanzi_cha是“测”字的 16×16 点阵字模每行 2 字节16 bits共 32 字节ST7567_DrawHanzi()将字模逐位映射到lcd_buffer支持任意坐标byte (1 (7 - bit))处理字模的 MSB 优先存储格式确保笔画方向正确此方法避免了动态编码转换适用于资源受限的 STM32F1 系列。用ST7567_DrawHanzi(10, 10, hanzi_cha)即可在屏幕 (10,10) 位置显示“测”字调用ST7567_Refresh()刷新即可。本文还有配套的精品资源点击获取