基于STM32的TFT-LCD各种显示实现(含代码)

基于STM32的TFT-LCD各种显示实现(含代码)

首页战争策略tft10.13更新时间:2024-05-07

前言:TFT-LCD模块作为人们日常生活中常见屏幕类型之一,使用的受众面非常广阔。例如:显示各个传感器数值显示精美界面多级化菜单系统等等都不离不开他的身影。可以说学会TFT-LCD模块是嵌入式开发必须掌握的驱动开发技能之一,同时,也是嵌入式开发调试配置的重要手段与技巧!(文章结尾会有代码开源

实验硬件:STM32F103C8T6;2.4寸TFT-LCD(240×320)

硬件实物图:

引脚连接:

VCC --> 3.3V

GND --> GND

CS --> PB11

Reset --> PB12

DC --> PB10

SDI --> PB15

SCK --> PB13

LED --> PB9(控制LCD背光,可以同PWM调节改变LCD亮暗)

一、TFT-LCD模块简介

TFT-LCDThin Film Transistor)液晶显示屏是薄膜晶体管型液晶显示屏,也就是“真彩”(TFT)。TFT液晶为每个像素都设有一个半导体开关,每个像素都可以通过点脉冲直接控制,因而每个节点都相对独立,并可以连续控制,不仅提高了显示屏的反应速度,同时可以精确控制显示色阶,所以TFT液晶的色彩更真

TFT液晶显示屏的特点是亮度好、对比度高、层次感强、颜色鲜艳,但也存在着比较耗电和成本过高的不足。TFT液晶技术加快了手机彩屏的发展。新一代的彩屏手机中很多都支持65536色显示,有的甚至支持16万色显示,这时TFT的高对比度,色彩丰富的优势就非常重要了。

市面上的TFT-LCD有需要的芯片驱动类型(不同的驱动芯片,其显存大小与其驱动时的传输LCD初始化数据不一样。其显示功能的API函数可以互通),市面上常见的芯片驱动有:ILI9341/ ILI9325/ RM68042/ RM68021/ ILI9320/ ILI9328/ LGDP4531/ LGDP4535/ SPFD5408/ SSD1289/ 1505/ B505/ C505/ NT35310/ NT35510 等。

笔者所用的TFTLCD驱动芯片为常见的ILI9341,这里就以ILI9341给大家为例讲诉(需要其他驱动芯片资料的可以评论留言,笔者基本上市面上常见的都有其代码与资料)。

ILI9341液晶控制器自带显存,其显存总大小为 172800(240*320*18/8),即 18 位模式(26万色)下的显存量。在 16 位模式下,ILI9341 采用 RGB565 格式存储颜色数据(在更高级的32位RGB储存颜色中还有RGBA888,Linux开发板中较为常见),此时 ILI9341的 18 位数据线与 MCU 的 16 位数据线以及 LCD GRAM 的对应关系如图 所示:

这样 MCU 的 16 位数据,最低 5 位代表蓝色中间 6 位为绿色最高 5 位为红色。数值越大,表示该颜色越深。另外,特别注意 ILI9341 所有的指令都是 8 位的(高 8 位无效),且参数除了读写 GRAM 的时候是 16 位,其他操作参数,都是 8 位的,这个和 ILI9320 等驱动器不一样,必须加以注意。

注意:不同的TFT-LCD模块的引脚可能不同,这里原因为该LCD的硬件通讯方式的不同。较为常见的TFTLCD通讯方式有:串行通讯,SPI,LVDS、EDP、MIPI等。(较多的为标红)

笔者这块TFT-LCD模块采用了SPI的通讯方式,故此接下来就以SPI下的TFT-LCD驱动为讲解。

一般 TFTLCD 模块的使用流程如图:

二、SPI简介

SPI 协议是由摩托罗拉公司提出的通讯协议 (Serial Peripheral Interface),即串行外围设备接口,是一种高速全双工的通信总线。它被广泛地使用在 ADC设备LCD 等设备与 MCU 间,要求通讯速率较高的场合。

2.1 SPI通讯系统

SPI 通讯使用3条总线片选线,3 条总线分别为 SCK、MOSI、MISO,片选线为 SS/CS ,它们的作用介绍如下:

(1) SS/CS( Slave Select)

从设备选择信号线,常称为片选信号线,也称为 NSS、CS,以下用 NSS表示。当有多个 SPI 从设备与 SPI 主机相连时,设备的其它信号线 SCK、MOSI 及 MISO同时并联到相同的 SPI 总线上,即无论有多少个从设备,都共同只使用这 3 条总线;而每个从设备都有独立的这一条 NSS 信号线,本信号线独占主机的一个引脚,即有多少个从设备,就有多少条片选信号线。I2C 协议中通过设备地址来寻址、选中总线上的某个设备并与其进行通讯;

