linux内核软件定时器
1.linux内核描述定时器使用的数据结构
struct timer_list {
unsigned long expires; //定时器的超时时间,例如如果设置超时时间的间隔为5秒;expires = jiffies + 5*HZ
void (*function)(unsigned long);//定时器的处理函数,当超时时间到期,内核就会执行定时器的处理函数,定时器到期内核会将定时器删除,也就是说定时器的处理函数只执行一次;
unsigned long data; //给定时器处理函数传递的参数,一般传递指针
};
如何使用内核定时器?
1.分配定时器对象
struct timer_list mytimer;
2.初始化定时器对象
init_timer(struct timer *timer);
函数功能:初始化定时器
参数:分配的定时器对象指针
注意:这个函数不会初始化expires,function,data这个三个字段,这三个字段需要程序员自己去指定,例如:
init_timer(&mytimer);
mytimer.expires = jiffies + 5*HZ
mytimer.function = mytimer_funtion;
mytimer.data = (unsigned long)&mydata;
3.向内核添加注册定时器
add_timer(&mytimer); //一旦添加完毕,内核就开始对这个定时器进行倒计时!时钟中断处理函数每隔10ms检查一次定时器是否到期,如果到期,内核执行对应的定时器处理函数,并且将定时器进行删除。
4.删除定时器
del_timer(&mytimer); //定时器到期,内核会帮你删除定时器,如果定时器没到期,可以使用此方法进行删除。
5.修改定时器的超时时间
mod_timer(&mytimer, jiffies + 2*HZ); //设置定时器的超时时间为2秒以后
相当于= del_timer 先将原先定时器删除
+ expires = jiffies + 2*HZ 设置新的超时时间
+ add_timer 重新添加定时器
注意:千万不能用以上三步骤来实现mod_timer,以上三步骤的执行路径不是原子的,有可能被打断!
6.注意:定时器的实现基于软中断,所以定时器的处理函数同样不能进行休眠操作!
7.如果想让定时器的处理函数重复执行,循环执行,只需在定时器处理函数中重新添加定时器即可!
案例1:利用定时器,每隔2秒钟打印"hello ,tarena"
案例2:利用定时器,每个2秒开关灯;
案例3:利用模块参数的知识(不能采用字符设备驱动框架)来动态修改灯的闪烁频率;2000ms,1000ms,500ms,200ms.
注意:加载完驱动模块以后,无需卸载的情况下,动态修改闪烁的频率!提示:权限为0或者非0
实验步骤:
insmod mytimer_drv.ko speed = 2000 //2秒闪烁
echo 500 > /sys/module/mytimer_drv/parameters/speed //500ms
毫秒和jiffies转换:
unsigned long timeout = jiffies + msecs_to_jiffies(500);
unsigned long timeout = jiffies + HZ/2;