目录

一、概述

二、源码获取

1、FreeRTOS官网

2、RTOS源码以及完整工程

三、移植

1、解压

2、精简FreeRTOS-Kernel文件

3、精简portable文件

4、打开keil

5、移植.C文件

6、包含.h文件

7、FreeRTOSConfig.h文件替换

四、应用测试

五、总结

一、概述

        本章手把手教学最新版FreeRTOS库移植到STM32F407ZGT6最小系统板中,其余型号的STM32单片机区别不大,换几个文件即可。开始前请准备好一个基础的例程,最好是串口和LED作为检验操作系统移植的正确性。

FreeRTOS版本: 202406.01LTS

开发板:STM32F407ZGT6

编译环境:Keil 5

二、源码获取

1、FreeRTOS官网

官网链接:FreeRTOS™ - FreeRTOS™https://www.freertos.org/zh-cn-cmn-s/

2、RTOS源码以及完整工程

通过网盘分享的文件:FreeRTOS工程

链接: 百度网盘 请输入提取码百度网盘为您提供文件的网络备份、同步和分享服务。空间大、速度快、安全稳固,支持教育网加速,支持手机端。注册使用百度网盘即可享受免费存储空间https://pan.baidu.com/s/1CY3LlEnMA5bGjWrN-KiLFA?pwd=4tkq 提取码: 4tkq

三、移植

1、解压

解压后来到这个目录下

examples ---> FreeRTOSConfig配置例程
include	 --->头文件,包含使用即可
portable ---> 不同环境下选择的内核不同

2、精简FreeRTOS-Kernel文件

路径:FreeRTOSv202406.01-LTS\FreeRTOS-LTS\FreeRTOS\FreeRTOS-Kernel

删除其余文件,保留需要用到的.c文件

3、精简portable文件

路径:FreeRTOSv202406.01-LTS\FreeRTOS-LTS\FreeRTOS\FreeRTOS-Kernel\portable

这里只保留MemMang文件和RVDS文件,其余文件全部删掉

删除后的效果图

        当精简完只有MemMang文件和RVDS文件的时候,我们先进入MemMang文件,这里是内存管理内核部分,常用的是heap4文件,如果需要切换直接保留需要的即可,这里我们只用heap4

只保留heap4的效果图

        随后我们来到RVDS文件,这里的文件对应不同的内核,这里我们选用的是STM32F407ZGT6单片机,内核架构是Cortex-M4,带浮点数版本,所以选择ARM_CM4F ,如果是STM32F103,选择M3即可

删除后的效果图

4、打开keil

首选确保你的工程文件能够正常编译,并且把FreeRTOS-Kernel文件放到keil工程目录下

5、移植.C文件

首先移植部分内核文件

        接下来移植RVDS文件和MemMang文件,因为之前已经做过裁剪,所以直接选择即可。MemMang文件中的heap_4.c 和 RVDS\ARM_CM4F文件中的port.c

如下图是.c文件移植完成后的结果,一共9个.c文件

6、包含.h文件

这里先包含include文件

随后我们在包含portable\RVDS\ARM_CM4F路径中的文件

最后我们把examples\template_configuration文件中的FreeRTOSConfig.h包含进来

7、FreeRTOSConfig.h文件替换

        打开FreeRTOSConfig.h文件,直接把如下的代码对该文件进行替换即可,博主已经对文件进行了修改。

#ifndef FREERTOS_CONFIG_H
#define FREERTOS_CONFIG_H

/* 头文件 */
#include "stm32f4xx.h"
#include <stdint.h>
#include <stdio.h>
#include <stdbool.h>

extern uint32_t SystemCoreClock;

