触摸屏驱动程序(输入子系统)

发布者:丝语轻风最新更新时间:2016-04-01 来源: eefocus关键字:触摸屏  驱动程序  输入子系统 手机看文章 扫描二维码
随时随地手机看文章
#include "linux/errno.h"
#include "linux/kernel.h"
#include "linux/module.h"
#include "linux/slab.h"
#include "linux/input.h"
#include "linux/init.h"
#include "linux/serio.h"
#include "linux/delay.h"
#include "linux/platform_device.h"
#include "linux/clk.h"
#include "asm/io.h"
#include "asm/irq.h"
 
#include "asm/plat-s3c24xx/ts.h"
 
#include "asm/arch/regs-adc.h"
#include "asm/arch/regs-gpio.h"
 
struct s3c_ts_regs {
        unsigned long adccon;
        unsigned long adctsc;
        unsigned long adcdly;
        unsigned long adcdat0;
        unsigned long adcdat1;
        unsigned long adcupdn;
};
 
static struct input_dev *s3c_ts_dev;
static volatile struct s3c_ts_regs *s3c_ts_regs;
 
static struct timer_list ts_timer;
 
//等到触控笔按下模式
static void enter_wait_pen_down_mode(void)
{
        s3c_ts_regs->adctsc = 0xd3;
}
//等到触控笔松开模式
static void enter_wait_pen_up_mode(void)
{
        s3c_ts_regs->adctsc = 0x1d3;
}
//进入X/Y方向ADC同时转换模式
static void enter_measure_xy_mode(void)
{
        s3c_ts_regs->adctsc = (1<<3)|(1<<2);
}
//启动ADC转换
static void start_adc(void)
{
        s3c_ts_regs->adccon |= (1<<0);
}
 
static int s3c_filter_ts(int x[], int y[])
{
#define ERR_LIMIT 10
 
        int avr_x, avr_y;
        int det_x, det_y;
 
        avr_x = (x[0] + x[1])/2;
        avr_y = (y[0] + y[1])/2;
 
        det_x = (x[2] > avr_x) ? (x[2] - avr_x) : (avr_x - x[2]);
        det_y = (y[2] > avr_y) ? (y[2] - avr_y) : (avr_y - y[2]);
 
        if ((det_x > ERR_LIMIT) || (det_y > ERR_LIMIT))
                return 0;
 
        avr_x = (x[1] + x[2])/2;
        avr_y = (y[1] + y[2])/2;
 
        det_x = (x[3] > avr_x) ? (x[3] - avr_x) : (avr_x - x[3]);
        det_y = (y[3] > avr_y) ? (y[3] - avr_y) : (avr_y - y[3]);
 
        if ((det_x > ERR_LIMIT) || (det_y > ERR_LIMIT))
                return 0;
        return 1;
}
 
static void s3c_ts_timer_function(unsigned long data)
{
        if (s3c_ts_regs->adcdat0 & (1<<15))
        {
                // 已经松开 
                input_report_abs(s3c_ts_dev, ABS_PRESSURE, 0);
                input_report_key(s3c_ts_dev, BTN_TOUCH, 0);
                input_sync(s3c_ts_dev);
                enter_wait_pen_down_mode();
        }
        else
        {
                // 测量X/Y坐标 
                enter_measure_xy_mode();
                start_adc();
        }
}
 
//触控笔按下、抬起中断服务函数
static irqreturn_t pen_down_up_irq(int irq, void *dev_id)
{
        if (s3c_ts_regs->adcdat0 & (1<<15))
        {
                //printk("pen up\n");
                input_report_abs(s3c_ts_dev, ABS_PRESSURE, 0);
                input_report_key(s3c_ts_dev, BTN_TOUCH, 0);
                input_sync(s3c_ts_dev);
                enter_wait_pen_down_mode();
        }
        else
        {
                //printk("pen down\n");
                //enter_wait_pen_up_mode();
                enter_measure_xy_mode();
                start_adc();
        }
        return IRQ_HANDLED;
}
 
