STM32f103的电阻触摸屏的五点校正算法

        由于电阻式触摸屏就是一种传感器,它利用压力感应进行控制,将矩形区域中触摸点(X,Y)的物理位置转换为代表 X座标和 座标的电压。这里先引入两个概念,物理座标和逻辑座标。物理座标指触摸屏上点的实际位置,通常以液晶上点的个数来度量。逻辑座标指这点被触摸时A/D 转换后的座标值。如图1,我们假定液晶最左下角为座标轴原点,在液晶上任取一点(十字线交叉中心),方向距离A 10 个点,在方向距离A20 个点,则这点的物理座标为(1020)。如果我们触摸这一点时得到的A/D 转换值为100A/D 转换值为200,则这点的逻辑座标为(100200)。

       常用的电阻式触摸屏矫正方法有两点校准法和三点校准法。本文这里介绍的是结合了不同的电阻式触摸屏矫正法的优化算法:五点校正法。其中主要的原理是使用4点矫正法的比例运算以及三点矫正法的基准点运算。五点校正法优势在于可以更加精确的计算出XY方向的比例缩放系数,同时提供了中心基准点,对于一些线性电阻系数比较差电阻式触摸屏有很好的校正功能。

       校正相关的变量主要有:

       x[5] , y[5] 五点定位的物理座标

       xl[5] , yl[5] 五点定位的逻辑座标

       KX , KY 横纵方向伸缩系数

       XLC , YLC 中心基点逻辑座标

       XC , YC 中心基点物理座标(数值采用LCD显示屏的物理长宽分辨率的一半)

       触摸屏常和点阵式液晶显示(LCD)屏叠加在一起配套使用,构成一个矩形的实际物理平面而由用户触摸的触摸点集合经过 A/D 转换器,得到具体显示座标的集合,这个集合构成了一个逻辑平面。 由于存在误差,这两个平面并不重合,校准的作用就是要将逻辑平面映射到物理平面上,即得到触点在液晶屏上的位置座标。 校准算法的中心思想也就是要建立这样一个映射函数现有的校准算法大多是基于线性校准即首先假定物理平面和逻辑平面之间的误差是线性误差,由旋转和偏移形成。


《STM32f103的电阻触摸屏的五点校正算法》

        x[5] , y[5] 五点定位的物理座标是已知的,其中4点分别设置在LCD的角落,一点设置在LCD正中心,作为基准矫正点。校正关键点和距离布局如图。校正步骤如下:

        1. 通过先后点击LCD的4个角落的矫正点,获取4个角落的逻辑座标值。

        2. 计算 s1’ = xl[2] – xl[1] 、 s3’ = xl[3] – xl[4] 、 s2’ = yl[3] – yl[2] 、 s4’ = yl[4] – yl[1]

            计算 s1 = x[2] – x[1] 、 s3 = x[3] – x[4] 、 s2 = y[3] – y[2] 、 s4 = y[4] – y[1],一般取点可以人为的设定s1 = s3 和 s2 = s4,以方便运算。

            计算 KX = ( s1’ + s3’ )/2/s1 、KY = ( s2’ + s4’ )/2/s2

        3. 点击LCD正中心,获取中心点的逻辑座标,作为矫正的基准点。

        4. 完成以上步骤则校正完成。下次点击触摸屏的时候获取的逻辑值XL和YL,可根据公式转换成物理值:

            X = ( XL – XLC ) / KX + XC

            Y = ( YL – YLC ) / KY + YC

        换算出来的X , Y即是和LCD像素相对应的物理座标值,方便对触屏响应程序做区域判别。

以下是校正程序:

