简介:这是一份基于意法半导体STM32F103RCT6微控制器驱动1.44英寸彩色液晶屏的完整工程,适合嵌入式入门开发者学习串行外设接口通信、液晶底层驱动与图形界面显示。工程采用标准外设库编写,涵盖引脚定义、时钟配置、数据发送、屏幕初始化序列、显存缓冲区刷新等关键环节,同时附带动画和图形绘制演示;代码注释完整,可在集成开发环境中直接打开并编译烧录,快速验证彩色显示效果,还能按项目需求进行裁剪和移植。压缩包共86个文件,以38个头文件与32个C语言源文件为主体,另有启动文件、工程配置、十六进制固件、一键清理脚本、调试配置及说明文档,整体大小仅289KB,目录划分清晰。已有4044人学习下载,对需要为设备添加小尺寸彩色屏幕的开发者来说,这是一份可直接运行并二次开发的参考设计。 这个项目听起来很基础——STM32F103RCT6加一块1.44寸TFT彩屏,点亮屏幕显示点什么东西。但真把它从零跑通,你会发现里面藏着不少值得掰扯的细节:芯片选型、引脚分配、ST7735S初始化序列、SPI时序,任何一个环节卡住,屏幕要么白屏,要么花屏,要么颜色鬼畜。这篇文章我就按自己做项目时的思路,把这套东西完整拆一遍,包括硬件接线、驱动代码逻辑、常见坑位,全程都是能直接抄作业的内容。
这个配置最常见的用处就是做桌面小仪表、信号发生器、温湿度计、迷你游戏机这类设备,屏幕虽然只有128x128,但显示数值、波形、菜单绰绰有余。适合刚学完STM32基础外设、想上一个带屏幕项目的朋友,也适合手里正好有这块屏幕和板子、不知道从哪里下手的同学。
1. 项目拆解:为什么是STM32F103RCT6配1.44寸TFT
1.1 STM32F103RCT6这颗芯片的底气
STM32F103RCT6是Cortex-M3内核,主频最高72MHz,Flash有256KB,SRAM有48KB。带一块128x128的TFT屏,画点、刷全屏、跑简单界面,性能绰绰有余。很多人拿它和更常见的F103C8T6对比,C8T6只有64KB Flash和20KB SRAM,带屏也能跑,但内存确实吃紧。RCT6的48KB SRAM刚好能宽松应对屏幕的数据缓冲需求。
另外一个关键点是IO数量。RCT6是LQFP64封装,有51个可用IO,接屏幕那8个引脚之后,还能剩一大堆GPIO接按键、传感器、编码器、蜂鸣器。这也是为什么很多小项目喜欢把它当“带屏主控”——以后想扩展功能,IO不会成为瓶颈。
1.2 1.44寸TFT与ST7735S的对应关系
1.44寸TFT模块,分辨率固定是128x128 RGB,绝大多数内置ST7735S控制器。ST7735S内部有一块完整的128x128x16bit GRAM,你通过SPI把像素颜色写进去,它自己负责把GRAM内容刷新到液晶面板上。
这里要区分两个概念:屏幕模块和驱动IC。网上买到的通常是一个带转接板的模块,板上焊着ST7735S芯片、稳压电路和背光电路,引出一排排母引脚,常见的就是VCC、GND、CS、RESET、DC、SDA、SCK、BL这8个。如果是裸屏,那就只有玻璃面板和排线,驱动要做在COF软排线上,不适合新手直接玩。
关于屏幕类型,这个尺寸的TFT模块大部分是TN屏,可视角度一般,侧面看会变暗或偏色。想改善可以选IPS屏,但1.44寸的IPS模块很少,价格也高。区分方法很简单:TN屏从侧面看很快变暗或颜色反转,IPS屏侧面保持颜色大体一致,对比度更稳定。选屏的时候注意看商品标注或者直接问卖家,收到货之后从侧面看一眼就能判断。
1.3 这个项目背后真正要练的基本功
点亮屏幕只是结果,过程里涉及的知识才是这个项目的核心价值:SPI通信模式、命令/数据切换、RGB565颜色编码、时序延时、显存管理。这些基础跟驱动其他显示屏是完全通用的,OLED、1.3寸TFT、2.4寸大彩屏,底层逻辑都是同一套东西。
把这套跑通之后,后面做信号发生器只是把ADC采样数据画成曲线,做仪表只是把数值映射成文本显示,做菜单只是多几个状态切换。本质上都是基于那几个底层函数在叠功能。所以这个项目特别适合作为从“单片机裸机”到“带显示界面系统”的跳板。
2. 硬件接线方案:8个引脚怎么分配不踩坑
2.1 屏幕引脚逐一解读
先把这8个引脚的作用说清楚,接线就不会晕:
- VCC:模块电源,一般接3.3V。有些模块板载AMS1117-3.3稳压芯片,可以接5V,没有就别乱接,后面会细说。
- GND:地线,必须和STM32共地。
- CS:片选,低电平有效。只有一根SPI总线上挂多个设备时才需要分时操作,单屏可以直接拉低固定,但程序里一般还是会控制它。
- RESET:复位引脚,低电平复位。MCU上电后要给一个至少20ms的低脉冲再释放,否则初始化会乱。
- DC/RS:数据/命令选择。DC低电平表示传输的是命令,高电平表示传输的是像素或参数数据。这根线是驱动逻辑的关键。
- SDA:SPI的MOSI数据线,数据从STM32发往屏幕。注意这种屏幕一般没有MISO,因为数据方向是单向的。
- SCK:SPI时钟线。
- BL:背光控制。接高电平背光亮,接PWM可以调亮度,不接的话可能背光不亮但显示正常。
2.2 我采用的接线方案:软件SPI与硬件SPI怎么选
两种方案都行,各有取舍。软件SPI就是拿几个普通GPIO手动翻转电平模拟时序,优点是引脚随便挑,不用去查芯片的复用功能表,出问题方便换线排查;缺点是刷新速度受GPIO翻转速率限制,全屏填充会慢一些。硬件SPI用芯片内部的SPI外设,速度快且稳定,但引脚通常是固定的,比如SPI1的SCK固定在PA5、MOSI在PA7,得先查数据手册确认复用关系。
我的建议是:第一次点亮屏幕、只想跑通显示逻辑,优先用软件SPI,代码直观,排查方便;后续要做动画、波形刷新这类对速度有要求的场景,再切到硬件SPI。下面给出一套软件SPI接线方案,引脚都放在PB口,方便直接照着接:
| 屏幕引脚 | STM32引脚 |
|---|---|
| VCC | 3.3V |
| GND | GND |
| CS | PB12 |
| RESET | PB11 |
| DC | PB10 |
| SDA | PB15 |
| SCK | PB13 |
| BL | 3.3V |
为什么选这几个引脚?因为都是普通GPIO,不占用SWD下载接口(PA13/PA14)和串口(PA9/PA10),以后调试串口或下载程序不会冲突。实际你完全可以换成其他空闲引脚,只要在代码里同步修改宏定义就行。
2.3 供电与电平匹配的细节
这一块是我踩过坑的地方。1.44寸TFT模块的逻辑电平是3.3V,STM32的GPIO配置成推挽输出,输出3.3V电平驱动模块一般没问题。真正的坑在供电:
有些模块板载了3.3V稳压IC(常见AMS1117-3.3),VCC接5V没问题,模块自己会转成3.3V;有些简化版模块没有稳压,VCC直接进ST7735S,接5V就烧。稳妥的判断方法是看模块背面有没有稳压芯片,有就可以接5V,没有就老老实实接3.3V。
背光也要注意:BL直接接3.3V通常OK,模块上一般串了限流电阻。如果发现背光特别亮、模块发热,可以串一个几十欧的电阻,或者用PWM降低占空比。另外,有的模块没有电平转换电路,STM32那几个号称5V容忍的引脚可以接5V逻辑,但没有转换电路时,不要用5V逻辑去驱动屏幕,会损坏ST7735S。
3. ST7735S初始化与底层驱动:屏幕点亮的灵魂
3.1 SPI时序与命令/数据切换
ST7735S的SPI工作模式一般是模式0,也就是CPOL=0、CPHA=0:SCK空闲为低电平,数据在上升沿被采样。一个字节8个bit,先发高位再发低位。软件SPI写一个字节的代码特别简单:
void TFT_WriteByte(uint8_t dat) { for (int i = 0; i < 8; i++) { if (dat & 0x80) { TFT_SDA_H; } else { TFT_SDA_L; } TFT_SCK_H; // 上升沿,屏幕采样 dat <<= 1; TFT_SCK_L; } }命令和数据要靠DC引脚区分:
void TFT_WriteCmd(uint8_t cmd) { TFT_DC_L; TFT_CS_L; TFT_WriteByte(cmd); TFT_CS_H; } void TFT_WriteData(uint8_t dat) { TFT_DC_H; TFT_CS_L; TFT_WriteByte(dat); TFT_CS_H; }如果后面换成硬件SPI,只需要把TFT_WriteByte内部替换成SPI外设的发送函数,上层调用完全不用改。这种分层思路在后面扩展时非常省事。
3.2 初始化序列到底在初始化什么
很多人第一次接触ST7735S,看到那一大串寄存器和参数就头疼。其实初始化序列可以分成几组来理解:
- 复位相关:SWRESET软复位、SLPOUT退出睡眠模式,这两条命令后都必须延时等待内部稳定。
- 显示方向与色深:MADCTL设置扫描方向和RGB/BGR顺序,COLMOD设置颜色格式为16bit。
- 电源和伽马:PWCTR1/2、VMCTR1/2、FRMCTRL、伽马曲线等,负责内部电压、画面亮度和对比度。这些参数厂商一般提供了推荐值,直接抄模块商或常见驱动库的即可。
- 边界设置:CASET/RASET设定写入区域,对应屏幕128x128像素的横向和纵向范围。
- 开显示:NORON进入正常显示模式、DISPON打开显示。
以1.44寸模块为例,我常用的最小可用初始化核心片段如下:
TFT_WriteCmd(0x01); delay_ms(150); // SWRESET TFT_WriteCmd(0x11); delay_ms(120); // SLPOUT TFT_WriteCmd(0xB1); TFT_WriteData(0x05); TFT_WriteData(0x3C); TFT_WriteData(0x3C); TFT_WriteCmd(0x3A); TFT_WriteData(0x05); // RGB565 TFT_WriteCmd(0x36); TFT_WriteData(0x00); // MADCTL,如果颜色反了则试0x08或0xC8 TFT_WriteCmd(0x2A); TFT_WriteData(0x00); TFT_WriteData(0x02); TFT_WriteData(0x00); TFT_WriteData(0x81); TFT_WriteCmd(0x2B); TFT_WriteData(0x00); TFT_WriteData(0x02); TFT_WriteData(0x00); TFT_WriteData(0x81); TFT_WriteCmd(0x29); // DISPON这段是从多个ST7735S驱动中提炼出的精简序列。其中CASET/RASET里的02和81很关键:很多1.44寸面板的实际可视区域并不从内部坐标0开始,而是从(2,2)偏移开始,所以列地址范围写0x02到0x81,正好覆盖128个像素。如果你的屏幕显示内容偏移了几个像素,八成是这里的边界没对上。
3.3 驱动代码的组织方式
我会把显示相关代码拆成两个文件:底层tft_driver.c只负责写命令、写数据、设置窗口、填充颜色,不关心业务逻辑;上层显示模块负责画点、画线、画字符、显示图片。以后换更大尺寸的屏幕,只改底层,上层不动。
画点是最基础的操作。RGB565颜色在SPI传输时的字节序是先高8位后低8位:
void TFT_DrawPixel(uint16_t x, uint16_t y, uint16_t color) { TFT_WriteCmd(0x2A); TFT_WriteData(x >> 8); TFT_WriteData(x & 0xFF); TFT_WriteData(x >> 8); TFT_WriteData(x & 0xFF); TFT_WriteCmd(0x2B); TFT_WriteData(y >> 8); TFT_WriteData(y & 0xFF); TFT_WriteData(y >> 8); TFT_WriteData(y & 0xFF); TFT_WriteCmd(0x2C); TFT_WriteData(color >> 8); TFT_WriteData(color & 0xFF); }单点操作每次都要设置列地址和行地址,效率低。所以填充区域时应该先把CASET/RASET设置一次,然后连续写入所有像素。全屏填充就是设置完窗口后,连续发送128x128x2字节的数据。
4. 显示功能实现:从画点、字符到图片显示
4.1 填充与清屏:先把显示区域用起来
先写一个矩形填充函数,它能帮你快速调试屏幕是否有偏移、颜色是否正确:
void TFT_FillRect(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t color) { uint8_t hi = color >> 8, lo = color & 0xFF; TFT_WriteCmd(0x2A); TFT_WriteData(x0 >> 8); TFT_WriteData(x0 & 0xFF); TFT_WriteData(x1 >> 8); TFT_WriteData(x1 & 0xFF); TFT_WriteCmd(0x2B); TFT_WriteData(y0 >> 8); TFT_WriteData(y0 & 0xFF); TFT_WriteData(y1 >> 8); TFT_WriteData(y1 & 0xFF); TFT_WriteCmd(0x2C); TFT_DC_H; for (uint32_t i = 0; i < (x1 - x0 + 1) * (y1 - y0 + 1); i++) { TFT_WriteByte(hi); TFT_WriteByte(lo); } }烧录后调用TFT_FillRect(0, 0, 127, 127, 0xF800),应该看到全屏红色。如果看到蓝色或绿色,说明MADCTL的BGR位需要调整。常用颜色值记住这几个:红色0xF800、绿色0x07E0、蓝色0x001F、白色0xFFFF、黑色0x0000,调试时很常用。
4.2 字符显示与字模取模细节
显示字符的本质是把每个字符拆成点阵数据,逐点画上去。最省事的方式是用取模软件生成字模,比如PCtoLCD2002。以8x16的ASCII码为例,每个字符占16字节,一行一个字节,位为1就画前景色,位为0就画背景色或跳过。
取模方向要选对,取模软件里英文一般用“逐行式”,格式选“十六进制”。如果发现字符左右颠倒或上下颠倒,多半是取模方向选成了“逐列式”或者“逆向”。
显示一个英文字符的函数框架:
void TFT_ShowChar(uint16_t x, uint16_t y, char ch, uint16_t fg, uint16_t bg) { const uint8_t *data = &ASCII_8x16[(ch - 32) * 16]; for (uint8_t i = 0; i < 16; i++) { for (uint8_t j = 0; j < 8; j++) { if (data[i] & (0x80 >> j)) TFT_DrawPixel(x + j, y + i, fg); else TFT_DrawPixel(x + j, y + i, bg); } } }中文16x16点阵就是一个字占32字节,显示逻辑相同,只是行数和列数翻倍。逐点画字符在72MHz主频下也能跑,但刷一屏文字会比较慢,对静态界面完全够用。
4.3 图片显示与Flash空间权衡
彩色图片取模一般用Image2Lcd软件,输出格式选C数组,颜色格式选RGB565,扫描方式选水平扫描,输出宽度和高度设成128。生成的数组大小是128x128x2=32768字节,约32KB。这个大小在RCT6的256KB Flash面前不算什么,放两三张全屏图没问题,但别指望放几十张。
放图之前注意图片宽高要和屏幕一致,否则会出现截断或滚动效果。另一种常见需求是曲线和波形显示,信号发生器场景就是典型:每个ADC采样点映射成屏幕Y坐标,画点时用前景色画当前点,顺手用背景色擦除上一帧同位置的旧点,这样就能做到局部刷新,不用全屏重绘。
全屏刷新率方面,软件SPI大概只有每秒两三帧,肉眼能感到明显闪烁;切换到硬件SPI并打开到18MHz左右,全屏刷新可以到十几帧以上,波形动画才够顺滑。我的建议是:要做动画先切硬件SPI,同时只更新变化区域,能省则省。
5. 常见问题与排查技巧实录
5.1 白屏、黑屏、花屏分别怎么处理
白屏通常说明屏幕初始化没生效,系统根本没进入正常显示状态。优先检查三件事:RESET引脚有没有给到低脉冲、初始化函数有没有被调用、DC引脚是否接对。黑屏但背光亮,说明电源正常但显示数据没进去,重点查SCK和SDA接线,以及SPI模式是否配置成CPOL=0、CPHA=0。花屏多半是初始化序列被截断或延时不足,把每条命令后的延时稍微加长,特别是SWRESET和SLPOUT后面。
下面列一个快速排查表:
| 症状 | 大概率原因 | 排查动作 |
|---|---|---|
| 白屏 | 初始化未执行或RESET异常 | 确认复位脉冲,检查初始化函数是否调用 |
| 黑屏但背光亮 | SPI数据未写入 | 检查SDA/SCK接线,确认CPOL/CPHA |
| 花屏 | 初始化不完整或供电不稳 | 补全初始化序列,量电源纹波 |
| 颜色红蓝互换 | MADCTL的BGR位反了 | 修改MADCTL值,0x00和0x08互换 |
| 显示内容偏移 | CASET/RASET边界不对 | 调整0x02和0x81参数 |
5.2 颜色不对、偏色、对比度异常
颜色只有红蓝互换的话,改MADCTL的RB位即可,0x00和0x08之间切换。但偏色或对比度异常,更多是伽马和电源寄存器的问题。ST7735S驱动库里的伽马设置(0xE0、0xE1两组参数)对色彩影响很大,如果屏幕发灰或偏色明显,不要自己乱调,直接换成常见驱动库的标准伽马参数。
另一个容易被忽略的是背光电压。背光太暗会让人觉得屏幕偏色,这时候先排除供电问题,再考虑调寄存器。
5.3 用逻辑分析仪抓SPI时序
排查SPI问题我最推荐逻辑分析仪。接上SCK和SDA两根线,抓一次初始化过程,能直接看到发出去的命令是不是0x01、0x11、0xB1这些,也能看清数据波形里有没有毛刺。如果波形正常但屏幕不亮,问题大概率在屏幕本身或供电;如果波形根本不对,就去查GPIO配置或引脚映射。
实测下来,这个工具比瞎猜高效太多,也比示波器容易上手。
我自己做这个项目时的习惯是:先把最简初始化跑通,确认能全屏填色,再加字符、图片。每加一个功能就烧一次程序验证,而不是一轮写到底。屏幕驱动这种东西,问题往往不出在单个函数,而出在函数之间的配合和时序上,分阶段验证能帮你快速定位问题在底层还是上层。
最后再分享一点实际体会:1.44寸TFT属于小屏,做产品界面时信息密度别拉太高,显示大号数字或状态图标,比塞一堆小字实用得多。如果后续要接电阻触摸屏,可以在这个基础上增加ADC触摸采样和四点校准逻辑;要扩展成信号发生器,就用ADC采集波形并用画线函数绘制曲线。核心还是把这一套显示链路吃透,后面都是换汤不换药的事情。
本文还有配套的精品资源,点击获取