linux驱动之内核定时器

本文详细介绍了Linux内核定时器的使用,包括setup_timer、add_timer、mod_timer、del_timer和del_timer_sync等关键函数。讲解了定时器时间单位、jiffies全局变量及其相关比较宏,并给出了实例代码展示如何设置和管理定时器。同时,提到了内核短延迟函数如ndelay、udelay和mdelay。
摘要由CSDN通过智能技术生成

linux内核定时器如何使用?

内核定时器不是周期性的, 一次定时时间到了以后就会关闭, 除非重新打开

关键函数
头文件 include\linux\timer.h

定时器结构体:

struct timer_list {
	/*
	 * All fields that change during normal runtime grouped to the
	 * same cacheline
	 */
	struct hlist_node	entry;
	unsigned long		expires;//超时时间
	void			(*function)(unsigned long);//定时器超时函数
	unsigned long		data;//传入超时函数的参数
	u32			flags;

#ifdef CONFIG_TIMER_STATS
	int			start_pid;
	void			*start_site;
	char			start_comm[16];
#endif
#ifdef CONFIG_LOCKDEP
	struct lockdep_map	lockdep_map;
#endif
};

在这里插入图片描述
通过宏 from_timer 可以获取包含定时器结构体的首地址

①setup_timer(timer, fn, data);
设置定时器,主要是初始化timer_list结构体,设置其中的函数、参数。
*② void add_timer(struct timer_list timer):
向内核添加定时器。timer->expires表示超时时间。
当超时时间到达,内核就会调用这个函数:timer->function(timer->data)。
*③ int mod_timer(struct timer_list timer, unsigned long expires):
修改定时器的超时时间,
它等同于:del_timer(timer); timer->expires = expires; add_timer(timer);
但是更加高效。
*④ int del_timer(struct timer_list timer):
删除定时器。
**⑤int del_timer_sync(struct timer_list *timer) **
del_timer_sync函数是 del_timer函数的同步版,会等待其他处理器使用完定时器再删除,
del_timer_sync不能使用在中断上下文中。

int del_timer_sync(struct timer_list *timer) 

定时器时间单位

编译内核时,可以在内核源码根目录下用“ls -a”看到一个隐藏文件 .config, 打开后可以看到如下这项:
CONFIG_HZ=100
这表示内核每秒中会发生100次系统滴答中断
每发生一次tick中断,全局变量jiffies就会累加1。
这个在内核配置是可以修改的
menuconfig的

-> Kernel Features                                                                                                            
   -> Timer frequency (<choice> [=y])  

全局变量 jiffies
既然是变量那么就有溢出的风险, 内核提供了宏来避免溢出造成的错误
time_after(unkown, known) unkown > known?
time_before(unkown, known) unkown < known?
time_after_eq(unkown, known) unkown >= known?
time_before_eq(unkown, known) unkown <= known?

unkown通常为 jiffies,known通常是需要对比的值。

Linux内核提供了几个 jiffies和 ms、us、ns之间的转换函数

//将 jiffies类型的参数 j分别转换为对应的毫秒、微秒、纳秒。
int jiffies_to_msecs(const unsigned long j)  
int jiffies_to_usecs(const unsigned long j) 
u64 jiffies_to_nsecs(const unsigned long j) 

// 将毫秒、微秒、纳秒转换为 jiffies类型。 
long msecs_to_jiffies(const unsigned int m) 
long usecs_to_jiffies(const unsigned int u) 
unsigned long nsecs_to_jiffies(u64 n)
  unsigned long timeout; 
  timeout = jiffies + (2 * HZ);    /* 超时的时间点 */ 
   
  /************************************* 
    具体的代码 
   ************************************/ 
    
  /* 判断有没有超时 */ 
  if(time_before(jiffies, timeout)) { 
   /* 超时未发生 */ 
 } else { 
   /* 超时发生 */ 
 } 

定时器的时间就是基于jiffies的,我们修改超时时间时,一般使用这2种方法:
① 在add_timer之前,直接修改:
timer.expires = jiffies + xxx; // xxx表示多少个滴答后超时,也就是xxx10ms
timer.expires = jiffies + 2
HZ; // HZ等于CONFIG_HZ,2HZ就相当于2秒
**!宏 HZ 表示一秒的节拍数, 即频率 **
② 在add_timer之后,使用mod_timer修改:
mod_timer(&timer, jiffies + xxx); // xxx表示多少个滴答后超时,也就是xxx
10ms
mod_timer(&timer, jiffies + 2HZ); // HZ等于CONFIG_HZ,2HZ就相当于2秒

编码
核心代码:

定时器超时函数申明:

static void key_timer_expire(unsigned long data)
{
	/* data ==> gpio */
	struct gpio_dev *dev = data;//地址强转
}

初始化定时器:


struct gpio_dev{
	int gpio;
	......
	struct timer_list key_timer;//声明一个定时器
} ;
static struct gpio_dev dev;

//初始化定时器
setup_timer(&dev.key_timer, key_timer_expire, &dev);

向内核添加定时器:

注意: 这里add_timer添加之后 如果超时时间是0, 那么超时函数会被马上调用, 所以在刚开始时,要先设成最大值
dev.key_timer.expires = ~0; //~0 变成最大值
add_timer(&gpio_keys_100ask[i].key_timer);

设置定时器超时时间:
如果定时器还没有激活的话,mod_timer函数会激活定时

//HZ表示1000毫秒, HZ/50表示20毫秒
mod_timer(&dev->key_timer, jiffies + HZ/50);//也可以使用宏jffies + msecs_to_jiffies(20);

内核短延迟函数

 纳秒、微秒和毫秒延时函数。
void ndelay(unsigned long nsecs) 
 void udelay(unsigned long usecs) 
void mdelay(unsigned long mseces)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值