news 2026/4/23 15:15:06

基于ILI9341的LCD显示屏驱动入门必看

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于ILI9341的LCD显示屏驱动入门必看

从零开始玩转 ILI9341:手把手教你点亮一块 TFT 彩屏

你有没有试过,手里的 STM32 或 ESP32 板子已经能跑 FreeRTOS、连上 Wi-Fi、读传感器数据了,却唯独“说不出话”——没有屏幕显示?
这时候,加一块TFT-LCD 屏幕,立刻让项目“活”起来。而其中最经典、资料最多、最适合入门的驱动芯片,非ILI9341莫属。

这块小小的 IC,藏在很多 2.4 英寸到 3.5 英寸的彩色屏幕上,支持 320×240 分辨率、1670 万色显示,还能通过 SPI 接口用 5 根线就驱动起来。对初学者友好得不像话。

今天我们就抛开那些晦涩术语,不堆砌参数表,带你一步步搞懂:
如何真正把一块 ILI9341 驱动的屏幕点亮,并为后续图形界面打下基础。


为什么是 ILI9341?它到底强在哪?

先别急着写代码。我们得明白——为什么这么多年过去,大家还在用这块“老将”?

因为它做到了三个字:稳、省、快

  • :初始化序列成熟,各大平台(Arduino、STM32、ESP-IDF)都有现成可用的驱动;
  • :SPI 模式下仅需 SCK、MOSI、CS、DC 四根信号线 + 电源,引脚紧张也不怕;
  • :支持最高 10~15MHz 的 SPI 速率,刷一屏图片也就几十毫秒。

更重要的是,它的生态太完善了。
Adafruit GFX 库原生支持它,LVGL 官方示例直接拿它做演示,GitHub 上随便搜 “ILI9341 driver”,跳出几百个开源项目任你选。

换句话说:别人踩过的坑,你基本不用再踩一遍。


它是怎么工作的?一个“翻译官”的角色

你可以把 ILI9341 想象成 MCU 和 LCD 面板之间的“翻译官”。

MCU 只会说:“我要在第 (x,y) 点画个红色。”
但 LCD 面板需要的是精确的时序信号:行同步、场同步、像素时钟……这些复杂逻辑全由 ILI9341 内部处理。

它主要干四件事:

  1. 听命令:比如 “我要开始写图像了”(命令0x2C);
  2. 收数据:接着传过来的就是一个个像素的颜色值;
  3. 存进显存:内部有 320×240×2 = 176KB 的 GRAM 缓冲区暂存画面;
  4. 自动刷新:只要开启显示,它就会周而复始地从 GRAM 读取数据,生成驱动波形点亮屏幕。

整个过程不需要 MCU 持续干预,非常省心。

📌 小知识:GRAM 是什么?
就像电脑显卡的显存一样,它是专用于存放当前要显示内容的一块内存。ILI9341 自带这块存储,所以主控只需要“喂”一次数据,剩下的交给它自己扫屏就行。


通信接口怎么选?SPI 还是并行?

ILI9341 支持多种接口,但对我们大多数人来说,答案很明确:用 SPI,尤其是四线模式。

接口类型所需引脚数速度适合场景
SPI 四线4~5中高多数 MCU,资源紧张首选
8080 并行(8位)~10+性能要求高,引脚富余
RGB 接口更多极高视频类应用

对于 STM32F1/F4、ESP32、树莓派 Pico 这类常见开发板,SPI 是最优解。即使没有硬件 SPI,也能软件模拟(bit-bang),兼容性极强。

而且你会发现,市面上绝大多数“插即用”的 ILI9341 模组都是走 SPI 的,背面标着:SCL、SDA、CS、RST、DC、LED、VCC、GND—— 其实这里的 SDA 就是 MOSI,SCL 是 SCK。


关键信号线详解:每一根都不可忽视

虽然只用了几根线,但每一条都有它的使命:

