【STM32F407】第8章 RTX5任務優先順序分配和修改

2022-01-05 10:00:33

論壇原始地址(持續更新):【安富萊】RTX5核心教學,採用CMSIS-RTOS V2封裝層,已經更新發布至第9章 (2021-12-27) - STM32H7 - 硬漢嵌入式論壇 - Powered by Discuz!

第8章   RTX5任務優先順序分配和修改

本章節主要為大家講解RTX5任務優先順序設定的注意事項,任務優先順序的分配方案及其相關的一個例子,內容相對比較簡單。

目錄

8.1   RTX5支援的優先順序設定

8.2   任務優先順序分配方案

8.3   任務優先順序設定函數osThreadSetPriority

8.4   任務優先順序獲取函數osThreadGetPriority

8.5   實驗例程說明

8.6   總結


8.1   RTX5支援的優先順序設定

RTX5作業系統支援的優先順序設定如下:

/// Priority values.
typedef enum {
  osPriorityNone          =  0,         ///< No priority (not initialized).
  osPriorityIdle          =  1,         ///< Reserved for Idle thread.
  osPriorityLow           =  8,         ///< Priority: low
  osPriorityLow1          =  8+1,       ///< Priority: low + 1
  osPriorityLow2          =  8+2,       ///< Priority: low + 2
  osPriorityLow3          =  8+3,       ///< Priority: low + 3
  osPriorityLow4          =  8+4,       ///< Priority: low + 4
  osPriorityLow5          =  8+5,       ///< Priority: low + 5
  osPriorityLow6          =  8+6,       ///< Priority: low + 6
  osPriorityLow7          =  8+7,       ///< Priority: low + 7
  osPriorityBelowNormal   = 16,         ///< Priority: below normal
  osPriorityBelowNormal1  = 16+1,       ///< Priority: below normal + 1
  osPriorityBelowNormal2  = 16+2,       ///< Priority: below normal + 2
  osPriorityBelowNormal3  = 16+3,       ///< Priority: below normal + 3
  osPriorityBelowNormal4  = 16+4,       ///< Priority: below normal + 4
  osPriorityBelowNormal5  = 16+5,       ///< Priority: below normal + 5
  osPriorityBelowNormal6  = 16+6,       ///< Priority: below normal + 6
  osPriorityBelowNormal7  = 16+7,       ///< Priority: below normal + 7
  osPriorityNormal        = 24,         ///< Priority: normal
  osPriorityNormal1       = 24+1,       ///< Priority: normal + 1
  osPriorityNormal2       = 24+2,       ///< Priority: normal + 2
  osPriorityNormal3       = 24+3,       ///< Priority: normal + 3
  osPriorityNormal4       = 24+4,       ///< Priority: normal + 4
  osPriorityNormal5       = 24+5,       ///< Priority: normal + 5
  osPriorityNormal6       = 24+6,       ///< Priority: normal + 6
  osPriorityNormal7       = 24+7,       ///< Priority: normal + 7
  osPriorityAboveNormal   = 32,         ///< Priority: above normal
  osPriorityAboveNormal1  = 32+1,       ///< Priority: above normal + 1
  osPriorityAboveNormal2  = 32+2,       ///< Priority: above normal + 2
  osPriorityAboveNormal3  = 32+3,       ///< Priority: above normal + 3
  osPriorityAboveNormal4  = 32+4,       ///< Priority: above normal + 4
  osPriorityAboveNormal5  = 32+5,       ///< Priority: above normal + 5
  osPriorityAboveNormal6  = 32+6,       ///< Priority: above normal + 6
  osPriorityAboveNormal7  = 32+7,       ///< Priority: above normal + 7
  osPriorityHigh          = 40,         ///< Priority: high
  osPriorityHigh1         = 40+1,       ///< Priority: high + 1
  osPriorityHigh2         = 40+2,       ///< Priority: high + 2
  osPriorityHigh3         = 40+3,       ///< Priority: high + 3
  osPriorityHigh4         = 40+4,       ///< Priority: high + 4
  osPriorityHigh5         = 40+5,       ///< Priority: high + 5
  osPriorityHigh6         = 40+6,       ///< Priority: high + 6
  osPriorityHigh7         = 40+7,       ///< Priority: high + 7
  osPriorityRealtime      = 48,         ///< Priority: realtime
  osPriorityRealtime1     = 48+1,       ///< Priority: realtime + 1
  osPriorityRealtime2     = 48+2,       ///< Priority: realtime + 2
  osPriorityRealtime3     = 48+3,       ///< Priority: realtime + 3
  osPriorityRealtime4     = 48+4,       ///< Priority: realtime + 4
  osPriorityRealtime5     = 48+5,       ///< Priority: realtime + 5
  osPriorityRealtime6     = 48+6,       ///< Priority: realtime + 6
  osPriorityRealtime7     = 48+7,       ///< Priority: realtime + 7
  osPriorityISR           = 56,         ///< Reserved for ISR deferred thread.
  osPriorityError         = -1,         ///< System cannot determine priority or illegal priority.
  osPriorityReserved      = 0x7FFFFFFF  ///< Prevents enum down-size compiler optimization.
} osPriority_t;

