15.linux按键驱动程序(二)
linux按键驱动程序
包含内容定时器延时去抖动,阻塞型设备驱动设计
一、定时器延时去抖
按键所用开关为机械弹性开关,当机械触点断开、闭合时,由于机械触点的弹性作用,开关不会马上稳定地接通或断开。因而在闭合及断开的瞬间总是伴有一连串的抖动的。按键去抖动的方法主要有两种,一种是硬件电路去抖动;另一种就是软件延时去抖动。而延时又一般分为了两种,一种是for循环等待,另一种是定时器延时。在操作系统中,由于效率方面的原因,一使用定时器。
1.1内核定时器
定时器的使用分为了四个步骤:
1.定义定时器的变量,就是timer_list结构。
2.要对结构进行初始化。Init_timer是系统自动运行的初始化函数,能初始化很大部分timer_list里面的成员。但是,超时函数是需要我们自己设置,就是function。
3.使用add_timer函数注册定时器。
4.mod_timer重启定时器。注意,定时器不是循环的,需要重复调用mod_timer函数。
Linux内核使用struct timer_list来描述一个定时器:
struct timer_list{
struct list_head entry;
unsigned long expires;
void (*function)(unsigned long);
unsigned long data;
struct tvec_base *base;
};
其中expires是定时器延时的时间,function函数是定时器超时后要做的事情。
1.2使用内核定时器
二、阻塞型驱动程序设计
当一个设备无法立刻满足用户的读写请求时应当如何处理? 例如:调用read时,设备没有数据提供, 但以后可能会有;或者一个进程试图向设备写入数据,但是设备暂时没有准备好接收数据。当上述情况发生的时候,驱动程序应当(缺省地)阻塞进程,使它进入等待(睡眠)状态,直到请求可以得到满足。
2.1内核等待队列
在实现阻塞驱动的过程中,也需要有一个“候车室”来安排被阻塞的进程“休息”,当唤醒它们的条件成熟时,则可以从“候车室”中将这些进程唤醒。而这个“候车室”就是等待队列。
2.2队列描述
1、定义等待队列
wait_queue_head_t my_queue
2、初始化等待队列
init_waitqueue_head(&my_queue)
3、定义+初始化等待队列
DECLARE_WAIT_QUEUE_HEAD(my_queue)
4、进入等待队列,睡眠
4.1 wait_event(queue,condition)
当condition(布尔表达式)为真时,立即返回;否则让进程
进入TASK_UNINTERRUPTIBLE模式的睡眠,并挂在queue参数所指定的等待队列上。
4.2wait_event_interruptible(queue,condition)
当condition(布尔表达式)为真时,立即返回;否则让
进程进入TASK_INTERRUPTIBLE的睡眠,并挂在queue参数所指定的等待队列上。
4.3int wait_event_killable(queue, condition)
当condition(一个布尔表达式)为真时,立即返回;否则让进程进入TASK_KILLABLE的睡眠,并挂在queue参数所指定的等待队列上。
5、从等待队列中唤醒进程
5.1 wake_up(wait_queue_t *q)
从等待队列q中唤醒状态为TASK_UNINTERRUPTIBLE,TASK_INTERRUPTIBLE,TASK_KILLABLE 的所有进程。
5.2 wake_up_interruptible(wait_queue_t *q)
从等待队列q中唤醒状态为TASK_INTERRUPTIBLE 的进程
按键阻塞代码如下(也是关于按键所有的程序):
#include <linux/module.h>
#include <linux/init.h>
#include <linux/miscdevice.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/uaccess.h> #include <linux/sched.h> #define GPNCON 0x7f008830
#define GPNDAT 0x7f008834 MODULE_LICENSE("GPL"); struct work_struct *work1;
unsigned int *gpio_dat;
struct timer_list key_timer; unsigned int key_num = ;
wait_queue_head_t key_q; void work1_func(struct work_struct *work)
{
//启动定时器 100毫秒超时=HZ/10,HZ=1秒。jiffies是系统当前时间
mod_timer(&key_timer,jiffies + (HZ/)); //启动定时器
} void key_timer_func(unsigned long data) //定时器超时函数
{
unsigned int key_val;
key_val = readw(gpio_dat) &0x01;
if(key_val==)
key_num = ;
key_val = readw(gpio_dat) &0x02;
if(key_val==)
key_num = ;
wake_up(&key_q);
} irqreturn_t key_int(int irp,void *dev_id) //中断处理函数
{
//3.提交下半部
schedule_work(work1);
return IRQ_HANDLED;
} void key_hw_init(void) //硬件初始化
{
unsigned int *gpio_config;
unsigned short data;
gpio_config = ioremap(GPNCON,); //动态映射虚拟地址
data = readw(gpio_config);
data &= ~0xfff;
data |= 0xaaa;
writew(data,gpio_config);
gpio_dat = ioremap(GPNDAT,); //将数据寄存器地址转化为虚拟地址
} int key_open(struct inode *node,struct file *filp)
{
return ;
} ssize_t key_read (struct file *filp, char __user *buf, size_t size, loff_t *pos)
{
wait_event(key_q,key_num); //进入睡眠 copy_to_user(buf,&key_num,); key_num = ;
return ;
} struct file_operations key_fops =
{
.open = key_open,
.read = key_read,
}; struct miscdevice key_miscdev =
{
.minor = , //次设备号
.name = "key",
.fops = &key_fops,
};
//驱动程序初始化
static int button_init(void)
{
misc_register(&key_miscdev); //1注册混杂设备
//2按键硬件初始化
key_hw_init();
request_irq(IRQ_EINT(),key_int,IRQF_TRIGGER_FALLING,"key",); //注册中断处理程序
request_irq(IRQ_EINT(),key_int,IRQF_TRIGGER_FALLING,"key",); //注册中断处理程序 //3创建工作1
work1 = kmalloc(sizeof(struct work_struct),GFP_KERNEL);
INIT_WORK(work1,work1_func); //4初始化内核定时器
init_timer(&key_timer);
key_timer.function = key_timer_func;
//注册定时器
add_timer(&key_timer);
//初始化等待队列
init_waitqueue_head(&key_q);
return ;
} static void button_exit(void)
{
misc_deregister(&key_miscdev); //注销混杂设备
//注销中断处理程序
free_irq(IRQ_EINT(),);
free_irq(IRQ_EINT(),);
} module_init(button_init);
module_exit(button_exit);
按键应用程序:
#include <stdio.h>
#include <stdlib.h> int main()
{
int fd;
int key_num; //1.打开设备
fd = open("/dev/6410key",);
if(fd<)
printf("open device fail!\n"); //2.读取设备
read(fd,&key_num,);
printf("key is %d\n",key_num); //3.关闭设备
close(fd);
}
运行过程如下:
15.linux按键驱动程序(二)的更多相关文章
- 14.linux按键驱动程序(一)
按键驱动程序 本文学习主要包含按键硬件的实现.中断分层管理.按键定时器去抖.阻塞性驱动程序设计.这里面需要使用到混杂设备驱动和中断处理程序的内容. 一.创建按键混杂设备驱动模型 int key_ope ...
- LINUX按键驱动程序
<<混杂设备驱动模型>> <混杂设设备的描述> <混在设备的概念> 在linux系统中,存在一类字符设备,他们拥有相同的主设备号(10),但是次设备号不 ...
- 在Linux下的中断方式读取按键驱动程序
// 在Linux下的中断方式读取按键驱动程序 //包含外部中断 休眠 加入poll机制 // 采用异步通知的方式 // 驱动程序发 ---> app接收 (通过kill_fasync()发送) ...
- 转:Linux网卡驱动程序编写
Linux网卡驱动程序编写 [摘自 LinuxAID] 工作需要写了我们公司一块网卡的Linux驱动程序.经历一个从无到有的过程,深感技术交流的重要.Linux作为挑战微软垄断的强有力武器,日益受到大 ...
- 【转】linux设备驱动程序中的阻塞机制
原文网址:http://www.cnblogs.com/geneil/archive/2011/12/04/2275272.html 阻塞与非阻塞是设备访问的两种方式.在写阻塞与非阻塞的驱动程序时,经 ...
- 在Ubuntu上为Android系统编写Linux内核驱动程序(老罗学习笔记1)
这里,我们不会为真实的硬件设备编写内核驱动程序.为了方便描述为Android系统编写内核驱动程序的过程,我们使用一个虚拟的硬件设备,这个设备只有一个4字节的寄存器,它可读可写.想起我们第一次学习程序语 ...
- 在Ubuntu上为Android系统内置C可执行程序测试Linux内核驱动程序(老罗学习笔记2)
在前一篇文章中,我们介绍了如何在Ubuntu上为Android系统编写Linux内核驱动程序.在这个名为hello的Linux内核驱动程序中,创建三个不同的文件节点来供用户空间访问,分别是传统的设备文 ...
- 在Ubuntu上为Android增加硬件抽象层(HAL)模块访问Linux内核驱动程序(老罗学习笔记3)
简单来说,硬件驱动程序一方面分布在Linux内核中,另一方面分布在用户空间的硬件抽象层中.接着,在Ubuntu上为Android系统编写Linux内核驱动程序(老罗学习笔记1)一文中举例子说明了如何在 ...
- 如何编写Linux设备驱动程序
一.Linux device driver 的概念 系统调用是操作系统内核和应用程序之间的接口,设备驱动程序是操作系统内核和机器硬件之间的接口.设备驱动程序为应用程序屏蔽了硬件的细节,这样在应用程序看 ...
随机推荐
- IRequiresSessionState接口控制
刚刚接触.net web端的朋友都会被Session坑过,莫名其妙的不能读取Session数据,后来知道原来有IRequiresSessionState这个接口,不继承的就不能读取Session里面的 ...
- Web API系列(一)设计经验与总结
在移动互联网的时代, Web服务已经成为了异构系统之间的互联与集成的主要手段,各种 Web服务几乎都采用REST风格的Web Api来构建. 通过Http协议的形式来. 以Get/Post方式发送请求 ...
- RabbitMQ学习
参考链接:http://www.cnblogs.com/leocook/p/mq_rabbitmq_0.html
- 关于LESS
LESS 是动态的样式表语言,通过简洁明了的语法定义,使编写 CSS 的工作变得非常简单. 翻译成大白话:写CSS算是体力活,并没有编程的感觉,不给前端人员装逼的机会,于是就搞了这玩意,相当于编程写C ...
- C#大数据文本高效去重
C#大数据文本高效去重 转载请注明出处 http://www.cnblogs.com/Huerye/ TextReader reader = File.OpenText(@"C:\Users ...
- 3.0、Spring-注入
一.Spring的基本介绍:Spring是一个开源框架,Spring是于2003 年兴起的一个轻量级的Java 开发框架,由Rod Johnson创建.简单来说,Spring是一个分层的JavaSE/ ...
- Apache Torque入门学习
Introduction Apache Torque is an object-relational mapper for java. In other words, Torque lets you ...
- 信息安全比赛总结(21ic转帖)
我们的题目是基于这个ZedBoard的__视频流的人脸识别识别的算法采用的是PCA,,但是在后期的调试和实验中发现,,PCA的效果很容易受到环境,比如光照强度,背景,摄像头像素等影响:如果后期的改进的 ...
- Spring-test使用JUnit时,测试类autowired报错,create bean error
Spring-test使用JUnit时,测试类里面使用autowired会报错, 报create bean error...... 但是controller里面@autowired可以正常运行的. 在 ...
- Android开发 default activity not found
新建的项目,今天打开的时候,发现无法编译了.编译按钮无法点击,必须edit configuration.并且报错 default activity not found. 解决: 少写了一个" ...