STM32 ILI9341驱动TFTLCD屏(一)

发布者:美好的人生最新更新时间:2024-03-22 来源: elecfans关键字:STM32  ILI9341 手机看文章 扫描二维码
随时随地手机看文章

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口的初始化函数


static void 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);

[1] [2]
关键字:STM32  ILI9341 引用地址:STM32 ILI9341驱动TFTLCD屏(一)

上一篇:用48脚的STM32驱动16位并口TFT彩屏
下一篇:SD NAND 的 SDIO在STM32上的应用详解(上篇)

推荐阅读最新更新时间:2026-03-25 01:16

STM32 ILI9341驱动TFTLCD(六)LCD画直线
通过前面的学习,已经掌握了LCD显示图片以及显示Gif动画。这些图片其实也可以自己通过写显存,以画画的方式完成。而画画最基本的就是点和线了。 要画一个点,只要取一个点的区域,写该点的显存就可以完成。 void LCD_DrawPoint(u16 x,u16 y,u16 color) { ILI9341_SetPageAddr(y,y); //页地址设置 ILI9341_SetColumnAddr(x,x); //列地址设置 ILI9341_WriteMemory(&color,1); //写点的显存 } 接着进行测试,连续画多个点看最终效果。 主函数 #include stm32f4xx.h #i
[单片机]
<font color='red'>STM32</font> <font color='red'>ILI9341</font><font color='red'>驱动</font><font color='red'>TFTLCD</font><font color='red'>屏</font>(六)LCD画直线
STM32 ILI9341驱动TFTLCD(四)
完成了图片显示,那动画显示也很好完成。因为动画也是由很多张图片组成的。这里以显示Gif动画为例。借助GIF动画分解软件GifSplitter把Gif动画分解成单个图像帧。然后修改图片尺寸,再用Image2Lcd把图片转换为数组。后面的操作就跟图片显示一样了。 GifSplitter分离Gif动画步骤: (1)输入要显示的Gif动画; (2)选择图片输出目录; (3)分离动画。 分解完成后得到了组成Gif动画的12张图片。 由于STM32的flash空间有限,所以只选取前6张图片进行测试。 对生成图片的尺寸进行修改,再用Image2Lcd生成6个数组,将这6个数据依次写入显存并延时一小段时间,就能看到Gif动画的效果了
[单片机]
<font color='red'>STM32</font> <font color='red'>ILI9341</font><font color='red'>驱动</font><font color='red'>TFTLCD</font><font color='red'>屏</font>(四)
STM32 控制lcm液晶ILI9341驱动的液晶驱动程序
/* 选择BANK1-BORSRAM1 连接 TFT,地址范围为0X60000000~0X63FFFFFF * FSMC_A16 接LCD的DC(寄存器/数据选择)脚 * 16 bit = FSMC 对应HADDR * 寄存器基地址 = 0X60000000 * RAM基地址 = 0X60020000 = 0X60000000+2^16*2 = 0X60000000 + 0X20000 = 0X60020000 * 当选择不同的地址线时,地址要重新计算。 */ //#define Bank1_LCD_D ((u32)0x60020000) //Disp Data ADDR //#define Bank1_LCD_C ((u3
[单片机]
STM32驱动WS2811实现渐变色、跑马灯
一、WS2811简介 输出端口耐压12V 芯片内置稳压管,24V以下电源端只需串电阻IC到VDD脚,无需外加稳压管 灰度调节电路(256级灰度可调) 内置信号整形电路,任何一个IC收到信号后经过波形整形后在输出,保证线路波形畸变不会累加 内置上电复位和掉电复位电路 PWM控制端能够实现256级调节,扫描频率不低于400HZ/S 串行接口级联,一根信号线DI完成数据的接收与解码 任意两点传输距离不超过2米无需增加任何电路 当刷新速率30帧/秒时,低速模式级联数不小于512点,高速模式下不小于1024点 数据发送速度可达与400Kbps与800Kbps两种模式 二、通讯协议 数据协议采用单线归零码的通讯方式,
[单片机]
<font color='red'>STM32</font><font color='red'>驱动</font>WS2811实现渐变色、跑马灯
深夜!我偷偷的把室友的STM32换成了GD32
一、什么是GD32 GD32是由北京兆易创新开发的国产32位MCU,基于Arm Cortex- M3/M23/M4内核以及RISC-V内核的32位通用微控制器,与STM32相比,CPU主频更高,内存更多,外设更丰富。其众多产品是以STM32芯片为模板,基于STM32的底层寄存器地址进行正向研发,部分产品可以直接PIN TO PIN替代STM32的芯片,部分型号可以直接以STM32的程序做部分修改后直接烧入进GD32中运行,例如GD32E103、GD32F10x、GD32F30x都是和STM32F10x系列是完全PIN TO PIN兼容的,内部地址寄存器完全兼容,唯一区别只是内核不同,但在使用外设时影响不会很大。 一个大胆的想法
[单片机]
STM32输入捕获
输入捕获是处理器捕获外部输入信号的功能,基于定时器抓取输入信号指定触发方式之间的长度。具体有下面三种触发情况: 1、 上升沿触发 2、 下降沿触发 3、 上下都触发 当触发条件发生后,捕获比较寄存器锁定当前的计数值,如果开启了中断或者DMA,就可以通过中断或DMA及时获得数据进行处理。有时可能遇到上一次触发的标志还没清除,下次触发就发生了,此时会将over-capture标志置位,对于可能出现over-capture的情况,建议先读取数据再清除标志,避免在读取标志后及读取数据前这段时间错过over-capture。 配置输入捕获的步骤: 1. 打开定时器和对应输入引脚的时钟 2. 配置引脚为对应的复用功能 3.
[单片机]
I2C、IIC通讯(填坑作,MPU6050数据读取,STM32主控,附源码)
上图的VCC 接 3.3V,GND接地,SCL和SDA分别接上单片机引脚,并加上上拉电阻,AD0接地。 代码链接:https://pan.baidu.com/s/1AvuMYvgX8Xy8g81S0Ay5Yg 提取码:sce0 初始化单片机引脚,并置1 程序里引脚的变化顺序还有延时的位置一定不要错。 IIC起始信号;SDA置零,等待,SCL置零 写入一次数据,IIC每次写入的数据长度都是8Bit,写入顺序是从最高位写到最低位。 SCL置0,SDA存放数据的最高位,数据左移1位,等待,SCL置1,数据起效,等待。 右移7位:1000 0000会变成0000 0001。(0X80 0X01) 左移1位:1101 000
[单片机]
使用micropython开发STM32
一、前言 MicroPython(官网:https://micropython.org),是Python3编程语言的一个完整软件实现,用C语言编写,被优化于运行在微控制器之上。MicroPython是运行在微控制器硬件之上的完全的Python编译器和运行时系统。提供给用户一个交互式提示符(REPL)来立即执行所支持的命令。除了包括选定的核心Python库,MicroPython还包括了给予编程者访问低层硬件的模块。(摘抄自weact微行工作室)。 用我的理解简单来说,就是使用C语言往单片机里写了一个Python的解释器,再将MicroPython程序脚本保存到单片机(或外部存储器)内,然后由内部的解释器运行脚本代码。优点就是接
[单片机]
小广播
最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

厂商技术中心

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

 
机器人开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2026 EEWORLD.com.cn, Inc. All rights reserved