觸摸屏濾波的一點心得
引子
最近在編寫Nios II的觸摸屏驅動,TFT的驅動器為ILI9325,觸摸AD為ADS9325。無論是輪詢的方式抑或中斷的方式,都會出現令人討厭的散點。經過在SOPC技術聯盟群的討論,達克斯特兄給我一點啟示,讓我成功消除了散點。
第1種嘗試 中位值平均濾波法
首先移植的是liujun6037的代碼,他的代碼思路為:對X、Y的坐標連續采樣十次;不足十次則認為數據無效,不做任何操作;然后對十次數據進行排序;最后取中間三次的數據進行平均,得到最終的X、Y坐標。不同的是,我把冒泡排序換成我常用的選擇排序,其實還是O(n^2)。其效果如圖1所示。可以清楚地看到,本次嘗試很失敗,有很多莫名其妙的散點。
代碼1 第一種嘗試
{
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<cnt-1; i++)
{
min=i;
for (j=i+1; j<cnt; j++)
{
if (tempXY[k][min] > 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 第二種嘗試
{
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_DIV2 2
u8 ads_GetXY(void)
{
u8 i, j, k, min;
u16 temp;
u16 tempXY[2][SAMP_CNT], XY[2];
// 采樣
for(i=0; i<SAMP_CNT; i++)
{
if(ads_ReadXY())
{
tempXY[0][i] = X;
tempXY[1][i] = Y;
}
}
// 濾波
for(k=0; k<2; k++)
{ // 降序排列
for(i=0; i<SAMP_CNT-1; i++)
{
min=i;
for (j=i+1; j<SAMP_CNT; j++)
{
if (tempXY[k][min] > 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 第三種嘗試
參考
1. liujun6037.2.4寸TFTLCD觸摸屏測試通過!(ADS7846/7843)
2. 鷹之翔.畢業設計第六天(觸摸屏在S3C2410上的軟件濾波 )