资讯中心

1.54英寸LCD模块驱动全解析:从SPI接口到STM32 DMA优化实践

📅 2026/8/1 15:43:27
1.54英寸LCD模块驱动全解析:从SPI接口到STM32 DMA优化实践
1. 项目概述1.54英寸LCD模块的入门与核心价值如果你正在寻找一款小巧、低功耗且易于驱动的显示方案那么1.54英寸的LCD模块绝对值得你花时间研究。这类模块通常指的是对角线为1.54英寸的液晶显示屏搭配了必要的驱动电路和接口封装成一个可以直接与微控制器比如我们熟悉的STM32、ESP32或者Arduino连接的独立组件。它不像手机屏幕那样需要复杂的时序控制器其核心往往是一颗集成了显存和驱动逻辑的芯片我们通过简单的SPI或I2C总线发送命令和数据就能控制屏幕上每一个像素的亮灭。为什么是1.54英寸这个尺寸在嵌入式领域是一个“甜点”尺寸。它足够大可以清晰地显示几行文字、简单的图标或波形比如在便携式设备上显示心率、温度、或者作为小型仪表的界面同时又足够小功耗极低非常适合电池供电的物联网设备、可穿戴设备如智能手环的早期屏幕方案或者各种需要紧凑设计的工控仪表。我最初接触它是在一个智能家居的温湿度监测终端项目上需要一块常亮显示但耗电不能太大的屏幕1.54寸的LCD模块就成了不二之选。它的核心价值在于为资源有限的嵌入式系统提供了一个“即插即用”的图形化人机交互窗口极大地降低了开发门槛。2. 模块核心解析从玻璃到像素的驱动之旅要玩转一块LCD模块不能只停留在调用库函数的层面。理解其内部构造和工作原理是后续解决各种稀奇古怪显示问题的关键。一块典型的1.54英寸LCD模块可以拆解为三个核心部分液晶玻璃面板、驱动芯片以及外围电路。2.1 液晶面板与驱动芯片的协同液晶面板本身是被动的它需要驱动芯片来“指挥”。对于1.54英寸这类小尺寸模块常用的驱动芯片有ST7789、ST7735S、ILI9341虽然更常见于稍大尺寸但也有变种以及国产的JD79653A常用于电子纸但原理相通等。以ST7789为例它内部集成了显存GRAM我们通过SPI接口写入的数据实际上就是填充到了这片GRAM中。驱动芯片会按照设定的扫描方式持续地从GRAM中读取数据转换成对应的电压施加到液晶面板的电极上从而控制每个像素的透光率。这里有一个关键概念像素格式。我们常说的RGB565、RGB888指的是一个像素点在GRAM中所占的位数。RGB565用16位2字节表示一个像素其中红色占5位绿色占6位蓝色占5位。这是嵌入式领域最常用的格式因为在色彩丰富度和内存占用之间取得了很好的平衡。当你通过LCD_DrawPoint(x, y, COLOR_RED)这样的函数画一个红点时底层操作就是将代表红色的RGB565数值例如0xF800写入到GRAM中(x, y)坐标对应的内存位置。注意驱动芯片的GRAM起始坐标原点和扫描方向是可以配置的。有些模块默认是竖屏模式原点在左上角有些则是横屏。如果你发现图片显示方向不对或者镜像了不要慌这通常不是硬件问题而是需要通过发送命令如ST7789的MADCTL命令来设置内存访问控制寄存器调整扫描方向。2.2 接口选择SPI与I2C的权衡1.54英寸模块的接口以SPI为主部分极简的单色屏可能会使用I2C。SPI是首选原因在于其高速性。显示一幅图片需要传输大量数据SPI的全双工和高速特性通常可以跑到几十MHz能显著缩短刷新时间避免肉眼可见的刷屏延迟。一个标准的四线SPI接口包含SCK时钟线由主机MCU产生。MOSI主机输出从机输入用于发送命令和数据。DC或常写作RS/A0数据/命令选择线。这是LCD驱动特有的关键引脚。当DC置为低电平时MOSI上传送的是命令字节如设置显示区域、睡眠模式当DC置为高电平时传送的是像素数据。这个引脚的存在使得驱动芯片能区分你发来的是指令还是真要显示的内容。CS片选线低电平有效。当总线上挂载多个SPI设备时用于选择当前通信的LCD模块。有些模块为了节省引脚会使用“模拟SPI”即用MCU的任意GPIO口模拟SCK和MOSI的时序这在MCU硬件SPI资源紧张时是可行的但速度会慢很多刷屏体验大打折扣。我的经验是只要硬件SPI有空闲务必使用硬件SPI并开启DMA直接存储器访问这是实现流畅显示尤其是动态波形或动画的基石。后文会详细探讨STM32H750的SPI DMA驱动中遇到的典型问题。3. 硬件连接与初始化让屏幕亮起来的第一步拿到模块后第一件事就是正确接线和进行初始化序列配置。这一步看似基础却决定了屏幕能否正常工作。3.1 引脚定义与电源管理通常1.54英寸LCD模块会有一个排针接口引脚定义大同小异。你需要仔细查阅卖家提供的资料或驱动芯片的数据手册。一个典型的引脚列表如下引脚标号名称功能连接说明1VCC电源正极接3.3V切勿接5V多数芯片是3.3V逻辑电平。2GND电源地接系统地。3SCKSPI时钟接MCU的SPI_SCK引脚。4MOSI (SDA)SPI数据输入接MCU的SPI_MOSI引脚。5DC (RS/A0)数据/命令选择接MCU任意GPIO用于区分命令/数据。6CS片选接MCU任意GPIO初始化后通常可一直拉低如果只接一个SPI设备。7RST复位接MCU任意GPIO用于硬件复位。8BLK (LED)背光控制接MCU PWM引脚或通过三极管控制用于调节亮度。实操心得RST引脚非常重要。很多初始化失败的问题可以通过一个可靠的复位序列解决。正确的做法是上电后先将RST拉低至少10ms然后拉高等待至少120ms后再开始发送初始化命令。这个延时给驱动芯片的内部振荡器和电路足够的稳定时间。我曾因为省略了这个延时导致屏幕初始化随机性失败调试了很久。3.2 初始化序列与驱动芯片的第一次对话初始化序列是一系列预先定义好的命令和参数用于配置驱动芯片的工作模式。包括设置像素格式、扫描方向、伽马校正、打开显示等。这些序列通常可以在驱动芯片的数据手册中找到或者使用卖家提供的示例代码。以ST7789为例一个简化的初始化流程如下执行硬件复位操作RST引脚。发送SWRESET软件复位命令。延时等待。发送SLPOUT退出睡眠模式命令。发送COLMOD设置接口像素格式命令参数设为0x55代表RGB565。发送MADCTL设置显示方向命令参数例如0x00为竖屏。发送DISPON打开显示命令。这些命令和数据的发送依赖于你编写的底层LCD_Write_Cmd和LCD_Write_Data函数。这两个函数的核心就是操作DC引脚和SPI总线。// 示例向LCD写入一个命令 void LCD_Write_Cmd(uint8_t cmd) { LCD_DC_LOW(); // DC置低表示接下来是命令 HAL_SPI_Transmit(hspi1, cmd, 1, HAL_MAX_DELAY); } // 示例向LCD写入一个数据参数或像素数据 void LCD_Write_Data(uint8_t data) { LCD_DC_HIGH(); // DC置高表示接下来是数据 HAL_SPI_Transmit(hspi1, data, 1, HAL_MAX_DELAY); } // 初始化序列中的一部分 LCD_Write_Cmd(0x36); // MADCTL命令 LCD_Write_Data(0x00); // 参数设置扫描方向4. 核心驱动策略STM32的SPI与DMA高效应用当你能在屏幕上画出一个静态的点或线后下一步就是追求效率如何快速填充整个屏幕或者绘制复杂的图形、显示图片。这时SPIDMA的组合就闪亮登场了。4.1 为何需要DMA如果不使用DMA每次调用HAL_SPI_Transmit发送一个像素2字节CPU都需要参与其中准备数据、启动传输、等待传输完成中断。绘制一个240x240的屏幕1.54寸常见分辨率需要发送115200字节这意味着CPU会被占用115200次期间几乎无法处理其他任务造成系统卡顿。DMA直接存储器访问就像一个“数据搬运工”。你只需要告诉它源地址存放像素数据的数组、目标地址SPI数据寄存器、以及数据量它就会在后台自动完成搬运而CPU在此期间可以自由地执行其他代码比如处理传感器数据、运行用户逻辑。传输完成后DMA会产生一个中断通知CPU。4.2 STM32H750驱动SPI LCD的典型问题与解决STM32H750性能强大但其SPI和DMA的配置也更为复杂。根据网络上的常见反馈如“stm32h750 dma 驱动 spi lcd 问题”以下几个坑点需要特别注意问题一DMA传输完成中断不触发或数据错位。这可能是DMA流/通道与SPI的映射关系错误导致的。在CubeMX中配置时必须确保为SPI的TX发送选择正确的DMA流和通道。例如对于SPI1的TX通常需要选择DMA2的Stream3或Stream5通道为CHANNEL_3。务必查阅STM32H750的参考手册中的DMA请求映射表。问题二屏幕显示花屏、错乱或局部更新异常。这往往与内存管理有关。STM32H750有复杂的存储器架构ITCM, DTCM, AXI SRAM, SRAM1/2/3/4等。用于DMA传输的缓冲区像素数组必须位于DMA可以访问的内存区域。默认的局部变量在栈中可能位于DTCM而某些DMA控制器如DMA2可能无法访问DTCM。解决方案使用__attribute__((section(.dma_buffer)))或将数组定义为全局变量并确保其链接到AXI SRAM或SRAM1/2/3/4。可以在CubeMX的Project Manager - Linker Settings中指定特定变量到特定内存段或者在代码中使用__attribute__((at(0x24000000)))指定到AXI SRAM的地址。问题三SPI时钟速度上不去导致刷屏慢。检查以下几点GPIO速度将SPI相关引脚SCK, MOSI的GPIO速度设置为“Very High”。SPI分频确保SPI的时钟分频系数设置正确。H750的APB总线时钟很高可以尝试PCLK/4或PCLK/2。SPI模式必须是模式0CPOL0 CPHA0或模式3CPOL1 CPHA1具体需查阅LCD驱动芯片手册。ST7789通常用模式0。硬件连接过长的飞线会引起信号完整性问题导致高速下通信失败。尽量使用短而粗的连线。问题四使用DMA双缓冲模式时切换缓冲区时机不当导致撕裂Tearing效应。双缓冲是高级技巧用于实现无撕裂动画。原理是准备两个显存缓冲区Frame BufferDMA正在从缓冲区A读取数据发送时CPU向缓冲区B绘制下一帧。完成后切换DMA的目标地址到缓冲区B。关键点切换缓冲区的操作必须在上一帧DMA传输完成中断中进行并且要重新配置DMA的存储器地址和数据量。不能在传输过程中随意切换否则必然花屏。// 简化的DMA传输完成中断处理思路 uint16_t frame_buffer[2][SCREEN_WIDTH * SCREEN_HEIGHT]; // 双缓冲 volatile uint8_t active_buffer 0; void SPI_Tx_DMA_Complete_Callback(SPI_HandleTypeDef *hspi) { // 传输完成切换缓冲区 active_buffer 1 - active_buffer; // 0-1, 1-0 // 重新配置DMA指向新的活跃缓冲区 HAL_SPI_DMAStop(hspi1); // ... 重新关联DMA到 frame_buffer[active_buffer] ... HAL_SPI_Transmit_DMA(hspi1, (uint8_t*)frame_buffer[active_buffer], BUFFER_SIZE); // 通知主循环可以在非活跃缓冲区刚刚画完的那个绘制下一帧了 frame_ready_flag 1; }5. 图形库与高级功能实现有了稳定的底层驱动我们就可以在其上构建更丰富的图形功能。你可以选择移植成熟的嵌入式图形库如LVGL、uGFX、STemWin也可以自己实现一些基本功能。5.1 基础绘图函数实现自己实现绘图函数有助于深入理解显存操作。核心是LCD_DrawPixel函数所有高级图形线、矩形、圆、图片都基于它。// 设置显示窗口告诉驱动芯片接下来要写入的像素区域 void LCD_SetWindow(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2) { LCD_Write_Cmd(0x2A); // 列地址设置命令 LCD_Write_Data(x1 8); LCD_Write_Data(x1 0xFF); LCD_Write_Data(x2 8); LCD_Write_Data(x2 0xFF); LCD_Write_Cmd(0x2B); // 行地址设置命令 LCD_Write_Data(y1 8); LCD_Write_Data(y1 0xFF); LCD_Write_Data(y2 8); LCD_Write_Data(y2 0xFF); LCD_Write_Cmd(0x2C); // 存储器写命令此后发送的都是像素数据 } // 画点函数 void LCD_DrawPixel(uint16_t x, uint16_t y, uint16_t color) { if(x LCD_WIDTH || y LCD_HEIGHT) return; // 边界检查 LCD_SetWindow(x, y, x, y); LCD_Write_Data(color 8); // 先发送高字节RGB565格式 LCD_Write_Data(color 0xFF); // 再发送低字节 }基于DrawPixel你可以实现画线Bresenham算法、画矩形填充、画圆等函数。但要注意逐点绘制效率很低。更高效的方式是使用SetWindow设置一个区域然后通过DMA连续发送整个区域的像素数据数组。5.2 显示图片与中文字库显示图片需要先将图片文件如BMP、JPG转换成C语言数组。有很多在线工具如LCD Image Converter或离线软件如Img2Lcd可以完成这个工作并生成RGB565格式的数组。显示图片的关键步骤将图片数组存放在MCU的Flash或外部存储器中。使用LCD_SetWindow设置图片要显示的区域。将图片数组的数据通过SPI最好用DMA连续发送出去。显示中文则涉及字库。通常需要获取点阵字库如16x16 24x24同样将其转换为数组。显示一个汉字时根据其内码计算出在字库数组中的位置然后按位读取点阵信息在屏幕上相应的位置画点。避坑技巧如果图片或文字显示颜色错误比如红蓝对调这很可能是字节序Endian问题。RGB565数据在内存中的存储顺序高字节在前还是低字节在前需要与驱动芯片的读取顺序匹配。有些芯片需要[R4-R0, G5-G3]和[G2-G0, B4-B0]分两个字节发送而你的数组可能是[B4-B0, G2-G0]和[G5-G3, R4-R0]。遇到颜色不对尝试交换发送的两个字节的顺序或者修改图片转换工具的输出格式。6. 实战优化与电源管理在实际项目中除了显示功能功耗和稳定性同样重要。6.1 降低功耗的策略动态背光控制背光LED通常是最大的耗电源。如果你的应用场景环境光变化大可以添加光敏传感器根据环境亮度动态调节背光的PWM占空比甚至关闭背光。利用睡眠模式当屏幕不需要更新时可以发送命令让驱动芯片进入睡眠模式SLPIN。在此模式下芯片内部大部分电路关闭功耗可降至微安级。需要显示时再发送SLPOUT唤醒。注意进入睡眠前最好先清屏或保留当前显示内容因为唤醒后GRAM数据可能保持也可能丢失需查阅芯片手册。减少全屏刷新只刷新需要更新的区域而不是整个屏幕。这需要你的图形库或应用逻辑支持局部更新。6.2 提高刷新率与流畅度极限优化SPI时钟在保证信号完整性的前提下尽可能提高SPI时钟频率。使用硬件加速如果MCU有LCD-TFT控制器如STM32F429/769那将是另一个层面的性能飞跃可以直接驱动RGB接口屏幕。但对于SPI接口的1.54寸屏我们只能优化SPI和DMA。避免频繁设置窗口SetWindow命令本身也有开销。如果连续绘制多个相邻元素尽量合并到一个窗口设置内进行数据发送。7. 常见问题排查速查表在开发过程中你一定会遇到各种显示问题。下面这个表格整理了我踩过的一些坑和解决方法问题现象可能原因排查步骤与解决方案屏幕白屏背光亮1. 初始化序列错误或缺失。2. 电源电压不对接了5V。3. 复位时序不正确。1. 用逻辑分析仪或示波器抓取SPI波形核对初始化命令序列是否与数据手册一致。2. 确认VCC接3.3V。3. 确保复位引脚有正确的低电平脉冲10ms并留有足够的上电延时(120ms)。屏幕花屏显示乱码1. SPI模式CPOL/CPHA设置错误。2. 像素数据格式RGB565顺序错误。3. DMA内存地址错误或缓冲区溢出。4. 扫描方向MADCTL设置与绘图坐标逻辑不匹配。1. 确认驱动芯片要求的SPI模式通常是Mode 0。2. 尝试交换发送像素数据的高低字节顺序。3. 检查DMA传输缓冲区地址和大小确保其在有效内存区域且未越界。4. 调整MADCTL参数并同步修改绘图函数中的坐标映射逻辑。显示内容镜像或旋转内存访问控制MADCTL寄存器设置错误。查阅芯片手册修改MADCTL命令的参数调整X/Y镜像和扫描方向。刷屏速度慢有肉眼可见的扫描线1. SPI时钟频率太低。2. 使用模拟SPI或未启用DMA。3. 绘图算法效率低如用画点函数画矩形。1. 提高SPI波特率分频比。2. 换用硬件SPI并启用DMA传输。3. 对于矩形填充等操作使用设置窗口后连续送数据的方式。局部显示正常大面积刷新时错乱DMA传输过程中源数据被修改CPU与DMA访问冲突。确保DMA传输期间CPU不会去修改正在被DMA读取的缓冲区。可以使用双缓冲机制或确保DMA传输完成中断后再更新下一帧数据。屏幕有残影或拖尾1. 液晶响应时间较慢尤其是低端TN屏。2. 刷新率过高液晶分子来不及响应。1. 这是硬件特性难以完全消除。避免快速变化的动态内容。2. 适当降低刷新频率或在帧之间增加微小延时。背光无法调节或关闭背光控制电路接法错误。确认BLK引脚是PWM驱动还是简单的开关控制。如果是PWM检查PWM输出是否正常如果是开关检查GPIO输出电平。调试LCD一个逻辑分析仪是极其有用的工具它可以非侵入式地捕获SPI总线上的所有命令和数据让你清晰地看到初始化序列是否正确、像素数据是否按预期发送是定位通信问题的利器。最后驱动一块LCD模块就像和它进行一场精细的对话。从正确的硬件连接到精准的时序控制从高效的DMA搬运到上层图形的构建每一步都需要耐心和细致。当你的代码最终让屏幕亮起并稳定地显示出预期的图像时那种成就感是实实在在的。希望这些从实际项目中总结出的经验和坑点能帮助你更顺畅地驾驭手中的这块1.54英寸小世界。