| **银杏科技有限公司旗下技术文档发布平台** |||| |技术支持电话|**0379-69926675-801**||| |技术支持邮件|Gingko@vip.163.com||| ^ 版本 ^ 日期 ^ 作者 ^ 修改内容 ^ | V1.0 | 2019-12-25 | gingko | 初次建立 | ===== 实验三十一:TFT_LCD触摸屏实验 ===== === 一、实验目的与意义 === -了解触摸屏工作原理 -掌握触摸屏驱动方式 -学习触摸屏控制和TFT_LCD屏显示内容的交互 === 二、实验设备及平台 ==== -iCore3 双核心板( FPGA型号为EP4CE10F17)。[[https://item.taobao.com/item.htm?id=524229438677|点击购买]] -转接板和40P的FPC连接线。 -iCore3(7寸TFT_LCD)液晶显示模块。[[https://item.taobao.com/item.htm?spm=a1z10.5-c.w4002-251734908.20.1a34750bPZ3UBu&id=560722486083|点击购买]] -Blaster(或相同功能的)仿真器。[[https://item.taobao.com/item.htm?id=554869837940|点击购买]] -Micro USB线缆和USB线缆。 -QuartusII开发软件(本实验中使用的是13.1版本)。\\ {{ :icore3:图31-1_硬件连接实物图.jpg?direct&700 |图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处理,从而判断触摸点的位置。 {{ :icore3:图31-2_ads7843基础应用电路.png?direct |图31-2 ads7843基础应用电路}} == 2、ads7843触摸屏AD芯片的配置 == *本次实验所用触摸屏模块的AD芯片ads7843,具有同步串行接口,内置12位取样模数转换器,最高转换速率可达125KHz。由ads7843的原理图可以看到,AD芯片和FPGA之间是通过串行接口传送数据和指令的。其串行接口由DIN,DOUT,CS,DCLK 四个信号线构成。其中,DCLK提供串行传输时钟信号,DIN和DOUT则用与FPGA和AD芯片间指令数据的传输。CS作为选通信号,置低位有效。 {{ :icore3:图31-3_触摸屏模块ad转换电路原理图.png?direct |图31-3 触摸屏模块ad转换电路原理图}} == 3、触摸动作识别 == *通过前面对触摸屏原理的学习,如果想识别到触摸动作,那么就要对ADS7843传送到FPGA的数据进行断,是否为触摸屏无触碰状态下的数值。 *图31-4是理想状态下识别的电压和输出编码之间对应关系,理论上触摸屏的输入坐标识别精度可达有效位宽的1/4096,对应的输出编码从3’h000到3’hfff。通过对其输出编码进行处理,判断是否为无触碰状态下的值,从而判断触摸动作有无发生。 {{ :icore3:图31-4_理想状态下ads7843输入电压和输出编码之间的对应关系图.png?direct |图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被赋的值所代表的含义了吧? {{ :icore3:图31-5_ads7843控制存储器1.png?direct |图31-5 ads7843控制寄存器1}}\\ {{ :icore3:图31-5_ads7843控制寄存器2.png?direct |图31-5 ads7843控制寄存器2}} *其次是DCLK,这部分代码是通过对30MHz时钟进行计数,分频产生100KHz时钟信号,即DCLK,用于串行通信。这里我们先看一下ADS7843的串行通信时序图,如下: {{ :icore3:图31-6_ads7843串行通讯时序图.png?direct |图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液晶屏刷新成绿色。 {{:icore3:图31-7_7寸液晶屏触摸效果展示1_副本.jpg?direct&200|图31-7 7寸液晶屏触摸效果展示1}}{{:icore3:图31-7_7寸液晶屏触摸效果展示2_副本.jpg?direct&200|图31-7 7寸液晶屏触摸效果展示2}} === 六、拓展实验 === -将屏幕区域均分四块,实现触碰不同区域,切换不同颜色。