FREERTOS移植STM32F407
Posted Albert Nie
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了FREERTOS移植STM32F407相关的知识,希望对你有一定的参考价值。
FREERTOS移植STM32F407
获取FREERTOS源码
从github上下载:FREERTOS源码
创建基础工程
1.利用Keil 5 创建一个STM32基础工程,建议直接使用任何一个STM32库模板。
- 在基础工程中创建一个文件夹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.o
与stm32f4xx_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_task
和task2_task
。
首先定义创建任务需要的一些宏,并包含FreeRTOS.h
和task.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_task
和task2_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
stm32f407移植ucos怎么把ucos放在stm32上?
FreeRTOSFreeRTOS学习笔记— 使用STM32CubeMX对F407ZGT6移植FreeRTOS(CMSIS API)