IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> LCD实验 -> 正文阅读

[嵌入式]LCD实验

LCD – TFTLCD 原理与配置

TFTLCD(薄膜晶体管液晶显示器)

简介

Thin Film Transistor - Liquid Crystal Display
TFTLCD计技术是微电子技术与液晶显示器技术巧妙结合的一种技术。
TFT-LCD屏可视为两片玻璃基板中间夹着一层液晶,上层的玻璃基板贴合彩色滤波片,下层玻璃有晶体管镶嵌。当有电流通过晶体管产生电场变化,造成液晶分子偏转,借以改变光线的偏极性,再利用偏光片决定像素的明暗状态。此外,上层玻璃因与彩色滤光片贴合,形成每个像素各包含红蓝绿三颜色,像素便构成了皮肤上的图像画面。
每一个像素上都设置有一个薄膜晶体管--->大大提高了图像质量

特点

亮度高
对比度高
层次感强
颜色鲜艳

原理

在这里插入图片描述
接口说明:
(DB1DB8,DB10DB17,总是按顺序连接MCU的D0~D15)
① LCD_CS:LCD片选信号
② LCD_WR:LCD写信号
③ LCD_RD: LCD读信号
④ DB[17:1]:16位双向数据线
⑤ LCD_RST:硬复位LCD信号
⑥ LCD_RS: 命令/数据标志(0:命令,1:数据)
⑦ BL_CTR:背光控制信号
⑧ T_MISO/T_MOST/T_PEN/T_CS/T_CLK,触摸屏接口信号

驱动

8080并口读/写过程为:
先根据要写入/读取的数据的类型,设置RS为高(数据)/低(命令),然后拉低片选,选中ILI9341,接着根据是读还是写数据置RD/WD 为低
1.读数据:在RD的上升沿,读取数据线上的数据(D[15:0])
2.写数据:在WR的上升沿,使数据写入到ILI9341里面
在这里插入图片描述

驱动流程

硬复位

LCD_RST=0;
delay_ms(100);
LCD_RST=1;

初始化序列

不同厂家出厂的LCD的初始化序列是不同的,由厂家提供。

设置坐标

写GRAM指令
写入颜色数据(0X2C)
LCD显示
读GRAM指令
读出颜色数据(0X2E)
单片机处理

RGB565格式

在这里插入图片描述

ILI9341指令格式说明

几条重要指令

0XD3

用来读取LCD控制器的ID
代码相同,ID不同——>执行不同的LCD驱动初始化——>兼容不同的LCD屏幕
在这里插入图片描述

0X36

存储访问控制指令,可以控制ILI9341存储器的读写方向
就是在连续写GRAM的时候,可以控制GRAM指针的增长方向,从而控制显示方式(读GRAM也是一样)

在这里插入图片描述
在这里插入图片描述

0X2A

列地址设置指令,默认从左向右,从上到下的扫描方式,用于设置横坐标
在这里插入图片描述
0<=SC<=EC<=239

0X2B

页(理解是行)地址设置指令,从左到右,从上到下的扫描方式下面,该指令用于设置纵坐标。
在这里插入图片描述
0<=SP<=EP<=319

0X2C

写GRAM指令,在发送该指令后,可往LCD的GRAM里面写入颜色数据,支持连续写(地址自动递增)
在这里插入图片描述

0X2E

读GRAM指令,用于读取ILI9341的显存,同0X2C指令,该指令支持连续读(地址自动递增)
在这里插入图片描述
ILI9341收到指令后,第一次输出dummy数据(无效),第二次开始,读取到的才是有效的GRAM数据,输出规律为每个颜色分量占8个位,一次输出2个颜色分量。比如:第一次输出是R1G1,随后的规律为B1R1->G2B2->R3G3->~

FSMC简介

FSMC,灵活的静态存储控制器,能够与同步或异步存储器和16位IPC存储器卡连接。

在这里插入图片描述

FSMC驱动LCD

FSMC驱动外部SRAM时,外部SRAM的控制一般有:地址线(如A0A25)、数据线(如D0D15)、写信号(WE,即WR)、读信号(OE,即RD)、片选信号(CS),如果SRAM支持字节控制,那么还有UBLB信号。
而TFTL CD的信号我们在前面介绍过,包括: RS、D0D15、WR、RD、CS.RST和BL等,其中真正在操作LCD的时候需要用到的就只有:RS、DOD15、WR.RD和CS.其操作时序和SRAM的控制完全类似,唯一不同就是TFTLCD有RS信号,但是没有地址信号。
TFTLCD通过RS信号来决定传送的数据是数据还是命令,本质上可以理解为一个地址信号,比如我们把RS接在AO上面,那么当FSMC控制器写地址0的时候,会使得AO变为0,对TFTLCD来说,就是写命令。而FSMC写地址1的时候, A0将会变为1,对TFTLCD来说,就是写数据。这样把数据和命令区分开,对应SRAM操作的两个连续地址。当然RS也可以接在其他地址线上,战舰V3和精英板开发板都是把RS连接在A10上面,而探索者STM32F4把RS接在A6上面。
因此,可以把TFTLCD当成一个SRAM来用,只不过这个SRAM有2个地址,这就是FSMC可以驱动LCD的原理。

