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.外部中断0的tasklet 任务启动定时器
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);