mini2440上连接的是一个电阻式触摸屏,电阻式触摸屏是基于AD转换实现的,即某个位置按下之后,这点的电压会发生改变,通过电压就可以判断出是哪一个点被按下了,arm可以得到这个点的坐标。因为触摸屏和lcd是两个设备,因此,触摸屏得到的坐标一般不能够与lcd上的坐标对应起来,所以需要我们在程序中手动的进行校正(虽然不对应,但是他们之间的关系式线性的,因此通过三个点的采样,就可以把系数确定下来。)
s3c2440是不支持中断嵌套的。
arm与触摸屏通过tsxp\tsxm tsyp\tsym 四根线相连接,数据手册中有一句话:When Touch Screen device is used; XM or PM is only connected ground for Touch Screen I/F.s3c2440一共有4种触摸屏接口模式,其中,自动(连续)XY坐标转换模式和等待中断模式是我们用到的。
(1)等待中断模式是在触笔落下时产生一个中断,在这种模式下,A/D触摸屏控制寄存器ADCTSC的值应为0xD3,在系统响应中断后,XY坐标的测量模式必须为无操作模式,即寄存器ADCTSC的低两位必须清零。
(2)自动(连续)XY坐标转换模式是系统依次转换触点的X轴坐标和Y轴坐标,其中X轴坐标值写入寄存器ADCDAT0的低10位中,Y轴坐标写入寄存器ADCDAT1的低10位中,在这种模式下,系统同样会产生中断信号。
在一般情况下,为实现触摸屏功能,先是设置为等待中断模式,在产生int_tc中断后,在中断函数中再设置为自动(连续)XY坐标转换模式,依次读取触点的坐标值。
与触摸屏的功能实现相关的有两个中断:int_adc和int_tc,这两个中断源属于subinterrupt source,都属于int_adc,因此在配置中断的时候就需要按照sub中断源的配置方法进行配置。其中,int_tc是在触摸屏被按下或被释放时产生,一个时刻只能检测其中一种事件,具体是检测触摸屏按下还是释放,需要我们在寄存器ADCTSC的第8位能够设置。int_adc是在ad转换完成之后产生的。
寄存器ADCTSC的第3位可以选择上拉电阻的使能,在等待中断模式下,上拉电阻要有效,在触发中断后,上拉电阻要无效。寄存器ADCTSC的第2位用于选择自动(连续)XY坐标转换模式。触笔抬起/落下中断状态寄存器ADCUPDN的低2位能够判断触笔在何种状态下引起的中断。A/D延时寄存器ADCDLY可以设置开始中断到真正开始A/D转换这段时间的延时长度,它的时钟源频率为3.68MHz。
实现触摸屏功能的流程是这样的:
1. 设置触摸屏为等待中断模式,配置ADCTSC为检测触摸屏被按下 产生中断。
2. 产生中断后,证明触摸屏被按下。在中断函数中修改ADCTSC和ADCCON,配置触摸屏为连续转换功能。同时要屏蔽int_adc中断。因为我们是在中断函数中,所以,通过while循环检测srcpnd 和 subsrcpnd寄存器来检测是否产生了adc转换完成的中断。也就是屏蔽中断,但是通过检测是否产生中断,来判断adc转换是否完成。
3. adc转换结束后,提取想要的数据。然后配置ADCSTC为检测触摸屏被释放产生中断,同时也要继续屏蔽中断。通过检测srcpnd和subsrcpnd来判断是否产生了触摸屏被释放的中断。当检测到触摸屏被释放后,结束中断函数。
当然,采用其他方法来实现我觉也是可以的,比如说检测到触摸屏被按下后,就结束中断函数。也就是把上面的三个步骤,分别在三个中断函数中实现,也是可行的。
此外,涉及到触摸屏的校正,转载赵老师的方法如下:
比较常见的校正方法是三点校正法,它的原理是:
设LCD上每个点PD的坐标为[XD,YD],触摸屏上每个点PT的坐标为[XT,YT]。要实现触摸屏上的坐标转换为LCD上的坐标,需要下列公式进行转换:
XD=A×XT+B×YT+C
YD=D×XT+E×YT+F
因为其中一共有六个参数(A,B,C,D,E,F),因此只需要三个取样点就可以求得这六个参数。这六个参数一旦确定下来,只要给出任意触摸屏上的坐标点PT,代入这个公式,就可以得到它所对应的LCD上像素点的坐标PD。具体的求解过程就不细讲,只给出最终的结果。已知LCD上的三个取样点为:PD0,PD1,PD2,它们所对应的触摸屏上的三个点为:PT0,PT1,PT2。A,B,C,D,E,F这六个参数最终的结果都是一个分式,而且都有一个共同的分母,为:
K=(XT0-XT2)×(YT1-YT2)-(XT1-XT2)×(YT0-YT2)
那么这六个参数分别为:
A=[(XD0-XD2)×(YT1-YT2)-(XD1-XD2)×(YT0-YT2)] / K
B=[(XT0-XT2)×(XD1-XD2)-(XD0-XD2)×(XT1-XT2)] / K
C=[YT0×(XT2×XD1-XT1×XD2)+YT1×(XT0×XD2-XT2×XD0)+YT2×(XT1×XD0-XT0×XD1)] / K
D=[(YD0-YD2)×(YT1-YT2)-(YD1-YD2)×(YT0-YT2)] / K
E=[(XT0-XT2)×(YD1-YD2)-(YD0-YD2)×(XT1-XT2)] / K
F=[YT0×(XT2×YD1-XT1×YD2)+YT1×(XT0×YD2-XT2×YD0)+YT2×(XT1×YD0-XT0×YD1)] / K
具体操作,就是先在lcd上显示三个点,然后等用于点击这三个点之后,采集这三个点的实际坐标和理论坐标,这样就可以计算得到上面的参数。
下面附上我的代码。
static void __irq touchscreen_irq(void)
{
int xdata, ydata;
rADCTSC = (1<<3)|(1<<2); //上拉电阻无效,自动连续XY坐标转换模式开启
rADCDLY = 40000; //延时
rADCCON|=0x1; //开始A/D转换
while(rADCCON & 0x1); //检查A/D转换是否开始
while(!(rADCCON & 0x8000)); //等待A/D转换的结束
while(!(rSRCPND & (BIT_ADC))) ; //判断A/D中断的悬挂位
xdata=(rADCDAT0&0x3ff); //读取X轴坐标
ydata=(rADCDAT1&0x3ff); //读取Y轴坐标
uart_printf("xdata = %x, ydata = %x adcdata0 = %x ", xdata, ydata, rADCDAT0);
rSUBSRCPND|=BIT_SUB_TC;
ClearPending(BIT_ADC);
rADCTSC =0xd3; //再次设置等待中断模式,这一次是判断触笔的抬起
rADCTSC = rADCTSC|(1<<8); //设置触笔抬起中断
while(1) //等待触笔的抬起
{
if(rSUBSRCPND & (0x1<<9)) //检查A/D触摸屏中断悬挂
{
break; //如果触笔抬起,则跳出该循环
}
}
uart_printf("adcdata0 = %x ", rADCDAT0);
rSUBSRCPND = 1<<9;
ClearPending(BIT_ADC);
uart_printf("irq finish\r\n");
rADCTSC=0xd3; // important here
}
void touchscreen_init(void)
{
rADCDLY=50000; //设置延时
rADCCON=(1<<14)+(9<<6); //设置A/D预分频
rADCTSC=0xd3; //设置触摸屏为等待中断模式。
pISR_ADC = (U32)touchscreen_irq;
rINTSUBMSK &= ~(BIT_SUB_TC);
rSUBSRCPND = 1<<9;
ClearPending(BIT_ADC);
EnableIrq(BIT_ADC);
}
void touchscreen_test(void)
{
touchscreen_init();
}