linux驱动 — timer定时器的使用

前言

定时器是我们最常用到的功能,一般用来完成定时功能,本章我们就来学习一下 Linux 内
核提供的定时器 API 函数,通过这些定时器 API 函数我们可以完成很多要求定时的应用。Linux
内核也提供了短延时函数,比如微秒、纳秒、毫秒延时函数,本章我们就来学习一下这些和时
间有关的功能。

一、普通定时器使用

这种定时精度低,对实时性要求不严格的场合可以用,内核中使用 CONFIG_HZ 来设置自己的系统时
钟。打开文件 include/asm-generic/param.h,有如下内容:

# undef HZ
# define HZ CONFIG_HZ 
# define USER_HZ 100 
# define CLOCKS_PER_SEC (USER_HZ)

Linux 内核使用全局变量 jiffies 来记录系统从启动以来的系统节拍数,系统启动的时候会
将 jiffies 初始化为 0,jiffies 定义在文件 include/linux/jiffies.h 中,定义如下:

extern u64 __jiffy_data jiffies_64;
extern unsigned long volatile __jiffy_data jiffies;
//判断有没有超时,实际就是比较两个数的大小
#define time_after(a,b)		\
	(typecheck(unsigned long, a) && \
	 typecheck(unsigned long, b) && \
	 ((long)((b) - (a)) < 0))
#define time_before(a,b)	time_after(b,a)

代码实例

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/hrtimer.h>
#include <linux/jiffies.h>
 
//定义一个timer_dev结构体
struct timer_dev{
	int timeperiod; /* 定时周期,单位为 ms */
	struct timer_list timer; /* 定义一个定时器 */
	spinlock_t lock; /* 定义自旋锁 */
};
struct timer_dev dev;

//定时器回调函数
void normal_timer_hander(unsigned long arg)
{ 
	printk("enter normal_timer_hander\r\n");
	//修改定时值并且重新启动定时器
	mod_timer(&dev.timer, jiffies + msecs_to_jiffies(2000));
}

static int __init test_init(void) 
{
	init_timer(&dev.timer); //初始化定时器,必须的必
	//设置定时器回调函数
	dev.timer.function = normal_timer_hander; 
	//定时器超时时间设置,单位为节拍数,使用毫秒转节拍
	dev.timer.expires=jiffies + msecs_to_jiffies(2000);//2S
	//将设备结构体作为参数
	dev.timer.data = (unsigned long)&dev;
	//向Linux内核注册定时器,注册之后定时器就会开始运行
	add_timer(&dev.timer);
}

static void __exit test_exit(void)
{
	del_timer(&dev.timer); //删除定时器
	//del_timer_sync(&dev.timer);//会等待其他处理器使用完定时器再删除
}

module_init(test_init);
module_exit(test_exit);
MODULE_LICENSE("GPL");

二、高精度定时器使用

高精度定时器,为我们提供了纳秒级别的定时精度,以满足对精确时间有迫切需求的应用程序或内核驱动。
hrtimer 结构体定义在<Linux/hrtimer.h>中,如下:

/**
 * The hrtimer structure must be initialized by hrtimer_init()
 */
struct hrtimer {
	struct timerqueue_node		node;
	ktime_t				_softexpires;
	enum hrtimer_restart		(*function)(struct hrtimer *);
	struct hrtimer_clock_base	*base;
	u8				state;
	u8				is_rel;
	u8				is_soft;
};

看到没有,hrtimer定义的结构体必须用hrtimer_init()函数来初始化
_softexpires :记录了定时器到期时间
function:定时器回调函数,该函数返回一个枚举值,它决定了该hrtimer是否需要被重新激活。
base:clock基类,里面有很多跟时间相关的,比如我们常用的get_time()函数

代码实例

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/hrtimer.h>
#include <linux/jiffies.h>

//定义一个hrtimer
static struct hrtimer timer;
ktime_t kt;

//定时器回调函数
static enum hrtimer_restart hrtimer_hander(struct hrtimer *timer)
{
    printk("enter hrtimer_hander\r\n");
    hrtimer_forward(timer,timer->base->get_time(),kt);
	//hrtimer_forward_now(timer, ktime_set(1,0));//同上面函数
    return HRTIMER_RESTART;  //重启定时器
}
 
static int __init test_init(void)
{
	//设置定时时间
    kt = ktime_set(1,10000000);// 1s  10000000ns = 1s+10ms
	//hrtimer_init(timer, which_clock, mode);
	//which_clock:表示选择系统的哪种时钟,一种CLOCK_REALTIME表示绝对时间,另一种CLOCK_MONOTONIC表示相对时间。
	//mode:表示hrtimer的类型,HRTIMER_MODE_ABS,HRTIMER_MODE_REL,前者是绝对模式,对应于CLOCK_REALTIME时钟
    hrtimer_init(&timer,CLOCK_MONOTONIC,HRTIMER_MODE_REL);
	//启动一个定时器
    hrtimer_start(&timer,kt,HRTIMER_MODE_REL);
    timer.function = hrtimer_hander;//设置定时器回调函数
    return 0;
}
 
static void __exit test_exit(void)
{
	//取消一个定时器,并等待其执行完毕
    hrtimer_cancel(&timer);
    printk("------------test over---------------\r\n");
}
module_init(test_init);
module_exit(test_exit);
MODULE_LICENSE("GPL");

参考文献:
https://kunaly.blog.csdn.net/article/details/99641461
https://blog.csdn.net/lhl_blog/article/details/106824066

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

东皇※太一

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值