而SPI 协议中没有设备地址,它使用 NSS 信号线来寻址,当主机要选择从设备时,把该从设备的 NSS 信号线设置为低电平,该从设备即被选中,即片选有效,接着主机开始与被选中的从设备进行 SPI 通讯。所以 SPI 通讯以 NSS 线置低电平为开始信号,以NSS 线被拉高作为结束信号。(在LCD中,片选线有很多名称,CS,SS,NSS都是指片选

(2) SCK (Serial Clock):

时钟信号线,用于通讯数据同步。它由通讯主机产生,决定了通讯的速率,不同的设备支持的最高时钟频率不一样,如 STM32 的 SPI 时钟频率最大为 fpclk/2,两个设备之间通讯时,通讯速率受限于低速设备

(3) MOSI (Master Output,Slave Input):

主设备输出/从设备输入引脚。主机的数据从这条信号线输出,从机由这条信号线读入主机发送的数据,即这条线上数据的方向为主机到从机。 (与IIC相比,这个就是信号线,由主机向从机发送数据,即SDA

(4) MISO(Master Input,,Slave Output):

主设备输入/从设备输出引脚。主机从这条信线读入数据,从机的数据由这条信号线输出到主机,即在这条线上数据的方向为从机到主机。 (从机向主机发送数据,使用触摸屏时需要这根线。如果单纯使用LCD来显示,这根线可以不接)。

多设备的SPI通讯接线:

SPI 有四种工作模式,通过串行时钟极性(CPOL)和相位(CPHA)的搭配来得到四种工作模式:
①、CPOL=0,串行时钟空闲状态为低电平。
②、CPOL=1,串行时钟空闲状态为高电平,此时可以通过配置时钟相位(CPHA)来选择具
体的传输协议。
③、CPHA=0,串行时钟的第一个跳变沿(上升沿或下降沿)采集数据。
④、CPHA=1,串行时钟的第二个跳变沿(上升沿或下降沿)采集数据。

三、CubexMX配置

1、RCC配置外部高速晶振(精度更高)——HSE;

2、SYS配置:Debug设置成Serial Wire否则可能导致芯片自锁);

3、GPIO配置:将PB9,PB10,PB11,PB12都设置为GPIO_OUTPUT,速度为:Hight;

4、SPI配置:配置使用SPI2作为TFT-LCD通讯方式

5、时钟树配置:

6、工程配置

详细流程可以进群免费领取:

四、代码实现与实验效果4.1 TFT-LCD基础的初始化

以下代码读者朋友可以参考各自TFT-LCD的datasheet文本,不同类型的TFT-LCD屏幕的初始化写入的数据可能不同,但是主要还是对那几个功能寄存器写入对应的数值。

lcd.h

/**************************************************************************** * 名 称:void SPIv_WriteData(u8 Data) * 功 能:STM32_模拟SPI写一个字节数据底层函数 * 入口参数:Data * 出口参数:无 * 说 明:STM32_模拟SPI读写一个字节数据底层函数 ****************************************************************************/ //void SPIv_WriteData(u8 Data) //{ // unsigned char i=0; // for(i=8;i>0;i--) // { // if(Data&0x80) // { // LCD_SDA_SET; //???? // } // else // { // LCD_SDA_CLR; // } // LCD_SCL_CLR; // LCD_SCL_SET; // Data<<=1; // } //} void SPIv_WriteData(u8 Data) { SPI_WriteByte(&Data, 1); } /**************************************************************************** * 名 称:Lcd_WriteIndex(u8 Index) * 功 能:向液晶屏写一个8位指令 * 入口参数:Index 寄存器地址 * 出口参数:无 * 说 明:调用前需先选中控制器,内部函数 ****************************************************************************/ void Lcd_WriteIndex(u8 Index) { LCD_CS_CLR; LCD_RS_CLR; SPIv_WriteData(Index); LCD_CS_SET; } /**************************************************************************** * 名 称:Lcd_WriteData(u8 Data) * 功 能:向液晶屏写一个8位数据 * 入口参数:dat 寄存器数据 * 出口参数:无 * 说 明:向控制器指定地址写入数据,内部函数 ****************************************************************************/ void Lcd_WriteData(u8 Data) { LCD_CS_CLR; LCD_RS_SET; SPIv_WriteData(Data); LCD_CS_SET; } /**************************************************************************** * 名 称:void LCD_WriteReg(u8 Index,u16 Data) * 功 能:写寄存器数据 * 入口参数:Index,Data * 出口参数:无 * 说 明:本函数为组合函数,向Index地址的寄存器写入Data值 ****************************************************************************/ void LCD_WriteReg(u8 Index,u16 Data) { Lcd_WriteIndex(Index); Lcd_WriteData_16Bit(Data); } /**************************************************************************** * 名 称:void Lcd_WriteData_16Bit(u16 Data) * 功 能:向液晶屏写一个16位数据 * 入口参数:Data * 出口参数:无 * 说 明:向控制器指定地址写入一个16位数据 ****************************************************************************/ void Lcd_WriteData_16Bit(u16 Data) { LCD_CS_CLR; LCD_RS_SET; Lcd_WriteData(Data>>8); Lcd_WriteData(Data); LCD_CS_SET; } /**************************************************************************** * 名 称:void Lcd_Reset(void) * 功 能:液晶硬复位函数 * 入口参数:无 * 出口参数:无 * 说 明:液晶初始化前需执行一次复位操作 ****************************************************************************/ void Lcd_Reset(void) { LCD_RST_CLR; HAL_Delay(100); LCD_RST_SET; HAL_Delay(50); } void Lcd_Init(void) { Lcd_Reset(); //Reset before LCD Init. //2.2inch TM2.2-G2.2 Init 20171020 Lcd_WriteIndex(0x11); Lcd_WriteData(0x00); Lcd_WriteIndex(0xCF); Lcd_WriteData(0X00); Lcd_WriteData(0XC1); Lcd_WriteData(0X30); Lcd_WriteIndex(0xED); Lcd_WriteData(0X64); Lcd_WriteData(0X03); Lcd_WriteData(0X12); Lcd_WriteData(0X81); Lcd_WriteIndex(0xE8); Lcd_WriteData(0X85); Lcd_WriteData(0X11); Lcd_WriteData(0X78); Lcd_WriteIndex(0xF6); Lcd_WriteData(0X01); Lcd_WriteData(0X30); Lcd_WriteData(0X00); Lcd_WriteIndex(0xCB); Lcd_WriteData(0X39); Lcd_WriteData(0X2C); Lcd_WriteData(0X00); Lcd_WriteData(0X34); Lcd_WriteData(0X05); Lcd_WriteIndex(0xF7); Lcd_WriteData(0X20); Lcd_WriteIndex(0xEA); Lcd_WriteData(0X00); Lcd_WriteData(0X00); Lcd_WriteIndex(0xC0); Lcd_WriteData(0X20); Lcd_WriteIndex(0xC1); Lcd_WriteData(0X11); Lcd_WriteIndex(0xC5); Lcd_WriteData(0X31); Lcd_WriteData(0X3C); Lcd_WriteIndex(0xC7); Lcd_WriteData(0XA9); Lcd_WriteIndex(0x3A); Lcd_WriteData(0X55); Lcd_WriteIndex(0x36); #if USE_HORIZONTAL Lcd_WriteData(0xE8);//横屏参数 #else Lcd_WriteData(0x48);//竖屏参数 #endif Lcd_WriteIndex(0xB1); Lcd_WriteData(0X00); Lcd_WriteData(0X18); Lcd_WriteIndex(0xB4); Lcd_WriteData(0X00); Lcd_WriteData(0X00); Lcd_WriteIndex(0xF2); Lcd_WriteData(0X00); Lcd_WriteIndex(0x26); Lcd_WriteData(0X01); Lcd_WriteIndex(0xE0); Lcd_WriteData(0X0F); Lcd_WriteData(0X17); Lcd_WriteData(0X14); Lcd_WriteData(0X09); Lcd_WriteData(0X0C); Lcd_WriteData(0X06); Lcd_WriteData(0X43); Lcd_WriteData(0X75); Lcd_WriteData(0X36); Lcd_WriteData(0X08); Lcd_WriteData(0X13); Lcd_WriteData(0X05); Lcd_WriteData(0X10); Lcd_WriteData(0X0B); Lcd_WriteData(0X08); Lcd_WriteIndex(0xE1); Lcd_WriteData(0X00); Lcd_WriteData(0X1F); Lcd_WriteData(0X23); Lcd_WriteData(0X03); Lcd_WriteData(0X0E); Lcd_WriteData(0X04); Lcd_WriteData(0X39); Lcd_WriteData(0X25); Lcd_WriteData(0X4D); Lcd_WriteData(0X06); Lcd_WriteData(0X0D); Lcd_WriteData(0X0B); Lcd_WriteData(0X33); Lcd_WriteData(0X37); Lcd_WriteData(0X0F); Lcd_WriteIndex(0x29); }4.2 SPI函数重写

因为笔者采用了HAL库去使用SPI通讯,所以需要去重写SPI函数

spi.h

spi.c

4.3 TFT-LCD显示的基础函数

TFT-LCD的显示需要依赖几个基础功能函数,这几个函数也时通用的。

总的lcd.h函数

4.4 TFT-LCD显示的API函数

LCDAPI.h

详细代码课进群免费领取!!

嵌入式物联网的学习之路非常漫长,不少人因为学习路线不对或者学习内容不够专业而错失高薪offer。不过别担心,我为大家整理了一份150多G的学习资源,基本上涵盖了嵌入式物联网学习的所有内容。点击下方链接,0元领取学习资源,让你的学习之路更加顺畅!记得点赞、关注、收藏、转发哦!

点击这里找小助理0元领取:

查看全文
大家还看了
也许喜欢
更多游戏

Copyright © 2024 妖气游戏网 www.17u1u.com All Rights Reserved