==========================================================

开发环境

编译系统 :fedora9

编译器 :arm-linux-4.4.3

主控芯片 :S3C2440

开发板 :mini2440

==========================================================

一、电阻式触摸屏工作原理
二、 S3C2440 电阻式触摸屏接口、内部ADC结构
三、Linux输入子系统(InputSubsystem)
四、mini2440触摸屏驱动分析

==========================================================

一、电阻式触摸屏工作原理原理

1,电阻式触摸屏实物

触摸屏附着在显示器的表面,与显示器相配合使用,如果能测量出触摸点在屏幕上的坐标位置,则可根据显示屏上对应坐标点的显示内容或图符获知触摸者的意图。触摸屏按其技术原理可分为五类:矢量压力传感式、电阻式、电容式、红外线式、表面声波式,其中电阻式触摸屏在嵌入式系统中用的较多。

为了防止触摸屏和LCD混淆,来张实物图,这就是我们要了解在四线触摸屏,咋一看就是一片一玻璃,下面我们一点一点分析,看它是如何工作的

2,电阻式触摸屏结构

如上图所示,电阻触摸屏是一块4层的透明的复合薄膜屏,触摸屏由两层塑料薄膜组成,各薄膜层上均涂有一层导电金属(通常是氧化铟锡),中间的空气间隙将二者分开。如下图所示,外面两层白色的,上面我软薄膜,下面白色为玻璃基板,中间两层分别为X、Y两个透明电极层。由上图可知,电阻触摸屏在最上面的触摸屏是软的,所以也称为软屏(相对于电容触摸屏为硬屏)

2,电阻式触摸屏如何得到坐标点

下面这个示意图更比较明确:如果有点按下,如下,X+为VDD,X-为GND,Y+为AD转化,Y-为高阻状态。这样可以测出触点X轴的AD值,同样也可以测出这点Y轴的AD值。

如果上面不太明白的话,再来一个比较简易理解的。等效电路如下所示,电阻式触摸屏工作的核心为:当在X方向的电极对上施加一确定的电压,而Y方向电极对上不加电压时,在X平行电压场中,触点处的电压值可以在Y+(或Y-)电极上反映出来,通过测量Y+电极对地的电压大小,便可得知触点的X坐标值。同理,当在Y电极对上加电压,而X电极对上不加电压时,通过测量X+电极的电压,便可得知触点的Y坐标。得到(X,Y)就可以得到一个点的坐标值了。

通过上面我们了解了电阻式触摸屏工作原理,坐标位置是如何取得的。下面我们分析在S3C2440关开电阻式触摸屏的接口。

二、S3C2440 电阻式触摸屏接口、内部ADC结构

1,电阻式触摸屏接口、内部ADC结构

如下图所示:

2,AD转换的一些参数

转换速率:当PCLK=50MHz时,分频设为49,则10位的转换计算如下:

AD转换频率 = 50MHz/(49+1)=1MHz

AD转换时间 = 1/(1MHz/ 5cycles)=1/200KHz=5us

从上面的结构图和数据手册可以知道,该ADC模块总共有8个通道可以进行模拟信号的输入,分别是AIN0、AIN1、AIN2、AIN3、YM、YP、XM、XP。

3,触摸屏接口

XP、XM、YP、YM为四线电阻触摸屏接口,四条信号线分别代码的含义为:

nXPON

Plus X-axis on-off control signal

x轴正极开关控制信号

XMON

Minus X-axis on-off control signal

x轴负极开关控制信号

nYPON

Plus Y-axis on-off control signal

y轴正极开关控制信号

YMON

Minus Y-axis on-off control signal

y轴负极开关控制信号

触摸屏接口的模式有以下几种:

(1)、普通ADC转换模式

(2)、独立X/Y位置转换模式

(3)、自动X/Y位置转换模式

(4)、等待中断模式

我们主要接受触摸屏接口的等待中断模式和自动X/Y位置转换模式,自动转换模式操作流程如下:触摸屏控制器自动转换X,Y的触摸位置,当转换完毕后将数据分别存放在寄存器ADCDAT0和ADCDAT1.并产生INT_ADC中断通知转换完毕。

