FreeRTOS基本教程零:STM32 FReeRTOS 移植流程
一、資料準備
FreeRTOS源碼下載地址:
https://github.com/FreeRTOS/FreeRTOShttps://github.com/FreeRTOS/FreeRTOS我移植的是FreeRTOSv9.0.0
stm32裸機程序:
二、FreeRTOS目錄
?一共有三個文件夾
其中Demo文件夾中是FreeRTOS的例程,License文件夾是與FreeRTOS相關的許可信息,Source是FreeRTOS的源碼。
?include文件夾是移植需要的頭文件,下面的croutine.c等C文件是FreeRTOS的源碼文件,移植時需要。Protable文件夾是將軟件(FreeRTOS)與硬件(不同MCU)連接的文件,
我們使用的Keil平臺,硬件為stm32f103,屬于CM3內核。
所以我們需要Keil文件夾,而文件夾中的See-also-the-RVDS-directory.txt提示參考RVDS,我們選用RVDS/ARM_CM3文件夾的文件。
MemMang是與內存管理相關關的,移植時是需要的。
?FreeRTOS-Plus文件夾不是源碼,是在源碼上加了一些功能的代碼。
二、移植
2.1 文件的添加
將FreeRTOS文件夾添加到工程文件夾中,保留License和Demo文件夾保留,將其他文件刪除,License文件夾與FreeRTOS相關的許可信息,要做產品的需要注意,這里作為學習,所以未做詳細介紹。
Source\portable中只保留Keil、MemMang、RVDS文件夾,其他文件夾均刪除。
RVDS文件夾中只保留ARM_CM3文件夾,其他均刪除。
打開工程,新建FreeRTOS_CORE和FreeRTOS_PROTABLE兩個分組
?將源文件添加到這兩個分組中,如下圖所示:
將文件路徑添加到工程里
?添加完之后,進行編譯。
?報錯:..\FreeRTOS\Source\include\FreeRTOS.h(98): error: ?#5: cannot open source input file "FreeRTOSConfig.h": No such file or directory
表示找不到FreeRTOSConfig.h,我們從官方移植好的工程拷貝到include文件夾中,用于系統的裁剪和配置功能,為系統的配置文件。
2.2 文件修改
再編譯:
?將stm32f10x_it.c文件中的?SVC_Handler 和 PendSV_Handler 屏蔽掉,再編譯編譯通過。
修改sys.h文件
將
//0,不支持ucos //1,支持ucos #define SYSTEM_SUPPORT_OS 0 //定義系統文件夾是否支持UCOS修改為
//0,不支持ucos //1,支持ucos #define SYSTEM_SUPPORT_OS 1 //定義系統文件夾是否支持UCOS修改usart.c
?將
//如果需要使用OS,則包括下面的頭文件即可. #if SYSTEM_SUPPORT_OS #include "includes.h" //ucos 使用 #endif修改為
//如果需要使用OS,則包括下面的頭文件即可. #if SYSTEM_SUPPORT_OS #include "FreeRTOS.h" //ucos 使用 #endif刪除
#if SYSTEM_SUPPORT_OS //如果SYSTEM_SUPPORT_OS為真,則需要支持OS.OSIntEnter(); #endif#if SYSTEM_SUPPORT_OS //如果SYSTEM_SUPPORT_OS為真,則需要支持OS.OSIntExit(); #endif修改delay.c修改比較大,最終為
#include "delay.h" // //如果需要使用OS,則包括下面的頭文件即可. #if SYSTEM_SUPPORT_OS #include "FreeRTOS.h" //FreeRTOS使用 #include "task.h" #endifstatic u8 fac_us=0; //us延時倍乘數 static u16 fac_ms=0; //ms延時倍乘數,在ucos下,代表每個節拍的ms數extern void xPortSysTickHandler(void);//systick中斷服務函數,使用ucos時用到 void SysTick_Handler(void) { if(xTaskGetSchedulerState()!=taskSCHEDULER_NOT_STARTED)//系統已經運行{xPortSysTickHandler(); } }//初始化延遲函數 //SYSTICK的時鐘固定為AHB時鐘,基礎例程里面SYSTICK時鐘頻率為AHB/8 //這里為了兼容FreeRTOS,所以將SYSTICK的時鐘頻率改為AHB的頻率! //SYSCLK:系統時鐘頻率 void delay_init() {u32 reload;SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK);//選擇外部時鐘 HCLKfac_us=SystemCoreClock/1000000; //不論是否使用OS,fac_us都需要使用reload=SystemCoreClock/1000000; //每秒鐘的計數次數 單位為M reload*=1000000/configTICK_RATE_HZ; //根據configTICK_RATE_HZ設定溢出時間//reload為24位寄存器,最大值:16777216,在72M下,約合0.233s左右 fac_ms=1000/configTICK_RATE_HZ; //代表OS可以延時的最少單位 SysTick->CTRL|=SysTick_CTRL_TICKINT_Msk; //開啟SYSTICK中斷SysTick->LOAD=reload; //每1/configTICK_RATE_HZ秒中斷一次 SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk; //開啟SYSTICK } //延時nus //nus:要延時的us數. //nus:0~204522252(最大值即2^32/fac_us@fac_us=168) void delay_us(u32 nus) { u32 ticks;u32 told,tnow,tcnt=0;u32 reload=SysTick->LOAD; //LOAD的值 ticks=nus*fac_us; //需要的節拍數 told=SysTick->VAL; //剛進入時的計數器值while(1){tnow=SysTick->VAL; if(tnow!=told){ if(tnow<told)tcnt+=told-tnow; //這里注意一下SYSTICK是一個遞減的計數器就可以了.else tcnt+=reload-tnow+told; told=tnow;if(tcnt>=ticks)break; //時間超過/等于要延遲的時間,則退出.} } } //延時nms //nms:要延時的ms數 //nms:0~65535 void delay_ms(u16 nms) { if(xTaskGetSchedulerState()!=taskSCHEDULER_NOT_STARTED)//系統已經運行{ if(nms>=fac_ms) //延時的時間大于OS的最少時間周期 { vTaskDelay(nms/fac_ms); //FreeRTOS延時}nms%=fac_ms; //OS已經無法提供這么小的延時了,采用普通方式延時 }delay_us((u32)(nms*1000)); //普通方式延時 }//延時nms,不會引起任務調度 //nms:要延時的ms數 void delay_xms(u32 nms) {u32 i;for(i=0;i<nms;i++) delay_us(1000); }編譯報錯:
..\OBJ\LED.axf: Error: L6200E: Symbol SysTick_Handler multiply defined (by delay.o and stm32f10x_it.o).
?將stm32f10x_it.c文件中的 SysTick_Handler 屏蔽掉,編譯通過,stm32f10x_it.c最終如下
?2.3 測試
//main.c #include "led.h" #include "delay.h" #include "sys.h" #include "FreeRTOS.h" #include "task.h" /************************************************ALIENTEK Mini STM32F103開發板 FreeRTOS實驗2-1FreeRTOS移植實驗-庫函數版本技術支持:www.openedv.com淘寶店鋪:http://eboard.taobao.com 關注微信公眾平臺微信號:"正點原子",免費獲取STM32資料。廣州市星翼電子科技有限公司 作者:正點原子 @ALIENTEK ************************************************///任務優先級 #define START_TASK_PRIO 1 //任務堆棧大小 #define START_STK_SIZE 128 //任務句柄 TaskHandle_t StartTask_Handler; //任務函數 void start_task(void *pvParameters);//任務優先級 #define LED0_TASK_PRIO 2 //任務堆棧大小 #define LED0_STK_SIZE 50 //任務句柄 TaskHandle_t LED0Task_Handler; //任務函數 void led0_task(void *pvParameters);//任務優先級 #define LED1_TASK_PRIO 3 //任務堆棧大小 #define LED1_STK_SIZE 50 //50*4個字節 = 200字節 含寄存器和任務的變量 //任務句柄 TaskHandle_t LED1Task_Handler; //任務函數 void led1_task(void *pvParameters);int main(void) {NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//設置系統中斷優先級分組4 delay_init(); //延時函數初始化 uart_init(115200); //初始化串口LED_Init(); //初始化LED//創建開始任務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(); //進入臨界區//創建LED0任務xTaskCreate((TaskFunction_t )led0_task, (const char* )"led0_task", (uint16_t )LED0_STK_SIZE, (void* )NULL, (UBaseType_t )LED0_TASK_PRIO, (TaskHandle_t* )&LED0Task_Handler); //創建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(); //退出臨界區 }//LED0任務函數 void led0_task(void *pvParameters) {while(1){LED0=~LED0;vTaskDelay(500);} } //LED1任務函數 void led1_task(void *pvParameters) {while(1){LED1=0;vTaskDelay(200);LED1=1;vTaskDelay(800);} }總結
以上是生活随笔為你收集整理的FreeRTOS基本教程零:STM32 FReeRTOS 移植流程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 项目进度计划的基本方法
- 下一篇: 韦东山freeRTOS系列教程:入门文档