static irqreturn_t adc_irq(int irq, void *dev_id)
{
        static int cnt = 0;
        static int x[4], y[4];
        int adcdat0, adcdat1;
        // 优化措施2: 如果ADC完成时, 发现触摸笔已经松开, 则丢弃此次结果 
        adcdat0 = s3c_ts_regs->adcdat0;
        adcdat1 = s3c_ts_regs->adcdat1;
 
        if (s3c_ts_regs->adcdat0 & (1<<15))
        {
                // 已经松开 
                cnt = 0;
                input_report_abs(s3c_ts_dev, ABS_PRESSURE, 0);
                input_report_key(s3c_ts_dev, BTN_TOUCH, 0);
                input_sync(s3c_ts_dev);
                enter_wait_pen_down_mode();
        }
        else
        {
                // printk("adc_irq cnt = %d, x = %d, y = %d\n", ++cnt, adcdat0 & 0x3ff, adcdat1 & 0x3ff);
                // 优化措施3: 多次测量求平均值 
                x[cnt] = adcdat0 & 0x3ff;
                y[cnt] = adcdat1 & 0x3ff;
                ++cnt;
                if (cnt == 4)
                {
                         // 优化措施4: 软件过滤 
                         if (s3c_filter_ts(x, y))
                         {
                               //printk("x = %d, y = %d\n", (x[0]+x[1]+x[2]+x[3])/4, (y[0]+y[1]+y[2]+y[3])/4);
                               input_report_abs(s3c_ts_dev, ABS_X, (x[0]+x[1]+x[2]+x[3])/4);
                               input_report_abs(s3c_ts_dev, ABS_Y, (y[0]+y[1]+y[2]+y[3])/4);
                               input_report_abs(s3c_ts_dev, ABS_PRESSURE, 1);
                               input_report_key(s3c_ts_dev, BTN_TOUCH, 1);
                               input_sync(s3c_ts_dev);
                        }
                        cnt = 0;
                        enter_wait_pen_up_mode();
 
                        // 启动定时器处理长按/滑动的情况 
                        mod_timer(&ts_timer, jiffies + HZ/100);
                }
                else
                {
                                enter_measure_xy_mode();
                                start_adc();
                }
        }
        return IRQ_HANDLED;
}
 
static int s3c_ts_init(void)
{
         struct clk* clk;
         // 1. 分配一个input_dev结构体 
         s3c_ts_dev = input_allocate_device();
 
         // 2. 设置 
         // 2.1 能产生哪类事件 
         set_bit(EV_KEY, s3c_ts_dev->evbit);  //按键类事件
         set_bit(EV_ABS, s3c_ts_dev->evbit); //绝对位移类事件
 
         // 2.2 能产生这类事件里的哪些事件 
         set_bit(BTN_TOUCH, s3c_ts_dev->keybit);
 
         input_set_abs_params(s3c_ts_dev, ABS_X, 0, 0x3FF, 0, 0);
         input_set_abs_params(s3c_ts_dev, ABS_Y, 0, 0x3FF, 0, 0);
         input_set_abs_params(s3c_ts_dev, ABS_PRESSURE, 0, 1, 0, 0);//按压力度:1表示按下、0松开
 
 
         // 3. 注册 
         input_register_device(s3c_ts_dev);
 
         // 4. 硬件相关的操作 
         //4.1 使能时钟(CLKCON[15]) 
         clk = clk_get(NULL, "adc");
         clk_enable(clk);
         // 4.2 设置S3C2440的ADC/TS寄存器 
         s3c_ts_regs = ioremap(0x58000000, sizeof(struct s3c_ts_regs));
 
         //bit[14]  : 1-A/D converter prescaler enable
          * bit[13:6]: A/D converter prescaler value,
          *            49, ADCCLK=PCLK/(49+1)=50MHz/(49+1)=1MHz
          * bit[0]: A/D conversion starts by enable. 先设为0
         //
         s3c_ts_regs->adccon = (1<<14)|(49<<6);
 
         request_irq(IRQ_TC, pen_down_up_irq, IRQF_SAMPLE_RANDOM, "ts_pen", NULL);
         request_irq(IRQ_ADC, adc_irq, IRQF_SAMPLE_RANDOM, "adc", NULL);
 
         // 优化措施1: 
         // 设置ADCDLY为最大值, 这使得电压稳定后再发出IRQ_TC中断
         s3c_ts_regs->adcdly = 0xffff;
 
         //优化措施5: 使用定时器处理长按,滑动的情况
         init_timer(&ts_timer);
         ts_timer.function = s3c_ts_timer_function;
         add_timer(&ts_timer);
 
         enter_wait_pen_down_mode();
         return 0;
}
 
