用户工具

站点工具


tft_lcd触摸屏实验
银杏科技有限公司旗下技术文档发布平台
技术支持电话0379-69926675-801
技术支持邮件Gingko@vip.163.com
版本 日期 作者 修改内容
V1.0 2019-12-25 gingko 初次建立

实验三十一:TFT_LCD触摸屏实验

一、实验目的与意义

  1. 了解触摸屏工作原理
  2. 掌握触摸屏驱动方式
  3. 学习触摸屏控制和TFT_LCD屏显示内容的交互

二、实验设备及平台

  1. iCore3 双核心板( FPGA型号为EP4CE10F17)。点击购买
  2. 转接板和40P的FPC连接线。
  3. iCore3(7寸TFT_LCD)液晶显示模块。点击购买
  4. Blaster(或相同功能的)仿真器。点击购买
  5. Micro USB线缆和USB线缆。
  6. QuartusII开发软件(本实验中使用的是13.1版本)。

图31-1硬件连接实物图

注意事项1: 注意FPC转接板和核心板之间引脚要对齐(如图31-1中处所示,转接板和核心板边缘要对齐)。

注意事项2: FPC软线与FPC接口连接时,请确认软排线接口处蓝色绝缘皮朝上(如图31-1中②③所示)。

注意事项3: 下载程序前请确认FPC连接线无误,且iCore3核心板引脚与PIN.tcl文件中绑定引脚相互对应。

三、实验原理

  • 实验中所采用的7寸电阻式触摸屏液晶屏,所以本实验是在TFT_LCD显示彩条实验的基础上加上触摸识别内容。触摸屏采集到模拟信号,经AD芯片转换为数字信号后被FPGA读取,进行触摸动作的判断。。如果判断有触摸动作,则切换液晶屏的色彩显示。因此这里对液晶屏的显示控制不再做详解,主要介绍触摸屏的工作原理,和TFT_LCD触摸屏模块AD转换芯片的配置。
1、触摸屏的工作原理
  • 由电阻式触摸屏的结构特性可知,触摸屏实际上是贴在显示屏上的电阻薄膜屏,而这个薄膜屏又由两个相互分离的导电层构成。当触触摸屏工作时,上下导电层相当于两个电阻网络,当上层薄膜加上电压时,该层薄膜上会有个电压梯度。如果按压屏幕,使上下两个导电层接触,那么下层就会带有接触点处的电压,通过对下层电压的检测就可以确定X轴或者Y轴方向的位置。同理,可得另一个方向的位置,那么就可以识别出按压点在屏幕当中的位置了。
  • 下图是AD转换芯片ads7843的典型应用电路,从图中也可以看出触摸屏作为等效电阻网络,通过四线连接到ads7843芯片的X+、X-、Y+、Y- 等引脚。经AD芯片转换后发送给FP GA或者ARM处理,从而判断触摸点的位置。

图31-2 ads7843基础应用电路

2、ads7843触摸屏AD芯片的配置
  • 本次实验所用触摸屏模块的AD芯片ads7843,具有同步串行接口,内置12位取样模数转换器,最高转换速率可达125KHz。由ads7843的原理图可以看到,AD芯片和FPGA之间是通过串行接口传送数据和指令的。其串行接口由DIN,DOUT,CS,DCLK 四个信号线构成。其中,DCLK提供串行传输时钟信号,DIN和DOUT则用与FPGA和AD芯片间指令数据的传输。CS作为选通信号,置低位有效。

图31-3 触摸屏模块ad转换电路原理图

3、触摸动作识别
  • 通过前面对触摸屏原理的学习,如果想识别到触摸动作,那么就要对ADS7843传送到FPGA的数据进行断,是否为触摸屏无触碰状态下的数值。
  • 图31-4是理想状态下识别的电压和输出编码之间对应关系,理论上触摸屏的输入坐标识别精度可达有效位宽的1/4096,对应的输出编码从3’h000到3’hfff。通过对其输出编码进行处理,判断是否为无触碰状态下的值,从而判断触摸动作有无发生。

图31-4 理想状态下ads7843输入电压和输出编码之间的对应关系图

