FreeRTOS移植完成後,就要來進行程式撰寫與測試,FreeRTOS的程式碼可分成任務、通訊和硬體界面這三個區塊,
1. 任務(task)在FreeRTOS中的基本單位,每個task是由C函數所組成,首先建立C語言的函數,再使用xTaskCreate()這個API來建立一個task,task通常會在一個無限迴圈中進行,FreeRTOS不允許task自行結束
2. 通訊在task間的溝通是透過把資料傳送到queue和讀取queue中資料實現
3. 硬體界面在好幾千行的FreeRTOS程式碼中,將FreeRTOS核心代碼與硬體做了結合,可使FreeRTOS在不同硬體平台上運行
以簡單的程式來講解FreeRTOS任務(task)要怎麼使用,第一支API是建立任務xTaskCreate,函數說明如下,
BaseType_t xTaskCreate(
TaskFunction_t pvTaskCode,
const char * const pcName,
configSTACK_DEPTH_TYPE usStackDepth,
void *pvParameters,
UBaseType_t uxPriority,
TaskHandle_t *pvCreatedTask
);
# TaskFunction_t pvTaskCode: 將建立好的C語言函數設置在此任務中,此C語言函數不得有回傳(return)的方法
# const char * const pcName: 任務的名字,在FreeRTOS不會用到它,這只是用於debug用途,名字長度限制為configMAX_TASK_NAME_LEN,為16個字元
# configSTACK_DEPTH_TYPE usStackDepth: 指定此任務stack的數量,例如stack寬度為16 bits,usStackDepth可設為100或200,將被分配用於stack儲存
# void *pvParameters: 要傳給task的參數陣列,也就是我們在C函數宣告的參數
# UBaseType_t uxPriority: 任務運行優先權設定
# TaskHandle_t *pvCreatedTask: 這個task的reference,用於動態調整這個task的priority,或是刪掉這個task
# BaseType_t: 會回傳此任務是否創建成功,創建成功會回pdPASS代碼,否則會回projdefs.h中定義一個錯誤代碼
了解xTaskCreate後就以實際範例來做說明,此範例需要建立配置GPIO與UART這兩個功能才能運行,將建立配置好的GPIO與UART放在STM32F407_Configuration資料夾裡,如下所示,
本人會在增加task_programs.c與task_programs.h這兩支程式來撰寫FreeRTOS任務程式,存放在User資料夾內,如下所示,
task_programs.c程式如下所示,
#include "task_programs.h"
/* 任務控制代碼 */
TaskHandle_t vTaskOne,vTaskTwo;
/*
程式名稱:創建任務
程式版本:V1.0
程式撰寫者:Michael Jheng(鄭智遠)
程式撰寫日期:2018/1/8
程式修改日期:N/A
程式說明:
*/
void AppTaskCreate(void){
/* 創建任務LED1 */
if(xTaskCreate(vTaskLED1, "vTask LED1", 512, "LED1 RUN\r\n", 2, &vTaskOne)==pdPASS){
UART2_Send((uint8_t*)"LED1 PASS\r\n", 11);
}else{
UART2_Send((uint8_t*)"LED1 ERROR\r\n", 12);
}
/* 創建任務LED2 */
if(xTaskCreate(vTaskLED2, "vTask LED2", 512, "LED2 RUN\r\n", 1, &vTaskTwo)==pdPASS){
UART2_Send((uint8_t*)"LED2 PASS\r\n", 11);
}else{
UART2_Send((uint8_t*)"LED2 ERROR\r\n", 12);
}
}
/*
程式名稱:任務LED1
程式版本:V1.0
程式撰寫者:Michael Jheng(鄭智遠)
程式撰寫日期:2018/1/8
程式修改日期:N/A
程式說明:
*/
void vTaskLED1(void *pvParameters){
portTickType xLastWakeTime = xTaskGetTickCount();
for(;;){
if(GPIO_ReadOutputDataBit(GPIOF, GPIO_Pin_10)==1){
GPIO_SetBits(GPIOF, GPIO_Pin_9);
}else{
GPIO_ResetBits(GPIOF, GPIO_Pin_9);
}
/* 顯示此任務訊息 */
UART2_Send(pvParameters, strlen(pvParameters));
vTaskDelayUntil( &xLastWakeTime, (500/portTICK_RATE_MS));
}
}
/*
程式名稱:任務LED2
程式版本:V1.0
程式撰寫者:Michael Jheng(鄭智遠)
程式撰寫日期:2018/1/8
程式修改日期:N/A
程式說明:
*/
void vTaskLED2(void *pvParameters){
portTickType xLastWakeTime = xTaskGetTickCount();
for(;;){
if(GPIO_ReadOutputDataBit(GPIOF, GPIO_Pin_10)==0){
GPIO_SetBits(GPIOF, GPIO_Pin_10);
}else{
GPIO_ResetBits(GPIOF, GPIO_Pin_10);
}
/* 顯示此任務訊息 */
UART2_Send(pvParameters, strlen(pvParameters));
vTaskDelayUntil( &xLastWakeTime, (500/portTICK_RATE_MS));
}
}
task_programs.h程式如下所示,
#ifndef __TASK_PROGRAMS_H
#define __TASK_PROGRAMS_H
#include "main.h"
/* 創建任務 */
void AppTaskCreate(void);
/* 任務LED1 */
void vTaskLED1(void *pvParameters);
/* 任務LED2 */
void vTaskLED2(void *pvParameters);
#endif
其他程式部分bsp.c如下所示,
#include "bsp.h"
/*
程式名稱:開發板全域變數初始化
程式版本:V1.0
程式撰寫者:Michael Jheng(鄭智遠)
程式撰寫日期:2018/1/6
程式修改日期:N/A
程式說明:
*/
void BSP_VariableInit(void){
uint16_t i=0;
for(i=0; i<255; i++){
UART2_Ptr->rxData[i] = 0;
}
UART2_Ptr->rxCount = 0;
UART2_Ptr->rxFlag = 0;
}
/*
程式名稱:開發板整體系統初始化
程式版本:V1.0
程式撰寫者:Michael Jheng(鄭智遠)
程式撰寫日期:2018/1/6
程式修改日期:N/A
程式說明:
*/
void BSP_Init(void){
/* 設置系統中斷優先級分組4 */
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
/* GPIO配置初始化 */
GPIO_CONFIGInit();
/* UART2配置初始化 */
UART2_ConfigInit(115200);
/* 創建任務 */
AppTaskCreate();
/* 任務排程開始 */
vTaskStartScheduler();
}
main.c程式如下所示,
#include "main.h"
/*
程式名稱:主程式
程式版本:V1.0
程式撰寫者:Michael Jheng(鄭智遠)
程式撰寫日期:2018/1/6
程式修改日期:N/A
程式說明:
*/
int main(void){
/* 開發板全域變數初始化 */
BSP_VariableInit();
/* 開發板整體系統初始化 */
BSP_Init();
/* Infinite loop */
for(;;){
}
}
把程式編譯完成後,無錯誤就點擊上方LOAD圖示把程式燒入至MCU,
執行結果如下,LED1 PASS與LED2 PASS就代表任務創建成功,由於LED1任務權限比LED2任務大,所以LED1 RUN訊息會先出現,再來出現LED2 RUN,
LED呈現結果如下,紅色與綠色LED交互閃爍,
留言列表