Linux驱动中断与时间篇——低分辨率定时器

文章目录

内核延时函数接口


延时的函数有delay和sleep两种类型:

delay接口

c 复制代码
void ndelay(unsigned long nsecs);//纳秒延时
void udelay(unsigned long usecs);//微妙延时
void mdelay(unsigned long msecs);//毫秒延时

sleep接口

c 复制代码
void msleep(unsigned int msecs);//毫秒级延时
long msleep_interruptible(unsigned int msecs);//毫秒级延时,可被信号打断
void ssleep(unsigned int seconds);//秒级延时

delay和sleep的区别

delay型延时:忙等待,占用CPU资源,延迟过程无法进行其他任务。

sleep型延时:休眠,不占用CPU资源,其它模块此时可以使用CPU资源。

低分辨率定时器


jiffies和HZ

jiffies:全局变量,表示系统启动以来产生的节拍数 。每产生一次中断,jiffies自动加一。

HZ:赫兹,也叫节拍率 ,表示每秒种产生多少次中断。

例如:HZ为200,代表每秒产生200次中断,那2秒钟jiffies的值就应该是400。因此系统的运行时间可以用jiffies/HZ表示。

一秒钟:jiffies + HZ表示一秒钟

原因:内核中统计时间是通过jiffies,因此要比较时间或者定时也是通过jiffies。

例如程序运行一秒钟,内核如何知道运行了一秒?答案是运行一秒后的jiffies值和运行前的jiffies值进行比较,如果相差为一个HZ,则代表一秒钟。jiffies+HZ其实就是一秒后jiffies的值,所以jiffies+HZ可以间接表示一秒钟。

定时2秒:jiffies + 2*HZ。以此类推

获取当前的jiffies值,可以用get_jiffies_64()函数。

将时间转为对应的jiffies值,可以用msecs_to_jiffies()等函数,例如msecs_to_jiffies(1000)代表1秒,函数返回值其实就是HZ。

相关接口

c 复制代码
#include<linux/timer.h>

struct timer_list { 
    struct list_head list;  
    unsigned long expires; 	//定时器到期时间,传入的是jiffies值
    unsigned long data; 	//作为参数被传入定时器处理函数
    void (*function)(unsigned long);
};
c 复制代码
void init_timer(struct timer_list * timer);//初始化定时器
void add_timer(struct timer_list * timer);//添加一个定时器
int mod_timer(struct timer_list *timer, unsigned long expires);//修改定时器的定时时间expires
int del_timer(struct timer_list * timer);//删除定时器
c 复制代码
unsigned int jiffies_to_msecs (const unsigned long j);//将jiffies转为对应的毫秒值
unsigned int jiffies_to_usecs (const unsigned long j);//将jiffies转为对应的微秒值
unsigned long msecs_to_jiffies (const unsigned int m);//将毫秒值转为对应的jiffies
unsigned long usecs_to_jiffies (const unsigned int u);//将微秒值转为对应的jiffies

定时器使用示例

使用步骤:

1、调用init_timer初始化一个定时器,给struct timer_list各成员赋值。

2、调用add_timer将定时器添加到内核定时器链表,时间到后回调函数自动调用,用mod_timer修改expires的值可实现循环定时。

3、不需要定时器时,调用del_timer删除。

单次定时

加载驱动一秒钟后,打印出"timer handler, data:520":

c 复制代码
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>

#include <linux/sched.h>//jiffies在此头文件中定义
#include <linux/timer.h>//struct timer_list

struct timer_list timer;

static void timer_handler (unsigned long arg)
{
	printk("timer handler, data:%d\n", arg);
}

static int __init my_init(void)
{
	printk("%s enter\n", __func__);

	init_timer(&timer);
	timer.expires = get_jiffies_64() + msecs_to_jiffies(1000);//定时1秒
	timer.function = timer_handler;
	timer.data = 520;
	add_timer(&timer);

    return 0;
}

static void __exit my_exit(void)
{
	printk("%s enter\n", __func__);
	del_timer(&timer);
}

module_init(my_init);
module_exit(my_exit);
MODULE_LICENSE("GPL");

循环定时

实现循环定时就是在定时时间到了之后,调用mod_timer函数再次修改定时时间。

每隔一秒钟打印"timer handler, data:520"

c 复制代码
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>

#include <linux/sched.h>//jiffies在此头文件中定义
#include <linux/timer.h>//struct timer_list

struct timer_list timer;

static void timer_handler (unsigned long arg)
{
	printk("timer handler, data:%d\n", arg);

	mod_timer(&timer, get_jiffies_64() + msecs_to_jiffies (1000));
}

static int __init my_init(void)
{
	init_timer(&timer);
	timer.expires = get_jiffies_64() + msecs_to_jiffies (1000);//定时1秒
	timer.function = timer_handler;
	timer.data = 520;
	add_timer(&timer);

    return 0;
}

static void __exit my_exit(void)
{
	del_timer(&timer);
}

module_init(my_init);
module_exit(my_exit);
MODULE_LICENSE("GPL");
相关推荐
2035去旅行11 小时前
bootcmd 详细讲解
linux·嵌入式·arm·soc
陈希12311 小时前
Linux 防火墙配置实战:firewalld、iptables 与云安全组
linux·运维·服务器
女神下凡12 小时前
芯参谋(95):嵌入式文件系统_开发指南
linux·服务器·arm开发·驱动开发·设计规范
且从容.15 小时前
Ubuntu安装flume
linux·ubuntu·flume
承渊政道16 小时前
Linux网络学习【Reactor反应堆模式】
linux·网络·学习·ubuntu·reactor
且从容.19 小时前
ubuntu安装flink
linux·ubuntu·flink
爱和冰阔落20 小时前
【Linux网络】TCP 服务器如何并发处理多个客户端?从 fork、僵尸进程到双重 fork
linux·运维·服务器·网络
程序员沉梦听雨20 小时前
WSL2的安装与使用
linux·wsl
微小的鱼21 小时前
Linux的渲染与显示系统链路
android·java·linux
lisanmengmeng21 小时前
alertmanger 标签 rules 打上分组标签
linux·运维·服务器