1. 项目概述一块1.47英寸LCD模块的深度探索最近在捣鼓一个需要显示信息的小项目手头正好有一块1.47英寸的LCD模块。这尺寸听起来有点“非主流”比常见的0.96英寸大一圈又比1.8英寸小一点属于那种在特定空间限制下追求更大可视面积的折中选择。市面上这类模块通常基于ST7735S或ST7789这类驱动芯片分辨率常见的是172x320竖屏或320x172横屏色彩深度能达到16位RGB565显示效果相当细腻。对于嵌入式开发者、电子爱好者或者想给树莓派Pico、Arduino、ESP32等主控板加个“眼睛”的朋友来说这类小屏是绝佳的交互窗口。它能显示文本、图形、图标甚至简单的动画应用场景从智能穿戴设备的副屏、微型游戏机、传感器数据显示终端到DIY的小型仪表盘非常广泛。这篇文章我就以手头这块屏为例带你从硬件引脚、驱动原理、软件适配一路走到实际应用把这块小屏玩透。2. 硬件接口与电路连接详解拿到一块裸屏模块第一步永远是看引脚定义和接电路。别看它小接口可能有好几种接错了轻则不显示重则烧芯片。2.1 常见接口类型与引脚定义1.47英寸LCD模块常见的接口是SPI串行外设接口因为SPI引脚少、速度快非常适合驱动这种分辨率不算太高的彩屏。一块典型的SPI接口1.47寸屏其引脚通常包括引脚名称功能描述连接注意事项VCC电源正极通常为3.3V务必确认模块工作电压接5V可能永久损坏。GND电源地与主控板共地。SCL / SCKSPI时钟线主控输出屏幕输入。SDA / MOSISPI数据线主出从入主控输出屏幕输入。RES / RST复位引脚低电平有效用于硬件复位屏幕控制器。DC / A0数据/命令选择引脚关键引脚高电平时SDA上传的是显示数据像素颜色低电平时传的是命令如设置扫描方向。CS / CS片选引脚低电平有效选中该SPI从设备。BLK / LED背光控制通常接高电平3.3V常亮或接PWM引脚实现亮度调节。注意有些模块为了简化可能将RES引脚内部上拉外部只需接VCC即可但为了可靠复位建议还是连接到主控的GPIO上。背光引脚如果是LED和LED-则需要在中间串联一个限流电阻如100欧姆。2.2 与主流主控板的连接示例以最流行的ESP32开发板如ESP32 DevKitC和树莓派Pico为例连接方式非常直观。关键在于利用硬件SPI接口以获得最佳性能。连接ESP32ESP32通常有两组硬件SPIHSPI和VSPI。我们可以任意选用一组例如VSPI。VCC- ESP32的3.3V引脚GND- ESP32的GNDSCL- ESP32的GPIO 18(VSPI SCK)SDA- ESP32的GPIO 23(VSPI MOSI)RES- ESP32的GPIO 4(任意空闲GPIO)DC- ESP32的GPIO 2(任意空闲GPIO)CS- ESP32的GPIO 5(任意空闲GPIO或接GND如果模块上只有一个SPI设备)BLK- ESP32的3.3V或GPIO用于PWM调光连接树莓派PicoRP2040RP2040也有两组硬件SPISPI0和SPI1。我们使用SPI0。VCC- Pico的3.3V OUT(Pin 36)GND- Pico的GND(Pin 38)SCL- Pico的GPIO 18(SPI0 SCK)SDA- Pico的GPIO 19(SPI0 MOSI)RES- Pico的GPIO 20DC- Pico的GPIO 21CS- Pico的GPIO 17(SPI0 CSn)BLK- Pico的3.3V OUT实操心得在面包板上连接时最稳妥的方法是先用万用表蜂鸣档逐一检查VCC和GND是否短路再上电。第一次测试时可以暂时不接背光BLK如果程序正确你可能会在特定角度下看到非常暗淡的显示内容这能证明驱动芯片和核心通信是正常的只是背光没亮。3. 驱动原理与初始化序列剖析点亮屏幕不仅仅是通电和发数据那么简单驱动芯片如ST7735S就像屏幕的“大脑”需要一套精确的“开机指令”进行配置才能正常工作和显示我们想要的画面。3.1 驱动芯片如何工作以ST7735S为例它内部有一个显存GRAM对应着屏幕上的每一个像素点。我们的任务就是通过SPI总线向这个GRAM写入颜色数据。但是在写数据之前必须告诉驱动芯片一系列参数比如扫描方向是从左到右还是从上到下、颜色格式是RGB565还是其他、帧率、电源配置等等。这些配置都是通过发送“命令”Command和紧随其后的“参数”Data来实现的。DC引脚在此扮演了至关重要的角色当DC置为低电平接下来通过SDAMOSI发送的一个字节就会被芯片解释为命令码当DC置为高电平接下来发送的字节则被解释为数据可以是命令的参数也可以是像素颜色值。例如设置扫描方向的命令可能是0x36其后需要跟一个字节的数据来指定具体模式。3.2 关键初始化命令解析一个典型的初始化序列包含几十条命令。我们挑几条最核心的来理解软件复位SWRESET, 0x01发送此命令让驱动芯片内部复位通常需要等待几毫秒让其稳定。退出睡眠模式SLPOUT, 0x11屏幕刚上电可能处于睡眠省电模式此命令唤醒它。发送后需要等待120ms以上。颜色接口格式COLMOD, 0x3A这是最关键的命令之一。它告诉芯片我们后续发送像素数据所用的格式。对于16位色65K色我们通常发送参数0x05代表RGB565格式即一个像素用2个字节表示高5位红6位绿低5位蓝。内存访问控制MADCTL, 0x36这是另一个极其重要的命令。它控制显示方向、颜色顺序等。通过修改其参数我们可以实现屏幕0°、90°、180°、270°旋转以及镜像显示。例如参数0x00通常代表横屏模式0xA0或0xC0可能代表竖屏模式具体需要查阅具体屏的规格书或驱动库源码。显示开启DISPON, 0x29完成所有配置后发送此命令正式开启显示。踩坑实录最常遇到的问题就是“花屏”或颜色错乱。十有八九是COLMOD命令设置的颜色格式与后续绘图函数发送的数据格式不匹配。比如库默认发送RGB8883字节但屏幕配置成了RGB5652字节必然错乱。另一个就是MADCTL设置的方向不对导致绘图坐标计算全部错误图形显示在奇怪的位置。4. 软件驱动库选择与适配实战我们不可能每次都从零开始写SPI底层和初始化序列利用成熟的驱动库是最高效的方式。针对不同的主控和开发环境选择也不同。4.1 Arduino 环境下的 TFT_eSPI 库对于Arduino IDE兼容ESP32、ESP8266、STM32等TFT_eSPI库是功能最强大、社区支持最好的选择之一。它支持数十种驱动芯片和屏幕。适配步骤安装库在Arduino库管理中搜索并安装TFT_eSPI。配置用户设置文件这是最关键的一步。找到Arduino安装目录下的libraries/TFT_eSPI/User_Setup.h文件或User_Setup_Select.h我们需要编辑它。选择驱动和定义引脚通常不直接修改User_Setup.h而是通过User_Setup_Select.h来选择或新建一个配置文件。更简单的方法是在TFT_eSPI库的User_Setups文件夹下找一个接近的配置如Setup24_ST7735.h复制并重命名为Setup47_ST7735.h然后修改其中内容。// 示例片段 (Setup47_ST7735.h) #define ST7735_DRIVER // 声明使用ST7735驱动 #define TFT_WIDTH 172 // 设置屏幕宽度像素 #define TFT_HEIGHT 320 // 设置屏幕高度像素 #define TFT_RGB_ORDER TFT_RGB // 颜色顺序如果红色蓝色反了可以改为TFT_BGR #define TFT_INVERSION_ON // 通常需要开启否则颜色可能反相 // 定义引脚 #define TFT_CS PIN_D5 // 你的CS引脚对应Arduino引脚号 #define TFT_DC PIN_D3 // 你的DC引脚 #define TFT_RST PIN_D4 // 你的RST引脚如果共用可设为-1 // 定义SPI频率 #define SPI_FREQUENCY 27000000 // 27MHz在ESP32上可以尝试更高在User_Setup_Select.h中启用你的配置找到一行类似#include User_Setups/Setup47_ST7735.h取消它的注释。编写测试代码#include TFT_eSPI.h TFT_eSPI tft TFT_eSPI(); void setup() { tft.init(); tft.setRotation(1); // 根据你的屏幕方向调整0-3 tft.fillScreen(TFT_BLACK); tft.setTextColor(TFT_WHITE, TFT_BLACK); tft.drawString(Hello, 1.47!, 10, 10, 4); } void loop() {}4.2 MicroPython / CircuitPython 环境对于树莓派Pico、ESP32的MicroPython环境常用st7789或st7735的库。由于1.47寸屏多用ST7735S我们可以使用st7735库。适配步骤以RP2040 MicroPython为例刷写MicroPython固件到Pico。上传驱动库文件将st7735.py或类似驱动文件通过Thonny等IDE上传到Pico的文件系统。连接硬件如前文所述连接好硬件。编写测试代码import machine import st7735 import time # 定义SPI和引脚 spi machine.SPI(0, baudrate20000000, polarity0, phase0, sckmachine.Pin(18), mosimachine.Pin(19)) tft st7735.ST7735(spi, rstmachine.Pin(20), dcmachine.Pin(21), csmachine.Pin(17), width172, height320) # 初始化 tft.init() # 清屏并显示文字 tft.fill(st7735.BLACK) tft.text(MicroPython, 10, 10, st7735.WHITE) tft.show() # 有些库需要显式调用show有些是立即生效注意事项MicroPython的SPI速度baudrate不要一开始就设得太高先从10MHz开始测试稳定后再逐步提高。另外st7735库可能需要根据你的屏幕具体型号修改初始化序列这需要查看库文件的init函数部分。5. 图形绘制与界面优化技巧驱动点亮后真正的乐趣在于绘制内容。无论是显示传感器数据还是制作小动画都需要基本的图形学知识。5.1 基础绘图函数与坐标系统所有图形库都提供类似的基础函数fillScreen(color)用指定颜色清空整个屏幕。drawPixel(x, y, color)在坐标(x, y)画一个点。drawLine(x0, y0, x1, y1, color)画线。drawRect(x, y, w, h, color)画空心矩形。fillRect(x, y, w, h, color)画实心矩形。drawCircle(x, y, r, color)画空心圆。fillCircle(x, y, r, color)画实心圆。setTextColor(foreground, background)设置文本颜色前景色和背景色。drawString(string, x, y, font)在指定位置用指定字体绘制字符串。坐标系统陷阱原点(0,0)默认通常在屏幕的左上角X轴向右递增Y轴向下递增。但当你使用setRotation()函数旋转屏幕后这个坐标系也会跟着旋转例如旋转90度后原来的“宽度”变成了“高度”绘图时必须根据新的宽高来调整坐标计算否则内容会显示在屏幕外。5.2 提升显示性能与流畅度小屏资源有限优化很重要。局部刷新如果只是更新部分区域如一个数字不要调用fillScreen清全屏只调用fillRect清除那个数字所在的区域然后再绘制新内容。这能极大减少闪烁和提升速度。使用帧缓冲区Frame Buffer高级玩法。在内存中开辟一块和屏幕分辨率一样大的缓冲区对于172x320的RGB565需要约107.5KB内存。所有绘图操作先在内存缓冲区中进行完成一整帧画面后一次性调用pushImage或swap函数将整个缓冲区数据发送到屏幕。这能完全消除闪烁实现流畅动画。TFT_eSPI库通过setSwapBytes和pushImage函数支持此功能但需要主控有足够内存ESP32通常可以。双缓冲区Double Buffering在帧缓冲区的基础上使用两个缓冲区。当一个缓冲区正在被后台绘图时另一个缓冲区的内容被送到前台显示。绘制完成后交换缓冲区。这是实现复杂动画的终极方案但对内存要求更高。精简与压缩使用小字体减少文本占用的像素数量。对于图标、位图使用取模软件将其转换为字节数组并以PROGMEMArduino或const方式存储减少RAM占用。绘制时使用drawBitmap函数。如果颜色种类不多可以考虑使用颜色索引模式但大多数小屏库不支持需自己实现。5.3 制作一个简单的数据仪表盘结合上述知识我们可以快速做一个显示温湿度传感器数据的界面。// Arduino TFT_eSPI 示例片段 #include TFT_eSPI.h TFT_eSPI tft TFT_eSPI(); float temp 25.6; float humidity 60.3; void setup() { tft.init(); tft.setRotation(1); tft.fillScreen(TFT_BLACK); // 绘制静态标题和边框 tft.setTextColor(TFT_CYAN, TFT_BLACK); tft.drawString(Env Monitor, 20, 10, 4); tft.drawRect(10, 50, tft.width()-20, 100, TFT_WHITE); } void loop() { // 模拟读取传感器数据实际应替换为真实传感器代码 // temp readTemperature(); // humidity readHumidity(); // 局部刷新先清除旧数据区域 tft.fillRect(20, 70, 120, 60, TFT_BLACK); // 绘制新数据 tft.setTextColor(TFT_YELLOW, TFT_BLACK); tft.drawString(Temp:, 20, 70, 2); tft.drawFloat(temp, 1, 70, 70, 2); // 在(70,70)位置绘制浮点数保留1位小数 tft.setTextColor(TFT_GREEN, TFT_BLACK); tft.drawString(Humi:, 20, 90, 2); tft.drawFloat(humidity, 1, 70, 90, 2); tft.drawString(%, 110, 90, 2); delay(2000); // 每2秒更新一次 }这个例子展示了如何划分静态UI和动态数据区域并通过局部刷新来高效更新。在实际项目中你还可以添加进度条、趋势图等更丰富的元素。6. 功耗管理与背光控制对于电池供电的项目屏幕往往是耗电大户。1.47寸LCD的功耗主要由背光LED和驱动芯片本身产生。背光控制这是省电的关键。如果背光引脚BLK直接接VCC则背光常亮。更优的做法是将其连接到一个GPIO引脚上。开关控制需要显示时将GPIO设为高电平打开背光进入待机或不需要看屏幕时设为低电平关闭背光。这能立刻节省大量电流。PWM调光将背光引脚连接到支持PWM输出的GPIO。通过调节PWM的占空比0-255可以无级调节屏幕亮度。在环境光暗时降低亮度既能省电又能保护眼睛。在Arduino中使用analogWrite(pin, brightness)即可实现。驱动芯片功耗模式通过发送命令可以让ST7735S等驱动芯片进入睡眠模式SLPIN, 0x10。在此模式下芯片内部大部分电路关闭功耗可降至微安级别。唤醒则需要发送SLPOUT (0x11)命令并等待一段时间。在长时间不需要显示的场合结合关闭背光和进入睡眠模式可以将整体功耗降到最低。实测经验我测量过一款1.47寸屏背光全亮约3.3V供电时总电流约80mA。关闭背光后电流降至约20mA。再让驱动芯片进入睡眠电流可以降到1mA以下。对于使用小型锂聚合物电池如500mAh的项目合理管理屏幕开关能显著延长续航时间。7. 常见问题排查与硬件调试即使按照教程连接第一次也难免遇到问题。这里梳理一个排查链路。现象一屏幕完全无反应背光也不亮。检查电源用万用表测量屏幕VCC和GND之间的电压确认是否为3.3V或模块标称电压。电流是否足够尝试单独给屏幕供电。检查背光确认BLK引脚是否已正确接到高电平或PWM信号。可以尝试直接用杜邦线将BLK短接到VCC看背光是否亮起。检查复位有些模块需要上电后一个正确的复位脉冲。确保RST引脚在初始化前有一个从高到低再到高的跳变过程。可以在代码开头手动控制该引脚digitalWrite(RST_PIN, HIGH); delay(10); digitalWrite(RST_PIN, LOW); delay(10); digitalWrite(RST_PIN, HIGH); delay(120);。现象二背光亮但屏幕全白、全黑或有杂乱色块。检查SPI通信这是最常见的问题。首先确认SCK、MOSI、CS、DC引脚连接是否正确且牢固。特别是DC引脚接错必然导致无法识别命令和数据。降低SPI频率在初始化代码中将SPI时钟频率如SPI_FREQUENCY从27MHz先降到1MHz或更低排除因布线过长或干扰导致的数据错误。检查初始化序列确认使用的驱动库是否完全兼容你的屏幕型号。不同批次的1.47寸屏其ST7735S的初始化参数可能有细微差别。尝试在库的配置文件中切换TFT_INVERSION_ON/OFF或调整TFT_RGB_ORDER。逻辑分析仪抓包如果以上都不行终极武器是使用逻辑分析仪如Saleae连接SPI线抓取上电初始化过程中的数据流。对照ST7735S数据手册的命令集看发送的命令和参数是否正确。这是定位底层通信问题的金标准。现象三显示内容错位、镜像或颜色异常。调整扫描方向MADCTL修改setRotation()函数的参数0,1,2,3逐一尝试。如果库不支持或无效直接查找并修改驱动库中MADCTL命令对应的参数值。检查颜色格式COLMOD确认库中配置的颜色格式如RGB565与绘图函数输出的数据格式一致。TFT_eSPI库中drawPixel等函数会自动处理格式但如果你直接操作帧缓冲区就必须保证缓冲区数据的排列格式与COLMOD设置匹配。检查字节序Endianness在ESP32等小端序Little-Endian处理器上一个16位的RGB565颜色值如0xF800代表红色在内存中存储为0x00 0xF8低字节在前。而SPI发送通常是先发高字节。TFT_eSPI库的setSwapBytes(true)函数就是用来解决这个问题的它会在发送前交换字节顺序。如果颜色完全不对比如红色显示成浅蓝色可以尝试切换这个设置。玩转一块小屏的乐趣在于从硬件连接到软件驱动从点亮第一颗像素到完成一个流畅界面的完整掌控感。1.47英寸这个尺寸在紧凑性和可视性之间取得了不错的平衡希望这篇从硬件到软件、从原理到踩坑的详细梳理能帮你省去大量摸索的时间。在实际项目中更复杂的挑战可能来自于多任务下的刷新优化、低功耗设计以及与其它传感器的协同但有了这些扎实的基础那些挑战都将成为有趣的扩展。