static void s3c_ts_exit(void)
{
         free_irq(IRQ_TC, NULL);
         free_irq(IRQ_ADC, NULL);
         iounmap(s3c_ts_regs);
         input_unregister_device(s3c_ts_dev);
         input_free_device(s3c_ts_dev);
         del_timer(&ts_timer);
}
 
module_init(s3c_ts_init);
module_exit(s3c_ts_exit);
 
 
MODULE_LICENSE("GPL");
 
================================================================
解析:
加载驱动以后运行s3c_ts_init函数,程序进入等待触控笔按下模式enter_wait_pen_down_mode(),当有触控笔按下时进入按下中断服务函数中运行,即pen_down_up_irq中,进入中断服务函数后立即判断触控笔是否依然按下,如果这个时候触控笔已经松开则上报事件;若此时触控笔依然按下则进入X/Y双方向同时进行ADC转换模式,并启动ADC转换。当ADC转换完成以后进入ADC中断服务程序,从adcdat0、adcdat1获取到x方向、y方向的ADC数据,再判断触控笔是否离开,如果已经离开则进行上报数据;否则保存此次ADC转换数据再判断ADC采集到的数据有没有到4次,如果累计到4次则进行软件滤波后上报事件,进入等待触控笔离开模式enter_wait_pen_up_mode,同时启动定时器开始计时处理连续按压事件;如果不够4次则再次进入X/Y双方向同时进行ADC转换模式,并启动ADC转换。当定时时间到了以后进入定时中断服务函数里,判断触控笔是否离开,如果触控笔松开则上报事件,进入等待触控笔按下模式,否则再次进入X/Y双方向同时进行ADC转换模式,并启动ADC转换。依次!
 
测试2th~7th:
1. make menuconfig 去掉原来的触摸屏驱动程序
-> Device Drivers
  -> Input device support
    -> Generic input layer
      -> Touchscreens
      <>   S3C2410/S3C2440 touchscreens
 
make uImage
使用新内核启动
 
2. insmod s3c_ts.ko
按下/松开触摸笔
 
 
测试2th~7th:
1. ls /dev/event* 
2. insmod s3c_ts.ko
3. ls /dev/event* 
4. hexdump /dev/event0
            秒       微秒   type code    value
0000000 29a4 0000 8625 0008 0003 0000 0172 0000
0000010 29a4 0000 8631 0008 0003 0001 027c 0000
0000020 29a4 0000 8634 0008 0003 0018 0001 0000
0000030 29a4 0000 8638 0008 0001 014a 0001 0000
0000040 29a4 0000 863c 0008 0000 0000 0000 0000
0000050 29a4 0000 c85e 0008 0003 0000 0171 0000
0000060 29a4 0000 c874 0008 0003 0001 027d 0000
0000070 29a4 0000 c87b 0008 0000 0000 0000 0000
0000080 29a4 0000 ed37 0008 0003 0018 0000 0000
0000090 29a4 0000 ed48 0008 0001 014a 0000 0000
00000a0 29a4 0000 ed4a 0008 0000 0000 0000 0000
 
lcd和触摸屏联合使用参考”tslib编译使用方法“
 
//暂时忽略下面三行命令
//sudo apt-get install autoconf
//sudo apt-get install automake
//sudo apt-get install libtool
 
编译:
tar xzf tslib-1.4.tar.gz
cd tslib
./autogen.sh 
 
mkdir tmp
echo "ac_cv_func_malloc_0_nonnull=yes" >arm-linux.cache
./configure --host=arm-linux --cache-file=arm-linux.cache --prefix=$(pwd)/tmp
make
make install      //安装到tmp目录
 
