内核中定时器是一个基础的功能,很多的驱动程序都会用到定时器进行定时或延时,当然比较短的延时也可以使用ndelay和udelay这样的函数,但是这些函数都是以浪费机器周期来获得延时的,所以还是应该避免使用。下面介绍一下定时器的内容:
#include<linux/timer.h> //头文件
//主要的结构体文件
struct timer_list {
struct list_head list;unsigned long expires; //定时时间
unsigned long data; //作为参数被传入定时器处理函数
void (*function)(unsigned long); //定时器处理函数
};
用到的函数:
void init_timer(struct timer_list * timer); //初始化定时器
void add_timer(struct timer_list * timer);//添加定时器到链表
int mod_timer(struct timer_list *timer, unsigned long expires);//修改定时器的expires
int del_timer(struct timer_list * timer); //从链表中删除定时器
基本操作步骤:
1、定义一个定时器timer
struct timer_list timer;
2、初始化该定时器
init_timer(&timer);
3、给定时器成员变量赋值(主要设定定时时间、处理函数和传递参数)
timer.expires = jiffies + 延时;
timer.function = timer_handle; //timer_handle需要自己定义的处理函数
timer.data = 0; //传递给timer_handle的参数
4、添加该定时器到定时列表
add_timer(&timer);
5、定义并实现timer_handle函数
static void timer_handle( unsigned long arg)
{
... ...
//如果不希望定时器只工作一次,需要重新定义定时expires并添加到定时器列表
timer.expires = jiffies + 延时;
add_timer(&timer);
//或者使用mod_timer也可以实现循环定时
//mod_timer(&timer, jiffies + 延时);
}
6、在release函数中删除定时器
del_timer(&timer);
这样定时就设置好了,一旦你添加定时器到定时链表中,定时器就开始工作了,所以还是建议把定时器的初始化工作(步骤2-4)放在open函数中去实现,只有用到的时候才会开启定时器工作,这样就不会造成CPU资源的浪费了。
定时器实现的原理还是通过CPU内部的定时器模块来实现的,软件只是对硬件寄存器进行配置,最终实现还是通过硬件完成的。一个硬件定时器的初始化需要设置定时器的初始值,注册中断向量寄存器,设置优先级,然后打开中断(定时中断、外设中断等)。定时器会按照机器周期来增加,当增加到的值和设定的定时器初值相等或者定时器溢出时,定时器会触发定时中断,然后CPU会找到中断向量寄存器中注册的中断函数进行中断的处理。CPU的机器周期是通过外部的振荡电路获取的,然后通过内部的锁相环电路(PLL)来调整到合适的频率提供给每个模块使用。