在我们的生活中,触摸屏可以说无处不在。我们可以在各种触摸面板上看到触摸屏,一些产品的价值也因为触摸屏而飙升。接下来,小蛋糕会带你对触摸屏有更深入的了解。
触摸屏可分为电阻触摸屏和电容触摸屏。在这里,我们介绍电阻触摸屏(为什么使用电阻触摸屏更好或更广泛?no no no 事实上,电容式触摸屏现在被广泛使用。电容式触摸屏是我们主流手机使用的屏幕。那我为什么要用电阻触摸屏,因为它便宜(手动无奈表情)。
言归正传,我来介绍一下电阻屏的优缺点,如下表所示:
电阻触摸屏的优点 | 电阻触摸屏的缺点 |
精度高,价格低,抗干扰能力强,稳定性好 | 易划伤,透光性差,不支持多点触摸 |
在我们眼里,触摸屏一直是一种科技感慢的高科技设备,but看完小蛋糕下触摸屏原理的介绍,你会觉得触摸屏,just so so。
首先,我们需要了解触摸屏的组成结构。电阻触摸屏的主要部分是一个与显示器表面非常匹配的电阻膜屏,是一种多层复合膜,以玻璃或硬塑料板为基层,表面涂有透明氧化物膜导电层,外表面硬化处理,塑料层光滑,内表面涂有涂层,两层导电层之间有许多小的透明隔离点。当手指触摸屏幕时,两层导电层在接触点接触,电阻在X和Y在两个方向上产生相应的信号,然后发送到触摸屏控制器。该接触被控制器检测到并计算(X,Y)变量,然后根据获得的位置模拟鼠标运行,以上是电阻触摸屏的基本原理。怎么样,是不是老简单!
在这篇文章中,小蛋糕了解触摸屏的工作过程。
我们以STM32F103系列的MINI开发板、2.以8电阻触摸屏为例,解释我们的相关硬件和程序代码。在这里,我们暂时不考虑触摸屏信号AD转换,关于AD将在以后的文章中解释小蛋糕的转换。
本实验首先需要初始化LCD,根据LCD的ID判断是否是电阻触摸屏,如果没有,我们需要继续遵循电容触摸屏的设计算法程序,是的,我们继续判断后进入相关测试板是一种逻辑强的通用方法,由于数据庞大,本片代码只详细说明电阻屏幕的相关代码。获得ID判断为电阻触摸屏后,需要判断触摸屏是否校准(触摸屏可以记住校准)。如果不需要校准,校准后(或之前校准过)进入电阻屏测试测序(测试界面右上角会有清空操作区域)。RST,单击此处将完全清除,恢复白板状态)
了解实验内容后,我们开始了编写代码的旅程,are you ready?
因为我们需要使用它LCD显示相关信息,这里的小蛋糕带你手拉手LCD初始化及相关应用。
由于LDC有太多的初始化代码,这里只解释关键代码
//结构声明 GPIO_InitTypeDef GPIO_InitStructure; //使能相关IO口的时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC|RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO, ENABLE); //开启SWD,使能JTAG GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable , ENABLE); //使用的IO口(具体IO可以查看开发手册进行初始化 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10|GPIO_Pin_9|GPIO_Pin_8|GPIO_Pin_7|GPIO_Pin_6; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOC, &GPIO_InitStructure); //GPIOC GPIO_SetBits(GPIOC,GPIO_Pin_10|GPIO_Pin_9|GPIO_Pin_8|GPIO_Pin_7|GPIO_Pin_6); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All; // PORTBí?íìê?íìê?3? GPIO_Init(GPIOB, &GPIO_InitStructure); //GPIOB GPIO_SetBits(GPIOB,GPIO_Pin_All);
完成LCD初始化后,我们需要LCD相关信息显示在上面,所以我们需要编写相关函数,即LCD_ShowString()函数。
//x,y代表打印信息的起始地址 //width和heigth代表信息显示区间的长度和高度 //size代表字符的大小 //*p指向我们想要输出信息地址的指针 void LCD_ShowString(u16 x,u16 y,u16 width,u16 height,u8 size,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,0); x =size/2; p ; } }
LCD工作结束后,我们开始了触摸屏的相关操作
首先,我们检查电阻屏控制器结构的定义
typedef struct { u8 (*init)(void); u8 (*scan)(u8); //扫描触摸屏 void (*adjust)(void); u16 x[CT_MAX_TOUCH]; u16 y[CT_MAX_TOUCH]; u8 sta; float xfac; float yfac; short xoff; short yoff; u8 touchtype; }_m_tp_dev;
然后我们需要初始化触摸屏。电阻触摸屏初始化代码如下:
//首先,我们仍然需要使相关的时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO, ENABLE); /*********************************************************************************/ //对触摸屏IO口进行初始化 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3|GPIO_Pin_0|GPIO_Pin_13; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOC, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1|GPIO_Pin_2; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU ; GPIO_Init(GPIOC, &GPIO_InitStructure); /************************************************************************************/ ////读第一次初始化xy的坐标 TP_Read_XY(&tp_dev.x[0],&tp_dev.y[0]); //初始化 AT24CXX_Init(); //判断是否校准 if(TP_Get_Adjdata())return 0; //如果校准不成功,再次校准 else { LCD_Clear(WHITE); P_Adjust();
TP_Save_Adjdata();
}
TP_Get_Adjdata();
扫描触摸屏,获得触摸地址的代码如下:
//tp用来区分屏幕坐标或者是物理坐标
u8 TP_Scan(u8 tp)
{
if(PEN==0)
{
if(tp)TP_Read_XY2(&tp_dev.x[0],&tp_dev.y[0]);//tp为真,读取物理坐标
else if(TP_Read_XY2(&tp_dev.x[0],&tp_dev.y[0]))//tp为假,读取屏幕坐标
{
//对读取的结果进行转化,转化为可使用的屏幕坐标
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;//返回当前触摸屏或者按键的状态
}
触摸屏校准部分的核心代码如下所示:其中xfac yfac xoff yoff用来保存计算坐标偏差时的一些数据。
tp_dev.sta = 0;//消除触发信号
tp_dev.xfac = 0;//xfac用来标记是否校准过,所以校准之前必须清掉!以免错误
while(1)//如果连续10秒钟没有按下,则自动退出
{
READJ:
tp_dev.scan(1);//扫描物理坐标
if((tp_dev.sta&0xc0)==TP_CATH_PRES)//按键按下了一次
{
outtime = 0;
tp_dev.sta &= ~(1<<6); //标记按键已经被处理过了.
pos_temp[cnt][0] = tp_dev.x[0];
pos_temp[cnt][1] = tp_dev.y[0];
cnt++;
switch(cnt)
{
case 1:
TP_Drow_Touch_Point(20,20,WHITE); //清除点1
TP_Drow_Touch_Point(lcddev.width-20,20,RED); //画点2
break;
case 2:
TP_Drow_Touch_Point(lcddev.width-20,20,WHITE); //清除点2
TP_Drow_Touch_Point(20,lcddev.height-20,RED); //画点3
break;
case 3:
TP_Drow_Touch_Point(20,lcddev.height-20,WHITE); //清除点3
TP_Drow_Touch_Point(lcddev.width-20,lcddev.height-20,RED); //画点4
break;
case 4: //全部四个点已经得到
for(cnt = 0;cnt < 3;cnt++)//计算三组点的距离是否在允许范围内?
{
tem1 = abs(pos_temp[TP_ADJDIS_TBL[cnt][0]][0]-pos_temp[TP_ADJDIS_TBL[cnt][1]][0]);//x1-x2/x1-x3/x2-x3
tem2 = abs(pos_temp[TP_ADJDIS_TBL[cnt][0]][1]-pos_temp[TP_ADJDIS_TBL[cnt][1]][1]);//y1-y2/y1-y3/y2-y3
tem1 *= tem1;
tem2 *= tem2;
d1 = sqrt(tem1+tem2);//得到两点之间的距离
tem1 = abs(pos_temp[TP_ADJDIS_TBL[cnt][2]][0]-pos_temp[TP_ADJDIS_TBL[cnt][3]][0]);//x3-x4/x2-x4/x1-x4
tem2 = abs(pos_temp[TP_ADJDIS_TBL[cnt][2]][1]-pos_temp[TP_ADJDIS_TBL[cnt][3]][1]);//y3-y4/y2-y4/y1-y4
tem1 *= tem1;
tem2 *= tem2;
d2 = sqrt(tem1+tem2);//得到两点之间的距离
fac = (float)d1/d2;
if(fac<0.95||fac>1.05||d1==0||d2==0)//不合格
{
cnt = 0;
TP_Drow_Touch_Point(lcddev.width-20,lcddev.height-20,WHITE); //清除点4
TP_Drow_Touch_Point(20,20,RED); //画点1
TP_Adj_Info_Show(pos_temp[0][0],pos_temp[0][1],pos_temp[1][0],pos_temp[1][1],pos_temp[2][0],pos_temp[2][1],pos_temp[3][0],pos_temp[3][1],fac*100);//显示数据
goto READJ; //不合格,重新校准
}
}
//正确了
//计算结果
tp_dev.xfac = (float)(lcddev.width-40)/(pos_temp[1][0]-pos_temp[0][0]);//得到xfac
tp_dev.xoff = (lcddev.width-tp_dev.xfac*(pos_temp[1][0]+pos_temp[0][0]))/2;//得到xoff
tp_dev.yfac = (float)(lcddev.height-40)/(pos_temp[2][1]-pos_temp[0][1]);//得到yfac
tp_dev.yoff = (lcddev.height-tp_dev.yfac*(pos_temp[2][1]+pos_temp[0][1]))/2;//得到yoff
if(abs(tp_dev.xfac)>2||abs(tp_dev.yfac)>2)//触屏和预设的相反了.
{
cnt = 0;
TP_Drow_Touch_Point(lcddev.width-20,lcddev.height-20,WHITE); //清除点4
TP_Drow_Touch_Point(20,20,RED); //画点1
LCD_ShowString(40,26,lcddev.width,lcddev.height,16,"TP Need readjust!");
tp_dev.touchtype = !tp_dev.touchtype;//修改触屏类型.
if(tp_dev.touchtype)//X,Y方向与屏幕相反
{
CMD_RDX = 0X90;
CMD_RDY = 0XD0;
}else //X,Y方向与屏幕相同
{
CMD_RDX = 0XD0;
CMD_RDY = 0X90;
}
continue;
}
POINT_COLOR=BLUE;
LCD_Clear(WHITE);//清屏
LCD_ShowString(35,110,lcddev.width,lcddev.height,16,"Touch Screen Adjust OK!");//校正完成
delay_ms(1000);
TP_Save_Adjdata();
LCD_Clear(WHITE);//清屏
return;//校正完成
}
}
delay_ms(10);
outtime++;
if(outtime>1000)
{
TP_Get_Adjdata();
break;
}
}
}
完成上述操作后,我们就可以完成最神奇的一步——在触摸的点画图。这一步的核心代码如下图所示。
所谓将触摸点显示出来其实就是,触摸屏控制器获得触摸点位置之后,利用画图函数,以触摸点为中心,给该中心极小范围内的像素点上色的过程。怎么样,是不是简单的出乎意料?
void rtp_test(void)
{
u8 key;
u8 i=0;
while(1)
{
key=KEY_Scan(0);
tp_dev.scan(0);
if(tp_dev.sta&TP_PRES_DOWN) //触摸屏被按下
{
if(tp_dev.x[0]<lcddev.width&&tp_dev.y[0]<lcddev.height)
{
if(tp_dev.x[0]>(lcddev.width-24)&&tp_dev.y[0]<16)Load_Drow_Dialog();//触摸点在有效范围外,不显示
else TP_Draw_Big_Point(tp_dev.x[0],tp_dev.y[0],RED);//触摸点在范围内,使用画图的方式将触摸点表示出来
}
}else delay_ms(10);
if(key==KEY0_PRES) //按键被按下,进行强制校准
{
LCD_Clear(WHITE);
TP_Adjust();
TP_Save_Adjdata();
Load_Drow_Dialog();
}
i++;
if(i%20==0)LED0=!LED0;//使用LED灯闪烁表示程序运行
}
}
all right ,关于电阻式触摸屏就到这里,你学废了吗?我们下篇文章见!!!拜拜!!!