什么是freertos?
参考正点原子的教程
- 免费实时操作系统
- 对某一事件做实时响应,即:任务调度是可以预测的
- 用户分配优先级:文件系统比ucos小
移植
freertos v9
-
FREERTOS/sources 所有文件复制到新建工程下
-
/porttable 只留下 Keil;MemMang(内存管理);RVDs(针对架构的代码)
-
添加到工程
FREERTOS/CORE:
FREERTOS/PORTABLE:
ports/ARM_CM4F/port.c
ports/MemMang/heap_4.c (5中不同的内存管理)
-
FreeRTOSConfig.h(demo 目录下)添加到库中
配置文件
并配置 SystemCoreClock 支持
#if __ICCARM__||__CC_ARM||__GNUC__
#include <stdint.h>
extern uint32_t SystemCoreClock;
#endif
- 屏蔽stm32f4xxit.c 中
PendSV_Handler()
SysTick_Handler()
SVC_Handler()
- 关闭钩子(回调)函数
#define configUSE_IDLE_HOOK 0
#define configUSE_TICK_HOOK 0
#define configUSE_MALLOC_FAILED_HOOK 0
- 修改sys.h
sys和usart
sys
#define SYSTEM_SUPPORT_OS 1
usart
#include "FreeRTOS.H"//替换#include "includes.h"
删除usart 中对于ucos的支持
delay
//系统时钟
#include "task.h"
extern void xPortSysTickHandler(void);
void SysTick_Handler(void)
{
if(xTaskGetSchedulerState()!=taskSCHEDULER_NOT_STARTED) //系统正在运行
{
xPortSysTickHandler();
}
HAL_IncTick();
HAL_SYSTICK_IRQHandler();
}
void delay_init(u8 SYSCLK)
{
#if SYSTEM_SUPPORT_OS //如果需要支持OS.
u32 reload;
#endif
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);;//SysTick频率为HCLK
fac_us=SYSCLK; //不论是否使用OS,fac_us都需要使用
#if SYSTEM_SUPPORT_OS //如果需要支持OS.
reload=SYSCLK; //每秒钟的计数次数 单位为K
reload*=1000000/configTICK_RATE_HZ; //根据configTICK_TATE_HZ 设置
//reload为24位寄存器,最大值:16777216,在180M下
fac_ms=1000/configTICK_RATE_HZ; //代表OS可以延时的最少单位
SysTick->CTRL|=SysTick_CTRL_TICKINT_Msk;//开启SYSTICK中断
SysTick->LOAD=reload; //每1/OS_TICKS_PER_SEC秒中断一次
SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk; //开启SYSTICK
#else
#endif
}
delay_us()//注释os
void delay_ms(u16 nms)
{
if(xTaskGetSchedulerState()!=taskSCHEDULER_NOT_STARTED)//如果OS已经在跑了,并且不是在中断里面(中断里面不能任务调度)
{
if(nms>=fac_ms) //延时的时间大于OS的最少时间周期
{
vTaskDelay(nms/fac_ms); //OS延时
}
nms%=fac_ms; //OS已经无法提供这么小的延时了,采用普通方式延时
}
delay_us((u32)(nms*1000)); //普通方式延时
}
测试
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "key.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 LED0_TASK_PRIO 2
#define LED0_STK_SIZE 50
TaskHandle_t LED0Task_Handler;
void led0_task(void *p_arg);
#define LED1_TASK_PRIO 3
#define LED1_STK_SIZE 50
TaskHandle_t LED1Task_Handler;
void led1_task(void *p_arg);
#define FLOAT_TASK_PRIO 4
#define FLOAT_STK_SIZE 128
TaskHandle_t FLOATTask_Hanlder;
void float_task(void *p_arg);
int main(void)
{
HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);
HAL_Init();//初始化 flash 预存取(FLASH访问周期FLASH 存储器具有由两个64 位缓存器组成的预取缓冲器,这些缓冲器可以从FLASH 存储器中进行64 位宽读取,然后传递独立的16 位或32 位指令给Cortex CPU执性) 系统中断 系统时钟 中断回调
Stm32_Clock_Init(336,8,2,7);
delay_init(168);
uart_init(115200);
LED_Init();
//创建起始任务
xTaskCreate( (TaskFunction_t ) start_task,//任务函数
(const char*) "start_task",//任务名
(uint16_t ) START_STK_SIZE, //堆栈大小
(void *) NULL, //传递参书
(UBaseType_t) START_TASK_PRIO,//优先级 unsign long
(TaskHandle_t *) &StartTask_Handler//人去句柄
);
vTaskStartScheduler();
}
void start_task(void *pvParameters)
{
taskENTER_CRITICAL();//进入临界区
//创建任务1
xTaskCreate( (TaskFunction_t)led0_task,
(const char *)"led 0",
(uint16_t) LED0_STK_SIZE,
(void *)NULL,
(UBaseType_t) LED0_TASK_PRIO,
(TaskHandle_t *) &LED0Task_Handler
);
xTaskCreate( (TaskFunction_t)led1_task,
(const char*)"led1",
(uint16_t)LED1_STK_SIZE,
(void *)NULL,
(UBaseType_t) LED1_TASK_PRIO,
(TaskHandle_t *)&LED1Task_Handler
);
xTaskCreate( (TaskFunction_t)float_task,
(const char *)"float task",
(uint16_t)FLOAT_STK_SIZE,
(void *)NULL,
(UBaseType_t)FLOAT_TASK_PRIO,
(TaskHandle_t *)&FLOATTask_Hanlder
);
vTaskDelete(StartTask_Handler); //删除开始任务
taskEXIT_CRITICAL();//推出临界区
}
void led0_task(void *p_arg)
{
while(1)
{
LED0=!LED0;
vTaskDelay(500);
}
}
void led1_task(void *p_arg)
{
while(1)
{
LED1=0;
vTaskDelay(200);
LED1=1;
vTaskDelay(800);
}
}
void float_task(void *p_arg)
{
static float float_num=0.0;
while(1)
{
float_num +=0.01f;
printf("float_num:%.4f\r\n",float_num);
vTaskDelay(1000);
}
}
FreeRTOSConfig.h 文件简单阅读
- include宏
宏 | 对应函数 | 说明 |
---|---|---|
INCLUDE_vTaskPrioritySet | uxTaskPriorityGet() | 函数用于查询一个任务的优先级 |
INCLUDE_uxTaskPriorityGet | vTaskPrioritySet() | 修改任务的优先级 |
INCLUDE_vTaskDelete | vTaskDelete | 删除任务 |
INCLUDE_vTaskCleanUpResources | vTaskCleanUpResources( ) | 回收任务的ram等资源 |
INCLUDE_vTaskSuspend | vTaskSuspend();vTaskResume();prvTaskIsTaskSusPended() | 与任务挂起相关 |
INCLUDE_vTaskDelayUntil | vTaskDelayUntil() | 指定任务离开阻塞态进入就绪态那一刻的心跳计数值 |
INCLUDE_vTaskDelay | vTaskDelay | 任务将进入阻塞态 |
INCLUDE_xSemaphoreGetMutexHolder | xQueueGetMutexHolder | 获取函数参数中互斥量的任务句柄 |
INCLUDE_xTaskAbortDelay | xTaskAbortDelay() | 任务中止延时函数,该函数能立即解除任务的阻塞状态,将任务插入就绪列表中 |
INCLUDE_xTaskGetCurrentTaskHandle | xTaskGetCurentTaskHandle() | 获得当前任务句柄 |
INCLUDE_xTaskGetHandle | xTaskGetHandle() | |
INCLUDE_xTaskGetSchedulerState | xTaskGetSchedulerState() | 获取任务调度器的壮态,开启或未开启。 |
INCLUDE_uxTaskGetStackHIghWaterMark | xTaskGetSchedulerState | 获取任务的堆栈的历史剩余最小值, FreeRTOS 中叫做“高水位线” |
INCLUDE_xTaskResumeFromISR | xTaskResumeFromISR() | j将任务从挂起状态恢复 |
INCLUDE_xTimerPendFunctionCall | xTImerPendFunctionCall xTimerPendFunctionCallFromISR | 需要configUSE_TIMERS=1 定时器任务 |
- config 宏
宏 | 说明 |
---|---|
configUSE_PREEMPTION | 1:抢占式优先级 0:使用协程(1) 调用taskYIELD() 发生 (2):调用了使任务进入阻塞态的API函数 (3):中断中执行上下文切换 |
configUSE_IDLE_HOOK | 空闲钩子函数,需要用户自己实现 |
configUSE_TICK_HOOK | 使能时间片钩子函数,用户自己实现 |
configCPU_CLOCK_HZ | CPUI频率 |
configTICK_RATE_HZ | Freertos 系统时钟节拍,单位HZ,1000=1ms |
configMAX_PRIORITIES | 系统优先级的数量 0:为最低优先级(与ucos不同) |
configMINIMAL_STACK_SIZE | 空闲任务的最小任务堆栈大小,单位(字 = 4字节) |
configTOTAL_HEAP_SIZE | 如果使能动态内存管理,会使用heap_x中的内存申请函数来申请内存 |
configUSE_TRACE_FACILITY | 与configUSE_STATS_FORMATTING_FUNCTIONS=1 生成vTaskList() 和vTaskGetRunTImeStatus()分析任务内存和状态 |
configUSE_16_BIT_TICKS | 设置系统节拍的变量类型 1:TickType_t 16位 0:32位 |
configIDLE_SHOULD_YIELD | 空闲任务与同优先级的执行机制,0:空闲任务优先 1:空闲人无让出CPU给同优先级的任务 |
configUSE_MUTEXES | 是否使用信号量 |
configQUEUE_REGISTRY_SIZE | 可以注册的队列和信号量的最大数量,使用内核调试器需要查看信号量和队列时需要设置,且先注册消息队列和信号量 |
configCHECK_FOR_STACK_OVERFLOW | 堆栈溢出检测,xTaskCreate()大小自动从任务堆栈分配,xTaskCreateStatic()从用户设置堆栈中分配,用户必须自己设置一个钩子函数(void vApplicationStackOverflowHook(TaskHandle_t xTask,char* pcTaskName)) ,其余暂时没遇到 |
configUSE_RECURSIVE_MUTEXES | 使用互斥信号量 |
configUSE_MALLOC_FAILED_HOOK | 内存分配失败的回调函数 |
configUSE_APPLICATION_TASK_TAG | configUSE_APPLICATION_TASK_TAGF() &xTaskCallApplicationTaskHook() 可以为任务绑定回调函数 |
configUSE_COUNTING_SEMAPHORES | 是否启用计数型信号量 |
configGENERATE_RUN_TIME_STATS | 是否时间统计功能 ,需要定义一个宏 |
协程 | |
configUSE_CO_ROUTINES | 是否启用协程 |
configMAX_CO_ROUTINE_PRIORITIES | 分配给协程的最大优先级(0 最低) |
定时器 | |
configUSE_TIMERS | 1 使能软件定时器 |
configTIMER_TASK_PRIORITY | 软件定时器优先级 |
configTIMER_QUEUE_LENGTH | 软件定时器的命令队列长度 |
configTIMER_TASK_STACK_DEPTH | 软件定时器任务堆栈大小 |
中断配置 | |
configPRIO_BITS | MCU优先级的位数 STM32 4位(16个抢占) |
configLIBRARY_LOWEST_INTERRUPT_PRIORITY | 设置最低优先级,stm32 使用组4,最低值位15 |
configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY | FreeRtos可管理的最大优先级 |
configKERNEL_INTERRUPT_PRIORITY | 内核中断优先级 |
configASSERT | 错误判断函数 |
vPortSVCHandler | 中断服务函数 |
vPortSVCHandler | SVC中断服务函数 |
xPortSysTickHandler | 系统滴答定时器 |