STM32F411移植FreeRtos教程
目錄
1.第一步準備好基礎工程
?2.軟件仿真相關設置
3.軟件仿真環境,printf重定向
4.移植FreeRtos源碼
4.1 拷貝文件
5.增加freertos源碼到keil工程中
5.1增加.c文件到工程:
5.2增加頭文件到工程:
6.修改編譯問題
7.修改SYSTEM文件和systick中斷處理函數
7.1 修改sys.h文件
7.2?修改usart.c文件
7.3?修改delay.c文件
7.3?修改SysTick_Handler中斷處理函數
7.修改main文件,創建freertos任務
1.第一步準備好基礎工程
準備好基礎工程,并且編譯通過,這里使用正點原子STM32F411提供的“F411_標準例程-寄存器版本“中的”實驗4 串口通信實驗“為基礎。
?2.軟件仿真相關設置
?通過菜單project->Options for target,打開工程設置
?修改外部時鐘頻率為8M:
設置軟件仿真,初始化文件,以及STM32F411RC對應的調試DLL
?說明:
1.選擇Use Simulator可以直接使用軟件仿真,不需要硬件單板。
2.設置Initialization File是為.\DebugConfig\debug.ini,是為了避免出現
*** error 65: access violation at 0x40023800 : no 'read' permission錯誤。
對應文件內容為:
map 0x40000000, 0x40007FFF read write // APB1
map 0x40010000, 0x400157FF read write // APB2
map 0x40020000, 0x4007FFFF read write // AHB1
map 0x50000000, 0x50060BFF read write // AHB2
map 0x60000000, 0x60000FFF read write // AHB3
map 0xE0000000, 0xE00FFFFF read write // CORTEX-M4 internal peripherals
3.設置調試dll和參數,調試dll為DARMSTM.DLL,Parameter根據需要仿真的硬件單板來填。
3.軟件仿真環境,printf重定向
3.1修改部分仿真環境下死循環問題
- 在仿真環境下,設置時鐘為HSE后,等待HSE READY一直等不到,具體原因不曉得。
修改的辦法就是增加一個宏隔離,在#ifndef SIM情況下,不用死等。
3.2修改printf仿真環境下無法輸出問題
?主要參考教材:(4條消息) MDK下仿真實現printf功能_mytt2013的博客-CSDN博客_mdk中printf
?基于原工程,只需要修改一個函數:
//重定義fputc函數 int fputc(int ch, FILE *f) { #ifdef SIM //仿真環境下printf重定向return ITM_SendChar(ch); #else while((USART1->SR&0X40)==0);//循環發送,直到發送完畢 USART1->DR = (u8) ch; return ch; #endif }?另外還有一個教程,是使用微庫的版本,也可以參考:printf系列教程01_UART打印輸出配置,基于STM32(Keil、IAR)_strongerHuang的博客-CSDN博客
4.移植FreeRtos源碼
主要過程參考:(4條消息) FreeRTOS在STM32F4上移植_Zach_z的博客-CSDN博客
4.1 拷貝文件
1.在測試工程中建立兩個文件夾,分別為Freertos_core和Freertos_port,
?2.拷貝freertosv9.0.0\FreeRTOS\Source公共源碼到工程目錄Freertos_core下:
?拷貝source目錄下所有文件,除了portable文件到工程目錄的Freertos_core目錄下:
3.拷貝FreeRtos架構相關源碼到工程目錄Freertos_port下:
拷貝:FreeRTOS\Source\portable\MemMang\heap_4.c
拷貝:\freertosv9.0.0\FreeRTOS\Source\portable\RVDS\ARM_CM4F 下所有文件
另外,還需要一個FreeRTOSConfig.h,由于我們單板是STM32F411,所以選擇FreeRTOS\Demo\CORTEX_M4F_STM32F407ZG-SK工程下的文件,將該文件拷貝到freertos_stm32f411\Freertos_port\include目錄,拷貝后的文件結構:
5.增加freertos源碼到keil工程中
5.1增加.c文件到工程:
打開keil工程,點擊Manager Project item,增加
?增加Group,并增加文件到Group后的狀態:
?點擊OK后,可以看到工程中,已經增加了FreeRtos相關源碼:
5.2增加頭文件到工程:
點擊Project->Options for "Target 1"
?在C/C++選項卡中,增加相關頭文件:
?增加Freertos頭文件后如圖:
6.修改編譯問題
1.修改SystemCoreClock條件編譯,
? Freertos_port\include\FreeRTOSConfig.h中
#ifdef __ICCARM__#include <stdint.h>extern uint32_t SystemCoreClock; #endif修改為
#if defined(__ICCARM__) || defined(__CC_ARM) ||defined(__GUNC__)#include <stdint.h>extern uint32_t SystemCoreClock; #endif2.重定義函數處理
PendSV_Handler,SVC_Handler ,SysTick_Handler三個函數有重復定義:
注釋掉SYSTEM\delay\delay.c中的PendSV_Handler和SVC_Handler定義,
注釋掉include\FreeRTOSConfig.h中的#define xPortSysTickHandler SysTick_Handler
3.關閉鉤子函數
復制過來的FreeRTOSConfig.h文件中默認開啟了一些鉤子函數,都是以Hook結尾,但并未定義,在FreeRTOSConfig.h中把configUSE_IDLE_HOOK、configUSE_TICK_HOOK、configCHECK_FOR_STACK_OVERFLOW和configUSE_MALLOC_FAILED_HOOK的宏定義改為0
至此,應該能編譯通過了。
7.修改SYSTEM文件和systick中斷處理函數
因為原子的SYSTEM文件夾是針對UCOS編寫的,所以要進行對應的修改
7.1 修改sys.h文件
把宏定義SYSTEM_SUPPORT_OS改為1即可,要支持OS,UCOS也一樣的
//0,不支持os //1,支持os #define SYSTEM_SUPPORT_OS 1 //定義系統文件夾是否支持OS? ?調試過程中發現直接定義SYSTEM_SUPPORT_OS宏,更好一些,避免有些文件沒有包含sys.h,導致一些異常難以發現。所以這里可以直接把這行去掉,然后在宏里面定義。
7.2?修改usart.c文件
打開SYSTEM文件夾下usart.c文件,添加FreeRTOS.h頭文件
#if SYSTEM_SUPPORT_OS #include "FreeRTOS.h" //FreeRtos #endifUSART1的中斷服務函數在使用UCOS時進出中斷添加OSIntEnter()與OSIntExit(),使用FreeRTOS則不需要,故注釋掉
//串口1中斷服務程序 void USART1_IRQHandler(void) { u32 timeout=0;u32 maxDelay=0x1FFFF; //#if SYSTEM_SUPPORT_OS //使用OS // OSIntEnter(); //#endifHAL_UART_IRQHandler(&UART1_Handler); //調用HAL庫中斷處理公用函數timeout=0;while (HAL_UART_GetState(&UART1_Handler) != HAL_UART_STATE_READY)//等待就緒{timeout++;超時處理if(timeout>maxDelay) break; }timeout=0;while(HAL_UART_Receive_IT(&UART1_Handler, (u8 *)aRxBuffer, RXBUFFERSIZE) != HAL_OK)//一次處理完成之后,重新開啟中斷并設置RxXferCount為1{timeout++; //超時處理if(timeout>maxDelay) break; } //#if SYSTEM_SUPPORT_OS //使用OS // OSIntExit(); //#endif }7.3?修改delay.c文件
使用以下代碼:
#include "delay.h" #include "sys.h" // //如果需要使用OS,則包括下面的頭文件即可. #if SYSTEM_SUPPORT_OS #include "FreeRTOS.h" //freertos 使用 #include "task.h" #endif// static u32 fac_us=0; //us延時倍乘數#if SYSTEM_SUPPORT_OS static u16 fac_ms=0; //ms延時倍乘數,在os下,代表每個節拍的ms數 #endif//初始化延遲函數 //當使用ucos的時候,此函數會初始化ucos的時鐘節拍 //SYSTICK的時鐘固定為AHB時鐘 //SYSCLK:系統時鐘頻率 void delay_init(u8 SYSCLK) { #if SYSTEM_SUPPORT_OS //如果需要支持OS.u32 reload; #endifHAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);//SysTick頻率為HCLKfac_us=SYSCLK; //不論是否使用OS,fac_us都需要使用 #if SYSTEM_SUPPORT_OS //如果需要支持OS.reload=SYSCLK; //每秒鐘的計數次數 單位為K 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/OS_TICKS_PER_SEC秒中斷一次 SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk; //開啟SYSTICK #else #endif } #if SYSTEM_SUPPORT_OS //如果需要支持OS. //延時nus //nus:要延時的us數. //nus:0~190887435(最大值即2^32/fac_us@fac_us=22.5) 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(u32 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); }#else //不用ucos時//延時nus //nus為要延時的us數. //nus:0~190887435(最大值即2^32/fac_us@fac_us=22.5) 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數 void delay_ms(u32 nms) {u32 i;for(i=0;i<nms;i++) delay_us(1000); } #endif7.3?修改SysTick_Handler中斷處理函數
使用以下代碼:
#ifdef SYSTEM_SUPPORT_OS #include "FreeRTOS.h" //freertos 使用 #include "task.h" extern void xPortSysTickHandler(void); //systick中斷服務函數,使用OS時用到 void SysTick_Handler(void) { if(xTaskGetSchedulerState()!=taskSCHEDULER_NOT_STARTED)//系統已經運行{xPortSysTickHandler(); }HAL_IncTick(); } #else void SysTick_Handler(void) {HAL_IncTick(); } #endif7.修改main文件,創建freertos任務
#include "sys.h" #include "delay.h" #include "usart.h" #include "led.h" #include "beep.h" #include "key.h"/************************************************ALIENTEK NANO板STM32F4開發板實驗4串口通信實驗-HAL庫版本技術支持:www.openedv.com淘寶店鋪:http://eboard.taobao.com 關注微信公眾平臺微信號:"正點原子",免費獲取STM32資料。廣州市星翼電子科技有限公司 作者:正點原子 @ALIENTEK ************************************************///說明,在工程宏定義中增加SYSTEM_SUPPORT_OS定義,則編譯出來版本就是freertos創建任務的版本。否則就是普通的裸機版本。 #ifdef SYSTEM_SUPPORT_OS #include "FreeRTOS.h" #include "task.h" #include "timers.h" #include "semphr.h"//500ms LED1燈狀態翻轉一次 static void led1Task( void * pvParameters ) {u8 len; while(1){if(USART_RX_STA&0x8000){ len=USART_RX_STA&0x3fff;//得到此次接收到的數據長度printf("\r\n您發送的消息為:\r\n");HAL_UART_Transmit(&UART1_Handler,(uint8_t*)USART_RX_BUF,len,1000); //發送接收到的數據while(__HAL_UART_GET_FLAG(&UART1_Handler,UART_FLAG_TC)!=SET); //等待發送結束printf("\r\n\r\n");//插入換行USART_RX_STA=0;}vTaskDelay(1);} } //1000ms LED2燈狀態翻轉一次 static void led2Task( void * pvParameters ) {u32 times=0; while(1){if(times%5000==0){printf("\r\nALIENTEK NANO STM32開發板 Freertos串口實驗\r\n");printf("正點原子@ALIENTEK\r\n\r\n\r\n");}times++;if(times%200==0)printf("請輸入數據,以回車鍵結束\r\n"); if(times%30==0)LED0=!LED0;//閃爍LED,提示系統正在運行.vTaskDelay(10);} }void startTasks(void) {xTaskCreate(led1Task,"LED1",256,NULL,100,(TaskHandle_t *)NULL);xTaskCreate(led2Task,"LED2",256,NULL,101,(TaskHandle_t *)NULL);/* 啟動任務調度器. */vTaskStartScheduler(); } #else void startTasks(void) {u8 len; u32 times=0; while(1){if(USART_RX_STA&0x8000){ len=USART_RX_STA&0x3fff;//得到此次接收到的數據長度printf("\r\n您發送的消息為:\r\n");HAL_UART_Transmit(&UART1_Handler,(uint8_t*)USART_RX_BUF,len,1000); //發送接收到的數據while(__HAL_UART_GET_FLAG(&UART1_Handler,UART_FLAG_TC)!=SET); //等待發送結束printf("\r\n\r\n");//插入換行USART_RX_STA=0;}else{if(times%5000==0){printf("\r\nALIENTEK NANO STM32開發板 裸機串口實驗\r\n");printf("正點原子@ALIENTEK\r\n\r\n\r\n");}times++;if(times%200==0)printf("請輸入數據,以回車鍵結束\r\n"); if(times%30==0)LED0=!LED0;//閃爍LED,提示系統正在運行.delay_ms(10); } } } #endifint main(void) {HAL_Init(); //初始化HAL庫 Stm32_Clock_Init(96,4,2,4); //設置時鐘,96Mhzdelay_init(96); //初始化延時函數LED_Init(); //初始化LED uart_init(115200); //初始化串口115200startTasks();}其他參考文章:
2、STM32F407移植FreeRTOS步驟_nandycooh的博客-CSDN博客_stm32f407移植freertos
FreeRTOS的移植與初步使用_不吃魚的貓丿的博客-CSDN博客
總結
以上是生活随笔為你收集整理的STM32F411移植FreeRtos教程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: “野火FreeRTOS教程”第9章知识点
- 下一篇: 通过tinyalsa中的tinymix来