1. 项目概述
最近在咸鱼淘到一批超便宜的2元液晶屏,带触摸功能,型号是GC9306。这种240*240分辨率的屏幕虽然规格不高,但对于嵌入式开发学习和小型项目来说性价比极高。屏幕采用SPI半双工通信模式,配合STM32驱动可以实现丰富的显示效果。
在实际调试过程中,我发现GC9306的数据手册有些细节不够明确,特别是时序控制和寄存器配置部分。经过反复测试,终于摸清了这块屏幕的驱动方法。下面就把完整的实现过程分享给大家,包括硬件连接、SPI配置、初始化流程和显示控制等关键环节。
2. 硬件连接与SPI配置
2.1 引脚定义与接线
GC9306液晶屏的接口比较简单,主要需要连接以下信号线:
- RST:复位引脚,低电平有效,正常工作时需保持高电平
- NSS:片选信号,低电平选中
- SPI_CLK:SPI时钟线
- SPI_MOSI:主出从入数据线(在GC9306上标记为SDA)
- D/C:数据/命令选择线,低电平表示命令,高电平表示数据
注意:GC9306采用半双工SPI模式,这意味着同一时间只能进行单向数据传输。这与标准SPI全双工模式有所不同,需要在软件实现上特别注意。
2.2 SPI模式配置
在STM32CubeMX中配置SPI时,需要选择以下参数:
- Mode:Half-Duplex Master(半双工主模式)
- NSS:Software NSS Management(软件控制片选)
- Data Size:8-bit
- First Bit:MSB First
- Clock Polarity:Low(空闲时SCLK为低电平)
- Clock Phase:1 Edge(数据在时钟上升沿采样)
波特率预分频可以根据实际需求设置,测试发现GC9306对SPI时钟频率要求不高,从低速到高速都能正常工作。
3. 通信协议解析
3.1 基本通信时序
GC9306的SPI通信遵循以下基本时序:
- 片选激活:NSS拉低,开始通信
- 命令阶段:D/C拉低,通过SPI发送1字节命令
- 数据阶段(如有参数):
- D/C拉高
- 发送或接收数据字节
- 片选释放:NSS拉高,结束通信
3.2 命令类型分析
GC9306的命令主要分为三类:
- 单字节命令:仅发送命令字节,无后续参数(如0x11退出休眠)
- 带参数命令:命令后跟随1个或多个数据字节(如0x2A设置列地址)
- 读取命令:发送命令后需要读取返回数据(如0x04读取ID)
重要提示:对于读取命令,必须保持NSS在整个读取过程中为低电平。如果使用硬件NSS控制,HAL库会在每次传输后自动拉高NSS,这将导致读取失败。因此必须使用软件控制NSS。
3.3 读取ID异常问题
在读取屏幕ID时,我遇到了一个有趣的现象:
- 发送0x04命令读取4字节ID
- 预期返回值:0x00009306
- 实际返回值:0x00004983
- 解决方法:将结果左移一位即可得到正确ID
这个问题可能与GC9306内部的数据对齐方式有关,虽然不影响正常使用,但值得注意。
4. 屏幕初始化流程
4.1 基本初始化步骤
完整的屏幕初始化需要执行以下命令序列:
c复制void dsp_GC9306_Init(void)
{
HAL_GPIO_WritePin(GC9306_CS_GPIO_Port, GC9306_CS_Pin, GPIO_PIN_RESET);
// 设置显示方向和数据格式
WriteComm(0x36);
WriteData(0x08); // BGR格式
// 设置像素格式
WriteComm(0x3a);
WriteData(0x05); // 16位RGB565
// 设置列显示范围
WriteComm(0x2a);
WriteData(0x00);
WriteData(0x00);
WriteData(0x00);
WriteData(239); // 240列(0-239)
// 设置行显示范围
WriteComm(0x2b);
WriteData(0x00);
WriteData(0x00);
WriteData(0x00);
WriteData(239); // 240行(0-239)
// 退出睡眠模式
WriteComm(0x11);
HAL_Delay(120); // 必须的延时
// 打开显示
WriteComm(0x29);
// 关闭部分显示
WriteComm(0x13);
// 关闭反显
WriteComm(0x21);
HAL_GPIO_WritePin(GC9306_CS_GPIO_Port, GC9306_CS_Pin, GPIO_PIN_SET);
}
4.2 关键命令详解
-
0x36 - 显示方向控制
- 参数0x08选择BGR格式(而非RGB)
- 这个设置必须与图像转换软件保持一致,否则会出现颜色异常
-
0x3A - 接口像素格式
- 参数0x05表示16位RGB565格式
- 也可以选择18位RGB666,但会降低传输效率
-
0x2A/0x2B - 设置显示窗口
- 通过4个参数设置行列地址范围
- 合理设置可以只刷新屏幕部分区域,提高效率
-
0x11 - 退出睡眠
- 发送后必须延时120ms,等待屏幕稳定
-
0x29 - 打开显示
- 在此之前的所有操作都不会在屏幕上显示
5. 图像显示实现
5.1 基本显示函数
c复制void dsp_GC9306_display(void)
{
HAL_GPIO_WritePin(GC9306_CS_GPIO_Port, GC9306_CS_Pin, GPIO_PIN_RESET);
// 启动内存写入
WriteComm(0x2C);
HAL_GPIO_WritePin(GC9306_DC_GPIO_Port, GC9306_DC_Pin, GPIO_PIN_SET);
// 逐行发送图像数据
for(uint16_t hang=0; hang<240; hang++)
{
HAL_SPI_Transmit(&hspi2, gImage_tupian2+hang*240*2, 240*2, 100000);
}
HAL_GPIO_WritePin(GC9306_CS_GPIO_Port, GC9306_CS_Pin, GPIO_PIN_SET);
HAL_Delay(1000);
}
5.2 图像数据准备
显示图像前,需要将图片转换为RGB565格式的数组。推荐使用Image2Lcd软件进行转换,设置参数如下:
- 输出数据类型:C语言数组
- 扫描模式:水平扫描
- 输出灰度:16位真彩色
- 最大宽度和高度:240
- 字节排列:C语言格式
特别注意:软件中的颜色设置必须与屏幕初始化时的0x36命令一致。如果屏幕设置为BGR格式,软件也必须选择BGR输出,否则会出现颜色错乱。
6. 常见问题与解决方法
6.1 屏幕无任何显示
可能原因及解决方法:
-
电源问题
- 检查VCC和GND连接
- 确认背光是否正常
-
复位问题
- 确保RST引脚已正确上拉
- 上电后应有复位脉冲
-
初始化顺序错误
- 必须按照:退出睡眠→延时→打开显示的顺序
- 缺少延时会导致初始化不完整
-
SPI通信失败
- 用逻辑分析仪检查SPI信号
- 确认NSS、D/C时序正确
6.2 显示颜色异常
可能原因:
-
像素格式不匹配
- 检查0x3A命令设置的格式与图像数据是否一致
- RGB565和RGB666不要混用
-
颜色顺序错误
- 0x36命令设置的BGR/RGB格式必须与图像数据匹配
- 在Image2Lcd中调整输出格式
-
反显模式影响
- 某些屏幕需要关闭反显(0x21命令)
- 尝试发送或不发送这个命令看效果
6.3 读取操作失败
解决方法:
-
确保使用软件NSS控制
- 硬件NSS会在每次传输后自动拉高,破坏读取时序
-
保持CS在整个读取过程为低
- 读取多字节数据时CS不能中途拉高
-
检查半双工模式设置
- 必须选择Half-Duplex模式
- 全双工模式无法正常工作
7. 性能优化建议
-
使用DMA传输
- 对于全屏刷新,可以配置SPI DMA提高效率
- 减少CPU占用,特别在需要频繁刷新的场景
-
局部刷新优化
- 通过0x2A/0x2B命令设置只刷新变化区域
- 大幅减少数据传输量
-
双缓冲机制
- 在内存中准备下一帧图像
- 切换时只需发送更新命令,减少视觉闪烁
-
合理设置SPI时钟
- 过高的时钟可能导致通信不稳定
- 建议从低速开始测试,逐步提高
在实际项目中,我测试发现GC9306虽然价格低廉,但显示效果和响应速度都相当不错。通过合理的软件优化,完全可以满足大多数嵌入式显示需求。特别是在SPI时钟设置为18MHz时,全屏刷新率可以达到15fps左右,对于非视频应用已经足够流畅。