FreeRTOS學習筆記——移植FreeRTOS至核心板

第一步:官網下載FreeRTOS v10.2.1,解壓後包含的文件如下圖所示
FreeRTOS v10.2.1包含的文件
第二步:提取FreeRTOS文件。將…\FreeRTOSv10.2.1\FreeRTOSv10.2.1_191129\FreeRTOS\Source文件夾複製到裸機工程模板的FreeRTOS v10.2.1文件夾,將portable文件夾中除keil、MemMang、RVDS文件夾外的其餘文件夾刪除,如下圖。
並將…\FreeRTOSv10.2.1\FreeRTOSv10.2.1_191129\FreeRTOS\Demo\CORTEX_STM32F103_Keil文件夾中的FreeRTOSConfig.h文件拷貝至工程User文件夾。
Source文件夾包含的文件portable文件夾包含的文件
第三步:在裸機工程中添加FreeRTOS文件,如下圖所示(需配置include中頭文件的路徑)。選擇…\portable\MemMang文件夾中的heap_4.c以及…\portable\RVDS\ARM_CM3文件夾中的port.c和portmacro.h文件添加至port目錄
工程中添加FreeRTOS相關文件
第四步:修改啓動文件startup_stm32f10x_hd.s。由於FreeRTOS在port.c中定義了
116:void xPortPendSVHandler( void );
117:void xPortSysTickHandler( void );
118:void vPortSVCHandler( void );
三個中斷供內核使用,所以需要在啓動文件中重新定義中斷的入口函數,以防止調用stm32f10x_it.c中的中斷,彙編代碼修改如下啓動文件的修改
第五步:編寫main函數,創建點亮LED的任務,代碼如下

/*
******************************************************************************
*     包含的頭文件
******************************************************************************
*/
//FreeRTOS頭文件
#include "FreeRTOS.h"
#include "task.h"
//開發板硬件bsp頭文件
#include "./led/bsp_led.h"
#include "./uart/bsp_usart.h"

/***************************** 任務句柄 **************************************/
/*
 * 任務句柄是一個指針,用於指向一個任務。當任務創建好之後,它就具有一個任務句柄,
 * 以後我們想操作這個任務都需要用到這個任務句柄,如果是任務操作自身,那麼這個句柄可以爲NULL
*/
//創建任務句柄
static TaskHandle_t AppTaskCreate_Handle;
//LED1任務句柄
static TaskHandle_t LED1_Task_Handle = NULL;
//LED2任務句柄
static TaskHandle_t LED2_Task_Handle = NULL;

/*************************** 內核對象句柄 ************************************/
/*
 * 信號量、消息隊列、事件標誌組、軟件定時器都屬於內核的對象,要想使用這些內核對象,
 * 必須先創建,創建成功之後會返回相應的句柄。這實際上就是一個指針,後續我們就可以
 * 通過句柄操作這些內核對象。
 *
 *
 * 內核對象可以理解爲一種全局的數據結構,通過這些數據結構可以實現任務間的通信、任
 * 務間的事件同步等功能。這些功能的實現是通過調用內核對象的函數來完成的。
 *
 *
*/

/*
******************************************************************************
*     函數聲明
******************************************************************************
*/
static void AppTaskCreate(void);  //用於創建任務

static void LED1_Task(void* pvParameters);  //LED1_Task任務實現
static void LED2_Task(void* pvParameters);  //LED2_Task任務實現

static void BSP_Init(void);  //用於初始化板載相關資源