4,ADC模拟数字转换接口

A[3:0],也就是AIN0、AIN1、AIN2、AIN3为三个模拟转数字通道。当触摸屏接口不使用时,XP、XM、YP、YM四个引脚也可以用做ADC转化。

三、Linux输入子系统(InputSubsystem)

1,linux输入子系统简述

其实驱动这部分大多还是转载别人的,linux输入子系统后面再详细分析。

在Linux中,输入子系统是由输入子系统设备驱动层、输入子系统核心层(InputCore)和输入子系统事件处理层(Event Handler)组成。其中设备驱动层提供对硬件各寄存器的读写访问和将底层硬件对用户输入访问的响应转换为标准的输入事件,再通过核心层提交给事件处理层;而核心层对下提供了设备驱动层的编程接口,对上又提供了事件处理层的编程接口;而事件处理层就为我们用户空间的应用程序提供了统一访问设备的接口和驱动层提交来的事件处理。所以这使得我们输入设备的驱动部分不在用关心对设备文件的操作,而是要关心对各硬件寄存器的操作和提交的输入事件。下面用图形来描述一下这三者的关系吧!

输入子系统与驱动关系

2、输入子系统设备驱动层实现原理

在Linux中,Input设备用input_dev结构体描述,定义在input.h中。设备的驱动只需按照如下步骤就可实现了。

(1)、在驱动模块加载函数中设置Input设备支持input子系统的数据;

(2)、将Input设备注册到input子系统中;

(3)、在Input设备发生输入操作时(如:键盘被按下/抬起、触摸屏被触摸/抬起/移动、鼠标被移动/单击/抬起时等),提交所发生的事件及对应的键值/坐标等状态。

Linux中输入设备的事件类型有(这里只列出了常用的一些,更多请看linux/input.h中):

[cpp]  view plain copy
  1. EV_SYN     0x00     同步事件
  2. EV_KEY     0x01     按键事件
  3. EV_REL     0x02     相对坐标(如:鼠标移动,报告的是相对最后一次位置的偏移)
  4. EV_ABS     0x03     绝对坐标(如:触摸屏和操作杆,报告的是绝对的坐标位置)
  5. EV_MSC     0x04     其它
  6. EV_LED     0x11     LED
  7. EV_SND     0x12     声音
  8. EV_REP     0x14     Repeat
  9. EV_FF      0x15     力反馈

用于提交较常用的事件类型给输入子系统的函数有:

[cpp]  view plain copy
  1. void input_report_key(struct input_dev *dev, unsigned int code, int value); //提交按键事件的函数
  2. void input_report_rel(struct input_dev *dev, unsigned int code, int value); //提交相对坐标事件的函数
  3. void input_report_abs(struct input_dev *dev, unsigned int code, int value); //提交绝对坐标事件的函数
  4. 注意,在提交输入设备的事件后必须用下列方法使事件同步,让它告知input系统,设备驱动已经发出了一个完整的报告:
  5. void input_sync(struct input_dev *dev)

(这部分转自:http://blog.chinaunix.net/uid-22174347-id-1786941.html 文章写得很好)

四、mini2440触摸屏驱动分析

1、硬件原理图分析

S3c2440芯片内部触摸屏接口与ADC接口是集成在一起的,硬件结构原理图请看:S3C2440上ADC驱动实例开发讲解中的图,其中通道7(XP或AIN7)作为触摸屏接口的X坐标输入,通道5(YP或AIN5)作为触摸屏接口的Y坐标输入。在"S3C2440上ADC驱动实例开发讲解"中,AD转换的模拟信号是由开发板上的一个电位器产生并通过通道1(AIN0)输入的,而这里的模拟信号则是由点触触摸屏所产生的X坐标和Y坐标两个模拟信号,并分别通过通道7和通道5输入。S3c2440提供的触摸屏接口有4种处理模式,分别是:正常转换模式、单独的X/Y位置转换模式、自动X/Y位置转换模式和等待中断模式,对于在每种模式下工作的要求,请详细查看数据手册的描述。本驱动实例将采用自动X/Y位置转换模式和等待中断模式。

注意:在每步中,为了让代码逻辑更加有条理和容易理解,就没有考虑代码的顺序,比如函数要先定义后调用。如果要编译此代码,请严格按照C语言的规范来调整代码的顺序。

2、建立触摸屏驱动程序my2440_ts.c,首先实现加载和卸载部分,在驱动加载部分,我们主要做的事情是:启用ADC所需要的时钟、映射IO口、初始化寄存器、申请中断、初始化输入设备、将输入设备注册到输入子系统。代码如下:

[cpp]  view plain copy
  1. #include <linux/module.h>
  2. #include <linux/kernel.h>
  3. #include <linux/clk.h>
  4. #include <linux/init.h>
  5. #include <linux/input.h>
  6. #include <linux/serio.h>
  7. #include <plat/regs-adc.h>
  8. #include <asm/irq.h>
  9. #include <asm/io.h>
  10. /*用于保存从平台时钟列表中获取的ADC时钟*/
  11. static struct clk *adc_clk;
  12. /*定义了一个用来保存经过虚拟映射后的内存地址*/
  13. static void __iomem *adc_base;
  14. /*定义一个输入设备来表示我们的触摸屏设备*/
  15. static struct input_dev *ts_dev;
  16. /*设备名称*/
  17. #define DEVICE_NAME    "my2440_TouchScreen"
  18. /*定义一个WAIT4INT宏,该宏将对ADC触摸屏控制寄存器进行操作
  19. S3C2410_ADCTSC_YM_SEN这些宏都定义在regs-adc.h中*/
  20. #define WAIT4INT(x)    (((x)<<8) | S3C2410_ADCTSC_YM_SEN | S3C2410_ADCTSC_YP_SEN | \
  21. S3C2410_ADCTSC_XP_SEN | S3C2410_ADCTSC_XY_PST(3))
  22. static int __init ts_init(void)
  23. {
  24. int ret;
  25. /*从平台时钟队列中获取ADC的时钟,这里为什么要取得这个时钟,因为ADC的转换频率跟时钟有关。
  26. 系统的一些时钟定义在arch/arm/plat-s3c24xx/s3c2410-clock.c中*/
  27. adc_clk = clk_get(NULL, "adc");
  28. if(!adc_clk)
  29. {
  30. /*错误处理*/
  31. printk(KERN_ERR "falied to find adc clock source\n");
  32. return -ENOENT;
  33. }
  34. /*时钟获取后要使能后才可以使用,clk_enable定义在arch/arm/plat-s3c/clock.c中*/
  35. clk_enable(adc_clk);
  36. /*将ADC的IO端口占用的这段IO空间映射到内存的虚拟地址,ioremap定义在io.h中。
  37. 注意:IO空间要映射后才能使用,以后对虚拟地址的操作就是对IO空间的操作,
  38. S3C2410_PA_ADC是ADC控制器的基地址,定义在mach-s3c2410/include/mach/map.h中,0x20是虚拟地址长度大小*/
  39. adc_base = ioremap(S3C2410_PA_ADC, 0x20);
  40. if(adc_base == NULL)
  41. {
  42. /*错误处理*/
  43. printk(KERN_ERR "failed to remap register block\n");
  44. ret = -EINVAL;
  45. goto err_noclk;
  46. }
  47. /*初始化ADC控制寄存器和ADC触摸屏控制寄存器*/
  48. adc_initialize();
  49. /*申请ADC中断,AD转换完成后触发。这里使用共享中断IRQF_SHARED是因为该中断号在ADC驱动中也使用了,
  50. 最后一个参数1是随便给的一个值,因为如果不给值设为NULL的话,中断就申请不成功*/
  51. ret = request_irq(IRQ_ADC, adc_irq, IRQF_SHARED | IRQF_SAMPLE_RANDOM, DEVICE_NAME, 1);
  52. if(ret)
  53. {
  54. printk(KERN_ERR "IRQ%d error %d\n", IRQ_ADC, ret);
  55. ret = -EINVAL;
  56. goto err_nomap;
  57. }
  58. /*申请触摸屏中断,对触摸屏按下或提笔时触发*/
  59. ret = request_irq(IRQ_TC, tc_irq, IRQF_SAMPLE_RANDOM, DEVICE_NAME, 1);
  60. if(ret)
  61. {
  62. printk(KERN_ERR "IRQ%d error %d\n", IRQ_TC, ret);
  63. ret = -EINVAL;
  64. goto err_noirq;
  65. }
  66. /*给输入设备申请空间,input_allocate_device定义在input.h中*/
  67. ts_dev = input_allocate_device();
  68. /*下面初始化输入设备,即给输入设备结构体input_dev的成员设置值。
  69. evbit字段用于描述支持的事件,这里支持同步事件、按键事件、绝对坐标事件,
  70. BIT宏实际就是对1进行位操作,定义在linux/bitops.h中*/
  71. ts_dev->evbit[0] = BIT(EV_SYN) | BIT(EV_KEY) | BIT(EV_ABS);
  72. /*keybit字段用于描述按键的类型,在input.h中定义了很多,这里用BTN_TOUCH类型来表示触摸屏的点击*/
  73. ts_dev->keybit[BITS_TO_LONGS(BTN_TOUCH)] = BIT(BTN_TOUCH);
  74. /*对于触摸屏来说,使用的是绝对坐标系统。这里设置该坐标系统中X和Y坐标的最小值和最大值(0-1023范围)
  75. ABS_X和ABS_Y就表示X坐标和Y坐标,ABS_PRESSURE就表示触摸屏是按下还是抬起状态*/
  76. input_set_abs_params(ts_dev, ABS_X, 0, 0x3FF, 0, 0);
  77. input_set_abs_params(ts_dev, ABS_Y, 0, 0x3FF, 0, 0);
  78. input_set_abs_params(ts_dev, ABS_PRESSURE, 0, 1, 0, 0);
  79. /*以下是设置触摸屏输入设备的身份信息,直接在这里写死。
  80. 这些信息可以在驱动挂载后在/proc/bus/input/devices中查看到*/
  81. ts_dev->name          = DEVICE_NAME;   /*设备名称*/
  82. ts_dev->id.bustype    = BUS_RS232;     /*总线类型*/
  83. ts_dev->id.vendor     = 0xDEAD;        /*经销商ID号*/
  84. ts_dev->id.product    = 0xBEEF;        /*产品ID号*/
  85. ts_dev->id.version    = 0x0101;        /*版本ID号*/
  86. /*好了,一些都准备就绪,现在就把ts_dev触摸屏设备注册到输入子系统中*/
  87. input_register_device(ts_dev);
  88. return 0;
  89. /*下面是错误跳转处理*/
  90. err_noclk:
  91. clk_disable(adc_clk);
  92. clk_put(adc_clk);
  93. err_nomap:
  94. iounmap(adc_base);
  95. err_noirq:
  96. free_irq(IRQ_ADC, 1);
  97. return ret;
  98. }
  99. /*初始化ADC控制寄存器和ADC触摸屏控制寄存器*/
  100. static void adc_initialize(void)
  101. {
  102. /*计算结果为(二进制):111111111000000,再根据数据手册得知
  103. 此处是将AD转换预定标器值设为255、AD转换预定标器使能有效*/
  104. writel(S3C2410_ADCCON_PRSCEN | S3C2410_ADCCON_PRSCVL(0xFF), adc_base + S3C2410_ADCCON);
  105. /*对ADC开始延时寄存器进行设置,延时值为0xffff*/
  106. writel(0xffff, adc_base + S3C2410_ADCDLY);
  107. /*WAIT4INT宏计算结果为(二进制):11010011,再根据数据手册得知
  108. 此处是将ADC触摸屏控制寄存器设置成等待中断模式*/
  109. writel(WAIT4INT(0), adc_base + S3C2410_ADCTSC);
  110. }
  111. static void __exit ts_exit(void)
  112. {
  113. /*屏蔽和释放中断*/
  114. disable_irq(IRQ_ADC);
  115. disable_irq(IRQ_TC);
  116. free_irq(IRQ_ADC, 1);
  117. free_irq(IRQ_TC, 1);
  118. /*释放虚拟地址映射空间*/
  119. iounmap(adc_base);
  120. /*屏蔽和销毁时钟*/
  121. if(adc_clk)
  122. {
  123. clk_disable(adc_clk);
  124. clk_put(adc_clk);
  125. adc_clk = NULL;
  126. }
  127. /*将触摸屏设备从输入子系统中注销*/
  128. input_unregister_device(ts_dev);
  129. }
  130. module_init(ts_init);
  131. module_exit(ts_exit);
  132. MODULE_LICENSE("GPL");
  133. MODULE_AUTHOR("s3c2440 tp");
  134. MODULE_DESCRIPTION("My2440 Touch Screen Driver");

2、接下来要做的是,在两个中断服务程序中实现触摸屏状态和坐标的转换。先看代码,如下:

[cpp]  view plain copy
  1. /*定义一个外部的信号量ADC_LOCK,因为ADC_LOCK在ADC驱动程序中已申明
  2. 这样就能保证ADC资源在ADC驱动和触摸屏驱动中进行互斥访问*/
  3. extern struct semaphore ADC_LOCK;
  4. /*做为一个标签,只有对触摸屏操作后才对X和Y坐标进行转换*/
  5. static int OwnADC = 0;
  6. /*用于记录转换后的X坐标值和Y坐标值*/
  7. static long xp;
  8. static long yp;
  9. /*用于计数对触摸屏压下或抬起时模拟输入转换的次数*/
  10. static int count;
  11. /*定义一个AUTOPST宏,将ADC触摸屏控制寄存器设置成自动转换模式*/
  12. #define AUTOPST    (S3C2410_ADCTSC_YM_SEN | S3C2410_ADCTSC_YP_SEN | S3C2410_ADCTSC_XP_SEN | \
  13. S3C2410_ADCTSC_AUTO_PST | S3C2410_ADCTSC_XY_PST(0))
  14. /*触摸屏中断服务程序,对触摸屏按下或提笔时触发执行*/
  15. static irqreturn_t tc_irq(int irq, void *dev_id)
  16. {
  17. /*用于记录这一次AD转换后的值*/
  18. unsigned long data0;
  19. unsigned long data1;
  20. /*用于记录触摸屏操作状态是按下还是抬起*/
  21. int updown;
  22. /*ADC资源可以获取,即上锁*/
  23. if (down_trylock(&ADC_LOCK) == 0)
  24. {
  25. /*标识对触摸屏进行了操作*/
  26. OwnADC = 1;
  27. /*读取这一次AD转换后的值,注意这次主要读的是状态*/
  28. data0 = readl(adc_base + S3C2410_ADCDAT0);
  29. data1 = readl(adc_base + S3C2410_ADCDAT1);
  30. /*记录这一次对触摸屏是压下还是抬起,该状态保存在数据寄存器的第15位,所以与上S3C2410_ADCDAT0_UPDOWN*/
  31. updown = (!(data0 & S3C2410_ADCDAT0_UPDOWN)) && (!(data1 & S3C2410_ADCDAT0_UPDOWN));
  32. /*判断触摸屏的操作状态*/
  33. if (updown)
  34. {
  35. /*如果是按下状态,则调用touch_timer_fire函数来启动ADC转换,该函数定义后面再讲*/
  36. touch_timer_fire(0);
  37. }
  38. else
  39. {
  40. /*如果是抬起状态,就结束了这一次的操作,所以就释放ADC资源的占有*/
  41. OwnADC = 0;
  42. up(&ADC_LOCK);
  43. }
  44. }
  45. return IRQ_HANDLED;
  46. }
  47. static void touch_timer_fire(unsigned long data)
  48. {
  49. /*用于记录这一次AD转换后的值*/
  50. unsigned long data0;
  51. unsigned long data1;
  52. /*用于记录触摸屏操作状态是按下还是抬起*/
  53. int updown;
  54. /*读取这一次AD转换后的值,注意这次主要读的是状态*/
  55. data0 = readl(adc_base + S3C2410_ADCDAT0);
  56. data1 = readl(adc_base + S3C2410_ADCDAT1);
  57. /*记录这一次对触摸屏是压下还是抬起,该状态保存在数据寄存器的第15位,所以与上S3C2410_ADCDAT0_UPDOWN*/
  58. updown = (!(data0 & S3C2410_ADCDAT0_UPDOWN)) && (!(data1 & S3C2410_ADCDAT0_UPDOWN));
  59. /*判断触摸屏的操作状态*/
  60. if (updown)
  61. {
  62. /*如果状态是按下,并且ADC已经转换了就报告事件和数据*/
  63. if (count != 0)
  64. {
  65. long tmp;
  66. tmp = xp;
  67. xp = yp;
  68. yp = tmp;
  69. xp >>= 2;
  70. yp >>= 2;
  71. #ifdef CONFIG_TOUCHSCREEN_MY2440_DEBUG
  72. /*触摸屏调试信息,编译内核时选上此项后,点击触摸屏会在终端上打印出坐标信息*/
  73. struct timeval tv;
  74. do_gettimeofday(&tv);
  75. printk(KERN_DEBUG "T: %06d, X: %03ld, Y: %03ld\n", (int)tv.tv_usec, xp, yp);
  76. #endif
  77. /*报告X、Y的绝对坐标值*/
  78. input_report_abs(ts_dev, ABS_X, xp);
  79. input_report_abs(ts_dev, ABS_Y, yp);
  80. /*报告触摸屏的状态,1表明触摸屏被按下*/
  81. input_report_abs(ts_dev, ABS_PRESSURE, 1);
  82. /*报告按键事件,键值为1(代表触摸屏对应的按键被按下)*/
  83. input_report_key(ts_dev, BTN_TOUCH, 1);
  84. /*等待接收方受到数据后回复确认,用于同步*/
  85. input_sync(ts_dev);
  86. }
  87. /*如果状态是按下,并且ADC还没有开始转换就启动ADC进行转换*/
  88. xp = 0;
  89. yp = 0;
  90. count = 0;
  91. /*设置触摸屏的模式为自动转换模式*/
  92. writel(S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST, adc_base + S3C2410_ADCTSC);
  93. /*启动ADC转换*/
  94. writel(readl(adc_base + S3C2410_ADCCON) | S3C2410_ADCCON_ENABLE_START, adc_base + S3C2410_ADCCON);
  95. }
  96. else
  97. {
  98. /*否则是抬起状态*/
  99. count = 0;
  100. /*报告按键事件,键值为0(代表触摸屏对应的按键被释放)*/
  101. input_report_key(ts_dev, BTN_TOUCH, 0);
  102. /*报告触摸屏的状态,0表明触摸屏没被按下*/
  103. input_report_abs(ts_dev, ABS_PRESSURE, 0);
  104. /*等待接收方受到数据后回复确认,用于同步*/
  105. input_sync(ts_dev);
  106. /*将触摸屏重新设置为等待中断状态*/
  107. writel(WAIT4INT(0), adc_base + S3C2410_ADCTSC);
  108. /*如果触摸屏抬起,就意味着这一次的操作结束,所以就释放ADC资源的占有*/
  109. if (OwnADC)
  110. {
  111. OwnADC = 0;
  112. up(&ADC_LOCK);
  113. }
  114. }
  115. }
  116. /*定义并初始化了一个定时器touch_timer,定时器服务程序为touch_timer_fire*/
  117. static struct timer_list touch_timer = TIMER_INITIALIZER(touch_timer_fire, 0, 0);
  118. /*ADC中断服务程序,AD转换完成后触发执行*/
  119. static irqreturn_t adc_irq(int irq, void *dev_id)
  120. {
  121. /*用于记录这一次AD转换后的值*/
  122. unsigned long data0;
  123. unsigned long data1;
  124. if(OwnADC)
  125. {
  126. /*读取这一次AD转换后的值,注意这次主要读的是坐标*/
  127. data0 = readl(adc_base + S3C2410_ADCDAT0);
  128. data1 = readl(adc_base + S3C2410_ADCDAT1);
  129. /*记录这一次通过AD转换后的X坐标值和Y坐标值,根据数据手册可知,X和Y坐标转换数值
  130. 分别保存在数据寄存器0和1的第0-9位,所以这里与上S3C2410_ADCDAT0_XPDATA_MASK就是取0-9位的值*/
  131. xp += data0 & S3C2410_ADCDAT0_XPDATA_MASK;
  132. yp += data1 & S3C2410_ADCDAT1_YPDATA_MASK;
  133. /*计数这一次AD转换的次数*/
  134. count++;
  135. if (count < (1<<2))
  136. {
  137. /*如果转换的次数小于4,则重新启动ADC转换*/
  138. writel(S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST, adc_base + S3C2410_ADCTSC);
  139. writel(readl(adc_base + S3C2410_ADCCON) | S3C2410_ADCCON_ENABLE_START, adc_base + S3C2410_ADCCON);
  140. }
  141. else
  142. {
  143. /*否则,启动1个时间滴答的定时器,这是就会去执行定时器服务程序上报事件和数据*/
  144. mod_timer(&touch_timer, jiffies + 1);
  145. writel(WAIT4INT(1), adc_base + S3C2410_ADCTSC);
  146. }
  147. }
  148. return IRQ_HANDLED;
  149. }

3、我们从整体上描述转换这个的过程:

(1)如果触摸屏感觉到触摸,则触发触摸屏中断即进入tc_irq,获取ADC_LOCK后判断触摸屏状态为按下,则调用touch_timer_fire启动ADC转换;

(2)当ADC转换启动后,触发ADC中断即进入adc_irq,如果这一次转换的次数小于4,则重新启动ADC进行转换,如果4次完毕后,启动1个时间滴答的定时器,停止ADC转换,也就是说在这个时间滴答内,ADC转换是停止的;

(3)这里为什么要在1个时间滴答到来之前停止ADC的转换呢?这是为了防止屏幕抖动。

(4)如果1个时间滴答到来则进入定时器服务程序touch_timer_fire,判断触摸屏仍然处于按下状态则上报事件和转换的数据,并重启ADC转换,重复第(2)步;

(5)如果触摸抬起了,则上报释放事件,并将触摸屏重新设置为等待中断状态。

4、整体流程如下图所示

基于 mini2440 电阻式触摸屏:电阻式触摸屏工作原理相关推荐

  1. 分段式多级离心泵_D型卧式多级泵结构组成及工作原理

    D型卧式多级泵结构组成及工作原理 D型卧式多级泵结构组成: D型卧式多级泵分双层壳体式及分段式两种,目前使用分段式多级离心泵的较多.分段式D型卧式多级泵是一种垂直剖分多级泵,它有一个前段.一个尾段和若 ...

  2. 三极管工作原理_4种集电极-基极负反馈式三极管偏置电路的工作原理分析

    集电极-基极负反馈式偏置电路是三极管偏置电路中用得最多的一种,它只用一只偏置电阻构成偏置电路. 1.典型三极管集电极-基极负反馈式偏置电路 图1-108所示是典型的三极管集电极-基极负反馈式偏置电路. ...

  3. 计算机什么ups又称在线式ups,UPS电源的工作原理及维护

    UPS电源的工作原理及维护 [摘要]本文阐述了UPS电源的种类和运行特点,以及日常应用中的维护和维修方法. [关键词]UPS;逆变器;智能化;蓄电池;维护 UPS电源也称不间断电源,能够提供持续.稳定 ...

  4. 一键式测量仪结构及工作原理

    一键式测量仪是近几年兴起的快速尺寸测量设备,其具有快速检测.尺寸小方便快捷.测量精准等特点.一键式测量仪对小规格产品的二维尺寸测量效率,基本等同于5-10台二次元影像测量仪,对比传统的游标卡尺等传统常 ...

  5. 国产电容式触控IC的工作原理及应用

    国产电容式触控IC采用CMOS工艺,内建稳压和驱动电路,具有高可靠性.高灵敏度.超低功耗.强稳定性.抗干扰能力强.宽工作电压等方面优点,专为取代光感和传统按键开发而设计. 电容式触控芯片 - CT82 ...

  6. 反激式变换器(Flyback Converter)的工作原理

    原文:https://wenku.baidu.com/view/44aa8e4afe4733687e21aabe.html

  7. 物联网传感技术——电阻(应变)式传感器

    电阻(应变)式传感器 [ 章节要点 工作原理 特性分析与误差(温度)补偿 测量电路 主要应用--柱式,悬臂梁式传感器的分析计算 习题 ] || 工作原理 早在1856年,英国物理学家就发现了金属的电阻 ...

  8. 增量式旋转编码器工作原理

    增量式旋转编码器工作原理 增量式旋转编码器通过内部两个光敏接受管转化其角度码盘的时序和相位关系,得到其角度码盘角度位移量增加(正方向)或减少(负方向).在接合数字电路特别是单片机后,增量式旋转编码器在 ...

  9. 增量式(相对式)编码器与绝对式编码器工作原理

    增量式(相对式)编码器与绝对式编码器工作原理 增量式编码器工作原理 绝对式编码器工作原理 根据检测原理,编码器可分为光学式.磁式.感应式和电容式.根据其刻度方法及信号输出形式,可分为增量式.绝对式以及 ...

  10. MG995舵机工作原理及基于STM32的驱动源代码

    MG995舵机工作原理及基于STM32的驱动源代码 一·MG995舵机工作原理 1.MG995舵机简介 产品型号 MG995 产品尺寸 40.7*19.7*42.9mm 产品重量 55g 工作扭矩 1 ...