/****************************************************************************
* 名    称:void LCD_Adjustd(void)
* 功    能:校正电阻屏系数
* 入口参数:	null
* 出口参数:无
* 说    明:null
* 调用方法:LCD_Adjustd();
****************************************************************************/
u8 LCD_Adjustd(void)
{
	EXTI_InitTypeDef EXTI_InitStructure;
	
	EXTI_InitStructure.EXTI_Line    = EXTI_Line7;
	EXTI_InitStructure.EXTI_Mode    = EXTI_Mode_Interrupt;	//为中断请求
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;//Falling下降沿 Rising上升
	EXTI_InitStructure.EXTI_LineCmd = DISABLE;
	EXTI_Init(&EXTI_InitStructure);
	//显示停止刷屏
	TIM_Cmd(TIM3, DISABLE);  //使能TIMx外设
	
	LCD_Clear(White );
	LCD_printString(110,20, "Adjustd Begin" ,Black);
	delay_ms(5000);
	// 定第一个点
	LCD_Draw_Target(20, 20, Red);
	while( GPIO_ReadInputDataBit(GPIOG,GPIO_Pin_7));
	while( (1-GPIO_ReadInputDataBit(GPIOG,GPIO_Pin_7)))
	{
		x[0] = Read_XY(CMD_RDX);
		y[0] = Read_XY(CMD_RDY); 
		LCD_ShowNum(150,80,x[0],Black);
		LCD_ShowNum(150,110,y[0],Black);
		delay_ms(200);
		LCD_Color_Fill(150,80,200,120, White);
	}
	// 定第二个点
	LCD_Draw_Target(300, 20, Red);
	LCD_Draw_Target(20, 20, White);
	while( GPIO_ReadInputDataBit(GPIOG,GPIO_Pin_7));
	while( (1-GPIO_ReadInputDataBit(GPIOG,GPIO_Pin_7)))
	{
		x[1] = Read_XY(CMD_RDX);
		y[1] = Read_XY(CMD_RDY); 
		LCD_ShowNum(150,80,x[1],Black);
		LCD_ShowNum(150,110,y[1],Black);
		delay_ms(200);
		LCD_Color_Fill(150,80,200,120, White);
	}
	if(abs(y[1]-y[0]) >60)
	{
		LCD_Clear(White );
		LCD_printString(110,20, "Adjustd Fail" ,Black);
		delay_ms(5000);
		LCD_Clear(White );
		return 1;
	}
	// 定第三个点
	LCD_Draw_Target(20, 220, Red);
	LCD_Draw_Target(300, 20, White);
	while( GPIO_ReadInputDataBit(GPIOG,GPIO_Pin_7));
	while( (1-GPIO_ReadInputDataBit(GPIOG,GPIO_Pin_7)))
	{
		x[2] = Read_XY(CMD_RDX);
		y[2] = Read_XY(CMD_RDY); 
		LCD_ShowNum(150,80,x[2],Black);
		LCD_ShowNum(150,110,y[2],Black);
		delay_ms(200);
		LCD_Color_Fill(150,80,200,120, White);
	}
	if(abs(x[2]-x[0]) >80)
	{
		LCD_Clear(White );
		LCD_printString(110,20, "Adjustd Fail" ,Black);
		delay_ms(5000);
		LCD_Clear(White );
		return 1;
	}
	// 定第四个点
	LCD_Draw_Target(300, 220, Red);
	LCD_Draw_Target(20, 220, White);
	while( GPIO_ReadInputDataBit(GPIOG,GPIO_Pin_7));
	while( (1-GPIO_ReadInputDataBit(GPIOG,GPIO_Pin_7)))
	{
		x[3] = Read_XY(CMD_RDX);
		y[3] = Read_XY(CMD_RDY); 
		LCD_ShowNum(150,80,x[3],Black);
		LCD_ShowNum(150,110,y[3],Black);
		delay_ms(200);
		LCD_Color_Fill(150,80,200,120, White);
	}
	if((abs(y[2]-y[3]) >60) || (abs(x[1]-x[3]) >80))
	{
		LCD_Clear(White );
		LCD_printString(110,20, "Adjustd Fail" ,Black);
		delay_ms(5000);
		LCD_Clear(White );
		return 1;
	}
	// 定第五个点
	LCD_Draw_Target(160, 120, Red);
	LCD_Draw_Target(300, 220, White);
	while( GPIO_ReadInputDataBit(GPIOG,GPIO_Pin_7));
	while( (1-GPIO_ReadInputDataBit(GPIOG,GPIO_Pin_7)))
	{
		x[4] = Read_XY(CMD_RDX);
		y[4] = Read_XY(CMD_RDY);
		delay_ms(200);
	}
	//计算校正系数
// 	KX  = ((abs(y[0]-y[2])/280+abs(y[1]-y[3])/280)/2);
// 	KY  = ((abs(x[0]-x[1])/200+abs(x[2]-x[3])/200)/2);
	KX  = (((float)(y[0]-y[2])/280+(float)(y[1]-y[3])/280)/2);
	KY  = (((float)(x[0]-x[1])/200+(float)(x[2]-x[3])/200)/2);
	XC = 160;
	YC = 120;
	XLC  = y[4];
	YLC  = x[4];
	
	// 定点完成
	LCD_Clear(White );
	LCD_printString(110,20, "Adjustd Done" ,Black);
	delay_ms(5000);
	LCD_Color_Fill(110,20,200,35, White);
	LCD_printString(110,20, "Testing" ,Black);
	
	EXTI_InitStructure.EXTI_Line    = EXTI_Line7;
	EXTI_InitStructure.EXTI_Mode    = EXTI_Mode_Interrupt;	//为中断请求
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;//Falling下降沿 Rising上升
	EXTI_InitStructure.EXTI_LineCmd = ENABLE;
	EXTI_Init(&EXTI_InitStructure);
	EXTI_ClearITPendingBit(EXTI_Line7);	   //清除线路挂起位
	
	//显示开始刷屏
	TIM_Cmd(TIM3, ENABLE);  //使能TIMx外设
	
	Add_Button();
	
	return 0;
}

点赞