STM32学习笔记一一触摸屏

发布者:创新驿站最新更新时间:2019-08-15 来源: eefocus关键字:STM32  触摸屏 手机看文章 扫描二维码
随时随地手机看文章

1. 简介

1.1 电阻式触摸屏

电阻式触摸屏利用压力感应进行触点检测控制,需要直接应力接触, 通过检测电阻来定位触摸位置 。


1.1.1 电阻式触摸屏的原理

电阻触摸屏的主要部分是一块与显示器表面非常配合的电阻薄膜屏,这是一种多层的复合薄膜,它以一层玻璃或硬塑料平板作为基层,表面涂有一层透明氧化金属(透明的导电电阻)导电层,上面再盖有一层外表面硬化处理、光滑防擦的塑料层、它的内表面也涂有一层涂层、在他们之间有许多细小的(小于 1/1000 英寸)的透明隔离点把两层导电层隔开绝缘。


在这里插入图片描述

当手指触摸屏幕时,两层导电层在触摸点位置就有了接触,电阻发生变化,在 X 和 Y 两个方向上产生信号,然后送触摸屏控制器。控制器侦测到这一接触并计算出( X Y )的位置,再根据获得的位置模拟鼠标的方式运作。


电阻式触摸屏都需要一个AD 转换器, 所以一般来说驱动屏幕需要一个控制器芯片。这种屏幕可以用四线、五线、七线或八线来产生屏幕偏置电压,同时读回触摸点的电压。


1.1.2 电阻式触摸屏得到触点坐标


在这里插入图片描述

如上图所示,但在 X 轴方向的点极施加一定的电压,而 Y 轴方向不加电压时,在 X 轴的平行电场中,触点处的电压值可以在 Y 轴的测量点得到,知道了测量点处 Y 轴的电压(X对地电阻的电压),也就确定了 X 轴上的坐标;同理,当 Y 轴方向施加固定的电压时,可在 X 轴的测量点上得到对应的电压。经过两次的测量,就可以得出触点(X,Y)的坐标了。


1.1.3 电阻式触摸屏的优缺点

优点: 精度高、价格便宜、抗干扰能力强、稳定性好 。


缺点: 容易被划伤、透光性不太好、不支持多点触摸。直接的感觉就是体验不如电容屏幕。


1.2 电容式触摸屏

电容屏利用人体感应进行触点检测控制,不需要直接接触或只需要轻微接触,通过检测感应电流来定位触摸坐标 。


在这里插入图片描述

当手指点击屏幕,会从接触点吸收小量电流,造成角落电极的压降,利用感应人体微弱电流的方式来达到触控的目的。


1.2.1 表面电容式电容触摸屏

表面电容式触摸屏技术是利用 ITO 铟锡氧化物,是 一种透明的导电材料导电膜,通过电场感应方式感测屏幕表面的触摸行为进行。但是表面电容式触摸屏有一些局限性,它只能识别一个手指或者一次触摸。


1.2.2 投射式电容触摸屏

投射电容式触摸屏是传感器利用触摸屏电极发射出静电场线。一般用于投射电容传感技术的电容类型有两种: 自我电容和交互电容 。


自我电容: 又称绝对电容,自我电容通常是指扫描电极与地构成的电容。在玻璃表面有用 ITO 制成的横向与纵向的扫描电极,这些电极和地之间就构成一个电容的两极。当用手或触摸笔触摸的时候就会并联一个电容到电路中去,从而使在该条扫描线上的总体的电容量有所改变。在扫描的时候,控制 IC 依次扫描纵向和横向电极,并根据扫描前后的电容变化来确定触摸点坐标位置。笔记本电脑触摸输入板就是采用的这种方式。笔记本电脑的输入板采用 X*Y 的传感电极阵列形成一个传感格子, 当手指靠近触摸输入板时,在手指和传感电极之间产生一个小量电荷。采用特定的运算法则处理来自行、列传感器的信号来确定手指的位置。

在这里插入图片描述

交互电容: 又叫做跨越电容,它是在玻璃表面的横向和纵向的 ITO 电极的交叉处形成电容。交互电容的扫描方式就是扫描每个交叉处的电容变化,来判定触摸点的位置。当触摸的时候就会影响到相邻电极的耦合,从而改变交叉处的电容量,交互电容的扫面方法可以侦测到每个交叉点的电容值和触摸后电容变化,因而它需要的扫描时间与自我电容的扫描方式相比要长一些,需要扫描检测 X*Y 根电极。 目前智能手机 平板电脑等的触摸屏 ,都是采用 交互电容技术。


1.2.3 投射式电容触摸屏——交互电容详解

投射式电容触摸屏采用纵横两列电极组成感应矩阵,来感应触摸。以两个交叉的电极矩阵,即: X 轴电极和 Y 轴电极,来检测每一 格感应单元的电容变化 。

在这里插入图片描述

如下图,当手指触碰到屏幕的时候,人体自身的感应电流会引起屏幕上排布的电容的变化,进而让处理器知道有触摸动作发生,得到触摸点坐标。

在这里插入图片描述

X 、 Y 轴的透明电极电容屏的精度、分辨率与 X 、 Y 轴的通道数有关,通道数越多,精度越高。


1.2.4 电容式触摸屏的优缺点

优点: 手感好、无需校准、支持多点触摸、透光性好;

缺点: 成本高、精度不高、抗干扰能力差。


2. 电容触摸驱动 IC——OTT2001A介绍

OTT2001A ,最多支持 208 个通道。支持 SPI/IIC 接口。 IIC 接口模式下,该驱动 IC 与 STM32 的连接仅需要 4 根线: SDA 、 SCL 、 RST 和 INT,SDA 和 SCL 是 IIC 通信用的, RST 是复位脚(低电平有效), INT 是中断输出信号。


2.1 寄存器介绍

(1)手势 ID 寄存器


手势 ID 寄存器( 00H )用于告诉 MCU ,哪些点有效,哪些点无效,从而读取对应的数据。

在这里插入图片描述


可知模块只支持最多 5 点触摸。表中只有 5 个位用来表示对应点坐标是否有效,其余位为保留位(读为 0 ),通过读取该寄存器,可知哪些点有数据,哪些点无数据,如果读到的全是 0 ,则说明没有任何触摸。


(2)传感器控制寄存器(ODH)


传感器控制寄存器(ODH ),该寄存器也是 8 位,仅最高位有效,其他位都是保留,当最高位为 1 的时候,打开传感器(开始检测),当最高位设置为 0 的时候,关闭传感器(停止检测)。


(3)坐标数据寄存器(共 20 个)


坐标数据寄存器总共有 20 个,每个坐标占用 4 个寄存器,坐标寄存器与坐标的对应关系下图;


在这里插入图片描述

每个坐标的值,可以通过 4 个寄存器读出,比如读取坐标 A: (X1,Y1),可以读取 01H~04H ,就可以知道当前坐标 1 的具体数值了。也可以只发送寄存器 01 ,然后连续读取 4 个字节,也可以正常读取坐标 A ,寄存器地址会自动增加,从而提高读取速度。


注:


(1)OTT2001A 的寄存器是 8 位的,但是发送的时候要发送 16 位(高八位有效),才可以正常使用。


(2)OTT2001A 的输出坐标,默认是以: X 坐标最大值是 2700 Y 坐标最大值是 1500 的分辨率输出的,也就是输出范围为: X:0-2700,Y:0-1500 。MCU 在读取到坐标后,必须根据 LCD 分辨率做一个换算,才能得到真实的 LCD 坐标。


2.2 初始化流程

在这里插入图片描述

3. 软件分析

这里简要的分析一下电阻屏的驱动。


3.1 通信方式实现

/*软件模拟SPI写数据*/

void TP_Write_Byte(u8 num)    

{  

u8 count = 0;

for(count = 0;count < 8;count++)  

{   

if(num&0x80)

TDIN = 1;  

else 

TDIN = 0;   

num <<= 1;    

TCLK = 0;  

TCLK = 1; //上升沿有效         

}     

}


3.2 触摸屏驱动实现

/*从触摸屏读取 ADC 的数值*/

u16 TP_Read_AD(u8 CMD)   

{  

u8 count = 0;   

u16 Num = 0; 

TCLK = 0; //先拉低时钟  

TDIN = 0; //拉低数据线

TCS = 0; //选中触摸屏IC

TP_Write_Byte(CMD);//发送命令字

delay_us(6);//ADS7846的转换时间最长为6us

TCLK = 0;           

delay_us(1);       

TCLK = 1; //给1个时钟,清除BUSY         

TCLK = 0;           

for(count = 0;count < 16;count++)//读出16位数据,只有高12位有效 

{   

Num <<= 1;  

TCLK = 0; //下降沿有效         

TCLK = 1;

if(DOUT)

Num++;  

Num >>= 4;    //只有高12位有效,移除低四位

TCS = 1; //释放片选  

return(Num);   

}


/*读取x或y的坐标值,并且多次读取,去掉最大、最小值,减少测量误差*/


#define READ_TIMES 5 //读取次数

#define LOST_VAL 1   //丢弃值

u16 TP_Read_XOY(u8 xy)

{

u16 i, j;

u16 buf[READ_TIMES];

u16 sum=0;

u16 temp;


for(i=0;i buf[i] = TP_Read_AD(xy);     

for(i = 0;i < READ_TIMES-1; i++)//排序

{

for(j=i+1;j {

if(buf[i]>buf[j])//升序排列

{

temp = buf[i];

buf[i] = buf[j];

buf[j] = temp;

}

}

}   

sum = 0;

for(i = LOST_VAL;i < READ_TIMES-LOST_VAL;i++) //丢掉最大最小值

sum += buf[i];

temp = sum/(READ_TIMES-2*LOST_VAL);

return temp;   


/*读取x,y的坐标值*/

u8 TP_Read_XY(u16 *x,u16 *y)

{

u16 xtemp,ytemp;


xtemp = TP_Read_XOY(CMD_RDX);

ytemp = TP_Read_XOY(CMD_RDY);      

//if(xtemp<100||ytemp<100)return 0;//读数失败

*x = xtemp;

*y = ytemp;

return 1;//读数成功

}


/*连续两次读取触摸屏数值,并且设定读数误差范围*/


#define ERR_RANGE 50 //误差范围 

u8 TP_Read_XY2(u16 *x,u16 *y) 

{

u16 x1,y1;

  u16 x2,y2;

  u8 flag;  


    flag = TP_Read_XY(&x1,&y1);   

    if(flag==0)

return(0);

    flag = TP_Read_XY(&x2,&y2);    

    if(flag==0)

return(0);   

    if(((x2<=x1&&x1    &&((y2<=y1&&y1    {

        *x = (x1+x2)/2;

        *y = (y1+y2)/2;

        return 1;

    }

else 

return 0;   


3.3 显示处理

/*调用LCD显示函数,显示出触摸点*/

void TP_Drow_Touch_Point(u16 x,u16 y,u16 color)

{

POINT_COLOR = color;

LCD_DrawLine(x-12,y,x+13,y);//横线

LCD_DrawLine(x,y-12,x,y+13);//竖线

LCD_DrawPoint(x+1,y+1);

LCD_DrawPoint(x-1,y+1);

LCD_DrawPoint(x+1,y-1);

LCD_DrawPoint(x-1,y-1);

LCD_Draw_Circle(x,y,6);//画中心圈

}


void TP_Draw_Big_Point(u16 x,u16 y,u16 color)

{     

POINT_COLOR=color;

LCD_DrawPoint(x,y);//中心点 

LCD_DrawPoint(x+1,y);

LCD_DrawPoint(x,y+1);

LCD_DrawPoint(x+1,y+1);  

}


3.4 触摸屏数据处理

/*扫描触摸按键*/

u8 TP_Scan(u8 tp)

{    

if(PEN==0)//有按键按下

{

if(tp)

TP_Read_XY2(&tp_dev.x[0],&tp_dev.y[0]);//读取物理坐标

else if(TP_Read_XY2(&tp_dev.x[0],&tp_dev.y[0]))//读取屏幕坐标

{

tp_dev.x[0] = tp_dev.xfac*tp_dev.x[0]+tp_dev.xoff;//将结果转换为屏幕坐标

tp_dev.y[0] = tp_dev.yfac*tp_dev.y[0]+tp_dev.yoff;  

if((tp_dev.sta&TP_PRES_DOWN)==0)//之前没有被按下

{  

tp_dev.sta = TP_PRES_DOWN|TP_CATH_PRES;//按键按下  

tp_dev.x[4] = tp_dev.x[0];//记录第一次按下时的坐标

tp_dev.y[4] = tp_dev.y[0];       

}    

}

else

{

if(tp_dev.sta&TP_PRES_DOWN)//之前是被按下的

{

tp_dev.sta&=~(1<<7);//标记按键松开

}

else//之前就没有被按下

{

tp_dev.x[4] = 0;

tp_dev.y[4] = 0;

tp_dev.x[0] = 0xffff;

tp_dev.y[0] = 0xffff;

}     

}

return tp_dev.sta&TP_PRES_DOWN;//返回当前的触屏状态

}


#define SAVE_ADDR_BASE 40

//保存校准参数     

void TP_Save_Adjdata(void)

{  

s32 temp;  

//保存校正结果!       

temp = tp_dev.xfac*100000000;//保存x校正因素      

    AT24CXX_WriteLenByte(SAVE_ADDR_BASE,temp,4);   

temp = tp_dev.yfac*100000000;//保存y校正因素    

    AT24CXX_WriteLenByte(SAVE_ADDR_BASE+4,temp,4);

//保存x偏移量

    AT24CXX_WriteLenByte(SAVE_ADDR_BASE+8,tp_dev.xoff,2);     

//保存y偏移量

AT24CXX_WriteLenByte(SAVE_ADDR_BASE+10,tp_dev.yoff,2);

//保存触屏类型

AT24CXX_WriteOneByte(SAVE_ADDR_BASE+12,tp_dev.touchtype);

temp = 0X0A;//标记校准过了

AT24CXX_WriteOneByte(SAVE_ADDR_BASE+13,temp); 

}


/*读出保存的校准参数,检查屏幕状态*/

u8 TP_Get_Adjdata(void)

{   

s32 tempfac;   

u8 temp;


temp = AT24CXX_ReadOneByte(SAVE_ADDR_BASE+13);//读取标记字,看是否校准过!  

if(temp==0X0A)//触摸屏已经校准过了    

{     

tempfac = AT24CXX_ReadLenByte(SAVE_ADDR_BASE,4);    

tp_dev.xfac = (float)tempfac/100000000;//得到x校准参数

tempfac = AT24CXX_ReadLenByte(SAVE_ADDR_BASE+4,4);           

tp_dev.yfa c= (float)tempfac/100000000;//得到y校准参数

    //得到x偏移量

tp_dev.xoff = AT24CXX_ReadLenByte(SAVE_ADDR_BASE+8,2);       

      //得到y偏移量

tp_dev.yoff = AT24CXX_ReadLenByte(SAVE_ADDR_BASE+10,2);   

  tp_dev.touchtype = AT24CXX_ReadOneByte(SAVE_ADDR_BASE+12);//读取触屏类型标记

if(tp_dev.touchtype)//X,Y方向与屏幕相反

{

CMD_RDX = 0X90;

CMD_RDY = 0XD0;  

}

else    //X,Y方向与屏幕相同

{

CMD_RDX = 0XD0;

CMD_RDY = 0X90;  

}  

return 1;  

}

return 0;

}  


/*显示出校准的坐标参数*/

void TP_Adj_Info_Show(u16 x0,u16 y0,u16 x1,u16 y1,u16 x2,u16 y2,u16 x3,u16 y3,u16 fac)

{   

POINT_COLOR = RED;

LCD_ShowString(40,160,lcddev.width,lcddev.height,16,"x1:");

  LCD_ShowString(40+80,160,lcddev.width,lcddev.height,16,"y1:");

  LCD_ShowString(40,180,lcddev.width,lcddev.height,16,"x2:");

  LCD_ShowString(40+80,180,lcddev.width,lcddev.height,16,"y2:");

LCD_ShowString(40,200,lcddev.width,lcddev.height,16,"x3:");

  LCD_ShowString(40+80,200,lcddev.width,lcddev.height,16,"y3:");

LCD_ShowString(40,220,lcddev.width,lcddev.height,16,"x4:");

  LCD_ShowString(40+80,220,lcddev.width,lcddev.height,16,"y4:");  

  LCD_ShowString(40,240,lcddev.width,lcddev.height,16,"fac is:");     

LCD_ShowNum(40+24,160,x0,4,16); //显示数值

LCD_ShowNum(40+24+80,160,y0,4,16); //显示数值

LCD_ShowNum(40+24,180,x1,4,16); //显示数值

LCD_ShowNum(40+24+80,180,y1,4,16); //显示数值

LCD_ShowNum(40+24,200,x2,4,16); //显示数值

LCD_ShowNum(40+24+80,200,y2,4,16); //显示数值

LCD_ShowNum(40+24,220,x3,4,16); //显示数值

LCD_ShowNum(40+24+80,220,y3,4,16); //显示数值

  LCD_ShowNum(40+56,lcddev.width,fac,3,16); //显示数值,该数值必须在95~105范围之内.


}


const u8 TP_ADJDIS_TBL[3][4]={{0,1,2,3},{0,2,1,3},{1,2,0,3}};//校准距离计算表

//触摸屏校准代码

//得到四个校准参数

void TP_Adjust(void)

{  

u16 pos_temp[4][2];//坐标缓存值

u8  cnt = 0;

u16 d1,d2;

u32 tem1,tem2;

float fac;

u16 outtime=0; 


LCD_Clear(WHITE); //清屏     

POINT_COLOR = BLUE; //蓝色

[1] [2]
关键字:STM32  触摸屏 引用地址:STM32学习笔记一一触摸屏

上一篇:STM32读取温湿度传感器DHT11和DHT21(AM2301)系列问题
下一篇:STM32学习笔记一一RTC实时时钟

小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved