迅为嵌入式linux驱动开发笔记(八)—内核定时器

内核定时器

二. Linux 内核定时器基础知识
Linux 内 核 使 用 timer_list 结 构 体 表 示 内 核 定 时 器 ,timer_list 定 义 在 文 件 include/linux/timer.h 中,定义如下:

struct timer_list { 
			struct list_head entry;
			unsigned long expires; /* 定时器超时时间,不是时长,单位是节拍数 */
			struct tvec_base *base;
			void (*function)(unsigned long); /* 定时处理函数 */
			unsigned long data; /* 要传递给 function 函数的参数 */ 
			int slack; 
};

在这个结构体中,有几个参数需要重点关注。 一是 expires 到期时间,单位是节拍数。 等于定时的当前的时钟节拍计数(存储在系统的全局变量 jiffies)+定时时长对应的时钟节拍数量。
那么怎么把时间转换成节拍数量呢?
示例:从现在开始定时 1 秒:内核中有一个宏 HZ, 表示一秒对应的时钟节拍数,那么就可以通过这个宏来把时间转换成节拍数。 所以,定时 1 秒就是:expires = jiffies + 1*HZ 。 HZ 的值是可以设置的,也就是说一秒对应的时钟拍数是可以设置的, Linux 内核会使用CONFIG_HZ 来设置系统时钟 。
打 开 文 件 include/asm generic/param.h , 有如下内容:

# undef HZ 
# define HZ CONFIG_HZ 
# define USER_HZ 100宏 

HZ 就是 CONFIG_HZ,因此 HZ=100,表示一秒的节拍数是 100 , 在编译 Linux 内核的时候可以通过图形化界面设置系统节拍率,按照如下路径打开配置界面。迅为嵌入式linux驱动开发笔记(八)—内核定时器_第1张图片通过上图可以发现可选的系统节拍率为 100Hz 、 200Hz 、 250Hz 、 300Hz 、 500Hz 和 1000Hz 。 默认是 100Hz 。
第二个需要关心的参数是 function 超时处理函数,这个并不是硬件中断服务程序。 原型:void function(unsigned long data);
第三个参数是 data 传递给超时处理函数的参数,可以把一个变量的地址转换成 unsigned long 。

三、Linux 内核定时器相关操作函数

1、时间转换函数
<1>ms 转换为时钟节拍函数

 unsigned long msecs_to_jiffies(const unsigned int m) 

<2>us 转换为时钟节拍函数

 unsigned long usecs_to_jiffies(const unsigned int u) 

举例:
<1> 定时10ms
计算: jiffies +msecs_to_jiffies(10)

<2> 定时10us
计算: jiffies +usecs_to_jiffies(10)

<2> 宏 DEFINE_TIMER
原型: #define DEFINE_TIMER(_name, _function, _expires, _data)
作用:静态定义结构体变量并且初始化初始化 function, expires, data 成员。
参数: _name 变量名;
_function 超时处理函数 ;
_data 传递给超时处理函数的参数 _expires 到点时间,一般在启动定时前需要重新初始化。

<3>add_timer 函数
原型: void add_timer(struct timer_list *timer)
作用: add_timer函数用于向Linux 内核注册定时器,使用 add_timer 函数向内核注册定时器以后,定时器就会开始运行
参数:
timer : 要注册的定时器。

<4>del_timer 函数
原型: int del_timer(struct timer_list * timer)
作用: del_timer 函数用于删除一个定时器,不管定时器有没有被激活,都可以使用此函数删除。 在多处理器系统上,定时器可能会在其他的处理器上运行,因此在调用 del_timer 函数 删除定时器之前要先等待其他处理器的定时处理器函数退出
timer : 要删除的定时器。
返回值: 0 , 定时器还没被激活; 1 , 定时器已经激活。

<5>mod_timer 函数
函数原型: int mod_timer(struct timer_list *timer, unsigned long expires)
作用: mod_timer 函数用于修改定时值,如果定时器还没有激活的话, mod_timer 函数会 激活定时器!
参数:
timer : 要修改超时时间 ( 定时值 ) 的定时器。
expires : 修改后的超时时间。
返回值: 0 , 调用 mod_timer 函数前定时器未被激活; 1 , 调用 mod_timer 函数前定时器已被激活。

实践课

每隔1s,打印一句话。

定时器初始化:

#include 

DEFINE_TIMER(test_timer,timer_function,0,0);

static int hello_init(void)
{
    printk("hello world\n");

    test_timer.expires = jiffies + 1*HZ;
		//jiffies相当于手机的当前时刻!!!
    add_timer(&test_timer);//启动定时器

    return 0;
}

超时处理函数,让超时之后继续加载:

static void timer_function(unsigned long data)
{
    printk("This is timer function\n");
		//重新开启定时器
    mod_timer(&test_timer,jiffies + 1*HZ);
}

按键消抖

#include 

DEFINE_TIMER(test_timer,timer_function,0,0);

static void timer_function(unsigned long data)
{
    //超时时间处理函数
}

中断处理函数:

irq_handler_t test_key(int irq, void *args)//中断处理函数
{
    test_timer.expires = jiffies + msecs_to_jiffies(20) ;
    //jiffies相当于手机的当前时刻!!!
    add_timer(&test_timer);//启动定时器

    return IRQ_HANDLED;
}

你可能感兴趣的:(#,嵌入式驱动linux,Linux操作系统,linux,驱动开发,运维,arm,单片机)