2)摘自《开拓者 Nios II开拓指南》关注官方微旗子暗记"大众号,获取更多资料:正点原子
3)全套实验源码+手册+视频下载地址:http://www.openedv.com/docs/index.html
第十章MCU TFT-LCD图片显示实验

TFT LCD是Thin Film Transistor Liquid Crystal Display的缩写,即薄膜场效应晶体
管液晶显示器,即每个液晶像素点都是由集成在像素点后面的薄膜晶体管来驱动,这样不仅
提高了显示屏的相应速率,同时还可以精确掌握显示色阶,做到高速率、高彩色保真度、高
亮度、高比拟度和高分辨率。TFT LCD能够低电压驱动,具有功耗低,利用寿命长等特点。其
显示运用范围覆盖了从1英寸至40英寸范围内的所有显示器以及投影大平面,是全尺寸显示终
端。其余TFT LCD的环保特性好,无辐射、无闪烁,是设计用户友好型图形界面的优秀载体。
本章我们将利用Nios II驱动TFT LCD的显示。
本章包括以下几个部分:
10.1 简介
10.2 实验任务
10.3 硬件设计
10.4 软件设计
10.5 下载验证
简介
ATK-4.3’TFTLCD是ALIENTEK推出的一款高性能4.3寸电容触摸屏模块。该模块屏幕分辨
率为800480,16位真彩显示,采取Intel8080接口(MCU接口),该芯片自带GRAM,无需外加
驱动器,因而任何单片机,都可以轻易驱动。此外ALIENTEK还推出了一款具有相同接口和分
辨率的TFTLCD——ALIENTEK第二代7寸TFTLCD——ATK-7’ TFTLCD-V2.2,ATK-7’TFTLCD V2
模块具有屏幕分辨率高(800480),支持16/18/24位真彩显示、支持8/9/12/16位数据格
式、支持开窗显示等特色。当然了,ALIENTEK也供应了3.5寸和2.8寸的TFTLCD,以知足不同
运用的需求。
虽然这些不同尺寸的TFTLCD的LCD驱动器芯片不同(关于各尺寸的TFTLCD的详细先容可参
见供应的增值资料部分),如7寸的ATK-7’ TFTLCD-V2.2采取的是SSD1963、4.3寸的ATK-
4.3’TFTLCD采取的是NT35510等,但都采取Intel8080接口。Intel8080接口是一种并行接口
协议,由Intel公司提出,被广泛运用于各种液晶显示器。下面我们理解一下Intel8080接口
的操作时序。
为了更好的理解Intel8080接口,我们先来看一下TFTLCD模块的接口事理图,如下图所
示:
图10.1.1 TFTLCD模块接口事理图
各引脚的详细描述如下表所示:
表格10.1.1 TFTLCD模块接口引脚功能描述
在Intel8080并口模式下,LCD驱动须要用到的旗子暗记线如下:
CS:LCD片选旗子暗记。
WR:向LCD写入数据。
RD:从LCD读取数据。
D[15:0]:16位双向数据线(RGB565)。
RST:硬复位LCD。
RS:命令/数据标志(0,读写命令;1,读写数据)。
除了以上旗子暗记,我们一样平常还须要用到这2个旗子暗记:RST和BL_CTR,个中RST是液晶的硬复位
脚,低电平有效,用于复位TFTLCD的驱动芯片如NT35510,实现液晶复位,在每次初始化之
前,我们建议先实行硬复位,再做初始化。BL_CTR则是背光掌握引脚,高电平有效,即高电平时点亮背光,其余可以用PWM掌握BL_CTR脚,从而掌握背光的亮度。
Intel8080并口读/写的过程为:拉低片选CS,选中驱动芯片,并根据要写入/读取的数据
的类型,设置RS为高(数据)/低(命令),然后我们根据是读数据还是写数据设置RD/WR为
低,即当写数据时,WR设为低电平,RD保持高电平,当读数据时,RD设为低电平,WR保持高
电平,然后:当WR由低到高时,TFTLCD锁存数据。写时序的时序图如下:
图10.1.2 8080 并口写时序图
从上图可以看到,在写数据时,读旗子暗记RD保持高电平,RS根据写数据的类型设置为高或
低电平(高:数据,低:命令),当WR为低电平时,往D0~D15写数据,当WR由低电平变成高
电平时,TFTLCD锁存数据。
读时序的时序图如下:
图 10.1.3 8080 并口读时序图
从上图可以看到,在读数据时,写旗子暗记WR保持高电平,当RD为低电平时,TFTLCD掌握数
据总线D0~D15,当RD由低电平变成高电平时,主机读取数据。
Intel8080接口办法下,掌握脚的旗子暗记状态所对应的功能如下表所示:
图 10.1.4 掌握脚旗子暗记状态功能表
在Intel8080接口下读数据操作的时候,我们有时候(例如读显存的时候)须要一个假读
命(Dummy Read),以使得微掌握器的操作频率和显存的操作频率相匹配。在读取真正的数
据之前,由一个的假读的过程。这里的假读,实在便是第一个读到的字节丢弃不要,从第二
个开始,才是我们真正要读的数据。一个范例的读显存的时序图,如下图所示:
图10.1.5 读显存时序图
可以看到,在发送了列地址之后,开始读数据,第一个是Dummy Read,也便是假读,我
们从第二个开始,才算是真正有效的数据
现在我们以ATK-4.3’TFTLCD为例,看一下Intel8080总线读写时序的详细参数,如下图
所示:
图10.1.6 Intel总线读写时序
图中各韶光参数见表10.1.3 所示:
图 10.1.7 Intel8080 并口读写韶光参数
从上表可以看出,模块的写周期是非常快的,只须要33ns即可,理论上最大速率可以达
到:3030W像素每秒,即刷屏速率可以达到每秒钟78.9 帧。模块的读取速率相对较慢:读ID
(RD(ID))周期是160ns,读显存周期是400ns(RD(FM))。
并行接口模式就先容到这里,现在我们以4.3寸的ATK-4.3’TFTLCD的LCD驱动芯片
NT35510为例进行先容,其它的驱动芯片基本都类似,我们就不详细阐述了。
NT35510自带LCD GRAM(4808643字节),并且最高支持24位颜色深度(1600万色),
不过,我们一样平常利用16位颜色深度(65K色),RGB565格式,这样,在16位模式下,可以达到
最快的速率。
在16位模式下,NT35510采取RGB565格式存储颜色数据,此时NT35510的低16位数据总线
(高8位没有用到)与MCU(这里指Nios II)的16位数据线以及24位LCD GRAM的对应关系如下
表所示:
图10.1.8 16位总线与24位GRAM对应关系
从上表可以看出,NT35510的24位GRAM与16位RGB565的对应关系,实在便是分别将高位的
R、G、B数据,搬运到低位做添补,“凑成”24位,再显示。
MCU的16位数据中,最低5位代表蓝色,中间6位为绿色,最高5位为赤色。数值越大,表
示该颜色越深。其余,特殊把稳NT35510的指令是16位宽,数据除了GRAM读写的时候是16位
宽,其它都是8位宽的(高8位无效),这个和ILI9320等驱动器不一样,必须加以把稳。
接下来,我们先容一下NT35510的几个主要命令,由于NT35510的命令很多,我们这里就
不全部先容了,有兴趣的读者可以查看NT35510的datasheet。里面对这些命令有详细的介
绍。我们将先容:0XDA00,0XDB00,0XDC00,0X3600,0X2A00~0X2A03,0X2B00~0X2B03,
0X2C00,0X2E00 等14条指令。
首先来看指令:0XDA00,0XDB00,0XDC00,这三条指令是读ID1,ID2,ID3指令,也便是
用于读取LCD掌握器的ID,该指令如下表所示
图10.1.9 读ID指令描述
从上表可以看出,LCD读ID,统共由3个指令(0XDA00、0XDB00和0XDC00)构成,每个指
令输出一个参数,每个ID以8位数据(即指令后的参数)的形式输出(高8位固定为0),不过
这里输出的ID,并不包含5510这样的字样,仅有指令0XDB00会输出ID:0X80,其他两个指令
读到的ID都是0。将3个指令的输出,组合在一起,可以得到NT35510的ID为:0X8000。
通过这个ID,即可判别所用的LCD驱动器是什么型号,这样,我们的代码,就可以根据控
制器的型号去实行对应驱动IC的初始化代码,从而兼容不同驱动IC的屏,使得一个代码支持
多款LCD。
接下来看指令:0X3600,这是存储访问掌握指令,可以掌握NT35510存储器的读写方向,
大略的说,便是在连续写GRAM的时候,可以掌握GRAM指针的增长方向,从而掌握显示办法
(读GRAM也是一样)。该指令如表所示:
图10.1.10 0X3600 指令描述
从上表可以看出,0X3600指令后面,紧跟一个参数,这里我们紧张关注:MY、MX、MV这三个位,
通过这三个位的设置,我们可以掌握全体 NT35510 的全部扫描方向,如下表所示:
图10.1.11 MY、MX、MV设置与LCD扫描方向关系表
这样,我们在利用 NT35510 显示内容的时候,就有很大灵巧性了,比如显示 BMP 图片,BMP
解码数据,便是从图片的左下角开始,逐步显示到右上角,如果设置 TFTLCD扫描方向为从左
到右,从下到上,那么我们只须要设置一次坐标,然后就一直的往LCD添补颜色数据即可,这
样可以大大提高显示速率。
接下来看指令:0X2A00~0X2A03,这几个是列地址设置指令,在从左到右,从上到下的扫
描办法(默认)下面,该指令用于设置横坐标(x 坐标),该指令如下 表 所示:
图10.1.12 0X2A00~0X2A03指令描述
在默认扫描办法时,这4个指令用于设置x坐标,每条指令带有1个参数,实际上统共便是
2个坐标值:SC和EC(SC和EC都是16位的,由2个8位组成),即列地址的起始值和结束值,SC
必须小于即是EC,且0≤SC/EC≤479。一样平常在设置x坐标的时候,我们只须要0X2A00和0X2A01
两条指令即可,也便是设置SC即可,由于如果EC没有变革,我们只须要设置一次即可(在初
始化NT35510的时候设置),从而提高速率。
与0X2A00~0X2A03指令类似,指令:0X2B00~0X2B03,是页地址设置指令,在从左到右,
从上到下的扫描办法(默认)下面,该指令用于设置纵坐标(y坐标)。该指令如下 表 所
示:
图10.1.13 0X2B00~0X2B03指令描述
在默认扫描办法时,这4个指令用于设置y坐标,每条指令带有1个参数,实际上统共便是
2个坐标值:SP和EP(SP和EP都是16位的,由2个8位组成),即页地址的起始值和结束值,SP
必须小于即是EP,且0≤SP/EP≤799。一样平常在设置y坐标的时候,我们只须要带0X2B00和
0X2B01两条指令即可,也便是设置SP即可,由于如果EP没有变革,我们只须要设置一次即可
(在初始化NT35510的时候设置),从而提高速率。
接下来看指令:0X2C00,该指令是写GRAM指令,在发送该指令之后,我们便可以往LCD的
GRAM里面写入颜色数据了,该指令支持连续写,指令描述如下表所示:
图10.1.14 0X2C00指令描述
从上表可知,在收到指令 0X2C00之后,数据有效位宽变为16位,我们可以连续
写入LCD GRAM值,而GRAM的地址将根据MY/MX/MV设置的扫描方向进行自增。例如:假
设设置的是从左到右,从上到下的扫描办法,那么设置好起始坐标(通过SC,SP设
置)后,每写入一个颜色值,GRAM地址将会自动自增1(SC++),如果碰到EC,则回
到 SC,同时SP++,一贯到坐标:EC,EP结束,其间无需再次设置的坐标,从而大大
提高写入速率。
末了,来看看指令:0X2E00,该指令是读 GRAM 指令,用于读取 NT35510 的显存(GRAM),该指令在NT35510的数据手册上面的描述是有误的,真实的输出情形如
下表所示:
表10.1.11 0X2E00指令描述
该指令用于读取GRAM,如上表所示,NT35510在收到该指令后,第一次输出的是dummy数
据,也便是无效的数据,第二次开始,读取到的才是有效的GRAM数据(从坐标:SC,SP开
始),输出规律为:每个颜色分量占8个位,一次输出2个颜色分量。比如:第一次输出是
R1G1,随后的规律为:B1R2→G2B2→R3G3→B3R4→G4B4→R5G5...以此类推。如果我们只须要
读取一个点的颜色值,那么只须要吸收到参数3即可,如果要连续读取(利用GRAM地址自增,
方法同上),那么就按照上述规律去吸收颜色数据。
以上,便是操作NT35510常用的几个指令,通过这几个指令,我们便可以很好的掌握
NT35510 显示我们所要显示的内容了。
图10.1.15 TFTLCD利用流程
任何LCD,利用流程都可以大略的用以上流程图表示。个中硬复位和初始化序列,只须要
实行一次即可。而画点流程便是:设置坐标→写GRAM指令→写入颜色数据,然后在LCD 上
面,我们就可以看到对应的点显示我们写入的颜色了。读点流程为:设置坐标→读GRAM指令
→读取颜色数据,这样就可以获取到对应点的颜色数据了。
以上只是最大略的操作,也是最常用的操作,有了这些操作,一样平常就可以正常利用
TFTLCD了。接下来,我们开始利用Nios II驱动TFTLCD并使其显示。
实验任务
本章我们利用Nios II驱动TFTLCD,并使其显示图片,图片上叠加字符显示。
硬件设计
本章实验的硬件框架如下图所示:
图10.3.1 TFTLCD显示实验的硬件框架图
顶层代码如下:
1 module qsys_lcd(
2 //module clock
3 input sys_clk , //系统时钟,50Mhz
4 input sys_rst_n , //系统复位,低电平有效
5
6 //SDRAM interface
7 output sdram_clk , //SDRAM 芯片时钟
8 output sdram_cke , //SDRAM 时钟有效
9 output sdram_cs_n , //SDRAM 片选
10 output sdram_ras_n, //SDRAM 行有效
11 output sdram_cas_n, //SDRAM 列有效
12 output sdram_we_n , //SDRAM 写有效
13 output [ 1:0] sdram_ba , //SDRAM Bank地址
14 output [12:0] sdram_addr , //SDRAM 行/列地址
15 inout [15:0] sdram_data , //SDRAM 数据
16 output [ 1:0] sdram_dqm , //SDRAM 数据掩码
17
18 //EPCS FLASH interface
19 output epcs_dclk , // EPCS 时钟旗子暗记
20 output epcs_sce , // EPCS 片选旗子暗记
21 output epcs_sdo , // EPCS 数据输出旗子暗记
22 input epcs_data0, // EPCS 数据输入旗子暗记
23
24 //MCU LCD interface
25 inout [15:0] mlcd_data , // LCD 数据旗子暗记
26 output mlcd_bl , // LCD 背光旗子暗记
27 output mlcd_cs_n , // LCD 片选旗子暗记
28 output mlcd_wr_n , // LCD 写旗子暗记
29 output mlcd_rd_n , // LCD 读旗子暗记
30 output mlcd_rs , // LCD 命令/数据旗子暗记
31 output mlcd_rst_n // LCD 复位旗子暗记
32 //user interface
33
34 );
35
36 //wire define
37 wire clk_100m; //SDRAM 掌握器时钟
38 wire rst_n ; //系统复位旗子暗记
39 wire locked ; //PLL输出稳定标志
40
41 //
42 // main code
43 //
44
45 //待PLL输出稳定之后,停滞系统复位
46 assign rst_n = sys_rst_n & locked;
47
48 //例化PLL
49 pll_clk u_pll_clk(
50 .areset (~sys_rst_n),
51 .inclk0 (sys_clk ),
52 .c0 (clk_100m ),
53 .c1 (sdram_clk ),
54 .locked (locked )
55 );
56
57 //例化Nios2系统模块
58 nios2os u_nios2os (
59 .clk_clk (clk_100m ), // 时钟100M
60 .reset_reset_n (rst_n ), // 复位旗子暗记
61 .sdram_addr (sdram_addr ), // SDRAM 行/列地址
62 .sdram_ba (sdram_ba ), // SDRAM Bank地址
63 .sdram_cas_n (sdram_cas_n), // SDRAM 列有效
64 .sdram_cke (sdram_cke ), // SDRAM 时钟有效
65 .sdram_cs_n (sdram_cs_n ), // SDRAM 片选
66 .sdram_dq (sdram_data ), // SDRAM 数据
67 .sdram_dqm (sdram_dqm ), // SDRAM 数据掩码
68 .sdram_ras_n (sdram_ras_n), // SDRAM 行有效
69 .sdram_we_n (sdram_we_n ), // SDRAM 写有效
70 .epcs_dclk (epcs_dclk ), // EPCS 时钟旗子暗记
71 .epcs_sce (epcs_sce ), // EPCS 片选旗子暗记
72 .epcs_sdo (epcs_sdo ), // EPCS 数据输出旗子暗记
73 .epcs_data0 (epcs_data0 ), // EPCS 数据输入旗子暗记
74 .mlcd_data_export (mlcd_data ), // LCD 数据旗子暗记
75 .mlcd_cs_n_export (mlcd_cs_n ), // LCD 片选旗子暗记
76 .mlcd_wr_n_export (mlcd_wr_n ), // LCD 写旗子暗记
77 .mlcd_rd_n_export (mlcd_rd_n ), // LCD 读旗子暗记
78 .mlcd_rst_n_export(mlcd_rst_n ), // LCD 复位旗子暗记
79 .mlcd_rs_export (mlcd_rs ), // LCD 命令/数据旗子暗记
80 .mlcd_bl_export (mlcd_bl ) // LCD 背光旗子暗记
81 );
82
83 endmodule
顶层代码紧张实现PLL和Nios II系统模块的例化。
软件设计
创建好软件工程后,我们将hello_world.c变动为qsys_lcd.c,并在qsyslcd的运用工程
下新建一个文件夹,命名为drive,里面存放TFTLCD的驱动代码文件和相应的字体文件,文件
夹构造如下图所示:
图 10.4.1 文件构造
个中font.h是由取模软件“PCtoLCD2002”天生的不同字体大小的ASCII码字模文件,除
了支持0~9的10个数字字符和26个英笔墨母的大小写ASCII字符集外,还支持如下字符
集: !"#$%&'()+,-./:;<=>?@ [\]^_`{|}~,能显示四种字符点阵大小:1212、1616、
2424和3232。mculcd.h是TFTLCD驱动文件的头文件,mculcd.c是TFTLCD驱动文件的c文件。
由于这两个文件的代码较多,我们这里就不贴出来了,只针对几个主要的函数进行讲解。
我们先先容一下mculcd.h里面的一个主要构造体:
//LCD主要参数集
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坐标指令
}_lcd_dev;
//LCD参数
_lcd_dev lcddev; //管理LCD主要参数
该构造体用于保存一些TFTLCD主要参数信息,比如TFTLCD的长宽、LCD ID(驱动IC型
号)、LCD横竖屏状态等,这个构造体虽然占用了十几个字节的内存,但是却可以让我们的驱
动函数支持不同尺寸的LCD,同时可以实现LCD横竖屏切换等主要功能,以是还是利大于弊
的。有了以上理解,下面我们开始先容mculcd.c里面的一些主要函数。
//LCD延迟函数,单位毫秒
void delay_ms(u32 n)
{
usleep(n1000);
}
//LCD写命令
void LCD_WR_CMD(u16 Cmd)
{
IOWR_ALTERA_AVALON_PIO_DIRECTION(MLCD_DATA_BASE,0xFFFF); // 设置DATA PIO为输出
IOWR_ALTERA_AVALON_PIO_DATA(MLCD_RS_BASE,0); // 拉低RS
IOWR_ALTERA_AVALON_PIO_DATA(MLCD_RD_N_BASE,1); // RD设为高电平
IOWR_ALTERA_AVALON_PIO_DATA(MLCD_WR_N_BASE,0); // 拉低WR
IOWR_ALTERA_AVALON_PIO_DATA(MLCD_DATA_BASE,Cmd); // 往DATA端口写命令
IOWR_ALTERA_AVALON_PIO_DATA(MLCD_WR_N_BASE,1); // 拉高WR
}
//LCD写数据
void LCD_WR_DATA(u16 Data)
{
IOWR_ALTERA_AVALON_PIO_DATA(MLCD_RS_BASE,1);
IOWR_ALTERA_AVALON_PIO_DATA(MLCD_RD_N_BASE,1);
IOWR_ALTERA_AVALON_PIO_DATA(MLCD_WR_N_BASE,0);
IOWR_ALTERA_AVALON_PIO_DATA(MLCD_DATA_BASE,Data);
IOWR_ALTERA_AVALON_PIO_DATA(MLCD_WR_N_BASE,1);
}
//LCD读数据
u16 LCD_RD_DATA()
{
u16 read_data = 0;
IOWR_ALTERA_AVALON_PIO_DIRECTION(MLCD_DATA_BASE,0x0000); // 设置DATA PIO为输入
IOWR_ALTERA_AVALON_PIO_DATA(MLCD_RS_BASE,1);
IOWR_ALTERA_AVALON_PIO_DATA(MLCD_RD_N_BASE,0);
IOWR_ALTERA_AVALON_PIO_DATA(MLCD_WR_N_BASE,1);
IOWR_ALTERA_AVALON_PIO_DATA(MLCD_RD_N_BASE,1);
read_data = IORD_ALTERA_AVALON_PIO_DATA(MLCD_DATA_BASE);
return read_data;
}
//LCD写寄存器数据
void LCD_WriteReg(u16 LCD_Reg,u16 LCD_RegValue)
{
LCD_WR_CMD(LCD_Reg); // 写入的寄存器
LCD_WR_DATA(LCD_RegValue); // 写入的数据
}
//LCD读寄存器
u16 LCD_ReadReg(u16 LCD_Reg)
{
LCD_WR_CMD(LCD_Reg); // 要读取的寄存器
usleep(5); // 延时5us
return LCD_RD_DATA(); // 返回读取的数据
}
//开始写GRAM
void LCD_WriteRAM_Prepare(void)
{
LCD_WR_CMD(lcddev.wramcmd);
}
//LCD写GRAM
//RGB_Code:颜色值
void LCD_WriteRAM(u16 RGB_Code)
{
LCD_WR_DATA(RGB_Code); //写十六位GRAM
}
从该代码中我们可以看出,写命令和读写数据完备符合我们的时序图。须要把稳的是,
由于DATA PIO为双向的,以是在读写命令或数据之前须要先设置其方向,否则读写不堪利。
接下来我们先容的是画点函数。该函数实当代码如下:
//画点
//x,y:坐标
//POINT_COLOR:此点的颜色
void LCD_DrawPoint(u16 x,u16 y)
{
LCD_SetCursor(x,y); //设置光标位置
LCD_WriteRAM_Prepare(); //开始写入GRAM
LCD_WR_DATA(POINT_COLOR);
}
该函数实现比较大略,便是先设置坐标,然后往坐标写颜色。个中POINT_COLOR是我们定
义的一个全局变量,用于存放画笔颜色,顺带先容一下其余一个全局变量:BACK_COLOR,该
变量代表LCD的背景色。LCD_DrawPoint函数虽然大略,但是至关主要,其他险些所有上层函
数,都是通过调用这个函数实现的。
有了画点函数,自然就可以用画点函数显示字符串。显示字符串函数如下:
//显示字符串
//x,y:出发点坐标
//width,height:区域大小
//size:字体大小
//p:字符串起始地址
//mode:叠加办法(1)还是非叠加办法(0)
void LCD_ShowString(u16 x,u16 y,u16 width,u16 height,u8 size,u8 mode,u8 p)
{
u8 x0=x;
width+=x;
height+=y;
while((p<='~')&&(p>=' ')) { //判断是不是非法字符!
if(x>=width) {
x=x0;
y+=size;
}
if(y>=height)
break;//退出
LCD_ShowChar(x,y,p,size,mode);
x+=size/2;
p++;
}
}
字符串显示函数可以设置显示的位置x、y,和显示字体的大小size,还可以以叠加办法
显示,或者以非叠加办法显示。叠加办法显示多用于在显示的图片上再显示字符。非叠加方
式一样平常用于普通的显示。
TFTLCD最大的用途是显示图片,自然须要先容一下图片显示函数,函数如下:
//x,y:出发点坐标
//size:图片大小
//LCD显示图片
void LCD_DisplayPic(u16 x,u16 y,u32 size,const u8 pic)
{
u32 i;
LCD_SetCursor(x,y);
LCD_WriteRAM_Prepare(); //开始写入GRAM
for(i=0; i < size; i++)
LCD_WR_DATA(pic[i2]<<8 | pic[i2+1]);
}
这里假设图片经转换后得到的头文件数据类型是char类型,为8位,由于一个像素须要16
位(RGB565),以是须要合并两个8位为16,如果图片经转换后得到的头文件数据类型是16位
的,LCD_WR_DATA(pic[i2]<<8 | pic[i2+1])应改为LCD_WR_DATA(pic[i])。
末了,我们再先容一下TFTLCD模块的初始化函数MCULCD_Init,该函数先复位TFTLCD,然
后读取TFTLCD掌握器(驱动芯片)的型号,根据掌握IC的型号实行不同的初始化代码,由于
该函数代码较长,我们摘录部分如下:
//TFTLCD初始化
void MCULCD_Init(void)
{
//TFTLCD 复位
IOWR_ALTERA_AVALON_PIO_DATA(MLCD_RST_N_BASE,0);
delay_ms(100);
IOWR_ALTERA_AVALON_PIO_DATA(MLCD_RST_N_BASE,1);
IOWR_ALTERA_AVALON_PIO_DATA(MLCD_CS_N_BASE,1);
IOWR_ALTERA_AVALON_PIO_DATA(MLCD_RD_N_BASE,1);
IOWR_ALTERA_AVALON_PIO_DATA(MLCD_WR_N_BASE,1);
IOWR_ALTERA_AVALON_PIO_DATA(MLCD_CS_N_BASE,0);
delay_ms(50);
//考试测验9341 ID的读取
LCD_WR_CMD(0XD3);
lcddev.id=LCD_RD_DATA(); //dummy read
lcddev.id=LCD_RD_DATA(); //读到0X00
lcddev.id=LCD_RD_DATA(); //读取93
lcddev.id<<=8;
lcddev.id|=LCD_RD_DATA(); //读取41
if(lcddev.id!=0X9341) //非9341,考试测验看看是不是NT35310
……
主函数部分的代码如下:
1 #include <stdio.h>
2 #include <unistd.h>
3 #include "./drive/mculcd.h"
4 #include "pic01.h" //显示的图片
5
6 int main()
7 {
8 MCULCD_Init();
9 POINT_COLOR=MLCD_RED;
10
11 LCD_DisplayPic(0,0,lcddev.width lcddev.height,gImage_pic01);
12
13 LCD_ShowString(30,50,300,30,24,1,"Welcome to PIONEER FPGA");
14 LCD_ShowString(30,80,400,30,24,1,"This is a TFT LCD test application");
15 LCD_ShowString(30,110,200,30,24,1,"ATOM@ALIENTEK");
16 LCD_ShowString(30,140,200,30,24,1,"2018/10/10");
17
18 return 0;
19 }
“pic01.h”是由Image2Lcd软件转换得到的图片文件,该软件我们在《开拓者FPGA开拓
指南》的第四十章 SD卡图片显示实验(VGA显示)中已先容其利用,这里我们再大略的先容
下利用步骤,按下图箭头指示的方向,首先打开选择一幅分辨率为800480的jpg或bmp格式的
图片,图片加载进来之后,在工具界面左侧设置输出数据类型为“C措辞数据(.c)”,扫描
模式为“垂直扫描”,输出灰度为“16位真彩色”,最大宽度和高度分别为“800”和
“480”,选中“自右至左扫描”和“高位在前(MSB First)”。设置完成后在菜单栏中点
击“保存”,并在弹出的界面中选择C file(.c;.h)文件的保存路径并输入文件名,后缀
为.h,我们这里设置文件名为pic01.h。
图 10.4.2 图片转换设置
代码第17行的gImage_pic01是pic01.h中的数组,如下图所示:
图 10.4.3 转换后得到的图片数组
这里的字符显示我们设置为叠加模式,当然了也可以设置为非叠加模式,叠加模式在图
片上显示字符效果好。
下载验证
讲完了软件工程,接下来我们就将该实验下载至我们的开拓者开拓板进行验证。
首先我们将4.3寸的ATK-4.3’TFTLCD与开拓板上的MCU TFT LCD接口连接。再将下载器一
端连电脑,另一端与开拓板上对应端口连接,末了连接电源线并打开电源开关。开拓者开拓
板实物图如下所示:
图 10.5.1 开拓板实物图
接下来我们下载程序,验证TFT LCD显示功能。
我们在Quartus II软件中将qsys_lcd.sof文件下载至我们的开拓者开拓板,
qsys_lcd.sof下载完成后,我们还须要在Nios II SBT for Eclipse软件中将qsys_lcd.elf文
件下载至我们的开拓者开拓板,qsys_lcd.elf下载完成往后,我们的C程序将会实行在我们的
开拓者开拓板上,运行结果如下图所示。
图 10.5.2 实验结果图
图片上叠加显示我们写入的字符。至此,我们的TFT LCD显示实验就完成了。