前面共用了六个篇幅,把TFT-LCD原和驱动芯片ILI9341的接口系统与命令系统做了一个比较详细的介绍与解释。上面几篇的很多细节由于需要在使用过程中去验证。因此有此专有名语的解释以及功能的介绍相可能不十分准备与完整,在接下来的应用实例 中如果有发现此类情况会一一做出更正或完善。以希望读者能在过程中指证以期共同完善。也因此上面七篇完全可以做为指南手册性质的资料,在应用过程中随时查阅参考。
《ILI9341的使用之【一】TFT-LCD原理(转载)》
《ILI9341的使用之【二】ILI9341介绍》
《ILI9341的使用之【三】ILI9341系统通信接口模式操作详解》
《ILI9341的使用之【四】RGB接口操作详解》
《ILI9341的使用之【五】命令一》
《ILI9341的使用之【六】命令二》
《ILI9341的使用之【七】实体面板案例-arduino 2.4inch TFT Touch Shield》
《ILI9341的使用之【八】ASCII字符显示及驱动分析》
《ILI9341的使用之【九】BG2312字库》
接下来的几篇是围绕ILI9341芯片的相关应用案例的介绍以及分析。内容会涉及到具体的面板,例程分板,接口分析。通过更直观的方式实现基于ILI9341芯片的LCD面板的应用。
一、arduino 2.4inch TFT Touch Shield
该板是我在网上淘到到的一块基于ILI9341的2.4英寸,带触控功能的面板。这块板的设计以Shield的形态很好地与目前流行的arduino UNO开发板契合。使我们不需要纠结于硬件底层,而只需要关注应用实现。
插入arduino UNO后是这样的
二、面板的使用参数
三、重点说明
根据前面六篇对ILI9341的介绍,该2.4英寸面板,从硬件搭建上可以看出以下几点:
1、通讯接口
MCU通讯接口模式上使用的是并行8位接口模式。涉及到的相关硬件设置如下:
具体可 以参见《ILI9341的使用之【二】ILI9341介绍》
该面板已经在硬件上实现了ILI9341芯片的IM0,IM1,IM2,IM3四个引脚的低电平连接。使ILI9341芯片工作在8080 MCU 8-bit 总线接口的通信模式下。如上表的红框的定义描述。因此在整个2.4寸的面板对外引脚定义上,也是遵循8-bit接口模式的。具本内容见上面“Arduono 使用接线说明”。
2、显示接口
根据面板模块参数说明里的对应描述,在下面的例程中在Lcd_init()函数实现显示接口的相应设置:
可以知道,这里的Pixel Format Set (3Ah)指令里的像素定义为16bit。即DBI[2:0]与DPI[2:0]参数的最值都为”B101“对应如下格式
由于通信接口是8位的接品,因此总线一次是传送8bit数据的。所以在实际传送数据到RAM时是,一共传两次,一次8Bit,共16bit,先传高8位再传低8位。
例如:红色的像素数据为D[15:0]=11111 000 000 00000=f800h (前5位为红色编码区,中间6位为绿色编码区,后5位为兰色编码区)
---- | D15 | D14 | D13 | D12 | D11 | D10 | D9 | D8 | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
定义 | 红 | 色 | 编 | 码 | 区 | 绿 | 色 | 编 | 码 | 区 | 兰 | 色 | 编 | 码 | 区 | |
纯红 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
纯绿 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 |
纯兰 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 |
3、指令
涉及到的主要指令逻辑为列地址设置2Ah,行地址设置2Bh,内存写入2Ch:
涉及到的物理总线写写入时序为,在下面的例程中由Lcd_Write_Bus()实现该写入时序。
四、驱动应用案例一
第一个完整例程如下,在程序里已经对所有功能做了相应注释,请结合这前的工作原理描述和指令详细说明去理解。该例程在arduino UNO上运行通过。
//本例程做为基于ILI9341芯片驱动的2.4寸面板的第一个案例。采用了最基本的显示模式。以ILI9341指令系统中的
//MCU to memory write / read direction基础模式访问面板。
//下面是引脚定义,需结合面板的引脚图定义理解。
// Breakout/Arduino UNO pin usage:
// LCD Data Bit : 7 6 5 4 3 2 1 0
// Uno dig. pin : 7 6 5 4 3 2 9 8
// Uno port/pin : PD7 PD6 PD5 PD4 PD3 PD2 PB1 PB0 //对应Port的标识。实际为PROTD或PORTB的宏定义所操作的端口寄存器
// Mega dig. pin: 29 28 27 26 25 24 23 22
#define LCD_RD A0
#define LCD_WR A1
#define LCD_RS A2
#define LCD_CS A3
#define LCD_REST A4
//实现总线写入的最底层操作。在该函数调用前需设定好REST,RD,RS,CS提前置高。在SETUP主体中可以看到。
void Lcd_Writ_Bus(unsigned char d)
{
PORTD = (PORTD & B00000011) | ((d) & B11111100); //将d的2-7位写入PORTD的2-7位
PORTB = (PORTB & B11111100) | ((d) & B00000011); //将d的0-1位写入PROTB的0-1位
//*(portOutputRegister(digitalPinToPort(LCD_WR))) &= ~digitalPinToBitMask(LCD_WR);
//*(portOutputRegister(digitalPinToPort(LCD_WR)))|= digitalPinToBitMask(LCD_WR);
digitalWrite(LCD_WR,LOW);
digitalWrite(LCD_WR,HIGH);
}
//在总线上写入命令。写入前要置RS引脚为低电平。
void Lcd_Write_Com(unsigned char VH)
{
*(portOutputRegister(digitalPinToPort(LCD_RS))) &= ~digitalPinToBitMask(LCD_RS);//LCD_RS=0;
Lcd_Writ_Bus(VH);
}
//在总线上写入数据。写入前要置RS引脚为高电平。
void Lcd_Write_Data(unsigned char VH)
{
*(portOutputRegister(digitalPinToPort(LCD_RS)))|= digitalPinToBitMask(LCD_RS);//LCD_RS=1;
Lcd_Writ_Bus(VH);
}
//写完一条指令后再写一8位的数据
void Lcd_Write_Com_Data(unsigned char com,unsigned char dat)
{
Lcd_Write_Com(com);
Lcd_Write_Data(dat);
}
//地址区域设置。涉及指令2Ah、2Bh
void Address_set(unsigned int x1,unsigned int y1,unsigned int x2,unsigned int y2)
{
Lcd_Write_Com(0x2a);
Lcd_Write_Data(x1>>8); //设定屏幕数据操作区域的列首地址数据,,先写入16bit数据位的高位
Lcd_Write_Data(x1); //写入16bit数据位的低位
Lcd_Write_Data(x2>>8); //设定屏幕数据操作区域的列尾地址数据,,先写入16bit数据位的高位
Lcd_Write_Data(x2); //写入16bit数据位的低位
Lcd_Write_Com(0x2b);
Lcd_Write_Data(y1>>8); //设定屏幕数据操作区域的行首地址数据,,先写入16bit数据位的高位
Lcd_Write_Data(y1); //写入16bit数据位的低位
Lcd_Write_Data(y2>>8); //设定屏幕数据操作区域的行尾地址数据,,先写入16bit数据位的高位
Lcd_Write_Data(y2); //写入16bit数据位的低位
Lcd_Write_Com(0x2c); //开启RAM数据持续写入状态。
}
//面板初始化
void Lcd_Init(void)
{
digitalWrite(LCD_REST,HIGH);
delay(5);
digitalWrite(LCD_REST,LOW);
delay(15);
digitalWrite(LCD_REST,HIGH);
delay(15); //到此为硬重置
digitalWrite(LCD_CS,HIGH); //根据MCU 8080-I 8bit通信接口操作规范,设置引脚的对应状态。
digitalWrite(LCD_WR,HIGH);
digitalWrite(LCD_CS,LOW); //片选有效
Lcd_Write_Com(0xCB); // 指令Power Control A
Lcd_Write_Data(0x39);
Lcd_Write_Data(0x2C);
Lcd_Write_Data(0x00);
Lcd_Write_Data(0x34); //设置 Vcore=1.6V
Lcd_Write_Data(0x02); //设置DDVDH=5.6V
Lcd_Write_Com(0xCF); // 指令Power Control B
Lcd_Write_Data(0x00);
Lcd_Write_Data(0XC1);
Lcd_Write_Data(0X30);
Lcd_Write_Com(0xE8); //指令 Driver timing Congrol A
Lcd_Write_Data(0x85);
Lcd_Write_Data(0x00);
Lcd_Write_Data(0x78);
Lcd_Write_Com(0xEA); //指令 Driver timing Congrol B
Lcd_Write_Data(0x00);
Lcd_Write_Data(0x00);
Lcd_Write_Com(0xED); //指令 Power on sequence control
Lcd_Write_Data(0x64);
Lcd_Write_Data(0x03);
Lcd_Write_Data(0X12);
Lcd_Write_Data(0X81);
Lcd_Write_Com(0xF7); //指令Pump ratio control
Lcd_Write_Data(0x20); //DDVDH=2*VCL
Lcd_Write_Com(0xC0); //Power control
Lcd_Write_Data(0x23); //VRH[5:0] GVDD=4.6V
Lcd_Write_Com(0xC1); //Power control
Lcd_Write_Data(0x10); //SAP[2:0];BT[3:0]
Lcd_Write_Com(0xC5); //VCM control 1
Lcd_Write_Data(0x3e); //Contrast VCOMH=3.45V VCOML=-1.5V
Lcd_Write_Data(0x28);
Lcd_Write_Com(0xC7); //VCM control2
Lcd_Write_Data(0x86); //--
Lcd_Write_Com(0x36); // Memory Access Control
//Lcd_Write_Data(0x48); // MX=1 Column Address Order ; BGR=1 RGB(IC)-->BGR(LCD Panel)
Lcd_Write_Data(0x08); // MX=0,BGR =1
Lcd_Write_Com(0x3A); //指令Pixel Format Set
Lcd_Write_Data(0x55); //RGB 接口和MCU接口模式的像素数据格式为16bit/pixel
Lcd_Write_Com(0xB1); //Frame Rate Control (B1h)(In Normal Mode /Full colors )
Lcd_Write_Data(0x00);
Lcd_Write_Data(0x18); //79HZ(frame rate)
Lcd_Write_Com(0xB6); // Display Function Control
Lcd_Write_Data(0x08); // Interval Scan
Lcd_Write_Data(0x82); //底背景为白屏, 5 frams Scan Cycle
Lcd_Write_Data(0x27); //320 line
Lcd_Write_Com(0x11); //Exit Sleep
delay(120); //必须120ms的延迟
Lcd_Write_Com(0x29); //Display on
Lcd_Write_Com(0x2c); //Memory Write Start(2C) 或 Memory Write Continue(3ch)
}
//画水平线。。设定需填色的行列起止地址范围后往里填色
void H_line(unsigned int x, unsigned int y, unsigned int l, unsigned int c)
{
//x,y 为水平线的起始坐标 ,,l为水平线长度单位为像素,c为颜色参数
unsigned int i,j;
Lcd_Write_Com(0x02c); //write_memory_start
digitalWrite(LCD_RS,HIGH);
digitalWrite(LCD_CS,LOW);
l=l+x; //转换成终止列的X坐标
Address_set(x,y,l,y); //框出要填色的区域
j=l; //确定要填入的像素个数
for(i=1;i<=j;i++)
{
Lcd_Write_Data(c>>8); //写入颜色数据的高8位
Lcd_Write_Data(c); //写入颜色数据的低8位
}
digitalWrite(LCD_CS,HIGH);
}
//画垂直线。。设定需填色的行列起止地址范围后往里填色
void V_line(unsigned int x, unsigned int y, unsigned int l, unsigned int c)
{
unsigned int i,j;
Lcd_Write_Com(0x02c); //write_memory_start
digitalWrite(LCD_RS,HIGH);
digitalWrite(LCD_CS,LOW);
l=l+y; //转换成终止行的Y坐标
Address_set(x,y,x,l); //框出要填色的区域
j=l; //确定要填入的像素个数
for(i=1;i<=j;i++)
{
Lcd_Write_Data(c>>8); //写入颜色数据的高8位
Lcd_Write_Data(c); //写入颜色数据的低8位
}
digitalWrite(LCD_CS,HIGH);
}
//画空心矩形
void Rect(unsigned int x,unsigned int y,unsigned int w,unsigned int h,unsigned int c)
{
H_line(x , y , w, c);
H_line(x , y+h, w, c);
V_line(x , y , h, c);
V_line(x+w, y , h, c);
}
//画实心矩形
void Rectf(unsigned int x,unsigned int y,unsigned int w,unsigned int h,unsigned int c)
{
unsigned int i;
for(i=0;i<h;i++)
{
H_line(x , y+i, w, c);
}
}
int RGB(int r,int g,int b)
{return r << 16 | g << 8 | b;
}
//满屏填充
void LCD_Clear(unsigned int j)
{
unsigned int i,m;
digitalWrite(LCD_CS,LOW);
Address_set(0,0,239,319);
for(i=0;i<320;i++) //320个行
for(m=0;m<240;m++) //240列
{
Lcd_Write_Data(j>>8);
Lcd_Write_Data(j);
}
digitalWrite(LCD_CS,HIGH);
}
void setup()
{
Serial.begin(9600);
//以下为定义各个PIN脚的输入输出状态
for(int p=0;p<10;p++)
{
pinMode(p,OUTPUT);
}
pinMode(A0,OUTPUT);
pinMode(A1,OUTPUT);
pinMode(A2,OUTPUT);
pinMode(A3,OUTPUT);
pinMode(A4,OUTPUT);
digitalWrite(A0, HIGH);
digitalWrite(A1, HIGH);
digitalWrite(A2, HIGH);
digitalWrite(A3, HIGH);
digitalWrite(A4, HIGH);
Lcd_Init();//初始化面板
}
void loop()
{
LCD_Clear(0xf800); //红色填满屏
LCD_Clear(0x07E0); //绿色填满屏
LCD_Clear(0x001F); //兰色填满屏
//空心矩形
for(int i=0;i<500;i++)
{
Rect(random(300),random(300),random(300),random(300),random(65535)); // rectangle at x, y, with, hight, color
Serial.println("完成第"+String(i)+"个矩形");
}
//实心矩形
for(int i=0;i<10;i++)
{
Rectf(random(300),random(300),random(300),random(300),random(65535)); // rectangle at x, y, with, hight, color
Serial.println("完成第"+String(i)+"个实心矩形");
}
}