当前位置: 首页 > news >正文

用STM32F103驱动1.44寸TFT彩屏(ST7735S)显示自定义图片,手把手教你搞定Img2Lcd取模

STM32F103驱动1.44寸TFT彩屏全流程实战:从图片取模到动态显示

第一次在嵌入式设备上看到自己的图片显示出来,那种成就感就像小时候拼好了一艘乐高战舰。本文将带你完整实现从零开始驱动ST7735S屏幕的全过程,重点解决三个核心痛点:SPI通信配置的常见坑点、图片取模的参数玄学、以及显示优化的小技巧。

1. 硬件连接与SPI配置

1.1 硬件清单与引脚映射

需要准备的硬件组件:

  • STM32F103C8T6最小系统板(蓝色药丸版)
  • 1.44寸TFT屏(ST7735S驱动,128x128分辨率)
  • 面包板与杜邦线若干
  • USB转TTL模块(用于串口调试)

关键引脚连接对照表

TFT引脚STM32引脚功能说明
VCC3.3V电源正极
GNDGND电源地
SCLPB13SPI时钟线
SDAPB15SPI数据线
RESPB12复位信号
DCPB11数据/命令选择
CSPB10片选信号
BLKPB1背光控制

注意:部分屏幕的BLK引脚需要上拉电阻,若发现背光不亮,可尝试接10K电阻到3.3V

1.2 SPI模式配置要点

在STM32CubeMX中配置SPI2时,需要特别注意以下参数:

/* SPI2 parameter configuration */ hspi2.Instance = SPI2; hspi2.Init.Mode = SPI_MODE_MASTER; hspi2.Init.Direction = SPI_DIRECTION_2LINES; hspi2.Init.DataSize = SPI_DATASIZE_8BIT; hspi2.Init.CLKPolarity = SPI_POLARITY_LOW; // CPOL=0 hspi2.Init.CLKPhase = SPI_PHASE_1EDGE; // CPHA=0 hspi2.Init.NSS = SPI_NSS_SOFT; hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4; // 18MHz @72MHz主频 hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB; hspi2.Init.TIMode = SPI_TIMODE_DISABLE; hspi2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;

常见问题排查:

  • 若屏幕出现花屏:检查SPI时钟相位(CPHA)设置,ST7735S通常需要CPHA=0
  • 若通信完全失败:用逻辑分析仪捕捉SCL/SDA波形,确认时序符合规格书要求
  • 若显示颜色异常:检查数据格式是否为RGB565(16位色)

2. 屏幕初始化与基础驱动

2.1 初始化序列优化

ST7735S的初始化命令序列较长,但实际项目中只需关注几个关键配置:

