Linux驱动开发-9、Linux定时器

时间:2021-12-24 23:23:49

Linux定时器

1.定时器是对机器时钟中断的应用 -

2.内核提供一组数据结构来完成定时触发工作或者完成周期性的事务

3.操作系统中,一般不允许使用for循环来延时,一般使用定时器来完成延时功能

4.jiffies 表当前时间,HZ表示延迟1S

5.数据结构<linux/timer.h>

struct timer_list {

/*

 * All fields that change during normal runtime grouped to the

 * same cacheline

 */

struct list_head entry; /*定时器列表*/

unsigned long expires; /*定时器到期时间,以jiffy为单位*/

struct tvec_base *base; /**/

 

void (*function)(unsigned long);/*定时器到期处理函数*/

unsigned long data; /*作为参数被传入定时器处理函数*/

int slack;

....

};

 

6.相关函数

a) 初始化定时器

法一:

#define init_timer(timer)\

init_timer_key((timer), NULL, NULL)

 

void init_timer_key(struct timer_list *timer,const char *name,struct lock_class_key *key)

{

debug_init(timer);

__init_timer(timer, name, key);

}

 

static void __init_timer(struct timer_list *timer,const char *name,struct lock_class_key *key)

{

timer->entry.next = NULL;

timer->base = __raw_get_cpu_var(tvec_bases);

timer->slack = -1;

..

lockdep_init_map(&timer->lockdep_map, name, key, 0);

}

注:init_timer()宏初始化timer_list结构体entry成员的next为空,并给base指针赋值

 

法二:

下面这个宏也可以用来初始化:给定时器结构体的成员赋值

TIMER_INITIALIZER(_function, _expires, _data)

 

给定时器结构底成员赋值的快捷方式

#define DEFINE_TIMER(_name, _function, _expires, _data) \

struct timer_list _name = \在这里帮我们定义了结构体,所以快捷

TIMER_INITIALIZER(_function, _expires, _data)

法三:

最后一种方法用于初始化定时器斌为成员赋值

#define setup_timer(timer, fn, data) \

do { \

static struct lock_class_key __key; \

setup_timer_key((timer), #timer, &__key, (fn), (data));\

} while (0)

 

b) 添加定时器(注册内核定时器)

void add_timer(struct timer_list *timer);

 

c) 删除定时器

int del_timer(struct timer_list *timer)

 

d) 修改定时器---修改定时的超时时间expires

int mod_timer(struct timer_list *timer, unsigned long expires)

 

内核定时器使用模板

/*设备结构体*/

struct xxx_dev

{

struct miscdevices misc;

....

timer_list xxx_timer; /*设备具有的定时器*/

};

 

/*定时器处理函数,实现周期运行*/

static void xxx_do_timer(unsigned long arg)

{

struct xxx_dev *dev = (struct xxx_dev *)arg /*循环加载,相互转换*/

....

/*调度定时器再执行*/

dev->xxx_timer.expires = jiffies + delay;

add_timer(&(dev->timer));

}

/*驱动中的某函数*/

xxx_func1(...)

{

struct xxx_dev *dev = filp->private_data;/*使用文件结构的private_data传递结构*/

....

/*初始化定时器*/

init_timer(&(dev->xxx_timer)); /*注意取得是定时器的指针*/

dev->xxx_timer.function = xxx_do_timer;

dev->xxx_timer.data = (unsigned long)dev; /*将结构体的参数传递给超时处理函数*/

/*设定延时,注册定时器*/

dev->xxx_timer.expires = jiffies + delay;

add_timer(&dev->xxx_timer);

....

}

/*驱动中的某函数*/

xxx_func2(...)

{

....

/*删除定时器*/

del_timer(&(dev->xxx_timer));

...

}

 

 

驱动编程测试

 

 

/******************************************

author : hntea

date: 2016/3/15

function :

1.检测按键中断

2.在中断底半部交个tasklet处理

3.外部中断0tasklet 任务启动定时器

4.定时器打印消息

******************************************/

 

#include "key_hard.h"

/******************************************

定时器操作

******************************************/

 

/*创建一个定时器*/

struct timer_list key_timer;

 

/*定时器处理函数,实现周期运行*/

static void key_do_timer(unsigned long data)

{

printk("runing timer work\n");

}

 

/******************************************

函数名: key_open

函数功能:文件操作

******************************************/

int  key_open(struct inode *inode, struct file *filp)

{

key_hardinit();

return 0;

}

/******************************************

函数名:

函数功能:文件操作

******************************************/

struct file_operations key_fop =

{

.open = key_open,

};

 

struct miscdevice key=

{

.minor = DEV_MINIR ,

.name = "Key",

.fops = &key_fop,

};

 

/******************************************

中断底半部用任务实现

******************************************/

/*定义 task */

struct tasklet_struct key1_task;

struct tasklet_struct key2_task;

 

void key1_taskfun(unsigned long x)

{

int ret = 0;

printk("I am key1_task ------- My argument is:%ld\r\n",x);

ret = mod_timer(&key_timer,  jiffies + HZ); /*1S后执行超时函数*/

}

void key2_taskfun(unsigned long x)

{

printk("I am key2_task ------- My argument is:%ld\r\n",x);

}

/*关联结构体和服务函数*/

DECLARE_TASKLET(key1_task,key1_taskfun,1);

DECLARE_TASKLET(key2_task,key2_taskfun,2);

 

/******************************************

函数功能:中断服务函数入口

******************************************/

static irqreturn_t key1_interrupt (int irq, void *dev_id)

{

  /*1、顶部,硬件操作*/

  

  /*2、底部,交个工作队列来处理*/

    tasklet_schedule(&key1_task);

    return 0;

}

static irqreturn_t key2_interrupt (int irq, void *dev_id)

{

  /*1、顶部,硬件操作*/

  

  /*2、底部,交个工作队列来处理*/

    tasklet_schedule(&key2_task);

    return 0;

}

 

 

/**********************************

函数名:

函数功能:初始化函数

**********************************/

static int keyInit(void)

{

int ret = 0;

/*1、注册设备文件*/

ret = misc_register(&key);

/*2、注册中断号*/

ret = request_irq(IRQ_EINT0,key1_interrupt,IRQF_TRIGGER_FALLING, "key1", 0);

printk("ret val is:%d\n",ret);

ret = request_irq(IRQ_EINT1,key2_interrupt,IRQF_TRIGGER_FALLING, "key2", 0);

printk("ret val is:%d\n",ret);

/*初始化定时器*/

init_timer(&key_timer);

key_timer.function = key_do_timer;

/*注册定时器*/

add_timer(&key_timer);

return 0;

}

static void keyExit(void)

{

int ret = 0;

/*注销中断*/

free_irq(IRQ_EINT0, 0);

free_irq(IRQ_EINT1,0);

/*注销混杂设备*/

ret = misc_deregister(&key);

/*注销设备*/

}

 

MODULE_LICENSE("GPL");

MODULE_AUTHOR("Hntea");

 

module_init(keyInit);

module_exit(keyExit);