百为STM32开发板教程之六——触摸画板程序
一、四线电阻触摸屏的结构与工作原理
二、ADS7843触摸屏控制器与触摸坐标读取
三、触摸校准原理与算法
一、四线电阻触摸屏的结构与工作原理
1、四线电阻触摸屏主要由三部分构成:两层透明导体层、隔离层和电极。
2、触摸的检测。当在电极Y-和Y+上加电压时,从未加电压的X+或X-上可以读出触摸点的电压。同样在X-和X+上加电压时,可以从Y+或Y-上读出另一个方向的电压。
3、触摸屏的排线引出有4个信号:XL,YD,XR,YU:
这四个信号是接到ADS7843(ADS7843和TSC2046、XPT2046都是兼容的)上的,看百为stm32开发板光盘\原理图\tft_2.8_lcd_v3.0.pdf就知道了:
这里为什么YU接的是Y-而不是Y+呢,我的理解是这样的,因为LCD的坐标系是这样的:
所以默认把Y-和Y+倒过来了。
二、ADS7843触摸屏控制器与触摸坐标读取
1、ADS7843引脚定义
2、ADS7843典型应用电路
3、ADS7843寄存器操作。ADS7843的控制字结构如下:
其中S为数据传输起始标志位,该位必为"1"。
A2~A0进行信道选择(见表2和3)。
MODE用来选择A/D转换的精度,"1"选择8位,"0"选择12位。
SER/选择参考电压的输入模式(见表2和3)。
PD1、PD0选择省电模式:"00"省电模式允许,在两次A/D转换之间掉电,且中断允许;"01"同"00",只是不允许中断;"10"保留;"11"禁止省电模式。
我们这里用的是电压差动输入模式,12位精度,省电模式。所以要读取X坐标,S = 1,A2 A1 A0 = 0 0 1,SER/DFR = 0,PD1 PD0 = 00
即读X坐标时控制字要为0x90,同样得出读Y坐标时控制字要为0xD0(A2 A1 A0 = 1 0 1)。
4、读取触摸坐标程序设计
ADS7843控制器的PENIRQ引脚,当有触摸按下时,该引脚会输出低电平。所以程序中可以采用中断的方式检测触摸,也可以用查询方式检测触摸,
我们这里采用第二种方式。
PENIRQ引脚在百为STM32开发板上是接到STM32的PB10的,所以检测并读取坐标程序如下:
void getxy(int *x, int *y)
{
int i;
*x=0;
*y=0;
while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_10)==Bit_SET); //检测低电平,即检测是否有触摸按下
for(i=0; i<10; i++)
{
*y += SPI_TOUCH_Read_X();
*x += SPI_TOUCH_Read_Y();
}
while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_10)==Bit_RESET);
*x=*x/10;
*y=*y/10;
}
读X坐标程序:
u16 SPI_TOUCH_Read_X(void)
{
u16 xPos = 0, Temp = 0, Temp0 = 0, Temp1 = 0;
/* Select the TP: Chip Select low */
SPI_TOUCH_CS_LOW();
SPI_Delay(10);
/* Send Read xPos command */
SPI_TOUCH_SendByte(0x90);
SPI_Delay(10);
/* Read a byte from the TP */
Temp0 = SPI_TOUCH_ReadByte();
SPI_Delay(10);
/* Read a byte from the TP */
Temp1 = SPI_TOUCH_ReadByte();
SPI_Delay(10);
/* Deselect the TP: Chip Select high */
SPI_TOUCH_CS_HIGH();
Temp = (Temp0 << 8) | Temp1;
xPos = Temp>>3;
return xPos;
}
读Y坐标程序:
u16 SPI_TOUCH_Read_Y(void)
{
u16 yPos = 0, Temp = 0, Temp0 = 0, Temp1 = 0;
/* Select the TP: Chip Select low */
SPI_TOUCH_CS_LOW();
SPI_Delay(10);
/* Send Read yPos command */
SPI_TOUCH_SendByte(0xD0);
SPI_Delay(10);
/* Read a byte from the TP */
Temp0 = SPI_TOUCH_ReadByte();
SPI_Delay(10);
/* Read a byte from the TP */
Temp1 = SPI_TOUCH_ReadByte();
SPI_Delay(10);
/* Deselect the TP: Chip Select high */
SPI_TOUCH_CS_HIGH();
Temp = (Temp0 << 8) | Temp1;
yPos = Temp>>3;
return yPos;
}
三、触摸校准原理与算法
1、为什么需要触摸校准呢?
因为触摸屏和LCD显示屏坐标之间存在误差,这误差包括比例系数、机械不同轴性等。LCD显示屏与触摸屏之间的机械不同轴性又包括移动与旋转误差。
缩放:
平移:
旋转:
因此,从上面的缩放,平移,旋转,可以得出LCD坐标和触摸屏坐标的计算公式
XL=XT*A+XT*B+C
YL=YT*D+YT*E+F
所以,只要计算出参数A,B,C,D,E,F,
我们就可以将从触摸芯片(ADS7843/TSC2046/XPT2046)上读出的触摸屏坐标转换成LCD坐标
2、我们采用tslib的五点校准算法,
其中触摸采样采用tslib里的排序取中间值,另外加上阈值判断的滤波算法。
typedef struct {
int x[5], xfb[5];
int y[5], yfb[5];
int a[7];
} calibration;
xfb[5],yfb[5]存放预先设定的5个LCD坐标值
x[5],y[5]存放从触摸芯片读回来的触摸坐标值
函数get_sample调用put_cross输出田字形光标,并通过getxy采样触摸坐标值
static void get_sample (calibration *cal, int index, int x, int y, char *name)
{
put_cross(x, y, 2 | XORMODE);
while(!getxy (&cal->x [index], &cal->y [index])); //调用getxy将采样到的触摸坐标值存放在x[],y[]数组里
put_cross(x, y, 2 | XORMODE);
//将预先设定的LCD坐标值存放在xfb[],yfb[]数组里
cal->xfb [index] = x;
cal->yfb [index] = y;
}
getxy就是调用底层函数读取20组触摸坐标值,进行排序取中值平均,并进行阈值检查的函数
#define MAX_SAMPLES 20
struct ts_sample samp[MAX_SAMPLES];
int getxy(int *x, int *y)
{
int i;
int index, middle;
while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_10)==Bit_SET); //检测是否有触摸按下
index = 0;
while((index < MAX_SAMPLES)&&(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_10)==Bit_RESET)) //采样MAX_SAMPLES个点,直到触摸松开
{
index++;
samp[index].x = SPI_TOUCH_Read_X();
samp[index].y = SPI_TOUCH_Read_Y();
}
middle = index/2;
if (x) {
qsort(samp, index, sizeof(struct ts_sample), sort_by_x); //对采样到的数据进行排序
if(samp[middle].x - samp[middle-1].x > 5)
return 0;
if (index & 1) //若为奇数个点,则取中间3个点平均
*x = (samp[middle-1].x + samp[middle].x + samp[middle+1].x)/ 3;
else //否则取中间4个点平均
*x = (samp[middle-1].x + samp[middle].x + samp[middle-2].x + samp[middle+1].x) / 4;
}
if (y) {
qsort(samp, index, sizeof(struct ts_sample), sort_by_y); //对采样到的数据进行排序
if(samp[middle].y - samp[middle-1].y > 5)
return 0;
if (index & 1) //若为奇数个点,则取中间3个点平均
*y = (samp[middle-1].y + samp[middle].y + samp[middle+1].y) / 3;
else //否则取中间4个点平均
*y = (samp[middle-1].y + samp[middle].y + samp[middle-2].y + samp[middle+1].y) / 4;
}
return 1;
}
3、得到5个点的采样数据之后,下面就可以通过perform_calibration计算上面的参数A,B,C,D,E,F了
求解方法采用了克拉姆法则,这个是线性代数的内容了,若看不懂的话要复习下线性代数的行列式和矩阵的内容。
5点校准这部分内容也可以参考下《Tslib中触摸屏校准原理及其实现.pdf》
计算的到上面的参数后,存放在cal.a[]数组中。
然后程序就可以利用上面参数,计算出LCD坐标了,其中a[6]是放大倍数(因为部分参数是小数,所以把全部参数放大倍数,方便存储)
xtemp = cal.x[0];
ytemp = cal.y[0];
x = (int)(( cal.a[0] + cal.a[1]*xtemp + cal.a[2]*ytemp ) / cal.a[6]);
y = (int)(( cal.a[3] + cal.a[4]*xtemp + cal.a[5]*ytemp ) / cal.a[6]);
得到触摸按下时对应LCD的x,y坐标之后,我们就利用它来做触摸画板,GUI触摸输入等应用了
|