官方freeRTOS移植教程很多,本文不做赘述。本文基于Keil 5提供的freeRTOS库,进行移植。 Keil 版本:Keil MDK uVision5 首先准备好一个可以用的HAL库工程,为了方便调试,选择了原子哥的开发板上提供跑马灯工程。 打开工程, 点击,下载freeRTOS库, 我的已经安装过了 最新的版本10.3.1 下载完成后关闭,点击 ,在这个界面下,按下图选择对应的选项 选择完成后点击OK( 如果没有先下载),可以看到工程中已经添加RTOS 点击编译下, 有一个错误先不用管,接下来开始修改文件,先打开RTE_Components.h 将 #define CMSIS_device_header "stm32f10x.h" 修改成 #define CMSIS_device_header "stm32f1xx_hal.h" ,keil下载的默认是库函数版移植的,需要将头文件变更成"stm32f1xx_hal.h"
接下来修改FREERTOS_CONFIG.H,打开头文件FREERTOS_CONFIG.H, 将#define configUSE_TIMERS 0 修改成 #define configUSE_TIMERS 1 将#define xPortSysTickHandler SysTick_Handler 屏蔽 编译下,出现两个错误 打开 stm32f1xx_it.c,
将PendSV_Handler(void) 、SVC_Handler(void)、SysTick_Handler(void)3个函数 屏蔽 打开sys.h 将 #define SYSTEM_SUPPORT_OS 0 改成#define SYSTEM_SUPPORT_OS 1 打开delay.c 将内部所有代码替换 #include "delay.h"#include "sys.h"#include "FreeRTOS.h"#include "task.h" static u32 fac_us=0; //us延时倍乘数static u16 fac_ms=0; //ms延时倍乘数,在os下,代表每个节拍的ms数extern void xPortSysTickHandler(void); //systick中断服务函数,使用ucos时用到void SysTick_Handler(void) { if(xTaskGetSchedulerState()!=taskSCHEDULER_NOT_STARTED)//系统已经运行 { xPortSysTickHandler(); } HAL_IncTick(); } //初始化延迟函数//当使用ucos的时候,此函数会初始化ucos的时钟节拍//SYSTICK的时钟固定为AHB时钟//SYSCLK:系统时钟频率void delay_init(u8 SYSCLK) { u32 reload; HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);//SysTick频率为HCLKfac_us=SYSCLK; //不论是否使用OS,fac_us都需要使用reload=SYSCLK; //每秒钟的计数次数 单位为K reload*=1000000/configTICK_RATE_HZ; //根据delay_ostickspersec设定溢出时间//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} //延时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~65535void 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); } 打开delay.h将内部所有代码替换 #ifndef __DELAY_H#define __DELAY_H #include "sys.h" void delay_init(u8 SYSCLK);void delay_ms(u32 nms);void delay_us(u32 nus);void SysTick_Handler(void);void delay_xms(u32 nms);#endif 打开usart.c将代码 #if SYSTEM_SUPPORT_OS#include "includes.h" //ucos 使用 #endif 替换成 #if SYSTEM_SUPPORT_OS#include "FreeRTOS.h"#include "task.h" #endif 将代码段 //#if SYSTEM_SUPPORT_OS //使用OS// OSIntEnter(); //#endif 和 //#if SYSTEM_SUPPORT_OS //使用OS// OSIntExit(); //#endif 屏蔽 编译没有错误 打开main.c 将所有代码替换成 #include "sys.h"#include "delay.h"#include "usart.h"#include "led.h"#include "FreeRTOS.h"#include "task.h"#include "FreeRTOSConfig.h"//任务优先级#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 20 //任务句柄TaskHandle_t LED0Task_Handler;//任务函数void led0_task(void *pvParameters);//任务优先级#define LED1_TASK_PRIO 3//任务堆栈大小 #define LED1_STK_SIZE 20 //任务句柄TaskHandle_t LED1Task_Handler;//任务函数void led1_task(void *pvParameters);int main(void) { HAL_Init(); //初始化HAL库 Stm32_Clock_Init(RCC_PLL_MUL10); //设置时钟,72Mdelay_init(70); //初始化延时函数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(); //开启任务调度return(1);// while(1){// PAout(6)=~PAout(6);// delay_ms(500);// PAout(7)=~PAout(7);// delay_ms(1000);// }; }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(1000); } } //LED1任务函数void led1_task(void *pvParameters) {while(1) { LED1=~LED1; vTaskDelay(2000); } } 编译后下载,发现没有反应跑马灯不亮,调试发现卡死在下面这条指令处 /* The kernel interrupt priority should be set to the lowest priority. */configASSERT( ucMaxPriorityValue == ( configKERNEL_INTERRUPT_PRIORITY & ucMaxPriorityValue ) ); 打开"FreeRTOSConfig.h" 将下面的代码段屏蔽 /* Cortex-M specific definitions. */#ifdef __NVIC_PRIO_BITS /* __NVIC_PRIO_BITS will be specified when CMSIS is being used. */ #define configPRIO_BITS __NVIC_PRIO_BITS#else /* 7 priority levels */ #define configPRIO_BITS 3#endif 将 /* Interrupt priorities used by the kernel port layer itself. These are generic * to all Cortex-M ports, and do not rely on any particular library functions. */#define configKERNEL_INTERRUPT_PRIORITY (configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS))/* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!! * See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */#define configMAX_SYSCALL_INTERRUPT_PRIORITY (configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS)) 修改成 #define configKERNEL_INTERRUPT_PRIORITY 255//(configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS))/* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!! * See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */#define configMAX_SYSCALL_INTERRUPT_PRIORITY 191//(configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS)) 编译后下载,发现跑马灯常亮, 调试发现代码没有卡死,这个问题困扰我了还久, 再次打开"FreeRTOSConfig.h" 将下面 #define configTIMER_TASK_STACK_DEPTH (configMINIMAL_STACK_SIZE * 2) 修改成 #define configTIMER_TASK_STACK_DEPTH 256 编译下载 ,成功了!!! |
|