Linux內(nèi)核定時器
在Linux內(nèi)核中,也可以通過定時器來完成定時功能。但和單片機不同的是,Linux內(nèi)核定時器是一種基于未來時間點的計時方式,它以當(dāng)前時刻為啟動的時間點,以未來的某一時刻為終止點,類似于我們的鬧鐘。
當(dāng)內(nèi)核定時器定時時間到達(dá)時,會進(jìn)入用戶指定的函數(shù),相當(dāng)于軟中斷。內(nèi)核定時器完成注冊啟動后,僅執(zhí)行一次后就不會重復(fù)執(zhí)行(即超時候會自動關(guān)閉),若需要重復(fù)執(zhí)行則需要手動再次啟動(即修改超時時間)。
Linux內(nèi)核定時器相關(guān)函數(shù)位置:include/linux/timer.h
1.相關(guān)結(jié)構(gòu)體
??在使用內(nèi)核定時器時,我們需要關(guān)心的相關(guān)結(jié)構(gòu)體及其成員:
struct timer_list {
struct list_head entry;
unsigned long expires; /* 定時器時鐘節(jié)拍*/
struct tvec_base *base;
void (*function)(unsigned long); /*定時器工作函數(shù) */
unsigned long data; /*傳給定時器工作函數(shù)的參數(shù) */
};
?在Linux內(nèi)核中,有一個全局變量jiffies用來記錄時鐘節(jié)拍,每當(dāng)時鐘中斷觸發(fā)一次,jiffies就會+1。因此jiffies變量記錄了系統(tǒng)從啟動開始時鐘中斷觸發(fā)的次數(shù)。我們由此可以利用jiffies來計算驅(qū)動程序運行時長。jiffies每秒增加HZ次,因此jiffies+1的時長有HZ決定。當(dāng)HZ=100時,jiffies+1的時長則為10ms。在Linux3.5的內(nèi)核中HZ值默認(rèn)為200,即jiffies+1的時長則為5ms。
2.相關(guān)函數(shù)
2.1 定時器初始化init_timer()
#define init_timer(timer)
函數(shù)功能: 初始化定時
形參: 定時器結(jié)構(gòu)體
2.2 啟動定時器add_timer()
void add_timer(struct timer_list *timer)
函數(shù)功能: 啟動定時器
形參: 定時器結(jié)構(gòu)體
2.3 修改定時時間mod_timer()
int mod_timer(struct timer_list *timer, unsigned long expires)
函數(shù)功能: 修改定時器時間
形參: timer – 定時器結(jié)構(gòu)體
???expires --定時時間( 以時鐘節(jié)拍填入)
??注意:expires 填寫是基于jiffies+延時時間
2.4毫秒轉(zhuǎn)為時鐘節(jié)拍 msecs_to_jiffies()
unsigned long msecs_to_jiffies(const unsigned int m)
函數(shù)功能: 將毫秒時間轉(zhuǎn)換為時鐘節(jié)拍數(shù)
形參: m – 毫秒時間
返回值: – 返回節(jié)拍數(shù)
2.5微秒轉(zhuǎn)為時鐘節(jié)拍 usecs_to_jiffies()
unsigned long usecs_to_jiffies(const unsigned int u)
函數(shù)功能: 將微秒時間轉(zhuǎn)換為時鐘節(jié)拍數(shù)
形參: m – 位秒時間
返回值: – 返回節(jié)拍數(shù)
2.6關(guān)閉定時器
int del_timer(struct timer_list *timer)
函數(shù)功能:關(guān)閉定時器(停用一個定時器)
define del_timer_sync(t)
函數(shù)功能:關(guān)閉定時器(停用一個定時器),多處理器使用。如果編內(nèi)核時不支持 SMP(多處理器), del_timer_sync()和 del_timer()等價
2.7 獲取jiffies時間
#include
u64 get_jiffies_64(void)
函數(shù)功能: 獲取jiffies時間
返回值: 返回時鐘節(jié)拍jiffies
2.8 獲取內(nèi)核高精度時間
ktime_t ktime_get(void)
函數(shù)功能: 獲取內(nèi)核高精度時間
返回值: ktime_t – 共用體類型
union ktime {
s64 tv64;
#if BITS_PER_LONG != 64 && !defined(CONFIG_KTIME_SCALAR)
struct
{
# ifdef __BIG_ENDIAN
s32 sec, nsec;
# else
s32 nsec, sec;
# endif
} tv;
#endif
};
2.9 時間轉(zhuǎn)換函數(shù)
s64 ktime_to_ms(const ktime_t kt) /* 將獲取的系統(tǒng)時鐘轉(zhuǎn)換為ms單位*/
s64 ktime_to_us(const ktime_t kt) /* 將獲取的系統(tǒng)時鐘轉(zhuǎn)換為us單位*/
/將獲取的時間轉(zhuǎn)換為時鐘結(jié)構(gòu)體/
struct timeval ktime_to_timeval(const ktime_t kt)
struct timespec ktime_to_timespec(const ktime_t kt)
3.內(nèi)核定時器示例
??內(nèi)核定時器使用步驟:
- 初始化內(nèi)核定時器init_timer,設(shè)置超時時間,編寫內(nèi)核定時工作函數(shù);
- 啟動定時器add_timer;
- 若需要重復(fù)定時,則需要在定時器工作函數(shù)中修改超時時間mod_timer
#include
#include
#include
#include
#include
struct timer_list timer;
/*定時器工作函數(shù)*/
void timer_work(unsigned long data)
{
ktime_t time1;
printk("定時器時間到!data=%ld,",data);
time1=ktime_get();
printk("定時時間:%llu \n",ktime_to_ms(time1));
mod_timer(&timer,jiffies+msecs_to_jiffies(2000));/*修改定時時間*/
}
static int __init wbyq_timer_init(void)
{
timer.expires=jiffies+msecs_to_jiffies(1000);/*定時時間*/
timer.function=timer_work;/*定時器工作函數(shù)*/
timer.data=666;/*傳給定時器工作函數(shù)參數(shù),選填*/
init_timer(&timer);/*初始化定時器*/
add_timer(&timer);/*啟動定時器*/
return 0;
}
/*驅(qū)動釋放*/
static void __exit wbyq_timer_cleanup(void)
{
del_timer_sync(&timer);//關(guān)閉定時器
printk("驅(qū)動出口,驅(qū)動注銷成功\n");
}
module_init(wbyq_timer_init);//驅(qū)動入口函數(shù)
module_exit(wbyq_timer_cleanup);//驅(qū)動出口函數(shù)
MODULE_LICENSE("GPL");//驅(qū)動注冊協(xié)議
MODULE_AUTHOR("it_ashui");
MODULE_DESCRIPTION("Exynos4 timer Driver");
審核編輯:湯梓紅
-
內(nèi)核
+關(guān)注
關(guān)注
3文章
1372瀏覽量
40275 -
Linux
+關(guān)注
關(guān)注
87文章
11292瀏覽量
209318 -
定時器
+關(guān)注
關(guān)注
23文章
3246瀏覽量
114714
發(fā)布評論請先 登錄
相關(guān)推薦
評論