為了方便與UCOS對比,順序按照UCOS那篇編寫。 0、一些移植、系統相關 1、框架寫法(個人習慣相關) 1-1、main 函數里創建一個開始任務 1-2、開始任務里,創建我們要運行的多個任務 2、任務創建、掛起、刪除 2-0、相關配置 2-1、任務創建(動態) 2-2、任務掛起 2-3、任務解掛 ...
為了方便與UCOS對比,順序按照UCOS那篇編寫。
0、一些移植、系統相關
1、框架寫法(個人習慣相關)
1-1、main 函數里創建一個開始任務
int main(void) { 初始化外設 xTaskCreate(); //創建開始任務 vTaskStartScheduler(); //開啟任務調度 }
1-2、開始任務里,創建我們要運行的多個任務
void start_task(void *pvParameters) { taskENTER_CRITICAL(); //進入臨界區 xTaskCreate(); //創建任務 1 xTaskCreate(); //創建任務 2 xTaskCreate(); //創建任務 3 vTaskDelete(StartTask_Handler); //刪除開始任務 taskEXIT_CRITICAL(); //退出臨界區 }
2、任務創建、掛起、刪除
2-0、相關配置
#define configSUPPORT_DYNAMIC_ALLOCATION 1 //支持動態記憶體申請 //#define configSUPPORT_STATIC_ALLOCATION 1 //支持靜態記憶體申請 #define configTOTAL_HEAP_SIZE ((size_t)(20*1024)) //系統所有總的堆大小,heap_x.h需要,動態申請
2-1、任務創建(動態)
//==================任務創建巨集定義,便於修改================== #define START_TASK_PRIO 1 //任務優先順序 #define START_STK_SIZE 256 //任務堆棧大小 TaskHandle_t StartTask_Handler; //任務句柄 void start_task(void *pvParameters); //任務函數 //==================任務創建函數================== xTaskCreate((TaskFunction_t )start_task, //任務函數 (const char* )"start_task", //任務名稱 (uint16_t )START_STK_SIZE, //任務堆棧大小 (void* )NULL, //傳遞給任務函數的參數 (UBaseType_t )START_TASK_PRIO, //任務優先順序 (TaskHandle_t* )&StartTask_Handler); //任務句柄
2-2、任務掛起
vTaskSuspend(Task1Task_Handler); //掛起任務1
2-3、任務解掛
2-3-1、任務內任務解掛
vTaskResume(Task1Task_Handler); //恢復任務1
2-3-2、中斷內任務解掛
BaseType_t YieldRequired; YieldRequired=xTaskResumeFromISR(Task1Task_Handler); //恢復任務1 portYIELD_FROM_ISR(YieldRequired); //判斷是否需要調度到恢復的任務
2-4、任務刪除
vTaskDelete(Task1Task_Handler); //刪除任務1
2-5、任務創建(靜態)
2-5-1、靜態任務創建
//==================任務創建巨集定義,便於修改================== #define START_TASK_PRIO 1 //任務優先順序 #define START_STK_SIZE 128 //任務堆棧大小 StackType_t StartTaskStack[START_STK_SIZE]; //任務堆棧 StaticTask_t StartTaskTCB; //任務控制塊 TaskHandle_t StartTask_Handler; //任務句柄 void start_task(void *pvParameters); //任務函數 //==================任務創建函數================== StartTask_Handler=xTaskCreateStatic((TaskFunction_t )start_task, //任務函數 (const char* )"start_task", //任務名稱 (uint32_t )START_STK_SIZE, //任務堆棧大小 (void* )NULL, //傳遞給任務函數的參數 (UBaseType_t )START_TASK_PRIO, //任務優先順序 (StackType_t* )StartTaskStack, //任務堆棧 (StaticTask_t* )&StartTaskTCB); //任務控制塊
2-5-2、靜態創建任務還需實現 空閑任務、定時任務
//==================任務創建巨集定義,便於修改================== static StackType_t IdleTaskStack[configMINIMAL_STACK_SIZE]; //空閑任務任務堆棧 static StaticTask_t IdleTaskTCB; //空閑任務控制塊 static StackType_t TimerTaskStack[configTIMER_TASK_STACK_DEPTH]; //定時器服務任務堆棧 static StaticTask_t TimerTaskTCB; //定時器服務任務控制塊 //==================任務創建函數================== //獲取空閑任務地任務堆棧和任務控制塊記憶體 void vApplicationGetIdleTaskMemory(StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize) { *ppxIdleTaskTCBBuffer=&IdleTaskTCB; *ppxIdleTaskStackBuffer=IdleTaskStack; *pulIdleTaskStackSize=configMINIMAL_STACK_SIZE; } //獲取定時器服務任務的任務堆棧和任務控制塊記憶體 void vApplicationGetTimerTaskMemory(StaticTask_t **ppxTimerTaskTCBBuffer, StackType_t **ppxTimerTaskStackBuffer, uint32_t *pulTimerTaskStackSize) { *ppxTimerTaskTCBBuffer=&TimerTaskTCB; *ppxTimerTaskStackBuffer=TimerTaskStack; *pulTimerTaskStackSize=configTIMER_TASK_STACK_DEPTH; }
3、時間片輪轉
3-0、相關配置(時間片片長 即 1/Tick中斷頻率)
#define configUSE_PREEMPTION 1 //1使用搶占式內核,0使用協程 #define configUSE_TIME_SLICING 1 //1使能時間片調度(預設式使能的) #define configTICK_RATE_HZ (20) //時鐘節拍頻率,20HZ = 50ms
3-1、兩個任務優先順序相等
#define TASK1_TASK_PRIO 2 #define TASK1_STK_SIZE 128 TaskHandle_t Task1Task_Handler; void task1_task(void *pvParameters); #define TASK2_TASK_PRIO 2 #define TASK2_STK_SIZE 128 TaskHandle_t Task2Task_Handler; void task2_task(void *pvParameters);
4、鉤子函數。
4-0、相關配置
#define configUSE_IDLE_HOOK 1 //1,使用空閑鉤子;0,不使用 #define configUSE_TICK_HOOK 1 //1,使用時間片鉤子;0,不使用
4-1、自己實現鉤子函數
void vApplicationIdleHook( void ); //空閑鉤子函數 void vApplicationTickHook( void ); //時鐘節拍鉤子函數
5、軟體定時器
6、信號量
9、消息隊列
9-1、消息隊列創建
//================消息隊列巨集定義================ #define MESSAGE_Q_NUM 4 //發送數據的消息隊列的數量 #define MESSAGE_Q_ITEM_NUM 200 //每個消息的空間大小 QueueHandle_t Message_Queue; //信息隊列句柄 //================消息隊列創建================ Message_Queue=xQueueCreate(MESSAGE_Q_NUM,MESSAGE_Q_ITEM_NUM);
9-2、消息發送
9-2-1、任務內消息發送
u8 sendData[MESSAGE_Q_ITEM_NUM]; BaseType_t err; err=xQueueSend(Message_Queue,&senddata,10); //10為發送等待時間,有可能隊列已滿,err = errQUEUE_FULL 或 err = pdPASS
9-2-2、中斷內消息發送
u8 sendData[MESSAGE_Q_ITEM_NUM]; BaseType_t xHigherPriorityTaskWoken; xQueueSendFromISR(Message_Queue,sendData,&xHigherPriorityTaskWoken); //向隊列中發送數據,返回值,依然是 滿了或Pass,第三個參數是判斷高優先順序接受到隊列後,退出中斷,是否需要調度 portYIELD_FROM_ISR(xHigherPriorityTaskWoken);//如果需要的話進行一次任務切換
9-3、消息接收
9-3-1、任務內消息接收
u8 *receiveData; xQueueReceive(Message_Queue,receiveData,portMAX_DELAY) //返回值為pdPASS 或 errQUEUE_EMPTY,這裡等待時間用了portMAX_DELAY阻塞,所以不用再判斷了。
9-3-2、中斷內消息接收
u8 *receiveData; err=xQueueReceiveFromISR(Message_Queue,receiveData,&xTaskWokenByReceive); //向隊列中接受數據,返回值, FAIL或Pass,第三個參數是判斷高優先順序接受到隊列後,退出中斷,是否需要調度 portYIELD_FROM_ISR(xTaskWokenByReceive);//如果需要的話進行一次任務切換
9-4、隊列剩餘大小
u8 remain_size; //消息隊列剩餘大小 remain_size=uxQueueSpacesAvailable(Message_Queue); //得到隊列剩餘大小
9-5、隊列使用大小
u8 used_size; //消息隊列使用大小 used_size=uxQueueMessagesWaiting(Message_Queue); //得到隊列使用大小
================================================ 為了好與UCOS的文章對比,這些內容也放下麵================================================
1、中斷
1-0、相關配置
#ifdef __NVIC_PRIO_BITS #define configPRIO_BITS __NVIC_PRIO_BITS //STM32庫自帶 #else #define configPRIO_BITS 4 //STM32提供4Bit的中斷優先順序 #endif #define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 15 //中斷最低優先順序 #define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5 //系統可管理的最高中斷優先順序 #define configKERNEL_INTERRUPT_PRIORITY ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) ) //內核中斷優先順序,用來配置上下文切換、時鐘節拍優先順序,因為STM32優先順序寄存器用高4位,所以要左移 #define configMAX_SYSCALL_INTERRUPT_PRIORITY ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) ) //用來屏蔽中斷的閾值,左移原因同上 #define xPortPendSVHandler PendSV_Handler #define vPortSVCHandler SVC_Handler
1-1、中斷處理
無需特殊處理
2、臨界段處理
2-1、任務內臨界段處理
taskEXIT_CRITICAL(); //任務處理 taskEXIT_CRITICAL();
2-2、中斷內臨界段處理
taskENTER_CRITICAL_FROM_ISR(); //中斷內處理 taskEXIT_CRITICAL_FROM_ISR();
3、引起調度函數
3-1、延時
vTaskDelay(1000); //延時1000個時鐘節拍,也就是1s