[TOC]
❓ 问题描述:
linux系统中低精度定时器和高精度定时器的区别和使用方法
日志
分析步骤
核心区别
硬件依赖差异
1. 低精度定时器(基于 jiffies)
工作原理:
系统定时器会按固定频率(由内核配置的 HZ 决定,如 100Hz 或 1000Hz)产生 “滴答中断”(Timer Interrupt)。每发生一次中断,jiffies 计数器加 1,低精度定时器通过检查 jiffies 是否达到预设值来触发。
例如:若 HZ=100,则 1 个滴答 = 10ms,定时器的最小精度就是 10ms,无法设置比 10ms 更短的间隔。
2. 高精度定时器(hrtimer)
依赖的硬件:高精度时钟源, ARM 架构的 通用定时器(Generic Timer)。
工作原理:
高精度时钟源支持纳秒级时间戳和可编程中断,内核可直接通过硬件寄存器设置准确的触发时间。当硬件时钟达到预设时间时,会直接触发中断,调用定时器回调函数,无需等待系统滴答中断,因此精度极高。
代码片段
/*
* @Author: your name
* @Date: 2025-09-01 17:25:32
* @LastEditTime: 2025-09-01 17:41:10
* @LastEditors: Please set LastEditors
* @Description: In User Settings Edit
* @FilePath: linux-4.14.143driversgpudrm imer imer.c
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/timer.h>
#include <linux/jiffies.h>
/*
struct timer_list {
struct hlist_node entry;
unsigned long expires;
void (*function)(unsigned long);
unsigned long data;
u32 flags;
#ifdef CONFIG_LOCKDEP
struct lockdep_map lockdep_map;
#endif
};
使用普通定时器的步骤:
1、定义定时器结构体
2、初始化定时器
3、设置定时器回调函数
4、设置定时器触发时间
5、启动定时器
6、删除定时器(可选)
*/
// 普通定时器结构体
static struct timer_list normal_timer;
// 记录上一次触发时间(用于计算实际间隔)
static unsigned long last_jiffies;
// 触发次数计数器
static int trigger_count = 0;
// 定时器回调函数(中断上下文,不能睡眠)
static void normal_timer_handler(struct timer_list *t)
{
unsigned long current_jiffies = jiffies;
unsigned long interval_ms;
// 计算实际触发间隔(转换为毫秒)
interval_ms = jiffies_to_msecs(current_jiffies - last_jiffies);
last_jiffies = current_jiffies;
// 打印信息(包含当前计数和实际间隔)
trigger_count++;
printk(KERN_INFO "[普通定时器 = 0x%p] 第%d次触发,实际间隔: %lu ms (CPU: %d)
",
t, trigger_count, interval_ms, smp_processor_id());
// 重新设置定时器(100ms后再次触发)
mod_timer(t, jiffies + msecs_to_jiffies(100));
}
// 驱动初始化函数
static int __init normal_timer_init(void)
{
printk(KERN_INFO "普通定时器驱动初始化...
");
// 初始化定时器
timer_setup(&normal_timer, normal_timer_handler, 0);
// 记录初始时间,首次触发延迟100ms
last_jiffies = jiffies;
mod_timer(&normal_timer, jiffies + msecs_to_jiffies(100));
printk(KERN_INFO "普通定时器启动成功(预期间隔100ms,normal_timer = 0x%p)
", &normal_timer);
return 0;
}
// 驱动卸载函数
static void __exit normal_timer_exit(void)
{
// 删除定时器(确保不再触发)
del_timer(&normal_timer);
printk(KERN_INFO "普通定时器驱动卸载,共触发%d次
", trigger_count);
}
// 注册驱动入口和出口
module_init(normal_timer_init);
module_exit(normal_timer_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Normal Timer (jiffies-based) Demo");
MODULE_AUTHOR("Your Name");
/*
* @Author: your name
* @Date: 2025-09-01 17:49:16
* @LastEditTime: 2025-09-01 18:07:28
* @LastEditors: Please set LastEditors
* @Description: In User Settings Edit
* @FilePath: linux-4.14.143driversgpudrm imerhrtimer.c
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/hrtimer.h>
#include <linux/ktime.h>
/*
高精度定时器使用步骤
1. 定义高精度定时器结构体
2. 初始化高精度定时器
3. 绑定回调函数
4. 启动高精度定时器
5. 撤销高精度定时器
static inline ktime_t ktime_set(const long secs, const unsigned long nsecs);
参数详解
第一个参数 secs(const long 类型)
表明时间的秒数部分(可以是正数或 0)。
例如:secs = 1 表明 1 秒。
若只需表明毫秒 / 微秒 / 纳秒级时间(无需整秒),可设为 0。
第二个参数 nsecs(const unsigned long 类型)
表明时间的纳秒数部分(范围:0 ~ 999,999,999)。
1 秒 = 1,000,000,000 纳秒(1e9 纳秒),因此该参数不能超过 999,999,999。
常见单位转换:
1 毫秒(ms)= 1,000,000 纳秒(1e6 ns)
1 微秒(us)= 1,000 纳秒(1e3 ns)
函数功能
将 “秒数 + 纳秒数” 合并为一个 ktime_t 类型的时间值(内核中用于表明高精度时间的统一格式),用于高精度定时器的触发时间设置、时间差计算等场景。
*/
// 高精度定时器结构体
static struct hrtimer hr_timer;
// 记录上一次触发时间(用于计算实际间隔)
static ktime_t last_ktime;
// 触发次数计数器
static int trigger_count = 0;
// 预期间隔(10ms,即10,000,000纳秒)
#define INTERVAL_NS 1000000000ULL
// 定时器回调函数(返回值决定是否重复触发)
static enum hrtimer_restart hrtimer_handler(struct hrtimer *timer)
{
ktime_t current_ktime;
s64 interval_ns;
// 获取当前时间并计算实际间隔(纳秒)
current_ktime = ktime_get();
interval_ns = ktime_to_ns(ktime_sub(current_ktime, last_ktime));
last_ktime = current_ktime;
// 打印信息(包含当前计数和实际间隔)
trigger_count++;
printk(KERN_INFO "[高精度定时器] 第%d次触发,实际间隔: %lld ns (CPU: %d)
",
trigger_count, interval_ns, smp_processor_id());
// 设置下一次触发时间(绝对时间=当前时间+间隔)
hrtimer_forward(timer, current_ktime, ktime_set(0, INTERVAL_NS));
//或者使用下面额函数进行设置
//hrtimer_forward_now(timer, ktime_set(0, INTERVAL_NS));
// 返回RESTART表明重复触发
return HRTIMER_RESTART;
}
// 驱动初始化函数
static int __init hrtimerinit(void)
{
printk(KERN_INFO "高精度定时器驱动初始化...
");
// 初始化高精度定时器(模式:相对时间,CLOCK_MONOTONIC时钟)
hrtimer_init(&hr_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
// 绑定回调函数
hr_timer.function = hrtimer_handler;
// 记录初始时间,首次触发延迟10ms
last_ktime = ktime_get();
hrtimer_start(&hr_timer, ktime_set(0, INTERVAL_NS), HRTIMER_MODE_REL);
printk(KERN_INFO "高精度定时器启动成功(预期间隔10,000,000 ns)
");
return 0;
}
// 驱动卸载函数
static void __exit hrtimerexit(void)
{
// 撤销定时器(等待当前回调执行完毕)
hrtimer_cancel(&hr_timer);
printk(KERN_INFO "高精度定时器驱动卸载,共触发%d次
", trigger_count);
}
// 注册驱动入口和出口
module_init(hrtimerinit);
module_exit(hrtimerexit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("High-Resolution Timer (hrtimer) Demo");
MODULE_AUTHOR("Your Name");
图片
✅ 结论
输出结论
待查资料问题
- ❓ 问题 1:?
- ❓ 问题 2:?
参考链接
- Linux驱动中断与时间篇——高精度定时器hrtimer
© 版权声明
文章版权归作者所有,未经允许请勿转载。如内容涉嫌侵权,请在本页底部进入<联系我们>进行举报投诉!
THE END
暂无评论内容