通过本实验了解触摸屏的触摸原理和显示原理,能够在液晶屏上开发应用。
本实验要求:
1. 将存储在Flash中的一幅图像显示在液晶屏上。
2. 将用户在触摸屏上触摸的坐标显示在8段数码管上。



2.1 液晶屏的基本原理

液晶显示是目前最常用的显示方式,无论是简单的黑白显示还是高清晰度的数字电视,大量使用了液晶显示。液晶屏的基本物理原理是:液晶分子在不通电时排列混乱,阻止光线通过;当液晶上加一定电压时,分子便会重新垂直排列,使光线能直射出去,从而可以在液晶阵列上显示不同的图形。

本实验使用的液晶屏分辨率为400×240,其控制芯片为ILI9326。对于液晶屏显示的操作主要体现在对控制芯片ILI9326的操作上。

对ILI9326进行的操作可以分为读、写两种操作,本实验中主要用到写操作,在此简要介绍FPGA如何向ILI9326进行写操作。具体到写操作又可以分为两种操作模式:第一是对芯片ILI9326中寄存器的设置操作,第二是对ILI9326中存储像素值的GRAM的操作。本实验使用的液晶屏分辨率为400×240,一共有96000个像素点,而每一个像素点对应于一位16位宽的GRAM,也就是说通过控制ILI9326内部的GRAM即可以控制液晶屏的显示内容。

对ILI9326中控制寄存器的设置操作时序为:首先输出寄存器的编号,然后输出要向该寄存器写入的数据,其时序如图 20-1所示。在nWR的上升沿和RS信号为低时FPGA向从设备ILI9326送出寄存器的编号,而在下一个nWR的上升沿和RS信号为高时FPGA输出要写入数据。

图20-1 设置控制寄存器时序

图20-1 设置控制寄存器时

对ILI9326中GRAM的写操作时序为:首先在nWR的上升沿和RS为低电平的时FPGA向ILI9326发送0202h,然后在nWR的上升沿和RS为高电平期间FPGA逐次向ILI9326发送需要显示的图像像素数据(图 20 2)。在每写完一个图像像素数据后,ILI9326内部的计数器会自动加一,使下一个写入的数据对于下一个像素,以此类推达到控制液晶屏显示内容的目的。 图20-2 写入需要显示的图像信号

图20-2 写入需要显示的图像信号

2.2 触摸屏的基本原理

触摸屏(Touch panel)是可以接收触头等输入讯号的感应式显示装置,当触头接触了屏幕时,屏幕上的触觉反馈系统就可以感应到触头接触的位置。

从技术原理上,触摸屏可以分为五类:矢量压力传感技术触摸屏、电阻技术触摸屏、电容技术触摸屏、红外线技术触摸屏、表面声波技术触摸屏。其中矢量压力传感技术触摸屏已退出历史舞台;红外线技术触摸屏价格低廉,但其外框易碎,容易产生光干扰,曲面情况下失真;电容技术触摸屏设计构思合理,但其图像失真问题很难得到根本解决;电阻技术触摸屏的定位准确,但其价格颇高,且怕刮易损;表面声波触摸屏解决了以往触摸屏的各种缺陷,清晰不容易被损坏,适于各种场合,缺点是屏幕表面如果有水滴和尘土会使触摸屏变的迟钝,甚至不工作。按照触摸屏的工作原理和传输信息的介质,我们把触摸屏分为四种,它们分别为电阻式、电容感应式、红外线式以及表面声波式。每一类触摸屏都有其各自的优缺点,要了解那种触摸屏适用的场合,关键就在于要理解每一类触摸屏技术的工作原理和特点。下面对实际中应用较多的电容和电阻式触摸屏进行简要介绍一下。

  1. 电容式触摸屏  

电容技术触摸屏是利用人体的电流感应进行工作的。电容式触摸屏是是一块四层复合玻璃屏,玻璃屏的内表面和夹层各涂有一层ITO(氧化铟),最外层是一薄层矽土玻璃保护层,夹层ITO涂层作为工作面,四个角上引出四个电极,内层ITO为屏蔽层以保证良好的工作环境。 当手指触摸在金属层上时,由于人体电场,用户和触摸屏表面形成以一个耦合电容,对于高频电流,电容是直接导体,于是手指从接触点吸走一个很小的电流。这个电流分从触摸屏的四角上的电极中流出,并且流经这四个电极的电流与手指到四角的距离成正比,控制器通过对这四个电流比例的精确计算,得出触摸点的位置。

  1. 电阻式触摸屏