四、代码讲解

  • 本次实验主要内容包括TFT_LCD的显示驱动,触摸屏的配置和驱动,TFT_LCD屏显示内容的控制及触摸动作的识别。由于TFT驱动和色彩显示部分前面实验已经做过讲解,这里主要讲一下触摸屏的驱动和触摸动作的识别部分。
  • 打开例程工程文件,打开TOUCH_Ctrl.v文件,首先看到的是对CS信号的处理。因为系统稳定后我们要一直检测触摸屏是否有触摸动作发生,一直有数据的传送,因此这里将CS做了一直拉低处理。
  • 然后我们会看到例程代码中有个DIN的always块,这个块是用来向AD芯片发送寄存器指令的。首先来看一下这段代码,如下:
	/*输入转换命令字符*/
	reg [7:0]DIN_x;
	reg [7:0]DIN_y;
	reg DIN_r;
 
	always @(negedge spi_clk or negedge RST_n)
	if (!RST_n)
		begin
			DIN_x <= 8'b1101_0000;	//转换X方向模拟量命令
			DIN_y <= 8'b1001_0000;	//转换Y方向模拟量命令
		end	
  • 这里DIN_x和DIN_y对应的指令值在ADS7843的手册中可以查到,是要配置到AD转换芯片的寄存器的值。DIN_x和DIN_y是X方向和Y方向转换时需要分别输入到AD寄存器的值。S位表示数据传输起始,必须置1。A2、A1、A0组合进行通道X或通道Y的选择。MODE是精度选择位,这里我们用的是12位输出,MODE位置0。SER/DFR表示参考电压的输入模式,这里选择的是0,即差动输入模式,PD1和PD0是省电模式的选择,00代表在两次AD转换之间掉电。如此,明白DIN_x和DIN_y被赋的值所代表的含义了吧?

图31-5 ads7843控制寄存器1
图31-5 ads7843控制寄存器2

  • 其次是DCLK,这部分代码是通过对30MHz时钟进行计数,分频产生100KHz时钟信号,即DCLK,用于串行通信。这里我们先看一下ADS7843的串行通信时序图,如下:

图31-6 ads7843串行通讯时序图

  • 从图中可以看到,DIN和DOUT的电平在DCLK的上升沿是需要保持稳定的,而且输入和输出AD芯片的数据都是先高位后地位的。前面我们有讲到,DCLK是以30MHz时钟为基础分频产生的,先来看一下这段代码:
//--------------------DCLK------------------//
	reg [9:0]cnt_clk;
	reg spi_clk = 1'd0;
	reg spi_clk_r = 1'd0;
 
	always @(negedge TOUCH_CLK or negedge RST_n)
		if (!RST_n)
			cnt_clk <= 10'd0;
		else if (cnt_clk == 10'd299)//分频计数器
			cnt_clk <= 10'd0;
		else
			cnt_clk <= cnt_clk + 1'd1; 
 
	always @(negedge TOUCH_CLK or negedge RST_n)
		if (!RST_n)
			begin
				spi_clk <= 1'd0;
				spi_clk_r <= 1'd0;
			end
		else if (cnt_clk == 10'd0)
			begin
				spi_clk <= 1'd1;
				spi_clk_r <= 1'd1;
			end
		else if (cnt_clk == 10'd150)
			spi_clk <= 1'd0;
		else if(cnt_clk == 10'd130)
			spi_clk_r <= 1'd0;					
	assign DCLK = spi_clk;		//转换时钟100KHz
  • 这段代码是分频产生DCLK的代码,这里有个计数器变量cnt_clk,计满300清零。然后有两个寄存器变量spi_clk和spi_clk_r。他们的不同之处在于spi_clk是在cnt_clk计数到150的时候电平发生变化,从而产生100KHz,占空比50%的DCLK。而spi_clk_r电平发生变化是在cnt_clk等于130的时候,那么spi_clk_r也相当于一个100KHz,和DCLK同步但电平变化较早的时钟信号。
  • 再看这段代码:
//--------------------spi_clk_counter------------------//
	reg [9:0]spi_clk_counter;
 
	always @(posedge spi_clk_r or negedge RST_n)
	if (!RST_n)
		spi_clk_counter <= 10'd0;
	else if (spi_clk_counter == 10'd999)
			spi_clk_counter <= 10'd0;
		else spi_clk_counter <= spi_clk_counter + 10'd1;
  • 变量spi_clk_counter以spi_clk_r的上升沿作为触发条件进行计数,计满1000个数清零。那么,再看下面这段代码就很好理解了,以spi_clk为时钟,将寄存器配置指令从高位到底位输出到AD芯片;由于命令字值的变化是以spi_clk_r为基础的,在spi_clk电平变化时保证了数据的稳定。
//--------------------DIN------------------//	
	/*输入转换命令字符*/
	reg [7:0]DIN_x;
	reg [7:0]DIN_y;
	reg DIN_r;
	always @(negedge spi_clk or negedge RST_n)
	if (!RST_n)
		begin
			DIN_x <= 8'b1101_0000;	//转换X方向模拟量命令
			DIN_y <= 8'b1001_0000;	//转换Y方向模拟量命令
		end
	else
	case (spi_clk_counter)
		10'd0: DIN_r <= DIN_x[7];
		10'd1: DIN_r <= DIN_x[6];
		10'd2: DIN_r <= DIN_x[5];
		10'd3: DIN_r <= DIN_x[4];	
		10'd4: DIN_r <= DIN_x[3];
		10'd5: DIN_r <= DIN_x[2];	
		10'd6: DIN_r <= DIN_x[1];
		10'd7: DIN_r <= DIN_x[0];
 
		10'd24: DIN_r <= DIN_y[7];
		10'd25: DIN_r <= DIN_y[6];
		10'd26: DIN_r <= DIN_y[5];
		10'd27: DIN_r <= DIN_y[4];
		10'd28: DIN_r <= DIN_y[3];
		10'd29: DIN_r <= DIN_y[2];
		10'd30: DIN_r <= DIN_y[1];
		10'd31: DIN_r <= DIN_y[0];
			default: DIN_r <= 1'd0;		
	endcase
	assign DIN = DIN_r;
  • 寄存器变量spi_clk_counter每秒可以计100次999,那么,如果在spi_clk_counter每次计数到999的过程中给ADS7843一个转换命令,也就代表着每秒采集100次AD转换值,以此判断是否有触摸动作。
  • 由于FPGA和ADS7843数据的传输采用的是串行接口,数据由高位到低位传输进FPGA之后,我们还要进行一个转换,并在转换完成后给数据处理模块一个标志位,代码如下:
	//--------------------DOUT------------------//
	/*实现AD转换*/
	reg [11:0]DOUT_x;
	reg [11:0]DOUT_y;
 
	always @(negedge spi_clk or negedge RST_n) 
		if (!RST_n)
		begin
			DOUT_x <= 12'd0;
			DOUT_y <= 12'd0;
		end
	else
		case (spi_clk_counter)
		10'd10: DOUT_x[11] <= DOUT;
		10'd11: DOUT_x[10] <= DOUT;
		10'd12: DOUT_x[9] <= DOUT;
		10'd13: DOUT_x[8] <= DOUT;		
		10'd14: DOUT_x[7] <= DOUT;
		10'd15: DOUT_x[6] <= DOUT;	
		10'd16: DOUT_x[5] <= DOUT;
		10'd17: DOUT_x[4] <= DOUT;
		10'd18: DOUT_x[3] <= DOUT;
		10'd19: DOUT_x[2] <= DOUT;
		10'd20: DOUT_x[1] <= DOUT;
		10'd21: DOUT_x[0] <= DOUT;
 
		10'd34: DOUT_y[11] <= DOUT;
		10'd35: DOUT_y[10] <= DOUT;
		10'd36: DOUT_y[9] <= DOUT;
		10'd37: DOUT_y[8] <= DOUT;		
		10'd38: DOUT_y[7] <= DOUT;
		10'd39: DOUT_y[6] <= DOUT;	
		10'd40: DOUT_y[5] <= DOUT;
		10'd41: DOUT_y[4] <= DOUT;
		10'd42: DOUT_y[3] <= DOUT;
		10'd43: DOUT_y[2] <= DOUT;
		10'd44: DOUT_y[1] <= DOUT;
		10'd45: DOUT_y[0] <= DOUT;
	endcase
//--------------------POS------------------//
	/*输出转换值*/
	reg [11:0]x_pos;
	reg [11:0]y_pos;
	reg 		mark;//	reg [11:0]mark;
 
	always @(posedge TOUCH_CLK or negedge RST_n) 
		if (!RST_n)
			begin
				x_pos <= 12'd0;
				y_pos <= 12'd0;
				mark <= 1'd0;
			end
		else if (spi_clk_counter == 10'd46)	//转换完成,输出转换值,转换完成标志置1
			begin
				x_pos <= DOUT_x;
				y_pos <= DOUT_y;
				mark <= 1'd1;//转换完成标志位,高有效
			end	
		else
			mark <= 1'd0;
  • 这段代码中有个地方大家可以思考一下,这两个always块中的触发沿信号是不同的,他们在时序上是怎样的?对数据的变化有什么影响?
  • TOUCHU_Ctrl模块的功能是将读取到的AD值传送给Display_Ctrl模块,进行判断。代码如下:
//--------------------IMG_RGB-----------------------------------//
	reg	[15:0]	IMG_RGB_r;
	always@(posedge TFT_CLK or negedge RST_n)
		if (!RST_n)
			IMG_RGB_r<=16'd0;
		else  if((X_POS>12'h000)&&(Y_POS<12'hfff))//判断是否有触摸值,如果有触摸,则切换显示色彩。
				IMG_RGB_r<=16'b11111_000000_00000;//有触摸,显示红色
			else
				IMG_RGB_r<=16'b00000_111111_00000;//无触摸,显示绿色
	assign IMG_RGB = IMG_RGB_r;

五、实验结果

  • 程序调试编译完成后下载到我们的开发套件上,可以看到,铅笔碰触屏幕的时候,TFT_LCD液晶屏颜色刷新为红色,当没有碰触的时候,TFT_LCD液晶屏刷新成绿色。

图31-7 7寸液晶屏触摸效果展示1图31-7 7寸液晶屏触摸效果展示2

六、拓展实验

  1. 将屏幕区域均分四块,实现触碰不同区域,切换不同颜色。
tft_lcd触摸屏实验.txt · 最后更改: 2022/03/18 15:49 由 sean