大家設定任務優先順序的時候需要呼叫這些指定的優先順序,其中osPriorityIdle是最低優先順序,供空閒任務使用,而osPriorityRealtime7是最高優先順序。

8.2   任務優先順序分配方案

對於初學者,有時候會糾結任務優先順序設定為多少合適,因為任務優先順序設定多少是沒有標準的。對於這個問題,RTX5有一個推薦的設定標準,任務優先順序設定推薦方式如下圖8.1所示:

 圖8.1 任務優先順序分配方案

  •   IRQ任務:IRQ任務是指通過中斷服務程式進行觸發的任務,此類任務應該設定為所有任務裡面優先順序最高的。
  •   高優先順序後臺任務:比如按鍵檢測,觸控檢測,USB訊息處理,串列埠訊息處理等,都可以歸為這一類任務。
  •   低優先順序的時間片排程任務:比如emWin的介面顯示,LED數碼管的顯示等不需要實時執行的都可以歸為這一類任務。實際應用中使用者不必拘泥於將這些任務都設定為優先順序1的同優先順序任務,可以設定多個優先順序,只需注意這類任務不需要高實時性。
  •   空閒任務:空閒任務是系統任務。
  •   特別注意:IRQ任務和高優先順序任務必須設定為阻塞式(呼叫訊息等待或者延遲等函數即可),只有這樣高優先順序任務才會釋放CPU的使用權,從低優先順序任務才有機會得到執行。

這裡的優先順序分配方案是RTX作業系統推薦的一種方式,實際專案也可以不採用這種方法。偵錯出適合專案需求的才是最好的。

8.3   任務優先順序設定函數osThreadSetPriority

函數原型:

osStatus_t osThreadSetPriority(osThreadId_t    thread_id,

osPriority_t   priority )   

函數描述:

此函數用於修改任務的優先順序。

函數引數:

1、  第1個引數填任務的ID。

2、  第2個引數是任務優先順序。

3、  返回值:

  •   osOK: 任務優先順序修改成功。
  •   osErrorParameter: 任務ID是NULL或者優先順序無效。
  •   osErrorResource: 任務處於無效狀態。
  •   osErrorISR: 此函數不可以在中斷服務程式裡面呼叫。

使用舉例:

/*
**********************************************************************************************************
											 變數
**********************************************************************************************************
*/
static uint64_t AppTaskUserIFStk[512/8];  /* 任務棧 */

/* 任務控制程式碼 */
OS_TID HandleTaskUserIF = NULL;
/*
*********************************************************************************************************
*	函 數 名: AppTaskChangePrio
*	功能說明: 修改任務優先順序
*	形    參: 無
*	返 回 值: 無
*********************************************************************************************************
*/
static void AppTaskDelete (void)
{
	HandleTaskUserIF = os_tsk_create_user(AppTaskUserIF,             /* 任務函數 */ 
	                                      1,                         /* 任務優先順序 */ 
	                                      &AppTaskUserIFStk,         /* 任務棧 */
	                                      sizeof(AppTaskUserIFStk)); /* 任務棧大小,單位位元組數 */

	if(os_tsk_prio(HandleTaskLED, 3) == OS_R_OK)
	{
		printf("任務AppTaskLED優先順序修改成功\r\n");
	}
	else
	{
		printf("任務AppTaskLED優先順序修改失敗\r\n");					
	}
	
}

8.4   任務優先順序獲取函數osThreadGetPriority

函數原型:

osPriority_t osThreadGetPriority (osThreadId_t thread_id )

函數描述:

此函數用於獲取任務的優先順序。

函數引數:

1、  第1個引數填任務的ID。

2、  返回值:

  •   正常情況下,可以返回任務優先順序。
  •   osPriorityError 任務優先順序無法確定或者非法的,如果是在中斷服務程式裡面呼叫此函數也返回錯誤。

使用舉例:

/*
**********************************************************************************************************
											 變數
**********************************************************************************************************
*/
static uint64_t AppTaskUserIFStk[512/8];  /* 任務棧 */

/* 任務控制程式碼 */
OS_TID HandleTaskUserIF = NULL;
/*
*********************************************************************************************************
*	函 數 名: AppTaskChangePrio
*	功能說明: 修改任務優先順序
*	形    參: 無
*	返 回 值: 無
*********************************************************************************************************
*/
static void AppTaskDelete (void)
{
	HandleTaskUserIF = os_tsk_create_user(AppTaskUserIF,             /* 任務函數 */ 
	                                      1,                         /* 任務優先順序 */ 
	                                      &AppTaskUserIFStk,         /* 任務棧 */
	                                      sizeof(AppTaskUserIFStk)); /* 任務棧大小,單位位元組數 */

	if(os_tsk_prio(HandleTaskLED, 3) == OS_R_OK)
	{
		printf("任務AppTaskLED優先順序修改成功\r\n");
	}
	else
	{
		printf("任務AppTaskLED優先順序修改失敗\r\n");					
	}
	
}

8.5   實驗例程說明

配套例子:

V5-404_RTX5 Task Priority

實驗目的:

  1. 學習RTX的任務優先順序設定。

實驗內容:

  1. K1鍵按下,設定任務優先順序為osPriorityHigh。
  2. K2鍵按下,設定任務優先順序為osPriorityHigh2。
  3. 各個任務實現的功能如下:

AppTaskUserIF任務   : 按鍵訊息處理。

AppTaskLED任務      : LED閃爍。

AppTaskMsgPro任務   : 訊息處理。

AppTaskStart任務      : 啟動任務,也是最高優先順序任務,這裡實現按鍵掃描。

osRtxTimerThread任務 : 定時器任務,暫未使用。

串列埠列印資訊:

波特率 115200,資料位 8,奇偶校驗位無,停止位 1。

 

RTX設定:

RTX設定向導詳情如下:

 

  System Configuration

  •   Global Dynamic Memory size

全域性動態記憶體,這裡設定為32KB。

  •   Kernel Tick Frequency

系統時鐘節拍,這裡設定為1KHz。

  Thread Configuration

  •   Default Thread Stack size

預設的任務棧大小,這裡設定為1024位元組

RTX5任務偵錯資訊:

 

程式設計:

  任務棧大小分配:

全部獨立設定,沒有使用RTX5預設設定:

/*
**********************************************************************************************************
											 變數
**********************************************************************************************************
*/
/* 任務的屬性設定 */
const osThreadAttr_t ThreadStart_Attr = 
{
	/* 未使用 */
//	.cb_mem = &worker_thread_tcb_1,
//	.cb_size = sizeof(worker_thread_tcb_1),
//	.stack_mem = &worker_thread_stk_1[0],
//	.stack_size = sizeof(worker_thread_stk_1),
//	.priority = osPriorityAboveNormal,
//	.tz_module = 0
	
	.name = "osRtxStartThread",
	.attr_bits = osThreadDetached, 
	.priority = osPriorityHigh4,
	.stack_size = 2048,
};

const osThreadAttr_t ThreadMsgPro_Attr = 
{
	.name = "osRtxMsgProThread",
	.attr_bits = osThreadDetached, 
	.priority = osPriorityHigh3,
	.stack_size = 1024,
};

const osThreadAttr_t ThreadLED_Attr = 
{
	.name = "osRtxLEDThread",
	.attr_bits = osThreadDetached, 
	.priority = osPriorityHigh2,
	.stack_size = 512,
};

const osThreadAttr_t ThreadUserIF_Attr = 
{
	.name = "osRtxThreadUserIF",
	.attr_bits = osThreadDetached, 
	.priority = osPriorityHigh1,
	.stack_size = 1024,
};

  系統棧大小分配:

 

  RTX5初始化:

/*
*********************************************************************************************************
*    函 數 名: main
*    功能說明: 標準c程式入口。
*    形    參: 無
*    返 回 值: 無
*********************************************************************************************************
*/
int main (void) 
{    
    /* HAL庫,MPU,Cache,時鐘等系統初始化 */
    System_Init();

    /* 核心開啟前關閉HAL的時間基準 */
    HAL_SuspendTick();
    
    /* 核心初始化 */
    osKernelInitialize();                                  

    /* 建立啟動任務 */
    ThreadIdStart = osThreadNew(AppTaskStart, NULL, &ThreadStart_Attr);  

    /* 開啟多工 */
    osKernelStart();
    
    while(1);
}

  RTX5任務建立:

/*
*********************************************************************************************************
*    函 數 名: AppTaskCreate
*    功能說明: 建立應用任務
*    形    參: 無
*    返 回 值: 無
*********************************************************************************************************
*/
static void AppTaskCreate (void)
{
    ThreadIdTaskMsgPro = osThreadNew(AppTaskMsgPro, NULL, &ThreadMsgPro_Attr);  
    ThreadIdTaskLED = osThreadNew(AppTaskLED, NULL, &ThreadLED_Attr);  
    ThreadIdTaskUserIF = osThreadNew(AppTaskUserIF, NULL, &ThreadUserIF_Attr);  
}

  四個RTX任務的實現:

/*
*********************************************************************************************************
*	函 數 名: AppTaskUserIF
*	功能說明: 按鍵訊息處理		
*	形    參: 無
*	返 回 值: 無
*   優 先 級: osPriorityHigh1 (數值越小優先順序越低,這個跟uCOS相反)
*********************************************************************************************************
*/
void AppTaskUserIF(void *argument)
{
	uint8_t ucKeyCode;

    while(1)
    {
		ucKeyCode = bsp_GetKey();
		
		if (ucKeyCode != KEY_NONE)
		{
			switch (ucKeyCode)
			{
				/* K1鍵按下,設定任務優先順序為osPriorityHigh */
				case KEY_DOWN_K1:
					printf("K1鍵按下,設定任務 HandleTaskLED的優先順序為osPriorityHigh\r\n");
                      osThreadSetPriority(ThreadIdTaskLED, osPriorityHigh);
printf("任務ThreadIdTaskLED的優先順序 = %d\r\n",osThreadGetPriority(ThreadIdTaskLED));
					break;
					
				/* K2鍵按下,設定任務優先順序為osPriorityHigh2 */
				case KEY_DOWN_K2:
					printf("K2鍵按下,設定任務 HandleTaskLED的優先順序為osPriorityHigh2\r\n");
                    osThreadSetPriority(ThreadIdTaskLED, osPriorityHigh2);
				  printf("任務ThreadIdTaskLED的優先順序 = %d\r\n", osThreadGetPriority(ThreadIdTaskLED));
					break;

				/* 其他的鍵值不處理 */
				default:                     
					break;
			}
		}
		
		osDelay(20);
	}
}

/*
*********************************************************************************************************
*	函 數 名: AppTaskLED
*	功能說明: LED閃爍。
*	形    參: 無
*	返 回 值: 無
*   優 先 級: osPriorityHigh2 
*********************************************************************************************************
*/
void AppTaskLED(void *argument)
{
	const uint16_t usFrequency = 200; /* 延遲週期 */
	uint32_t tick;

	/* 獲取當前時間 */
	tick = osKernelGetTickCount(); 
	
    while(1)
    {
		bsp_LedToggle(2);
		/* 相對延遲 */
		tick += usFrequency;                          
		osDelayUntil(tick);
    }
}

/*
*********************************************************************************************************
*	函 數 名: AppTaskMsgPro
*	功能說明: 訊息處理,暫時未用到。
*	形    參: 無
*	返 回 值: 無
*   優 先 級: osPriorityHigh3  
*********************************************************************************************************
*/
void AppTaskMsgPro(void *argument)
{
	while(1)
	{
		osDelay(10);
	}	
}

/*
*********************************************************************************************************
*	函 數 名: AppTaskStart
*	功能說明: 啟動任務,這裡用作BSP驅動包處理。
*	形    參: 無
*	返 回 值: 無
*   優 先 級: osPriorityHigh4  
*********************************************************************************************************
*/
void AppTaskStart(void *argument)
{
	const uint16_t usFrequency = 1; /* 延遲週期 */
	uint32_t tick;
	
	/* 初始化外設 */
	HAL_ResumeTick();
	bsp_Init();

	/* 建立任務 */
	AppTaskCreate();

	/* 獲取當前時間 */
	tick = osKernelGetTickCount(); 
	
    while(1)
    {
		/* 需要週期性處理的程式,對應裸機工程呼叫的SysTick_ISR */
		bsp_ProPer1ms();
		
		/* 相對延遲 */
		tick += usFrequency;                          
		osDelayUntil(tick);
    }
}

8.6   總結

本章節內容相對比較容易,重點是學習任務優先順序分配方案,隨著後面的學習,初學者需要慢慢積累這方面的經驗。