当前位置: 代码迷 >> 驱动开发 >> 初进android驱动开发之字符设备(五-定时器)
  详细解决方案

初进android驱动开发之字符设备(五-定时器)

热度:385   发布时间:2016-04-28 09:58:52.0
初入android驱动开发之字符设备(五-定时器)

这个字符设备系列,主要借助较容易上手的字符设备实例,去讲解linux的一些机制,以及驱动中比较常用到的中断、定时器、信号量等一些知识,由于本人自身的知识有限,对于arm的架构体系不太了解,这里,一般这里只讲,如何去用,对于一些原理性的东西不会深究,以后的文章会慢慢的加深。

想想我们当初玩51单片机的时候,那时候按键防抖是一个硬件、软件都需要处理的地方。软件一般就是加延时检测判断。当然,这里我们也可以用到定时器的这个机制,做按键驱动,这里主要还是以按键为例,但不是讲的按键防抖。

1. 定时器的一些概念:

节拍率(HZ):它是通过静态预处理定义的,在系统启动时,按照HZ值对硬件进行设置。体系结构不同,HZ值不同。

jiffies:全局变量jiffies用来记录自系统启动以来产生的节拍的总数。启动时内核将它设为0。系统运行时间以秒为单位,等于jiffies/HZ。

定时器:它是管理内核流逝的时间的基础。内核常需要推后执行某些代码,也就是说,不在当前时间执行。定时器使用简单,一般做一些初始化工作,设置一个超时时间,指定超时发生后执行的函数,然后激活定时器就可以。指定的函数将在定时器到期时自动执行。执行结束后,定时器自行撤销。所以,定时器不断的创建和撤销,而且它的运行次数不受限制。

备注:部分neir来自于《linux内核设计与实现》


2. 驱动demo:

#include <linux/module.h>#include <linux/kernel.h>#include <linux/init.h>#include <linux/irq.h>#include <linux/input.h>#include <linux/platform_device.h>#include <linux/miscdevice.h>#include <mach/gpio.h>#include <linux/io.h>#include <mach/hardware.h>#include <linux/delay.h>#include <asm/irq.h>#include <asm/uaccess.h>#include <linux/interrupt.h>#include <linux/gpio.h>#include <linux/wait.h>#include <linux/sched.h>#include <plat/gpio-core.h>#include <plat/gpio-cfg.h>#include <plat/gpio-cfg-helpers.h>static struct class *buttondrv_class;static struct device *buttondrv_class_dev;int major;volatile unsigned long *GPCCON;volatile unsigned long *GPCDAT;//static DECLARE_WAIT_QUEUE_HEAD(button_waitq);static struct timer_list button_timer;static unsigned char key_val;static volatile int ev_press = 0;struct pin_desc{	unsigned int pin;	unsigned int key_val;};struct pin_desc pins_desc[2] = {	{S5PV210_GPH3(7), 0x01},};struct pins_desc *irq_temp;static irqreturn_t buttons_irq(int irq, void *dev_id){	printk(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>buttons_irq\n");	irq_temp = (struct pin_desc *)dev_id;	mod_timer(&button_timer, jiffies+HZ/100);	return IRQ_RETVAL(IRQ_HANDLED);}static int button_drv_open(struct inode *inode, struct file *file){	printk(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>button_drv_open\n");	int ret=-1;	s3c_gpio_setpull(S5PV210_GPH3(7), S3C_GPIO_PULL_NONE);	ret = request_threaded_irq(gpio_to_irq(S5PV210_GPH3(7)), NULL,					buttons_irq,					IRQF_TRIGGER_RISING,					"s2", &pins_desc[0]);	printk("ret=%d irq=%d >>>>>>>>>>>>>>>>>>>>>>>>>\n ",ret,gpio_to_irq(S5PV210_GPH3(7)));	return 0;}int button_drv_close(struct inode *inode, struct file *file){	free_irq(gpio_to_irq(S5PV210_GPH3(7)), &pins_desc[0]);	return 0;}static int button_drv_read(struct file *filp, char __user *buf,                                          size_t count, loff_t *offp){	printk(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>button_drv_read\n");	if (count != 1)		return -EINVAL;//	wait_event_interruptible(button_waitq, ev_press);	copy_to_user(buf, &key_val, 1);	key_val=0;	ev_press = 0;	return 1;}static void button_timer_function(unsigned long data){	printk(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>button_timer_function\n");	struct pin_desc *pindesc = irq_temp;	unsigned int pinval;	pinval = gpio_get_value(pindesc->pin);	printk("irq >>>>>>>>>>>>>>>>>>>>>>>>>>>>pinval =%d \n",pinval);	if (pinval)	{			key_val = 0x80 | pindesc->key_val;	}	else	{		key_val = pindesc->key_val;			}    ev_press = 1;                // wake_up_interruptible(&button_waitq);  }static struct file_operations button_drv_fops = {    .owner  =   THIS_MODULE,       .open   =   button_drv_open,           .read	=	button_drv_read,    .release =  button_drv_close,};unsigned long test=0;static int button_drv_init(void){	printk(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>button_drv_init\n");		button_timer.function = button_timer_function;	button_timer.data=test;	init_timer(&button_timer);	add_timer(&button_timer); //	setup_timer(&button_timer,button_timer_function,test);  //before 4 method  instead of the one    GPCCON = (volatile unsigned long *)ioremap(0xE0200C60, 8);  	GPCDAT= GPCCON + 1;	if (!GPCCON) {		return -EIO;	}	major = register_chrdev(0, "button_drv", &button_drv_fops); 	buttondrv_class = class_create(THIS_MODULE, "buttondrv");	buttondrv_class_dev = device_create(buttondrv_class, NULL, MKDEV(major, 0), NULL, "button"); 	return 0;}static void button_drv_exit(void){	printk(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>button_drv_exit\n");		unregister_chrdev(major, "button_drv"); 	device_unregister(buttondrv_class_dev);	class_destroy(buttondrv_class);	iounmap(GPCCON);}module_init(button_drv_init);module_exit(button_drv_exit);MODULE_LICENSE("GPL");

2.1 代码简单解析:

定时器操作的步骤:

1.定义一个timer_list结构体:static struct timer_list button_timer;

      2.定时器超时调用的函数:button_timer.function = button_timer_function;

给定时器操作函数传的参数:button_timer.data=test;

根据该定义该timer_list的参数初始化定时器:init_timer(&button_timer);

激活定时器:add_timer(&button_timer); 

   注:setup_timer(&button_timer,button_timer_function,test); 这个可代替上面的2步。

    3. 在中断处理函数中,mod_timer(&button_timer, jiffies+HZ/100); //10ms

注:动态定时器不需要手动释放,mod_timer超时执行之后,就会自动释放。

版权声明:本文为博主原创文章,未经博主允许不得转载。

  相关解决方案