/*
******************************************************************************
*     主函數
******************************************************************************
*/
int main(void)
{
	//定義一個創建信息返回值,默認爲pdPASS
	BaseType_t xReturn = pdPASS;
	
	//開發板硬件初始化
	BSP_Init();
	printf("動態創建任務\r\n");

	//創建AppTaskCreate任務
	xReturn = xTaskCreate((TaskFunction_t)AppTaskCreate,
												(const char*   )"AppTaskCreate",//任務名稱
												(uint16_t      )512,						//任務棧大小
												(void*         )NULL,					  //傳遞給任務函數的參數
												(UBaseType_t   )1,						  //任務優先級
												(TaskHandle_t* )&AppTaskCreate_Handle);//任務控制塊指針
	
	printf("創建AppTaskCreate任務成功\r\n");

	//啓動任務調度											
  if (pdPASS == xReturn)	
		vTaskStartScheduler();					//啓動任務,開啓調度
	else
		return -1;
	
	while(1);													//正常情況下不會執行到這裏
}

/*
******************************************************************************
*     AppTaskCreate函數
******************************************************************************
*/
static void AppTaskCreate(void)
{
	//定義一個創建信息返回值,默認爲pdPASS
	BaseType_t xReturn = pdPASS;
	
	taskENTER_CRITICAL();//進入臨界區
	
	//創建LED1_Task任務
	xReturn = xTaskCreate((TaskFunction_t)LED1_Task,
												(const char*   )"LED1_Task",//任務名稱
												(uint16_t      )512,						 //任務棧大小
												(void*         )NULL,					 //傳遞給任務函數的參數
												(UBaseType_t   )2,							 //任務優先級
												(TaskHandle_t* )&LED1_Task_Handle); //任務控制塊
	
	if (pdPASS == xReturn)	
		printf("LED1_Task任務創建成功!\n");
	else
		printf("LED1_Task任務創建失敗!\n");
	
	//創建LED2_Task任務
	xReturn = xTaskCreate((TaskFunction_t)LED2_Task,
												(const char*   )"LED2_Task",//任務名稱
												(uint16_t      )512,						 //任務棧大小
												(void*         )NULL,					 //傳遞給任務函數的參數
												(UBaseType_t   )3,							 //任務優先級
												(TaskHandle_t* )&LED2_Task_Handle); //任務控制塊
	
	if (pdPASS == xReturn)	
		printf("LED2_Task任務創建成功!\n");
	else
		printf("LED2_Task任務創建失敗!\n");
	
	vTaskDelete(AppTaskCreate_Handle);	//刪除AppTaskCreate任務
	
	taskEXIT_CRITICAL();	//退出臨界區
}

/*
******************************************************************************
*     LED1_Task函數
******************************************************************************
*/
static void LED1_Task(void* parameter)
{
	while(1)
	{
		LED1_ON();
		vTaskDelay(500);//延時500個tick
		printf("led1_task running,LED1_ON\r\n"); 
		
	  LED1_OFF();
		vTaskDelay(500);//延時500個tick
		printf("led1_task running,LED1_OFF\r\n"); 
	}
}

/*
******************************************************************************
*     LED2_Task函數
******************************************************************************
*/
static void LED2_Task(void* parameter)
{
	while(1)
	{
		LED2_ON();
		vTaskDelay(1000);//延時500個tick
		printf("led2_task running,LED1_ON\r\n"); 
		
	  LED2_OFF();
		vTaskDelay(1000);//延時500個tick
		printf("led2_task running,LED1_OFF\r\n"); 
	}
}

/*
******************************************************************************
*     BSP_Init函數
******************************************************************************
*/
static void BSP_Init(void)
{
	/*
	 * STM32中斷優先級分組爲4,即4位都用來表示搶佔優先級,範圍爲0~15,
	 * 優先級只需要分組一次即可,以後如果有其他任務需要用到中斷,
	 * 都統一用這個優先級分組,千萬不要再分組
	 */
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
	
	//LED初始化
	LED_Init();
	
	//測試硬件是否正常工作
	//LED1_ON();
	
	//串口初始化
	USART_Config();
}

第六步:編譯、下載。編譯報“Error: L6218E: Undefined symbol xTaskGetCurrentTaskHandle (referred from stream_buffer.o).”錯誤,需將FreeRTOS.h中的INCLUDE_xTaskGetCurrentTaskHandle定義爲1,如下圖
FreeRTOS.h中修改相關的宏定義
更改後可以正常運行。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章