最新文章

  1. go标准库的学习-crypto/sha1
  2. linux .ssh隐藏,linux安全配置-将ssh服务隐藏于Internet(端口碰撞)
  3. 经典C语言程序100例之八六
  4. 十大最主流的PHP框架
  5. java在面板中点击按钮后弹出对话框
  6. 【读书笔记】《深入浅出nodejs》第五章 内存控制
  7. java 和_java中的和=是什么意思
  8. python必备入门代码-初学必备:1分钟带你认识Python的代码(上)
  9. 关于概要设计文档的写作
  10. EasyUI下拉框自适应高度
  11. Matlab中矩阵的平方和矩阵中每个元素的平方介绍
  12. 用 LSTM 预测股票价格
  13. android 多线程 随机数,多线程安全的随机数生产函数
  14. 应用为王 宝德获最佳国产云计算方案奖
  15. dashboard的安装使用
  16. Mysql学习(4)——MySQL设计规范总结
  17. httpd虚拟主机三种模式配置与https配置
  18. 管理好公司固定资产需要做什么?资产管理一步到位
  19. 如何进行实时频谱分析仪的二次开发——MATLAB、C++、labview开发环境的部署
  20. 条码用什么条码标签打印软件可以达到A级

热门文章

  1. 浙江省计算机二级用户名,2016年浙江省计算机二级上机操作题
  2. Linux与安卓安全对抗
  3. JDK -- 网络编程(TCP/UDP)
  4. 开源iot平台 php,[LiteOne开源开发平台] 连接华为IoTHub指南
  5. Axure RP 9交互原型设计软件增加了哪些新功能
  6. ghost之后无法找到镜像文件
  7. 使用phpStudy加sqli-labs时出现“Unable to connect to the database: security”的解决办法
  8. 犀牛4.0鞋业插件orang1.2
  9. Strings的一些常见的用法
  10. 炉石传说 C# 开发笔记 (初版)