文章目录
内核延时函数接口
延时的函数有delay
和sleep
两种类型:
delay接口
c
void ndelay(unsigned long nsecs);//纳秒延时
void udelay(unsigned long usecs);//微妙延时
void mdelay(unsigned long msecs);//毫秒延时
sleep接口
c
void msleep(unsigned int msecs);//毫秒级延时
long msleep_interruptible(unsigned int msecs);//毫秒级延时,可被信号打断
void ssleep(unsigned int seconds);//秒级延时
delay和sleep的区别
delay
型延时:忙等待,占用CPU资源,延迟过程无法进行其他任务。
sleep
型延时:休眠,不占用CPU资源,其它模块此时可以使用CPU资源。
低分辨率定时器
jiffies和HZ
jiffies
:全局变量,表示系统启动以来产生的节拍数 。每产生一次中断,jiffies
自动加一。
HZ
:赫兹,也叫节拍率 ,表示每秒种产生多少次中断。
例如:HZ
为200
,代表每秒产生200
次中断,那2
秒钟jiffies
的值就应该是400
。因此系统的运行时间可以用jiffies/HZ表示。
一秒钟:jiffies
+ HZ
表示一秒钟
原因:内核中统计时间是通过jiffies,因此要比较时间或者定时也是通过jiffies。
例如程序运行一秒钟,内核如何知道运行了一秒?答案是运行一秒后的jiffies值和运行前的jiffies值进行比较,如果相差为一个HZ,则代表一秒钟。jiffies+HZ其实就是一秒后jiffies的值,所以jiffies+HZ可以间接表示一秒钟。
定时2秒:jiffies
+ 2*HZ
。以此类推
获取当前的jiffies
值,可以用get_jiffies_64()
函数。
将时间转为对应的jiffies
值,可以用msecs_to_jiffies()
等函数,例如msecs_to_jiffies(1000)
代表1秒,函数返回值其实就是HZ
。
相关接口
c
#include<linux/timer.h>
struct timer_list {
struct list_head list;
unsigned long expires; //定时器到期时间,传入的是jiffies值
unsigned long data; //作为参数被传入定时器处理函数
void (*function)(unsigned long);
};
c
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);//删除定时器
c
unsigned int jiffies_to_msecs (const unsigned long j);//将jiffies转为对应的毫秒值
unsigned int jiffies_to_usecs (const unsigned long j);//将jiffies转为对应的微秒值
unsigned long msecs_to_jiffies (const unsigned int m);//将毫秒值转为对应的jiffies
unsigned long usecs_to_jiffies (const unsigned int u);//将微秒值转为对应的jiffies
定时器使用示例
使用步骤:
1、调用init_timer
初始化一个定时器,给struct timer_list
各成员赋值。
2、调用add_timer
将定时器添加到内核定时器链表,时间到后回调函数自动调用,用mod_timer
修改expires
的值可实现循环定时。
3、不需要定时器时,调用del_timer
删除。
单次定时
加载驱动一秒钟后,打印出"timer handler, data:520
":
c
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/sched.h>//jiffies在此头文件中定义
#include <linux/timer.h>//struct timer_list
struct timer_list timer;
static void timer_handler (unsigned long arg)
{
printk("timer handler, data:%d\n", arg);
}
static int __init my_init(void)
{
printk("%s enter\n", __func__);
init_timer(&timer);
timer.expires = get_jiffies_64() + msecs_to_jiffies(1000);//定时1秒
timer.function = timer_handler;
timer.data = 520;
add_timer(&timer);
return 0;
}
static void __exit my_exit(void)
{
printk("%s enter\n", __func__);
del_timer(&timer);
}
module_init(my_init);
module_exit(my_exit);
MODULE_LICENSE("GPL");
循环定时
实现循环定时就是在定时时间到了之后,调用mod_timer函数再次修改定时时间。
每隔一秒钟打印"timer handler, data:520
"
c
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/sched.h>//jiffies在此头文件中定义
#include <linux/timer.h>//struct timer_list
struct timer_list timer;
static void timer_handler (unsigned long arg)
{
printk("timer handler, data:%d\n", arg);
mod_timer(&timer, get_jiffies_64() + msecs_to_jiffies (1000));
}
static int __init my_init(void)
{
init_timer(&timer);
timer.expires = get_jiffies_64() + msecs_to_jiffies (1000);//定时1秒
timer.function = timer_handler;
timer.data = 520;
add_timer(&timer);
return 0;
}
static void __exit my_exit(void)
{
del_timer(&timer);
}
module_init(my_init);
module_exit(my_exit);
MODULE_LICENSE("GPL");