硬件定时器提供时钟源,时钟源的频率可以设置,设置好后便周期性的产生定时中断,系统使用定时中断来计时,中断周期性产生的频率就是系统频率,也叫节拍率,1000Hz,100Hz等等,可以在编译Linux内核的时候通过图形化界面设置系统节拍率
->Kernel Features ->Timer freqency([=y])
设置好后再内核源码根目录下.config文件有COINFIG_HZ的定义,默认100Hz,10ms一次,一次中断发生的最短为10ms,比如Mpu6050的dmp5ms硬件中断不可
jiffies
Linux内核使用jiffies来记录系统从启动一来的系统节拍数,系统启动的时候将jiffies初始化为0,jiffies在include/linux/jiffies.h中
extern u64 __jiffy_data jiffies_64;extern unsigned long volatile __jiffy_data jiffies;
jiffies_64与jiffies是同一个东西,jiffies_64用于64位系统,jiffies用于32位系统,jiffies就是jiffies_64的低32位
Hz表示每秒的节拍数,jiffies表示运行jiffies节拍数,所以jiffies/Hz就是系统运行恶的时间,单位为秒(S)。jiffies和jiffies_64都有溢出的风险,叫做绕回
timer_after(unknow,known);time_before(unknow,known);time_after_eq(unknow,known);time_before_eq(unknow,known);//unknow为当前的jiffies的值//known为需要对比的值//unkown 超过 known 的话, time_after 函数返回真//如果 unkown 没有超过 known 的话 time_before 函数返回真,否则返回假//time_after_eq 函数和 time_after 函数类似,只是多了判断等于这个条件。同理, time_before_eq 函数和 time_before 函数也类似
unsigned long timeout;timeout=jiffies+(2*HZ);//超时的时间点,if(timer_before(jiffies,timeout))//判断代码执行时间是不是超过了2秒{ /*超时未发生*/}else{ /*超时处理*/}
jiffies和ms、us、ns之间的转换函数
int jiffies_to_msecs(const unsigned long j);int jiffies_to_usecs(const unsigned long j);u64 jiffies_to_nsecs(const unsigned long j);long msecs_to_jiffies(const unsigned int m);long usecs_to_jiffies(const unsigned int u);unsigned long nsecs_to_jiffies(u64 n);
内核定时器
使用timer_list结构体表示内核定时器
struct tiemr_list{ struct list_head entry; unsigned long expires; //定时超时时间,单位节拍数 struct tvec_base *base; void (*function)(unsigned long);//定时处理函数 unsigned long data;//传递给function函数的参数 int slack;};//超时两秒 expires=jiffies+(2*HZ)
定时器api函数
void init_timer(struct timer_list *timer);//timer 初始化定时器//返回值,无
void add_timer(struct timer_list *timer);//timer 要注册的定时器//返回值 无//使用add_timer函数向内核注册定时器后,定时器就会开始运行
int del_timer(struct timer_list *timer);//tiemr 要删除的定时器//返回值 0,定时器还没被激活 1,定时器已经被激活//在多处理器系统上,定时器可能会在其他的处理器上运行,因此在调用del_timer 函数删除定时器之前要先等待其他处理器的定时处理器函数退出
int del_timer_sync(struct timer_list *timer);//timer 要删除的定时器//返回值 0,定时器还没被激活,1,定时器已经被激活//del_timer_sync 函数是 del_timer 函数的同步版,会等待其他处理器使用完定时器再删除,del_timer_sync 不能使用在中断上下文中
int mod_timer(struct timer_list *timer,unsigned long expires);//用于修改定时值,如果定时器还没有被激活,mod_timer会激活定时器//tiemr 要修改超时时间(定时值)的定时器//expires修改后的超时时间//返回值 0,调用mod_timer函数前定时器未被激活;1,调用mod_timer函数前定时器已被激活
定时器使用一般流程
struct timer_list timer;void function(unsigned long arg){ /*定时器处理函数*/ //如果要周期性的运行 mod_timer(&dev-timertest,jiffies+msecs_to_jiffies(2000)); //2ms周期}//初始化void init(void){ init_timer(&timer); timer.function=function, timer.expires=jiffies+msecs_to_jiffies(2000), timer.data=(unsigned long)&dev;//将设备结构体作为参数 add_timer(&timer);//启动定时器}void exit(void){ del_timer(&timer); //or del_timer_sync(&timer);}
Linux内核短延时函数
void ndelay(unsigned long nsecs);void udelay(unsigned long usecs);void mdelay(unsigned long mseces)