从零驱动1.8寸ST7735S SPI彩屏:硬件接线、取模与显示优化实战

张开发
2026/6/10 0:35:55 15 分钟阅读
从零驱动1.8寸ST7735S SPI彩屏:硬件接线、取模与显示优化实战
1. 认识1.8寸ST7735S SPI彩屏第一次拿到这块1.8寸的小屏幕时我完全被它迷住了。128x160的分辨率虽然不高但色彩表现相当不错而且价格只要9.9元性价比简直爆表。这种屏幕在智能手表、小型设备状态显示等场景特别实用。ST7735S是这块屏幕的驱动芯片它通过SPI接口与主控通信。SPI的优势是接线简单只需要4根数据线MOSI、MISO、SCLK、CS加上几根控制线DC、RESET、BLK就能工作。实测下来SPI模式下刷新率能达到60Hz以上完全满足大多数嵌入式项目的需求。这块屏幕有几种常见版本合宙、中景园、金逸晨的模块我都用过。虽然引脚定义可能略有不同但驱动方式基本一致。最让我惊喜的是这些厂商都提供了完整的资料包包含驱动例程、取模工具和详细教程这对新手特别友好。2. 硬件接线实战2.1 引脚定义详解以合宙的1.8寸屏为例8针蓝板模块的引脚排列如下GND电源地VCC3.3V电源注意绝对不能接5VSCLSPI时钟线接主控SCLKSDASPI数据线接主控MOSIRES复位信号低电平有效DC数据/命令选择高电平数据低电平命令CS片选信号低电平有效BLK背光控制可接PWM调光我在ESP32C3上测试时接线是这样的#define PIN_NUM_MISO -1 // 不需要MISO #define PIN_NUM_MOSI 7 // SDA #define PIN_NUM_CLK 6 // SCL #define PIN_NUM_CS 10 // CS #define PIN_NUM_DC 3 // DC #define PIN_NUM_RST 4 // RES #define PIN_NUM_BCKL 5 // BLK2.2 常见接线问题排查第一次接线最容易犯三个错误电源接错一定要确认是3.3V我有次不小心接到5V屏幕瞬间发烫幸好没烧坏。引脚接反特别是SCL和SDA容易搞混如果屏幕全白或全黑先检查这两根线。忘记接背光BLK引脚如果不接屏幕会完全没显示容易误以为驱动失败。用万用表测量各引脚电压是个好习惯VCC正常应在3.2-3.3V之间RESET上电时应有个从低到高的跳变DC会在数据传输时频繁变化3. 驱动移植与初始化3.1 移植官方驱动库从中景园的资料包里找到lcd_init.c和lcd_init.h这是驱动核心。移植时要注意三点修改引脚定义// 根据实际接线修改这些宏定义 #define LCD_SCLK_Clr() GPIO_ResetBits(GPIOA,GPIO_Pin_0) #define LCD_SCLK_Set() GPIO_SetBits(GPIOA,GPIO_Pin_0) // ...其他引脚类似调整延时函数 不同主控的延时函数不同需要替换delay.h中的实现。比如在ESP32上void LCD_Delay(uint32_t ms) { vTaskDelay(ms / portTICK_PERIOD_MS); }初始化序列优化 官方驱动里的初始化命令序列可能比较保守实测可以精简// 删减后的初始化序列 static const uint8_t init_cmds[] { 0x01, 0x80, // Soft reset 0x11, 0x80, // Sleep out 0x3A, 0x81, 0x05, // 16-bit color // ...其他必要命令 };3.2 解决白边偏移问题这是ST7735S的经典问题表现为屏幕四周有白边或显示偏移。根本原因是驱动芯片的默认行列地址设置有问题。修改LCD_Address_Set函数void LCD_Address_Set(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2) { // 合宙屏幕需要2的偏移修正 x1 2; x2 2; y1 3; y2 3; LCD_WR_REG(0x2A); LCD_WR_DATA(x18); LCD_WR_DATA(x10xFF); LCD_WR_DATA(x28); LCD_WR_DATA(x20xFF); LCD_WR_REG(0x2B); LCD_WR_DATA(y18); LCD_WR_DATA(y10xFF); LCD_WR_DATA(y28); LCD_WR_DATA(y20xFF); LCD_WR_REG(0x2C); }不同厂商的屏幕偏移量可能不同建议先用测试程序全屏填充颜色观察边界位置再调整。4. 汉字与图像显示实战4.1 使用PCtoLCD2002取模显示汉字需要先取模。打开PCtoLCD2002软件设置参数点阵格式阴码取模方式逐列式取模走向低位在前输出格式C51格式生成字模代码// 24x24的电字 const unsigned char electricity[] { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x1F,0xFF,0xE0,0x10,0x00,0x20,0x10,0x00, 0x20,0x10,0x00,0x20,0x10,0x00,0x20,0x10, 0x00,0x20,0x1F,0xFF,0xE0,0x10,0x00,0x20, 0x10,0x00,0x20,0x10,0x00,0x20,0x10,0x00, 0x20,0x10,0x00,0x20,0x1F,0xFF,0xE0,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 };4.2 图片显示优化技巧显示图片时最容易遇到内存不足问题。我的解决方案是使用Image2LCD软件取模选择16位色(RGB565)将大图片分割成多个小图块使用PROGMEM存储对于AVR或const修饰符示例代码// 40x40的LOGO图片 const uint16_t gImage_logo[1600] { 0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF, // ...其他像素数据 }; void show_image(uint16_t x, uint16_t y, uint16_t w, uint16_t h, const uint16_t *img) { LCD_Address_Set(x, y, xw-1, yh-1); for(uint32_t i0; iw*h; i) { LCD_WR_DATA(img[i]); } }5. 性能优化技巧5.1 SPI时钟速度优化ST7735S最高支持15MHz的SPI时钟但实际要根据主控性能调整。测试方法// ESP32设置SPI模式 spi_bus_config_t buscfg { .miso_io_num PIN_NUM_MISO, .mosi_io_num PIN_NUM_MOSI, .sclk_io_num PIN_NUM_CLK, .quadwp_io_num -1, .quadhd_io_num -1, .max_transfer_sz 4096, }; spi_device_interface_config_t devcfg { .clock_speed_hz 15*1000*1000, // 从10MHz开始测试 .mode 0, .spics_io_num PIN_NUM_CS, .queue_size 7, };5.2 双缓冲与局部刷新对于动态显示可以采用两种优化策略双缓冲准备两块显存交替写入和刷新局部刷新只更新变化区域实现局部刷新的关键代码void LCD_UpdateArea(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2) { LCD_Address_Set(x1, y1, x2, y2); spi_device_queue_trans(spi, trans, portMAX_DELAY); } // 实际调用示例 LCD_DrawRect(10,10,50,50,RED); // 绘制矩形 LCD_UpdateArea(10,10,50,50); // 只刷新这个区域6. 常见问题解决方案6.1 显示花屏排查花屏通常有三种原因电源不稳在VCC和GND之间加个100uF电容SPI干扰缩短接线长度或降低时钟速度初始化时序问题确保复位信号满足时序要求我的调试步骤先用纯色填充测试检查SPI信号质量用逻辑分析仪重新校准初始化延时6.2 低功耗设计对于电池供电设备动态调整背光PWM控制BLK引脚void set_backlight(uint8_t brightness) { ledcWrite(0, brightness); // ESP32的LEDC功能 }睡眠模式当不需要显示时LCD_WR_REG(0x10); // 进入睡眠模式降低刷新率静态内容可以设为1Hz刷新7. 进阶应用实例7.1 简易UI框架实现基于ST7735S实现简单按钮和菜单typedef struct { uint16_t x,y,w,h; char *text; void (*action)(); } Button; void draw_button(Button btn) { LCD_Fill(btn.x, btn.y, btn.xbtn.w, btn.ybtn.h, BLUE); LCD_ShowString(btn.x5, btn.y5, (uint8_t*)btn.text, WHITE, BLUE, 16, 0); } // 使用示例 Button btn1 {10,10,80,30,确定, on_ok}; draw_button(btn1);7.2 波形显示优化用这块屏幕做示波器显示时有两个技巧使用直接写屏模式加速void draw_waveform(uint16_t *points, uint16_t count) { LCD_Address_Set(0, 0, LCD_W-1, LCD_H-1); for(int i0; icount; i) { LCD_WR_DATA(points[i]); } }网格背景预处理提前生成带网格的背景图刷新时只需叠加波形数据经过这些优化我在ESP32C3上实现了20fps的实时波形显示完全满足教学级示波器的需求。这块9.9元的小屏幕经过合理优化后表现远超预期。

更多文章