void ST7735_Init(void) { // 硬件复位 HAL_GPIO_WritePin(RES_GPIO_Port, RES_Pin, GPIO_PIN_RESET); HAL_Delay(120); HAL_GPIO_WritePin(RES_GPIO_Port, RES_Pin, GPIO_PIN_SET); HAL_Delay(50); // 关键初始化命令 ST7735_WriteCommand(0x11); // Sleep exit HAL_Delay(120); ST7735_WriteCommand(0xB1); // FRMCTR1 ST7735_WriteData(0x01); ST7735_WriteData(0x2C); ST7735_WriteData(0x2D); ST7735_WriteCommand(0x36); // MADCTL ST7735_WriteData(0xC8); // RGB顺序+行地址顺序 ST7735_WriteCommand(0x3A); // COLMOD ST7735_WriteData(0x05); // 16位像素格式 ST7735_WriteCommand(0x29); // Display on }

2.2 显存操作技巧

实现高效屏幕刷新的三个关键函数:

  1. 设置显示窗口函数:
void ST7735_SetWindow(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1) { ST7735_WriteCommand(0x2A); // 列地址设置 ST7735_WriteData(0x00); ST7735_WriteData(x0 + 2); // 偏移补偿 ST7735_WriteData(0x00); ST7735_WriteData(x1 + 2); ST7735_WriteCommand(0x2B); // 行地址设置 ST7735_WriteData(0x00); ST7735_WriteData(y0 + 3); ST7735_WriteData(0x00); ST7735_WriteData(y1 + 3); ST7735_WriteCommand(0x2C); // 内存写入 }
  1. 像素填充优化方案:
void ST7735_FillRect(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t color) { uint8_t buff[64]; // 发送缓冲区 uint16_t cnt = w * h; // 预填充缓冲区 for(uint8_t i=0; i<32; i++) { buff[2*i] = color >> 8; buff[2*i+1] = color & 0xFF; } ST7735_SetWindow(x, y, x+w-1, y+h-1); HAL_GPIO_WritePin(DC_GPIO_Port, DC_Pin, GPIO_PIN_SET); HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_RESET); while(cnt >= 32) { HAL_SPI_Transmit(&hspi2, buff, 64, 10); cnt -= 32; } if(cnt > 0) { HAL_SPI_Transmit(&hspi2, buff, cnt*2, 10); } HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_SET); }
  1. 双缓冲技术实现:
uint16_t frameBuffer[128][128]; // 第二帧缓冲区 void ST7735_Refresh(void) { ST7735_SetWindow(0, 0, 127, 127); HAL_GPIO_WritePin(DC_GPIO_Port, DC_Pin, GPIO_PIN_SET); HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_RESET); for(int y=0; y<128; y++) { HAL_SPI_Transmit(&hspi2, (uint8_t*)frameBuffer[y], 256, 100); } HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_SET); }

3. 图片取模实战指南

3.1 Img2Lcd配置详解

使用Img2Lcd V2.9进行图片转换时,必须注意以下参数组合:

关键配置项

  • 输出数据类型:C语言数组(*.c)
  • 扫描模式:水平扫描
  • 输出灰度:16位真彩色
  • 最大宽度和高度:128x128
  • 包含图像头数据:取消勾选
  • 字节排列方式:小端模式

实测发现:当图片尺寸小于128x128时,勾选"图像缩放"会导致颜色失真,建议提前用Photoshop调整尺寸

3.2 取模参数对照实验

我们测试了不同参数组合下的显示效果:

色彩模式扫描方向显示效果适用场景
RGB565水平扫描最佳彩色照片
RGB555垂直扫描色偏不推荐
灰度水平扫描黑白单色LOGO

3.3 自定义调色板技巧

对于公司LOGO等简单图形,可以手动定义调色板减少存储空间:

// 16色调色板 const uint16_t palette[16] = { 0x0000, // 黑色 0xFFFF, // 白色 0xF800, // 红色 0x07E0, // 绿色 ... // 其他颜色 }; // 4位索引图像数据 const uint8_t logo[] = { 0x01,0x01,0x01,0x02,0x02, 0x01,0x00,0x00,0x02,0x02, ... // 其他图像数据 }; void Draw_PaletteImage(uint8_t x, uint8_t y) { for(int i=0; i<sizeof(logo); i++) { uint16_t color = palette[logo[i] & 0x0F]; frameBuffer[y + i/128][x + i%128] = color; } }

4. 高级显示技巧与优化

4.1 动态刷新优化

通过DMA+SPI实现无阻塞刷新:

// 在CubeMX中启用SPI TX DMA通道 void ST7735_DMA_Refresh(uint16_t* buf, uint32_t len) { ST7735_SetWindow(0, 0, 127, 127); HAL_GPIO_WritePin(DC_GPIO_Port, DC_Pin, GPIO_PIN_SET); HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_RESET); HAL_SPI_Transmit_DMA(&hspi2, (uint8_t*)buf, len*2); // 在传输完成中断中拉高CS }

4.2 伪动画实现方案

在没有硬件加速的情况下,可以通过以下方式实现流畅动画:

  1. 使用脏矩形技术局部刷新
  2. 预先计算帧间差异区域
  3. 采用RLE压缩传输动画帧

示例代码:

typedef struct { uint8_t x, y, w, h; uint8_t* compressedData; } DiffArea; void Update_Animation(DiffArea* diff) { ST7735_SetWindow(diff->x, diff->y, diff->x+diff->w-1, diff->y+diff->h-1); // 解压并发送差异数据 RLE_Decode(diff->compressedData, frameBuffer); }

4.3 性能实测数据

不同刷新方式的性能对比:

刷新方式全屏刷新时间CPU占用率
普通SPI78ms98%
DMA传输62ms12%
差异刷新15ms30%

最后分享一个实际项目中的教训:当屏幕出现随机噪点时,检查电源滤波电容是否足够(建议在VCC和GND之间并联10μF+0.1μF电容)。曾经因为这个问题调试了整整两天,最终发现是电源干扰导致的显示异常。

http://www.jsqmd.com/news/748603/

相关文章:

  • SFMP框架:硬件友好的混合精度量化技术解析
  • 对比直接使用原厂 API 体验 Taotoken 聚合服务在接入便捷性上的优势
  • Qt表格开发避坑指南:QTableView/QTableWidget自适应拉伸的3个常见误区与正确姿势
  • 密评实战:当‘挑战-响应’遇到Wireshark,如何抓包并验证服务端身份?
  • Python低代码插件调试响应超2s?(基于perf + py-spy + eBPF的毫秒级性能归因分析法)
  • 从SystemVerilog信箱到UVM TLM:手把手教你重构一个可重用的验证组件通信层
  • Qwerty Learner:用打字锻炼英语肌肉记忆的终极指南
  • AppStore审核员视角:你的隐私声明和ATT请求为什么对不上?一次讲清Guideline 5.1.2的核心逻辑
  • 从LED闪烁到I2C通信:手把手拆解STM32 GPIO的四种输出模式实战(开漏/推挽详解)
  • 别再手动调图了!用MATLAB R2023b画论文折线图,从数据到投稿级配图一步到位
  • VeLoCity皮肤:为VLC播放器注入全新视觉体验与交互设计的界面革命
  • 告别编译报错:一份给STM32开发者的Arm Compiler 5.06独立安装与Keil集成指南
  • 新手必看:在快马平台动手学js近似数,可视化理解四舍五入与取整
  • Python风控配置即代码(CiC)实践指南:GitOps驱动的审计留痕+自动回滚+变更影响图谱
  • 不止于切片:用CloudCompare的断面工具,为BIM逆向建模和地质分析快速准备剖面数据
  • 造物者的恐惧:Claude的设计者说,她不知道自己创造了什么
  • Nacos 2.0 使用 gRPC 通信端口配置与 1.x 有什么区别
  • 别再只用默认参数了!手把手教你用cryptsetup调优LUKS2加密性能(附benchmark实战)
  • ISAC系统中杂波建模与抑制技术解析
  • 物理模拟KAN架构:边缘计算中的高效非线性处理方案
  • Oracle 19c装完登录报错?手把手教你排查CentOS7下的用户、目录与环境变量三大坑
  • 深入理解I2C协议:通过蓝桥杯PCF8591驱动代码,手把手教你调试单片机通信
  • 2026年托运公司选型全指南:成都工地工具物流托运、成都搬家安能物流公司推荐、成都搬家物流托运公司、成都物流托运公司选择指南 - 优质品牌商家
  • 不止是倍频分频:深入理解Vivado中PLL与MMCM的选择策略与性能差异
  • kkFileView离线安装踩坑全记录:从LibreOffice依赖缺失到中文乱码的完整解决流程
  • 野火/正点原子IMX6ULL开发板LED驱动实战:从寄存器操作到完整驱动加载(附避坑指南)
  • 对比 PHP 7.4 和 PHP 8.0 的数组操作性能差异在哪里?
  • 避开NVMe驱动开发的那些坑:手把手教你正确解析Completion Queue中的状态码(含SCT/SC详解)
  • 别再傻傻分不清了!Modbus RTU、TCP、RTU over TCP/IP 到底啥区别?用Java代码和mbslaveX64一次讲透
  • MiGPT开源项目:让小爱音箱秒变AI语音助手的技术改造指南