安装:
cd tmp
再把tmp目录下的4个文件全都拷贝到开发板的根目录下
cp * /home/book/workspace/JZ2440_TestFile/system/first_fs -rfd
(采用网络文件系统启动时开发板的根目录,但是此时并没有拷贝到开发板的flash上面,如果要拷贝到开发板的flash上面可以不用网络文件系统启动,采用手动挂载的方式把文件系统挂载到开发板的mnt目录下,在从mnt目录下把tmp里的文件拷贝到开发板的根目录下面,这样就算真正的在开发板的flash上面了。) 
 
使用:
 
先安装s3c_ts.ko, lcd.ko
 
1.
修改 /etc/ts.conf第1行(去掉#号和第一个空格):
# module_raw input
改为:
module_raw input
 
2.设置环境变量
export TSLIB_TSDEVICE=/dev/event0
export TSLIB_CALIBFILE=/etc/pointercal
export TSLIB_CONFFILE=/etc/ts.conf
export TSLIB_PLUGINDIR=/lib/ts
export TSLIB_CONSOLEDEVICE=none
export TSLIB_FBDEVICE=/dev/fb0
 
使用以下两个命令进行测试:
      ts_calibrate
      ts_test


关键字:触摸屏  驱动程序  输入子系统 引用地址:触摸屏驱动程序(输入子系统)

上一篇:块设备驱动程序的编写驱动之用内存模拟磁盘
下一篇:LCD驱动(输入子系统)

推荐阅读最新更新时间:2024-03-16 14:48

基于TQ2440和Linux的触摸屏的驱动研究
嵌入式技术在工业和日常生活中变得越来越普及,触摸屏作为交互终端已经逐渐取代键盘成为嵌入式系统的输入设备。使用TQ2440开发板,通过对嵌入式Linux内核中触摸屏驱动的研究,编写和移植了触摸屏的驱动程序,校准之后触摸屏可以正常使用。 随着信息查询技术的发展,触摸屏因具有坚固耐用、反应速度快、节省空间、易于交流等优点,而得到了广泛应用 。触摸屏作为一种新兴的电脑输入设备,是目前最简单、方便的一种人机交互设备。 1 硬件简介 1.1 TQ2440开发板简介 天嵌公司生产的TQ2440开发板,微处理器采用Samsung S3C2440AL,板载64 MB SDRAM、256 MB Nand Flash、2 MB Nor
[嵌入式]
电容式触摸传感器触摸屏的实现原理
随着混合信号技术的发展,可以利用基于噪声门限和手指门限的反跳法,实现按键开关状态之间的干净利落的转换,从而使得电容式触摸传感器成为各种消费电子产品中机械式开关的一种实用、增值型替代方案,另外,还提高了检测电路的灵敏度和可靠性。 触摸传感器的广泛使用已经有很多年了。不过,随着近期混合信号可编程器件的发展,使得电容式触摸传感器成为各种消费电子产品中机械式开关的一种实用、增值型替代方案。 对于典型的电容式传感器,规定其覆盖层的厚度为3mm或更薄。随着覆盖层厚度的增加,来传感手指的触摸将变得越来越困难。换句话说,伴随着覆盖层厚度的增加,系统调整过程将必须从“科学”跨越到“精益求精”。为了说明如何制作一个能够提升目前技术极限的电容式
[嵌入式]
Linux驱动学习笔记之触摸屏驱动
触摸屏归纳为输入子系统,这里主要是针对电阻屏,其使用过程如下 当用触摸笔按下时,产生中断。 在中断处理函数处理函数中启动ADC转换x,y坐标。 ADC结束,产生ADC中断 在ADC中断处理函数里上报(input_event)启动定时器 再次启动定时器(可以处理滑动、长按) 松开按键 其驱动程序的写法和之前写输入子系统的写法基本上一致。 写出入口函数,出口函数并加以修饰,加入相关头文件,然后开始完善各函数,在入口函数中分配input_dev结构体,设置(能产生哪类事件,能产生这类事件中的哪些事件),注册设备,硬件相关的操作等。出口函数中主要对之前注册、分配的一些资源进行释放。 还应根据2440数据手册ADC转换和触摸屏那一章,对
[单片机]
LCD12864(KS0108)驱动程序 显示汉字-字符
仿真原理图如下 #include reg52.h #include intrins.h #include string.h #include hanzi.h //汉字库头文件 #include shuzi.h //字符库头文件 #define uchar unsigned char #define uint unsigned int // lcd12864(ks0108) #define LCD_DATA P2 //LCD8位并行数据口 sbit LCD_RS=P0^5; //寄存器选择 sbit LCD_RW=P0^6; //读/写选择 sbit LCD_EN=P0^7;
[单片机]
LCD12864(KS0108)<font color='red'>驱动程序</font> 显示汉字-字符
NT下视频采集及解压驱动程序的设计与实现
    摘要: 分析了多媒体设备驱动程序的体系结构及视频采集与解压卡的驱动程序设计方案。描述了核心态驱动程序的处理流程,提供了用户态驱动程序的设计思路和具体算法。     关键词: 驱动程序 IRP(输入输出请求包) 驱动程序对象 设备对象 Windows NT的结构决定了应用程序不能直接操作硬件设备,它只能通过一个中间层来读写和控制设备,这个中间层就是驱动程序。驱动程序位于计算机软件的最低层(HAL 为硬件抽象层),直接与硬件设备的特性联系在一起。编写驱动程序不仅要了解设备的特性,而且还要了解操作系统的结构,难度较大。本文比较详细地分析了视频采集与解压卡的驱动程序设计思路。 1 视频
[应用]
TLC1549驱动程序
#include reg52.h #include intrins.h sbit AD_CS = P3^7; sbit AD_DAT = P3^5; sbit AD_CLK = P3^4; void DelayMS(unsigned int Num); /********主程序********/ main() { unsigned char i,j,q,p,k;//定义变量 bdata unsigned int AD_Temp,Temp,TempA; P0=0; while(1) //111111 { TempA=0; Temp=0; AD_CS = 1; AD_CLK = 1; AD_DAT = 1;
[单片机]
触摸屏是数字标牌与顾客之间的纽带
iPhone之类的触摸屏界面,已经教会消费者怎样使用触摸屏来和手机互动。消费者学习了如何与屏幕之类的媒介来互动,也开始期待触摸屏科技到底可以给他们带来怎样的体验感受。触摸屏已经在很多地方使用,像零售银行业服务、零售店自助结账、点购、交通和票务方面自助手续办理等。 触摸屏科技真正的潜能是可以提供一个更加逼真、协同、自然的用户体验。对于销售商来说,触摸屏系统提供的一个完整的工具箱可以作为控制用户体验的一个平台。 近日,美国圣地亚哥举行了“美国平板显示器会议”。英特尔数字标牌主任Jose Avalos说,“我们在谈到交互性方面时会想到英特尔的触摸屏系统。关于使用简易性方面进行了很多讨论,不过我想这个话题已经过时了。今天讨
[嵌入式]
组态王、触摸屏与多台PLC在PN协议下的自组网无线通信
本文以组态王与西门子触摸屏和2台西门子S7-200SMART为例,介绍组态王、触摸屏与多台 PLC在Profinet协议下的自组网无线通信实现过程。在本方案中采用了西门子PLC无线通讯终端——DTD418M,作为实现无线通讯的硬件设备。我们无需更改网络参数和原有程序,也不必了解协议细节,通过欧美系PLC专用无线通讯终端-- DTD418M,即可直接替换组态王与PLC之间有线以太网通讯,且稳定方便的实现PLC无线以太网通讯。 无线网络图 ▼ 测试设备与参数: ● 西门子PLC型号:S7-200Smart × 2台 ● 上位机:组态王6.55 × 1台 ● 西门子触摸屏: SMART 700 IE V3 × 1台 ● 无线通讯
[嵌入式]
组态王、<font color='red'>触摸屏</font>与多台PLC在PN协议下的自组网无线通信
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
热门活动
换一批
更多
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved