論壇原始地址(持續更新):http://www.armbbs.cn/forum.php?mod=viewthread&tid=99514
第9章 ThreadX任務管理
對於初學者,特別是對於沒有RTOS基礎的同學來說,了解ThreadX的任務管理非常重要,了解任務管理的目的就是讓初學者從裸機的,單任務編程過渡到帶OS的,多任務編程上來。搞清楚了這一點,那么ThreadX學習就算入門了。
9.1 單任務系統
9.2 多任務系統
9.3 ThreadX的任務棧設置
9.4 ThreadX的系統棧設置
9.5 ThreadX的任務狀態
9.6 ThreadX啟動流程圖示
9.7 ThreadX的空閑任務
9.8 ThreadX的啟動函數tx_kernal_enter
9.9 ThreadX的任務創建函數tx_threadx_create
9.10 ThreadX的任務刪除函數tx_threadx_delete
9.11 ThreadX的任務掛起函數tx_threadx_suspend
9.12 ThreadX的任務恢復函數tx_threadx_resume
9.13 ThreadX的任務復位函數tx_threadx_reset
9.14 ThreadX的任務終止函數tx_threadx_terminate
9.15 實驗例程說明
9.16 總結
9.1 單任務系統
學習多任務系統之前,我們先來回顧下單任務系統的編程框架,即裸機時的編程框架。裸機編程主要是采用超級循環(super-loops)系統,又稱前后台系統。應用程序是一個無限的循環,循環中調用相應的函數完成相應的操作,這部分可以看做后台行為;中斷服務程序處理異步事件,這部分可以看做是前台行為。后台也可以叫做任務級,前台也叫作中斷級。
對於前后台系統的編程思路主要有以下兩種方式:
9.1.1 查詢方式
對於一些簡單的應用,處理器可以查詢數據或者消息是否就緒,就緒后進行處理,然后再等待,如此循環下去。對於簡單的任務,這種方式簡單易處理。但大多數情況下,需要處理多個接口數據或者消息,那就需要多次處理,如下面的流程圖所示:
用查詢方式處理簡單的應用,效果比較好,但是隨着工程的復雜,采用查詢方式實現的工程就變得很難維護,同時,由於無法定義查詢任務的優先級,這種查詢方式會使得重要的接口消息得不到及時響應。比如程序一直在等待一個非緊急消息就緒,如果這個消息后面還有一個緊急的消息需要處理,那么就會使得緊急消息長時間得不到執行。
9.1.2 中斷方式
對於查詢方式無法有效執行緊急任務的情況,采用中斷方式就有效地解決了這個問題,下面是中斷方式簡單的流程圖:
采用中斷和查詢結合的方式可以解決大部分裸機應用,但隨着工程的復雜,裸機方式的缺點就暴露出來了:
1、 必須在中斷(ISR)內處理時間關鍵運算:
- ISR 函數變得非常復雜,並且需要很長執行時間。
- ISR 嵌套可能產生不可預測的執行時間和堆棧需求。
2、 超級循環和ISR之間的數據交換是通過全局共享變量進行的:
- 應用程序的程序員必須確保數據一致性。
3、 超級循環可以與系統計時器輕松同步,但:
- 如果系統需要多種不同的周期時間,則會很難實現。
- 超過超級循環周期的耗時函數需要做拆分。
- 增加軟件開銷,應用程序難以理解。
4、 超級循環使得應用程序變得非常復雜,因此難以擴展:
- 一個簡單的更改就可能產生不可預測的副作用,對這種副作用進行分析非常耗時。
- 超級循環概念的這些缺點可以通過使用實時操作系統 (RTOS) 來解決。
9.2 多任務系統
針對這些情況,使用多任務系統就可以解決這些問題了。下面是一個多任務系統的流程圖:
多任務系統或者說RTOS的實現,重點就在這個調度器上,而調度器的作用就是使用相關的調度算法來決定當前需要執行的任務。如上圖所示的那樣,創建了任務並完成OS初始化后,就可以通過調度器來決定任務A,任務B和任務C的運行,從而實現多任務系統。另外需要初學者注意的是,這里所說的多任務系統同一時刻只能有一個任務可以運行,只是通過調度器的決策,看起來像所有任務同時運行一樣。為了更好的說明這個問題,再舉一個詳細的運行例子,運行條件如下:
- 使用搶占式調度器。
- 1個空閑任務,優先級最低。
- 2個應用任務,一個高優先級和一個低優先級,優先級都比空閑任務優先級高。
- 中斷服務程序,含USB中斷,串口中斷和系統滴答定時器中斷。
下圖所示是任務的運行過程,其中橫坐標是任務優先級由低到高排列,縱坐標是運行時間,時間刻度有小到大。
(1) 啟動RTOS,首先執行高優先級任務(tx_kernel_enter)。
(2) 高優先級任務等待事件標志(tx_event_flags_gets)被阻塞,低優先級任務得到執行。
(3) 低優先級任務執行的過程中產生USB中斷,進入USB中斷服務程序。
(4) 退出USB中斷復位程序,回到低優先級任務繼續執行。
(5) 低優先級任務執行過程中產生串口接收中斷,進入串口接收中斷服務程序。
(6) 退出串口接收中斷復位程序,並發送事件標志設置消息(tx_event_flags_set),被阻塞的高優先級任務就會重新進入就緒狀態,這個時候高優先級任務和低優先級任務都在就緒態,搶占式調度器就會讓高優先級的任務先執行,所以此時就會進入高優先級任務。
(7) 高優先級任務由於等待事件標志(tx_event_flags_gets)會再次被阻塞,低優先級任務開始繼續執行。
(8) 低優先級任務調用函數tx_thread_sleep,低優先級任務被掛起,從而空閑任務得到執行。
(9) 空閑任務執行期間發生滴答定時器中斷,進入滴答定時器中斷服務程序。
(10) 退出滴答定時器中斷,由於低優先級任務延時時間到,低優先級任務繼續執行。
(11) 低優先級任務再次調用延遲函數tx_thread_sleep,低優先級任務被掛起,從而切換到空閑任務。空閑任務得到執行。
通過上面實例的講解,大家應該對多任務系統完整的運行過程有了一個全面的認識。隨着教程后面對調度器,任務切換等知識點的講解,大家會對這個運行過程有更深刻的理解。
9.3 ThreadX的任務棧設置
不管是裸機編程還是RTOS編程,棧的分配大小都非常重要。局部變量,函數調用時的現場保護和返回地址,函數的形參,進入中斷函數前和中斷嵌套等都需要棧空間,棧空間定義小了會造成系統崩潰。
裸機的情況下,用戶可以在這里配置棧大小:
不同於裸機編程,在RTOS下,每個任務都有自己的棧空間。對於ThreadX來說,支持動態內存分配方式和靜態分配方式,本教程全部是靜態分配方式。
具體每個任務的棧大小是在創建ThreadX的任務時進行設置的:
/* ********************************************************************************************************* * 任務棧大小,單位字節 ********************************************************************************************************* */ #define APP_CFG_TASK_START_STK_SIZE 4096u #define APP_CFG_TASK_MsgPro_STK_SIZE 4096u #define APP_CFG_TASK_COM_STK_SIZE 4096u #define APP_CFG_TASK_USER_IF_STK_SIZE 4096u #define APP_CFG_TASK_IDLE_STK_SIZE 1024u #define APP_CFG_TASK_STAT_STK_SIZE 1024u /* ********************************************************************************************************* * 函 數 名: tx_application_define * 功能說明: ThreadX專用的任務創建,通信組件創建函數 * 形 參: first_unused_memory 未使用的地址空間 * 返 回 值: 無 ********************************************************************************************************* */ void tx_application_define(void *first_unused_memory) { /**************創建啟動任務*********************/ tx_thread_create(&AppTaskStartTCB, /* 任務控制塊地址 */ "App Task Start", /* 任務名 */ AppTaskStart, /* 啟動任務函數地址 */ 0, /* 傳遞給任務的參數 */ &AppTaskStartStk[0], /* 堆棧基地址 */ APP_CFG_TASK_START_STK_SIZE, /* 堆棧空間大小 */ APP_CFG_TASK_START_PRIO, /* 任務優先級*/ APP_CFG_TASK_START_PRIO, /* 任務搶占閥值 */ TX_NO_TIME_SLICE, /* 不開啟時間片 */ TX_AUTO_START); /* 創建后立即啟動 */ /**************創建統計任務*********************/ tx_thread_create(&AppTaskStatTCB, /* 任務控制塊地址 */ "App Task STAT", /* 任務名 */ AppTaskStat, /* 啟動任務函數地址 */ 0, /* 傳遞給任務的參數 */ &AppTaskStatStk[0], /* 堆棧基地址 */ APP_CFG_TASK_STAT_STK_SIZE, /* 堆棧空間大小 */ APP_CFG_TASK_STAT_PRIO, /* 任務優先級*/ APP_CFG_TASK_STAT_PRIO, /* 任務搶占閥值 */ TX_NO_TIME_SLICE, /* 不開啟時間片 */ TX_AUTO_START); /* 創建后立即啟動 */ /**************創建空閑任務*********************/ tx_thread_create(&AppTaskIdleTCB, /* 任務控制塊地址 */ "App Task IDLE", /* 任務名 */ AppTaskIDLE, /* 啟動任務函數地址 */ 0, /* 傳遞給任務的參數 */ &AppTaskIdleStk[0], /* 堆棧基地址 */ APP_CFG_TASK_IDLE_STK_SIZE, /* 堆棧空間大小 */ APP_CFG_TASK_IDLE_PRIO, /* 任務優先級*/ APP_CFG_TASK_IDLE_PRIO, /* 任務搶占閥值 */ TX_NO_TIME_SLICE, /* 不開啟時間片 */ TX_AUTO_START); /* 創建后立即啟動 */ }
實際應用中給任務開辟多大的堆棧空間合適呢,在后面章詳細跟大家進行講解。
9.4 ThreadX的系統棧設置
上面跟大家講解了什么是任務棧,這里的系統棧又是什么呢?裸機的情況下,凡是用到棧空間的地方都是在這里配置的棧空間:
在RTOS下,上面截圖中設置的棧大小有了一個新的名字叫系統棧空間,而任務棧是不使用這里的空間的。任務棧不使用這里的棧空間,哪里使用這里的棧空間呢?答案就在中斷函數和中斷嵌套。
對於這個問題,簡單的描述如下,更詳細的內容待我們講解ThreadX任務切換和雙堆棧指針時再細說。
1、 由於Cortex-M3,M4,M7內核具有雙堆棧指針,MSP主堆棧指針和PSP進程堆棧指針,或者叫PSP任務堆棧指針也是可以的。在ThreadX操作系統中,主堆棧指針MSP是給系統棧空間使用的,進程堆棧指針PSP是給任務棧使用的。也就是說,在ThreadX任務中,所有棧空間的使用都是通過PSP指針進行指向的。一旦進入了中斷函數以及可能發生的中斷嵌套都是用的MSP指針。這個知識點要記住它,當前可以不知道這是為什么,但是一定要記住。
2、 實際應用中系統棧空間分配多大,主要是看可能發生的中斷嵌套層數,下面我們就按照最壞執行情況進行考慮,所有的寄存器都需要入棧,此時分為兩種情況:
- 64字節
對於Cortex-M3內核和未使用FPU(浮點運算單元)功能的Cortex-M4/M7內核在發生中斷時需要將16個通用寄存器全部入棧,每個寄存器占用4個字節,也就是16*4 = 64字節的空間。
可能發生幾次中斷嵌套就是要64乘以幾即可。當然,這種是最壞執行情況,也就是所有的寄存器都入棧。
(注:任務執行的過程中發生中斷的話,有8個寄存器是自動入棧的,這個棧是任務棧,進入中斷以后其余寄存器入棧以及發生中斷嵌套都是用的系統棧)
- 200字節
對於具有FPU(浮點運算單元)功能的Cortex-M4/M7內核,如果在任務中進行了浮點運算,那么在發生中斷的時候除了16個通用寄存器需要入棧,還有34個浮點寄存器也是要入棧的,也就是(16+34)*4 = 200字節的空間。當然,這種是最壞執行情況,也就是所有的寄存器都入棧。
(注:任務執行的過程中發送中斷的話,有8個通用寄存器和18個浮點寄存器是自動入棧的,這個棧是任務棧,進入中斷以后其余通用寄存器和浮點寄存器入棧以及發生中斷嵌套都是用的系統棧)
9.5 ThreadX的任務狀態
ThreadX有五種不同的線程狀態:Ready State就緒態,Suspended State掛起狀態,Executing State執行態,Terminated State終止執行態和Complete State完成態。:
- Executing State執行態
當任務處於實際運行狀態被稱之為執行態,即CPU的使用權被這個任務占用。
- Ready State就緒態
處於就緒態的任務是指那些能夠運行(沒有被掛起),但是當前沒有運行的任務,因為同優先級或更高優先級的任務正在運行。
- Suspended State掛起態
ThreadX的掛起包含了阻塞,即由於等待信號量,消息隊列,事件標志組等而處於的狀態也是掛起態,
任務調用延遲函數或者對任務進行掛起操作(有專門的掛起函數)也會處於掛起狀態。
- Completed State完成態
任務返回的狀態稱之為完成態,正常情況下每個任務是死循環,獨立執行,不會返回。
- Terminated State終止態
終止任務執行的狀態稱之為終止態。
9.6 ThreadX的啟動流程圖示
ThreadX啟動流程如下:
9.7 ThreadX的空閑任務
ThreadX中沒有空閑任務,不過用戶可以自己創建一個。使用空閑任務主要有以下幾個作用:
- 用戶不能讓系統一直在執行各個應用任務,這樣的話系統利用率就是 100%,系統就會一直超負荷運行,所以空閑任務很有必要。
- 為了更好的實現低功耗,空閑任務也很有必要,用戶可以在空閑任務中實現睡眠,停機等低功耗措施。
9.8 ThreadX的啟動函數tx_kernel_enter
函數原型:
#define tx_kernel_enter _tx_initialize_kernel_enter VOID _tx_initialize_kernel_enter(VOID)
函數描述:
函數tx_kernel_enter用於啟動ThreadX調度器,即啟動ThreadX的多任務執行。 此函數是ThreadX初始化階段第1個調用的函數。
此函數依次調用了下面四個主要函數:
- _tx_initialize_low_level :主要用於初始化滴答定時器,使能PendSV,SVC和Systick中斷。
- _tx_initialize_high_level:主要用於初始化信號量,事件標志組,消息隊列等。另外會根據是否使能了宏定義TX_NO_TIMER來創建一個定時器任務。
- tx_application_define:應用程序回調函數,用戶可以在里面創建任務,創建各種通信機制。
- _tx_thread_scheduler:啟動ThreadX調度器。
注意事項:
- 正常情況下這個函數是不會返回的,如果返回了,說明啟動失敗。
使用舉例:
/* ********************************************************************************************************* * 函 數 名: main * 功能說明: 標准c程序入口。 * 形 參: 無 * 返 回 值: 無 ********************************************************************************************************* */ int main(void) { /* HAL庫,MPU,Cache,時鍾等系統初始 */ System_Init(); /* 內核開啟前關閉HAL的時間基准 */ HAL_SuspendTick(); /* 進入ThreadX內核 */ tx_kernel_enter(); while(1); }
9.9 ThreadX的任務創建函數tx_thread_create
函數原型:
#define tx_thread_create(t,n,e,i,s,l,p,r,c,a) _txe_thread_create((t),(n),(e),(i),(s),(l),(p),(r),(c),(a),(sizeof(TX_THREAD))) UINT _txe_thread_create(TX_THREAD *thread_ptr, CHAR *name_ptr, VOID (*entry_function)(ULONG id), ULONG entry_input, VOID *stack_start, ULONG stack_size, UINT priority, UINT preempt_threshold, ULONG time_slice, UINT auto_start, UINT thread_control_block_size)
函數描述:
函數tx_thread_create用於實現ThreadX操作系統的任務創建,並且還可以自定義任務棧的大小。
函數形參:
- 第1個參數thread_ptr是任務控制塊地址。
- 第2個參數name_ptr是任務名,這個參數主要是用於調試目的,調試的時候方便看是哪個任務。
- 第3個參數entry_function是任務函數地址。當任務從此入口函數返回時,它將處於Complete State完成態,並無限掛起。
- 第4個參數entry_input是傳遞給任務的形參。
- 第5個參數stack_start棧基地址。
- 第6個參數stack_size是棧大小,單位字節,主要被函數嵌套調用和局部變量使用。
- 第7個參數priority是任務優先級,范圍0到(TX_MAX_PRIORITES-1),其中0表示最高優先級。
- 第8個參數preempt_threshold是搶占閥值,范圍0到(TX_MAX_PRIORITES-1)。只有高於此級別的優先級才可以搶占該任務。此數值必須小於或等於該任務的優先級數值。如果設置為等於該任務的優先級數值,將禁用搶占閾值。
- 第9個參數time_slice是時間片大小。
- 第10個參數auto_start是指定線程是立即啟動還是處於掛起狀態。
- TX_AUTO_START(0x01)立即啟動。
- TX_DONT_START(0x00)掛起狀態。
如果指定了TX_DONT_START,則應用程序以后必須調用tx_thread_resume才能運行線程。
- 返回值:
- TX_SUCCESS(0x00)成功創建線程。
- TX_THREAD_ERROR(0x0E)無效的任務控制塊指針。指針為NULL或任務已創建。
- TX_PTR_ERROR(0x03)任務函數地址或棧的起始地址無效,通常為NULL。
- TX_SIZE_ERROR(0x05)棧區域的大小無效。任務必須至少具有TX_MINIMUM_STACK字節才能執行。
- TX_PRIORITY_ERROR(0x0F)無效的任務優先級,該值超出(0到(TX_MAX_PRIORITIES-1))范圍。
- TX_THRESH_ERROR(0x18)指定了無效的搶占閾值。該值的有效優先級必須小於或等於該任務的初始優先級數值。
- TX_START_ERROR(0x10)無效的auto_start參數。
- TX_CALLER_ERROR(0x13)無效調用。
注意事項:
- 不允許在中斷服務程序中調用,只可以在初始化和任務中調用。
- 使用搶占閾值將禁用時間片。合法的時間片值范圍是1到0xFFFFFFFF(包括0)。值為TX_NO_TIME_SLICE(值為0)將禁用此任務的時間切片。
- 使用時間分片會導致少量系統開銷。由於時間片僅在多個線程共享相同優先級的情況下才有用,因此,具有唯一優先級的任務不要分配時間片。
使用舉例:
/* ********************************************************************************************************* * 任務優先級,數值越小優先級越高 ********************************************************************************************************* */ #define APP_CFG_TASK_START_PRIO 2u /* ********************************************************************************************************* * 任務棧大小,單位字節 ********************************************************************************************************* */ #define APP_CFG_TASK_START_STK_SIZE 4096u /* ********************************************************************************************************* * 靜態全局變量 ********************************************************************************************************* */ static TX_THREAD AppTaskStartTCB; static uint64_t AppTaskStartStk[APP_CFG_TASK_START_STK_SIZE/8]; tx_thread_create(&AppTaskStartTCB, /* 任務控制塊地址 */ "App Task Start", /* 任務名 */ AppTaskStart, /* 啟動任務函數地址 */ 0, /* 傳遞給任務的參數 */ &AppTaskStartStk[0], /* 堆棧基地址 */ APP_CFG_TASK_START_STK_SIZE, /* 堆棧空間大小 */ APP_CFG_TASK_START_PRIO, /* 任務優先級*/ APP_CFG_TASK_START_PRIO, /* 任務搶占閥值 */ TX_NO_TIME_SLICE, /* 不開啟時間片 */ TX_AUTO_START); /* 創建后立即啟動 */
9.10 ThreadX的任務刪除函數tx_thread_delete
函數原型:
#define tx_thread_delete _txe_thread_delete UINT _txe_thread_delete(TX_THREAD *thread_ptr)
函數描述:
函數tx_thread_delete用於實現ThreadX操作系統的任務刪除。
- 第1個參數填要刪除的任務控制塊地址。
- 返回值:
- TX_SUCCESS(0x00)成功刪除任務。
- TX_THREAD_ERROR(0x0E)無效的任務控制塊指針。
- TX_DELETE_ERROR(0x11)指定的任務未處於Terminated終止態或者Completed完成態。
- TX_CALLER_ERROR(0x13)無效調用者。
注意事項:
- 不允許在中斷服務程序中調用,只可以在任務和定時器組中調用。
- 只能刪除處於Terminated終止態或者Completed完成態的任務。因此也就不可以在要刪除的任務中調用此函數,也就是自己刪除自己。
使用舉例:
/* 任務控制塊 */ static TX_THREAD AppTaskStartTCB; tx_thread_delete(&AppTaskCOMTCB);
9.11ThreadX的任務掛起函數tx_thread_suspend
函數原型:
#define tx_thread_suspend _txe_thread_suspend UINT _txe_thread_suspend(TX_THREAD *thread_ptr)
函數描述:
函數tx_thread_suspend用於實現ThreadX操作系統的任務掛起。任務也可以掛起自己。掛起后,可以通過tx_thread_resume恢復。
函數形參:
- 第1個參數填要掛起任務的任務控制塊。
- 返回值:
- TX_SUCCESS(0x00)成功的任務掛起。
- TX_THREAD_ERROR(0x0E)無效的任務控制塊指針。
- TX_SUSPEND_ERROR(0x14)指定的線程處於終止或完成狀態。
- TX_CALLER_ERROR(0x13)無效調用者。
注意事項:
- 允許在中斷,任務,定時器組和初始化中調用。
- 如果指定的任務由於其它原因已經掛起,則本次掛起將被保存,直到之前的掛起已經恢復。當發生這種情況時,將執行指定任務的無條件掛起,之后的無條件掛起請求將無效。
使用舉例:
/* 任務控制塊 */ static TX_THREAD AppTaskStartTCB; tx_thread_suspend(&AppTaskCOMTCB);
9.12 ThreadX的任務恢復函數tx_thread_resume
函數原型:
#define tx_thread_resume _txe_thread_resume UINT _txe_thread_resume(TX_THREAD *thread_ptr)
函數描述:
函數tx_thread_resume用於實現ThreadX操作系統的任務恢復。另外,此任務還將恢復在沒有自動啟動的情況下創建的任務。
函數形參:
- 第1個參數填要恢復的任務控制塊地址。
- 返回值:
- TX_SUCCESS(0x00)成功的恢復任務。
- TX_SUSPEND_LIFTED(0x19)先前設置的延遲暫停已取消。
- TX_THREAD_ERROR(0x0E)無效的任務控制地址。
- TX_RESUME_ERROR(0x12)指定的任務沒有被掛起,或者之前被tx_thread_suspend以外的服務掛起。
注意事項:
- 允許在中斷,任務,定時器組和初始化中調用。
使用舉例:
/* 任務控制塊 */ static TX_THREAD AppTaskStartTCB; tx_thread_resume(&AppTaskCOMTCB);
9.13 ThreadX的任務復位函數tx_thread_reset
函數原型:
#define tx_thread_resume _txe_thread_resume UINT _txe_thread_resume(TX_THREAD *thread_ptr) #define tx_thread_reset _txe_thread_reset
函數描述:
函數tx_thread_reset用於實現ThreadX操作系統的任務復位。任務必須處於TX_COMPLETED完成態或TX_TERMINATED終止態才能復位。
函數形參:
- 第1個參數填要恢復的任務控制塊地址。
- 返回值:
- TX_SUCCESS(0x00)成功復位任務。
- TX_NOT_DONE(0x20)指定的線程未處於TX_COMPLETED或TX_TERMINATED狀態。
- TX_THREAD_ERROR(0x0E)無效的任務控制塊指針。
- TX_CALLER_ERROR(0x13)無效調用者。
注意事項:
- 不允許在中斷中調用,僅可以在任務中調用。
使用舉例:
/* 任務控制塊 */ static TX_THREAD AppTaskStartTCB; tx_thread_reset(&AppTaskCOMTCB);
9.14 ThreadX的任務終止函數tx_thread_terminate
函數原型:
#define tx_thread_terminate _txe_thread_terminate UINT _txe_thread_terminate(TX_THREAD *thread_ptr)
函數描述:
函數tx_thread_terminate用於實現ThreadX操作系統的任務終止。該函數終止指定任務,而不管該任務是否被掛起。任務可以調用此函數以終止自身。
函數形參:
- 第1個參數填要恢復的任務控制塊地址。
- 返回值:
- TX_SUCCESS(0x00)成功終止任務。
- TX_THREAD_ERROR(0x0E)無效的任務控制塊指針。
- TX_CALLER_ERROR(0x13)無效調用者。
注意事項:
- 不允許在中斷中調用,僅可以在任務和定時器組中調用。
- 終止后,必須調用函數tx_thread_reset復位任務以使其再次執行。
- 應用程序有責任確保任務處於適合終止的狀態。例如,任務不應在關鍵應用程序處理期間或在其他中間件組件內部終止,否則可能會使這種處理處於未知狀態。
使用舉例:
/* 任務控制塊 */ static TX_THREAD AppTaskStartTCB; tx_thread_terminate(&AppTaskCOMTCB);
9.15 實驗例程
配套例子:
V7-3004_ThreadX Task Control
實驗目的:
- 學習hreadX任務管理。
實驗內容:
1、共創建了如下幾個任務,通過按下按鍵K1可以通過串口或者RTT打印任務堆棧使用情況
===================================================
OS CPU Usage = 1.94%
=======================================================
Prio StackSize CurStack MaxStack Taskname
2 4092 383 391 App Task Start
3 4092 543 659 App Msp Pro
4 4092 391 391 App Task UserIF
5 4092 543 659 App Task COM
30 1020 519 519 App Task STAT
31 1020 143 71 App Task IDLE
0 1020 391 391 System Timer Thread
串口軟件可以使用SecureCRT或者H7-TOOL RTT查看打印信息。
App Task Start任務 :啟動任務,這里用作BSP驅動包處理。
App Task MspPro任務 :消息處理,這里未使用。
App Task UserIF任務 :按鍵消息處理。
App Task COM任務 :這里用作LED閃爍。
App Task STAT任務 :統計任務
App Task IDLE任務 :空閑任務
System Timer Thread任務:系統定時器任務
2、 (1) 凡是用到printf函數的全部通過函數App_Printf實現。
(2) App_Printf函數做了信號量的互斥操作,解決資源共享問題。
3、默認上電是通過串口打印信息,如果使用RTT打印信息
(1) MDK AC5,MDK AC6或IAR通過使能bsp.h文件中的宏定義為1即可
#define Enable_RTTViewer 1
(2) Embedded Studio繼續使用此宏定義為0, 因為Embedded Studio僅制作了調試狀態RTT方式查看。
實驗操作:
- K1按鍵按下打印任務執行情況。
- K2按鍵按下掛起任務App Task COM。
- K3按鍵按下恢復任務App Task COM。
- 搖桿OK按鍵按下復位任務App Task COM。
串口打印信息方式(AC5,AC6和IAR):
波特率 115200,數據位 8,奇偶校驗位無,停止位 1
RTT打印信息方式(AC5,AC6和IAR):
Embedded Studio僅支持調試狀態RTT打印:
由於Embedded Studio不支持中文,所以中文部分顯示亂碼,不用管。
程序執行框圖:
9.16 總結
本章節主要為大家講解了ThreadX的任務管理,此章節比較重要,望初學者用心掌握。