这种触摸屏利用压力感应进行控制。电阻触摸屏的主要部分是一块与显示器表面非常配合的电阻薄膜屏,这是一种多层的复合薄膜,它以一层玻璃或硬塑料平板作为基层,表面涂有一层透明氧化金属(透明的导电电阻)导电层,上面再盖有一层外表面硬化处理、光滑防擦的塑料层、它的内表面也涂有一层涂层、在他们之间有许多细小的(小于1/1000英寸)的透明隔离点把两层导电层隔开绝缘。 当手指触摸屏幕时,两层导电层在触摸点位置就有了接触,电阻发生变化,在X和Y两个方向上产生信号,然后送触摸屏控制器。控制器侦测到这一接触并计算出(X,Y)的位置。

而本实验中使用的TSC2046是一种典型的电阻式触摸屏,其采用的是逐次逼近型模数转换器(SAR ADC),包含了采样/保持、模数转换、串口数据 输出等功能。同时芯片集成有一个2.5V的内部参考电压源、温度检测电路,工作时使用外部时钟。TSC2046可以单电源供电,电源电压范围为 2.7V~5.5V。参考电压值直接决定ADC 的输入范围,参考电压可以使用内部参考电压,也可以从外部直接输入1V~VCC 范围内的参考电压(要求外部参考电压源输出阻抗低)。X、Y、Z、VBAT、Temp和 AUX模拟信号经过片内的控制寄存器选择后进入ADC,ADC可以配置为单端或差分模式。选择VBAT、Temp和AUX时应该配置为单端模式;作为触摸屏应用时,应该配置为差分模式,这可有效消除由于驱动开关的寄生电阻及外部的干扰带来的测量误差,提高转换精度。

其基本控制方式为:
首先通过SSI串行接口向TSC2046发送8位控制字(DIN),设置需要数模转换的信号(X、Y、Z、VBAT、Temp和 AUX等)和精度等,延时一个时钟周期后可以通过SSI接口读取相应的模拟信号数字化后的数数值,具体时序如图20-3所示。

发送给TSC2046的8位控制字的设置方式可以根据具体情况进行选择。通过8位控制字可以选择ADC的分辨率,即选择是8位分辨率还是12位分辨率。当设置为12位分辨率时得SSI数字接口如图20-3所示,而8位分辨率的传输时序基本类似。 图20-3 SSI数字接口时序

图20-3 SSI数字接口时序



3.1 总体架构

整个程序有5个模块构成,如图 20 4所示: 1. TFT是顶层模块,实例化各子模块并连接各子模块。 2. ping模块主要负责液晶屏的控制与显示。 3. touch模块负责控制和读取触摸屏上面的坐标值。 4. data2disp模块负责输入键值的译码,因为要分别对X坐标和Y坐标进行译码,而每一个坐标均需要2个七段数码管,所以程序中使用了4个data_2_disp模块。 5. U1模块是PLL模块,产生屏幕显示所需要的10MHz和5MHz的时钟。 图20-4 程序总体架构

图20-4 程序总体架构

3.2 液晶显示模块ping (ping.v)

Ping模块的基本思路为:首先对显示控制芯片ILI9326进行初始设置,然后将存储在Flash内的图像数据写入ILI9326中,将图像显示在液晶屏上。

该程序的接口主要分为两个部分,一部分是液晶屏接口部分,另一部分是Flash接口部分。 Ping模块的接口如下:

 
iRst         //全局异步复位
iClk50       //全局时钟 50Mhz
//液晶屏接口
oRst        //液晶屏异步复位
oCs_TFT    //液晶屏片选信号,低电平有效,只有在片选信号有效时,
//才能对液晶屏进行操作
oRs         //在对液晶屏控制芯片进行配置期间,该信号用于区分数据线上是寄//存器编号还是要向该寄存器写入的数据
oWr        //操作液晶屏控制芯片的时钟信号,上升沿有效
oData       //16位宽的数据线		
//Flash接口
FL_DQ		//Flash 数据接口
FL_CE_N   //Flash片选信号
FL_ADDR  //Flash地址信号
FL_OE_N   //Flash输出使能
FL_WE_N	//Flash输入使能
FL_RST_N  //Flash复位
FL_RY_BY  //Flash忙指示信号

Ping模块中的主要状态机为State,state的状态转移图如图 20 5所示。 图20-5 ping模块内的State状态机

图20-5 ping模块内的State状态机

状态机的跳转主要由计数器counter来进行控制。在counter的不同数值对应不同时间整个程序进入不同状态,具体跳转条件见程序。

程序一共有3个状态:WAIT、CONFIG和WRITEDATA:

WAIT状态:有两个可能程序处于WAIT状态时间,第一是上电后需要延时,因为液晶屏点亮等操作需要对电容等充电,在上电后程序出WAIT状态等待系统充电稳定。第二就是在配置ILI9326周期内,如果某些配置后同样需要ILI9326稳定一段时间后才能接着向下配置,此时程序也需要进入WAIT状态。

