一、ST7789V-LCD液晶显示
1,一种计算机的I/O设备,即输入输出设备;
2,数据传递结构,光线的传递通过偏光片进行调整,最终传递到滤光片上,进而不同RGB数据点,即像素点;
3, LCD显示器的关键参数
①像素:显示器的像素指它成像最小的点
②分辨率:像素点的个数的乘积,单位面积的像素点越多,分辨率越高
③色彩深度:每个像素点能表示多少种颜色,一般用“位”(bit)来表示,两种形式RGB565\RGB888,两种形式。其中,RGB565由于刚好是16bit,容易进行数据传递和解析,采用的相对更多,后面持续也会采用这种形式;
④点距:分辨率越高,则点距越小,画质越细腻;
4,LCD的控制原理
①两种主要的形式,F1芯片 ---通过8080传递数据和指令-----传递给液晶芯片控制器-----芯片控制器传递RGB控制液晶面板显示对应数据;
另外一种,F429为例,内部集成芯片控制单元,直接输出RGB接口信号给到液晶面板
本文采用相对简单的F103系列
5,液晶控制的外部控制接口
①由于采用液晶控制器外置在控制器上的形式,所以对于STM32F103来说,只需要负责把相应的指令和数据传递给液晶控制器即可,具体后面液晶控制器怎么负责在屏幕的展示,我们暂时不需要考虑;
液晶控制器使用8080接口与单片机通讯,图中液晶面板引出的FPC信号线即8080接口,且控制器中包含有显存,单片机把要显示的数据通过引出的8080接口发送到液晶控制器,这些数据会被存储到它内部的显存中,然后液晶控制器不断把显存的内容刷新到液晶面板,显示内容。
②F103和ST7789V-LCD液晶控制的交互接口
1-控制器根据自身的IM[3:0]信号线电平决定它与MCU的通讯方式,它本身支持SPI及8080通讯方式。本文使用8080接口通讯
2-像素点的数据采用RGB565通讯,2个字节
3-通讯的内容主要包括命令和显存数据,显存数据即各个像素点的RGB565内容;命令是指对显示芯片的的控制指令,MCU可通过8080接口发送命令编码的工作方式,例如复位指令、设置光标指令、睡眠模式指令等等
③通讯接口的信号线功能详解,看下图即可
这边主要说明DCX信号线:
在低电平时刻,传递的LCD_DB信号会被认为是控制信号;
高电平,传递的LCD_DB会被认为是数据信号;
④控制数据时序
CSX:片选,低有效
RESX:复位引脚,低有效
DCX:数据、命令指令
WRX:写使能
RDX:读使能
D:数据
下图为写时序:
下图为读时序,每次RDX低电平有效
至此,液晶控制模块基本知识介绍完毕,下面进入FSMC模块
二、FSMC模块
FMSC模块的基本介绍这边不说,可以看下我上一篇,这边主要讲FSMC如何实现8080通讯,与液晶控制器进行交互
1,FSMC接线接口与液晶控制器接口对比
主要差别在于FSMC接口:DCX接口和地址总线,其余都是一样
这就需要借用FSMC地址接口,传递出对应DCX信号;
2,FSMC控制时序(模式B)和液晶控制器的时序对比
时序相同,那么主要是地址线和CSX信号线的差异
3,解决 CSX使能线问题
1-FSMC的地址信号线A[25:0]与8080的数据/命令选择线D/CX有区别。而对于D/CX线,它为高电平的时候表示数值,为低电平的时候表示命令,如果能使用FSMC的A地址线根据不同的情况产生对应的电平,那么就完全可以使用FSMC来产生8080接口需要的时序了
2-可以把FSMC的A0地址线(也可以使用其它A1/A2等地址线)与ILI9341芯片8080接口的D/CX信号线连接,那么当A0为高电平时(即D/CX为高电平),数据线D[15:0]的信号会被ILI9341理解为数值,若A0为低电平时(即D/CX为低电平),传输的信号则会被理解为命令
3-实际由于16位地址传递的问题,由于地址转化的关系HADDR转化到实际FSMC地址传递,会有所差异(ps:这一块在控制SRAM时刻,不会产生影响。但是通过单独引脚控制时刻,就会产生地址位的偏移)
会产生一个数据位的偏移,所以如果是控制数据位0,则实际在地址上要控制bit1;
例如DCX接线A23引脚,则需要控制bit24来实现转化;
4,存储器类型和对应FSMC地址数据段
1-存储器类型:NORFLASH
2-地址空间
3- 对应A23调整,csx地址线,即对应bit24
#define LCD_sendDATA 0x6D000000
#define LCD_sendCMD 0x6C000000
5-FSMC初始化结构体
关于FSMC只介绍关键参数:
①FSMC结构初始化主要分为两个模块,时序初始化、整体FSMC初始化
1- FSMC结构初始化主要分为两个模块,时序初始化、整体FSMC初始化
配置好时序结构体后,再在整体初始化结构体中,进行地址传递,一起进行初始化
以上,fsmc对应LCD显示屏控制的核心逻辑已经介绍完毕,下面进入代码模块
三、代码模块
1,整体逻辑
①初始化对应GPIO端口
②初始化FSMC
③初始化LCD模块
④初始化发送数据、发送指令、接受数据模块
⑤显示窗口开辟
⑥RGB888数据转化RGB565函数建立
⑦矩形图形显示
ps:能够显示一个矩形,基本等于可以进行LCD驱动了,至于显示斜直线、圆等图形全部都是数学关系的转化;
2,正式进入代码模块
①初始化对应GPIO端口
FSMC模块引脚全部设置为复用推挽输出;
背光模块和复位不属于FSMC,属于GPIO模块,直接推挽输出;
void lcd_gpio_config(void)
{
//开启GPIO时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD
|RCC_APB2Periph_GPIOE|RCC_APB2Periph_GPIOG,ENABLE);
//配置GPIO
//先配置FSMC数据信号线 D0-D15 ,复用推挽
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_14;
GPIO_Init( GPIOD, &GPIO_InitStruct);//D0
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_15;
GPIO_Init( GPIOD, &GPIO_InitStruct);//D1
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_0;
GPIO_Init( GPIOD, &GPIO_InitStruct);//D2
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_1;
GPIO_Init( GPIOD, &GPIO_InitStruct);//D3
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_7;
GPIO_Init( GPIOE, &GPIO_InitStruct);//D4
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_8;
GPIO_Init( GPIOE, &GPIO_InitStruct);//D5
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_9;
GPIO_Init( GPIOE, &GPIO_InitStruct);//D6
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_10;
GPIO_Init( GPIOE, &GPIO_InitStruct);//D7
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_11;
GPIO_Init( GPIOE, &GPIO_InitStruct);//D8
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_12;
GPIO_Init( GPIOE, &GPIO_InitStruct);//D9
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_13;
GPIO_Init( GPIOE, &GPIO_InitStruct);//D10
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_14;
GPIO_Init( GPIOE, &GPIO_InitStruct);//D11
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_15;
GPIO_Init( GPIOE, &GPIO_InitStruct);//D12
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_8;
GPIO_Init( GPIOD, &GPIO_InitStruct);//D13
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_9;
GPIO_Init( GPIOD, &GPIO_InitStruct);//D14
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_10;
GPIO_Init( GPIOD, &GPIO_InitStruct);//D15
//配置相应FSMC控制引脚,复用推挽模式
// * FSMC_NOE :LCD-RD
// * FSMC_NWE :LCD-WR
// * FSMC_NE1 :LCD-CS
// * FSMC_A16 :LCD-DC 地址线*****
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_2;
GPIO_Init( GPIOE, &GPIO_InitStruct);// 地址线 A16 重要!
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_12;
GPIO_Init( GPIOG, &GPIO_InitStruct);// cs片选
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_5;
GPIO_Init( GPIOD, &GPIO_InitStruct);// WR 写使能
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_4;
GPIO_Init( GPIOD, &GPIO_InitStruct);// RD 读
//单独配置 RST BK引脚,推挽模式
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_11;
GPIO_Init( GPIOG, &GPIO_InitStruct);//复位引脚
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_6;
GPIO_Init( GPIOG, &GPIO_InitStruct);//背光引脚
}
②初始化FSMC
关键点:1-两个结构体;2-FSMC模式B;
3-地址区域bank1-sram4;
4-地址建立周期、数据建立周期
5-16位数据传递
6-非拓展模式
void LCD_FSMC_config(void)
{
//定义两个结构体,一个是时序结构体、一个是整体fsmc模块结构体
//先开启时钟
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_FSMC,ENABLE);//开启fsmc时钟
//先配置读写时序结构体
FSMC_NORSRAMTimingInitTypeDef readWriteTiming;
readWriteTiming.FSMC_AccessMode=FSMC_AccessMode_B;//控制sram选择模式B
readWriteTiming.FSMC_AddressHoldTime=0x00;//地址保持时间0
//地址建立时间(ADDSET)为1个HCLK 1/72M=14ns,addset+1
readWriteTiming.FSMC_AddressSetupTime=0x01;
readWriteTiming.FSMC_BusTurnAroundDuration=0;
readWriteTiming.FSMC_CLKDivision=0;
readWriteTiming.FSMC_DataLatency=0x00; //这三个,模式B未用到
//数据保持时间(DATAST)+ 1个HCLK = 3/72M=42ns(对EM的SRAM芯片)
readWriteTiming.FSMC_DataSetupTime=0x04;
//下面进行FSMC-SRAM初始化
FSMC_NORSRAMInitTypeDef FSMC_NORSRAMInitStruct;
//SRAM的地址区域在bank1-SRAM3
FSMC_NORSRAMInitStruct.FSMC_Bank= FSMC_Bank1_NORSRAM4 ;
//异步,不适用突发模式
FSMC_NORSRAMInitStruct.FSMC_BurstAccessMode=FSMC_BurstAccessMode_Disable ;
//等待时间
FSMC_NORSRAMInitStruct.FSMC_AsynchronousWait=FSMC_AsynchronousWait_Disable ;
//数据总线和地址总线不复用
FSMC_NORSRAMInitStruct.FSMC_DataAddressMux=FSMC_DataAddressMux_Disable ;
//扩展模式不开启,读写时序保持一种
FSMC_NORSRAMInitStruct.FSMC_ExtendedMode=FSMC_ExtendedMode_Disable ;
//数据宽度16位
FSMC_NORSRAMInitStruct.FSMC_MemoryDataWidth=FSMC_MemoryDataWidth_16b ;
//存储器类型 SRAM
FSMC_NORSRAMInitStruct.FSMC_MemoryType=FSMC_MemoryType_NOR ;
FSMC_NORSRAMInitStruct.FSMC_WaitSignal=FSMC_WaitSignal_Disable ;
FSMC_NORSRAMInitStruct.FSMC_WaitSignalActive=FSMC_WaitSignalActive_BeforeWaitState ;
FSMC_NORSRAMInitStruct.FSMC_WaitSignalPolarity=FSMC_WaitSignalPolarity_Low ;
FSMC_NORSRAMInitStruct.FSMC_WrapMode=FSMC_WrapMode_Disable;
FSMC_NORSRAMInitStruct.FSMC_WriteBurst=FSMC_WriteBurst_Disable ;
//写使能
FSMC_NORSRAMInitStruct.FSMC_WriteOperation=FSMC_WriteOperation_Enable ;
FSMC_NORSRAMInitStruct.FSMC_ReadWriteTimingStruct=&readWriteTiming;
//扩展模式有效
FSMC_NORSRAMInitStruct.FSMC_WriteTimingStruct=&readWriteTiming;
FSMC_NORSRAMInit(&FSMC_NORSRAMInitStruct);
//启动
FSMC_NORSRAMCmd( FSMC_Bank1_NORSRAM4,ENABLE);
}
③初始化LCD模块1
void LCDconfig(void)
{
lcd_gpio_config();
LCD_FSMC_config();
//复位LCD
GPIO_ResetBits(GPIOG,GPIO_Pin_11);//低使能复位
LCD_Delay ( 0xAFF );
GPIO_SetBits(GPIOG,GPIO_Pin_11);
LCD_Delay ( 0xAFF );
//开启背光,低电平点亮
GPIO_ResetBits(GPIOG,GPIO_Pin_6);
}
④初始化LCD模块2
void LCD_init(void)
{
/* Power control B (CFh) */
LCD_writecmd ( 0xCF );
LCD_writedata ( 0x00 );
LCD_writedata ( 0xC1 );
LCD_writedata ( 0x30 );
/* Power on sequence control (EDh) */
LCD_writecmd ( 0xED );
LCD_writedata ( 0x64 );
LCD_writedata ( 0x03 );
LCD_writedata ( 0x12 );
LCD_writedata ( 0x81 );
/* Driver timing control A (E8h) */
LCD_writecmd ( 0xE8 );
LCD_writedata ( 0x85 );
LCD_writedata ( 0x10 );
LCD_writedata ( 0x78 );
/* Power control A (CBh) */
LCD_writecmd ( 0xCB );
LCD_writedata ( 0x39 );
LCD_writedata ( 0x2C );
LCD_writedata ( 0x00 );
LCD_writedata ( 0x34 );
LCD_writedata ( 0x02 );
/* Pump ratio control (F7h) */
LCD_writecmd ( 0xF7 );
LCD_writedata ( 0x20 );
/* Driver timing control B */
LCD_writecmd ( 0xEA );
LCD_writedata ( 0x00 );
LCD_writedata ( 0x00 );
/* Power Control 1 (C0h) */
LCD_writecmd ( 0xC0 ); //Power control
LCD_writedata ( 0x21 ); //VRH[5:0]
/* Power Control 2 (C1h) */
LCD_writecmd ( 0xC1 ); //Power control
LCD_writedata ( 0x11 ); //SAP[2:0];BT[3:0]
/* VCOM Control 1 (C5h) */
LCD_writecmd ( 0xC5 );
LCD_writedata ( 0x2D );
LCD_writedata ( 0x33 );
/* VCOM Control 2 (C7h) */
// LCD_writecmd ( 0xC7 );
// LCD_writedata ( 0XC0 );
/* memory access control set */
LCD_writecmd ( 0x36 ); //Memory Access Control
LCD_writedata ( 0x00 ); /*竖屏 左上角到 (起点)到右下角 (终点)扫描方式*/
LCD_writecmd(0x3A);
LCD_writedata(0x55);
/* Frame Rate Control (In Normal Mode/Full Colors) (B1h) */
LCD_writecmd ( 0xB1 );
LCD_writedata ( 0x00 );
LCD_writedata ( 0x17 );
/* Display Function Control (B6h) */
LCD_writecmd ( 0xB6 );
LCD_writedata ( 0x0A );
LCD_writedata ( 0xA2 );
LCD_writecmd(0xF6);
LCD_writedata(0x01);
LCD_writedata(0x30);
/* Enable 3G (F2h) */
LCD_writecmd ( 0xF2 );
LCD_writedata ( 0x00 );
/* Gamma Set (26h) */
LCD_writecmd ( 0x26 );
LCD_writedata ( 0x01 );
/* Positive Gamma Correction */
LCD_writecmd(0xe0); //Positive gamma
LCD_writedata(0xd0);
LCD_writedata(0x00);
LCD_writedata(0x02);
LCD_writedata(0x07);
LCD_writedata(0x0b);
LCD_writedata(0x1a);
LCD_writedata(0x31);
LCD_writedata(0x54);
LCD_writedata(0x40);
LCD_writedata(0x29);
LCD_writedata(0x12);
LCD_writedata(0x12);
LCD_writedata(0x12);
LCD_writedata(0x17);
/* Negative Gamma Correction (E1h) */
LCD_writecmd(0xe1); //Negative gamma
LCD_writedata(0xd0);
LCD_writedata(0x00);
LCD_writedata(0x02);
LCD_writedata(0x07);
LCD_writedata(0x05);
LCD_writedata(0x25);
LCD_writedata(0x2d);
LCD_writedata(0x44);
LCD_writedata(0x45);
LCD_writedata(0x1c);
LCD_writedata(0x18);
LCD_writedata(0x16);
LCD_writedata(0x1c);
LCD_writedata(0x1d);
// /* column address control set */
// LCD_writecmd ( CMD_SetCoordinateX );
// LCD_writedata ( 0x00 );
// LCD_writedata ( 0x00 );
// LCD_writedata ( 0x00 );
// LCD_writedata ( 0xEF );
//
// /* page address control set */
//
// LCD_writecmd ( CMD_SetCoordinateY );
// LCD_writedata ( 0x00 );
// LCD_writedata ( 0x00 );
// LCD_writedata ( 0x01 );
// LCD_writedata ( 0x3F );
/* Sleep Out (11h) */
LCD_writecmd ( 0x11 ); //Exit Sleep
LCD_Delay ( 0xAFFf<<2 );
/* Display ON (29h) */
LCD_writecmd ( 0x29 ); //Display on
LCD_writecmd(0x2c);
}
⑤初始化发送数据、发送指令、接受数据模块
注意,对应地址要声明为volatile类型,避免编译器优化,每次都从内存中检查数据,而不是从内核寄存器直接读取;
不然读数据时刻会出错
//写数据
void LCD_writedata(uint16_t DATA)
{
*(__IO uint16_t*) LCD_sendDATA = DATA;
}
//写指令
void LCD_writecmd(uint16_t usDATA)
{
*(__IO uint16_t*) LCD_sendCMD = usDATA;
}
//读数据
uint16_t LCD_readdata(void)
{
return (*(__IO uint16_t*) LCD_sendDATA);
}
⑥显示窗口开辟
从startx,宽度为width
从starty,高度为height
#define CMD_SetCoordinateX 0x2A //设置X坐标
#define CMD_SetCoordinateY 0x2B //设置Y坐标
void lcd_open_window(uint16_t start_x,uint16_t start_y,uint16_t width,uint16_t heigth)
{
LCD_writecmd ( CMD_SetCoordinateX );
LCD_writedata ((start_x&0xff00)>>8);
LCD_writedata ((start_x&0x00ff));
LCD_writedata (((start_x+width)&0xff00)>>8);
LCD_writedata (((start_x+width)&0x00ff));
LCD_writecmd ( CMD_SetCoordinateY );
LCD_writedata ((start_y&0xff00)>>8);
LCD_writedata ((start_y&0x00ff));
LCD_writedata (((start_y+heigth)&0xff00)>>8);
LCD_writedata (((start_y+heigth)&0x00ff));
}
⑦RGB888数据转化RGB565函数建立
实际上,我们一般在像素点采集时刻,一般采用RGB888模式,如下
在输入时刻,需要进行转化
uint16_t RGB888_turn_565(uint8_t R,uint8_t G,uint8_t B)
{
return (uint16_t)(((B&0x1f)<<11) |((G&0x3f)<<5) | (R&0x1f));
}
⑧矩形图形显示
void draw_rectangle(void)
{
uint32_t i;
lcd_open_window(10,20,50,50);
LCD_writecmd(0x2c);
for(i=0;i<50*50;i++)
{
LCD_writedata(RGB888_turn_565(140,204,242));
}
}
再主函数main简单配置
#include "stm32f10x.h" // Device header
#include "LED.H"
#include "BSP_USART.H"
#include "bsp_lcd.h"
int main(void)
{
uint16_t temp;
LED_config();
LCDconfig();
LCD_init();
bsp_usart_config();
printf("LCD 测试开始\n");
temp=read_lcd_format();
draw_rectangle();
printf("数值为0x %x",temp);
while(1)
{
}
}
FSMC控制ST7789V-LCD液晶显示屏简单介绍至此完毕