嵌入式Linux驱动学习之路(十五)按键驱动-定时器防抖
在之前的定时器驱动程序中,我们发现在连续按下按键的时候,正常情况下应该是一次按下对应一次松开。而程序有时候会显示是两次按下,一次松开。这个问题是因为在按下的时候,因为是机械按键,所以电压信号会产生一定的波动,会让程序进行两次中断,如何解决这个问题呢?
我们可以在发生一次中断之后等待一段时间再去判断按键是否已经被按下,如果是已经被按下了 则本次有效,否则无效。这里用到了定时器。
定时器常用的操作函数有:
init_timer(&timer); //定时器初始化
timer.data=; //设置超时处理函数参数
timer.expires=jiffies+(*HZ); //设置超时jiffies值为10s
timer.function=timer_func; //设置超时处理函数
add_timer(&timer); //添加定时器到内核
del_timer(&timer); //删除定时器 在每次调用之前应该把上次调用的删除
驱动代码:
#include <linux/sched.h>
#include <linux/signal.h>
#include <linux/spinlock.h>
#include <linux/errno.h>
#include <linux/random.h>
#include <linux/poll.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/wait.h>
#include <linux/mutex.h>
#include <linux/io.h>
#include <asm/irq.h>
#include <linux/irq.h>
#include <linux/fs.h>
#include <asm/arch/regs-gpio.h>
#include <linux/interrupt.h>
#include <linux/poll.h> static struct class *key_class; //创建类
static struct class_device *key_class_devs; //创建类对应的设备
static struct timer_list keys_timer; struct pin_desc{
unsigned int pin;
unsigned int key_val;
};
struct pin_desc pins_desc[] = {
{S3C2410_GPF0,0X01},
{S3C2410_GPF2,0X02},
{S3C2410_GPG3,0X03},
{S3C2410_GPG11,0X04},
}; struct pin_desc *pin_timer; //在按键中断里保存按下按键的信息
unsigned char keyvals=; static volatile int ev_press = ;
static DECLARE_WAIT_QUEUE_HEAD(button_waitq); static struct fasync_struct *key_async_queue; static DECLARE_MUTEX(canopen); //定义互斥锁 static irqreturn_t keys_irq(int irq, void *dev_id)
{
pin_timer = (struct pin_desc *)dev_id;
mod_timer(&keys_timer, jiffies+HZ/ ); //jiffies是个全局变量,每10ms累加一次,这里是10ms产生一次中断
return IRQ_HANDLED;
} int key_open(struct inode *inode, struct file *fp)
{
/*获取信号量*/
if( fp->f_flags & O_NONBLOCK )
{
if(down_trylock(&canopen))
return -EBUSY;
}
else
{
down(&canopen);
}
request_irq( IRQ_EINT0, keys_irq, IRQT_BOTHEDGE, "key2", &pins_desc[]);
request_irq( IRQ_EINT2, keys_irq, IRQT_BOTHEDGE, "key3", &pins_desc[]);
request_irq( IRQ_EINT11, keys_irq, IRQT_BOTHEDGE, "key4", &pins_desc[]);
request_irq( IRQ_EINT19, keys_irq, IRQT_BOTHEDGE, "key5", &pins_desc[]);
return ;
} ssize_t key_read(struct file *fp, char __user *buff, size_t count, loff_t *offp){ if(fp->f_flags & O_NONBLOCK )
{
if(!ev_press)
return -EAGAIN;
}
else
{
wait_event_interruptible(button_waitq,ev_press);
}
if(count != )
{
return -EINVAL;
} copy_to_user(buff,&keyvals,);
ev_press = ;
return ;
} ssize_t key_write(struct file *fp, const char __user *buf, size_t count, loff_t *ppos){
} int key_close(struct inode *inode, struct file *file)
{
free_irq(IRQ_EINT0,&pins_desc[]);
free_irq(IRQ_EINT2,&pins_desc[]);
free_irq(IRQ_EINT11,&pins_desc[]);
free_irq(IRQ_EINT19,&pins_desc[]);
up(&canopen);
} static unsigned int key_poll(struct file *file, struct poll_table_struct *wait)
{
unsigned int mask = ;
poll_wait(file, &button_waitq,wait);
if(ev_press)
mask |= POLLIN|POLLRDNORM;
return mask;
} static int key_fsync (int fd, struct file *filp, int on)
{
printk("ok\n");
return fasync_helper (fd, filp, on, &key_async_queue);
} struct file_operations led_fops={
.owner = THIS_MODULE,
.open = key_open,
.write = key_write,
.read = key_read,
.release = key_close,
.poll = key_poll,
.fasync = key_fsync,
}; static void keys_timer_fun(unsigned long t)
{
struct pin_desc *pindesc = (struct pin_desc *)pin_timer;
unsigned int pinval;
if( !pindesc )
return ;
pinval = s3c2410_gpio_getpin(pindesc->pin);
if(pinval)
{
keyvals = pindesc->key_val|0x80; }
else
{
keyvals = pindesc->key_val;
}
ev_press = ;
wake_up_interruptible(&button_waitq); kill_fasync (&key_async_queue, SIGIO, POLL_IN);
return ;
} int major;
static int key_init(void)
{
major = register_chrdev( ,"key_drv", &led_fops );
key_class = class_create(THIS_MODULE,"key_class");
key_class_devs = class_device_create(key_class,NULL,MKDEV(major,),NULL,"my_keys"); init_timer(&keys_timer);
keys_timer.function = keys_timer_fun; /*定时器中断函数*/
keys_timer.expires = ;
add_timer(&keys_timer);
printk("key install Module\n");
return ;
} static void key_exit(void)
{
unregister_chrdev( major, "key_drv" );
class_device_unregister(key_class_devs);
class_destroy(key_class);
del_timer(&keys_timer); //删除定时器
printk("key Module exit\n");
} module_init(key_init);
module_exit(key_exit);
MODULE_LICENSE("GPL");
测试应用程序:
#include <stdio.h>
#include <signal.h>
#include <fcntl.h>
#include <unistd.h>
int fd;
static char key_val;
int main( int argc, char **argv )
{
int oflags;
fd = open("/dev/my_keys",O_RDWR);/* O_NONBLOCK为非阻塞*/
if(fd<)
{
printf("open failed\n");
return ;
}
while()
{
read(fd,&key_val,);
printf("key_val:%d\n",key_val);
}
return ;
}
sd
嵌入式Linux驱动学习之路(十五)按键驱动-定时器防抖的更多相关文章
- 嵌入式Linux驱动学习之路(十四)按键驱动-同步、互斥、阻塞
目的:同一个时刻,只能有一个应用程序打开我们的驱动程序. ①原子操作: v = ATOMIC_INIT( i ) 定义原子变量v并初始化为i atomic_read(v) 返回原子变量 ...
- 嵌入式Linux驱动学习之路(十二)按键驱动-poll机制
实现的功能是在读取按键信息的时候,如果没有产生按键,则程序休眠在read函数中,利用poll机制,可以在没有退出的情况下让程序自动退出. 下面的程序就是在读取按键信息的时候,如果5000ms内没有按键 ...
- 嵌入式Linux驱动学习之路(十八)LCD驱动
驱动代码: /************************************************************************* > File Name: lcd ...
- 嵌入式Linux驱动学习之路(十)字符设备驱动-my_led
首先贴上代码: 字符设备驱动代码: /** *file name: led.c */#include <linux/sched.h> #include <linux/signal.h ...
- 嵌入式Linux驱动学习之路(十九)触摸屏驱动、tslib测试
触摸屏使用流程: 1. 按下产生中断. 2.在中断处理程序中启动AD转换XY坐标. 3.AD转换结束并产生AD中断. 4. 在AD的中断处理函数中上报信息,启动定时器. 5. 定时器时间到后进入中断, ...
- 嵌入式Linux驱动学习之路(十六)输入子系统
以前写的一些输入设备的驱动都是采用字符设备处理的.问题由此而来,Linux开源社区的大神们看到了这大量输入设备如此分散不堪,有木有可以实现一种机制,可以对分散的.不同类别的输入设备进行统一的驱动,所以 ...
- 嵌入式linux的学习之路[转]
我认为的一条学习嵌入式Linux的路: 1)学习 Linux系统安装. 常用命令.应用程序安装. 2) 学习 Linux 下的 C 编程.这本书必学<UNIX 环境高级编程>.<UN ...
- zigbee学习之路(十五):基于协议栈的按键实验
一.前言 经过上次的学习,相信大家已经初步学会使用zigbee协议进行发送和接受数据了.今天,我们要进行的实验是按键的实验,学会如何在协议栈里实现按键中断. 二.实验功能 在协议栈上实现按键中断,BU ...
- IOS学习之路十五(UIView 添加背景图片以及加边框)
怎样给UIview添加背景图片呢很简单,就是先给view添加一个subview,然后设为背景图片: 效果图如下: 很简单直接上代码: //设置内容 self.myTopView.backgroundC ...
随机推荐
- 向 div 元素添加圆角边框:
div { border:2px solid; border-radius:25px; }
- jquery移除属性值
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- iPhone开发与cocos2d 经验谈
转CSDN jilongliang : 首先,对于一个完全没有mac开发经验,甚至从没摸过苹果系统的开发人员来说,首先就是要熟悉apple的那一套开发框架(含开发环境IDE.开发框架uikit,还有开 ...
- 疯狂Android讲义 - 学习笔记(六)
第7章 7.1 使用简单图片 7.1.1 使用Drawable对象 7.1.2 Bitmap和BitmapFactory 7.2 绘图 7.2.1 Android绘图基础:Canvas.Paint等 ...
- Differences between INDEX, PRIMARY, UNIQUE, FULLTEXT in MySQL?
487down vote Differences KEY or INDEX refers to a normal non-unique index. Non-distinct values for ...
- java Properties异常:Malformed \uxxxx encoding.
昨天项目中遇到一个 java.lang.IllegalArgumentException: Malformed \uxxxx encoding.这样的一个异常,debug了一下发现是读取propert ...
- ABP之动态WebAPI(一)
ABP的动态WebApi实现了直接对服务层的调用(其实病没有跨过ApiController,只是将ApiController公共化,对于这一点的处理类似于MVC,对服务端的 调用没有跨过HttpHan ...
- link与@import的区别
我们都知道link与@import都可以引入css样式表,那么这两种的区别是什么呢?先说说它们各自的链接方式,然后说说它们的区别~~~ link链入的方式: <link rel="st ...
- 【JavaScript】浅析javaScript和HTML与unicode字符集的关系
目录结构: // contents structure [-] javaScript和HTML的字符集 javaScript和HTML如何表现unicode字符集 参考文章 javaScript和HT ...
- WebStorage记录滚动条位置
因关注公众号<HTML5学堂>看到这篇文章 "利用本地存储,记录滚动条的位置" ,便好奇敲来试试,然后又看了一些关于WebStorage的资料 附上这篇文章的地址 ht ...