1.設備STM32F103C8T6
2.工程模板
單片機: 部分單片機的程序例程 - Gitee.comhttps://gitee.com/lovefoolnotme/singlechip/tree/master/STM32_FREERTOS/1.%E5%B7%A5%E7%A8%8B%E6%A8%A1%E6%9D%BF
3.代碼
1-FreeRTOS移植模板
#include "system.h"
#include "SysTick.h"
#include "led.h"
#include "usart.h"
#include "FreeRTOS.h"
#include "task.h"//任務優先級
#define START_TASK_PRIO 1
//任務堆棧大小
#define START_STK_SIZE 128
//任務句柄
TaskHandle_t StartTask_Handler;
//任務函數
void start_task(void *pvParameters);//任務優先級
#define LED1_TASK_PRIO 2
//任務堆棧大小 (單位字)
#define LED1_STK_SIZE 50
//任務句柄
TaskHandle_t LED1Task_Handler;
//任務函數
void led1_task(void *pvParameters);/*******************************************************************************
* 函 數 名 : main
* 函數功能 : 主函數
* 輸 入 : 無
* 輸 出 : 無
*******************************************************************************/
int main()
{SysTick_Init(72);NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//設置系統中斷優先級分組4LED_Init();USART1_Init(115200);//創建開始任務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); //任務句柄 vTaskStartScheduler(); //開啟任務調度
}//開始任務任務函數
void start_task(void *pvParameters)
{taskENTER_CRITICAL(); //進入臨界區//創建LED1任務xTaskCreate((TaskFunction_t )led1_task, (const char* )"led1_task", (uint16_t )LED1_STK_SIZE, (void* )NULL,(UBaseType_t )LED1_TASK_PRIO,(TaskHandle_t* )&LED1Task_Handler); vTaskDelete(StartTask_Handler); //刪除開始任務taskEXIT_CRITICAL(); //退出臨界區
} //LED1任務函數
void led1_task(void *pvParameters)
{while(1){LED1=!LED1;LED2=!LED2;LED3=!LED3;LED4=!LED4;vTaskDelay(500);}
}
2-FreeRTOS任務掛起實驗
#include "system.h"
#include "SysTick.h"
#include "led.h"
#include "key.h"
#include "usart.h"
#include "FreeRTOS.h"
#include "task.h"//任務優先級
#define START_TASK_PRIO 1
//任務堆棧大小
#define START_STK_SIZE 128
//任務句柄
TaskHandle_t StartTask_Handler;
//任務函數
void start_task(void *pvParameters);
/****************************************************************/
//任務優先級
#define LED1_TASK_PRIO 2
//任務堆棧大小 (單位字)
#define LED1_STK_SIZE 50
//任務句柄
TaskHandle_t LED1Task_Handler;
//任務函數
void led1_task(void *pvParameters);
/****************************************************************/
//任務優先級
#define LED2_TASK_PRIO 3
//任務堆棧大小 (單位字)
#define LED2_STK_SIZE 50
//任務句柄
TaskHandle_t LED2Task_Handler;
//任務函數
void led2_task(void *pvParameters);//任務優先級
#define KEY_TASK_PRIO 4
//任務堆棧大小 (單位字)
#define KEY_STK_SIZE 50
//任務句柄
TaskHandle_t KEYTask_Handler;
//任務函數
void key_task(void *pvParameters);/*******************************************************************************
* 函 數 名 : main
* 函數功能 : 主函數
* 輸 入 : 無
* 輸 出 : 無
*******************************************************************************/
int main()
{SysTick_Init(72);NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//設置系統中斷優先級分組4LED_Init();KEY_Init();USART1_Init(115200);//創建開始任務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); //任務句柄 vTaskStartScheduler(); //開啟任務調度
}//開始任務任務函數
void start_task(void *pvParameters)
{taskENTER_CRITICAL(); //進入臨界區//創建LED1任務xTaskCreate((TaskFunction_t )led1_task, (const char* )"led1_task", (uint16_t )LED1_STK_SIZE, (void* )NULL,(UBaseType_t )LED1_TASK_PRIO,(TaskHandle_t* )&LED1Task_Handler); //創建LED2任務xTaskCreate((TaskFunction_t )led2_task, (const char* )"led2_task", (uint16_t )LED2_STK_SIZE, (void* )NULL,(UBaseType_t )LED2_TASK_PRIO,(TaskHandle_t* )&LED2Task_Handler); //創建KEY任務xTaskCreate((TaskFunction_t )key_task, (const char* )"key_task", (uint16_t )KEY_STK_SIZE, (void* )NULL,(UBaseType_t )KEY_TASK_PRIO,(TaskHandle_t* )&KEYTask_Handler);vTaskDelete(StartTask_Handler); //刪除開始任務taskEXIT_CRITICAL(); //退出臨界區
} //LED1任務函數
void led1_task(void *pvParameters)
{while(1){LED1=!LED1;vTaskDelay(500);}
}//LED1任務函數
void led2_task(void *pvParameters)
{while(1){LED2=!LED2;vTaskDelay(500);}
}//LED1任務函數
void key_task(void *pvParameters)
{while(1){if(KEY==1) vTaskSuspend(LED2Task_Handler); else vTaskResume(LED2Task_Handler);vTaskDelay(100);}
}
3-FreeRTOS消息隊列實驗
/******************************2023年10月14日*************************************
此為一個消息隊列實驗,主要使用使用按鍵、OLED屏幕來觀察現象。
主要創建兩個任務一個接收,一個發送
發送不等待,但是需要按鍵觸發
接收是一直等待,直到接收到隊列里面的消息,使用本次實驗中的函數接收數據后會刪除隊列中的數據
宏定義隊列長度和單個消息大小都為4
需定義隊列句柄
*********************************************************************************/
#include "system.h"
#include "SysTick.h"
#include "led.h"
#include "key.h"
#include "oled.h"
#include "usart.h"
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
//任務優先級
#define START_TASK_PRIO 1
//任務堆棧大小
#define START_STK_SIZE 128
//任務句柄
TaskHandle_t StartTask_Handler;
//任務函數
void start_task(void *pvParameters);//任務優先級
#define LED1_TASK_PRIO 2
//任務堆棧大小 (單位字)
#define LED1_STK_SIZE 50
//任務句柄
TaskHandle_t LED1Task_Handler;
//任務函數
void led1_task(void *pvParameters);
/*******************************************************************************/
//任務優先級
#define SEND_TASK_PRIO 3
//任務堆棧大小
#define SEND_STK_SIZE 50
//任務句柄
TaskHandle_t SendTask_Handler;
//任務函數
void send_task(void *pvParameters);
/*******************************************************************************/
//任務優先級
#define RECEIVE_TASK_PRIO 4
//任務堆棧大小
#define RECEIVE_STK_SIZE 50
//任務句柄
TaskHandle_t ReceiveTask_Handler;
//任務函數
void receive_task(void *pvParameters);QueueHandle_t Test_Queue =NULL; //句柄
#define QUEUE_LEN 4 // 隊列的長度,最大可包含多少個消息 */
#define QUEUE_SIZE 4 // 隊列中每個消息大小(字節) *//*******************************************************************************
* 函 數 名 : main
* 函數功能 : 主函數
* 輸 入 : 無
* 輸 出 : 無
*******************************************************************************/
int main()
{SysTick_Init(72);NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//設置系統中斷優先級分組4USART1_Init(115200);KEY_Init();LED_Init();OLED_Init();OLED_ColorTurn(0);//0正常顯示,1 反色顯示 OLED_DisplayTurn(0);OLED_Clear();//創建開始任務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); //任務句柄 vTaskStartScheduler(); //開啟任務調度
}//開始任務任務函數
void start_task(void *pvParameters)
{taskENTER_CRITICAL(); //進入臨界區/* 創建Test_Queue */Test_Queue = xQueueCreate((UBaseType_t ) QUEUE_LEN,/* 消息隊列的長度 */(UBaseType_t ) QUEUE_SIZE);/* 消息的大小 *///創建LED1任務xTaskCreate((TaskFunction_t )led1_task, (const char* )"led1_task", (uint16_t )LED1_STK_SIZE, (void* )NULL,(UBaseType_t )LED1_TASK_PRIO,(TaskHandle_t* )&LED1Task_Handler); //創建接收任務xTaskCreate((TaskFunction_t )receive_task, (const char* )"receive_task", (uint16_t )RECEIVE_STK_SIZE, (void* )NULL,(UBaseType_t )RECEIVE_TASK_PRIO,(TaskHandle_t* )&ReceiveTask_Handler);//創建發送任務xTaskCreate((TaskFunction_t )send_task, (const char* )"send_task", (uint16_t )SEND_STK_SIZE, (void* )NULL,(UBaseType_t )SEND_TASK_PRIO,(TaskHandle_t* )&SendTask_Handler);vTaskDelete(StartTask_Handler); //刪除開始任務taskEXIT_CRITICAL(); //退出臨界區
} //LED1任務函數
void led1_task(void *pvParameters)
{while(1){LED1=!LED1;LED2=!LED2;LED3=!LED3;LED4=!LED4;vTaskDelay(500);}
}void send_task(void *pvParameters)
{ BaseType_t xReturn = pdPASS;/* 定義一個創建信息返回值,默認為pdPASS */static uint32_t send_data1 = 1;while(1){if(KEY==1) {xReturn = xQueueSend( Test_Queue, /* 消息隊列的句柄 */&send_data1,/* 發送的消息內容 */0 ); /* 等待時間 0 */ if(xReturn==pdPASS){OLED_ShowString(3,0,"ok",8,1); //按下顯示"ok"OLED_ShowNum(3,20,send_data1,2,8,1);OLED_Refresh();send_data1+=1; //遞增}}else {OLED_ShowString(3,0,"no",8,1);OLED_ShowString(3,40," ",8,1);OLED_Refresh();} //沒按下時顯示"no"vTaskDelay(100);}
}//接收任務函數
void receive_task(void *pvParameters)
{BaseType_t xReturn = pdTRUE;/* 定義一個創建信息返回值,默認為pdTRUE */uint32_t r_queue; /* 定義一個接收消息的變量 */while(1){xReturn = xQueueReceive( Test_Queue, /* 消息隊列的句柄 */&r_queue, /* 發送的消息內容 */portMAX_DELAY); /* 等待時間 一直等(等不到則下面的程序不執行) ,為0則不等*/ if(pdTRUE == xReturn) //接收成功{OLED_ShowString(3,40,"get",8,1);OLED_Refresh();}else //接收失敗{OLED_ShowString(3,40,"fal",8,1);OLED_Refresh();}vTaskDelay(100);}
}
4-FreeRTOS二值信號量實驗
/******************************2023年10月15日*************************************
此為一個二值信號量實驗,主要使用使用按鍵、OLED屏幕來觀察現象。
主要創建兩個任務一個接收,一個發送
二值信號量,需要按鍵觸發,按下按鍵則send任務釋放二值信號量、LED4翻轉;receive獲取二值信號量、LED3翻轉
receive任務是一直等待,只要send任務釋放則receive獲取二值信號量。
需定義二值信號量句柄
*********************************************************************************/
#include "system.h"
#include "SysTick.h"
#include "led.h"
#include "key.h"
#include "oled.h"
#include "usart.h"
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"//任務優先級
#define START_TASK_PRIO 1
//任務堆棧大小
#define START_STK_SIZE 128
//任務句柄
TaskHandle_t StartTask_Handler;
//任務函數
void start_task(void *pvParameters);//任務優先級
#define LED1_TASK_PRIO 2
//任務堆棧大小 (單位字)
#define LED1_STK_SIZE 50
//任務句柄
TaskHandle_t LED1Task_Handler;
//任務函數
void led1_task(void *pvParameters);
/*******************************************************************************/
//任務優先級
#define SEND_TASK_PRIO 3
//任務堆棧大小
#define SEND_STK_SIZE 50
//任務句柄
TaskHandle_t SendTask_Handler;
//任務函數
void send_task(void *pvParameters);
/*******************************************************************************/
//任務優先級
#define RECEIVE_TASK_PRIO 4
//任務堆棧大小
#define RECEIVE_STK_SIZE 50
//任務句柄
TaskHandle_t ReceiveTask_Handler;
//任務函數
void receive_task(void *pvParameters);//創建句柄
SemaphoreHandle_t BinarySem_Handle =NULL;/*******************************************************************************
* 函 數 名 : main
* 函數功能 : 主函數
* 輸 入 : 無
* 輸 出 : 無
*******************************************************************************/
int main()
{SysTick_Init(72);NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//設置系統中斷優先級分組4USART1_Init(115200);KEY_Init();LED_Init();OLED_Init();OLED_ColorTurn(0);//0正常顯示,1 反色顯示 OLED_DisplayTurn(0);OLED_Clear();//創建開始任務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); //任務句柄 vTaskStartScheduler(); //開啟任務調度
}//開始任務任務函數
void start_task(void *pvParameters)
{taskENTER_CRITICAL(); //進入臨界區/* 創建 BinarySem */BinarySem_Handle = xSemaphoreCreateBinary();//創建LED1任務xTaskCreate((TaskFunction_t )led1_task, (const char* )"led1_task", (uint16_t )LED1_STK_SIZE, (void* )NULL,(UBaseType_t )LED1_TASK_PRIO,(TaskHandle_t* )&LED1Task_Handler); //創建接收任務xTaskCreate((TaskFunction_t )receive_task, (const char* )"receive_task", (uint16_t )RECEIVE_STK_SIZE, (void* )NULL,(UBaseType_t )RECEIVE_TASK_PRIO,(TaskHandle_t* )&ReceiveTask_Handler);//創建發送任務xTaskCreate((TaskFunction_t )send_task, (const char* )"send_task", (uint16_t )SEND_STK_SIZE, (void* )NULL,(UBaseType_t )SEND_TASK_PRIO,(TaskHandle_t* )&SendTask_Handler);vTaskDelete(StartTask_Handler); //刪除開始任務taskEXIT_CRITICAL(); //退出臨界區
} //LED1任務函數
void led1_task(void *pvParameters)
{while(1){LED1=!LED1;vTaskDelay(500);}
}void send_task(void *pvParameters)
{ BaseType_t xReturn = pdPASS;/* 定義一個創建信息返回值,默認為pdPASS */while(1){if(KEY==1) {xReturn = xSemaphoreGive( BinarySem_Handle );//釋放二值信號量if(xReturn==pdPASS) {LED4=!LED4;OLED_ShowString(3,0,"release",8,1);} //釋放成功則LED4反轉else OLED_ShowString(3,0,"failed!",8,1);}else OLED_ShowString(3,0,"nopress",8,1); //沒按下時顯示"nopress"OLED_Refresh();vTaskDelay(100);}
}//接收任務函數
void receive_task(void *pvParameters)
{BaseType_t xReturn = pdTRUE;/* 定義一個創建信息返回值,默認為pdTRUE */while(1){//獲取二值信號量 xSemaphore,沒獲取到則一直等待xReturn = xSemaphoreTake(BinarySem_Handle,/* 二值信號量句柄 */portMAX_DELAY); /* 等待時間 */if(pdTRUE == xReturn) //獲取二值信號量成功{OLED_ShowString(3,40,"receive",8,1);LED3=!LED3; //獲取成功則LED3反轉}else //獲取二值信號量失敗{OLED_ShowString(3,40,"nochange",8,1);}OLED_Refresh();vTaskDelay(100);}
}
5-FreeRTOS計數信號量實驗
/******************************2023年10月15日*************************************
此為一個計數信號量實驗,主要使用使用按鍵、OLED屏幕來觀察現象。
主要創建兩個任務一個接收,一個發送
計數信號量,需要按鍵觸發,按下按鍵則send任務釋放計數信號量、LED4翻轉;receive獲取計數信號量、LED3翻轉
receive任務是不等待,只要send任務釋放則receive才能成功獲取二值信號量。
需定義計數信號量句柄
需要修改FreeRTOSConfig.h中的宏定義:
//為1時使用計數信號量
#define configUSE_COUNTING_SEMAPHORES 1
*********************************************************************************/
#include "system.h"
#include "SysTick.h"
#include "led.h"
#include "key.h"
#include "oled.h"
#include "usart.h"
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"//任務優先級
#define START_TASK_PRIO 1
//任務堆棧大小
#define START_STK_SIZE 128
//任務句柄
TaskHandle_t StartTask_Handler;
//任務函數
void start_task(void *pvParameters);//任務優先級
#define LED1_TASK_PRIO 2
//任務堆棧大小 (單位字)
#define LED1_STK_SIZE 50
//任務句柄
TaskHandle_t LED1Task_Handler;
//任務函數
void led1_task(void *pvParameters);
/*******************************************************************************/
//任務優先級
#define SEND_TASK_PRIO 3
//任務堆棧大小
#define SEND_STK_SIZE 50
//任務句柄
TaskHandle_t SendTask_Handler;
//任務函數
void send_task(void *pvParameters);
/*******************************************************************************/
//任務優先級
#define RECEIVE_TASK_PRIO 4
//任務堆棧大小
#define RECEIVE_STK_SIZE 50
//任務句柄
TaskHandle_t ReceiveTask_Handler;
//任務函數
void receive_task(void *pvParameters);//創建句柄
SemaphoreHandle_t CountSem_Handle =NULL;/*******************************************************************************
* 函 數 名 : main
* 函數功能 : 主函數
* 輸 入 : 無
* 輸 出 : 無
*******************************************************************************/
int main()
{SysTick_Init(72);NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//設置系統中斷優先級分組4USART1_Init(115200);KEY_Init();LED_Init();OLED_Init();OLED_ColorTurn(0);//0正常顯示,1 反色顯示 OLED_DisplayTurn(0);OLED_Clear();//創建開始任務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); //任務句柄 vTaskStartScheduler(); //開啟任務調度
}//開始任務任務函數
void start_task(void *pvParameters)
{taskENTER_CRITICAL(); //進入臨界區/* 創建 CountSem */CountSem_Handle = xSemaphoreCreateCounting(5,5);//創建LED1任務xTaskCreate((TaskFunction_t )led1_task, (const char* )"led1_task", (uint16_t )LED1_STK_SIZE, (void* )NULL,(UBaseType_t )LED1_TASK_PRIO,(TaskHandle_t* )&LED1Task_Handler); //創建接收任務xTaskCreate((TaskFunction_t )receive_task, (const char* )"receive_task", (uint16_t )RECEIVE_STK_SIZE, (void* )NULL,(UBaseType_t )RECEIVE_TASK_PRIO,(TaskHandle_t* )&ReceiveTask_Handler);//創建發送任務xTaskCreate((TaskFunction_t )send_task, (const char* )"send_task", (uint16_t )SEND_STK_SIZE, (void* )NULL,(UBaseType_t )SEND_TASK_PRIO,(TaskHandle_t* )&SendTask_Handler);vTaskDelete(StartTask_Handler); //刪除開始任務taskEXIT_CRITICAL(); //退出臨界區
} //LED1任務函數
void led1_task(void *pvParameters)
{while(1){LED1=!LED1;vTaskDelay(500);}
}void send_task(void *pvParameters)
{ BaseType_t xReturn = pdPASS;/* 定義一個創建信息返回值,默認為pdPASS */while(1){if(KEY==1) {xReturn = xSemaphoreGive( CountSem_Handle );//釋放計數信號量if(xReturn==pdPASS) {LED4=!LED4;OLED_ShowString(3,0,"release",8,1);} //釋放成功則LED4反轉else OLED_ShowString(3,0,"failed!",8,1);}else OLED_ShowString(3,0,"nopress",8,1); //沒按下時顯示"nopress"OLED_Refresh();vTaskDelay(100);}
}//接收任務函數
void receive_task(void *pvParameters)
{BaseType_t xReturn = pdTRUE;/* 定義一個創建信息返回值,默認為pdTRUE */while(1){//獲取計數信號量 xSemaphore,沒獲取到則不等待xReturn = xSemaphoreTake(CountSem_Handle,/* 計數信號量句柄 */0); /* 等待時間 */if(pdTRUE == xReturn) //獲取計數信號量成功{OLED_ShowString(3,40,"receive",8,1);LED3=!LED3; //獲取成功則LED3反轉}else //獲取計數信號量失敗{OLED_ShowString(3,40,"nochang",8,1);}OLED_Refresh();vTaskDelay(100);}
}
6-FreeRTOS互斥信號量實驗 - 優先級翻轉
/******************************2023年10月17日*************************************
此為一個優先級翻轉實驗,主要使用使用OLED屏幕來觀察現象。
主要創建三個任務高優先級、中優先級、低優先級
模擬優先級翻轉、低優先級任務運行時高優先級任務等待
需定義二值信號量句柄
由于高優先級任務需要的資源(二值信號量)被低優先級任務占據,所以無法執行,掛起(此時任務優先級翻轉)
中優先級任務沒有使用到被占據的資源(二值信號量),所以中優先級任務不用等待低優先級任務執行完畢需更改宏定義
//使用互斥信號量
#define configUSE_MUTEXES 1
*********************************************************************************/
#include "system.h"
#include "SysTick.h"
#include "led.h"
#include "key.h"
#include "oled.h"
#include "usart.h"
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"//任務優先級
#define START_TASK_PRIO 1
//任務堆棧大小
#define START_STK_SIZE 128
//任務句柄
TaskHandle_t StartTask_Handler;
//任務函數
void start_task(void *pvParameters);//任務優先級
#define LED1_TASK_PRIO 3 //這里提高LED任務優先級,防止低優先級任務阻塞了LED任務
//任務堆棧大小 (單位字)
#define LED1_STK_SIZE 50
//任務句柄
TaskHandle_t LED1Task_Handler;
//任務函數
void led1_task(void *pvParameters);
/*******************************************************************************/
//任務優先級
#define LowPriority_TASK_PRIO 2 //比LED優先級低
//任務堆棧大小
#define LowPriority_STK_SIZE 512
//任務句柄
TaskHandle_t LowPriority_Task_Handle;
//任務函數
void LowPriority_Task(void *pvParameters);
/*******************************************************************************/
//任務優先級
#define MidPriority_TASK_PRIO 4
//任務堆棧大小
#define MidPriority_STK_SIZE 512
//任務句柄
TaskHandle_t MidPriority_Task_Handle;
//任務函數
void MidPriority_Task(void *pvParameters);
/*******************************************************************************/
//任務優先級
#define HighPriority_TASK_PRIO 5
//任務堆棧大小
#define HighPriority_STK_SIZE 512
//任務句柄
TaskHandle_t HighPriority_Task_Handle;
//任務函數
void HighPriority_Task(void *pvParameters);//創建句柄
SemaphoreHandle_t BinarySem_Handle =NULL;
/*******************************************************************************
* 函 數 名 : main
* 函數功能 : 主函數
* 輸 入 : 無
* 輸 出 : 無
*******************************************************************************/
int main()
{SysTick_Init(72);NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//設置系統中斷優先級分組4USART1_Init(115200);KEY_Init();LED_Init();OLED_Init();OLED_ColorTurn(0);//0正常顯示,1 反色顯示 OLED_DisplayTurn(0);OLED_Clear();//創建開始任務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); //任務句柄 vTaskStartScheduler(); //開啟任務調度
}//開始任務任務函數
void start_task(void *pvParameters)
{ BaseType_t xReturn = pdPASS;taskENTER_CRITICAL(); //進入臨界區/* 創建 BinarySem */BinarySem_Handle = xSemaphoreCreateBinary();xReturn = xSemaphoreGive( BinarySem_Handle );//給出二值信號量 //創建LED1任務xTaskCreate((TaskFunction_t )led1_task, (const char* )"led1_task", (uint16_t )LED1_STK_SIZE, (void* )NULL,(UBaseType_t )LED1_TASK_PRIO,(TaskHandle_t* )&LED1Task_Handler); //創建低優先級任務xTaskCreate((TaskFunction_t )LowPriority_Task, (const char* )"LowPriority_Task", (uint16_t )LowPriority_STK_SIZE, (void* )NULL,(UBaseType_t )LowPriority_TASK_PRIO,(TaskHandle_t* )&LowPriority_Task_Handle);//創建中優先級任務xTaskCreate((TaskFunction_t )MidPriority_Task, (const char* )"MidPriority_Task", (uint16_t )MidPriority_STK_SIZE, (void* )NULL,(UBaseType_t )MidPriority_TASK_PRIO,(TaskHandle_t* )&MidPriority_Task_Handle);//創建高優先級任務xTaskCreate((TaskFunction_t )HighPriority_Task, (const char* )"HighPriority_Task", (uint16_t )HighPriority_STK_SIZE, (void* )NULL,(UBaseType_t )HighPriority_TASK_PRIO,(TaskHandle_t* )&HighPriority_Task_Handle);vTaskDelete(StartTask_Handler); //刪除開始任務taskEXIT_CRITICAL(); //退出臨界區
} //LED1任務函數
void led1_task(void *pvParameters)
{while(1){LED1=!LED1;vTaskDelay(500);}
}//低優先級任務函數
void LowPriority_Task(void *pvParameters)
{BaseType_t xReturn = pdPASS;/* 定義一個創建信息返回值,默認為pdPASS */static uint32_t i=0;static uint32_t low_see=0;while(1){ OLED_ShowString(3,0,"low_get",8,1);OLED_Refresh();//獲取二值信號量 xSemaphore,沒獲取到則一直等待xReturn = xSemaphoreTake(BinarySem_Handle,/* 二值信號量句柄 */portMAX_DELAY); /* 等待時間 */if( xReturn == pdTRUE ){OLED_ShowString(3,0,"low_run",8,1);low_see++;OLED_ShowNum(60,0,low_see,4,8,1);OLED_Refresh();}
/*****************************************************************************
此處可以占據二值信號量,導致高優先級任務無法獲取二值信號量無法執行。被迫等待低優先級任務執行完畢。
而中優先級任務不需要獲取二值信號量所以不受影響
*****************************************************************************/for(i=0;i<2000000;i++)//模擬低優先級任務占用信號量{taskYIELD();//發起任務調度}OLED_ShowString(3,0,"low_giv",8,1);OLED_Refresh();xReturn = xSemaphoreGive( BinarySem_Handle );//給出二值信號量LED2=!LED2;vTaskDelay(500);}
}//中優先級任務函數
void MidPriority_Task(void *pvParameters)
{static uint32_t see=0;while(1){see++;OLED_ShowNum(3,20,see,4,8,1); // 用來證明中優先級任務沒有被低優先級任務阻塞 OLED_Refresh();vTaskDelay(500);}
}//高優先級任務函數
void HighPriority_Task(void *pvParameters)
{BaseType_t xReturn = pdTRUE;static uint32_t high_see=0;while(1){ OLED_ShowString(3,40,"hig_get",8,1);OLED_Refresh();//獲取二值信號量 xSemaphore,沒獲取到則一直等待xReturn = xSemaphoreTake(BinarySem_Handle,/* 二值信號量句柄 */portMAX_DELAY); /* 等待時間 */if(pdTRUE == xReturn){ OLED_ShowString(3,40,"hig_run",8,1);high_see++;OLED_ShowNum(60,40,high_see,4,8,1);OLED_Refresh(); }LED2=!LED2;xReturn = xSemaphoreGive( BinarySem_Handle );//給出二值信號量vTaskDelay(500);}
}
7-FreeRTOS互斥信號量實驗-互斥量
/******************************2023年10月17日*************************************
此為一個互斥信號量實驗,主要使用使用OLED屏幕來觀察現象。
主要創建三個任務高優先級、中優先級、低優先級
模擬低優先級占用資源、低優先級任務運行時高優先級任務等待
需定義互斥信號量句柄
互斥信號量實驗與優先級翻轉實驗的區別就是:
優先級反轉實驗定義的是二值信號量,只有需要獲取二值信號量的任務會被影響;互斥信號量實驗定義的是互斥信號量,所有的任務都會被影響,體現資源占用互斥需更改宏定義
//使用互斥信號量
#define configUSE_MUTEXES 1
*********************************************************************************/
#include "system.h"
#include "SysTick.h"
#include "led.h"
#include "key.h"
#include "oled.h"
#include "usart.h"
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"//任務優先級
#define START_TASK_PRIO 1
//任務堆棧大小
#define START_STK_SIZE 128
//任務句柄
TaskHandle_t StartTask_Handler;
//任務函數
void start_task(void *pvParameters);//任務優先級
#define LED1_TASK_PRIO 3 //這里提高LED任務優先級,防止低優先級任務阻塞了LED任務
//任務堆棧大小 (單位字)
#define LED1_STK_SIZE 50
//任務句柄
TaskHandle_t LED1Task_Handler;
//任務函數
void led1_task(void *pvParameters);
/*******************************************************************************/
//任務優先級
#define LowPriority_TASK_PRIO 2 //比LED優先級低
//任務堆棧大小
#define LowPriority_STK_SIZE 512
//任務句柄
TaskHandle_t LowPriority_Task_Handle;
//任務函數
void LowPriority_Task(void *pvParameters);
/*******************************************************************************/
//任務優先級
#define MidPriority_TASK_PRIO 4
//任務堆棧大小
#define MidPriority_STK_SIZE 512
//任務句柄
TaskHandle_t MidPriority_Task_Handle;
//任務函數
void MidPriority_Task(void *pvParameters);
/*******************************************************************************/
//任務優先級
#define HighPriority_TASK_PRIO 5
//任務堆棧大小
#define HighPriority_STK_SIZE 512
//任務句柄
TaskHandle_t HighPriority_Task_Handle;
//任務函數
void HighPriority_Task(void *pvParameters);//創建句柄
SemaphoreHandle_t MuxSem_Handle =NULL;
/*******************************************************************************
* 函 數 名 : main
* 函數功能 : 主函數
* 輸 入 : 無
* 輸 出 : 無
*******************************************************************************/
int main()
{SysTick_Init(72);NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//設置系統中斷優先級分組4USART1_Init(115200);KEY_Init();LED_Init();OLED_Init();OLED_ColorTurn(0);//0正常顯示,1 反色顯示 OLED_DisplayTurn(0);OLED_Clear();//創建開始任務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); //任務句柄 vTaskStartScheduler(); //開啟任務調度
}//開始任務任務函數
void start_task(void *pvParameters)
{ taskENTER_CRITICAL(); //進入臨界區/* 創建 BinarySem */MuxSem_Handle = xSemaphoreCreateMutex(); //創建LED1任務xTaskCreate((TaskFunction_t )led1_task, (const char* )"led1_task", (uint16_t )LED1_STK_SIZE, (void* )NULL,(UBaseType_t )LED1_TASK_PRIO,(TaskHandle_t* )&LED1Task_Handler); //創建低優先級任務xTaskCreate((TaskFunction_t )LowPriority_Task, (const char* )"LowPriority_Task", (uint16_t )LowPriority_STK_SIZE, (void* )NULL,(UBaseType_t )LowPriority_TASK_PRIO,(TaskHandle_t* )&LowPriority_Task_Handle);//創建中優先級任務xTaskCreate((TaskFunction_t )MidPriority_Task, (const char* )"MidPriority_Task", (uint16_t )MidPriority_STK_SIZE, (void* )NULL,(UBaseType_t )MidPriority_TASK_PRIO,(TaskHandle_t* )&MidPriority_Task_Handle);//創建高優先級任務xTaskCreate((TaskFunction_t )HighPriority_Task, (const char* )"HighPriority_Task", (uint16_t )HighPriority_STK_SIZE, (void* )NULL,(UBaseType_t )HighPriority_TASK_PRIO,(TaskHandle_t* )&HighPriority_Task_Handle);vTaskDelete(StartTask_Handler); //刪除開始任務taskEXIT_CRITICAL(); //退出臨界區
} //LED1任務函數
void led1_task(void *pvParameters)
{while(1){LED1=!LED1;vTaskDelay(500);}
}//低優先級任務函數
void LowPriority_Task(void *pvParameters)
{BaseType_t xReturn = pdPASS;/* 定義一個創建信息返回值,默認為pdPASS */static uint32_t i=0;static uint32_t low_see=0;while(1){ OLED_ShowString(3,0,"low_get",8,1);OLED_Refresh();//獲取二值信號量 xSemaphore,沒獲取到則一直等待xReturn = xSemaphoreTake(MuxSem_Handle,/* 互斥信號量句柄 */portMAX_DELAY); /* 等待時間 */if( xReturn == pdTRUE ){OLED_ShowString(3,0,"low_run",8,1);low_see++;OLED_ShowNum(60,0,low_see,4,8,1);OLED_Refresh();}
/*****************************************************************************模擬低優先級任務占用資源
*****************************************************************************/for(i=0;i<2000000;i++)//模擬低優先級任務占用信號量{taskYIELD();//發起任務調度}OLED_ShowString(3,0,"low_giv",8,1);OLED_Refresh();xReturn = xSemaphoreGive( MuxSem_Handle );//給出互斥信號量LED2=!LED2;vTaskDelay(500);}
}//中優先級任務函數
void MidPriority_Task(void *pvParameters)
{static uint32_t see=0;while(1){see++;OLED_ShowNum(3,20,see,4,8,1); // 用來證明中優先級任務沒有被低優先級任務阻塞 OLED_Refresh();vTaskDelay(500);}
}//高優先級任務函數
void HighPriority_Task(void *pvParameters)
{BaseType_t xReturn = pdTRUE;static uint32_t high_see=0;while(1){ OLED_ShowString(3,40,"hig_get",8,1);OLED_Refresh();//獲取互斥信號量 xSemaphore,沒獲取到則一直等待xReturn = xSemaphoreTake(MuxSem_Handle,/* 互斥信號量句柄 */portMAX_DELAY); /* 等待時間 */if(pdTRUE == xReturn){ OLED_ShowString(3,40,"hig_run",8,1);high_see++;OLED_ShowNum(60,40,high_see,4,8,1);OLED_Refresh(); }LED2=!LED2;xReturn = xSemaphoreGive( MuxSem_Handle );//給出互斥信號量vTaskDelay(500);}
}
8-FreeRTOS事件實驗
/******************************2023年10月17日*************************************
這是一個事件實驗,LED2任務需要事件觸發,KEY任務可以通過按鍵計數創建對應的事件,
當事件滿足時LED2任務才可以執行一次,執行完之后由于xEventGroupWaitBits某個參數
設置為pdTRUE,所以觸發后會自動刪除標志位,自動清除。這個函數返回值為事件的計算值。
*********************************************************************************/
#include "system.h"
#include "SysTick.h"
#include "led.h"
#include "key.h"
#include "oled.h"
#include "usart.h"
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"
#include "event_groups.h"//任務優先級
#define START_TASK_PRIO 1
//任務堆棧大小
#define START_STK_SIZE 128
//任務句柄
TaskHandle_t StartTask_Handler;
//任務函數
void start_task(void *pvParameters);//任務優先級
#define LED1_TASK_PRIO 2
//任務堆棧大小
#define LED1_STK_SIZE 50
//任務句柄
TaskHandle_t LED1Task_Handler;
//任務函數
void led1_task(void *pvParameters);//任務優先級
#define LED2_TASK_PRIO 3
//任務堆棧大小
#define LED2_STK_SIZE 50
//任務句柄
TaskHandle_t LED2Task_Handler;
//任務函數
void led2_task(void *pvParameters);//任務優先級
#define KEY_TASK_PRIO 4
//任務堆棧大小
#define KEY_STK_SIZE 512
//任務句柄
TaskHandle_t KEYTask_Handler;
//任務函數
void key_task(void *pvParameters);//創建句柄
EventGroupHandle_t Event_Handle =NULL;#define KEY1_EVENT (0x01 << 0)//設置事件掩碼的位0
#define KEY2_EVENT (0x01 << 1)//設置事件掩碼的位1
/*******************************************************************************
* 函 數 名 : main
* 函數功能 : 主函數
* 輸 入 : 無
* 輸 出 : 無
*******************************************************************************/
int main()
{SysTick_Init(72);NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//設置系統中斷優先級分組4USART1_Init(115200);KEY_Init();LED_Init();OLED_Init();OLED_ColorTurn(0);//0正常顯示,1 反色顯示 OLED_DisplayTurn(0);OLED_Clear();//創建開始任務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); //任務句柄 vTaskStartScheduler(); //開啟任務調度
}//開始任務任務函數
void start_task(void *pvParameters)
{ taskENTER_CRITICAL(); //進入臨界區/* 創建 Event_Handle */Event_Handle = xEventGroupCreate(); //創建LED1任務xTaskCreate((TaskFunction_t )led1_task, (const char* )"led1_task", (uint16_t )LED1_STK_SIZE, (void* )NULL,(UBaseType_t )LED1_TASK_PRIO,(TaskHandle_t* )&LED1Task_Handler); //創建LED2任務xTaskCreate((TaskFunction_t )led2_task, (const char* )"led2_task", (uint16_t )LED2_STK_SIZE, (void* )NULL,(UBaseType_t )LED2_TASK_PRIO,(TaskHandle_t* )&LED2Task_Handler);//創建KEY任務xTaskCreate((TaskFunction_t )key_task, (const char* )"key_task", (uint16_t )KEY_STK_SIZE, (void* )NULL,(UBaseType_t )KEY_TASK_PRIO,(TaskHandle_t* )&KEYTask_Handler);vTaskDelete(StartTask_Handler); //刪除開始任務taskEXIT_CRITICAL(); //退出臨界區
} //LED1任務函數
void led1_task(void *pvParameters)
{while(1){LED1=0;vTaskDelay(200);LED1=1;vTaskDelay(800);}
}//LED2任務函數
void led2_task(void *pvParameters)
{EventBits_t r_event; /* 定義一個事件接收變量 */while(1){r_event = xEventGroupWaitBits(Event_Handle, /* 事件對象句柄 */KEY1_EVENT|KEY2_EVENT,/* 接收線程感興趣的事件 */pdTRUE, /* 退出時清除事件位 */pdTRUE, /* 滿足感興趣的所有事件 */portMAX_DELAY);/* 指定超時事件,一直等 */if((r_event & (KEY1_EVENT|KEY2_EVENT)) == (KEY1_EVENT|KEY2_EVENT)){OLED_ShowString(3,50 ,"get!",8,1);LED2=!LED2;}elseOLED_ShowString(3,50 ,"err!",8,1);OLED_Refresh();}
}//KEY任務函數
void key_task(void *pvParameters)
{static uint32_t KEY_DOWN=0;while(1){if(KEY==1){KEY_DOWN++;if(KEY_DOWN%2==0) {xEventGroupSetBits(Event_Handle,KEY1_EVENT); //偶數創建事件1OLED_ShowString(3,0 ,"event1 created!",8,1);}else{xEventGroupSetBits(Event_Handle,KEY2_EVENT); //奇數創建事件2OLED_ShowString(3,20 ,"event2 created!",8,1);}while(KEY==1);}OLED_ShowNum(3,40,KEY_DOWN,2,8,1);OLED_Refresh();vTaskDelay(20);}
}
9-FreeRTOS軟件定時器實驗
/******************************2023年10月17日*************************************
這是一個軟件定時器實驗,創建了兩個軟件定時器,定時器1可以一直定時,定時時間1秒;
定時器2只能定時一次,定時時間5秒。通過OLED屏幕顯示來觀察定時情況。
1 tick為 1 ms
需要修改宏定義中//啟用軟件定時器
#define configUSE_TIMERS 1
*********************************************************************************/
#include "system.h"
#include "SysTick.h"
#include "led.h"
#include "key.h"
#include "oled.h"
#include "usart.h"
#include "FreeRTOS.h"
#include "task.h"
#include "timers.h"//任務優先級
#define START_TASK_PRIO 1
//任務堆棧大小
#define START_STK_SIZE 128
//任務句柄
TaskHandle_t StartTask_Handler;
//任務函數
void start_task(void *pvParameters);/**************************************************************************************/
//任務優先級
#define LED1_TASK_PRIO 2
//任務堆棧大小
#define LED1_STK_SIZE 50
//任務句柄
TaskHandle_t LED1Task_Handler;
//任務函數
void led1_task(void *pvParameters);/**************************************************************************************/
//創建句柄
TimerHandle_t Swtmr1_Handle =NULL;
TimerHandle_t Swtmr2_Handle =NULL;static uint32_t TmrCb_Count1 = 0; /* 記錄軟件定時器1回調函數執行次數 */
static uint32_t TmrCb_Count2 = 0; /* 記錄軟件定時器2回調函數執行次數 *///聲明回調函數
static void Swtmr1_Callback(void* parameter);
static void Swtmr2_Callback(void* parameter);/*******************************************************************************
* 函 數 名 : main
* 函數功能 : 主函數
* 輸 入 : 無
* 輸 出 : 無
*******************************************************************************/
int main()
{SysTick_Init(72);NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//設置系統中斷優先級分組4USART1_Init(115200);KEY_Init();LED_Init();OLED_Init();OLED_ColorTurn(0);//0正常顯示,1 反色顯示 OLED_DisplayTurn(0);OLED_Clear();//創建開始任務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); //任務句柄 vTaskStartScheduler(); //開啟任務調度
}//開始任務任務函數
void start_task(void *pvParameters)
{taskENTER_CRITICAL(); //進入臨界區//創建定時器1Swtmr1_Handle=xTimerCreate((const char* )"AutoReloadTimer",(TickType_t )1000,/* 定時器周期 1000(tick) */(UBaseType_t )pdTRUE,/* 周期模式 */(void* )1,/* 為每個計時器分配一個索引的唯一ID */(TimerCallbackFunction_t)Swtmr1_Callback); /*回調函數名稱*/if(Swtmr1_Handle != NULL) {xTimerStart(Swtmr1_Handle,0); //開啟周期定時器}//創建定時器2Swtmr2_Handle=xTimerCreate((const char* )"OneShotTimer",(TickType_t )5000,/* 定時器周期 5000(tick) */(UBaseType_t )pdFALSE,/* 單次模式 */(void* )2,/* 為每個計時器分配一個索引的唯一ID */(TimerCallbackFunction_t)Swtmr2_Callback); /*回調函數名稱*/if(Swtmr2_Handle != NULL) {xTimerStart(Swtmr2_Handle,0); //開啟周期定時器}//創建LED1任務xTaskCreate((TaskFunction_t )led1_task, (const char* )"led1_task", (uint16_t )LED1_STK_SIZE, (void* )NULL,(UBaseType_t )LED1_TASK_PRIO,(TaskHandle_t* )&LED1Task_Handler); vTaskDelete(StartTask_Handler); //刪除開始任務taskEXIT_CRITICAL(); //退出臨界區
} //LED1任務函數
void led1_task(void *pvParameters)
{while(1){LED1=0;vTaskDelay(200);LED1=1;vTaskDelay(800);}
}//定時器1回調函數
//軟件定時器不要調用阻塞函數,也不要進行死循環,應快進快出
void Swtmr1_Callback(void* parameter)
{ TickType_t tick_num1;TmrCb_Count1++; /* 每回調一次加一 */tick_num1 = xTaskGetTickCount(); /* 獲取滴答定時器的計數值 */LED2=!LED2;OLED_ShowNum(3,0,tick_num1,5,8,1); //滴答定時器值OLED_ShowNum(3,20,TmrCb_Count1,5,8,1); //軟件定時器1值 OLED_Refresh();
}//定時器2回調函數
//軟件定時器不要調用阻塞函數,也不要進行死循環,應快進快出
void Swtmr2_Callback(void* parameter)
{ TickType_t tick_num2;TmrCb_Count2++; /* 每回調一次加一 */tick_num2 = xTaskGetTickCount(); /* 獲取滴答定時器的計數值 */OLED_ShowNum(3,40,TmrCb_Count2,5,8,1); //軟件定時器2值OLED_ShowNum(3,0,tick_num2,5,8,1); //滴答定時器值OLED_Refresh();
}
10-FreeRTOS任務通知代替消息隊列實驗
/******************************2023年10月18日*************************************
這是一個任務通知代替消息隊列的實驗,通過OLED與KEY觀察現象。
判斷KEY按下的次數來判斷發送哪一個通知,奇數通知接收任務1,偶數通知接收任務2
*********************************************************************************/
#include "system.h"
#include "SysTick.h"
#include "led.h"
#include "key.h"
#include "oled.h"
#include "usart.h"
#include "FreeRTOS.h"
#include "task.h"
#include "limits.h"//任務優先級
#define START_TASK_PRIO 1
//任務堆棧大小
#define START_STK_SIZE 128
//任務句柄
TaskHandle_t StartTask_Handler;
//任務函數
void start_task(void *pvParameters);//任務優先級
#define LED1_TASK_PRIO 2
//任務堆棧大小
#define LED1_STK_SIZE 50
//任務句柄
TaskHandle_t LED1Task_Handler;
//任務函數
void led1_task(void *pvParameters);//任務優先級
#define Receive1_TASK_PRIO 3
//任務堆棧大小
#define Receive1_STK_SIZE 512
//任務句柄
TaskHandle_t Receive1Task_Handler;
//任務函數
void Receive1_task(void *pvParameters);//任務優先級
#define Receive2_TASK_PRIO 4
//任務堆棧大小
#define Receive2_STK_SIZE 512
//任務句柄
TaskHandle_t Receive2Task_Handler;
//任務函數
void Receive2_task(void *pvParameters);//任務優先級
#define Send_TASK_PRIO 5
//任務堆棧大小
#define Send_STK_SIZE 512
//任務句柄
TaskHandle_t SendTask_Handler;
//任務函數
void Send_task(void *pvParameters);#define USE_CHAR 0 /* 測試字符串的時候配置為 1 ,測試變量配置為 0 *//*******************************************************************************
* 函 數 名 : main
* 函數功能 : 主函數
* 輸 入 : 無
* 輸 出 : 無
*******************************************************************************/
int main()
{SysTick_Init(72);NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//設置系統中斷優先級分組4USART1_Init(115200);KEY_Init();LED_Init();OLED_Init();OLED_ColorTurn(0);//0正常顯示,1 反色顯示 OLED_DisplayTurn(0);OLED_Clear();//創建開始任務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); //任務句柄 vTaskStartScheduler(); //開啟任務調度
}//開始任務任務函數
void start_task(void *pvParameters)
{taskENTER_CRITICAL(); //進入臨界區//創建LED1任務xTaskCreate((TaskFunction_t )led1_task, (const char* )"led1_task", (uint16_t )LED1_STK_SIZE, (void* )NULL,(UBaseType_t )LED1_TASK_PRIO,(TaskHandle_t* )&LED1Task_Handler); //創建Receive1任務xTaskCreate((TaskFunction_t )Receive1_task, (const char* )"Receive1_task", (uint16_t )Receive1_STK_SIZE, (void* )NULL,(UBaseType_t )Receive1_TASK_PRIO,(TaskHandle_t* )&Receive1Task_Handler);//創建Receive2任務xTaskCreate((TaskFunction_t )Receive2_task, (const char* )"Receive2_task", (uint16_t )Receive2_STK_SIZE, (void* )NULL,(UBaseType_t )Receive2_TASK_PRIO,(TaskHandle_t* )&Receive2Task_Handler);//創建Send任務xTaskCreate((TaskFunction_t )Send_task, (const char* )"Send_task", (uint16_t )Send_STK_SIZE, (void* )NULL,(UBaseType_t )Send_TASK_PRIO,(TaskHandle_t* )&SendTask_Handler);vTaskDelete(StartTask_Handler); //刪除開始任務taskEXIT_CRITICAL(); //退出臨界區
} //LED1任務函數
void led1_task(void *pvParameters)
{while(1){LED1=0;vTaskDelay(200);LED1=1;vTaskDelay(800);}
}//Receive1任務函數
void Receive1_task(void *pvParameters)
{BaseType_t xReturn = pdTRUE;
#if USE_CHARchar *r_char;
#elseuint32_t r_num;
#endifwhile(1){//獲取任務通知 ,沒獲取到則一直等待xReturn=xTaskNotifyWait(0x0, //進入函數的時候不清除任務bitULONG_MAX, //退出函數的時候清除所有的bit
#if USE_CHAR(uint32_t *)&r_char, //保存任務通知值
#else&r_num, //保存任務通知值
#endif portMAX_DELAY); //阻塞時間if( pdTRUE == xReturn )
#if USE_CHARprintf("Receive1_Task 任務通知消息為 %s \n",r_char);
#else{OLED_ShowString(3,0,"receive1:",8,1);OLED_ShowNum(70,0,r_num,1,8,1); OLED_Refresh(); }
#endif }
}//Receive2任務函數
void Receive2_task(void *pvParameters)
{BaseType_t xReturn = pdTRUE;
#if USE_CHARchar *r_char;
#elseuint32_t r_num;
#endifwhile(1){//獲取任務通知 ,沒獲取到則一直等待xReturn=xTaskNotifyWait(0x0, //進入函數的時候不清除任務bitULONG_MAX, //退出函數的時候清除所有的bit
#if USE_CHAR(uint32_t *)&r_char, //保存任務通知值
#else&r_num, //保存任務通知值
#endif portMAX_DELAY); //阻塞時間if( pdTRUE == xReturn )
#if USE_CHARprintf("Receive2_Task 任務通知消息為 %s \n",r_char);
#else {OLED_ShowString(3,20,"receive2:",8,1);OLED_ShowNum(70,20,r_num,1,8,1); OLED_Refresh();}
#endif }
}//Send任務函數
void Send_task(void *pvParameters)
{BaseType_t xReturn = pdPASS;u8 PRESS=0;
#if USE_CHARchar test_str1[] = "this is a mail test 1";/* 郵箱消息test1 */char test_str2[] = "this is a mail test 2";/* 郵箱消息test2 */
#elseuint32_t send1 = 1;uint32_t send2 = 2;
#endifwhile(1){if(KEY==1){ PRESS++;while(KEY==1);
/**************************************奇數發送Receive1*****************************************/ if(PRESS%2!=0){ xReturn = xTaskNotify(Receive1Task_Handler, /*任務句柄*/
#if USE_CHAR (uint32_t)&test_str1, /* 發送的數據,最大為4字節 */
#elsesend1, /* 發送的數據,最大為4字節 */
#endifeSetValueWithOverwrite );/*覆蓋當前通知*/if( xReturn == pdPASS ){ OLED_ShowString(3,40,"receive1 send!",8,1);OLED_Refresh();}}
/***************************************偶數發送Receive2**************************************/ else {xReturn = xTaskNotify(Receive2Task_Handler, /*任務句柄*/
#if USE_CHAR (uint32_t)&test_str2, /* 發送的數據,最大為4字節 */
#elsesend2, /* 發送的數據,最大為4字節 */
#endifeSetValueWithOverwrite );/*覆蓋當前通知*/if( xReturn == pdPASS ){ OLED_ShowString(3,40,"receive2 send!",8,1);OLED_Refresh();}}
/*****************************************************************************/ }vTaskDelay(20);}
}
11-FreeRTOS任務通知代替二值信號量實驗
/******************************2023年10月18日*************************************
這是一個任務通知代替二值信號量的實驗,通過OLED與KEY觀察現象。
判斷KEY按下的次數來判斷發送哪一個通知,奇數通知接收任務1,偶數通知接收任務2
*********************************************************************************/
#include "system.h"
#include "SysTick.h"
#include "led.h"
#include "key.h"
#include "oled.h"
#include "usart.h"
#include "FreeRTOS.h"
#include "task.h"
#include "limits.h"//任務優先級
#define START_TASK_PRIO 1
//任務堆棧大小
#define START_STK_SIZE 128
//任務句柄
TaskHandle_t StartTask_Handler;
//任務函數
void start_task(void *pvParameters);//任務優先級
#define LED1_TASK_PRIO 2
//任務堆棧大小
#define LED1_STK_SIZE 50
//任務句柄
TaskHandle_t LED1Task_Handler;
//任務函數
void led1_task(void *pvParameters);//任務優先級
#define Receive1_TASK_PRIO 3
//任務堆棧大小
#define Receive1_STK_SIZE 512
//任務句柄
TaskHandle_t Receive1Task_Handler;
//任務函數
void Receive1_task(void *pvParameters);//任務優先級
#define Receive2_TASK_PRIO 4
//任務堆棧大小
#define Receive2_STK_SIZE 512
//任務句柄
TaskHandle_t Receive2Task_Handler;
//任務函數
void Receive2_task(void *pvParameters);//任務優先級
#define Send_TASK_PRIO 5
//任務堆棧大小
#define Send_STK_SIZE 512
//任務句柄
TaskHandle_t SendTask_Handler;
//任務函數
void Send_task(void *pvParameters);/*******************************************************************************
* 函 數 名 : main
* 函數功能 : 主函數
* 輸 入 : 無
* 輸 出 : 無
*******************************************************************************/
int main()
{SysTick_Init(72);NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//設置系統中斷優先級分組4USART1_Init(115200);KEY_Init();LED_Init();OLED_Init();OLED_ColorTurn(0);//0正常顯示,1 反色顯示 OLED_DisplayTurn(0);OLED_Clear();//創建開始任務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); //任務句柄 vTaskStartScheduler(); //開啟任務調度
}//開始任務任務函數
void start_task(void *pvParameters)
{taskENTER_CRITICAL(); //進入臨界區//創建LED1任務xTaskCreate((TaskFunction_t )led1_task, (const char* )"led1_task", (uint16_t )LED1_STK_SIZE, (void* )NULL,(UBaseType_t )LED1_TASK_PRIO,(TaskHandle_t* )&LED1Task_Handler); //創建Receive1任務xTaskCreate((TaskFunction_t )Receive1_task, (const char* )"Receive1_task", (uint16_t )Receive1_STK_SIZE, (void* )NULL,(UBaseType_t )Receive1_TASK_PRIO,(TaskHandle_t* )&Receive1Task_Handler);//創建Receive2任務xTaskCreate((TaskFunction_t )Receive2_task, (const char* )"Receive2_task", (uint16_t )Receive2_STK_SIZE, (void* )NULL,(UBaseType_t )Receive2_TASK_PRIO,(TaskHandle_t* )&Receive2Task_Handler);//創建Send任務xTaskCreate((TaskFunction_t )Send_task, (const char* )"Send_task", (uint16_t )Send_STK_SIZE, (void* )NULL,(UBaseType_t )Send_TASK_PRIO,(TaskHandle_t* )&SendTask_Handler);vTaskDelete(StartTask_Handler); //刪除開始任務taskEXIT_CRITICAL(); //退出臨界區
} //LED1任務函數
void led1_task(void *pvParameters)
{while(1){LED1=0;vTaskDelay(200);LED1=1;vTaskDelay(800);}
}//Receive1任務函數
void Receive1_task(void *pvParameters)
{while(1){//獲取任務通知 ,沒獲取到則一直等待ulTaskNotifyTake(pdTRUE,portMAX_DELAY);OLED_ShowString(3,0,"task1 received!",8,1);OLED_Refresh();}
}//Receive2任務函數
void Receive2_task(void *pvParameters)
{ while(1){//獲取任務通知 ,沒獲取到則一直等待ulTaskNotifyTake(pdTRUE,portMAX_DELAY);OLED_ShowString(3,20,"task2 received!",8,1);OLED_Refresh();}
}//Send任務函數
void Send_task(void *pvParameters)
{BaseType_t xReturn = pdPASS;u8 PRESS=0;while(1){if(KEY==1){ PRESS++;while(KEY==1);
/**************************************奇數發送Receive1*****************************************/ if(PRESS%2!=0){ xReturn = xTaskNotifyGive(Receive1Task_Handler);if( xReturn == pdTRUE ){OLED_ShowString(3,40,"task1 send!",8,1);OLED_Refresh();}}
/***************************************偶數發送Receive2**************************************/ else {xReturn = xTaskNotifyGive(Receive2Task_Handler);if( xReturn == pdTRUE ){OLED_ShowString(3,40,"task2 send!",8,1);OLED_Refresh();}}
/*****************************************************************************/ }vTaskDelay(20);}
}
12-FreeRTOS任務通知代替計數信號量實驗
/******************************2023年10月18日*************************************
這是一個任務通知代替計數信號量的實驗,通過OLED與KEY觀察現象。
KEY按下釋放信號量,長按可一直釋放信號量
take任務會一直獲取信號量
*********************************************************************************/
#include "system.h"
#include "SysTick.h"
#include "led.h"
#include "key.h"
#include "oled.h"
#include "usart.h"
#include "FreeRTOS.h"
#include "task.h"
#include "limits.h"//任務優先級
#define START_TASK_PRIO 1
//任務堆棧大小
#define START_STK_SIZE 128
//任務句柄
TaskHandle_t StartTask_Handler;
//任務函數
void start_task(void *pvParameters);//任務優先級
#define LED1_TASK_PRIO 2
//任務堆棧大小
#define LED1_STK_SIZE 50
//任務句柄
TaskHandle_t LED1Task_Handler;
//任務函數
void led1_task(void *pvParameters);//任務優先級
#define Take_TASK_PRIO 3
//任務堆棧大小
#define Take_STK_SIZE 512
//任務句柄
TaskHandle_t TakeTask_Handler;
//任務函數
void Take_task(void *pvParameters);//任務優先級
#define Give_TASK_PRIO 4
//任務堆棧大小
#define Give_STK_SIZE 512
//任務句柄
TaskHandle_t GiveTask_Handler;
//任務函數
void Give_task(void *pvParameters);/*******************************************************************************
* 函 數 名 : main
* 函數功能 : 主函數
* 輸 入 : 無
* 輸 出 : 無
*******************************************************************************/
int main()
{SysTick_Init(72);NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//設置系統中斷優先級分組4USART1_Init(115200);KEY_Init();LED_Init();OLED_Init();OLED_ColorTurn(0);//0正常顯示,1 反色顯示 OLED_DisplayTurn(0);OLED_Clear();//創建開始任務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); //任務句柄 vTaskStartScheduler(); //開啟任務調度
}//開始任務任務函數
void start_task(void *pvParameters)
{taskENTER_CRITICAL(); //進入臨界區//創建LED1任務xTaskCreate((TaskFunction_t )led1_task, (const char* )"led1_task", (uint16_t )LED1_STK_SIZE, (void* )NULL,(UBaseType_t )LED1_TASK_PRIO,(TaskHandle_t* )&LED1Task_Handler); //創建Take任務xTaskCreate((TaskFunction_t )Take_task, (const char* )"Take_task", (uint16_t )Take_STK_SIZE, (void* )NULL,(UBaseType_t )Take_TASK_PRIO,(TaskHandle_t* )&TakeTask_Handler);//創建Give任務xTaskCreate((TaskFunction_t )Give_task, (const char* )"Give_task", (uint16_t )Give_STK_SIZE, (void* )NULL,(UBaseType_t )Give_TASK_PRIO,(TaskHandle_t* )&GiveTask_Handler);vTaskDelete(StartTask_Handler); //刪除開始任務taskEXIT_CRITICAL(); //退出臨界區
} //LED1任務函數
void led1_task(void *pvParameters)
{while(1){LED1=0;vTaskDelay(200);LED1=1;vTaskDelay(800);}
}//Give任務函數
void Give_task(void *pvParameters)
{ BaseType_t xReturn = pdPASS;while(1){if(KEY==1){xReturn=xTaskNotifyGive(TakeTask_Handler);//發送任務通知if ( pdPASS == xReturn ) { OLED_ShowString(3,0,"release one!",8,1);OLED_Refresh();}}vTaskDelay(20);}
}//Take任務函數
void Take_task(void *pvParameters)
{uint32_t take_num = pdTRUE;while(1){take_num=ulTaskNotifyTake(pdFALSE,0);if(take_num > 0)OLED_ShowNum(3,20,take_num,4,8,1);elseOLED_ShowString(3,40,"wait",8,1); OLED_Refresh();vTaskDelay(20);}
}
13-FreeRTOS任務通知代替事件組實驗
/******************************2023年10月18日*************************************
這是一個任務通知代替事件組的實驗,通過OLED與KEY觀察現象。
KEY按下計數,通過計數的奇偶值來判斷產生哪一個事件
*********************************************************************************/
#include "system.h"
#include "SysTick.h"
#include "led.h"
#include "key.h"
#include "oled.h"
#include "usart.h"
#include "FreeRTOS.h"
#include "task.h"
#include "limits.h"//任務優先級
#define START_TASK_PRIO 1
//任務堆棧大小
#define START_STK_SIZE 128
//任務句柄
TaskHandle_t StartTask_Handler;
//任務函數
void start_task(void *pvParameters);//任務優先級
#define LED1_TASK_PRIO 2
//任務堆棧大小
#define LED1_STK_SIZE 50
//任務句柄
TaskHandle_t LED1Task_Handler;
//任務函數
void led1_task(void *pvParameters);//任務優先級
#define LED2_TASK_PRIO 3
//任務堆棧大小
#define LED2_STK_SIZE 50
//任務句柄
TaskHandle_t LED2Task_Handler;
//任務函數
void led2_task(void *pvParameters);//任務優先級
#define KEY_TASK_PRIO 4
//任務堆棧大小
#define KEY_STK_SIZE 512
//任務句柄
TaskHandle_t KEYTask_Handler;
//任務函數
void key_task(void *pvParameters);#define KEY1_EVENT (0x01 << 0)//設置事件掩碼的位0
#define KEY2_EVENT (0x01 << 1)//設置事件掩碼的位1/*******************************************************************************
* 函 數 名 : main
* 函數功能 : 主函數
* 輸 入 : 無
* 輸 出 : 無
*******************************************************************************/
int main()
{SysTick_Init(72);NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//設置系統中斷優先級分組4USART1_Init(115200);KEY_Init();LED_Init();OLED_Init();OLED_ColorTurn(0);//0正常顯示,1 反色顯示 OLED_DisplayTurn(0);OLED_Clear();//創建開始任務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); //任務句柄 vTaskStartScheduler(); //開啟任務調度
}//開始任務任務函數
void start_task(void *pvParameters)
{taskENTER_CRITICAL(); //進入臨界區//創建LED1任務xTaskCreate((TaskFunction_t )led1_task, (const char* )"led1_task", (uint16_t )LED1_STK_SIZE, (void* )NULL,(UBaseType_t )LED1_TASK_PRIO,(TaskHandle_t* )&LED1Task_Handler); //創建LED2任務xTaskCreate((TaskFunction_t )led2_task, (const char* )"led2_task", (uint16_t )LED2_STK_SIZE, (void* )NULL,(UBaseType_t )LED2_TASK_PRIO,(TaskHandle_t* )&LED2Task_Handler);//創建KEY任務xTaskCreate((TaskFunction_t )key_task, (const char* )"key_task", (uint16_t )KEY_STK_SIZE, (void* )NULL,(UBaseType_t )KEY_TASK_PRIO,(TaskHandle_t* )&KEYTask_Handler);vTaskDelete(StartTask_Handler); //刪除開始任務taskEXIT_CRITICAL(); //退出臨界區
} //LED1任務函數
void led1_task(void *pvParameters)
{while(1){LED1=0;vTaskDelay(200);LED1=1;vTaskDelay(800);}
}//LED2任務函數
void led2_task(void *pvParameters)
{BaseType_t xReturn = pdTRUE;uint32_t r_event = 0; /* 定義一個事件接收變量 */uint32_t last_event = 0;/* 定義一個保存事件的變量 */while(1){//獲取任務通知 ,沒獲取到則一直等待xReturn = xTaskNotifyWait(0x0, //進入函數的時候不清除任務bitULONG_MAX, //退出函數的時候清除所有的bitR&r_event, //保存任務通知值 portMAX_DELAY); //阻塞時間if( pdTRUE == xReturn ){last_event |= r_event;if(last_event == (KEY1_EVENT|KEY2_EVENT)){last_event=0;LED2=!LED2;}elselast_event = r_event;}}
}//KEY任務函數
void key_task(void *pvParameters)
{u8 PRESS=0;while(1){if(KEY==1){ PRESS++;while(KEY==1); if(PRESS%2!=0) {OLED_ShowString(3,0,"KEY1_EVENT!",8,1);/* 觸發一個事件1 */xTaskNotify((TaskHandle_t )LED2Task_Handler,//接收任務通知的任務句柄(uint32_t )KEY1_EVENT,//要觸發的事件(eNotifyAction)eSetBits);//設置任務通知值中的位}else{OLED_ShowString(3,20,"KEY2_EVENT!",8,1);/* 觸發一個事件2 */xTaskNotify((TaskHandle_t )LED2Task_Handler,//接收任務通知的任務句柄(uint32_t )KEY2_EVENT,//要觸發的事件(eNotifyAction)eSetBits);//設置任務通知值中的位}}OLED_Refresh();vTaskDelay(20);}
}
14-FreeRTOS內存管理實驗
/******************************2023年10月18日*************************************
這是一個內存管理實驗,通過OLED與KEY觀察現象。
KEY按下計數,通過計數的奇偶值來判斷產生申請內存還是釋放內存
顯示申請到的內存地址,以及申請內存后的剩余空間,以及系統運行時間
*********************************************************************************/
#include "system.h"
#include "SysTick.h"
#include "led.h"
#include "key.h"
#include "oled.h"
#include "usart.h"
#include "FreeRTOS.h"
#include "task.h"
#include "limits.h"//任務優先級
#define START_TASK_PRIO 1
//任務堆棧大小
#define START_STK_SIZE 128
//任務句柄
TaskHandle_t StartTask_Handler;
//任務函數
void start_task(void *pvParameters);
/******************************************************************************/
//任務優先級
#define LED1_TASK_PRIO 2
//任務堆棧大小
#define LED1_STK_SIZE 50
//任務句柄
TaskHandle_t LED1Task_Handler;
//任務函數
void led1_task(void *pvParameters);
/******************************************************************************/
//任務優先級
#define KEY_TASK_PRIO 4
//任務堆棧大小
#define KEY_STK_SIZE 512
//任務句柄
TaskHandle_t KEYTask_Handler;
//任務函數
void key_task(void *pvParameters);uint8_t *Test_Ptr = NULL;/*******************************************************************************
* 函 數 名 : main
* 函數功能 : 主函數
* 輸 入 : 無
* 輸 出 : 無
*******************************************************************************/
int main()
{SysTick_Init(72);NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//設置系統中斷優先級分組4USART1_Init(115200);KEY_Init();LED_Init();OLED_Init();OLED_ColorTurn(0);//0正常顯示,1 反色顯示 OLED_DisplayTurn(0);OLED_Clear();//創建開始任務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); //任務句柄 vTaskStartScheduler(); //開啟任務調度
}//開始任務任務函數
void start_task(void *pvParameters)
{taskENTER_CRITICAL(); //進入臨界區//創建LED1任務xTaskCreate((TaskFunction_t )led1_task, (const char* )"led1_task", (uint16_t )LED1_STK_SIZE, (void* )NULL,(UBaseType_t )LED1_TASK_PRIO,(TaskHandle_t* )&LED1Task_Handler); //創建KEY任務xTaskCreate((TaskFunction_t )key_task, (const char* )"key_task", (uint16_t )KEY_STK_SIZE, (void* )NULL,(UBaseType_t )KEY_TASK_PRIO,(TaskHandle_t* )&KEYTask_Handler);vTaskDelete(StartTask_Handler); //刪除開始任務taskEXIT_CRITICAL(); //退出臨界區
} //LED1任務函數
void led1_task(void *pvParameters)
{while(1){LED1=0;vTaskDelay(200);LED1=1;vTaskDelay(800);}
}//KEY任務函數
void key_task(void *pvParameters)
{u8 PRESS=0;uint32_t g_memsize;while(1){if(KEY==1){while(KEY==1);PRESS++;if(PRESS%2!=0){if(NULL == Test_Ptr){/* 獲取當前內存大小 */g_memsize = xPortGetFreeHeapSize(); OLED_ShowString(3,0,"rest ram:",8,1);OLED_ShowNum(60,0,g_memsize,9,8,1);Test_Ptr = pvPortMalloc(1024); //申請1k內存if(NULL != Test_Ptr){OLED_ShowString(3,20,"get ram:",8,1);sprintf((char*)Test_Ptr," %#x \n",Test_Ptr); //轉變為16進制數據OLED_ShowString(60,20,(char*)Test_Ptr,8,1); //顯示地址/* 獲取當前內剩余存大小 */g_memsize = xPortGetFreeHeapSize();OLED_ShowString(3,40,"rest ram:",8,1);OLED_ShowNum(60,40,g_memsize,9,8,1);//向Test_Ptr中寫入當數據:當前系統時間sprintf((char*)Test_Ptr,"TickCount = %d \n",xTaskGetTickCount());
// printf("寫入的數據是 %s \n",(char*)Test_Ptr);OLED_ShowString(3,50,(char*)Test_Ptr,8,1);}}elseprintf("請先按下KEY2釋放內存再申請\n");}else{if(NULL != Test_Ptr){ OLED_Clear();OLED_ShowString(3,0,"clear ram",8,1);vPortFree(Test_Ptr);//釋放內存Test_Ptr=NULL;/* 獲取當前內剩余存大小 */g_memsize = xPortGetFreeHeapSize();OLED_ShowString(3,20,"rest ram:",8,1);OLED_ShowNum(60,20,g_memsize,9,8,1);}elseprintf("請先按下KEY1申請內存再釋放\n");}}OLED_Refresh();vTaskDelay(20);}
}
15-FreeRTOS-CPU利用率實驗
/******************************2023年10月18日*************************************
這是一個CPU利用率實驗,通過USART1與XCOM觀察現象。
串口會不斷的打印CPU利用情況
本次需要使用硬件定時器來統計CPU運行時間,頻率為10000HZ
需修改配置文件如下內容/********************************************************************FreeRTOS與運行時間和任務狀態收集有關的配置選項
**********************************************************************/
//啟用運行時間統計功能
//#define configGENERATE_RUN_TIME_STATS 1 //啟用可視化跟蹤調試
//#define configUSE_TRACE_FACILITY 1
/* 與宏configUSE_TRACE_FACILITY同時為1時會編譯下面3個函數* prvWriteNameToBuffer()* vTaskList(),* vTaskGetRunTimeStats()
*/
//#define configUSE_STATS_FORMATTING_FUNCTIONS 1
//
// extern volatile uint32_t CPU_RunTime;//#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() (CPU_RunTime = 0ul)
//#define portGET_RUN_TIME_COUNTER_VALUE() CPU_RunTime *********************************************************************************/
#include "system.h"
#include "SysTick.h"
#include "led.h"
#include "key.h"
#include "oled.h"
#include "usart.h"
#include "FreeRTOS.h"
#include "task.h"
#include "limits.h"
#include "timer.h"
#include "string.h"
/************************************************************/
//任務優先級
#define START_TASK_PRIO 1
//任務堆棧大小
#define START_STK_SIZE 128
//任務句柄
TaskHandle_t StartTask_Handler;
//任務函數
void start_task(void *pvParameters);
/************************************************************/
//任務優先級
#define LED1_TASK_PRIO 2
//任務堆棧大小
#define LED1_STK_SIZE 50
//任務句柄
TaskHandle_t LED1Task_Handler;
//任務函數
void led1_task(void *pvParameters);
/************************************************************/
//任務優先級
#define LED2_TASK_PRIO 3
//任務堆棧大小
#define LED2_STK_SIZE 50
//任務句柄
TaskHandle_t LED2Task_Handler;
//任務函數
void led2_task(void *pvParameters);
/************************************************************///任務優先級
#define CPU_TASK_PRIO 4
//任務堆棧大小
#define CPU_STK_SIZE 512
//任務句柄
TaskHandle_t CPUTask_Handler;
//任務函數
void CPU_task(void *pvParameters);
/************************************************************//*******************************************************************************
* 函 數 名 : main
* 函數功能 : 主函數
* 輸 入 : 無
* 輸 出 : 無
*******************************************************************************/
int main()
{SysTick_Init(72);NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//設置系統中斷優先級分組4USART1_Init(115200);KEY_Init();LED_Init();TIM2_Int_Init(100-1,72-1);printf("Freertos CPU利用率實驗\r\n");//創建開始任務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); //任務句柄 vTaskStartScheduler(); //開啟任務調度
}//開始任務任務函數
void start_task(void *pvParameters)
{taskENTER_CRITICAL(); //進入臨界區//創建LED1任務xTaskCreate((TaskFunction_t )led1_task, (const char* )"led1_task", (uint16_t )LED1_STK_SIZE, (void* )NULL,(UBaseType_t )LED1_TASK_PRIO,(TaskHandle_t* )&LED1Task_Handler);//創建LED2任務xTaskCreate((TaskFunction_t )led2_task, (const char* )"led2_task", (uint16_t )LED2_STK_SIZE, (void* )NULL,(UBaseType_t )LED2_TASK_PRIO,(TaskHandle_t* )&LED2Task_Handler);//創建CPU任務xTaskCreate((TaskFunction_t )CPU_task, (const char* )"CPU_task", (uint16_t )CPU_STK_SIZE, (void* )NULL,(UBaseType_t )CPU_TASK_PRIO,(TaskHandle_t* )&CPUTask_Handler);vTaskDelete(StartTask_Handler); //刪除開始任務taskEXIT_CRITICAL(); //退出臨界區
} //LED1任務函數
void led1_task(void *pvParameters)
{while(1){LED1=0;vTaskDelay(200);printf("LED1_Task Running,LED2_ON\r\n");LED1=1;vTaskDelay(800);printf("LED1_Task Running,LED2_OFF\r\n");}
}//LED2任務函數
void led2_task(void *pvParameters)
{while(1){LED2=0;vTaskDelay(800);printf("LED2_Task Running,LED2_ON\r\n");LED2=1;vTaskDelay(200);printf("LED2_Task Running,LED2_OFF\r\n");}
}//CPU任務函數
void CPU_task(void *pvParameters)
{uint8_t CPU_RunInfo[400];//保存任務運行時間信息while(1){memset(CPU_RunInfo,0,400);//信息緩沖區清零vTaskList((char *)&CPU_RunInfo); //獲取任務運行時間信息printf("---------------------------------------------\r\n");printf("任務名 任務狀態 優先級 剩余棧 任務序號\r\n");printf("%s", CPU_RunInfo);printf("---------------------------------------------\r\n");memset(CPU_RunInfo,0,400); //信息緩沖區清零vTaskGetRunTimeStats((char *)&CPU_RunInfo);printf("任務名 運行計數 利用率\r\n");printf("%s", CPU_RunInfo);printf("---------------------------------------------\r\n\n");vTaskDelay(1000); /* 延時1000個tick */}
}
16-FreeRTOS中斷管理實驗
/******************************2023年10月18日*************************************
這是一個中斷管理實驗,通過設置中斷優先級來起到控制作用。
freertos中斷開關管理可以管理優先級低的
中斷優先級數值越小,優先級越高。
默認中斷管理閾值為5,優先級數值高于或等于5的中斷可以被管理
任務優先級數值小于5的中斷不會被管理,因為優先級更高。
*********************************************************************************/
#include "system.h"
#include "SysTick.h"
#include "led.h"
#include "key.h"
#include "oled.h"
#include "usart.h"
#include "FreeRTOS.h"
#include "task.h"
#include "limits.h"
#include "timer.h"
#include "string.h"
/************************************************************/
//任務優先級
#define START_TASK_PRIO 1
//任務堆棧大小
#define START_STK_SIZE 128
//任務句柄
TaskHandle_t StartTask_Handler;
//任務函數
void start_task(void *pvParameters);//任務優先級
#define LED1_TASK_PRIO 2
//任務堆棧大小
#define LED1_STK_SIZE 512
//任務句柄
TaskHandle_t LED1Task_Handler;
//任務函數
void led1_task(void *pvParameters);//任務優先級
#define Interrupt_TASK_PRIO 4
//任務堆棧大小
#define Interrupt_STK_SIZE 512
//任務句柄
TaskHandle_t InterruptTask_Handler;
//任務函數
void Interrupt_task(void *pvParameters);extern volatile uint32_t TIME2_RUN;
extern volatile uint32_t TIME3_RUN;
/*******************************************************************************
* 函 數 名 : main
* 函數功能 : 主函數
* 輸 入 : 無
* 輸 出 : 無
*******************************************************************************/
int main()
{SysTick_Init(72);NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//設置系統中斷優先級分組4USART1_Init(115200);KEY_Init();LED_Init();OLED_Init();OLED_ColorTurn(0);//0正常顯示,1 反色顯示 OLED_DisplayTurn(0);OLED_Clear();TIM2_Int_Init(10000-1,7200-1); //1s中斷TIM3_Int_Init(10000-1,7200-1); //1s中斷printf("Freertos CPU利用率實驗\r\n");//創建開始任務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); //任務句柄 vTaskStartScheduler(); //開啟任務調度
}//開始任務任務函數
void start_task(void *pvParameters)
{taskENTER_CRITICAL(); //進入臨界區//創建LED1任務xTaskCreate((TaskFunction_t )led1_task, (const char* )"led1_task", (uint16_t )LED1_STK_SIZE, (void* )NULL,(UBaseType_t )LED1_TASK_PRIO,(TaskHandle_t* )&LED1Task_Handler); //創建Interrupt任務xTaskCreate((TaskFunction_t )Interrupt_task, (const char* )"Interrupt_task", (uint16_t )Interrupt_STK_SIZE, (void* )NULL,(UBaseType_t )Interrupt_TASK_PRIO,(TaskHandle_t* )&InterruptTask_Handler);vTaskDelete(StartTask_Handler); //刪除開始任務taskEXIT_CRITICAL(); //退出臨界區
} //LED1任務函數
void led1_task(void *pvParameters)
{ while(1){OLED_ShowNum(3,0,TIME3_RUN,4,8,1);OLED_ShowNum(3,20,TIME2_RUN,4,8,1);OLED_Refresh();vTaskDelay(200);}
}//Interrupt任務函數
void Interrupt_task(void *pvParameters)
{static u32 total_num=0;while(1){total_num+=1; if(total_num==5){printf("關閉中斷.............\r\n");portDISABLE_INTERRUPTS(); //關閉中斷delay_xms(6000); //延時6s,使用不影響任務調度的延時printf("打開中斷.............\r\n"); //打開中斷portENABLE_INTERRUPTS();}LED2=!LED2;vTaskDelay(1000);}
}