CONFIG状态:当程序处于CONFIG状态,程序从保存配置文件的内部ROM中读取配置数据,对ILI9326进行配置。配置内容参看文件displayData.hex。

WRITEDATA状态:主要是在配置完成后,从FLASH内读取待显示的数据写入ILI9326的GRAM内,控制液晶屏的显示内容。完成显示数据的读写后,程序进入WAIT,直至手动复位。具体程序如下所示:

 
always@(posedge clk_sys) begin
if(counter<=start_size + 1000) begin
			State <= WAIT;     //在start_size + 1000个时钟周期内,为上电延时
			color <= 1'b0;
		end
		else 
if(
				      ((start_size + 1000<counter)&(counter<=start_size + 1008))
				      |
				      ((start_size + 1108<counter)&(counter<=start_size + 1150))
				      |
				      ((start_size + 2150<counter)&(counter<=start_size + 2182))
				      |
				      ((start_size + 3182<counter)&(counter<=start_size + 3184))
				      |
				      ((start_size + 4184<counter)&(counter<=start_size + 4189))
				      )			//Write_Register(0x00,  0x00000);
				begin
State <= CONFIG;  //在start_size + 1000到start_size + 4190时钟周//期内状态在不停在WAIT和CONFIG之间跳转
                 //而在处于CONFIG状态时间,程序对液晶屏进//行配置
color <= 1'b0;
				end
				else 
if(
				   ((start_size + 1008<counter)&(counter<=start_size + 1208))
				   |
				   ((start_size + 1150<counter)&(counter<=start_size + 2150))
				   |
				   ((start_size + 2182<counter)&(counter<=start_size + 3182))
				   |
				   ((start_size + 3184<counter)&(counter<=start_size + 3184))
				   )		//delayms(20);//{time, 0010, ms);
				begin
State <= WAIT; //在start_size + 1000到start_size + 4190时钟周
//期内状态在不停在WAIT和CONFIG之间跳转
                //而在处于WAIT状态时间,程序在等待液晶屏
//的延时动作。
		      			color <= 1'b0;
				end
				else 
if( (counter > start_size + 4190) & (counter<All_Size)) begin
State <= WRITEDATA;//在此期间程序从FLASH内读取数据,//GRAM内写入数据
color <= 1'b1;
				end
				else  begin
					State <= WAIT;//进入最后的休眠状态。
			   		color <= 1'b0;
				end
end
		end
	end
	当处于CONFIG状态时,程序从内部ROM(registerData)存储器中读取出配置文件,该ROM地址生成程序如下所示:
always@(negedge clk_sys or negedge oRst)
begin
	if(!oRst)
		address <= 7'b0;
	else if(State == CONFIG)//处于CONFIG状态,ROM地址自动增加
		address <= address + 1'b1;
	else
		address <= address;		
end
 
Flash接口时序控制程序如下所示:
assign FL_WE_N = 1'b1;    //实验仅仅需要读取Flash,所以该信号一直拉高
assign FL_RST_N = iRst;    //Flash复位信号
assign FL_CE_N = 1'b0;     //片选信号总是有些
assign FL_OE_N = 1'b0;     //读输出总是有效
	而当程序处于WRITEDATA状态,也就是读取存储在FLASH内部的图像数据向TFT屏写入的状态时,其FLASH地址需要不断增加,程序如下所示:
always@(negedge flashclk or negedge oRst) begin //生成Flash地址信号 
		if(!oRst)	begin
			FL_ADDR <= 25'b0;
		end
		else begin 
