q2113435929的个人空间 https://www.eechina.com/space-uid-126185.html [收藏] [复制] [RSS]

博客

Linux内核定时器的使用

已有 1364 次阅读2015-10-16 14:21 | 4412, 开发板, Linux

Linux内核定时器的使用

linux内核中定时器的使用,定时器是很重要的内容,在调试TP或者其他许多程序时都涉及到定时器的使用,因此掌握定时器的运用是必备的。

下面将介绍定时器驱动的常用函数。对于具体的驱动后面的文档会以蜂鸣器驱动为例,并介绍框架层及应用怎样去控制蜂鸣器。

1.linux系统时间频率定义

系统定时器的时钟频率HZ 定义在 arch/arm/include/asm/param.h

#define  Hz  100  //ARM构架基本都是100

2.节拍总数(jiffies)

 全局变量jiffies用来记录自系统启动以来产生的节拍总数,根据这个节拍总数可以获得系统自启动以来的时间,linux系统启动时,会将jiffies初始化为0,

3.访问jiffies变量

 jiffies总是无符号长整数,该变量定义在linux/jiffies.h文件中

内核定时器

使用内核定时器的步骤

1. 定义内核定时器结构体变量

 内核定时器需要一个timer_list结构体(#include<linux/timer.h>),该结构体指定的内核定时器处理函数等

struct timer_list {

 struct list_head entry;      //定时器链表入口

 unsigned long expires;   //以jifffies为单位的定时值(过期时间)

 struct tvec_base *base;   // 定时器内部值,用户不要使用

 void (*function)(unsigned long);     // 定时器处理函数

 unsigned long data;                          //传给处理函数的长整形参数值

 int slack;                                             //与expires组合成新的expires,在第二部会初始化这个变量

#ifdef CONFIG_TIMER_STATS

 int start_pid;

 void *start_site;

 char start_comm[16];

#endif

#ifdef CONFIG_LOCKDEP

 struct lockdep_map lockdep_map;

#endif

};

2.初始化内核定时器(实际初始化timer_list 结构体)

初始化内核定时器需要使用init_timer宏(#include<linux/timer.h>),该宏原型如下:

#define init_timer(timer)       init_timer_key((timer), NULL, NULL) 

 其中timer就是timer_list的指针,init_timer主要调用了init_timer_key函数

void init_timer_key(struct timer_list *timer,  const char *name, struct lock_class_key *key) 

{

 debug_init(timer);

 __init_timer(timer, name, key);

}

static void __init_timer(struct timer_list *timer,

    const char *name,

    struct lock_class_key *key)

{

 timer->entry.next = NULL;

 timer->base = __raw_get_cpu_var(tvec_bases);

 timer->slack = -1;

#ifdef CONFIG_TIMER_STATS

 timer->start_site = NULL;

 timer->start_pid = -1;

 memset(timer->start_comm, 0, TASK_COMM_LEN);

#endif

 lockdep_init_map(&timer->lockdep_map, name, key, 0);

}

3.实现定时器处理函数

定时器处理函数原型如下:

  void  timer_handle(unsigned long arg)   //arg就是  timer_list .data的值

4.对timer_list 成员变量的进一步初始化

初始化function函数和expires的值,到达过期时间expires时执行function函数。

5.激活定时器

  定时器激活才能使用。使用add_timer函数才能激活定时器,add_timer函数原型如下:

void add_timer(struct timer_list *timer)

{

 BUG_ON(timer_pending(timer));

 mod_timer(timer, timer->expires);

}

int mod_timer(struct timer_list *timer, unsigned long expires)

{

 expires = apply_slack(timer, expires);

 /*

  * This is a common optimization triggered by the

  * networking code - if the timer is re-modified

  * to be the same thing then just return:

  */

 if (timer_pending(timer) && timer->expires == expires)

  return 1;

 return __mod_timer(timer, expires, false, TIMER_NOT_PINNED);

}

6.停止定时器

如果要在定时器到期之前停止定时器,可以使用如下函数:

int del_timer(struct timer_list *timer)

int del_timer_sync(struct timer_list *timer)

无论定时器是否被激活都可以使用这两个函数,未被激活是函数返回0,否则返回1,多处理器都在用定时器时使用此函数del_timer_sync

停止定时器。但此函数不能用在中断上下文中,(因为该函数可能引起阻塞)。

内核延迟

1.忙等待

 使用方法

  unsigned long  delay=jiffies + 5 * Hz;

  ............................................

  while(time_before(jiffies,delay))

   cond_resched();

2.短延迟

 linux/delay.h

ndelay(unsigned long x);  //延迟x纳秒

udelay(unsigned long x);  //延迟x微秒

mdelay(unsigned long x);  //延迟x毫秒

以上几个宏的实现原理是忙等待,会占用大量CPU资源,所以用下面的函数延时较好

msleep(unsigned int msecs)  //延迟msecs毫秒

msleep_interruptible(unsigned int msecs)  //延迟msecs毫秒,,可被中断打断

ssleep(unsigned int seconds)          //延迟seconds秒


路过

鸡蛋

鲜花

握手

雷人

评论 (0 个评论)

facelist

您需要登录后才可以评论 登录 | 立即注册

关于我们  -  服务条款  -  使用指南  -  站点地图  -  友情链接  -  联系我们
电子工程网 © 版权所有   京ICP备16069177号 | 京公网安备11010502021702
返回顶部