好了,一旦释放了锁,那么我们触摸屏事件的一个生命周期才真正算分析结束了,不过在此还有一个问题没有解决,是当我们触摸屏按键被释放后,其实也会产生一个按键中断,执行触摸中断程序,不过在这个程序中起初是为了获得一个信号量,由于信号量是等待锁,所以,程序一直在试图获取这个信号量,当我们的信号量在上面这个touch_timer_fire中被释放后,我们会再次获取这个信号量,继续跟踪这个触摸中断函数stylus_updown


static irqreturn_t stylus_updown(int irq, void *dev_id)
{
       unsigned long data0;
       unsigned long data1;
       int updown;
       if (down_trylock(&ADC_LOCK) == 0) { //再次获取锁
              OwnADC = 1;
              data0 = ioread32(base_addr+S3C2410_ADCDAT0);
              data1 = ioread32(base_addr+S3C2410_ADCDAT1);
              updown = (!(data0 & S3C2410_ADCDAT0_UPDOWN)) && (!(data1 & S3C2410_ADCDAT0_UPDOWN));
              if (updown) {   //因为是释放操作,所以updowm=0
                     touch_timer_fire(0);
              } else {
                     OwnADC = 0;
                     up(&ADC_LOCK);   //释放锁
              }
       }
       return IRQ_HANDLED;
}


  好了,这样我们真正结束了一次触摸时间的周期。

  总结下触摸屏控制的整个运行过程:

  Step1:软件开启INT_ADC和INT_TS中断,设置ADCCON以确定AD转换需要的时钟频率,设置ADCDLY以确定从得到命令到开始转换坐标的延时时长,设置ADCTSC使得触摸屏处于等待触笔按下状态

  Step2:当触笔按下,产生INT_TC中断,执行stylus_updown,stylus_updown首先判断中断产生的原因是不是触笔按下,是的话调用定时函数touch_timer_fire,在touch_timer_fire中设置ADCTSC使得触摸屏准备进行自动X/Y轴转换状态,然后设置ADCCON启动坐标转换,结束stylus_updown。

  Step3:触摸屏在延迟指定时间后开始转换X/Y坐标,并将转换的结果保存到ADCDAT0和ADADAT1中,完成后发出INT_ADC中断,表示转换完成。

  Step4:进入INT_ADC中断处理程序stylus_action,获取X/Y轴坐标,然后进行四次坐标转换以求平均值,后设置ADCTSC使得触摸屏处于等待触笔释放状态,同时当下一个节拍到来时,调用touch_timer_fire向input子系统报告坐标。

  Step5:当触笔释放,还会产生INT_TC中断,进入其中断处理程序,得到触笔释放的消息,后设置ADCTSC使得触摸屏处于下一次等待触笔按下状态。

  三、触摸屏驱动测试

  由于mini2440的触摸屏驱动是基于input子系统的,而input子系统给用户层提供的是input_event结构体,我们主要是在应用层接收这个结构体,然后对其类型进行分类,取出我们需要的数值。


struct input_event { struct timeval time;
       unsigned short type;  //支持的类型,如EV_ABS
       unsigned short code;   //支持的具体事件,如坐标事件的ABS_X
       unsigned int value;  //值
};


  测试触摸屏驱动的应用层代码如下


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <linux/input.h>
#include <sys/fcntl.h>
int main(int argc, char *argv[])
{
       int fd = -1;
       int num;
       size_t rb;
       int version;
       char name[20];
       struct input_event ev;
       int i=0;
       if ((fd = open("/dev/input/event0", O_RDONLY)) < 0)  //打开设备
       {
              perror("open error");
              exit(1);
       }
       while(1)
       {
              rb = read(fd, &ev, sizeof(struct input_event));  //读取设备
              if (rb < (int)sizeof(struct input_event))  //读取错误
              {
                     perror("read error");
                     exit(1);
              }
              if (EV_ABS==ev.type)                     //读取按键内容
              {
              printf("event=%s,value=%d ",ev.code==ABS_X?"ABS_X":ev.code==ABS_Y?"ABS_Y":ev.code==ABS_PRESSURE?"ABS_PRESSURE":"UNKNOWEN",ev.value);     
              }else{
              printf("not ev_abs ");        
              }
       }    
        close(fd);
       return 0;
}


  编译测试程序test.c

  arm-linux-gcc test.c –o test

  超级终端:

  ./test

  测试结果:(触笔按下触摸屏)

  event=ABS_X, value=505
  event=ABS_Y, value=334
  event=ABS_PRESSURE, value=1