国产精品久久久aaaa,日日干夜夜操天天插,亚洲乱熟女香蕉一区二区三区少妇,99精品国产高清一区二区三区,国产成人精品一区二区色戒,久久久国产精品成人免费,亚洲精品毛片久久久久,99久久婷婷国产综合精品电影,国产一区二区三区任你鲁

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

Linux驅動開發-內核定時器

DS小龍哥-嵌入式技術 ? 2022-09-17 15:06 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

【摘要】 內核定時器是內核用來控制在未來某個時間點(基于jiffies(節拍總數))調度執行某個函數的一種機制,相關函數位于 和 kernel/timer.c 文件中。 當內核定時器定時時間到達時,會進入用戶指定的函數,相當于軟中斷。內核定時器注冊開啟后,運行一次就不會再運行(相當于自動注銷),我們可以重新設置定時器的超時時間,讓定時器重復運行。

1. 內核定時器介紹

內核定時器是內核用來控制在未來某個時間點(基于jiffies(節拍總數))調度執行某個函數的一種機制,相關函數位于 和 kernel/timer.c 文件中。

當內核定時器定時時間到達時,會進入用戶指定的函數,相當于軟中斷。內核定時器注冊開啟后,運行一次就不會再運行(相當于自動注銷),我們可以重新設置定時器的超時時間,讓定時器重復運行。

每當時鐘中斷發生時,全局變量jiffies(一個32位的unsigned long 變量)就加1,因此jiffies記錄了linux系統啟動后時鐘中斷發生的次數,驅動程序常利用jiffies來計算不同事件間的時間間隔。內核每秒鐘將jiffies變量增加HZ次。因此,對于HZ值為100的系統,jiffy+1等于隔了10ms,而對于HZ為1000的系統,jiffy+1僅為1ms。

內核定時器結構體:
下面列出了需要關心的成員

struct timer_list {
	unsigned long expires;         //設置超時時間,用jiffies作為基準值
	void (*function)(unsigned long); //類似中斷服務函數,設置定時器到時后處理的函數 
	unsigned long data;           //中斷服務函數的參數
}

expires設置:以當前時間為基準加上延時時間,時間基準用jiffies變量表示,延時時間可以使用以下兩個宏轉換成jiffies單位。

2. 內核定時器相關API函數

2.1 修改定時器超時時間

函數原型 *int mod_timer(struct timer_list timer, unsigned long expires)
函數功能 修改定時器超時時間
函數參數 timer:對應的定時器結構體 expires:超時時間
函數返回值 成功返回 :修改成功的時間值
函數定義文件 \linux-3.5\kernel\timer.c

2.2 初始化定時器

函數原型 #define init_timer(timer)\
函數功能 初始化定時器結構
函數參數 timer:對應的定時器結構體
函數定義文件 \linux-3.5\include\linux\timer.h

2.3 關閉定時器

函數原型 int del_timer(struct timer_list *timer)
函數功能 關閉定時器,停用一個定時器。
函數參數 timer:對應的定 時器結構體
函數返回值 返回0:成功
函數定義文件 \linux-3.5\include\linux\timer.h

2.4 關閉定時器

函數原型 int del_timer_sync(struct timer_list *timer)
函數功能 關閉定時器,停用一個定時器,多處理器使用。如果編內核時不支持 SMP(多處理器), del_timer_sync()和 del_timer()等價
函數參數 timer:對應的定時器結構體
函數返回值 返回0:成功
函數定義文件 \linux-3.5\include\linux\timer.h

2.5 轉換時間(微妙單位)

函數原型 unsigned long usecs_to_jiffies(const unsigned int m)
函數功能 轉換時間(微妙單位),用于填充定時器結構體,設置超時時間
函數參數 m:要轉換的時間值(微妙為單位)
函數返回值 成功返回轉換成功的時間。用于填充定時器結構體,設置超時時間
函數定義文件 \linux-3.5\kernel\timer.c

2.6 轉換時間(毫秒為單位)

函數原型 unsigned long msecs_to_jiffies(const unsigned int m)
函數功能 轉換時間(毫秒為單位),用于填充定時器結構體,設置超時時間
函數參數 m:要轉換的時間值(毫秒為單位)
函數返回值 成功返回轉換成功的時間。用于填充定時器結構體,設置超時時間
函數定義文件 \linux-3.5\kernel\timer.c