/* 基础配置项 */
#define configUSE_PREEMPTION                            1                       /* 1: 抢占式调度器, 0: 协程式调度器, 无默认需定义 */
#define configUSE_PORT_OPTIMISED_TASK_SELECTION         1                       /* 1: 使用硬件计算下一个要运行的任务, 0: 使用软件算法计算下一个要运行的任务, 默认: 0 */
#define configUSE_TICKLESS_IDLE                         0                       /* 1: 使能tickless低功耗模式, 默认: 0 */
#define configCPU_CLOCK_HZ                              SystemCoreClock         /* 定义CPU主频, 单位: Hz, 无默认需定义 */
//#define configSYSTICK_CLOCK_HZ                          (configCPU_CLOCK_HZ / 8)/* 定义SysTick时钟频率,当SysTick时钟频率与内核时钟频率不同时才可以定义, 单位: Hz, 默认: 不定义 */
#define configTICK_RATE_HZ                              1000                    /* 定义系统时钟节拍频率, 单位: Hz, 无默认需定义 */
#define configMAX_PRIORITIES                            10                      /* 定义最大优先级数, 最大优先级=configMAX_PRIORITIES-1, 无默认需定义 */
#define configMINIMAL_STACK_SIZE                        128                     /* 定义空闲任务的栈空间大小, 单位: Word, 无默认需定义 */
#define configMAX_TASK_NAME_LEN                         16                      /* 定义任务名最大字符数, 默认: 16 */
#define configUSE_16_BIT_TICKS                          0                       /* 1: 定义系统时钟节拍计数器的数据类型为16位无符号数, 无默认需定义 */
#define configIDLE_SHOULD_YIELD                         1                       /* 1: 使能在抢占式调度下,同优先级的任务能抢占空闲任务, 默认: 1 */
#define configUSE_TASK_NOTIFICATIONS                    1                       /* 1: 使能任务间直接的消息传递,包括信号量、事件标志组和消息邮箱, 默认: 1 */
#define configTASK_NOTIFICATION_ARRAY_ENTRIES           1                       /* 定义任务通知数组的大小, 默认: 1 */
#define configUSE_MUTEXES                               1                       /* 1: 使能互斥信号量, 默认: 0 */
#define configUSE_RECURSIVE_MUTEXES                     1                       /* 1: 使能递归互斥信号量, 默认: 0 */
#define configUSE_COUNTING_SEMAPHORES                   1                       /* 1: 使能计数信号量, 默认: 0 */
#define configUSE_ALTERNATIVE_API                       0                       /* 已弃用!!! */
#define configQUEUE_REGISTRY_SIZE                       8                       /* 定义可以注册的信号量和消息队列的个数, 默认: 0 */
#define configUSE_QUEUE_SETS                            1                       /* 1: 使能队列集, 默认: 0 */
#define configUSE_TIME_SLICING                          1                       /* 1: 使能时间片调度, 默认: 1 */
#define configUSE_NEWLIB_REENTRANT                      0                       /* 1: 任务创建时分配Newlib的重入结构体, 默认: 0 */  
#define configENABLE_BACKWARD_COMPATIBILITY             0                       /* 1: 使能兼容老版本, 默认: 1 */
#define configNUM_THREAD_LOCAL_STORAGE_POINTERS         0                       /* 定义线程本地存储指针的个数, 默认: 0 */
#define configSTACK_DEPTH_TYPE                          uint16_t                /* 定义任务堆栈深度的数据类型, 默认: uint16_t */
#define configMESSAGE_BUFFER_LENGTH_TYPE                size_t                  /* 定义消息缓冲区中消息长度的数据类型, 默认: size_t */

/* 内存分配相关定义 */
#define configSUPPORT_STATIC_ALLOCATION                 0                       /* 1: 支持静态申请内存, 默认: 0 */
#define configSUPPORT_DYNAMIC_ALLOCATION                1                       /* 1: 支持动态申请内存, 默认: 1 */
#define configTOTAL_HEAP_SIZE                           ((size_t)(30 * 1024))   /* FreeRTOS堆中可用的RAM总量, 单位: Byte, 无默认需定义 */
#define configAPPLICATION_ALLOCATED_HEAP                0                       /* 1: 用户手动分配FreeRTOS内存堆(ucHeap), 默认: 0 */
#define configSTACK_ALLOCATION_FROM_SEPARATE_HEAP       0                       /* 1: 用户自行实现任务创建时使用的内存申请与释放函数, 默认: 0 */

/* 钩子函数相关定义 */
#define configUSE_IDLE_HOOK                             0                       /* 1: 使能空闲任务钩子函数, 无默认需定义  */
#define configUSE_TICK_HOOK                             0                       /* 1: 使能系统时钟节拍中断钩子函数, 无默认需定义 */
#define configCHECK_FOR_STACK_OVERFLOW                  0                       /* 1: 使能栈溢出检测方法1, 2: 使能栈溢出检测方法2, 默认: 0 */
#define configUSE_MALLOC_FAILED_HOOK                    0                       /* 1: 使能动态内存申请失败钩子函数, 默认: 0 */
#define configUSE_DAEMON_TASK_STARTUP_HOOK              0                       /* 1: 使能定时器服务任务首次执行前的钩子函数, 默认: 0 */

