简介:本资源是面向嵌入式初学者与51单片机开发者的STC15系列驱动ST7735S彩色TFT液晶屏的完整并口驱动工程,专为解决小尺寸彩屏在资源受限MCU上的高效显示问题而设计,适用于智能仪表、IoT终端、教学实验等低功耗嵌入式场景。压缩包共14个文件,含核心驱动源码(.c)、Keil uVision工程文件(.uvproj/.uvopt)、编译输出(.hex/.obj/.lst)、备份文件(.bak/.plg)及关键说明文档(.docx),其中《程序参考(2019-05-27)》详细梳理了P1口并行接线、时序控制要点、初始化流程与字符取模方法,配套工程可直接编译烧录验证。目前已有856人学习下载,读者可直接获取可运行的STC15W104等型号适配代码、完整的LCD寄存器配置序列、基于端口锁存的稳定写入逻辑,以及兼顾可读性与实时性的模块化函数封装,显著降低ST7735S并口驱动的入门门槛与调试成本。 网上那个“STC15+ST7735 并口驱动.zip”被我翻出来的时候,里面的代码能跑,但注释混乱、接线说明也不全,我自己折腾了一个晚上才把花屏和镜像问题整明白。ST7735这颗芯片大家通常都拿它当“SPI屏幕”用,但它的手册里其实明确支持8080并行接口,只是绝大多数模组默认焊成了SPI模式,没把并口引脚引出来。这篇文章就围绕“STC15用并口驱动ST7735”这条主线,把我在实际调板过程中的接线、时序、初始化、刷屏优化和坑点都整理清楚,给准备在51平台上跑低成本小彩屏的朋友一个可以直接参考的思路。
1. 为什么STC15非要折腾并口:从模拟SPI的挫败说起
1.1 模拟SPI的问题在哪
STC15是1T增强型8051,主频跑在30MHz时,单周期指令速度确实比老51快很多,但它的外设里没有硬件SPI(部分型号有但也不好用),所以大多数例程都用GPIO模拟SPI。模拟SPI本身不复杂:把SCLK拉高拉低、MOSI逐位送数据,一位一位地移。问题在于,刷一屏128x160、RGB565格式的画面总共要传输40960字节,换成位就是327680个bit,每个bit都要消耗好几条IO翻转指令,整屏刷下来时间在几百毫秒级别,做菜单动画或者简单仪表盘都能感觉到明显卡顿。
我之前用模拟SPI驱动同款屏幕,纯色刷新测下来大约180ms一屏,滚动文字时能看到“拖影”一样的刷新过程。不是屏幕响应慢,而是数据通道太窄,SPI一次只能走一位,这是物理层面的事,怎么优化代码都绕不过去。
1.2 并口到底快了多少:算一笔账
8080并行接口(也就是常说的并口)一次写操作可以送8位数据,数据通道宽度是SPI的8倍。同样在30MHz主频下,假设模拟SPI每传输1bit需要1微秒,传输40960字节就是4096081us≈328ms。改用并口后,写一个字节还是大约1微秒,传输40960字节就是约41ms,差距接近8倍。
实际测下来没有这么理想,因为并口还要处理RS、WR、CS等控制引脚时序,总耗时大约在50ms到70ms之间,但相比模拟SPI已经是质的提升。对于STC15这种不带硬件DMA、内存又小的平台,并口是榨干性能最直接的办法。
1.3 ST7735 自己就支持并口,别被“SPI屏”三个字唬住
ST7735是Sitronix(矽创)出品的TFT-LCD控制器,它的接口方式非常丰富:4线SPI、3线SPI、8080并行、6800并行都可以,具体工作在哪种模式由IM3、IM2、IM1、IM0这四个引脚的上拉/下拉决定。市面上的小尺寸模组为了节省引脚,通常出厂固定为4线SPI模式,只引出SCLK、MOSI、CS、DC、RST这几个信号。但也有部分模组在设计时把并行数据线D0-D7都引出来了,或者通过板上的0欧电阻可以切换接口模式。
标题里那个“4HW5”字样我猜测是模组丝印或版本号,代表这个模组确实支持并口版本。所以拿到一个ST7735模组,不能默认它就是SPI,先看丝印和引脚定义,如果看到了D0-D7、WR、RD这些引脚,说明这就是为并口设计的板子,用SPI去驱动反而浪费。
2. 硬件接线与接口模式配置:决定你能不能点亮的第一道坎
2.1 你的模组到底支持不支持并口
并口驱动的前提是硬件上支持且已经配置为并口模式。很多模块的IM引脚是固定的,没有引出,或者被板载电阻拉成了SPI模式。这种情况不能硬来,要么飞线改电阻位置,要么老老实实继续用SPI。
判断方法很简单:
- 看模组背面丝印,是否有D0-D7、WR、RD、RS、CS等引脚编号。
- 看原理图(如果卖家提供),确认IM0-IM3的电阻配置。
- 如果模组标称“SPI接口”但没有D0-D7,那就不要指望并口了。
如果模组支持并口,还要看IM引脚有没有引出来。有的模组把IM配置电阻做成了可跳线形式,方便切换;有的是焊死的,需要动烙铁。我手上这块板子是在背面留了三个0欧电阻位,把其中一个从A位置挪到B位置就切到了8080模式,不算太麻烦。
2.2 8080并口接线表与STC15引脚分配
8080并口模式下,需要用到CS(片选)、RS(也叫DC,命令/数据选择)、WR(写使能)、RD(读使能)、RESET(复位),以及D0-D7这8根数据线。如果是只写不读,RD可以固定接高电平或者直接不接。
下面是常用接线参考,STC15引脚可以按你手头板子的实际情况调整,但建议把数据线接到同一组IO上,方便一次性赋值:
| ST7735信号 | STC15引脚 | 说明 |
|---|---|---|
| D0-D7 | P0.0-P0.7 | 数据总线,尽量整组接入 |
| RS (DC) | P2.0 | 0=命令,1=数据 |
| WR | P2.1 | 写信号,上升沿锁存数据 |
| RD | 接VCC | 只写不读时悬空或接高 |
| CS | P2.2 | 片选,低有效,可一直拉低 |
| RESET | P2.3 | 复位,低有效,上电后拉高 |
| VCC | 3.3V | 逻辑电源 |
| GND | GND | 共地 |
| LED+ | 3.3V或PWM | 背光正极,可串电阻或接PWM引脚 |
| LED- | GND | 背光负极 |
把数据线放在P0口是最省心的方案,KEIL C51里直接给P0赋值就可以一次送出整个字节,比逐位操作快得多。控制线放在P2口,用sbit定义,代码可读性也好。
2.3 电平、供电、复位这些容易被忽略的细节
ST7735的逻辑电压一般在1.8V到3.3V之间,很多模组板载了3.3V LDO,所以从5V供电也可以运行。但数据引脚如果不做电平转换直接接5V单片机,长期运行有烧屏风险。
我建议的方案是:STC15和ST7735都用3.3V供电,STC15的工作电压范围很宽(2.4V到5.5V),3.3V下跑30MHz完全没问题。这样数据线电平一致,不用加转换芯片,也不担心5V高压灌进屏幕控制器。
复位引脚也需要重视。有的例程把RESET接到RC复位电路上,靠上电自然复位,这在电源爬坡慢的时候容易导致初始化失败,表现就是白屏。最稳的做法是用单片机IO控制复位:上电后先拉低RESET大约10ms,再拉高,然后延时120ms再发初始化命令。
3. 用IO翻转模拟8080时序:写命令、写数据的底层逻辑
3.1 8080写时序到底在写什么
8080并口的写操作本质上就是:把数据放到D0-D7上,操作RS区分命令还是数据,然后在WR引脚上产生一个上升沿。在这个上升沿,ST7735会锁存数据线上的内容。
整个时序可以拆成三步:
- 拉低CS,选中屏幕。
- 根据写的是命令还是数据,设置RS电平;把要发送的字节放到数据总线D0-D7上。
- 拉低WR,保持一小段建立时间,再拉高WR,产生上升沿完成锁存。
对于STC15这种没有专门并口外设的单片机,我们要做的就是确保数据线在WR上升沿之前稳定,且电平满足建立时间要求。ST7735手册里要求的写周期时间在百纳秒级,STC15的IO翻转速度天然满足,所以不需要额外加延时,代码可以写得非常紧凑。
3.2 一份可直接抄的驱动代码骨架
下面的代码是驱动核心,去掉所有显示函数后只剩下“写命令”和“写数据”两个底层操作。这是所有后续绘图、文字、刷屏功能的基础。
#include "stc15.h" // 数据总线使用P0整组端口 #define LCD_DB P0 // 控制引脚定义,具体端口按你的接线调整 sbit LCD_CS = P2^2; sbit LCD_RS = P2^0; sbit LCD_WR = P2^1; sbit LCD_RD = P2^3; sbit LCD_RST = P2^4; void lcd_write_cmd(unsigned char cmd) { LCD_CS = 0; LCD_RS = 0; // RS=0表示写命令 LCD_DB = cmd; // 数据放到总线上 LCD_WR = 0; LCD_WR = 1; // WR上升沿锁存 LCD_CS = 1; } void lcd_write_data(unsigned char dat) { LCD_CS = 0; LCD_RS = 1; // RS=1表示写数据 LCD_DB = dat; LCD_WR = 0; LCD_WR = 1; LCD_CS = 1; }这段代码很朴素,但它是整套驱动的底层。要注意的是,LCD_CS每次操作都拉低再拉高,保证每次访问都是独立周期。如果你的屏幕上只挂了这一颗芯片,也可以把CS固定拉低,省去两次IO翻转,又能快一点。但固定拉低后如果后续还想挂别的SPI/并口设备,就要注意总线冲突的问题。
3.3 速度极限与稳定性权衡
为了让并口速度尽量快,我把WR拉低和拉高之间没有插入任何延时,实测在30MHz主频下工作稳定。如果你手上的屏幕或者走线质量不太行,出现花屏或者写错数据的情况,可以在WR拉低后加两三个_nop_(),牺牲一点点速度换取稳定性。
另外,STC15的IO模式建议设置成推挽输出。准双向模式下IO翻转速度和驱动能力都比推挽差一些,尤其在PCB走线较长、寄生电容大的时候,上升沿变缓会导致时序余量不足。在代码初始化部分加一句:
P0M1 = 0x00; P0M0 = 0xFF; // P0口全推挽 P2M1 = 0x00; P2M0 = 0x00; // P2口准双向即可,控制线无所谓P0口设成推挽后,数据总线输出更干脆,整个总线稳定时间更短。控制引脚保持准双向模式,方便读取外部状态(比如后续想接触摸屏检测引脚)。
4. 初始化序列的秘密:为什么你的屏白屏、偏色、镜像
4.1 初始化序列不是随便抄的
ST7735上电后不会自动进入可显示状态,必须发送一串初始化命令,来配置像素格式、显示方向、电源时序、伽马曲线等。网上流传的51驱动里,几乎每个版本的初始化序列都不一样,有的是针对SPI模式写的,有的是针对不同分辨率写的,直接照搬到并口模式下,大概率出问题。
一个比较通用的初始化流程至少包含这几步:
- 软复位(SWRESET,0x01)
- 退出睡眠模式(SLPOUT,0x11)
- 设置像素格式(COLMOD,0x3A),常用RGB565对应0x05
- 设置显示方向(MADCTL,0x36)
- 设置显示窗口(CASET 0x2A、RASET 0x2B)
- 开显示(DISPON,0x29)
其中影响最直观的是MADCTL和COLMOD。COLMOD错了颜色会完全错乱,MADCTL错了会出现镜像、倒置、行列交换。我的经验是:初始化完成后先刷纯红色、纯绿色、纯蓝色三种色块,每种只刷新一个很小的矩形区域,用来验证颜色通道和扫描方向,再决定要不要调整MADCTL。
下面这段是简化但可用的初始化序列核心部分,实际画图前建议把所有命令补全:
void lcd_init(void) { LCD_RST = 0; delay_ms(20); LCD_RST = 1; delay_ms(120); lcd_write_cmd(0x01); // SWRESET delay_ms(150); lcd_write_cmd(0x11); // SLPOUT delay_ms(200); lcd_write_cmd(0x3A); // COLMOD lcd_write_data(0x05); // RGB565,16位/像素 lcd_write_cmd(0x36); // MADCTL lcd_write_data(0xC8); // 方向/镜像配置,按实际屏调 lcd_write_cmd(0x29); // DISPON }这里的0xC8并不是万能参数,它只是我那块模组在竖屏方向、BGR颜色顺序下正常显示的配置。你的屏如果出现上下颠倒或左右镜像,改的就是这个字节。
4.2 “st7735是高位”这句热评背后的坑
网上搜ST7735并口驱动时,经常会看到类似“st7735是高位”的说法。这里的“高位”指的是8080总线上字节传输的顺序约定:D7是最高位,D0是最低位,一个字节的最左边那位走D7,最右边那位走D0。
这个约定本身不复杂,但坑在于不同模组的D0-D7丝印排列不一定和ST7735芯片手册里的引脚顺序一致。我遇到过一块模组,PCB丝印上标的D0实际接到芯片的D7,导致我按照“D0接P0.0、D1接P0.1”的方式接线后,屏幕上显示的图像像被“逐位反转”了一样,颜色杂乱、字形颠倒。
排查这种问题最有效的方法是:初始化完成后,让屏幕全屏刷红色(0xF800,RGB565中的红色),如果实际显示的是蓝色或者绿色,说明RGB通道错位了。这时候要检查两个地方:一是D0-D7有没有接反,二是MADCTL里的RGB/BGR位有没有设置对。如果颜色偏绿偏蓝,多半是数据位顺序问题;如果红色显示成蓝色,大概率是BGR设置问题。
4.3 MADCTL:方向、镜像和RGB/BGR全靠它
MADCTL(0x36)的一个字节里包含了多个控制位:
- MY(bit7):行方向,置1时从下往上扫描
- MX(bit6):列方向,置1时从右往左扫描
- MV(bit5):行列交换,置1时横竖屏切换
- RGB/BGR(bit3):0=RGB颜色顺序,1=BGR
- ML(bit4):行输出方向
- MH(bit2):列输出方向
对于一块竖屏应用,我们通常希望从左上角开始扫描,颜色按RGB565标准输出。具体值需要结合你的模组和安装方向来试。最快的方法是把这几个值做成可调参数,从小到大逐个试,每次观察:
- 横竖屏是否对:调MV位
- 上下是否颠倒:调MY位
- 左右是否镜像:调MX位
- 颜色正不正常:调RGB/BGR位
我当时调试时写了一个循环,每隔2秒切换一组MADCTL参数,观察屏幕显示效果,很快就锁定了正确的配置。这个方法比盲猜高效得多。
5. 用并口刷整屏:帧率、缓冲和STC15的有限RAM
5.1 窗口命令 + RAMWR 的刷屏模型
ST7735内部有完整的GRAM(显存),我们可以先通过CASET和RASET设置一个矩形窗口,然后连续发送像素数据(写入0x2C命令后,数据按从左到右、从上到下的顺序填充窗口,地址自动递增),不需要每次发送像素都带坐标信息。
整屏刷新的流程是:
- 写命令CASET(0x2A),设置列起始和结束坐标。
- 写命令RASET(0x2B),设置行起始和结束坐标。
- 写命令RAMWR(0x2C)。
- 连续写入1281602(RGB565每像素2字节)个数据字节。
在这个模式下,写数据是一次连续的流,非常适合并口这种批量传输方式。每写完一个字节,GRAM地址自动指向下一个像素,主机这边只需要不断向P0口丢数据、拉WR,CPU不需要做坐标计算。
5.2 全屏缓冲放不下怎么办
STC15的内存比较紧张,常用的STC15W4K32S4有4KB SRAM,而全屏RGB565缓冲需要40960字节,完全放不下。所以不能像STM32那样先把整幅图像画在内存缓冲区,再一次拷贝到屏幕。
实际项目中我用的是分块绘制方案:把屏幕划分成若干个小区域,比如8行高、128列宽的小横条,每个横条的缓冲只有81282=2048字节,4KB内存刚好能放两个。需要更新某个区域时,先用CASET/RASET把窗口设置到这个区域,然后从缓冲区刷过去。
这个方案在显示波形、数字仪表、菜单列表时特别实用。比如做一个简易电压表,只需要更新数字所在的几十像素区域,刷新时间不到1ms,肉眼完全看不出闪烁。
如果需要显示图片,我建议直接把图片数据放在STC15的Flash里(STC15W4K32S4有32KB Flash,可以用Keil的code关键字把数组放在代码段),显示时按行读取、按行发送,不需要额外的RAM缓冲。
5.3 背光控制与进一步提速的空间
背光LED+可以直接接3.3V或者5V,但这会一直全亮。STC15自带多路PWM,可以把背光接到PWM引脚上,通过改变占空比调节亮度。我给ST7735留了一路PWM,亮度调到50%左右,功耗和显示效果平衡得不错。
关于提速,还有两个方向可以尝试:
- 把CS固定拉低,去掉每次写操作的CS翻转,大约能省10%到15%的时间。
- 使用STC15的“P0整组赋值 + WR连续翻转”组合,避免在写数据函数里做判断。
如果对速度有极致要求,可以研究一下STC15W系列是否支持地址自动递增的并行访问模式(类似XRAM写操作那套机制),但这属于比较偏门的用法,普通应用用不到。
6. 白屏、花屏、跑色:一整套实战排查清单
6.1 从“纯色测试”开始定位
点亮屏幕的第一步永远不是显示汉字或者图片,而是刷纯色。写一个最简单的函数,依次刷红、绿、蓝、白、黑五种颜色,每种停留1秒,然后根据现象缩小问题范围。
- 全屏纯白正常,但纯红显示成黑色:可能RGB/BGR设置反了,或者COLMOD设成了RGB666/444。
- 全屏颜色不对但矩形区域正常:窗口坐标(CASET/RASET)设置错误。
- 颜色看起来像“噪点”一样杂乱:数据线接触不良,或者WR时序太紧,数据建立时间不够。
- 屏幕一半正常一半异常:供电电流不够,或者数据总线中某几根线虚焊。
纯色刷不出来,就不要往下调其他功能。这是排查的基本原则。
6.2 常见故障对照表
| 现象 | 最可能的原因 | 排查/解决办法 |
|---|---|---|
| 白屏,背光亮 | 初始化没完成、RESET没复位、IM模式配置错 | 检查复位时序、IM引脚;用示波器看WR上有没有波形 |
| 花屏,看起来像镜像 | 数据位顺序接反(D0-D7方向反了) | 用纯红色测试,确认颜色通道;逐位核对硬件接线 |
| 颜色红蓝互换 | MADCTL里RGB/BGR位不对 | 修改MADCTL的bit3 |
| 上下颠倒或左右镜像 | MY/MX位不对 | 尝试修改MADCTL的bit7/bit6 |
| 显示内容错位 | 窗口坐标没有设置正确 | 检查CASET/RASET的坐标范围是否与分辨率一致 |
| 闪烁或不稳定 | 电源纹波大、W R时序余量不足 | 增加_nop_()延时;检查电源电容 |
| 只有顶部一条显示 | RASET行范围设置错误 | 确保RASET结束坐标不超过159 |
6.3 给ST7789V用户的一句话
如果你手头的屏是ST7789V(常见于1.3寸、1.54寸、2.0寸模组),并口驱动的思路完全一致,8080时序、窗口命令、RAMWR机制都差不多。区别主要在初始化序列和分辨率参数上,ST7789V的RAM尺寸更大(240x320甚至更高),CASET/RASET的坐标寄存器位数可能不同,COLMO D支持的模式一样丰富。把ST7735这套并口逻辑迁移过去,再对照ST7789V手册修一下初始化命令就可以了。
我在折腾这个并口方案的时候,最大的体会是:“并口驱动”看起来像是给老平台用的淘汰技术,但在STC15这种没有硬件SPI、没有DMA的芯片上,它反而是让彩色屏幕真正流畅起来的有效手段。网上那个zip包里的代码虽然乱,但方向是对的——如果你也正好收到一块带D0-D7引脚的ST7735模组,不妨把SPI例程扔到一边,用并口重新点亮它,速度上的提升会给你一个不小的惊喜。
本文还有配套的精品资源,点击获取