if(color_d == 1'b1) // color_d 为color的一个时钟延时,而color在WRITEDATA
//状态被拉低,也就是程序处于WRITEDATA状态时
//Flash地址自动增加
begin 
FL_ADDR <= FL_ADDR + 1'b1;
			end
			else
				FL_ADDR <= FL_ADDR;
		end
end
 
reg [7:0] FL_DQ_d;
always@(negedge flashclk or negedge oRst) begin //读取Flash信号
		if(!oRst)	begin
			FL_DQ_d <= 8'b0;
		end
		else
			FL_DQ_d <= FL_DQ;
end

程序中有一点时序需要注意,那就是GRAM位宽为16位,而Flash的位宽为8位,所以读取Flash的时钟需要是写入GRAM的时钟速率的两倍。将读取出来的两个8位Flash数据合并写入GRAM内。

其对应的时钟信号生成程序如下所示:

 
//分频以产生系统时钟
wire clk_sys;//5MHz	
wire flashclk;//10MHz
 
Pll U1(.inclk0(iClk50),
	.c0(flashclk),
	.c1(clk_sys));

3.3 触摸屏touch模块(touch.v)

触摸屏touch模块检测触点坐标的基本原理是:等待触摸屏送出IRQ终端信号,在检测到终端信号后,向触摸屏控制芯片TSC2046写入控制字,在写入控制字后通过SSI接口读取相应触点的x、y坐标位置,并将坐标位置显示在7段数码管上。

触摸屏主要有六个信号:CS、DCLK、DIN、BUSY、DOUT和IRQ,在检测到中断IRQ后,通过DOUT输出控制字,然后通过DIN接收坐标位置;CS为片选信号,DCLK为访问时钟;在输出控制字后,触摸屏置BUSY为高一个时钟周期,表示触摸屏正忙。 触摸屏模块touch的数据流如图20-6所示。 图20-6 触摸屏程序框图

图20-6 触摸屏程序框图

Ping模块的接口分两部分:一部分是与触摸屏控制芯片的接口,一部分是与显示坐标数据的8段数码管接口。与触摸屏的接口如下:

 
input 	IRQ;  	//触摸屏产生的中断信号,有触摸时IRQ为低。
input 	iBusy; 	//触摸屏工作中指示信号,为高时表示触摸屏忙。
input 	Din;  	//从触摸屏输入到FPGA的坐标位置数据。
output 	Dclk;	//接口时钟。
output 	Dout; 	//FPGA向触摸屏发送的控制信号。
output 	oCs; 	//触摸屏片选信号。
与显示坐标数据的7段数码管有关的引脚如下:                                                    
output [7:0]HEX_sel;	//七段数码管片选信号线。
output [7:0]HEX_seg;	//数码管显示的数据。

Touch模块主要受状态机State控制,其状态转移图如图 20-7所示。

图20-7 触摸屏程序状态机

图20-7 触摸屏程序状态机

State有XCONFIG、XDATA、YCONFIG和YDATA4个状态:

X_CONFIG状态:对TSC2046进行设置,以测试X方向的坐标。

X_DATA状态:读取TSC2046送来的X方向坐标值。

Y_CONFIG状态:对TSC2046进行设置,以测试Y方向的坐标。

Y_DATA状态:读取TSC2046送来的Y方向坐标值。

状态机的状态转移由计数器counter来进行控制。在初始时,State处于Y_DATA,而当IRQ被拉低期间,counter每个时钟自动增加,从而驱动状态机发生跳转以读取x、y坐标,并将坐标显示在八段数码管上。当触摸屏受到触发时IRQ信号被拉低,一般情况下拉低的周期足够完成状态机的跳转(因为FPGA运转很快,而人的操作则相对缓慢),完成坐标位置的读写。具体程序如下:

 
 reg [2:0] state;
 reg [11:0] counter;
 always@(negedge Dclk or negedge iRst) begin
 	if(!iRst)
         counter <= 12'b0;
    else begin
if(IRQ==1'b1)
		 counter <= 12'b0;
	 else					//在IRQ为低时,表示有触摸,counter开始工作。
         counter <= counter + 1'b1;  
		end
 end
 
always@(posedge Dclk or negedge iRst) begin
	if(!iRst) begin
         state <= Y_DATA;
	end
	else begin
	      if((counter>=3000) && (counter < 3008))
	         state <= X_CONFIG;  //发送命令:读取x坐标值
	      else if((counter >=3008) && (counter <3024))
	         state <= X_DATA;    //读取x坐标值
	      else if((counter >=3024) && (counter <3032))
	         state <= Y_CONFIG;  //发送命令:读取y坐标值
	      else
	         state <= Y_DATA; //读取y坐标值
	end
end

需要说明的是,因为该接口时钟为百K量级,所以触摸屏程序的时钟是通过内部触发器产生,没有统一到整个系统时钟域内。



从SignalTap中观测触摸屏程序中读取坐标值的信号如图 20 8所示,其中在XCONFIG、XDATA、YCONFIG、和YDATA 有效期间,Din和Dout在Dclk时钟控制下对TSC2046进行配置和读取。其中在XCONFIG有效期间程序向TSC2046发送的数据为8'b00011011,而在YCONFIG有效时程序向TSC2046发送的数据为8' b00011001。 图20-8 运行结果

图20-8 运行结果



文件名功能
TFT.v顶层模块。
ping.v液晶屏控制模块。
touch.v控制和读取触摸屏上面的坐标值。
data_2_display.v显示触点坐标。
displayData.hex该文件存储液晶屏芯片ILI9326的配置数据, 16位宽,奇数地址存储ILI9326的寄存器地址,偶数地址存储待向该地址写入配置数据。



演示设备:核心板、扩展板。

演示方法:首先需要用Nios将图像“tft屏显示图像.bmp”烧到Flash中,起始地址为0x0。然后把程序下载到开发板上之后,液晶屏上将显示烧入的图像。如果FLASH内没有烧入图像,液晶屏上将液晶花屏。用手指触摸液晶屏,可以看到在8段数码上显示当前触点的坐标值。