- 简述:
- 触摸屏又称控制面板,它是一种把触摸位置转换成坐标数据的输入设备;
- 按检测原理分类:
- 电阻式触摸屏:
- 优点:价格便宜,抗干扰能力强;
- 缺点:单点触控,压力感应,经常校准,表面易刮花,易磨损;
- 电容式触摸屏:
- 优点:多点触控,不用校准,检测精度高;
- 缺点:只能感应导电物体,表面有水珠时影响检测结果;
- 电阻式触摸屏:
- 电阻式触摸屏检测原理:
- 触摸屏结构:
- 触摸原理:
- 当触摸屏按下时,XY的IOT层相互接触(类似于薄膜键盘,按键按下,触点将上面两面导通,从而检测键盘位置),从触点处把ITO层分为两个电阻,由于均匀导电的关系,两个电阻的大小与触点离两电极的距离成比例关系,利用这个特性; 可通过下述过程来检测坐标;
- 检测原理:
- 等效电路:
- 原理描述:
- X坐标计算:
- X+电极接驱动电压Vref,X-极接地,因此X+与X-之间形成了匀强电场,触点处的电压通过Y+电极采集得到;触点电压/驱动电压 = 触点X坐标/屏宽;
- 公式为:X = Vy+(Y+采集到的触点电压)*Width / Vref(X+所施加电压)
- Y坐标计算:原理同上
- Y+电极接驱动电压Vref,Y-极接地,因此Y+与Y-之间形成了匀强电场,触点处的电压通过X+电极采集得到;触点电压/驱动电压 = 触点X坐标/屏宽;
- 公式为:Y = Vx+(X+采集到的触点电压)*Hight / Vref(Y+所施加电压)
- X坐标计算:
- 常用电阻触摸芯片:电阻触摸为4线制
- XPT2046、ADS7843、ADS7846这三款芯片完全兼容;
- XPT2046芯片介绍:
- 工作电压:2.2v~5.25v
- 支持1.5V~5.25V的数字I/O口
- 内建2.5V参考电压源
- SPI3线控制通信
- (开发板没有接到SPI接口,此处软件模拟)
- 模拟输入:
- 差分输入:本例程所用方式
- 单端输入:
- 自动Power-Down功能
- 芯片框图:
- 电气连接(软件模拟驱动):
- DCLK:外部时钟输入信号; ---------->PH6
- CS:片选信号,低电平有效; ---------->PI8
- DIN:串行数据输入端,CS为低电平时,数据在DCLK上升沿锁存进来; ---------->PI3
- DOUT:串行数据输出端,CS为高电平时,数据在DCLK下升沿锁存进来; ---------->PG3
- PENIRQ:笔接触中断引脚; ---------->PH7
- 时序框图:
- 读/写时序图:
- 输入配置寄存器详解:
- S位始终为1;
- 通道位只看红线标注的地方;
- 其他位默认为0;
- 两个读指令:
- X轴:0xd0;
- Y轴:0x90;
- 初始化例程:
- I/O端口初始化;
- 触摸芯片初始化;
- 上电读取存储器数据,是否有校准触摸屏,若无进行校准,也可以用按键做强制校准;并保存数据
- 计算坐标,并在液晶屏显示
- 管脚初始化:
/********************************************************* * 函数名:void BSP_Touch_IOInit(void) * 描述 : * 输入 :无 * 输出 :无 * 返回 :无 * 调用 :内部调用 **********************************************************/ void BSP_Touch_IOInit(void) { GPIO_InitTypeDef GPIO_InitStruct; __HAL_RCC_GPIOH_CLK_ENABLE(); //开启GPIOH时钟 __HAL_RCC_GPIOI_CLK_ENABLE(); //开启GPIOI时钟 __HAL_RCC_GPIOG_CLK_ENABLE(); //开启GPIOG时钟 //PH6 GPIO_InitStruct.Pin=GPIO_PIN_6; //PH6 GPIO_InitStruct.Mode=GPIO_MODE_OUTPUT_PP; //推挽输出 GPIO_InitStruct.Pull=GPIO_PULLUP; //上拉 GPIO_InitStruct.Speed=GPIO_SPEED_HIGH; //高速 HAL_GPIO_Init(GPIOH,&GPIO_InitStruct); //初始化 //PI3,8 GPIO_InitStruct.Pin=GPIO_PIN_3|GPIO_PIN_8; //PI3,8 HAL_GPIO_Init(GPIOI,&GPIO_InitStruct); //初始化 //PH7 GPIO_InitStruct.Pin=GPIO_PIN_7; //PH7 GPIO_InitStruct.Mode=GPIO_MODE_INPUT; //输入 HAL_GPIO_Init(GPIOH,&GPIO_InitStruct); //初始化 //PG3 GPIO_InitStruct.Pin=GPIO_PIN_3; //PG3 HAL_GPIO_Init(GPIOG,&GPIO_InitStruct); //初始化 }
- 写命令函数
/********************************************************* * 函数名:void BSP_Touch_WriteByte(u8 num) * 描述 :向控制芯片写入一个命令数据 * 输入 :时序:CS为低电平,CLK上升沿锁存数据; * 输出 :无 * 返回 :无 * 调用 :内部调用 **********************************************************/ void BSP_Touch_WriteByte(u8 num) { u8 count=0; for(count=0;count<8;count++) { if(num&0x80) TDIN(1); else TDIN(0); num<<=1; TCLK(0); delay_us(1); TCLK(1); //上升沿有效 } }
- 读命令函数
/********************************************************* * 函数名:u16 BSP_Touch_ReadAD(u8 cmd) * 描述 :读取X/Y轴坐标,并返回AD值; 2^12 = 4096; * 输入 : * 输出 :无 * 返回 : * 调用 :内部调用 **********************************************************/ u16 BSP_Touch_ReadAD(u8 cmd) { u8 count=0; u16 Num=0; TCLK(0); //先拉低时钟 TDIN(0); //拉低数据线 TCS(0); //选中触摸屏IC BSP_Touch_WriteByte(cmd);//发送命令字 delay_us(6);//ADS7846的转换时间最长为6us TCLK(0); delay_us(1); TCLK(1); //给1个时钟,清除BUSY delay_us(1); TCLK(0); for(count=0;count<16;count++)//读出16位数据,只有高12位有效 { Num<<=1; TCLK(0); //下降沿有效 delay_us(1); TCLK(1); if(DOUT)Num++; } Num>>=4; //只有高12位有效. TCS(1); //释放片选 return(Num); }
- 连续采样5次,丢掉最大最小剩余数求平均值
/********************************************************* * 函数名:u16 BSP_Touch_XYAverage(u8 xy) * 描述 :带滤波的坐标读取(X/Y),读取5次数据; * 输入 :f * 输出 :无 * 返回 : * 调用 :内部调用 **********************************************************/ u16 BSP_Touch_XYAverage(u8 xy) { u16 i, j; u16 buf[AVERAGE_TIMES]; u16 sum=0; u16 temp; for(i=0;i<AVERAGE_TIMES;i++) buf[i]=BSP_Touch_ReadAD(xy); for(i=0;i<AVERAGE_TIMES-1; i++)//排序 { for(j=i+1;j<AVERAGE_TIMES;j++) { if(buf[i]>buf[j])//升序排列 { temp=buf[i]; buf[i]=buf[j]; buf[j]=temp; } } } sum=0; for(i=LOST_AVE;i<AVERAGE_TIMES-LOST_AVE;i++) sum+=buf[i]; temp=sum/(AVERAGE_TIMES-2*LOST_AVE); return temp; }
- 误差值:连续采样2次,误差范围在设定范围内,坐标正确
/********************************************************* * 函数名:u8 BSP_Touch_XYErr_Range(u16 *x,u16 *y) * 描述 :连续采样2次; 误差范围在50以内,正确; * 输入 : * 输出 :无 * 返回 : * 调用 :内部调用 **********************************************************/ u8 BSP_Touch_XYErr_Range(u16 *x,u16 *y) { u16 x1,x2,y1,y2; x1 = BSP_Touch_XYAverage(CMD_RDX); y1 = BSP_Touch_XYAverage(CMD_RDY); x2 = BSP_Touch_XYAverage(CMD_RDX); y2 = BSP_Touch_XYAverage(CMD_RDY); if(((x2<=x1&&x1<x2+ERR_RANGE)||(x1<=x2&&x2<x1+ERR_RANGE))//前后两次采样在+-50内 &&((y2<=y1&&y1<y2+ERR_RANGE)||(y1<=y2&&y2<y1+ERR_RANGE))) { *x=(x1+x2)/2; *y=(y1+y2)/2; return 1; } else return 0; }
- 校准算法:4点校准,对边相等,对角相等判断为正确
//对边相等 TP_temp1 = abs(TP_Value[1][0] - TP_Value[0][0]); //x2 - x1; TP_temp2 = abs(TP_Value[1][1] - TP_Value[0][1]); //y2 - y1; TP_temp1 *= TP_temp1; TP_temp2 *= TP_temp2; TP_d1 = sqrt(TP_temp1 + TP_temp2); //得到1,2的距离; TP_temp1 = abs(TP_Value[3][0] - TP_Value[2][0]); //x4 - x3; TP_temp2 = abs(TP_Value[3][1] - TP_Value[2][1]); //y4 - y3; TP_temp1 *= TP_temp1; TP_temp2 *= TP_temp2; TP_d2 = sqrt(TP_temp1 + TP_temp2); //得到3,4的距离; TP_fac = (float)TP_d1/TP_d2; if(TP_fac<0.95||TP_fac>1.05||TP_d1==0||TP_d2==0)//不合格 { count=0; BSP_Touch_DrawPoint(BSP_LCD_InitStructure.width - 20,BSP_LCD_InitStructure.height - 20,WHITE); //清除点4 BSP_Touch_DrawPoint(20,20,RED); //画点1 BSP_LCD_ShowString(40,40,160,100,16,(u8*)TP_Again_Adjust_MSG);//提示开始校准; continue; } //对角线相等 TP_temp1 = abs(TP_Value[3][0] - TP_Value[0][0]); //x4 - x1; TP_temp2 = abs(TP_Value[3][1] - TP_Value[0][1]); //y4 - y1; TP_temp1 *= TP_temp1; TP_temp2 *= TP_temp2; TP_d1 = sqrt(TP_temp1 + TP_temp2); //得到1,4的距离; TP_temp1 = abs(TP_Value[2][0] - TP_Value[1][0]); //x3 - x2; TP_temp2 = abs(TP_Value[2][1] - TP_Value[1][1]); //y3 - y2; TP_temp1 *= TP_temp1; TP_temp2 *= TP_temp2; TP_d2 = sqrt(TP_temp1 + TP_temp2); //得到2,3的距离; TP_fac = (float)TP_d1/TP_d2; if(TP_fac<0.95||TP_fac>1.05)//不合格 { count=0; BSP_Touch_DrawPoint(BSP_LCD_InitStructure.width - 20,BSP_LCD_InitStructure.height - 20,WHITE); //清除点4 BSP_Touch_DrawPoint(20,20,RED); //画点1 BSP_LCD_ShowString(40,40,160,100,16,(u8*)TP_Again_Adjust_MSG);//提示开始校准; continue; } //计算正确 TP_xfac = (float)(BSP_LCD_InitStructure.width - 40)/(TP_Value[1][0] - TP_Value[0][0]); //得到xfac; TP_xoff = (BSP_LCD_InitStructure.width - TP_xfac*(TP_Value[1][0] + TP_Value[0][0]))/2; //得到xoff; TP_yfac = (float)(BSP_LCD_InitStructure.height - 40)/(TP_Value[2][1] - TP_Value[0][1]); //得到Yfac; TP_yoff = (BSP_LCD_InitStructure.height - TP_yfac*(TP_Value[2][1] + TP_Value[0][1]))/2; //得到Yoff;
- 坐标转换:
Touch_X = TP_xfac * Touch_X + TP_xoff; Touch_Y = TP_yfac * Touch_Y + TP_yoff;
-
总结:触摸算法多种多样,可以选择其他算法;
-
参考资料:
- 正点原子:STM32F7 开发指南(HAL 库版)
- 野火:STM32 HAL 库开发实战指南
【13】、STM32F767——————>电阻触摸屏(XPT2046 模拟SPI)
猜你喜欢
转载自blog.csdn.net/Linux_ARM9/article/details/104830868
今日推荐
周排行