freeRTOS学习笔记01(点灯+移植
1.freeRTOS入门
裸机和freeRTOS的区别(不使用中断的情况下):
裸机:实时性弱(轮询,单个任务切换执行),延时问题(无法执行其他)
freeRTOS:实时性强(分而治之,多任务同时运行),阻塞自动切换低优先级任务,高优先级抢占任务,对每个任务分配栈空间


根据实时性排列:中断>RTOS>裸机
具体还是根据实际情况来,不一定是哪个就是最好,各有各的优点
freeRTOS特点
免费的嵌入式实时操作系统;开源,可裁剪代码,简单,优先级不限(多任务同一优先级),任务数量不限(取决于栈的大小),任务调度功能丰富
RTOS:real time os即实时的系统在一个时间片内执行一个任务(1ms时钟节拍),来回进行切换,低于感知时间达到“影分身”的效果
free:免费,成本低;还有稳定性强,泛用性广的特点

2.freeRTOS基础
调度模式
抢占式,时间片,协程式
抢占式:类似于中断,代码运行时间可以更长,优先级没中断高,快速切换任务
时间片:针对优先级相同的任务,根据滴答时钟切换时间片,同时执行多个任务
任务的4个状态
运行,就绪,阻塞,挂起

就绪:pxReadyTasksLists[x],在32位操作系统中为0~31,其中task31最高
阻塞:pxDelayedTaskList,
挂起:xSuspendedTaskList
就绪态可以直接转运行,新建列表xTaskCreate默认为就绪列表,阻塞和挂起需要转为就绪列表才能运行
3.移植
网盘资料内容

1.添加源码文件
根据环境选择对应源码,这里选择kernel
\FreeRTOSv202406.04-LTS\FreeRTOS\FreeRTOS-Kernel

只留下使用的3个文件夹,使用AC6编译器这里RVDS换成gcc

在q5中添加文件夹 FreeRTOS_CORE和FreeRTOS_PORT(这个随便


在软件内左侧文件列表,双击文件夹图标添加文件
core文件夹 \FreeRTOS\所有c文件
port文件夹 根据开发板选择 \FreeRTOS\portable\RVDS
\FreeRTOS\portable\MemMang\heap_4.c

效果如下

2.配置头文件

3.修改FreeRTOSConfig.h
这里因为官网已经不提供例程(无法直接复制对应开发板的配置文件,采用直接移植的方法,改一下就好了
也是最推荐的方法(其实也不是很麻烦,或者使用cubeMx生成)
FreeRTOSConfig.h
#ifndef FREERTOS_CONFIG_H
#define FREERTOS_CONFIG_H
/* 头文件 */
#include <stdint.h>
#include <stdio.h>
#include "stm32f103xb.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, 默认: 不定义 仅f1打开:切换为HCLK时钟频率需要/8 */
#define configTICK_RATE_HZ 1000 /* 定义系统时钟节拍频率, 单位: Hz, 无默认需定义 */
#define configMAX_PRIORITIES 32 /* 定义最大优先级数, 最大优先级=configMAX_PRIORITIES-1, 无默认需定义 */
#define configMINIMAL_STACK_SIZE 128 /* 定义空闲任务的栈空间大小, 单位: Word, 无默认需定义 */
#define configMAX_TASK_NAME_LEN 16 /* 定义任务名最大字符数, 默认: 16 */
#define configUSE_16_BIT_TICKS 0 /* 1: 定义系统时钟节拍计数器的数据类型为16位无符号整型, 0:32位无符号整型 无默认需定义 */
#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)(10 * 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 vAssertCalled(char, int) printf("Error: %s, %d\r\n", char, int)
#define configASSERT(x) \
if ((x) == 0) \
vAssertCalled(__FILE__, __LINE__)
/* FreeRTOS MPU 特殊定义 */
// #define configINCLUDE_APPLICATION_DEFINED_PRIVILEGED_FUNCTIONS 0
// #define configTOTAL_MPU_REGIONS 8
// #define configTEX_S_C_B_FLASH 0x07UL
// #define configTEX_S_C_B_SRAM 0x07UL
// #define configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY 1
// #define configALLOW_UNPRIVILEGED_CRITICAL_SECTIONS 1
/* ARMv8-M 安全侧端口相关定义。 */
// #define secureconfigMAX_SECURE_CONTEXTS 5
#endif /* FREERTOS_CONFIG_H */
修改部分
第7行 #include "stm32f103xb.h" 需要根据开发板切换

stm32f103xb.h文件路径 \Drivers\CMSIS\Device\ST\STM32F1xx\Include\
f407IGT6为 #include "stm32f407xx.h"
调整内存分配,这里禁用静态模式
静态模式需要添加
1.空任务 保证运行
2.软件定时器
3.内存管理 手动分配指定内存(数组)
动态模式采用port4的简易内存管理,重复更改的动态管理会爆内存(泡空间)
41行要小于单片机RAM的大小
RAM大小仅供参考,并没有具体的定义
型号 falsh大小 RAM大小
x4 16KB 6KB
x6 32KB 10KB
x8 64KB 20KB
xB 128KB 20KB
xC 256KB 48KB
xE 384KB 64KB
xE 512KB 128KB
xF 768KB 192KB
xG 1MB 256KB

4.修改中断
在FreeRTOS 的移植过程中会这几到三个重要的中断,分别是 FreeRTOS 系统时基定时器 的中断(SysTick中断)、SVC中断、PendSV中断
这里在中断中定义可以避免cubeMx生成时中断函数被删除,会增加一个调用时间的延迟(很小,几us
添加头文件

声明中断服务函数

引用


5.验证
demo1.c
/* FreeRTOS */
#include "FreeRTOS.h"
#include "task.h"
#include "demo1.h"
/*FreeRTOS 任务配置*/
/* START_TASK 任务 配置
* 包括: 任务句柄 任务优先级 堆栈大小 创建任务
*/
#define START_TASK_PRIO 1 // 启动任务优先级
#define START_TASK_STK_SIZE 128 // 启动任务堆栈大小
TaskHandle_t Start_Task_Handler; // 启动任务句柄
void Start_Task(void *pvParameters); // 启动任务函数声明
#define TASK1_PRIO 2 // 任务优先级
#define TASK1_STK_SIZE 128 // 任务堆栈大小
TaskHandle_t Task1_Task_Handler; // 任务句柄
void Task1(void *pvParameters); // 任务函数声明
#define TASK2_PRIO 3 // 任务2优先级
#define TASK2_STK_SIZE 128 // 任务2堆栈大小
TaskHandle_t Task2_Task_Handler; // 任务2句柄
void Task2(void *pvParameters); // 任务2函数声明
/**
* @brief FreeRTOS例程入口函数
* @param 无
* @retval 无
*/
void freertos_demo(void)
{
xTaskCreate( (TaskFunction_t )Start_Task, /* 任务函数 */
(const char* )"start_task", /* 任务名称 */
(uint16_t )START_TASK_STK_SIZE, /* 任务堆栈大小 */
(void* )NULL, /* 传入给任务函数的参数 */
(UBaseType_t )START_TASK_PRIO, /* 任务优先级 */
(TaskHandle_t* )&Start_Task_Handler); /* 任务句柄 */
vTaskStartScheduler();
}
/**
* @brief start_task 开始任务入口函数
* @param pvParameters : 传入参数(未用到)
* @retval 无
*/
void Start_Task(void *pvParameters)
{
taskENTER_CRITICAL(); /* 进入临界区 */
/* 创建任务1 */
xTaskCreate( (TaskFunction_t )Task1,
(const char* )"task1",
(uint16_t )TASK1_STK_SIZE,
(void* )NULL,
(UBaseType_t )TASK1_PRIO,
(TaskHandle_t* )&Task1_Task_Handler);
/* 创建任务2 */
xTaskCreate( (TaskFunction_t )Task2,
(const char* )"task2",
(uint16_t )TASK2_STK_SIZE,
(void* )NULL,
(UBaseType_t )TASK2_PRIO,
(TaskHandle_t* )&Task2_Task_Handler);
vTaskDelete(Start_Task_Handler); /* 删除开始任务 */
taskEXIT_CRITICAL(); /* 退出临界区 */
}
/**
* @brief task1
* @param pvParameters : 传入参数(未用到)
* @retval 无
*/
void Task1(void *pvParameters)
{
while(1)
{
HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
vTaskDelay(1000);
}
}
/**
* @brief task2
* @param pvParameters : 传入参数(未用到)
* @retval 无
*/
void Task2(void *pvParameters)
{
float float_num = 0.0;
while(1)
{
float_num += 0.01f; /* 更新数值 */
printf("float_num: %0.4f\r\n", float_num); /* 打印数值 */
vTaskDelay(1000); /* 延时1000ticks */
}
}
demo1.h
#ifndef __DEMO1_H__
#define __DEMO1_H__
#include "stm32f1xx_hal.h"
#include "gpio.h"
void freertos_demo(void);
#endif
main.c
#include "main.h"
#include "usart.h"
#include "gpio.h"
#include "demo1.h"
#include "FreeRTOS.h"
#include "task.h"
void SystemClock_Config(void);
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART1_UART_Init();
freertos_demo();
while (1)
{
}
}
效果
是一个板载led闪烁和串口发送
4.freeRTOS配置文件
FreeRTOSConfig.h配置文件作用:对freeRTOS进行功能配置和裁剪,及api函数使能
官网中文在线文档:定制 - FreeRTOS™
“include” 配置API函数
“config” 功能配置和裁剪
“other” PendSV,SVC宏定义
5.api
动态创建任务函数xTaskCreate
BaseType_t xTaskCreate(
TaskFunction_t pxTaskCode, /*指向任务函数的指针*/
const char * const pcName, /*任务名字*/
const configSTACK_DEPTH_TYPE uxStackDepth, /*任务堆栈大小,以字为单位*/
void * const pvParameters, /*传递给任务函数的参数,一般为null*/
UBaseType_t uxPriority, /*任务优先级*/
TaskHandle_t * const pxCreatedTask /*任务句柄,任务控制块*/
) PRIVILEGED_FUNCTION;
返回值 1.pdPASS 创建成功
2.errCOULD_NOT_ALLOCATE_REQUIRED_MENMORY创建失败(该任务内存溢出
临界区taskENTER_CRITICAL();
创建任务时加的一层保险,暂时禁用中断,这里是防止创建任务失败
需要配合taskEXIT_CRITICAL(); 退出临界区一起使用
任务创建流程
1.注意宏定义参数;静态任务创建与动态任务创建
2.定义函数入口参数
3.编写任务函数
任务创建后会自动进入就绪列表
更多推荐


所有评论(0)