FREERTOS移植STM32F407

Posted 玖道

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了FREERTOS移植STM32F407相关的知识,希望对你有一定的参考价值。

FREERTOS移植STM32F407

获取FREERTOS源码

从github上下载:FREERTOS源码

创建基础工程

1.利用Keil 5 创建一个STM32基础工程,建议直接使用任何一个STM32库模板。

  1. 在基础工程中创建一个文件夹FREERTOS,用来存放FreeRTOS源码,该源码存放在下载的source文件夹下,然后删除不需要的文件。我们用到的文件如下:


其中port.c文件来自portable\\RVDS\\ARM_CM4F目录,heap_4.c来自portable\\MemMang目录,删除portable下的其他文件夹。

最后加入头文件路径:

3.编译报错(一): 找不到FreeRTOS.h

在源码FreeRTOSv202104.00\\FreeRTOSv202104.00\\FreeRTOS\\Demo文件夹中找到对应芯片工程的FreeRTOSConfig.h,比如STM32F407就需要找到并添加到工程的FREERTOS/include目录下。

编译报错(2):SystemCoreClock未定义

FreeRTOSConfig.h中的条件编译

#ifdef __ICCARM__

改为

#if defined(__ICCARM__)||defined(__CC_ARM)||defined(__GNU__)

编译报错(3): 提示port.ostm32f4xx_it.o有重复定义

注释掉stm32f4xx_it.c中的SVC_Handler(),PendSV_Handler(),SysTick_Handler()即可。

编译报错(4):提示4个hook函数未定义

修改FreeRTOSConfig.h中的HOOK宏的值为0

#define configUSE_IDLE_HOOK             0
#define configUSE_TICK_HOOK             0
#define configCHECK_FOR_STACK_OVERFLOW  0
#define configUSE_MALLOC_FAILED_HOOK    0

至此,编译成功~

接下来,可以创建我们的任务了。

任务创建函数

xTaskCreate函数原型在task.c文件中,是一种动态创建任务的方式,系统通过heap_4.c的配置为任务自动分配相关的内存。

BaseType_t xTaskCreate( TaskFunction_t pxTaskCode,              // 关联的任务函数名
                       const char * const pcName,               // 任务名
                       const uint16_t usStackDepth,             // 任务堆栈大小,是实际申请的4倍
                       void * const pvParameters,               // 任务函数的参数,没有设为NULL
                       UBaseType_t uxPriority,                  // 任务优先级 0 ~ configMAX_PRIORITIES - 1
                       TaskHandle_t * const pxCreatedTask )     // 任务句柄,是个指针
    
// 返回值: BaseType_t ,实际是long 类型,定义在 portmacro.h中
// 任务句柄的类型 TaskHandle_t 的实际类型是 void*,定义在task.h中

任务删除函数

vTaskDelete的函数原型也在task.c文件中。通过xTaskCreate()动态创建的任务,在使用vTaskDelete()删除后,该任务创建时申请的堆栈和内存会在系统的空闲任务中被释放掉。

void vTaskDelete(TaskHandle_t xTaskToDelete)   // xTaskToDelte : 要删除的任务句柄

任务调度函数

vTaskStartScheduler函数原型也在task.c文件中,不需要参数,开启后就由FreeRTOS开始任务调度工作。

void vTaskStartScheduler( void )

主函数

我们以前写的STM32库函数编程方式属于裸机编程,编程也称为前后台系统。它通过while(1)大循环,轮询循环体,使得各个任务耦合在一起,实时性不高。

// 裸机编程
int main()
   ...  // 初始化操作
   
   while(1)  // 轮询方式
       task1();    // 任务1,
       ...
       ... 
       task2();   // 任务2
       ....
   

比如上面两个任务必须交替执行,一个任务必须等待另外一个任务完成,而等待时间起决定具体程序。

为了提高实时性,我们便引进RTOS,即用操作系统来管理具体的任务调度,而不是采用轮询的方式,这样就大大提高了任务之间的独立性和实时性。在实时性编程中,我们只需要在main函数中创建任务并开启任务调度,即可使系统持续运行。

int main(void)
 
    //设置系统中断优先级分组4(FreeRTOS中的默认方式!)
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
    
    //初始化LED端口
    LED_Init();                         

    //创建开始任务
    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();          

