版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
1、溫州大學物理與電子信息工程學院 楊衛(wèi)波嵌入式系統(tǒng)原理與應用第12章 任務間通信與同步*嵌入式系統(tǒng)原理與應用2pRTX配置下是有并發(fā)的,但任一個時刻點上只有一個程序在處理機上運行。實際上并行是會涉及很多問題的,如多人同時在干活,他們需要共享到一些資源,那就涉及到溝通協(xié)調的額外付出了。pRTX的進程間通訊主要依賴于四種機制:事件(Event)、互斥鎖(Mutex)、信號量(Semaphore)、和郵箱(Mailbox)。前三種機制側重進程間的同步,郵箱側重進程間的數據通訊。前言任務間的同步任務間的同步任務間的同步 - 各任務運行的先后、觸發(fā)等關系備注:數據采集任務A 和數據處理任務B 之間存在同步
2、關系任務間的互斥任務間的互斥任務間的互斥 - 共享資源的申請使用備注:數據采集任務A 和數據處理任務B 之間存在互斥關系12.1 幾個重要的概念p臨界段:代碼的臨界段也稱為臨界區(qū),一旦這部分代碼開始執(zhí)行,則不允許任何中斷打斷。為確保臨界段代碼的執(zhí)行不被中斷,在進入臨界段之前須關中斷,而臨界段代碼執(zhí)行完畢后,要立即開中斷。 p由于Cortex-M3/M4的RTX內核庫中沒有關閉中斷的操作,也就是說 RTX 的源碼中不存在臨界段。p用戶寫應用的時候也有臨界段的問題,比如以下兩種: u讀取或者修改變量(特別是任務間通信的全局變量)的代碼,一般來說這是最常見的臨界代碼。u調用公共函數的代碼,特別是不可
3、重入的函數,如果多個任務都訪問這個函數,結果是可想而知的。 幾個重要的概念p中斷鎖:因為Cortex-M3/M4的RTX源碼中沒有關閉中斷的操作,所以也就沒有提供開關中斷函數。p用戶在自己的應用代碼采用裸機時如何開關中斷的,在使用了RTX后仍然使用以前的開關中斷函數即可。任務鎖p任務鎖:為了防止當前任務的執(zhí)行被其它高優(yōu)先級的任務打斷而提供的鎖機制就是任務鎖任務鎖。實現任務鎖可以通過給調度器加鎖或者直接關閉RTOS內核定時器(就是前面一直說的系統(tǒng)滴答定時器)來實現。 u通過給調度器加鎖實現給調度器加鎖的話,就無法實現任務切換,高優(yōu)先級任務也就無法搶占低優(yōu)先級任務的執(zhí)行,同時高優(yōu)先級任務也是無法向
4、低優(yōu)先級任務切換的。這種方式只是禁止了調度器工作,并沒有關閉任何中斷。u通過關閉 RTOS 內核定時器實現關閉了 RTOS 內核定時器的話,也就關閉了通過 RTOS 內核定時器中斷實現任務切換的功能,因為在退出定時器中斷時需要檢測當前需要執(zhí)行的最高優(yōu)先級任務,如果有高優(yōu)先級任務就緒的話需要做任務切換。RTX 操作系統(tǒng)是采用的這種方式實現任務鎖的。12.2 RTX 任務鎖的實現函數原型: voidvoid tsk_lock ( tsk_lock (voidvoid); ); 函數描述:禁止 RTX 內核定時器中斷,因此也就禁止了任務切換。 注意以下問題: p函數 tsk_lock 不支持嵌套調用
5、;p不允許在中斷服務程序中調用 tsk_lock;pRTX 內核定時器被關閉期間,RTX 內核任務調度器和需要時間片調度的任務被阻塞。p設置的任務延遲時間不再工作。p因此,強烈建議關 RTX 內核定時器中斷的時間越短越好。RTX 任務鎖的實現函數原型: voidvoid tsk_unlock ( tsk_unlock (voidvoid); ); 函數描述: 用于使能 RTX 內核定時器中斷,因此也就重新開啟任務切換。tsk_unlock 一定要跟 tsk_lock 配套使用。 使用這個函數要注意以下問題:函數 tsk_lock 不支持嵌套調用;不允許在中斷服務程序中調用 tsk_lock。使
6、用舉例: #include#include voidvoid protect_critical_op() protect_critical_op() tsk_lock(); tsk_lock(); do_critical_op(); do_critical_op(); tsk_unlock();tsk_unlock(); 12.2.3 例程說明實驗內容: 1. K1 按鍵按下,串口打印。2. 在調用 printf 函數的地方都加上任務鎖,防止多個任務調用此函數造成沖突,以至于串口打印出現亂碼。3. 各個任務實現的功能如下: AppTaskUserIF任務 :按鍵消息處理。 AppTaskLED
7、 任務:LED 閃爍,并串口打印任務正在運行。 AppTaskMsgPro 任務:消息處理,用作 LED 閃爍和串口打印任務正在運行。 AppTaskStart 任務:啟動任務,最高優(yōu)先級任務,實現按鍵掃描。RTX配置四個 RTX 任務的實現_task _task voidvoid AppTaskMsgPro( AppTaskMsgPro(voidvoid) ) whilewhile (1) (1) bsp_LedToggle(1); bsp_LedToggle(1); bsp_LedToggle(4);bsp_LedToggle(4);/ /* * 開啟任務鎖開啟任務鎖 */tsk_lock
8、();tsk_lock();printf(printf( 任務任務AppTaskMsgPro正在運行正在運行rn););/ /* * 關閉任務鎖關閉任務鎖 */tsk_unlock();tsk_unlock();os_dly_wait(300);os_dly_wait(300); RTX 任務調試信息12.3 事件標志組事件標志組是實現多任務同步的有效機制之一。初學者會問采用事件標志組多麻煩,搞個全局變量不是更簡單,其實不然。在裸機編程時,使用全局變量的確比較方便,但相比事件標志組主要有如下三個問題: p使用事件標志組可以讓 RTOS 內核有效的管理任務,全局變量是無法做到的,任務的超時等機制
9、需要用戶自己去實現。p使用了全局變量就要防止多任務的訪問沖突,使用事件標志組已經處理好了這個問題。用戶無需擔心。 p使用事件標志組可以有效的解決中斷服務程序和任務之間的同步問題。12.3.1 事件標志組的實現創(chuàng)建 2 個任務 Task1 和 Task2,運行過程描述如下: p任務 Task1 運行過程中調用函數 os_evt_wait_and,等待事件標志位被設置,任務 Task1 由運行態(tài)進入到掛起態(tài)p任務 Task2 設置了任務 Task1 的事件標志,任務 Task1 由掛起態(tài)進入到就緒態(tài),在調度器的作用下由就緒態(tài)又進入到運行態(tài)。各個任務之間使用事件標志組實現任務的通信或者同步。RTX
10、每個任務創(chuàng)建的時候,會自動創(chuàng)建 16 個事件標志,事件標志被存儲到每個任務的任務控制塊中,即每個任務支持 16 個事件標志。12.3.2 中斷方式事件標志組的實現 指中斷函數和 RTX 任務之間使用事件標志運行條件:創(chuàng)建 1 個任務和一個串口接收中斷運行過程描述如下: p任務 Task1 運行過程中調用函數 os_evt_wait_and,等待事件標志位被設置,任務 Task1 由運行態(tài)進入到掛起態(tài)pTask1 掛起的情況下,串口接收到數據進入到了串口中斷服務程序,在串口中斷服務程序中設置 Task1 的事件標志,任務 Task1 由掛起態(tài)進入到就緒態(tài),在調度器的作用下由就緒態(tài)又進入到運行態(tài)。
11、12.3.2 中斷方式事件標志組的實現 實際應用中,中斷方式的消息機制切記注意以下四個個問題: p中斷函數的執(zhí)行時間越短越好,防止其它低于這個中斷優(yōu)先級的異常不能得到及時響應。p實際應用中,建議不要在中斷中實現消息處理,用戶可以在中斷服務程序里面發(fā)送消息通知任務,在任務中實現消息處理,這樣可以有效的保證中斷服務程序的實時響應。同時此任務也需要設置為高優(yōu)先級,以便退出中斷函數后任務可以得到及時執(zhí)行。p中斷服務程序中一定要調用專用于中斷的事件標志設置函數 isr_evt_setisr_evt_set。p在 RTX 操作系統(tǒng)中實現中斷函數跟裸機編程是一樣的。中斷方式*嵌入式系統(tǒng)原理與應用18p節(jié)拍時
12、鐘任務不僅僅在時鐘節(jié)拍中斷產生時運行,而且當一個中斷調用isr_函數時也執(zhí)行。這是因為中斷不能使當前任務等待,因此也不能進行任務的切換。p中斷可以產生事件、信號量或是消息(使用isr_庫函數)來表明一個更高優(yōu)先級的任務正在等待。p更高優(yōu)先級的任務將搶占當前的任務,但必須在中斷函數結束后才能進行。這樣就強制產生在當前中斷結束后運行的時鐘節(jié)拍中斷,而且激發(fā)任務調度。任務調度處理所有的任務,并將就緒的最高優(yōu)先級的任務投入運行,最高優(yōu)先級的任務因此可以持續(xù)的運行。*嵌入式系統(tǒng)原理與應用19PendSV中斷12.3.3 事件標志組 API 函數使用如下6個函數可以實現 RTX 的事件標志組: pos_e
13、vt_clros_evt_clr();();pos_evt_getos_evt_get();();pos_evt_setos_evt_set();();pos_evt_wait_andos_evt_wait_and();();pos_evt_wait_oros_evt_wait_or();();pisr_evt_setisr_evt_set();();函數 os_evt_setvoidvoid os_evt_set ( U16 event_flags, /* 16位的事件標志設置位的事件標志設置 */ OS_TID task ); /* 要設置事件標志的任務要設置事件標志的任務ID */ 函數
14、描述:用于設置指定任務的事件標志。 p第1個參數表示16個可設置的事件標志位。因為RTX的每個任務創(chuàng)建時有16個可設置的事件標志,這里用 U16 類型的變量 event_flag 就可以表示,變量 event_flag 的某個位設置為 1,那么指定 RTX 任務的事件標志相應位就設置為 1。變量 event_flag 設置為 0 的位對 RTX 任務的事件標志相應位沒有影響。比如設置變量 event_flag = 0 x0003 就表示將 RTX 任務事件標志的位 0 和位 1 設置為 1,其余位沒有變化。p第 2 個參數是任務 ID。函數 os_evt_set使用這個函數要注意:此函數是用于
15、任務代碼中調用的,故不可以在中斷服務程序中調用此函數,中斷服務程序中使用的是 isr_evt_set#include #include _task void task1 (_task void task1 (voidvoid) . ) . os_evt_set (0 x0003, tsk2); os_evt_set (0 x0003, tsk2); . . 函數 isr_evt_set voidvoid isr_evt_set ( U16 event_flags, /* 16位的事件標志設置位的事件標志設置 */ OS_TID task ); /* 要設置事件標志的任務要設置事件標志的任務ID
16、 */ 函數描述函數描述:用于設置指定任務的事件標志。 p第1個參數表示16個可設置的事件標志位。p第 2 個參數是任務 ID。使用這個函數要注意以下問題: 1.此函數是用于中斷服務程序中調用的。2. 調用不能太頻繁,太頻繁的話會大大增加系統(tǒng)內核的開銷,會造成事件標志得不到及時處理從而造成丟失事件標志的情況。#include #include voidvoid EXTI0_IRQHandler ( EXTI0_IRQHandler (voidvoid) . ) . isr_evt_set (0 x0003, tsk2); . isr_evt_set (0 x0003, tsk2); . 函數
17、os_evt_wait_andOS_RESULT os_evt_wait_and ( U16 wait_flags, /* 16位的事件標志等待位的事件標志等待 */ U16 timeout ); /* 超時時間設置超時時間設置 */ 函數描述函數描述:用于等待事件標志被設置。 p第1 個參數表示任務等待的事件標志位。因為 RTX 的每個任務創(chuàng)建時有 16 個可以設置的事件標志,這里用 U16 類型的變量 event_flag 就可以設置,變量 event_flag 的那位設置為 1,那么 RTX 任務的事件標志就等待那個位被設置為 1。而且要所有要求的位都被設置為 1 才可以。比如設置變量
18、event_flag = 0 x0003 就表示 RTX 任務在等待事件標志的位 0 和位 1 都被設置為 1。p第 2 個參數表示設在的等待時間,范圍 0-0 xFFFF,當參數設置為 0-0 xFFFE 時,表示等這么多個時鐘節(jié)拍,參數設置為 0 xFFFF 時表示無限等待直到事件標志滿足要求。函數 os_evt_wait_andp函數返回 OS_R_EVT 表示等待的事件標志位都被設置了,也就是返回成功。返回 OS_R_TMO 表示超時。使用這個函數要注意以下問題: 1. 當要求的事件標志位都被設置為 1 時或者設置的超時時間溢出時,函數 os_evt_wait_and 才會返回。 2.
19、 如果函數 os_evt_wait_and 返回前所要求的事件標志位都設置了,那么此函數會在返回前將相應的事件標志位清零,其它位不受此影響。函數os_evt_wait_oros_evt_wait_or(U16wait_flags,U16timeout);與事件等待,參數意義與和事件等待相同。這兩個操作的差別在于(其實應該比較一目了然)對于和事件等待而言,所有標示都滿足了,進程才會被喚醒,對于與事件等待而言,任一標示狀態(tài)滿足了就會喚醒進程。 例子:os_evt_wait_and (0 xABCD, 0 xFFFF);os_evt_wait_or (0 xABCD, 0 xFFFF);p第一個語句
20、的話,進程會等待15,13,11,9,8,7,6,3,2,0位(0 xABCD)的標示全部被設為1時才會被喚醒;p第二個語句而言,15,13,11,9,8,7,6,3,2,0位中的任一一位標示被設為1,進程就會被喚醒。使用舉例#include#include #define#define BIT_0BIT_0 (1 0) (1 0) #define#define BIT_1BIT_1 (1 1) (1 1) #define#define BIT_ALLBIT_ALL ( (BIT_0BIT_0 | | BIT_1BIT_1) ) _task _task voidvoid AppTaskMsgP
21、ro( AppTaskMsgPro(voidvoid) ) OS_RESULT xResult;OS_RESULT xResult;constconst uint16_t usMaxBlockTime = 500; uint16_t usMaxBlockTime = 500; / /* * 延遲周期延遲周期 */whilewhile (1) (1) xResult = os_evt_wait_and(xResult = os_evt_wait_and(BIT_ALLBIT_ALL, usMaxBlockTime);, usMaxBlockTime);switchswitch (xResult)
22、 (xResult) casecase OS_R_EVT: OS_R_EVT:/ /* * 接收到接收到bit1和和bit0都被設置的消息都被設置的消息 */printf(printf( 接收到接收到bit0和和bit1都被設置的消息都被設置的消息rn););breakbreak; ;casecase OS_R_TMO: OS_R_TMO: / /* * 超時超時 */bsp_LedToggle(1);bsp_LedToggle(1);bsp_LedToggle(4);bsp_LedToggle(4);breakbreak; ;defaultdefault: : / /* * 其他值不處理其他
23、值不處理 */breakbreak; ; *嵌入式系統(tǒng)原理與應用28os_evt_get()12.3.4 例程說明(任務間通信)內容: 1. K1 按鍵按下,串口打印。2. K2 鍵按下,直接發(fā)送事件標志給任務AppTaskMsgPro,設置 bit0 3. K3 鍵按下,直接發(fā)送事件標志給任務 AppTaskMsgPro,設置 bit1 4. 任務 AppTaskMsgPro 只有接收到 bit0 和 bit1 都被設置了才執(zhí)行串口打印信息。各個任務實現的功能如下: AppTaskUserIF 任務:按鍵消息處理。 AppTaskLED 任務:LED 閃爍。 AppTaskMsgPro 任務
24、:消息處理,等待任務 AppTaskUserIF 發(fā)來的事件標志。 AppTaskStart 任務 :啟動任務,最高優(yōu)先級任務,實現按鍵掃描。 RTX 配置RTX 任務調試信息Event Value:任務 AppTaskMsgPro 當前的事件標志數值。Event Mask:任務 AppTaskMsgPro 等待的事件標志數值。12.3.4 例程說明(中斷方式通信) 內容: 1. K1 按鍵按下,串口打印。2. K2鍵按下,啟動單次定時器中斷,50ms后在定時器中斷給任務AppTaskMsgPro發(fā)送事件標志,設置 bit0。3. K3鍵按下,啟動單次定時器中斷,50ms后在定時器中斷給任務A
25、ppTaskMsgPro發(fā)送事件標志,設置 bit1。 4. 任務 AppTaskMsgPro 只有接收到 bit0 和 bit1 都被設置了才執(zhí)行串口打印信息。各個任務實現的功能如下: AppTaskUserIF 任務:按鍵消息處理。 AppTaskLED 任務:LED 閃爍。 AppTaskMsgPro 任務 :消息處理,等待定時器中斷發(fā)來的事件標志。 AppTaskStart 任務 :啟動任務,也是最高優(yōu)先級任務,這里實現按鍵掃描。*嵌入式系統(tǒng)原理與應用33#define#define EVT_KEYEVT_KEY 0 x0001 0 x0001OS_TID pr_task;OS_TID
26、 pr_task;intint num_ints; num_ints;/ /* *- External 0 Interrupt Service Routine- External 0 Interrupt Service Routine-* */ /voidvoid ext0_int( ext0_int(voidvoid) _irq ) _irq isr_evt_set(isr_evt_set(EVT_KEYEVT_KEY, pr_task); , pr_task); / /* * Send event to process_task Send event to process_task* */
27、 /. _task _task voidvoid process_task( process_task(voidvoid) ) num_ints = 0;num_ints = 0;whilewhile (1) (1) os_evt_wait_or(os_evt_wait_or(EVT_KEYEVT_KEY, 0 xffff);, 0 xffff);num_ints+;num_ints+; voidvoid init_task( init_task(voidvoid) _task ) _task .pr_task = os_tsk_create(process_task,100);pr_task
28、 = os_tsk_create(process_task,100);os_tsk_delete_self(); os_tsk_delete_self(); / /* * Terminate this task Terminate this task * */ / RTX核中使用中斷任務process_task僅是記錄發(fā)生中斷的次數*嵌入式系統(tǒng)原理與應用34分析程序的功能#include RTL.hOS_TID id1, id2;_task void task1 (void);_task void task2 (void);_task void task1 (void) id1 = os_ts
29、k_self (); id2 = os_tsk_create (task2, 0); for (;) os_evt_set (0 x0004, id2); os_evt_wait_or (0 x0004, 0 xffff); os_dly_wait (5); _task void task2 (void) for (;) os_evt_wait_or (0 x0004, 0 xffff); os_dly_wait (2); os_evt_set (0 x0004, id1); int main (void) os_sys_init (task1);12.4 信號量信號量(semaphores)
30、是20世紀60年代中期Edgser Dijkstra發(fā)明的。最初目的是為了給共享資源建立一個表示該共享資源被占用情況的標志。當一個任務在訪問共享資源前,先對這個標志進行查詢,在了解資源被占用的情況后,再來決定自己的行為。 如有個 30 人的電腦機房,創(chuàng)建信號量的初始化值是30,表示30 個可用資源。要求一個同學使用一臺電腦,有一個同學使用一臺電腦,信號量的數值就減一。當信號量的數值為 0時,還有同學沒有電腦可以使用,那么這個同學就得等待,直到有同學離開,有一個同學離開,那么信號量的數值就加 1,依次類推。剛才沒有電腦用的同學此時就有電腦可以用了。這么一個過程就是使用信號量來管理共享資源的過程。
31、 12.4 信號量平時使用信號量主要實現以下兩個功能: p兩個任務或者中斷函數跟任務之間的同步功能,和事件標志組是類似的。其實就是共享資源為 1 的時候。p多個共享資源的管理,就像上面機房上機的例子。 簡單說來,信號量有三個部分:u第一部分就是一個代幣容器(一個整形變量),記錄著可用的資源數;u第二部分就是取用資源(P,嘗試的荷蘭語)的操作;u第三個就是還回資源(V, 增加的荷蘭語)的操作。當資源數量為0時任何取用資源的操作都會被阻斷,直到資源數量增加。12.4.2 RTX 任務間信號量的實現指各個任務之間使用信號量實現任務的同步或者資源共享功能。運行過程描述如下: pTask1運行中調用os
32、_sem_wait獲取信號量資源,如果信號量沒有被Task2占用,Task1 將直接獲取資源。如果信號被 Task2 占用,Task1 將由運行態(tài)轉到掛起狀態(tài),等待資源可用。一旦獲取了資源并使用完畢后會通過函數 os_sem_send 釋放掉資源pTask2運行中調用os_sem_wait獲取信號量資源,如果信號量沒有被任務Task2占用,Task1將直接獲取資源。如果信號被Task2 占用,Task1將由運行態(tài)轉到掛起狀態(tài),等待資源可以。一旦獲取了資源并使用完畢后會通過函數 os_sem_send 釋放掉資源。運行條件:創(chuàng)建 2 個任務 Task1 和 Task2,創(chuàng)建信號量可用資源為 1。
33、12.4.3 中斷方式信號量的實現指中斷函數和 RTX 任務之間使用信號量,主要是用于實現任務同步。p創(chuàng)建 1 個任務 Task1 和一個串口接收中斷。p信號量的初始值為 0,串口中斷調用函數 isr_sem_send 釋放信號量,任務 Task1 調用函數 os_sem_wait 獲取信號量資源。運行過程描述p任務 Task1 運行過程中調用函數 os_sem_wait,由于信號量的初始值是 0,沒有信號量資源可用,任務 Task1 由運行態(tài)進入到掛起態(tài)。pTask1 掛起的情況下,串口接收到數據進入到了串口中斷服務程序,在串口中斷服務程序中調用函數 isr_sem_send 釋放信號量資源
34、,信號量數值加 1,此時信號量計數值為 1,任務 Task1 由掛起態(tài)進入到就緒態(tài),在調度器的作用下由就緒態(tài)又進入到運行態(tài),任務 Task1 獲得信號量后,信號量數值減1,此時信號量計數值又變成了 0。p再次循環(huán)執(zhí)行時,任務 Task1 調用函數 os_sem_wait 由于沒有資源可用再次進入到掛起態(tài),等待串口釋放信號量資源,如此往復循環(huán)。注意以下四個問題p中斷函數的執(zhí)行時間越短越好,防止其它低于這個中斷優(yōu)先級的異常不能得到及時響應。p實際應用中,建議不要在中斷中實現消息處理,用戶可以在中斷服務程序里面發(fā)送消息通知任務,在任務中實現消息處理,這樣可以有效的保證中斷服務程序的實時響應。同時此任
35、務也需要設置為高優(yōu)先級,以便退出中斷函數后任務可以得到及時執(zhí)行。p中斷服務程序中一定要調用專用于中斷的信號量設置函數 isr_sem_send。p在 RTX 操作系統(tǒng)中實現中斷函數和裸機編程是一樣的。12.4.4 信號量 API 函數使用如下4個函數可以實現 RTX 的信號量: pos_sem_initos_sem_initpos_sem_sendos_sem_sendpisr_sem_sendisr_sem_sendpu os_sem_wait u os_sem_wait 函數 os_sem_initvoid os_sem_init ( OS_ID semaphore, /* os_sem類
36、型變量類型變量 */ U16 token_count ); /* 信號量初始值信號量初始值 */ 函數描述函數描述:用于信號量的初始化并設置初始值 p第1個參數填寫數據類型為OS_SEM的變量,同時也作為ID標識;p第2個參數是信號量初始值,也就是可用資源個數。使用舉例使用舉例: #include #include OS_SEM semaphore; OS_SEM semaphore; static void AppObjCreate(void)static void AppObjCreate(void) /* 創(chuàng)建信號量計數值是創(chuàng)建信號量計數值是0, 用于任務同步用于任務同步 */os_se
37、m_init(&semaphore, 0);os_sem_init(&semaphore, 0); 為什么變量semaphore 前面加一個取地址符&?函數 os_sem_sendOS_RESULT os_sem_send ( OS_ID semaphore ); /* OS_SEM類型變量類型變量 */ 函數描述:函數描述:用于釋放信號量,調用后信號量計數值加 1。 p第 1 個參數參數填寫數據類型為 OS_SEM 的變量,同時也作為 ID 標識。p返回值永遠是 OS_R_OK。p使用此函數前一定要調用函數 os_sem_init 進行初始化。使用舉例:使用舉例: #include #inc
38、lude OS_SEM semaphore; OS_SEM semaphore; _task void task1 (void) . _task void task1 (void) . os_sem_init (&semaphore, 0); os_sem_init (&semaphore, 0); os_sem_send (&semaphore); . os_sem_send (&semaphore); . 函數 isr_sem_sendvoid isr_sem_send ( OS_ID semaphore ); /* OS_SEM類型變量類型變量 */ 函數描述:函數描述:用于釋放信號量,
39、調用后信號量計數值加 1。 p第 1 個參數參數填寫數據類型為 OS_SEM 的變量,同時也作為 ID 標識。p使用此函數前一定要調用函數 os_sem_init 進行初始化。使用舉例:使用舉例: #include #include OS_SEM semaphore; OS_SEM semaphore; void EXTI0_IRQHandler (void) . void EXTI0_IRQHandler (void) . isr_sem_send (&semaphore1); . isr_sem_send (&semaphore1); . 函數 os_sem_waitOS_RESULT o
40、s_sem_wait ( OS_ID semaphore, /* OS_SEM類型變量類型變量 */ U16 timeout ); /* 超時時間設置超時時間設置 */ 函數描述:用于獲取信號量,如果當前的信號量計數值大于函數描述:用于獲取信號量,如果當前的信號量計數值大于 0,那么調用函數,那么調用函數 os_sem_wait 后可以成功獲取信號量,并將信號量的計數值減后可以成功獲取信號量,并將信號量的計數值減 1。如果信號。如果信號量計數值等于量計數值等于 0,調用此函數的任務將由運行態(tài)轉到掛起態(tài),等待信號量資源,調用此函數的任務將由運行態(tài)轉到掛起態(tài),等待信號量資源可用,也就是等待信號量計
41、數值大于可用,也就是等待信號量計數值大于 0。 p第 1 個參數參數填寫數據類型為 OS_SEM 的變量,同時也作為 ID 標識。p第 2 個參數表示設置的等待時間,范圍 0-0 xFFFF,當參數設置為 0-0 xFFFE 時,表示等待這么多個時鐘節(jié)拍,參數設置為 0 xFFFF 時表示無限等待直到有信號量資源可用。p函數返回 OS_R_SEM 表示函數設置的超時時間范圍內收到信號量可用資源。函數返回 OS_R_TMO 表示超時。函數返回 OS_R_OK 表示無需等待,立即獲得可用信號量資源。使用舉例#include OS_SEM semaphore;_task void AppTaskMs
42、gPro(void) OS_RESULT xResult;const uint16_t usMaxBlockTime = 200; /* 延遲周期 */while (1)xResult = os_sem_wait(&semaphore, usMaxBlockTime);switch (xResult)case OS_R_OK:printf(無需等待接受到信號量同步信號rn);break;case OS_R_SEM:printf(信號量不可用,內收到信號量同步信號rn);break;case OS_R_TMO: /* 超時 */bsp_LedToggle(1);bsp_LedToggle(4);
43、 break; default:break;使用舉例os_semsemaphore;os_semsemaphore;_taskvoid task1(_taskvoid task1(voidvoid) ) os_sem_init(semaphore, 0);os_sem_init(semaphore, 0);whilewhile (1) (1) Function1();Function1();os_sem_send(semaphore);os_sem_send(semaphore); _taskvoid task2(_taskvoid task2(voidvoid) ) whilewhile (
44、1) (1) os_sem_wait(semaphore, 0 xFFFF);os_sem_wait(semaphore, 0 xFFFF);Function2();Function2(); 信號量的作用就是確保在每一次調用Function2之前,Function1都有一次完整的調用。使用舉例os_semArrived1, Arrived2;os_semArrived1, Arrived2;_task void task1(_task void task1(voidvoid) ) os_sem_init(Arrived1, 0);os_sem_init(Arrived1, 0);os_sem_
45、init(Arrived2, 0);os_sem_init(Arrived2, 0);whilewhile (1) (1) FunctionA1();FunctionA1();os_sem_send(Arrived1);os_sem_send(Arrived1);os_sem_wait(Arrived2, 0 xFFFF);os_sem_wait(Arrived2, 0 xFFFF);FunctionA2();FunctionA2(); _task void task2(_task void task2(voidvoid) ) whilewhile (1) (1) FunctionB1();F
46、unctionB1();os_sem_send(Arrived2);os_sem_send(Arrived2);os_sem_wait(Arrived1, 0 xFFFF);os_sem_wait(Arrived1, 0 xFFFF);FunctionB2();FunctionB2(); 目的是讓FunctionA1,functionB1都完成以后,再執(zhí)行FunctionA2和FunctionB2使用舉例os_semMultiplex;os_semMultiplex;_taskvoid task(_taskvoid task(voidvoid) ) os_sem_init(Multiplex,
47、 5);os_sem_init(Multiplex, 5);whilewhile (1) (1) os_sem_wait(Multiplex, 0 xFFFF);os_sem_wait(Multiplex, 0 xFFFF);Function();Function();os_sem_send(Multiplex);os_sem_send(Multiplex); 保證最多只有五個進程能夠同時調用Function()。12.4.5 實驗例程說明(任務間通信)目的: 學習 RTX 的信號量實驗內容: 1. K1 按鍵按下,串口打印。2. K2 鍵按下,直接發(fā)送信號量同步信號給任務 AppTaskMs
48、gPro。任務 AppTaskMsgPro 接收到消息后進行消息處理。3. 各個任務實現的功能如下: AppTaskUserIF 任務:按鍵消息處理。 AppTaskLED 任務:LED 閃爍。 AppTaskMsgPro 任務 :消息處理,等待任務 AppTaskUserIF 發(fā)來的信號量同步信號。 AppTaskStart 任務 :啟動任務,也是最高優(yōu)先級任務,這里實現按鍵掃描。 RTX 配置RTX 任務調試信息12.4 .5例程說明(中斷方式通信)目的: 學習 RTX 的信號量(中斷方式)實驗內容: 1. K1 按鍵按下,串口打印。2. K2 鍵按下,啟動單次定時器中斷,50ms 后在定
49、時器中斷給任務 AppTaskMsgPro 發(fā)送信號量同步信號。任務 AppTaskMsgPro 接收到消息后進行消息處理。 3. 各個任務實現的功能如下: AppTaskUserIF 任務 :按鍵消息處理。 AppTaskLED 任務:LED 閃爍。 AppTaskMsgPro 任務:消息處理,等待定時器中斷發(fā)來的信號量同步信號。 AppTaskStart 任務:啟動任務,最高優(yōu)先級任務,實現按鍵掃描。定時器中斷回調函數中發(fā)送信號量同步信號:定時器中斷的初始化和中斷函數在 bsp_timer.c 文件中實現, RTX 的信號量函數在中斷服務程序中使用:staticstatic voidvoi
50、d TIM_CallBack1( TIM_CallBack1(voidvoid) ) / /* * 發(fā)送信號量同步信號發(fā)送信號量同步信號 */isr_sem_send(&semaphore);isr_sem_send(&semaphore); RTX 任務調試信息*嵌入式系統(tǒng)原理與應用56課堂作業(yè)建立兩個任務 AppTaskPost 和 AppTaskPend。按鍵按下時任務 AppTaskPost 當每隔 200ms 向等待的任務 AppTaskPend 發(fā)送一個任務信號量,并通過串口打印出任務信號量的值。當按鍵松開時任務AppTaskPend每隔 200ms請求一個任務信號量,紅色 LED
51、 閃爍表示請求到一個任務信號量,任務信號量的值減小,任務AppTaskPost通過串口打印任務信號量的值。當任務信號量的值減小到 0時,任務AppTaskPend請求不到任務信號量,紅色LED不再閃爍。12.5 互斥信號量p互斥信號量就是信號量的一種特殊形式,也就是信號量初始值為 1 的情況。有些 RTOS 中也將信號量初始值設置為 1 的情況稱之為二值信號量。為什么叫二值信號量呢?因為信號量資源被獲取了,信號量值就是 0,信號量資源被釋放,信號量值就是 1,把這種只有 0 和 1 兩種情況的信號量稱之為二值信號量。p互斥信號量的主要作用就是對資源實現互斥訪問。運行條件p讓兩個任務 Task1
52、 和 Task2 都有運行串口打印 printf,對函數 printf 通過二值信號量實現互斥訪問。如果不對函數 printf 進行互斥訪問,串口打印容易出現亂碼。p用信號量實現二值信號量只需將信號量的初始值設置為 1 即可。創(chuàng)建二值信號量創(chuàng)建二值信號量OS_SEM semaphore;OS_SEM semaphore;staticstatic voidvoid AppObjCreate( AppObjCreate(voidvoid) ) / /* * 創(chuàng)建二值信號量,實現對互斥資源的獨享創(chuàng)建二值信號量,實現對互斥資源的獨享 */os_sem_init(semaphore, 0);os_sem
53、_init(semaphore, 0); 二值信號量實現互斥訪問_task _task voidvoid AppTaskLED( AppTaskLED(voidvoid) ) constconst uint16_t usFrequency = 1000; uint16_t usFrequency = 1000; os_itv_set(usFrequency);os_itv_set(usFrequency);whilewhile (1) (1) / /* * 永久等待互斥資源可用永久等待互斥資源可用 */os_sem_wait(&semaphore, 0 xffff);os_sem_wait(&
54、semaphore, 0 xffff);printf(printf( 任務任務AppTaskLED正在運行正在運行rn););/ /* * 釋放互斥資源釋放互斥資源 */os_sem_send(&semaphore);os_sem_send(&semaphore);/ /* * os_itv_wait os_itv_wait是絕對延遲,是絕對延遲,os_dly_wait是相對延遲。是相對延遲。*/os_itv_wait();os_itv_wait(); _task void AppTaskMsgPro(void)const uint16_t usFrequency = 1000; /* 延遲周
55、期 */os_itv_set(usFrequency); /* 設置延遲周期 */while (1)/* 永久等待互斥資源可以 */printf(任務AppTaskMsgPro正在運行rn);/* 釋放互斥資源 */os_sem_send(&semaphore);/* os_itv_wait是絕對延遲,os_dly_wait是相對延遲。*/os_itv_wait();12.5.2 優(yōu)先級翻轉問題 p3 個任務 Task1,Task2 和 Task3,優(yōu)先級分別為 3,2,1。pTask1和Task3采用二值信號實現互斥訪問串口打印printf。p起初 Task3 通過二值信號量正在調用 pri
56、ntf,被任務 Task1 搶占,開始執(zhí)行任務 Task1,也就是圖的起始位置。優(yōu)先級翻轉問題pTask1 運行的過程需要調用printf,發(fā)現Task3 正在調用,Task1 會被掛起,等待 Task3 釋放函數 printf。p在調度器的作用下,Task3 得到運行,Task3 運行的過程中,由于Task2 就緒,搶占了 Task3 的運行。優(yōu)先級翻轉問題就出在這里了,從任務執(zhí)行的現象上看,高優(yōu)先級任務 Task1 需要等待低優(yōu)先級任務 Task2 執(zhí)行完畢才有機會得到執(zhí)行,這個與搶占式調度正好反了。pTask2 執(zhí)行完畢后,Task3 恢復執(zhí)行,Task3 釋放互斥資源后,Task1得到
57、互斥資源,從而可以繼續(xù)執(zhí)行。優(yōu)先級翻轉問題(2)考慮三個進程,T1,T2,T3。T3的優(yōu)先度大于T2,T2的優(yōu)先度大于T1,采用的調度算法算法是優(yōu)先度高的可以打斷優(yōu)先度低的進程,臨界區(qū)等待可以阻斷高優(yōu)先度的進程。問題:進程3被什么阻斷了?答:進程3因為要求資源R的臨界區(qū),而此時資源R臨界區(qū)被進程1占用。所以,進程3實際上是被進程2阻斷了,低優(yōu)先度的進程阻斷了高優(yōu)先度的進程,這就是優(yōu)先度翻轉問題。優(yōu)先度繼承優(yōu)先度繼承的意思是,將臨界區(qū)內的進程的優(yōu)先度提高為該進程阻斷的進程里的優(yōu)先級最高進程的優(yōu)先級。當進程3要求進入R臨界區(qū)執(zhí)行時,因為被進程1阻斷了,進程1此時在臨界區(qū)內,而且它阻斷的是進程3,那
58、么此時它的優(yōu)先度就會提升為進程3的優(yōu)先度,也就是說繼承了進程3的優(yōu)先度。當退出臨界執(zhí)行區(qū)后,進程1優(yōu)先度又會降為原先的優(yōu)先度。這就很好地解決了高優(yōu)先度進程被無條件阻斷的問題死鎖優(yōu)先度繼承的意思是,將臨界區(qū)內的進程的優(yōu)先度提高為該進程阻斷的進程里的優(yōu)先級最高進程的優(yōu)先級。T1被創(chuàng)造T1要求進入資源A臨界區(qū)T2被創(chuàng)建T2要講求進入資源B臨界區(qū)T2要求進入資源A臨界區(qū)T1要求進入資源B臨界區(qū)當進程2要求資源A臨界區(qū)時,因為進程1正在資源A臨界區(qū)內,所以其優(yōu)先級繼承了進程2的優(yōu)先級,但進程1執(zhí)行了一段時間后又要求進入資源B臨界區(qū)以完成當前任務,退出臨界區(qū)A。兩個進程此時都在等待對方退出臨界區(qū),而自己卻
59、不會主動退出自己占有的臨界區(qū),所以死鎖。優(yōu)先度天花板具體說來就是,為每個資源定義優(yōu)先度天花板,資源的優(yōu)先度天花板是所有可能要互斥使用該資源的進程的最高優(yōu)先度。這種策略只允許滿足一個條件的進程去進入臨界區(qū),該進程的優(yōu)先度要大于(等于不足夠)所有其他進程占用的資源的優(yōu)先度天花板的最高優(yōu)先度。同時保留優(yōu)先度繼承策略。當進程2想進入資源B臨界區(qū)時,被阻斷了,因為它優(yōu)先度并不大于其他進程(進程1)占用資源(A)的優(yōu)先度天花板(進程2的優(yōu)先度),被進程1阻斷,與此同時,進程1的優(yōu)先度提升為進程2的優(yōu)先度,繼續(xù)執(zhí)行,直到退出兩個臨界區(qū)。任務任務A申請共享資源申請共享資源S S是否被占用是否被占用任務任務A獲
60、得共享資源獲得共享資源S S被任務被任務B占用,任務占用,任務A被掛起被掛起 Priority(B)Priority( A)?提升提升B的優(yōu)先級到的優(yōu)先級到PIP B釋放資源釋放資源s并恢復原來的優(yōu)先級并恢復原來的優(yōu)先級 等待隊列等待隊列中優(yōu)先級最高的任務獲得中優(yōu)先級最高的任務獲得s任務任務A繼續(xù)執(zhí)行繼續(xù)執(zhí)行NYNY優(yōu)先級繼承的主要思想當高優(yōu)先級任務因申請某共享資源失敗被阻塞時,把當前擁有該資源的、且優(yōu)先級較低的任務的優(yōu)先級提升,提升的高度等于這個高優(yōu)先級任務的優(yōu)先級(可以指定一個PIP) 12.5.3 RTX 互斥信號量的實現RTX 互斥信號量是怎么實現的呢?其實相比二值信號量就是解決了一下
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 贛南醫(yī)學院《攝影與攝像》2023-2024學年第一學期期末試卷
- 贛南師范大學《能源化工專業(yè)英語》2023-2024學年第一學期期末試卷
- 甘肅中醫(yī)藥大學《麻醉設備學基礎》2023-2024學年第一學期期末試卷
- 2022年上半年盧姨筆試幼兒綜合教資押題(含答案)
- 三年級數學上冊第五單元倍的認識第1課時倍的認識教案新人教版
- 三年級科學下冊四植物和我們1植物和我們的生活教案新人教版
- 員工培訓課件服從
- 禮儀常識培訓課件
- 面部手法培訓課件
- 《水環(huán)境公共政策》課件
- 2024年高等教育教育類自考-03372團體心理咨詢考試近5年真題集錦(頻考類試題)帶答案
- 部編版小學三年級上冊道德與法治教案設計(全冊)
- 自考證據法學講義(大全)
- 2024年化工儀表維修工職業(yè)技能競賽理論考試題庫500題(含答案)
- 光合作用(光合作用的研究歷程)課件-2024-2025學年北師大版生物七年級上冊
- 2024-2030年全球及中國用于防御的紅外反狙擊手探測系統(tǒng)行業(yè)市場現狀供需分析及市場深度研究發(fā)展前景及規(guī)劃可行性分析研究報告
- 2024年安徽六年級數學第一學期期末考試試題含解析
- 上海市縣(2024年-2025年小學四年級語文)統(tǒng)編版期末考試(上學期)試卷及答案
- 北京市大興區(qū)名校2025屆數學八年級第一學期期末統(tǒng)考試題含解析2
- 制造業(yè)行業(yè):制造業(yè)質量控制與提升方案
- 正常分娩個案護理
評論
0/150
提交評論