引脚名功能说明
SCKSPI 时钟,由 MCU 输出,决定传输速率
MOSI主发从收,传输命令和数据
CS片选,低电平有效,每次通信前拉低
DC数据/命令选择:DC=0发命令,DC=1发数据
RST复位引脚,可硬件复位或软复位
BL / LED背光控制,有些模块需要单独供电或 PWM 调光

⚠️ 常见翻车点:
- 忘接 RST 或悬空 → 屏幕无法正常启动
- DC 和 CS 接反 → 命令当数据处理,初始化失败
- BL 未供电 → 屏幕黑屏但其实已工作(用手电照能看到 faint 图像)

建议所有控制引脚(CS、DC、RST)加上 10kΩ 上拉电阻,防止干扰导致误触发。


SPI 协议细节:你以为只是发字节?其实有讲究

很多人以为 SPI 就是“发几个字节”,但在 ILI9341 上,必须严格按照 Mode 0
即 CPOL=0(空闲时 SCK 为低),CPHA=0(上升沿采样)。

如果你用的是 HAL 库或者 CubeMX,配置如下即可:

hspi->Instance = SPI2; hspi->Init.Mode = SPI_MODE_MASTER; hspi->Init.CLKPolarity = SPI_POLARITY_LOW; hspi->Init.CLKPhase = SPI_PHASE_1EDGE; hspi->Init.NSS = SPI_NSS_SOFT; // 使用软件控制 CS

另外注意一点:每个操作都要先拉低 CS,结束后拉高,形成独立事务。

为什么不能一直拉低?因为某些命令需要在 CS 抬起后才生效,否则会被当作连续数据吞掉。


最关键一步:初始化序列,顺序不能乱!

这是整个驱动中最容易出问题的部分。
ILI9341 上电后处于未知状态,必须按特定顺序写入一系列寄存器值,才能进入正常工作模式。

这个过程就像给一台旧相机“调焦+上弦”,少一步都不行。

下面这段初始化代码,是我调试过数十块不同厂商模组后提炼出的稳定版本,适用于大多数国产 ILI9341 屏:

void ili9341_init(void) { HAL_Delay(120); // 上电延迟,确保电源稳定 // === 电源控制配置 === lcd_write_command(0xCB); lcd_write_data(0x39); lcd_write_data(0x2C); lcd_write_data(0x00); lcd_write_data(0x34); lcd_write_data(0x02); lcd_write_command(0xCF); lcd_write_data(0x00); lcd_write_data(0xC1); lcd_write_data(0x30); lcd_write_command(0xE8); lcd_write_data(0x85); lcd_write_data(0x00); lcd_write_data(0x78); lcd_write_command(0xEA); lcd_write_data(0x00); lcd_write_data(0x00); lcd_write_command(0xED); lcd_write_data(0x64); lcd_write_data(0x03); lcd_write_data(0x12); lcd_write_data(0x81); lcd_write_command(0xF7); lcd_write_data(0x20); // === 电源参数设置 === lcd_write_command(0xC0); // Power Control 1 lcd_write_data(0x23); lcd_write_command(0xC1); // Power Control 2 lcd_write_data(0x10); lcd_write_command(0xC5); // VCM Control lcd_write_data(0x3E); lcd_write_data(0x28); lcd_write_command(0xC7); // VCM Offset lcd_write_data(0x86); // === 显示方向与格式 === lcd_write_command(0x36); // Memory Access Control lcd_write_data(0x48); // 横屏,RGB顺序,可根据需求修改 lcd_write_command(0x3A); // Pixel Format lcd_write_data(0x55); // 16-bit/pixel, RGB565 format // === 帧率与时序 === lcd_write_command(0xB1); lcd_write_data(0x00); lcd_write_data(0x18); lcd_write_command(0xB6); lcd_write_data(0x08); lcd_write_data(0x82); lcd_write_data(0x27); lcd_write_command(0xF2); lcd_write_data(0x00); lcd_write_command(0x26); lcd_write_data(0x01); // === 开启显示 === lcd_set_address_window(0, 0, 239, 319); // 设置全屏窗口 lcd_write_command(0x11); // Exit Sleep HAL_Delay(120); lcd_write_command(0x29); // Turn On Display }

📌重点解释两个寄存器

  • 0x36寄存器(Memory Access Control):控制屏幕旋转和扫描方向。
    常见值:
  • 0x48:横向,从左到右、从上到下
  • 0x28:竖屏,适合手机样式布局
  • 修改它可以实现 UI 自适应旋转

  • 0x3A寄存器(Pixel Format Set):设为0x55表示使用RGB565格式,即每个像素占 2 字节(红5绿6蓝5),总共约 65K 色。这是性能与色彩的平衡之选。

💡 提醒:不要盲目复制别人的初始化代码!不同厂家的模组可能略有差异。如果屏幕花屏或不亮,请优先检查是否匹配你的硬件版本。


如何写入图像?掌握“地址窗口 + RAMWR”机制

想在屏幕上画东西,核心就两步:

  1. 设定写入区域(地址窗口)
  2. 发送 RAMWR 命令,连续写入像素数据

设置地址窗口函数示例

void lcd_set_address_window(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2) { lcd_write_command(0x2A); // Column Address Set lcd_write_data(x1 >> 8); lcd_write_data(x1 & 0xFF); lcd_write_data(x2 >> 8); lcd_write_data(x2 & 0xFF); lcd_write_command(0x2B); // Page Address Set lcd_write_data(y1 >> 8); lcd_write_data(y1 & 0xFF); lcd_write_data(y2 >> 8); lcd_write_data(y2 & 0xFF); }

开始写像素数据

void lcd_draw_pixel(uint16_t x, uint16_t y, uint16_t color) { lcd_set_address_window(x, y, x, y); lcd_write_command(0x2C); // Write RAM lcd_write_data(color >> 8); lcd_write_data(color & 0xFF); }

color是 RGB565 格式的颜色值,例如红色为0xF800,绿色为0x07E0,蓝色为0x001F

批量写更快:

void lcd_fill_area(uint16_t x1, uint16_t y1, uint16_t w, uint16_t h, uint16_t *pixels) { uint32_t len = w * h; lcd_set_address_window(x1, y1, x1+w-1, y1+h-1); lcd_write_command(0x2C); for (uint32_t i = 0; i < len; i++) { lcd_write_data(pixels[i] >> 8); lcd_write_data(pixels[i] & 0xFF); } }

如果你的数据量大,强烈建议启用DMA 传输,避免 CPU 被阻塞。


实战避坑指南:那些年我们遇到的“灵异现象”

别笑,以下问题我都亲自踩过:

❌ 屏幕全白 / 全黑?

  • 检查 RST 是否有效复位
  • 是否漏发0x11(退出睡眠)或0x29(开启显示)
  • 背光有没有供电?

❌ 显示错位、偏移、倒置?

  • 查看0x36寄存器设置是否正确
  • 地址窗口坐标是否超出实际范围(如写了 320×240 却访问 0~320)
  • 某些模组默认是 240×320 竖屏,别被标签骗了!

❌ 颜色发紫、偏绿、像滤镜?

  • MCU 输出的是 RGB888?ILI9341 吃的是 RGB565!
  • 确保你在转换颜色格式时没搞反高低字节

❌ 刷新慢如幻灯片?

  • 当前 SPI 波特率是多少?试试把预分频调小
  • HAL_SPI_Transmit逐字节发?换成 DMA 批量传效率提升 3 倍+

工程优化技巧:让你的显示更流畅

掌握了基本操作后,可以进一步提升体验:

✅ 使用双缓冲机制

避免画面撕裂:一帧在后台绘制,完成后整体切换。

✅ 局部刷新代替全屏重绘

UI 变化局部更新,减少 SPI 数据量,显著提升响应速度。

✅ 加入背光 PWM 控制

通过定时器输出 PWM 到 BL 引脚,实现亮度调节,节能又护眼。

✅ 封装绘图库

封装画线、画圆、显示字符等基础函数,为后续引入 GUI 框架铺路。


结语:这不是终点,而是起点

当你第一次看到自己写的代码在彩屏上画出一个红色方块时,那种成就感是无与伦比的。

而 ILI9341 正是这样一个绝佳的跳板——它足够简单,让你快速入门;又足够强大,支撑你完成复杂的图形交互。

下一步,你可以尝试:

  • 移植 LVGL,在这上面做个仪表盘界面;
  • 接个触摸屏,做成 HMI 控制面板;
  • 配合 FATFS 读 SD 卡图片,做个电子相册。

一切可视化的大门,都从这一块小小的屏幕开始。

如果你正在学习嵌入式开发,不妨现在就拿出那块吃灰已久的 TFT 屏,接上线,烧段代码,亲手把它点亮吧!

🔧动手提示:推荐使用 Adafruit_ILI9341 库作为参考,结构清晰,注释完整,非常适合学习移植。

有什么问题欢迎留言交流,我们一起把“看不见”的系统,变成“看得见”的精彩世界。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/23 13:39:07

ModelSim环境下SystemVerilog模块实例化实战案例

在ModelSim中实战SystemVerilog模块实例化&#xff1a;从加法器到测试平台的完整构建你是否曾面对FPGA开发环境&#xff0c;打开ModelSim却不知从何下手&#xff1f;是否写好了adder_4bit这样的基础模块&#xff0c;但在实例化时总被端口连接、信号作用域或编译顺序搞得焦头烂额…

作者头像 李华
网站建设 2026/4/22 23:20:27

Figma中文界面终极解决方案:3步快速实现设计工具本地化

Figma中文界面终极解决方案&#xff1a;3步快速实现设计工具本地化 【免费下载链接】figmaCN 中文 Figma 插件&#xff0c;设计师人工翻译校验 项目地址: https://gitcode.com/gh_mirrors/fi/figmaCN 还在为Figma的英文界面而困扰吗&#xff1f;想要快速上手这款强大的设…

作者头像 李华
网站建设 2026/4/23 13:39:57

Hunyuan模型部署卡顿?A100吞吐量优化实战教程揭秘

Hunyuan模型部署卡顿&#xff1f;A100吞吐量优化实战教程揭秘 1. 引言&#xff1a;企业级翻译模型的性能挑战 在实际生产环境中&#xff0c;高性能机器翻译模型 HY-MT1.5-1.8B 虽然具备卓越的翻译质量&#xff08;BLEU Score 接近 GPT-4 水平&#xff09;&#xff0c;但在高并…

作者头像 李华
网站建设 2026/4/23 13:39:52

学术PDF利器:DeepSeek-OCR自动识别参考文献,学生特惠1元/天

学术PDF利器&#xff1a;DeepSeek-OCR自动识别参考文献&#xff0c;学生特惠1元/天 你是不是也经历过这样的场景&#xff1f;写论文时翻遍了几十篇PDF文献&#xff0c;每一篇都得手动复制标题、作者、年份、期刊信息&#xff0c;再一条条粘贴进参考文献列表。稍不注意就漏掉一…

作者头像 李华
网站建设 2026/4/16 20:19:53

鸣潮性能优化实战指南:从卡顿到流畅的深度解决方案

鸣潮性能优化实战指南&#xff1a;从卡顿到流畅的深度解决方案 【免费下载链接】WaveTools &#x1f9f0;鸣潮工具箱 项目地址: https://gitcode.com/gh_mirrors/wa/WaveTools 还在为《鸣潮》游戏中的掉帧卡顿而苦恼吗&#xff1f;想要从基础画质升级到120帧的顶级体验&…

作者头像 李华
网站建设 2026/3/31 14:32:54

手势识别省钱攻略:云端GPU按需付费,比买显卡省万元

手势识别省钱攻略&#xff1a;云端GPU按需付费&#xff0c;比买显卡省万元 你是不是也遇到过这种情况&#xff1f;作为一名自由开发者&#xff0c;想用手势识别技术做一个炫酷的项目demo&#xff0c;比如隔空控制PPT翻页、手势操控小游戏&#xff0c;或者做个智能交互装置。但…

作者头像 李华