当前位置: 首页 >关注 > 列表
STM32 ILI9341驱动TFTLCD屏(一)
2023-07-27 16:54:39    纷纭杂谈

TFTLCD是薄膜晶体管液晶显示器。TFTLCD具有亮度好,对比度高,层次感强,颜色鲜艳等优点,是目前最主流的LCD显示器 ,广泛用于电视,手机,电脑,平板等各种的电子产品

LCD原理图


(资料图片)

LCD_CS为芯片选择输入引脚(“低”启用)。

RS用于在并行接口中选择“数据或命令”,当RS为1时,数据被选中;当RS为0时,命令被选中。

WR作为写信号,上升沿写入数据。

RD作为读取信号,上升沿读取数据。

RST为硬复位LCD信号。

D0-D15为16位双向数据线。

BL为背光灯控制信号。

MISO/MOSI/T_PEN/T_CS/CLK为触摸屏接口信号,本节暂不做介绍。

引脚分配为:

LCD_CS:PG12、RS:PF12、WR:PD5、RD:PD4、RESET:PG15、BL:PB15、D0:PD14、D1:PD15、D2:PD0、D3:PD1、D4:PE7、D5:PE8、D6:PE9、D7:PE10、D8:PE11、D9:PE12、D10:PE13、D11:PE14、D12:PE15、D13:PD8、D14:PD9、D15:PD10。

由于开漏模式下电压达不到LCD的要求,所以所有引脚配置为推挽模式,数据输出时切换为输出模式,接收数据时切换为输入模式。

构造时序时经常要对片选信号CS、数据/命令选择RS、写信号WR、读信号RD、背光灯控制BL进行操作,为了更方便编写程序,可以对这几个信号进行宏定义。

#define LCD_CS_H()   do{GPIOG- >BSRRL = 0x1< <12;}while(0)  //片选失效#define LCD_CS_L()   do{GPIOG- >BSRRH = 0x1< <12;}while(0)  //片选有效#define RS_H()       do{GPIOF- >BSRRL = 0x1< <12;}while(0)  //选择为参数状态#define RS_L()       do{GPIOF- >BSRRH = 0x1< <12;}while(0)  //选择为命令状态#define WR_H()        do{GPIOD- >BSRRL = 0x1< <5;}while(0)    //写失效#define WR_L()         do{GPIOD- >BSRRH = 0x1< <5;}while(0)    //写有效#define RD_H()        do{GPIOD- >BSRRL = 0x1< <4;}while(0)    //读失效#define RD_L()        do{GPIOD- >BSRRH = 0x1< <4;}while(0)    //读有效#define BL_H()        do{GPIOB- >BSRRL = 0x1< <15;}while(0)  //关背光灯#define BL_L()        do{GPIOB- >BSRRH = 0x1< <15;}while(0)  //开背光灯

接着编写ILI9341GPIO口的初始化函数