NOR PSRAM外设接口

STM32的FSMC将外部存储器划分为固定大小为256M字节的四个存储块
在这里插入图片描述

存储块1

Bank1(存储块1)用于驱动NOR FLASH/SRAM/PSRAM,被分为四个区,每区管理54M字节空间,每个区都有独立的寄存器对所连接的存储器进行配置。Bank1 的256M字节空间由28根地址线[HADDR【27:0】]寻址。
HADDR是内部AHB地址总线,其中HADDR【25:0】来自外部存储器地址FSMC_A[25:0],HADDR[26:27]对四个区进行寻址。
在这里插入图片描述
当Bank1接的是16位宽度存储器的时候: HADDR[25:1——>FSMC_A[24:0]
当Bank1接的是8位宽度存储器的时候: HADDR[25:0]——>FSMC_A[25:0]
不论外部接8位/16位宽设备,FSMC_A[0]永远接在外部设备地址A[0]

这里使用模式A来驱动LCD
在这里插入图片描述
在这里插入图片描述

寄存器

在这里插入图片描述
对于NORELASH/PSRAM控制器(存储块1),通过ESMC BCRx、FSMC_BTRx和FSMC_ BWTRx寄存器设置(其中x=1~4,对应4个区)。通过这3个寄存器,可E设置FSMC访问外部存储器的时序参数,拓宽了可选用的外部存储器的速度范围。

EXTMOD:扩展模式使能位,控制是否允许读写不同的时序,需设置为1
WREN:写使能位。向TFTLCD写数据,故该位必须设置为1
MWID[1:0]:存储器数据总线宽度。00,表示8位数据模式;01表示16位数据模式;10和11保留。TFTLCD是16位数据线,所以设置WMID[1:0]=01."MTYP[1:0]:存储器类型。00表示SRAM、ROM; 01表示PSRAM:10表示NORFLASH;11保留。LCD当成SRAM,需要设置MTYP[1:0]=00.
MBKEN:存储块使能位。设置为1
在这里插入图片描述
ACCMOD[1:0]:访问模式。00:模式A;01:模式B:10:模式C;11:模式D.
DATAST[7:0]:数据保持时间,等于: DATAST(+1)个HCLK时钟周期,DATAST最大为255。对ILI9341来说,其实就是RD低电平持续时间,最大为355ns,对STM32F1,一个HCLK=13.8ns (1/72M),设置为15;对STM32F4,一个HCLK=6ns(1/168M),设置为60。
ADDSET[3:0]:地址建立时间。表示:ADDSET (+1)个HCLK周期, ADDSET最大为15。对ILI9341来说,这里相当于RD高电平持续时间,为90ns,STM32F1的FSMC性能存在问题,即便设置为0,RD也有190ns的高电平,我们这里设置为1。而对STM32F4,则设置为15。

在这里插入图片描述
ACCMOD[1:0]:访问模式。00:模式A;01:模式B:10:模式C;11:模式D,
DATAST[7:0]:数据保持时间,等于:DATAST(+1)个HCLK时钟周期, DATAST最大为255。对I LI9341来说,其实就是WR低电平持续时间,为15ns,不过ILI9320等则需要50ns。考虑兼容性,对STM32F1,一个HCLK=13.8ns (1/72M),设置为3;对STM32F4,一个HCLK=6ns(1/168M),设置为9。
ADDSET[3:0]:地址建立时间。表示: ADDSET+1个HCLK周期, ADDSET最大为15。对ILI9341相当于WR高电平持续时间,为15ns。兼容ILI9320,对STM32F1设置为1。STM32F4,设置为8。

寄存器组合

ST官方库提供的寄存器定义,没有定义单独的寄存器,而是将他们进行组合。

FSMC BCR×和FSMC_BTRx,组合成BTCR[8]寄存器组
BTCR[0]对应FSMC BCR1,BTCR[1]对应FSMC BTR1
BTCR[2]对应FSMC BCR2,BTCR[3]对应FSMC BTR2
BTCR[4]对应FSMC_BCR3,BTCR[5]对应FSMC BTR3
BTCR[6]对应FSMC BCR4,BTCR[7]对应FSMC BTR4

F.SMC BWTRX则组合成BWTR[7]:
BWTR[O]对应FSMC_BWTR1,BWTR[2]对应FSMC_BWTR2
BWTRI4]对应FSMC BWTR3, BWTR[6]对应FSMC BWTR4

