安德鲁

[原创].触摸屏滤波的一点心得

0
阅读(32510)

引子

最近在编写Nios II的触摸屏驱动,TFT的驱动器为ILI9325,触摸AD为ADS9325。无论是轮询的方式抑或中断的方式,都会出现令人讨厌的散点。经过在SOPC技术联盟群的讨论,达克斯特兄给我一点启示,让我成功消除了散点。

 

第1种尝试 中位值平均滤波法

首先移植的是liujun6037的代码,他的代码思路为:对X、Y的坐标连续采样十次;不足十次则认为数据无效,不做任何操作;然后对十次数据进 行排序;最后取中间三次的数据进行平均,得到最终的X、Y坐标。不同的是,我把冒泡排序换成我常用的选择排序,其实还是O(n^2)。其效果如图1所示。 可以清楚地看到,本次尝试很失败,有很多莫名其妙的散点。

代码1 第一种尝试

void ads_GetXY(void)
	{
	  u8 cnt=0;
	  u8 i, j, k, min;
	  u16 temp;
	  u16 tempXY[2][9], XY[2];
	  do
	  {
	    if(ads_ReadXY())
	    {
	      tempXY[0][cnt] = X;
	      tempXY[1][cnt] = Y;
	      cnt++;
	    }
	  }while(cnt<9);
	  if(cnt==9)
	  {
	    for(k=0; k<2; k++)
	    { // 降序排列
	      for(i=0; i tempXY[k][j]) min=j;
	        }
	        temp = tempXY[k][i];
	        tempXY[k][i] = tempXY[k][min];
	        tempXY[k][min] = temp;
	      }
	      // 求中间值的均值
	      XY[k] = (tempXY[k][3]+tempXY[k][4]+tempXY[k][5]+tempXY[k][6]) / 4;
	    }
	  }
	  // 矫正坐标
	  X = ((XY[0]-350)/11);
	  Y = ((XY[1]-400)/14);
	}

图1 第一种尝试

 

第2种尝试 差值平均滤波法

由于第一种尝试比较失败,我就在网上搜到了参考2的算法。尝试了一下,效果极差,线条极其发散,图片就不贴了。代码贴到这里作为反面例程。

代码2 第二种尝试

void ads_GetXY(void)
	{
	  u8 cnt=0;
	  u8 i, j, k, min;
	  u16 temp;
	  u16 tempXY[2][9], avgXY[2][3], XY[2];
	  s16 diffXY[2][3];
	  do
	  {
	    if(ads_ReadXY())
	    {
	      tempXY[0][cnt] = X;
	      tempXY[1][cnt] = Y;
	      cnt++;
	    }
	  }while(cnt<9);
	  if(cnt==9)
	  {
	    for(k=0; k<2; k++)
	    { // 取平均值
	      avgXY[k][0] = (tempXY[k][0]+tempXY[k][1]+tempXY[k][2])/3;
	      avgXY[k][1] = (tempXY[k][3]+tempXY[k][4]+tempXY[k][5])/3;
	      avgXY[k][2] = (tempXY[k][6]+tempXY[k][7]+tempXY[k][8])/3;
	      // 取差值
	      diffXY[k][0] = avgXY[k][0] - avgXY[k][1];
	      diffXY[k][1] = avgXY[k][1] - avgXY[k][2];
	      diffXY[k][2] = avgXY[k][2] - avgXY[k][0];
	      // 取差值的绝对值
	      diffXY[k][0] = (diffXY[k][0] > 0) ? diffXY[k][0] : -diffXY[k][0];
	      diffXY[k][1] = (diffXY[k][1] > 0) ? diffXY[k][1] : -diffXY[k][1];
	      diffXY[k][2] = (diffXY[k][2] > 0) ? diffXY[k][2] : -diffXY[k][2];
	      // 取最小的数得平均值
	      if(diffXY[k][0] < diffXY[k][1])
	      {
	        if(diffXY[k][2] < diffXY[k][1])
	          XY[k] = (avgXY[k][0]+avgXY[k][2])>>1;
	        else
	          XY[k] = (avgXY[k][0]+avgXY[k][1])>>1;
	      }
	      else if(diffXY[k][2] < diffXY[k][1])
	        XY[k] = (avgXY[k][0]+avgXY[k][2])>>1;
	      else
	        XY[k] = (avgXY[k][1]+avgXY[k][2])>>1;
	    }
	  }
	  // 矫正坐标
	  X = ((XY[0]-350)/11);
	  Y = ((XY[1]-400)/14);
	}

第3种尝试 中位值平均加阈值滤波法

既然第一种尝试的线条已经比较收敛,那么散点是怎么出来的呢?经过达克斯特兄的一点指导和我的多次实验,终于干掉了这个头疼的散点。原来虽然使用中 位值平均滤波法可以稳定获取符合触摸屏范围的数据,但是却无法滤除跳变的散点。对于跳变的散点必须通过加阈值才能消除。下面贴出我的代码。代码思路:采样 符合触摸屏范围的数据若干次,将其排序,取中间两位的差值;若差值大于阈值,则丢弃。因为数据已经排序,因此差值肯定是正值或零值,即无需申明为有符号 数。同时由于阈值判断的加入,我们可以将数据的采样次数适当调整,此处仅为4次,所得效果已经非常令人满意。需要注意的是采样数据不宜过多,否则连续的线 会变成离散的点。

代码3 第3种尝试

#define SAMP_CNT      4
	#define SAMP_CNT_DIV2 2
	u8 ads_GetXY(void)
	{
	  u8 i, j, k, min;
	  u16 temp;
	  u16 tempXY[2][SAMP_CNT], XY[2];
	  // 采样
	  for(i=0; i<2; k++)
	  { // 降序排列
	    for(i=0; i tempXY[k][j]) min=j;
	      }
	      temp = tempXY[k][i];
	      tempXY[k][i] = tempXY[k][min];
	      tempXY[k][min] = temp;
	    }
	    // 设定阈值
	    if((tempXY[k][SAMP_CNT_DIV2]-tempXY[k][SAMP_CNT_DIV2-1]) > 5)
	      return 0;
	    // 求中间值的均值
	    XY[k] = (tempXY[k][SAMP_CNT_DIV2]+tempXY[k][SAMP_CNT_DIV2-1]) / 2;
	  }
	  // 矫正坐标
          X = ((XY[0]-350)/11);
	  Y = ((XY[1]-400)/14);
	  return 1;
	}

图片3 第三种尝试

视频,触摸屏测试:http://v.youku.com/v_show/id_XMjI2MDIzMTcy.html

 

参考

1. liujun6037.2.4寸TFTLCD触摸屏测试通过!(ADS7846/7843)
2. 鹰之翔.毕业设计第六天(触摸屏在S3C2410上的软件滤波 )