触摸屏代码分析——实现滑动功能

触摸屏代码分析——实现滑动功能
前⾯提到过,我们可以通过定时器来实现滑动的功能。我们再来啰嗦⼀遍原理:设置定时器,在定时器处理函数中开启AD转换,可以得到坐标的实时值。先来看代码:
#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 adc_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 adc_regs *adc_regs;
static struct timer_list ts_timer;
static void enter_wait_pen_down_mode(void)
{
adc_regs->adctsc = 0xd3;
}
static void enter_wait_pen_up_mode(void)
{
adc_regs->adctsc = 0x1d3;
}
static void enter_measure_xy_mode(void)
{
adc_regs->adctsc |= (1<<2) | (1<<3);
}
static void start_adc(void)
{
adc_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_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 (adc_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
{
enter_measure_xy_mode();发热器
start_adc();
}
}
static irqreturn_t pen_down_up_irq(int irq, void *dev_id)
{
if (adc_regs->adcdat0 & (1<<15))
{
printk("pen up\n");
enter_wait_pen_down_mode();
}
else
{
enter_measure_xy_mode();//进⼊⾃动转换模式
start_adc();//开启AD转换
}
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;
adcdat0 =adc_regs->adcdat0;
adcdat1 = adc_regs->adcdat1;
if(adc_regs->adcdat0 & (1<<15))
{
input_report_abs(s3c_ts_dev, ABS_PRESSURE, 0);//如果按键松开则上报事件,0代表松开 input_report_key(s3c_ts_dev, BTN_TOUCH, 0);
input_sync(s3c_ts_dev);
enter_wait_pen_down_mode();
else
{
x[cnt] = adcdat0 & 0x3ff;
y[cnt] = adcdat1 & 0x3ff;
cnt++;
if(cnt==4)
{
if(s3c_filter_ts(x, y))
{
input_report_abs(s3c_ts_dev, ABS_X, (x[0]+x[1]+x[2]+x[3])/4);//上报x坐标
input_report_abs(s3c_ts_dev, ABS_Y, (y[0]+y[1]+y[2]+y[3])/4);//上报y坐标
input_report_abs(s3c_ts_dev, ABS_PRESSURE, 1);//上报按下事件,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;
s3c_ts_dev = input_allocate_device();//分配input_dev 结构体
set_bit(EV_KEY,s3c_ts_dev->evbit);//可以产⽣按键类事件
set_bit(EV_ABS,s3c_ts_dev->evbit);//可以产⽣绝对位移事件
set_bit(BTN_TOUCH,s3c_ts_dev->keybit);//可以产⽣按键类事件⾥的触摸屏事件
input_set_abs_params(s3c_ts_dev, ABS_X, 0, 0x3FF, 0, 0);//可以产⽣绝对位移事件⾥的x位置事件
input_set_abs_params(s3c_ts_dev, ABS_Y, 0, 0x3FF, 0, 0);//可以产⽣绝对位移事件⾥的y位置事件
input_set_abs_params(s3c_ts_dev, ABS_PRESSURE, 0, 1, 0, 0);//可以产⽣绝对位移事件⾥的按下/松开位置事件    input_register_device(s3c_ts_dev);//注册
clk=clk_get(NULL, "adc");//获取时钟
clk_enable(clk);//使能时钟
adc_regs=ioremap(0x58000000,sizeof(struct adc_regs));//映射寄存器
adc_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);//注册AD转换完成中断
adc_regs->adcdly = 0xffff;//设置延时
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(adc_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");
在这个函数⾥⾯我们新加了两个功能:⼀是加⼊了定时器功能,使其⽀持滑动。⼆是改打印坐标为上报事件。⾄此触摸屏函数完成了。我们再来总体概括⼀下它的⼯作流程,以⽅便程序的阅读:
按下触摸屏产⽣中断,进⼊按下中断处理函数⾥,在这个按下中断处理函数⾥我们开启了AD转换,⼀旦转换完成,就会发⽣AD转换完成中断,在这个AD转换完成中断处理函数中上报坐标值,并且要修改定时器的值。⼀旦定时器到时的话,就会进⼊定时器处理函数,在这个函数⾥,会重新启动AD转换,从⽽进⼊AD转换中断处理函数⾥,上报坐标值。这样即使不再次按下,也会不断进⾏AD转换,不断上报,从⽽得到实时的按下的坐标值,从⽽⽀持了滑动。
测试:
(1)从新编译内核:make
(2)从新编译模块:make modules,⼀开始没有从新编译模块,直接⽤之前的cfbcopyarea.ko、cfbfillrect.ko、cfbimgblt.ko是会出现段错误的
(3)将c fbcopyarea.ko、 cfbfillrect.ko、 cfbimgblt.ko拷贝到开发板可以挂载的⽬录⾥,新内核启动开发板
(4) 编译:
tar xzf tslib-1.
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⽬录下
(5)安装:
cd tmp
cp * -rf /nfsroot  //在开发板上将tmp⽬录下的所有⽂件都拷贝到开发板的根⽬录下
(6)使⽤:
insmod touchscreen.ko
insmod c fbcopyarea.ko
insmod  cfbfillrect.ko
insmod  cfbimgblt.ko
insmod lcd.ko    //如果出现段错误,可以从新编译内核和模块
(7)
修改 /f第1⾏(去掉#号和第⼀个空格):
# module_raw input
改为:
module_raw input
(8)
export TSLIB_TSDEVICE=/dev/event0
export TSLIB_CALIBFILE=/etc/pointercal
export TSLIB_CONFFILE=/f
export TSLIB_PLUGINDIR=/lib/ts
export TSLIB_CONSOLEDEVICE=none
export TSLIB_FBDEVICE=/dev/fb0
(9)正式的测试:
ts_calibrate
iomvts_test

本文发布于:2024-09-23 16:24:12,感谢您对本站的认可!

本文链接:https://www.17tex.com/tex/2/283160.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:事件   转换   上报   中断   编译   处理函数
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2024 Comsenz Inc.Powered by © 易纺专利技术学习网 豫ICP备2022007602号 豫公网安备41160202000603 站长QQ:729038198 关于我们 投诉建议