STM32 SPI驱动触摸屏(XPT2046)(下)

电阻屏是通过检测触点处的电压来确定位置的,电压受到电阻材料的影响,而生产中不同批次的电阻材料可能会有偏差,因此需要先定位几个点来确定屏幕的偏移量 ( 也就是校准 ) ,以后通过校准得来的偏移量调整坐标输出,才能准确通过电压反映坐标。而电容屏是直接由多个电容组成的矩阵,检测时可获知整个电容矩阵中哪些电容发生了改变,而且各个电容在生产时就确认了它在触摸屏中的坐标,所以只要获知哪些电容发生了变化,就可直接得出触点位置,无须校准。
由于用的是电阻屏,所以这里需要进行校准。
屏幕坐标与ad转换结果也不是相等的,面是存在一定比例关系,也就是说ad转换结果与实际屏幕坐标之间是一条不过坐标原点,且斜率不为1的直线,线性关系可表示为:
**lcd_x=kxadc_x+offset_x
lcd_y=kyadc_y+offset_y *
式中lcd_x和lcd_ y是lcd屏幕上的坐标位置,adc_x和adcy为点击屏上(lcdx.,lcd y)时所采集的ad值,kx和ky是两者之同的比例关系,而 offset_x和 offset_y则为两者相对于坐标原点时的的偏移量。屏幕上点的坐标与其ad值之间的关系可用图表示:
由图可知,只要确定线性关系当中的kx、ky及 offset_x和 offset_y,当获取到触摸点对应的ad值时,即可确定触摸点的位置,比较简单的方法是采集屏幕的左上角(0,0)位置和右下角(239,319)位置的ad值,假定为(ad_x0,ad_y0)和(ad_x1,ad_y1),有了坐标和ad值,即可确定线性关系,kx=(ad_x1- ad_x1)/239;ky=( ade y1-ad_y0)/319,确定了kx和ky即可确定 offset_x和offset_y,从而最终确定线性关系,以后点击屏幕任意点,都可根据线性关系确定屏幕坐标位置。
通常,由于lcd屏幕边界处存在较多的噪点,为了更为准确地校准屏幕,并确定线性关系,往往采用四点校屏法或五点校屏法,但本质都是一样的。四点校屏即在屏幕靠近四个角落的地方给定四个点,以提示用户点击这四点,并假定用户点击后所得的ad值就是这四个点的ad值(当然,实际触摸位置总是会存在一定偏差,若在一定误差范围内,则认为触摸点就是给定点),从而根据给定位置和所得ad值,就可确定线性关系,原理与点击左上角与右下角是一样的。至于五点校屏,无非就是在屏幕中心位置又增加一参考点而已 。
先为校准的参数定义一个结构体:
typedef struct{ float kx; float ky; float dx; float dy; u8 flag; //用来标识,是否校准过}touchparam_typedef;校准思路:在在屏幕上给出参考的点击点,当用户触摸屏幕时,假定所得的触点ad值就是参考点的adc,利用实际所得的ad值和参考坐标,计算出一个线性关系。然后,再把触点ad值代入所得的线性关系中,计算实际触点的坐标,若实际坐标与给定坐标满足的误差条件,则认为该直线即为线性关系。下面给出校准示意图:
这里采用四点校屏法,来确定线性关系中的比例系数和偏移量,即屏幕校准。选择4个参考点,参考点选取越靠边界,范围就越大,这样校准精度就越高,但是越靠近边界,噪声就越大,所以我们去距离边界20的4个点来校准:(20,20)、(220,20)、(20,300)、(220,300)。
void touch_adjust(){ u16 ref_point[4][2] = {{20,20},{220,20},{20,300},{220,300}}; u16 real_point[4][2] = {0}; point_typedef pt = {0xffff,0xffff}; u16 err[4] = {0}; u8 i = 0; s8 error = 0; lcd_clearscreen(0xffff); while(1) { for(i=0;iidr & (1< idr & (1< idr & (1< <1)) == 0){} //清除已触摸的点 lcd_drawline(ref_point[i][0]-7,ref_point[i][1],ref_point[i][0]+7,ref_point[i][1],0xffff); //画垂直线 lcd_drawline(ref_point[i][0],ref_point[i][1]-7,ref_point[i][0],ref_point[i][1]+7,0xffff); //画圆圈 lcd_drawcircle(ref_point[i][0],ref_point[i][1],5,0xffff); } //4个点的adc值已经获取,根据ad值和参考坐标,求线性关系 //利用第1点和第4点,求线性关系 /* ref_point[0][0] = kx * real_point[0][0] + dx; (1) ref_point[3][0] = kx * real_point[3][0] + dx; (2) 由(1)和(2)可得: kx = (float)(ref_point[3][0] - ref_point[0][0])/(real_point[3][0] - real_point[0][0]); dx = (float)(ref_point[3][0]*real_point[0][0] - ref_point[0][0]*real_point[3][0])/(real_point[0][0] - real_point[3][0]); ref_point[0][1] = ky * real_point[0][1] + dy; (3) ref_point[3][1] = ky * real_point[3][1] + dy; (4) 由(3)和(4)可得: ky = (float)(ref_point[3][1] - ref_point[0][1])/(real_point[3][1] - real_point[0][1]); dy = (float)(ref_point[3][1]*real_point[0][1] - ref_point[0][1]*real_point[3][1])/(real_point[0][1] - real_point[3][1]); */ touchparam.kx = (float)(ref_point[3][0] - ref_point[0][0])/(real_point[3][0] - real_point[0][0]); touchparam.dx = (float)(ref_point[3][0]*real_point[0][0] - ref_point[0][0]*real_point[3][0])/(real_point[0][0] - real_point[3][0]); touchparam.ky = (float)(ref_point[3][1] - ref_point[0][1])/(real_point[3][1] - real_point[0][1]); touchparam.dy = (float)(ref_point[3][1]*real_point[0][1] - ref_point[0][1]*real_point[3][1])/(real_point[0][1] - real_point[3][1]); //利用计算的线性关系,求实际触点坐标 for(i=0;i< 4;i++) { real_point[i][0] = touchparam.kx * real_point[i][0] + touchparam.dx; real_point[i][1] = touchparam.ky * real_point[i][1] + touchparam.dy; printf((%d,%d)rn,real_point[i][0],real_point[i][1] ); } //引入误差条件(如果4个实际点都在小圆内,此认为校准通过,) for(i=0;i< 4;i++) { //这里计算距离平方 err[i] = (real_point[i][0] - ref_point[i][0]) * (real_point[i][0] - ref_point[i][0]) + (real_point[i][1] - ref_point[i][1]) * (real_point[i][1] - ref_point[i][1]); printf(err[%d]=%drn,i,err[i]); } //误差判断 if(err[0]< 100 && err[1]< 100 && err[2]< 100 && err[3]< 100) { //认为校准通过(存储到24c02或w25q64中,以24c02为例) touchparam.flag = 0xaa; at24c02_continuewrite(touch_param_add,(u8 *)&touchparam,sizeof(touchparam),&error); break; } } //校准通过 lcd_print(50,160,(u8 *)adjust ok,0,0xffff,1,24); delay_ms(3000); lcd_clearscreen(0xffff);}校准函数编写完成,需要添加到触摸屏初始化函数中,初始化gpio时判断是否已经校准过,没有校准过就进行校准。
void touch_init(){ s8 error = 0; touch_gpio_init(); at24c02_continueread(touch_param_add,(u8 *)&touchparam,sizeof(touchparam),&error); if(touchparam.flag != 0x77) //没有校准 touch_adjust();}接着编写主函数进行测试。
#include stm32f4xx.h#include usart.h#include delay.h#include stdio.h#include touch.h#include at24c02.h#include ili9341.h#include lcd.hint main(){ usart1_init(115200); at24c02_init(); lcd_init(); touch_init(); while(1) {}}运行后,显示一个校准点,点击该点校准后,第一个校准点被擦除,显示第二个校准点,这样依次校准四个校准点,校准结果在误差允许范围内,屏幕显示adjust ok,延时3秒后,屏幕被清为白色,触摸屏校准成功,接下来就可以在校准好的基础上在触摸屏上做其他应用了。
测试结果如下图所示:

雅特力携高性能 MCU亮相ELEXCON 2022,持续发力中高端
蔬菜农药检测仪的使用方法
美国制裁范围扩大!这次是中国服务器巨头浪潮被断供
英伟达超级芯片的真正杀手锏,C2C互联技术
湿敏元件分类:
STM32 SPI驱动触摸屏(XPT2046)(下)
随着互联网的进一步普及 人工智能发展正在加速崛起
竟然存在比原子钟还要精确的东西?
MOSFET管驱动电路基础总结
石墨烯如何与3D打印颠覆锂离子电池行业?
华为mate9评测,科技感爆棚 跑分比骁龙821高三分之一
IP视频监控系统存储设备选型指导
自动驾驶大规模落地离我们还有多远?
一文解读100G光模块发展标准及主要类型
AI去马赛克,你听说过吗?
瑞森碳化硅功率器件,国产替代的助推器
索尼FES Watch U手表在日本开售:电子墨水技术
努比亚Z17发布会最新消息:努比亚Z17配置、价格预测,努比亚Z17发布会直播地址、视频直播、图文直播平台
传感器是决定手机摄像头拍照质量好坏的本质
基于FPGA芯片XC3S2000实现卫星信道模拟器的设计