將jiffies單位轉為struct timespec結構體表示:

Void jiffies_to_timespec(const unsigned long jiffies, struct timespec *value);

示例:
jiffies_to_timespec(jiffies,&value);
printk("value.ts_sec=%d\n",value.tv_sec);
printk("value.tv_nsec=%d\n",value.tv_nsec);

2.7 初始化定時器的結構體成員

TIMER_INITIALIZER( _function, _expires, _data) 宏用于賦值定時器結構體的function、 expires、 data 和 base 成員, 這個宏的定義如下所示:(被DEFINE_TIMER宏調用)

#define TIMER_INITIALIZER(_function, _expires, _data) {		\
		.entry = { .prev = TIMER_ENTRY_STATIC },	\
		.function = (_function),			\
		.expires = (_expires),				\
		.data = (_data),				\
		.base = &boot_tvec_bases,			\
		.slack = -1,					\
		__TIMER_LOCKDEP_MAP_INITIALIZER(		\
			__FILE__ ":" __stringify(__LINE__))	\
	}

2.8 初始化定時器并且賦值

DEFINE_TIMER( _na me , _functi o n, _e x pires, _data) 宏是定義并初始化定時器成員的“快捷方式”, 這個宏定義如下所示:

/*初始化定時器,并進行賦值*/
#define DEFINE_TIMER(_name, _function, _expires, _data)		\
	struct timer_list _name =				\
		TIMER_INITIALIZER(_function, _expires, _data)

2.9 定時器初始化賦值

setup_timer()也可用于初始化定時器并賦值其成員, 其源代碼如下:

//初始化定時器并進行賦值
#define setup_timer(timer, fn, data)					\
	do {								\
		static struct lock_class_key __key;			\
		setup_timer_key((timer), #timer, &__key, (fn), (data));\
	} while (0)

static inline void setup_timer_key(struct timer_list * timer,
				const char *name,
				struct lock_class_key *key,
				void (*function)(unsigned long),
				unsigned long data)
{
	timer->function = function;
	timer->data = data;
	init_timer_key(timer, name, key);
}

3. 使用定時器的步驟

(1) 定義定時器結構體timer_list。

/*定義一個內核定時器配置結構體*/
static struct timer_list mytimer ; 

(2) 設置超時時間,定義定時器處理函數和傳參。

mytimer.expires=jiffies+ msecs_to_jiffies(1000); /*設置定時器的超時時間,1000毫秒*/
//或者
//mytimer.expires=jiffies+HZ; /*設置定時器的超時時間,1000毫秒*/

mytimer.function = time_fun;	              /*定時器超時的回調函數,類似中斷服務函數*/
mytimer.data = 12;                       /*傳給定時器服務函數的參數*/

(3) 開啟定時器。

init_timer(&mytimer);          /*初始化定時器*/
add_timer(&mytimer);	        /*啟動定時器*/

完整示例代碼:

#include 
#include 
#include 

static struct timer_list timer;

static void timer_function(unsigned long data)
{
	printk("data=%ld\n",data);
	mod_timer(&timer,msecs_to_jiffies(3000)+jiffies);
}

static int __init tiny4412_linux_timer_init(void)
{
	timer.expires=HZ*3+jiffies; /*單位是節拍*/
	timer.function=timer_function;
	timer.data=666;
	
	/*1. 初始化定時器*/
	init_timer(&timer);
	/*2. 添加定時器到內核*/
	add_timer(&timer);
    printk("驅動測試: 驅動安裝成功\n");
    return 0;
}

static void __exit tiny4412_linux_timer_cleanup(void)
{
	/*3. 刪除定時器*/
	del_timer_sync(&timer);
    printk("驅動測試: 驅動卸載成功\n");
}

module_init(tiny4412_linux_timer_init);    /*驅動入口--安裝驅動的時候執行*/
module_exit(tiny4412_linux_timer_cleanup); /*驅動出口--卸載驅動的時候執行*/

MODULE_LICENSE("GPL");  /*設置模塊的許可證--GPL*/

4. 內核提供的延時函數

Linux 內核中提供了進行納秒、微秒和毫秒延遲。
void ndelay(unsigned long nsecs) ;
void udelay(unsigned long usecs) ;
void mdelay(unsigned long msecs) ;
上述延遲的實現原理本質上是忙等待,根據 CPU 頻率進行一定次數的循環。在內核中,最好不要直接使用mdelay()函數, 這將無謂地耗費CPU資源。
void msleep(unsigned int millisecs) ;
unsigned long msleep_interruptible(unsigned int millisecs) ;
void ssleep(unsigned int seconds) ;
上述函數將使得調用它的進程睡眠參數指定的時間, msleep()、 ssleep()不能被打斷,而 msleep_interruptible()則可以被打斷。

5. 精度較高的時間獲取方式

高精度定時器通常用ktime作為計時單位。
獲取內核高精度時間單位: ktime_t ktime_get(void)

下面是一些時間輔助函數用于計算和轉換:

ktime_t ktime_set(const long secs, const unsigned long nsecs);   
ktime_t ktime_sub(const ktime_t lhs, const ktime_t rhs);   
ktime_t ktime_add(const ktime_t add1, const ktime_t add2);   
ktime_t ktime_add_ns(const ktime_t kt, u64 nsec);   
ktime_t ktime_sub_ns(const ktime_t kt, u64 nsec);   
ktime_t timespec_to_ktime(const struct timespec ts);   
ktime_t timeval_to_ktime(const struct timeval tv);   
struct timespec ktime_to_timespec(const ktime_t kt);   //轉換的時間通過timespec結構體保存
struct timeval ktime_to_timeval(const ktime_t kt);     //轉換的時間通過timeval結構體保存
s64 ktime_to_ns(const ktime_t kt);     //轉換為ns單位
int ktime_equal(const ktime_t cmp1, const ktime_t cmp2);   
s64 ktime_to_us(const ktime_t kt);    //轉換為us單位
s64 ktime_to_ms(const ktime_t kt);    //轉換為ms單位
ktime_t ns_to_ktime(u64 ns);

示例: 計算經過的一段時間

static int hello_init(void)
{
	ktime_t my_time,my_time2;
	unsigned int i,j;
	unsigned int time_cnt=0;
	my_time=ktime_get();    		//獲取當前時間
	i=ktime_to_us(my_time); 		//轉us
	
	udelay(600);  				//延時一段時間
	
	my_time2=ktime_get();  	  	//獲取當前時間
	j=ktime_to_us(my_time2);  		//轉us
	
	printk("time_cnt=%ld\n",j-i); 	//得出之間差值,正確值為: 600
	return 0;
}
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 內核
    +關注

    關注

    4

    文章

    1467

    瀏覽量

    42869
  • 定時器
    +關注

    關注

    23

    文章

    3368

    瀏覽量

    123573
  • 函數
    +關注

    關注

    3

    文章

    4417

    瀏覽量

    67499
收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關推薦
    熱點推薦

    深入解析 LM555 定時器:特性、應用與設計要點

    深入解析 LM555 定時器:特性、應用與設計要點 一、引言 在電子工程師的工具箱中,定時器芯片是常用的基礎元件之一。而 TI 公司的 LM555 定時器,以其高穩定性、多種工作模式和廣泛的應用范圍
    的頭像 發表于 02-10 15:35 ?201次閱讀

    Linux內核的“心跳”:jiffies如何為系統計時?

    Linux 內核的世界里,有一個默默工作的 "計時"——jiffies。它不像我們手機上的時鐘那樣顯示年月日,卻掌控著內核中絕大多數時間相關的操作:從進程調度到設備
    的頭像 發表于 02-04 16:27 ?813次閱讀
    <b class='flag-5'>Linux</b><b class='flag-5'>內核</b>的“心跳”:jiffies如何為系統計時?

    【「Linux 設備驅動開發(第 2 版)」閱讀體驗】Linux內核開發基礎

    感謝電子發燒友論壇提供的《Linux設備驅動開發(第2版)》閱讀機會,測評將從Linux內核開發
    發表于 01-12 22:45

    LAT1173高精度定時器的同步功能應用筆記

    STM32G474 所含的高精度定時器(HRTIMER)其實包含了多個定時器,多個定時器之間可以單獨工作,也可以進行同步,且高精度定時器還能與片上的其他
    發表于 01-11 17:32 ?0次下載

    LMH1218:低功耗超高清電纜驅動器與集成式重定時器的技術解析

    LMH1218:低功耗超高清電纜驅動器與集成式重定時器的技術解析 一、引言 在當今超高清視頻飛速發展的時代,對于能夠支持高速數據傳輸的視頻電纜驅動器和重定時器的需求也日益增長。LMH1
    的頭像 發表于 12-22 15:15 ?351次閱讀

    Linux驅動開發的必備知識

    驅動框架進行開發。 6、調試技能: 掌握內核調試工具,如 KDB、KGDB、printk 等。 能夠分析內核日志,定位驅動程序中的問
    發表于 12-04 07:58

    【迅為工業RK3568穩定可靠】itop-3568開發Linux驅動開發實戰:RK3568內核模塊符號導出詳解

    【迅為工業RK3568穩定可靠】itop-3568開發Linux驅動開發實戰:RK3568內核模塊符號導出詳解
    的頭像 發表于 11-21 13:25 ?1180次閱讀
    【迅為工業RK3568穩定可靠】itop-3568<b class='flag-5'>開發</b>板<b class='flag-5'>Linux</b><b class='flag-5'>驅動</b><b class='flag-5'>開發</b>實戰:RK3568<b class='flag-5'>內核</b>模塊符號導出詳解

    使用系統定時器SysTick來實現精確延時微秒和毫秒函數

    Cortex-M內核MCU都有的一個定時器,所以以上延時微秒和延時毫秒的函數適用于任何 Cortex-M內核的MCU。有了精確延時函數,那么使用通用GPIO軟件模擬一些通信協議,如IIC、SPI等串行協議,就可以
    發表于 11-20 07:12

    【免費送書】成為硬核Linux開發者:《Linux 設備驅動開發(第 2 版)》

    Linux系統的設備驅動開發,一直給人門檻較高的印象,主要因內核機制抽象、需深度理解硬件原理、開發調試難度大所致。2021年,一本講解
    的頭像 發表于 11-18 08:06 ?1385次閱讀
    【免費送書】成為硬核<b class='flag-5'>Linux</b><b class='flag-5'>開發</b>者:《<b class='flag-5'>Linux</b> 設備<b class='flag-5'>驅動</b><b class='flag-5'>開發</b>(第 2 版)》

    【書籍評測活動NO.67】成為硬核Linux開發者:《Linux 設備驅動開發(第 2 版)》

    )。成為硬核Linux開發Linux系統的設備驅動開發,一直給人門檻較高的印象,主要因內核機制
    發表于 11-17 17:52

    PWM、定時器、SysTick 區別及應用場景

    在單片機和嵌入式開發中,經常會遇到PWM(脈寬調制)、定時器、SysTick(系統滴答定時器)這幾個詞。很多初學者容易把它們混為一談,以為都是“定時相關的東西”。其實,它們在本質和應用
    的頭像 發表于 11-17 10:53 ?506次閱讀
    PWM、<b class='flag-5'>定時器</b>、SysTick 區別及應用場景

    SysTick系統滴答定時器簡介

    SysTick—系統定時器是屬于CM33內核中的一個外設,內嵌在NVIC中。系統定時器是一個24bit的向下遞減的計數,計數每計數一次的
    的頭像 發表于 09-23 09:50 ?1619次閱讀
    SysTick系統滴答<b class='flag-5'>定時器</b>簡介

    大彩講堂:VisualHMI-LUA教程-定時器的使用指南

    定時器的使用
    的頭像 發表于 08-31 16:59 ?1139次閱讀
    大彩講堂:VisualHMI-LUA教程-<b class='flag-5'>定時器</b>的使用指南

    MCU定時器/計數

    架構與功能特性? 定時器類型與配置? 高級控制定時器?:支持互補PWM輸出與剎車功能,適用于電機驅動等高精度控制場景。通用定時器?:集成輸入捕獲、輸出比較、單脈沖模式等基礎功能?。 系
    的頭像 發表于 04-27 13:54 ?773次閱讀