/* 运行时间和任务状态统计相关定义 */
#define configGENERATE_RUN_TIME_STATS                   0                       /* 1: 使能任务运行时间统计功能, 默认: 0 */
#if configGENERATE_RUN_TIME_STATS
#include "./BSP/TIMER/btim.h"
#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS()        ConfigureTimeForRunTimeStats()
extern uint32_t FreeRTOSRunTimeTicks;
#define portGET_RUN_TIME_COUNTER_VALUE()                FreeRTOSRunTimeTicks
#endif
#define configUSE_TRACE_FACILITY                        1                       /* 1: 使能可视化跟踪调试, 默认: 0 */
#define configUSE_STATS_FORMATTING_FUNCTIONS            1                       /* 1: configUSE_TRACE_FACILITY为1时,会编译vTaskList()和vTaskGetRunTimeStats()函数, 默认: 0 */

/* 协程相关定义 */
#define configUSE_CO_ROUTINES                           0                       /* 1: 启用协程, 默认: 0 */
#define configMAX_CO_ROUTINE_PRIORITIES                 2                       /* 定义协程的最大优先级, 最大优先级=configMAX_CO_ROUTINE_PRIORITIES-1, 无默认configUSE_CO_ROUTINES为1时需定义 */

/* 软件定时器相关定义 */
#define configUSE_TIMERS                                1                               /* 1: 使能软件定时器, 默认: 0 */
#define configTIMER_TASK_PRIORITY                       ( configMAX_PRIORITIES - 1 )    /* 定义软件定时器任务的优先级, 无默认configUSE_TIMERS为1时需定义 */
#define configTIMER_QUEUE_LENGTH                        5                               /* 定义软件定时器命令队列的长度, 无默认configUSE_TIMERS为1时需定义 */
#define configTIMER_TASK_STACK_DEPTH                    ( configMINIMAL_STACK_SIZE * 2) /* 定义软件定时器任务的栈空间大小, 无默认configUSE_TIMERS为1时需定义 */

/* 可选函数, 1: 使能 */
#define INCLUDE_vTaskPrioritySet                        1                       /* 设置任务优先级 */
#define INCLUDE_uxTaskPriorityGet                       1                       /* 获取任务优先级 */
#define INCLUDE_vTaskDelete                             1                       /* 删除任务 */
#define INCLUDE_vTaskSuspend                            1                       /* 挂起任务 */
#define INCLUDE_xResumeFromISR                          1                       /* 恢复在中断中挂起的任务 */
#define INCLUDE_vTaskDelayUntil                         1                       /* 任务绝对延时 */
#define INCLUDE_vTaskDelay                              1                       /* 任务延时 */
#define INCLUDE_xTaskGetSchedulerState                  1                       /* 获取任务调度器状态 */
#define INCLUDE_xTaskGetCurrentTaskHandle               1                       /* 获取当前任务的任务句柄 */
#define INCLUDE_uxTaskGetStackHighWaterMark             1                       /* 获取任务堆栈历史剩余最小值 */
#define INCLUDE_xTaskGetIdleTaskHandle                  1                       /* 获取空闲任务的任务句柄 */
#define INCLUDE_eTaskGetState                           1                       /* 获取任务状态 */
#define INCLUDE_xEventGroupSetBitFromISR                1                       /* 在中断中设置事件标志位 */
#define INCLUDE_xTimerPendFunctionCall                  1                       /* 将函数的执行挂到定时器服务任务 */
#define INCLUDE_xTaskAbortDelay                         1                       /* 中断任务延时 */
#define INCLUDE_xTaskGetHandle                          1                       /* 通过任务名获取任务句柄 */
#define INCLUDE_xTaskResumeFromISR                      1                       /* 恢复在中断中挂起的任务 */

/* 中断嵌套行为配置 */
#ifdef __NVIC_PRIO_BITS
    #define configPRIO_BITS __NVIC_PRIO_BITS
#else
    #define configPRIO_BITS 4
#endif

