- 配置内核系统节拍率
- 图形化界面配置 -> Kernel Features
->Timer frequencey (<choise> [=y]) - in .config 文件
CONFIG_HZ_100=y
CONFIG_HZ=100 - in include/asm-generic/param.h
#define HZ CONFIG_HZ - 高节拍和低节拍的优缺点:
①、高节拍率会提高系统时间精度,如果采用 100Hz 的节拍率,时间精度就是 10ms,采用
1000Hz 的话时间精度就是 1ms,精度提高了 10 倍。高精度时钟的好处有很多,对于那些对时
间要求严格的函数来说,能够以更高的精度运行,时间测量也更加准确。
②、高节拍率会导致中断的产生更加频繁,频繁的中断会加剧系统的负担,1000Hz 和 100Hz
的系统节拍率相比,系统要花费 10 倍的“精力”去处理中断。中断服务函数占用处理器的时间
增加,但是现在的处理器性能都很强大,所以采用 1000Hz 的系统节拍率并不会增加太大的负
载压力。根据自己的实际情况,选择合适的系统节拍率,本教程我们全部采用默认的 100Hz 系
统节拍率。
- jiffies
Linux 内核使用全局变量 jiffies 来记录系统从启动以来的系统节拍数,系统启动的时候会
将 jiffies 初始化为 0,jiffies 定义在文件 include/linux/jiffies.h 中,定义如下:
示例代码 50.1.1.2 include/jiffies.h 文件
jiffies_64 和 jiffies 其实是同一个东西,jiffies_64 用于 64 位系统,而 jiffies 用于 32 位系统。
为了兼容不同的硬件,jiffies 其实就是 jiffies_64 的低 32 位#include "include/linux/jiffies.h" extern u64 __jiffy_data jiffies_64; extern unsigned long volatile __jiffy_data jiffies; /*unkown通常为jiffies,known通常是需要对比的值*/ time_after(unkown, known) time_before(unkown, known) time_after_eq(unkown, known) time_before_eq(unkown, 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)
- 内核短延时函数
/*纳秒,微秒和毫秒延时函数*/ void ndelay(unsigned long nsecs) void udelay(unsigned long usecs) void mdelay(unsigned long mseces)
- 内核定时器
定时器是一个很常用的功能,需要周期性处理的工作都要用到定时器。Linux 内核定时器
采用系统时钟来实现,并不是我们在裸机篇中讲解的 PIT 等硬件定时器。Linux 内核定时器使
用很简单,只需要提供超时时间(相当于定时值)和定时处理函数即可,当超时时间到了以后设
置的定时处理函数就会执行,和我们使用硬件定时器的套路一样,只是使用内核定时器不需要
做一大堆的寄存器初始化工作。
在使用内核定时器的时候要注意一点,内核定时器并不是周期
性运行的,超时以后就会自动关闭,因此如果想要实现周期性定时,那么就需要在定时处理函
数中重新开启定时器。#include "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; }; void init_timer(struct timer_list *timer) /*向 Linux 内核注册定时器,使用 add_timer 函数向内核注册定时器以后, 定时器就会开始运行 */ void add_timer(struct timer_list *timer) /*删除一个定时器,不管定时器有没有被激活,都可以使用此函数删除。 在多处理器系统上,定时器可能会在其他的处理器上运行,因此在调用 del_timer 函数删除定时 器之前要先等待其他处理器的定时处理器函数退出 返回值:0,定时器还没被激活;1,定时器已经激活。 */ int del_timer(struct timer_list *timer) /*del_timer 函数的同步版,会等待其他处理器使用完定时器再删除, 返回值:0,定时器还没被激活;1,定时器已经激活 del_timer_sync 不能使用在中断上下文中 */ int del_timer_sync(struct timer_list *timer) /*用于修改定时值,如果定时器还没有激活的话,mod_timer 函数会激活定时 器 expires:修改后的超时时间 返回值:0,调用 mod_timer 函数前定时器未被激活;1,调用 mod_timer 函数前定时器已 被激活 */ int mod_timer(struct timer_list *timer, unsigned long expires)