开始任务的函数是一个接口,负责创建其他子任务,创建完之后会把自己删掉。这样在我们的main函数中,只需要一个start_task函数就行了,具体的任务创建都打包在start_task函数中。

这里我们创建两个任务:tast1_tasktask2_task

首先定义创建任务需要的一些宏,并包含FreeRTOS.htask.h头文件。

#include "FreeRTOS.h"
#include "task.h"

//任务参数--------------------------
//优先级 堆栈大小 任务句柄 任务函数
#define START_TASK_PRIO     1
#define START_STK_SIZE      128  
TaskHandle_t StartTask_Handler;
void start_task(void *pvParameters);

#define TASK1_TASK_PRIO     2
#define TASK1_STK_SIZE      128  
TaskHandle_t Task1Task_Handler;
void task1_task(void *pvParameters);

#define TASK2_TASK_PRIO     3   
#define TASK2_STK_SIZE      128  
TaskHandle_t Task2Task_Handler;
void task2_task(void *pvParameters);

然后编写start_task函数。

//开始任务任务函数
void start_task(void *pvParameters)

    taskENTER_CRITICAL();           //进入临界区
    
    //创建TASK1任务
    xTaskCreate((TaskFunction_t )task1_task,             
                (const char*    )"task1_task",           
                (uint16_t       )TASK1_STK_SIZE,        
                (void*          )NULL,                  
                (UBaseType_t    )TASK1_TASK_PRIO,        
                (TaskHandle_t*  )&Task1Task_Handler);   
    //创建TASK2任务
    xTaskCreate((TaskFunction_t )task2_task,     
                (const char*    )"task2_task",   
                (uint16_t       )TASK2_STK_SIZE,
                (void*          )NULL,
                (UBaseType_t    )TASK2_TASK_PRIO,
                (TaskHandle_t*  )&Task2Task_Handler); 
                
    vTaskDelete(StartTask_Handler); //删除开始任务
                
    taskEXIT_CRITICAL();            //退出临界区

最后创建两个任务函数:task1_tasktask2_task。每个任务函数都是一个死循环,注意循环中必须添加vTaskDelay()延时函数,用于任务的切换。

//task1任务函数
void task1_task(void *pvParameters)

    while(1)
    
        LED0 = 1;
        vTaskDelay(500); //延时500ms
        LED0 = 0;
        vTaskDelay(200); //延时200ms
    


//task2任务函数
void task2_task(void *pvParameters)

    while(1)
    
        LED1 = 1;
        vTaskDelay(200); //延时200ms
        LED1 = 0;
        vTaskDelay(200); //延时200ms
    

最后烧录到STM32F407开发板中,然后操作系统便开始调度任务。可以看到两个LED灯任务便开始根据系统的调度算法进行运行。

------------------------------------------------分割线~------------------------------------------------------

移植M3

题外话,这里顺带提一点M3内核移植FreeRTOS。

基本步骤同上,编译问题有所不同。

1.选择STM32F103的FreeRTOSConfig.h文件,并放置在FREERTOS\\include文件夹下

2.选择内核文件,使用这里的port.c文件。

3.编译出现一个问题,在FreeRTOS.h中修改宏如下

#ifndef INCLUDE_xTaskGetCurrentTaskHandle
    #define INCLUDE_xTaskGetCurrentTaskHandle   1   // 将0改为1
#endif

4.在启动文件startup_stm32f10x_hds中添加

以及修改如下

差不多就是这样~

最后的最后,移植操作系统虽然没啥技术含量,但移植成功,系统跑起来了还是蛮开心的,各位加油,奥利给~

以上是关于FREERTOS移植STM32F407的主要内容,如果未能解决你的问题,请参考以下文章

使用HAL对STM32F407ZGT6单片机移植FreeRTOS(参考正点原子)

freeRTOS V10.0.1移植到STM32F407标准库 - 环境Keil5

HAL STM32F407ZGT6 FreeRTOS

stm32f407移植ucos怎么把ucos放在stm32上?

STM32F407第3章 ThreadX USBX协议栈移植到STM32F407

STM32F407的DSP教程第29章 STM32F407移植汇编定点FFT库(64点,256点和1024点)