LCD实验源码

硬件连接(STM32F4开发板)

LCD_BL(背光控刷)对应 PBO;
LCD_CS对应PGl2即 FSMC_NE4;
LCD_RS对应 PG0FSMC_Al0;
LCD_wR对应PDS 即 FSMC_NWE;
LCD_RD对应PD4即 FSMC_NOE;
LCD_D[15:0]则直接连接在FSMC_Dl5~FSMC_D0;

LCD&lcddev结构体

LCD结构体
typedef struct
{
vu16 LCD_ REG;
vu16 LCD RAM;
}LCD_TypeDef;
//使用NOR/SRAM的 Bank1.sector4,地址位HADDR[27,26]=11A10作为数据命令区分线
//注意设置时STM32内部会右移一位对齐!
#define LCD_BASE    ((u32)(0x6co0o000|Ox0000007FE))
#define LCD    ((LCD_ TypeDef*)LCD_ BASE)

LCD_BASE,根据外部电路的连接来确定,如Bank1.sector4就是从地址OX6C000000开始,而OX000007FE,则是A10的偏移量。以A10为例,7FE换成二进制为:111 11111110,而16位数据时,地址右移一位对齐,对应到地址引脚,就是: A10:A0=011 11111111,此时A10是0,但是如果16位地址再加1(对应到8位地址是加2,即7FE+0X02),那么:A10:A0=100 0000 0000,此时A10就是1了,即实现了对RS的0和1的控制。
将((LCD_ TypeDef)LCD_ BASE)这个地址强制转换为LCD_TypeDef结构体地址,得到LCD->LCD_REG的地址OX6CO0,07FE,对应A10的状态为O(即RS=0),而LCD->LCD_RAM的地址就是0X6C00,0800(结构体地址自增),对应A10的状态为1(即RS=1),从而实现对RS的控制。*

lcddev结构体
typedef struct{
u16 width;    //LCD宽度
u16 height;   //LCD高度
u16 id;       //LCD ID
u8 dir;       //横屏还是竖屏控制:0,竖屏:1,横屏。
u16 wramcmd;  //开始写gram指令
u16 setxcmd;  //设置x坐标指令
u16 setycmd;  //设置y坐标指令
}_Icd_dev;
//LCD参数
extern _lcd_dev lcddev;//管理LCD重要参数

该结构体参数的赋值,基本都是在LCD_Display_Dir函数完成

底层接口函数

总括:

void LCD WR REG(u16 regval)  //写寄存器值函数
void LCD WR DATA(u16 data)   //写数据函数
u16 LCD RD DATA(void)        //读数据函数
void LCD_WriteReg(u16 LCD_Reg,u16 LCD_RegValue) //写寄存器内容函数
u16 LCD_ReadReg(u16 LCD_Reg) //读寄存器内容函数
void LCD WriteRAM Prepare(void)                  //开始写GRAM函数
void LCD_WriteRAM(u16 RGB_Code)                  //写GRAM函数

void LCD_WR_REG(vu16 regval)
{   
	regval=regval;		//使用-O2优化时,必须插入延时
	LCD->LCD_REG=regval;//写入寄存器序号 
}//写寄存器值
void LcD_WR_DATA(vul6 data)
data=data;
//使用-o2优化的时候,必须插入的延时
LCD->LCD_RAM=data ;
)
//读LcD数据

ul6 LCD_RD_DATA (void)
vul6 ram;
//防止被优化
ram=LCD->LCD_RAM;
return ram;

