FreeRTOS內核應用開發學習手記移植任務狀態遷移任務創建與刪除任務掛起與恢復任務延時消息隊列信號量事件軟件定時器任務通知內存管理
FreeRTOS內核應用開發學習手記
移植
1、解壓並添加官方源碼到工程中,包括:
FreeRTOS\Source\*.c
FreeRTOS\Source\include\*.h
FreeRTOS\Source\portable\MemMang\heap_4.c
FreeRTOS\Source\portable\RVDS\ARM_CM4F\*
FreeRTOS\Demo\CORTEX_STM32F103_Keil\FreeRTOSConfig.h
2、修改FreeRTOSConfig.h:
#include "stm32f103.h"
改爲你的,如
#include "stm32f4xx.h"
3、註釋原工程中:
void SVC_Handler(void) {}
void PendSV_Handler(void) {}
4、修改SysTick中斷服務函數
extern void xPortSysTickHandler(void);
//systick中斷服務函數
void SysTick_Handler(void)
{
TimingDelay_Decrement();
#if (INCLUDE_xTaskGetSchedulerState == 1 )
if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED)
{
#endif /* INCLUDE_xTaskGetSchedulerState */
xPortSysTickHandler();
#if (INCLUDE_xTaskGetSchedulerState == 1 )
}
#endif /* INCLUDE_xTaskGetSchedulerState */
}
5、完成
任務狀態遷移
任務創建與刪除
BaseType_t xReturn = pdPASS; // 返回值
TaskHandle_t testHandle = NULL; // 任務句柄
xReturn = xTaskCreate((TaskFunction_t) TaskTest, // 任務入口函數
(const char*) "TaskTest"), // 任務名字
(uint16_t) 512, // 任務棧大小
(void*) NULL, // 任務入口函數參數
(UBaseType_t)3, // 任務優先級
(TaskHandle_t*)&testHandle); // 控制塊指針
if(xReturn == pdPASS){
vTaskStartScheduler(); // 啓動任務調度
}
vTaskDelete(testHandle); // 刪除指定任務
vTaskDelete(NULL); // 刪除任務自身
任務掛起與恢復
// 掛起任務
vTaskSuspend(taskHandle);
// 掛起全部任務
vTaskSuspendAll();
// 恢復任務
vTaskResume(taskHandle);
// 恢復全部任務
vTaskResumeAll();
// 從中斷恢復任務
BaseType_t xYieldRequired = xTaskResumeFromISR(taskHandle);
if(xYieldRequired == pdTRUE){
portYIELD_FROM_ISR(); // 執行上下文切換
}
任務延時
/***********************相對延時**************************/
// 相對延時,延時100個tick,不排除調用前後任務被搶佔
vTaskDelay(100);
/* ...code... */
/***********************絕對延時*************************/
// 絕對延時,固定頻率運行
static portTickType previousWakeTime; // 保存上一次時間,系統自動更新
const portTickType timeIncrement = pdMS_TO_TICKS(100); // 延時時間
previousWakeTime = xTaskGetTickCount(); // 當前系統時間
while(1){
vTaskDelayUntil(&previousWakeTime, timeIncrement); // 間隔100個tick
/* ...code... */
}
消息隊列
configSUPPORT_DYNAMIC_ALLOCATION = 1
/************************創建隊列***********************/
#define QUEUE_LEN 4 // 隊列長度,最大消息數
#define QUEUE_SIZE 4 // 每個消息的大小(字節)
BaseType_t xReturn = pdPASS; // 返回值
QueueHandle_t queueHandle = NULL; // 隊列句柄
taskENTER_CRITICAL(); // 進入臨界區
queueHandle = xQueueCreate((UBaseType_t) QUEUE_LEN, // 長度
(UBaseType_t) QUEUE_SIZE); // 大小
if(NULL != queueHandle){
printf("創建成功\r\n"); // 創建成功
}
taskEXIT_CRITICAL(); // 退出臨界區
/*********************任務中發到隊尾***********************/
vQueueDelete(queueHandle); // 刪除隊列
uint32_t sendData = 1; // 待發送內容
xReturn = xQueueSend(queueHandle, // 隊列句柄
&sendData, // 發送內容
0); // 等待時間
if(pdPASS == xReturn){ // 發送成功
printf("發送成功\r\n");
}
/*********************中斷中發到隊尾**********************/
BaseType_t xHigherPriorityTaskWoken = pdFALSE; // 從中斷髮送隊列消息
xQueueSendFromISR(queueHandle,&sendData,&xHigherPriorityTaskWoken);
if(xHigherPriorityTaskWoken){
taskYIELD_FROM_ISR(); // 上下文切換
}
/**********************其他發到隊首***********************/
xQueueSendToFront(...); // 發到隊首
xQueueSendToFrontFromISR(...); // 中斷中發到隊首
/*********************任務中接收消息**********************/
uint32_t getData; // 待接收內容
xReturn = xQueueRecevie(queueHandle, // 隊列句柄(會刪除隊列消息)
&getData, // 接收內容
portMAX_DELAY); // 等待時間,一直等
if(pdTRUE == xReturn){ // 獲取成功
print("接收到:%d\r\n", getData);
}
xQueuePeek(...) // 獲取隊列消息,但不刪除隊列中的內容,用法一樣
/********************中斷中接收消息**********************/
BaseType_t xTaskWokenByReceive = pdFALSE;
xQueueReceiveFromISR(queueHandle, &getData, xTaskWokenByReceive);
if(xTaskWokenByReceive != pdFALSE){
taskYIELD(); // 上下文切換
}
信號量
信號量可以由其他任務刪除,互斥量只能由當前任務刪除。
互斥量可減小“優先級翻轉”現象的影響。
configUSE_MUTEXES = 1
configUSE_RECURSIVE_MUTEXES = 1
configQUEUE_REGISTRY_SIZE = 10
/********************二值信號量**********************/
SemaphoreHandle_t semaphoreHandle = NULL; // 信號量句柄
semaphoreHandle = xSemaphoreCreateBinary(); // 創建二值信號量
if(semaphoreHandle != NULL){ // 創建成功
print("創建成功\r\n");
}
/********************計數信號量**********************/
semaphoreHandle = xSemaphoreCreateCounting(5, // 最大技術到5
5); // 初始當前計數值爲5
if(semaphoreHandle != NULL){ // 創建成功
print("創建成功\r\n");
}
/********************互斥信號量**********************/
semaphoreHandle = xSemaphoreCreateMutex(); // 創建單次互斥量
if(semaphoreHandle != NULL){ // 創建成功
print("創建成功\r\n");
}
semaphoreHandle = xSemaphoreCreateRecursiveMutex(); // 創建遞歸互斥量
if(semaphoreHandle != NULL){ // 創建成功
print("創建成功\r\n");
}
/********************刪除信號量**********************/
vSemaphoreDelete(semaphoreHandle);
/******************任務中釋放信號量*******************/
xReturn = xSemaphoreGive(semaphoreHandle);
if(pdTRUE == xReturn){
print("釋放成功\r\n");
}
xSemaphoreGiveRecursive(...); // 釋放遞歸互斥量,其他一樣
/******************中斷中釋放信號量*******************/
BaseType_t pxHigherPriorityTaskWoken;
xSemaphoreGiveFromISR(semaphoreHandle, &pxHigherPriorityTaskWoken);
portYIELD_FROM_ISR(pxHigherPriorityTaskWoken); // 上下文切換
/*****************任務中獲取信號量********************/
xReturn = xSemaphoreTake(semaphoreHandle, // 信號量句柄
portMAX_DELAY) // 等待時間,一直等
if(pdTRUE == xReturn){
print("獲取成功\r\n");
}
xSemaphoreTakeRecursive(...); // 獲取遞歸互斥量,其他一樣
/*****************中斷中獲取信號量********************/
很少用到
事件
configUSE_16_BIT_TICKS = 0
/*****************任務中創建事件*********************/
EventGroupHandle_t eventHandle = NULL; // 事件句柄
eventHandle = xEventGroupCreate(); // 創建事件
if(NULL != eventHandle){ // 創建成功
print("創建成功\r\n");
}
xEventGroupDelete(eventHandle); // 刪除事件
#define BIT0 (0x01 << 0) //
#define BIT1 (0x01 << 1) //
/*****************任務中設置事件********************/
EventBits_t rReturn; // 返回值,返回的置位前的值
rReturn = xEventGroupSetBits(eventHandle, // 事件句柄
BIT0 | BIT1); // 置位事件組
/*****************中斷中設置事件********************/
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
BaseType_t xResult;
xResult = xEventGroupSetBitsFromISR(eventHandle,
BIT0 | BIT1,
&xHigherPriorityTaskWoken);
if(pdFAIL != xResult){
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
/*****************任務中等待事件********************/
EventBits_t rReturn;
rReturn = xEventGroupWaitBits(eventHandle, // 事件句柄
BIT0|BIT1, // 事件組
pdTRUE, // 退出時清除事件
pdTRUE, // 等待所有事件
portMAX_DELAY) // 超時等待時間
if((rReturn&(BIT0|BIT1)) == (BIT0|BIT1)){ // 兩個事件都到達
print("BIT0和BIT1都到達\r\n");
}
/*****************任務中清除事件********************/
EventBits_t uxBits; // 返回值,返回的清除前的值
uxBits = xEventGroupClearBits(eventHandle, BITO|BIT1);
軟件定時器
configUSE_TIMERS = 1
configTIMER_TASK_PRIORITY = (configMAX_PRIORITIES-1)
configTIMER_QUEUE_LENGTH = 10
/*****************任務中創建定時器********************/
TimerHandle_t swtmrHandle = NULL; // 定時器句柄
BaseType_t xReturn;
void SwtFun(void* parameter){} // 自定義回調函數
swtmrHandle = xTimerCreate((const char*)"time1", // 定時器名字
(TickType_t)1000, // 週期1000tick
(UBaseType_t)pdTRUE, // 循環模式
(void*)1, // 唯一ID
(TimerCallbackFunction_t)SwtFun);//回調函數
/*****************任務中啓動定時器********************/
if(NULL != swtmrHandle){ // 創建成功
xTimerStart(swtmrHandle, // 啓動定時器
0); // 等待時間0
}
xReturn = vTimerStop(swtmrHandle, 0); // 停止軟件定時器
xReturn = xTimerDelete(swtmrHandle, 0); // 刪除軟件定時器
/*****************中斷中啓動定時器********************/
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
xReturn = xTimerStartFromISR(swtmrHandle,&xHigherPriorityTaskWoken);
if(pdPASS == xReturn){
print("啓動成功\r\n");
}
if(xHigherPriorityTaskWoken){
// 上下文切換
}
xReturn = vTimerStopFromISR(swtmrHandle, &xHigherPriorityTaskWoken);
if(pdPASS == xReturn){
print("停止成功\r\n");
}
if(xHigherPriorityTaskWoken){
// 上下文切換
}
任務通知
configUSE_TASK_NOTIFICATIONS = 1
// 發送通知部分
/*****************xTaskNotifyGive()********************/
TaskHandle_t taskHandle;
xTaskNotifyGive(taskHandle); // 向taskHandle發送通知
ulTaskNotifyTake(pdTRUE, // 退出時清空任務計數
portMAX_DELAY); // 阻塞等待通知
/*************vTaskNotifyGiveFromISR()*****************/
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
vTaskNotifyGiveFromISR(taskHandle, &xHigherPriorityTaskWoken);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken); // 上下文切換
/******************xTaskNotify()***********************/
xTaskNotify(taskHandle, 0, eNoAction);
“eAction取值:eNoAction、eSetBits、eIncrement、eSetValueWithOverwrite、eSetValueWithoutOverwrite”
/***************xTaskNotifyFromISR()*******************/
xTaskNotifyFromISR(taskHandle, 0, eNoAction, &xHigherPriTaskWoken);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken); // 上下文切換
/***************xTaskNotifyAndQuery()******************/
uint32_t ulPreviousValue; // 存對象任務的上一個任務通知值,爲NULL則不用回傳
xTaskNotifyAndQuery(taskHandle, 0, eSetBits, &ulPreviousValue)
/************xTaskNotifyAndQueryFromISR()**************/
xTaskNotifyAndQueryFromISR(taskHandle,
0,
eSetBits,
&ulPreviousValue,
&xHigherPriorityTaskWoken);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken); // 上下文切換
// 獲取通知部分
/****************ulTaskNotifyTake()*******************/
uint32_t res; // 返回任務的當前通知值(減1或清0之前的值)
res = ulTaskNotifyTake(pdTRUE, // 退出時清零(pdFALSE則減一)
portMAX_DELAY); // 等待時間
/****************xTaskNotifyWait()********************/
uint32_t ulNotifiedValue; // 存接收到的任務通知值,爲NULL則不需要
BaseType_t res;
res = xTaskNotifyWait(0x00, // 使用通知前,任務通知值的哪些位清0
ULONG_MAX, // 結束本函數前,接收到的通知值的哪些位清0
&ulNotifiedValue, // 保存接收到的任務通知值
portMAX_DELAY); // 等待時間
if((ulNotifiedValue & 0x01) != 0){
/* 位0被置1 */
}
內存管理
/****************heap_4.c*******************/
//系統所有總的堆大小
#define configTOTAL_HEAP_SIZE ((size_t)(36*1024))
uint32_t g_memsize = xPortGetFreeHeapSize(); // 獲取剩餘內存
uint8_t* ptr = pvPortMalloc(1024); // 申請1024字節內存
if(NULL != ptr) { // 獲取成功
printf("\r\n");
}
vPortFree(ptr); // 釋放內存