staticvoid ILI9341_GpioInit(){  //1. 开时钟PB/D/E/F/G  RCC- >AHB1ENR  |= 1< <1 | 0XF< <3;  //2. 设置模式(输出)  //  BL:PB15  GPIOB- >MODER &=~ (0x3< <30);  GPIOB- >MODER |=  (0x1< <30);  //  D2:PD0、D3:PD1、RD:PD4、WR:PD5、D13:PD8、D14:PD9、D15:PD10、D0:PD14、D1:PD15  GPIOD- >MODER &=~ (0xf03f0f0f< <0);  GPIOD- >MODER |=  (0x50150505< <0);  //  D4:PE7、D5:PE8、D6:PE9、D7:PE10、D8:PE11、D9:PE12、D10:PE13、D11:PE14、D12:PE15  GPIOE- >MODER &=~ (0xffffc000< <0);  GPIOE- >MODER |=  (0x55554000< <0);  //  RS:PF12  GPIOF- >MODER &=~ (0x3< <24);  GPIOF- >MODER |=  (0x1< <24);  //  LCD_CS:PG12、RESET:PG15  GPIOG- >MODER &=~ (0xc3000000< <0);  GPIOG- >MODER |=  (0x41000000< <0);  //3. 输出类型:推挽输出  //  BL:PB15  GPIOB- >OTYPER &=~ (0x1< <15);  //  D2:PD0、D3:PD1、RD:PD4、WR:PD5、D13:PD8、D14:PD9、D15:PD10、D0:PD14、D1:PD15  GPIOD- >OTYPER &=~ (0xc733< <0);  //  D4:PE7、D5:PE8、D6:PE9、D7:PE10、D8:PE11、D9:PE12、D10:PE13、D11:PE14、D12:PE15  GPIOE- >OTYPER &=~ (0xff80< <0);  //  RS:PF12  GPIOF- >OTYPER &=~ (0x1< <24);  //  LCD_CS:PG12、RESET:PG15  GPIOG- >OTYPER &=~ (0x9000< <0);  //4. 速度(100Mhz)      //  BL:PB15  GPIOB- >OSPEEDR |=  (0x3< <30);  //  D2:PD0、D3:PD1、RD:PD4、WR:PD5、D13:PD8、D14:PD9、D15:PD10、D0:PD14、D1:PD15  GPIOD- >OSPEEDR |=  (0xf03f0f0f< <0);  //  D4:PE7、D5:PE8、D6:PE9、D7:PE10、D8:PE11、D9:PE12、D10:PE13、D11:PE14、D12:PE15  GPIOE- >OSPEEDR |=  (0xffffc000< <0);  //  RS:PF12  GPIOF- >OSPEEDR |=  (0x3< <24);  //  LCD_CS:PG12、RESET:PG15  GPIOG- >OSPEEDR |=  (0xc3000000< <0);  //5. 上下拉(上拉)  //  BL:PB15  GPIOB- >PUPDR &=~ (0x3< <30);  //  D2:PD0、D3:PD1、RD:PD4、WR:PD5、D13:PD8、D14:PD9、D15:PD10、D0:PD14、D1:PD15  GPIOD- >PUPDR &=~ (0xf03f0f0f< <0);  //  D4:PE7、D5:PE8、D6:PE9、D7:PE10、D8:PE11、D9:PE12、D10:PE13、D11:PE14、D12:PE15  GPIOE- >PUPDR &=~ (0xffffc000< <0);  //  RS:PF12  GPIOF- >PUPDR &=~ (0x3< <24);  //  LCD_CS:PG12、RESET:PG15  GPIOG- >PUPDR &=~ (0xc3000000< <0);  //6. 引脚初始电平  LCD_CS_H();    //片选失效  RS_H();        //选择为参数状态  WR_H();        //写失效  RD_H();        //读失效  BL_H();        //关背光灯}

引脚初始化中,由于LCD模块涉及的引脚相对比较多,最好在配置时先写好每个寄存器的注释,方便进行配置,也方便后面进行排错。为方便数据的读写,添加数据引脚的输入输出模式切换函数。

//模式切换为输入void ILI9341_MODE_IN(){  //  D2:PD0、D3:PD1、D13:PD8、D14:PD9、D15:PD10、D0:PD14、D1:PD15  GPIOD- >MODER &=~ (0xf03f000f< <0);  //  D4:PE7、D5:PE8、D6:PE9、D7:PE10、D8:PE11、D9:PE12、D10:PE13、D11:PE14、D12:PE15  GPIOE- >MODER &=~ (0xffffc000< <0);}//模式切换为输出void ILI9341_MODE_OUT(){  //  D2:PD0、D3:PD1、D13:PD8、D14:PD9、D15:PD10、D0:PD14、D1:PD15  GPIOD- >MODER &=~ (0xf03f000f< <0);  GPIOD- >MODER |=  (0x50150005< <0);  //  D4:PE7、D5:PE8、D6:PE9、D7:PE10、D8:PE11、D9:PE12、D10:PE13、D11:PE14、D12:PE15  GPIOE- >MODER &=~ (0xffffc000< <0);  GPIOE- >MODER |=  (0x55554000< <0);}

写数据到ILI9341时要通过判断16位数据来确定输出数据线的高低电平。

void ILI9341_Write(u16 dat){  //D0-D1:PD14/PD15  GPIOD- >ODR  &= 0x3fff;  GPIOD- >ODR  |= ((dat)&0x0003)< <14;  //D2-D3:PD0/PD1  GPIOD- >ODR  &= 0xfffc;  GPIOD- >ODR  |= ((dat >>2)&0x0003)< <0;  //D4-D12:PE7-PE15  GPIOE- >ODR  &= 0X007F;  GPIOE- >ODR  |= ((dat >>4)&0x01ff)< <7;    //D13-D15:PD8-PD10  GPIOD- >ODR  &= ~(0X7< <8);  GPIOD- >ODR  |= (dat >>13)< <8;}

读数据则通过判断数据线输入电平来确定输入的16位数据。

u16 ILI9341_Read(){  u16 temp = 0;  //D0-D1:PD14/PD15  temp |= (GPIOD- >IDR & 0X3)< <0;  //D2-D3:PD0/PD1  temp |= (GPIOD- >IDR & 0X3)< <2;  //D4-D12:PE7-PE15  temp |= (GPIOE- >IDR  > >7)< <4;  //D13-D15:PD8-PD10  temp |= ((GPIOD- >IDR > >8)&0X7)< <13;  return temp;}

由于使用的数据线是16条,所以采用8080时序的16位总线操作进行写命令、读状态、写参数、读参数。由表可以看出片选信号CS低电平时为使能。

根据表格8080时序写出写命令、读状态、写参数、读参数的函数。

//写命令void ILI9341_WriteCmd(u16 cmd){  LCD_CS_L();              //片选有效  RS_L();                  //选择为命令状态  ILI9341_Write(cmd);  WR_L();    //写失效  WR_H();    //写有效  LCD_CS_L();    //片选失效        }//读状态u16 ILI9341_ReadStatus(){  u16 temp = 0;  //模式切换为读  ILI9341_MODE_IN();  LCD_CS_L();              //片选有效  RS_H();                  //选择为参数状态  //rd:PD4  RD_H();          //读失效  RD_L();           //读有效  temp = ILI9341_Read();  LCD_CS_L();    //片选失效                    //模式切换为读  ILI9341_MODE_OUT();  return temp;}//写参数void ILI9341_WriteParam(u16 param){  LCD_CS_L();              //片选有效  RS_H();                  //选择为参数状态  ILI9341_Write(param);  //WR:PD5  WR_L();    //写失效  WR_H();    //写有效  LCD_CS_L();    //片选失效                    }//读参数u16 ILI9341_ReadParam(){  u16 temp = 0;  //模式切换为读  ILI9341_MODE_IN();  LCD_CS_L();              //片选有效  RS_H();                  //选择为参数状态  //rd:PD4  RD_H();          //读失效  RD_L();           //读有效  temp = ILI9341_Read();  LCD_CS_L();    //片选失效                    //模式切换为读  ILI9341_MODE_OUT();  return temp;}

最后,完成ILI9341初始化函数。先初始化GPIO引脚,软件复位,再添加屏幕厂家提供的初始化序列。

void ILI9341_Init(){    u32 i = 0;  //引脚初始化  ILI9341_GpioInit();  ILI9341_WriteCmd(0x01);    //初始化9341  Delay_ms(120); // Delay 120 ms//****Start Initial Sequence(以下代码厂家提供) ****    ILI9341_WriteCmd(0xCF);            //电源设置    ILI9341_WriteParam(0x00);              //默认值    ILI9341_WriteParam(0x81);              //默认值    ILI9341_WriteParam(0X30);            //默认值    ILI9341_WriteCmd(0xED);            //上电序列控制    ILI9341_WriteParam(0x64);    ILI9341_WriteParam(0x03);    ILI9341_WriteParam(0X12);    ILI9341_WriteParam(0X81);    ILI9341_WriteCmd(0xE8);            //驱动时序控制    ILI9341_WriteParam(0x85);    ILI9341_WriteParam(0x01);    ILI9341_WriteParam(0x79);    ILI9341_WriteCmd(0xCB);            //电源控制A    ILI9341_WriteParam(0x39);    ILI9341_WriteParam(0x2C);    ILI9341_WriteParam(0x00);    ILI9341_WriteParam(0x34);    ILI9341_WriteParam(0x02);      ILI9341_WriteCmd(0xF7);            //Pump ratio control     ILI9341_WriteParam(0x20);    ILI9341_WriteCmd(0xEA);            //Driver timing control B    ILI9341_WriteParam(0x00);    ILI9341_WriteParam(0x00);    ILI9341_WriteCmd(0xC0);             //Power control    ILI9341_WriteParam(0x1D);             //VRH[5:0]    ILI9341_WriteCmd(0xC1);             //Power control    ILI9341_WriteParam(0x11);             //SAP[2:0];BT[3:0]    ILI9341_WriteCmd(0xC5);             //VCM control    ILI9341_WriteParam(0x33);    ILI9341_WriteParam(0x34);    ILI9341_WriteCmd(0xC7);             //VCM control2    ILI9341_WriteParam(0Xbe);//    ILI9341_MemoryAccessCtrl(SCAN_MODE,1);      //扫描模式,默认为L2R_U2D,颜色顺序:RGB    ILI9341_WriteCmd(0X36);    ILI9341_WriteParam(0);      ILI9341_WriteCmd(0xB1);    ILI9341_WriteParam(0x00);    ILI9341_WriteParam(0x1B);    ILI9341_WriteCmd(0xB6);             // Display Function Control    ILI9341_WriteParam(0x0A);    ILI9341_WriteParam(0xA2);    ILI9341_WriteCmd(0xF2);             // 3Gamma Function Disable    ILI9341_WriteParam(0x00);    ILI9341_WriteCmd(0x26);             //Gamma curve selected    ILI9341_WriteParam(0x01);    ILI9341_WriteCmd(0xE0);             //Set Gamma    ILI9341_WriteParam(0x0F);    ILI9341_WriteParam(0x23);    ILI9341_WriteParam(0x1F);    ILI9341_WriteParam(0x09);    ILI9341_WriteParam(0x0f);    ILI9341_WriteParam(0x08);    ILI9341_WriteParam(0x4B);    ILI9341_WriteParam(0Xf2);    ILI9341_WriteParam(0x38);    ILI9341_WriteParam(0x09);    ILI9341_WriteParam(0x13);    ILI9341_WriteParam(0x03);    ILI9341_WriteParam(0x12);    ILI9341_WriteParam(0x07);    ILI9341_WriteParam(0x04);    ILI9341_WriteCmd(0XE1);             //Set Gamma    ILI9341_WriteParam(0x00);    ILI9341_WriteParam(0x1d);    ILI9341_WriteParam(0x20);    ILI9341_WriteParam(0x02);    ILI9341_WriteParam(0x11);    ILI9341_WriteParam(0x07);    ILI9341_WriteParam(0x34);    ILI9341_WriteParam(0x81);    ILI9341_WriteParam(0x46);    ILI9341_WriteParam(0x06);    ILI9341_WriteParam(0x0e);    ILI9341_WriteParam(0x0c);    ILI9341_WriteParam(0x32);    ILI9341_WriteParam(0x38);    ILI9341_WriteParam(0x0F);    //数据格式16bit设置    ILI9341_WriteCmd(0x3a);    ILI9341_WriteParam(0x55);              //RGB接口格式16bits/pixel,MCU接口格式16bits/pixel//    ILI9341_ExitSleepMode();              //退出睡眠模式    ILI9341_WriteCmd(0x11);    Delay_ms(120);    ILI9341_WriteCmd(0X2C);      //2CH    for(i=0;i< 240*320;i++)    {      ILI9341_WriteParam(0xffff);          //显示绿屏    }    ILI9341_WriteCmd(0X29);    GPIOB- >BSRRL = 1< <15;                  //开背光  }

最后在主文件调用ILI9341的初始化函数,进行测试。

#include "stm32f4xx.h"#include "core_cm4.h"#include "delay.h"#include "ili9341.h"int main(){  ILI9341_Init();  while(1);}

编译程序并烧入开发板,LCD亮并显示绿色,ILI9341初始化成功。

ILI9341驱动LCD涉及的引脚比较多,所以在配置时一定要细心,一旦出错也会很难排查,所以尽量一次写成。

X 关闭

Copyright ? 2015-2018 青年电气网版权所有  

备案号:皖ICP备2022009963号-20

邮箱: 39 60 291 42@qq.com