Table of Contents
定时器简介
1、HZ
系统定时器频率,与体系结构相关,系统启动根据HZ设置定时器硬件
HZ = (100) (ARM 平台)
2、jiffies
内核全局变量,32位,unsigned long,记录自开机依赖发生了多少次时钟中断,每发生一次,jiffies+1
系统时间以秒为单位就等于jiffies/HZ
以秒为单位的时间转化为jiffies: Seconds*HZ
msecs_to_jiffies()毫秒转jiffies
3、tick (节拍)
它是HZ的倒数,也就是每发生一次硬件定时器中断的时间间隔 ,如HZ为100 ,tick为10毫秒
定时器编程步骤
1、定时器初始化
定时器对应的数据结构
struct timer_list {
unsigned long expires; // 超时时候jiffies的值:jiffies + 3*HZ
void (*function)(unsigned long); // 超时处理函数,注意要对形参进行数据类型的转换
unsigned long data; // 内核调用超时处理函数时传递给它的参数,data存放指针
}
static struct timer_list mytimer;
初始化定时器
init_timer(&mytimer);
mytimer.function = mytimer_func; //指定定时器的处理函数
mytimer.expires = jiffies + 3*HZ; //超时时间为3s以后
//给超时处理函数传递的参数是mydata的地址,要注意在超时处理函数中进行数据类型的转换
mytimer.data = (unsigned long )&mydata;
内核要管理一大堆的定时器,因此会把定时器挂到链表上进行管理
2、添加定时器到内核并启动定时器
//启动定时器
add_timer(&mytimer);
3、编写定时处理函数
定时处理函数记得重新刷新定时时间,否则这个函数只会被执行一次
mod_timer(&mytimer, jiffies + msecs_to_jiffies(2000));
//超时处理函数
static void mytimer_func(unsigned long data)
{
int *pdata = (int *)data;
printk("hello,kernel, data = %#x\n", *pdata);
//重新添加定时器,如果不添加,定时器处理函数只执行一次
mod_timer(&mytimer, jiffies + msecs_to_jiffies(2000));
}
4、其他操作
删除定时器del_timer
参考代码
#include <linux/init.h>
#include <linux/module.h>
#include <linux/timer.h>
#include <asm/gpio.h>
#include <plat/gpio-cfg.h>
//分配定时器
static struct timer_list mytimer;
static int mydata = 0x5555;
//超时处理函数
static void mytimer_func(unsigned long data)
{
int *pdata = (int *)data;
printk("hello,kernel, data = %#x\n", *pdata);
//重新添加定时器,如果不添加,定时器处理函数只执行一次
mod_timer(&mytimer, jiffies + msecs_to_jiffies(2000));
}
static int mytimer_init(void)
{
//初始化定时器
init_timer(&mytimer);
//指定定时器超时时候的时间
mytimer.expires = jiffies + msecs_to_jiffies(2000); //2s
mytimer.function = mytimer_func; //超时处理函数
mytimer.data = (unsigned long)&mydata; //给超时处理函数传递参数
//启动定时器
add_timer(&mytimer);
printk("add timer ok!\n");
return 0;
}
static void mytimer_exit(void)
{
del_timer(&mytimer);
printk("del timer ok!\n");
}
module_init(mytimer_init);
module_exit(mytimer_exit);
MODULE_LICENSE("GPL");