//LCD_Reg:寄存器地址
//LCD Regvalue:要写入的数据
void LcD_WriteReg (ul6 LCD_Reg,ul6 LCD_Regvalue)
LCD->LCD_REG= LCD_Reg;//写入要写的寄存器序号LCD->LCD_RAM=LCD_Regvalue; //写入数据
//读寄存器
//LCD Reg:寄存器地址//返回值:读到的数据
ul6 LCD_ReadReg (ul6 LCD_Reg)
L.CD_WR_REG(LCD_Reg) ;//写入要读的寄存器序号delay_us(5) ;
return LCD_RD_DATA ( );//返回读到的值
}
void LCD_writeRAM_Prepare (void)
{
LCD->LCD_REG=lcddev.wramcmd;
}
//RGB_code:颜色值
void LcD_writeRAM (ul6 RGB_code){
LCD->LCD_RAM=RGB_code; //写十六位GRAM

初始化函数

//LCD初始化
void LCD_Init(void)
{
  初始化GPIO;
  初始化FSMC;
  读取LCD D;
  printf( "LCD ID:%Kx\rn", lcddev.id);//打印LCD ID,用到了串口1
                                       //初始化串口1,否则黑屏
根据不同的ID执行LCD初始化代码;
LCD Display Dir(0);                    //默认为竖屏
LCD LED=1;                             //点亮背光
LCD Clear (WHITE);                     //清屏

坐标设置函数

//设置光标位置
//Xpos:横坐标
//Ypos:纵坐标
void LCD SetCursor (ul6 Xpos,u16 Ypos)
{
    if(lcddev.idoX9341 I|lcddev.id 0X5310)
    {
    LCD_WR_REG(lcddev.setxcmd);
    LCD_WR DATA (Xpos>>8);
    LCD_WR DATA (Xpos&OXFF);
    LCD_WR_REG(1eddev.setycmd);
    LCD_WR_DATA(Ypos>>8);
    LCD_WR_ DATA(Ypos&OXFF);
    }else if(lcddev. idXXX){}
//根据不同的LCD型号,执行不同的代码
}

画点函数

//画点
//x, y:坐标
//POINT _COLOR:此点的颜色
void LCD_DrawPoint (u16 x, ul6 y)
{
    LCD SetCursor (x,y);    //设置光标位置
    LCD_WriteRAM_Prepare(); //开始写入GRAM
    LCD->LCD_ RAM=POINT_COLOR;//非Mini板的操作方式

读点函数

ul6 LCD_ReadPoint (ul6 x,ul6 y){
ul6 r=0, g=o,b=0 ;
if(x>=lcddev.width ||y>=lcddev.height)return 0;//超过了范围,直接返回LcD_setcursor(x,y);
if(lcddev.id==0X9341||lcddev.id==OX6804 ||lcddev.id==OX5310||leddev.id==OX1963)LED_WR_REG(0X2E);//341/684/3510/1963发送读cour指令
else if (lcddev.id==0X5510)LCD_wR_REG (OX2Eo0); //5510发送读GRAw指令
else LCD_WR_REG(0X22);//其他Ic发送读GRAv指令
if(lcddev.id==0X9320)opt_delay (2);//FOR 9320,延时2usr=LCD_RD_DATA();-l / dummy Read
if ( lcddev.id==0X1963) return r;//1963直接读就可以
opt_delay (2);
r=LCD_RD_DATA( ) ;//实际坐标颜色
if (lcddev.id==0X9341||lcddev.id==OX5310||lcddev.id==OX5510)//9341/NT35310/NT35510要分2次读出
{
opt_delay (2);
b=LCD_RD_DATA();
g=r&0XFF;//对于9341/5310/5510,第一次读取的是Rc的值,R在前,c在后,各占8位
g<<=8 ;
if(lcddev.id==O0X9325||lcddev. id=O0X4535||lcddev .id==0X4531 ||lcddev .id==O0XB505]||lcddev.id==0XC505)return r;//这几种rc直接返回颜色值
else if(lcddev.id=0X9341||lcddev.id==0X5310||lcddev.id==0X5510)return ((r>>l)<<I1)|(g>>10)<<5)|(b>>11));//ILI3L1/NT35310/NT35510需要公式转
else return LCD_BGR2RGB(r) ;//其他ic

字符显示函数

void LcD_ShowChar(ul6 x,ul6 y,u8 num, u8 size,u8 mode)
{
   u8 temp,tl,t;
   ul6 yO=y;
   u8 csize=(size/8+((size卺8)?1:0))*(size/2);.//得到字体一个字符对应点阵集所占的字
   num=num-' ';//得到偏移后的值(AscII字库是从空格开始取模,所以-·'就是对应字符的字库)
   for (t=0;t<csize;t++)
   {
     if(size==l2)temp=asc2_1206[num][t];//调用1206字体
     else if(size==l6)temp=asc2_1608 [num][t];//调用1608字体
     else if(size==24)temp=asc2_2412[num][t]; //调用2412字体
     else return;
        //没有的字库
        for (tl=0;tl<8;tl++)
        {
        if (temp&0x80)LCD_Fast_DrawPoint (x,y,POINT_COLOR) ;
        else if (mode==0)LCD_Fast_DrawPoint (x,y,BACK_COLOR);
        temp<<=l;
        y++;
        if(y>=lcddev.height) return;//超区域
        if( (y-y0 )==size)
        {
        y=y0;x++;
        if(>=lcddev.width) return;//超区域
        break;
        }
        }
    }
}
  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2021-08-09 10:23:46  更:2021-08-09 10:24:30 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/13 7:46:38-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码