#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY         15                  /* 中断最低优先级 */
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY    5                   /* FreeRTOS可管理的最高中断优先级 */
#define configKERNEL_INTERRUPT_PRIORITY                 ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
#define configMAX_SYSCALL_INTERRUPT_PRIORITY            ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
#define configMAX_API_CALL_INTERRUPT_PRIORITY           configMAX_SYSCALL_INTERRUPT_PRIORITY

/* FreeRTOS中断服务函数相关定义 */
#define xPortPendSVHandler PendSV_Handler
#define vPortSVCHandler SVC_Handler
#define xPortSysTickHandler SysTick_Handler


/* 断言 */
#define vAssertCalled(char, int) printf("Error: %s, %d\r\n", char, int)
#define configASSERT( x ) if( ( x ) == 0 ) vAssertCalled( __FILE__, __LINE__ )


#endif /* FREERTOS_CONFIG_H */

        替换后编译效果,会提示有三个报错,我们需要进入stm32f4xx_it.c文件,将SVC_Handler 、 PendSV_Handler 、 SysTick_Handler中断服务函数注释掉(删除也可以),这是因为RTOS切换过程中,需要用到这三个中断服务函数,在port文件中对三个函数进行了改写,如想了解更多,请查看博主主页

编译后效果图,此时可以正常的编写函数应用

四、应用测试

如果准备好串口1调试的例程,直接复制如下代码即可完成基本的FreeRTOS应用。

#include "main.h"
#include "stm32f4xx.h"
#include "FreeRTOS.h"
#include "task.h"
#include "timers.h"
#include "queue.h"
#include "stream_buffer.h"
#include "semphr.h"
 
//创建队列句柄
QueueHandle_t Queue_Data_Handle;
#define queue_data_length 10
 
//宏定义 send_task
BaseType_t retA;		
TaskHandle_t Pt_send_Task_TaskHandle;
void queue_sned_Task(void *p);
#define Sned_Task_Name 		  "queue_send"
#define Sned_Task_StackD  		128
#define Sned_Task_Priority		1
 
//宏定义 rece_task
BaseType_t retB;
TaskHandle_t Pt_rece_Task_TaskHandle;
void queue_receive_Task(void *p);
#define Rece_Task_Name 		  "queue_rece"
#define Rece_Task_StackD  		128
#define Rece_Task_Priority		1

void queue_send_Task(void *p)
{	
	uint32_t send_value = 0;
	while(1)
	{    
		xQueueSend(Queue_Data_Handle, &send_value, portMAX_DELAY);
		{	//如果BUFF满,则不会执行如下程序
			send_value++;
			if(send_value > 100)
			{
				send_value = 0;
			}
			vTaskDelay(100);
		}
	}
}
 
void queue_receive_Task(void *p)
{
	uint32_t rece_value = 0;
	while(1)
	{
		xQueueReceive(Queue_Data_Handle, &rece_value, portMAX_DELAY);
		{
			//如果BUFF空,则不会执行如下程序
			printf("rece_value = %d\r\n", rece_value);
			
		}		
	}
}

int main(void)
{
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
	Debug_Init(115200);
	
	/*创建队列 注意队列长度 和 数据字节大小*/
	Queue_Data_Handle = xQueueCreate(queue_data_length,  //队列长度
																		sizeof(uint32_t));  //单个数据大小四字节
									
	/*创建发送任务*/
	retA = xTaskCreate(	(TaskFunction_t)    queue_send_Task,
											(const char *)Sned_Task_Name,
											(uint16_t)Sned_Task_StackD,
											(void *)NULL,
											(UBaseType_t)Sned_Task_Priority,
											(TaskHandle_t *)&Pt_send_Task_TaskHandle);
	/*创建接收任务*/
	retA = xTaskCreate(	(TaskFunction_t)    queue_receive_Task,
											(const char *)Rece_Task_Name,
											(uint16_t)Rece_Task_StackD,
											(void *)NULL,
											(UBaseType_t)Rece_Task_Priority,
											(TaskHandle_t *)&Pt_rece_Task_TaskHandle);
	/*开始调度*/
	vTaskStartScheduler();
	/*不会执行到这里*/
	while (1) {		
		;
	}
}

运行效果图如下

五、总结

如果有兴趣的话可以对照FreeRTOSConfig文件自行配置宏定义,同时了解更多FreeRTOS的应用以及源码请查看博主主页。

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