1. 資料準備
因為板子是stm32F407的第二版的,所以開始下的資料是舊版本的,但是舊版本的FreeRTOS工程沒有hal庫的,都是標準庫的,這里是下載stm32F407最新版的資料,進行移植。
資料可以在正點原子官網(wǎng)下載,如下:
http://www.openedv.com/docs/boards/stm32/index.html
一定要下載最新的資料(開始用舊版本的移植不成功)。
準備stm32F407 hal庫的 實驗8 基本定時器實驗和 實驗37 內(nèi)存管理實驗兩個工程,以及FreeRTOS的源碼,以內(nèi)存管理實驗為模版,進行移植。
2. 實驗流程
- 添加 FreeRTOS 源碼
- 添加FreeRTOSConfig.h配置文件
- 修改SYSTEM文件
- 修改中斷相關(guān)文件
- 添加應(yīng)用程序
2.1 添加 FreeRTOS 源碼
在Middlewares文件夾中新建一個FreeRTOS文件夾,把FreeRTOS源碼中的source中文件都拷貝到新建的FreeRTOS文件夾中,刪去其余不是.c的文件。
portable文件夾里面的東西是連接軟件層面的FreeRTOS 操作系統(tǒng)和硬件層面的芯片的橋梁,這里只保留portable文件夾中的RVDS、MemMang、Keil三個文件夾(因為stm32F4只用到這三個文件夾)。
2.2 將文件添加到工程
在工程中新建兩個分組,Middlewares/FreeRTOS_CORE 和 Middlewares/FreeRTOS_PORT。
將.c文件添加到Middlewares/FreeRTOS_CORE 分組中。
將MemMang文件夾下的heap_4.c添加到Middlewares/FreeRTOS_PORT分組中。
將RVDS文件夾下的ARM_CM4F下的port.c添加到Middlewares/FreeRTOS_PORT分組中。
2.3 添加頭文件路徑
添加頭文件路徑FreeRTOS/include和port.c的文件路徑。
2.4 添加 FreeRTOSConfig.h文件
在FreeRTOS的例程中找到該文件FreeRTOSConfig.h,放到移植工程即可,這里放到user文件夾中。
2.5 修改SYSTEM文件
- 修改sys.h文件
/**
1. SYS_SUPPORT_OS用于定義系統(tǒng)文件夾是否支持OS
2. 0,不支持OS
3. 1,支持OS
*/
//#define SYS_SUPPORT_OS 0
#define SYS_SUPPORT_OS 1
- 修改usart.c 文件,刪掉OSIntEnter()和 OSIntExit()兩個函數(shù)
void USART_UX_IRQHandler(void)
{
uint32_t timeout = 0;
uint32_t maxDelay = 0x1FFFF;
//#if SYS_SUPPORT_OS /* 使用OS */
// OSIntEnter();
//#endif
HAL_UART_IRQHandler(&g_uart1_handle); /* 調(diào)用HAL庫中斷處理公用函數(shù) */
timeout = 0;
while (HAL_UART_GetState(&g_uart1_handle) != HAL_UART_STATE_READY) /* 等待就緒 */
{
timeout++; /* 超時處理 */
if(timeout > maxDelay)
{
break;
}
}
timeout=0;
/* 一次處理完成之后,重新開啟中斷并設(shè)置RxXferCount為1 */
while (HAL_UART_Receive_IT(&g_uart1_handle, (uint8_t *)g_rx_buffer, RXBUFFERSIZE) != HAL_OK)
{
timeout++; /* 超時處理 */
if (timeout > maxDelay)
{
break;
}
}
//#if SYS_SUPPORT_OS /* 使用OS */
// OSIntExit();
//#endif
}
- 將 usart.c中包含的關(guān)于 OS 的頭文件刪除
///* 如果使用os,則包括下面的頭文件即可 */
//#if SYS_SUPPORT_OS
//#include "includes.h" /* os 使用 */
//#endif
- 修改delay.c 文件,刪除如下代碼
//static uint16_t g_fac_ms = 0;
///*
// * 當delay_us/delay_ms需要支持OS的時候需要三個與OS相關(guān)的宏定義和函數(shù)來支持
// * 首先是3個宏定義:
// * delay_osrunning :用于表示OS當前是否正在運行,以決定是否可以使用相關(guān)函數(shù)
// * delay_ostickspersec:用于表示OS設(shè)定的時鐘節(jié)拍,delay_init將根據(jù)這個參數(shù)來初始化systick
// * delay_osintnesting :用于表示OS中斷嵌套級別,因為中斷里面不可以調(diào)度,delay_ms使用該參數(shù)來決定如何運行
// * 然后是3個函數(shù):
// * delay_osschedlock :用于鎖定OS任務(wù)調(diào)度,禁止調(diào)度
// * delay_osschedunlock:用于解鎖OS任務(wù)調(diào)度,重新開啟調(diào)度
// * delay_ostimedly :用于OS延時,可以引起任務(wù)調(diào)度.
// *
// * 本例程僅作UCOSII和UCOSIII的支持,其他OS,請自行參考移植
// */
//
///* 支持UCOSII */
//#ifdef OS_CRITICAL_METHOD /* OS_CRITICAL_METHOD定義了,說明要支持UCOSII */
//#define delay_osrunning OSRunning /* OS是否運行標記,0,不運行;1,在運行 */
//#define delay_ostickspersec OS_TICKS_PER_SEC /* OS時鐘節(jié)拍,即每秒調(diào)度次數(shù) */
//#define delay_osintnesting OSIntNesting /* 中斷嵌套級別,即中斷嵌套次數(shù) */
//#endif
///* 支持UCOSIII */
//#ifdef CPU_CFG_CRITICAL_METHOD /* CPU_CFG_CRITICAL_METHOD定義了,說明要支持UCOSIII */
//#define delay_osrunning OSRunning /* OS是否運行標記,0,不運行;1,在運行 */
//#define delay_ostickspersec OSCfg_TickRate_Hz /* OS時鐘節(jié)拍,即每秒調(diào)度次數(shù) */
//#define delay_osintnesting OSIntNestingCtr /* 中斷嵌套級別,即中斷嵌套次數(shù) */
//#endif
///**
// * @brief us級延時時,關(guān)閉任務(wù)調(diào)度(防止打斷us級延遲)
// * @param 無
// * @retval 無
// */
//void delay_osschedlock(void)
//{
//#ifdef CPU_CFG_CRITICAL_METHOD /* 使用UCOSIII */
// OS_ERR err;
// OSSchedLock(&err); /* UCOSIII的方式,禁止調(diào)度,防止打斷us延時 */
//#else /* 否則UCOSII */
// OSSchedLock(); /* UCOSII的方式,禁止調(diào)度,防止打斷us延時 */
//#endif
//}
///**
// * @brief us級延時時,恢復(fù)任務(wù)調(diào)度
// * @param 無
// * @retval 無
// */
//void delay_osschedunlock(void)
//{
//#ifdef CPU_CFG_CRITICAL_METHOD /* 使用UCOSIII */
// OS_ERR err;
// OSSchedUnlock(&err); /* UCOSIII的方式,恢復(fù)調(diào)度 */
//#else /* 否則UCOSII */
// OSSchedUnlock(); /* UCOSII的方式,恢復(fù)調(diào)度 */
//#endif
//}
///**
// * @brief us級延時時,恢復(fù)任務(wù)調(diào)度
// * @param ticks : 延時的節(jié)拍數(shù)
// * @retval 無
// */
//void delay_ostimedly(uint32_t ticks)
//{
//#ifdef CPU_CFG_CRITICAL_METHOD
// OS_ERR err;
// OSTimeDly(ticks, OS_OPT_TIME_PERIODIC, &err); /* UCOSIII延時采用周期模式 */
//#else
// OSTimeDly(ticks); /* UCOSII延時 */
//#endif
//}
- 添加 FreeRTOS 的相關(guān)代碼(在delay.c文件中)
extern void xPortSysTickHandler(void);
- 修改SysTick_Handler()函數(shù)
void SysTick_Handler(void)
{
HAL_IncTick();
// if (delay_osrunning == 1) /* OS開始跑了,才執(zhí)行正常的調(diào)度處理 */
// {
// OSIntEnter(); /* 進入中斷 */
// OSTimeTick(); /* 調(diào)用ucos的時鐘服務(wù)程序 */
// OSIntExit(); /* 觸發(fā)任務(wù)切換軟中斷 */
// }
/* OS 開始跑了,才執(zhí)行正常的調(diào)度處理 */
if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED)
{
xPortSysTickHandler();
}
}
- 修改delay_init()函數(shù)
void delay_init(uint16_t sysclk)
{
reload *= 1000000 / configTICK_RATE_HZ;
// g_fac_ms = 1000 / delay_ostickspersec;
}
/* 刪除不用的 g_fac_ms 相關(guān)代碼 */
- 修改delay_us()函數(shù)
void delay_us(uint32_t nus)
{
// delay_osschedlock(); /* 阻止OS調(diào)度,防止打斷us延時 */
// delay_osschedunlock(); /* 恢復(fù)OS調(diào)度 */
}
- 修改delay_ms()函數(shù)
void delay_ms(uint16_t nms)
{
// if (delay_osrunning && delay_osintnesting == 0) /* 如果OS已經(jīng)在跑了,并且不是在中斷里面(中斷里面不能任務(wù)調(diào)度) */
// {
// if (nms >= g_fac_ms) /* 延時的時間大于OS的最少時間周期 */
// {
// delay_ostimedly(nms / g_fac_ms); /* OS延時 */
// }
// nms %= g_fac_ms; /* OS已經(jīng)無法提供這么小的延時了,采用普通方式延時 */
// }
// delay_us((uint32_t)(nms * 1000)); /* 普通方式延時 */
uint32_t i;
for (i=0; i<nms; i++)
{
delay_us(1000);
}
}
- 包含頭文件
/* 添加公共頭文件 ( ucos需要用到) */
//#include "includes.h"
#include "FreeRTOS.h"
#include "task.h"
- 修改中斷相關(guān)文件,修改stm32f4xx_it.c文件
//void SVC_Handler(void)
//{
//}
//void PendSV_Handler(void)
//{
//}
//void SysTick_Handler(void)
//{
// HAL_IncTick();
//}
- 修改FreeRTOSConfig.h文件。
#define configPRIO_BITS __NVIC_PRIO_BITS
//#define __NVIC_PRIO_BITS 4U
#define __NVIC_PRIO_BITS 4
2.6 移除USMART調(diào)試組件
因為沒有使用到 USMART 調(diào)試組件,所以把這個組件刪掉。
注釋掉main.c中的有關(guān)USMART代碼。
//#include "./USMART/usmart.h"
//int main(void){
// usmart_dev.init(84); /* 初始化USMART */
}
2.7 添加定時器驅(qū)動
把基本定時器工程中的TIMER文件夾,復(fù)制到移植工程中的BSP文件夾中。
將定時器的相關(guān)驅(qū)動文件添加到工程的 Drivers/BSP 文件分組中。
3. 實驗驗證
把FreeRTOS例程中的demo復(fù)制到移植工程中User中。
將demo的驅(qū)動文件添加到工程的User文件分組中。
刪減之后的部分代碼如下:
int main(void)
{
HAL_Init(); /* 初始化 HAL 庫 */
sys_stm32_clock_init(RCC_PLL_MUL9); /* 設(shè)置時鐘, 72Mhz */
delay_init(72); /* 延時初始化 */
usart_init(115200); /* 串口初始化為 115200 */
led_init(); /* 初始化 LED */
lcd_init(); /* 初始化 LCD */
key_init(); /* 初始化按鍵 */
sram_init(); /* SRAM 初始化 */
my_mem_init(SRAMIN); /* 初始化內(nèi)部 SRAM 內(nèi)存池 */
my_mem_init(SRAMEX); /* 初始化外部 SRAM 內(nèi)存池 */
freertos_demo(); /* 運行 FreeRTOS 例程 */
}
void freertos_demo(void)
{
xTaskCreate((TaskFunction_t )start_task, /* 任務(wù)函數(shù) */
(const char* )"start_task", /* 任務(wù)名稱 */
(uint16_t )START_STK_SIZE, /* 任務(wù)堆棧大小 */
(void* )NULL, /* 傳入給任務(wù)函數(shù)的參數(shù) */
(UBaseType_t )START_TASK_PRIO, /* 任務(wù)優(yōu)先級 */
(TaskHandle_t* )&StartTask_Handler); /* 任務(wù)句柄 */
vTaskStartScheduler();
}
void task1(void *pvParameters)
{
while(1)
{
LED0_TOGGLE(); /* LED0閃爍 */
vTaskDelay(1000); /* 延時1000ticks */
}
}
void task2(void *pvParameters)
{
while(1)
{
LED1_TOGGLE(); /* LED1閃爍 */
vTaskDelay(500); /* 延時500ticks */
}
}
把程序燒到開發(fā)板中,實驗結(jié)果如下,可以看到與預(yù)設(shè)程序一致,紅色LED,1000ms亮滅一次,藍色LED,500ms亮滅一次(可以在如下視頻看到)。文章來源:http://www.zghlxwxcb.cn/news/detail-460837.html
FreeRTOS移植文章來源地址http://www.zghlxwxcb.cn/news/detail-460837.html
4. 總結(jié)
- 遇到如下報大量語法錯誤,原因是keil編譯器問題,把編譯器的版本設(shè)置為V5即可。
- 最后把程序燒到開發(fā)板中,如果LED燈沒有亮,復(fù)位幾次,觀察LED是否亮。
到了這里,關(guān)于基于stm32F407的hal庫,移植FreeRTOS的具體步驟和遇到的問題(看正點原子的視頻)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!