【GD32450I-EVAL】+ 05FreeRTOS移植与任务创建
[复制链接]
本帖最后由 DDZZ669 于 2020-9-26 15:34 编辑
FreeRTOS是一个迷你的实时操作系统内核。作为一个轻量级的操作系统,功能包括:任务管理、时间管理、信号量、消息队列、内存管理、记录功能、软件定时器、协程等,可基本满足较小系统的需要。
1 FreeRTOS基本结构
FreeRTOS系统简单小巧、文件数量少、通常情况下内核占用4~9k字节空间,代码主要由C编写,可移植性高,已实现在30多种架构的芯片上移植。
由于FreeRTOS的最新代码目前从官网下载的速度特别慢,这里先以之前的FreeRTOS v9.0.0版本为例进行实验。FreeRTOS代码包含FreeRTOS和FreeRTOS-Plus文件夹,后者是一些补充文件,一般用不到,可以先忽略。
在FreeRTOS文件夹中主要关注source文件夹,这里是FreeRTOS的全部源码,包括6个c文件和include文件夹下的多个h文件。另外,在portable文件夹下,是针对不同硬件平台的单独区分使用的代码,目前考虑使用Keil开发STM32F407,所以portable文件夹只需使用RVDS的ARM_CM4F以及MemMang。
关于各个c文件的主要用途:
在Demo文件夹下还需要用到一个FreeRTOSConfig.h,该文件中通过各种宏定义的方式来配置FreeRTOS需要使用哪些资源。
2 FreeRTOS移植
2.1 准备一个基础工程
这里以光盘资料里的LED工程为基础,移植FreeRTOS系统。先来看一下LED基础工程的结构:
2.2 添加FreeRTOS库文件
把FreeRTOS源码中的Source文件夹复制出来并重命名为FreeRTOS(便于与GD32F4库文件区分),用于添加到LED基础工程中,Source文件夹中的portable子文件夹中,只保留RVDS与MemMang,其余的用不到可以删除。
另外还需要一个名为“FreeRTOSConfig.h”的配置文件,因为FreeRTOSv9.0中还没有GD32F450的Demo,可以先使用Demo文件夹下的CORTEX_M4F_STM32F407ZG-SK文件夹里的这个文件,因为它们同属M4内核。然后将该文件放到include子文件夹中。
将FreeRTOS源码中的c文件添加到LED基础工程中:
再添加头文件的路径:
2.3 编译与配置
添加FreeRTOS的C文件并添加H文件搜索路径后,编译一下工程,提示3个错误:
port.c和gd32f4xx_it.c中的函数重复定义了,因为port.c的FreeRTOS中的文件,那我们不修改它,而是把gd32f4xx_it.c中的同名函数先注释掉,并再次编译,就不报错了:
3 任务创建示例
使用FreeRTOS开发,与裸机开发的最大区别就是,裸机程序是一条主线从上到下执行,再配合中断功能来实现紧急时间的处理。而使用FreeRTOS等实时操作系统,可以将所以实现的各个功能单独设计为一个个子任务,每个子任务都是一个死循环,通过任务的调度的方式来实现各个子任务的运行与信息交流。
以下是两个LED灯的测试程序,LED1子任务的功能是每隔500ms进行亮灭转换,LED2子任务的功能是亮200ms,灭800ms循环。这两个子任务通过系统调度的方式,各自运行,互不影响。
另外,FreeRTOS中首先需要一个起始任务,用来创建其它任务,创建完其它任务后,该任务将自己删除。
#include "gd32f4xx.h"
#include "gd32f450i_eval.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);
int main(void)
{
//设置系统中断优先级分组4(FreeRTOS中的默认方式!)
nvic_priority_group_set(NVIC_PRIGROUP_PRE4_SUB0);
gd_eval_led_init(LED1);
gd_eval_led_init(LED2);
//创建开始任务
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();
}
//开始任务任务函数
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任务函数
void task1_task(void *pvParameters)
{
while(1)
{
gd_eval_led_toggle(LED1);
vTaskDelay(500); //延时500ms
}
}
//task2任务函数
void task2_task(void *pvParameters)
{
while(1)
{
gd_eval_led_on(LED2);;
vTaskDelay(200); //延时200ms
gd_eval_led_off(LED2);;
vTaskDelay(800); //延时800ms
}
}
4 测试效果
|