文章目录[隐藏]
基本概念
ROTS
RTOS全称:Real time OS,就是实时操作系统,强调的是:实时性。实时操作系统又分为软实时和硬实时。硬实时要求在规定时间内必须完成操作,硬实时不允许超时,软实时里面处理过程超时的后果就没有那么严格。
在实时操作系统中,我们可以把要实现的功能划分为多个任务,每个任务负责实现其中的一部分,每个任务都是一个很简单的程序,通常是一个死循环。
RTOS操作系统:FreeRTOS,UCOS,RTX,RT-THread,DJYOS等
RTOS操作系统的核心内容在于:实时内核。
可剥夺内核
RTOS的内核负责管理所有的任务,内核决定了运行那个任务,何时停止当前任务切换到其他任务,这个是内核的多任务管理能力。多任务管理给人的感觉就是芯片有多个CPU,多任务管理实现了CPU资源的最大化利用,多任务管理有助于实现程序的模块化开发,能够实现复杂的实时利用。
可剥夺性内核顾名思义就是可以剥夺其他任务的CPU使用权,他总是运行就绪任务中优先级最高的任务。
为什么学习FreeRtos
1 因为Freertos开源
2 Freertos免费
3 Freertos是很多第三方组件钦定的系统
FreeRTOS 特点
FreeRTOS 是一个可裁剪的小型 RTOS 系统,其特点包括:
1 任务简单
2 任务没有数量使用限制
3 任务支持抢占
4 任务支持优先级
5 每个任务都拥有堆栈导致了RAM使用量大
6 如果使用抢占的话必须仔细考虑重入问题
FreeRTOS 任务状态
对于单内核的芯片而言,任一任务要么处于运行态,要么处于非运行态。但同一时刻只能有一个任务处于运行态。这也是为什么这个图中①画的任务框是多个叠起来的,而②所示的任务只有一个框的原因。
任务从非运行态转移到运行态被称为”切换入或切入(switched in)”或”交换入(swapped in)”。相反,任务从运行态转移到非运行态被称为”切换出或切出(switched
out)”或”交换出(swapped out)”。FreeRTOS 的调度器是能让任务切入切出的唯一实体。
那么事实上,对于非运行态其内部又被划分出了几个子状态:
挂起态
就绪态
阻塞态
僵尸态
FreeRTOS资料与源码下载
要找资料,官网是最好的地方,FreeRTOS的官网是www.freertos.org。
进入 FreeRTOS 首页,就会看到download下载链接,进入后下载“FreeRTOS 202112.00”文件
FreeRTOS移植
1、添加 FreeRTOS 源码
在基础工程中新建一个名为 FreeRTOS 的文件夹。创建FreeRTOS 文件夹以后就可以将 FreeRTOS 的源码添加到这个文件夹中,我们只需要留下 keil、MemMang 和 RVDS 这三个文件夹,其他的都可以删除掉。
2、向工程分组中添加文件
打开基础工程,新建分组 FreeRTOS_CORE 和 FreeRTOS_PORTABLE,然后向这两个分组中添加文件。
3、添加相应的头文件路径
添加完 FreeRTOS 源码中的 C 文件以后还要添加 FreeRTOS 源码的头文件路径,头文件路径
头文件路径添加完成以后编译一下,看看有没有什么错误,结果会发现提示打不开“FreeRTOSConfig.h”这个文件
打开FreeRTOS 针对 STM32F103 的移植工程文件,从例程中找到这个文件复制过来。
4、修改 SYSTEM 文件
1、修改 sys.h 文件
sys.h 文件修改很简单,在 sys.h 文件里面用宏 SYSTEM_SUPPORT_OS 来定义是否使用 OS,
我们使用了 FreeRTOS,所以应该将宏 SYSTEM_SUPPORT_OS 改为 1。
//0,不支持os
//1,支持os
#define SYSTEM_SUPPORT_OS 1 //定义系统文件夹是否支持OS
2、修改 usart.c 文件
一个是添加 FreeRTOS.h 头文件
#if SYSTEM_SUPPORT_OS
#include "FreeRTOS.h" //FreeRTOS使用
#endif
另外一个就是 USART1 的中断服务函数,在使用 UCOS 的时候进出中断的时候需要添加OSIntEnter()和 OSIntExit(),使用 FreeRTOS 的话就不需要了,所以将这两行代码删除掉。
3、修改 delay.c 文件
delay.c 文件修改的就比较大了,因为涉及到 FreeRTOS 的系统时钟
1 在滴答定时器中断服务函数中调用FreeRTOS 的 API 函数 xPortSysTickHandler()。
extern void xPortSysTickHandler(void);
2 在基础例程中滴答定时器的时钟频率设置的是 AHB 的 1/8,这里为了兼容 FreeRTOS 将滴答定时器的时钟频率改为了 AHB,也就是 72MHz!
void delay_init()
{
u32 reload;
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK);//选择外部时钟 HCLK
fac_us=SystemCoreClock/1000000; //不论是否使用OS,fac_us都需要使用
reload=SystemCoreClock/1000000; //每秒钟的计数次数 单位为M
reload*=1000000/configTICK_RATE_HZ; //根据configTICK_RATE_HZ设定溢出时间
//reload为24位寄存器,最大值:16777216,在72M下,约合0.233s左右
fac_ms=1000/configTICK_RATE_HZ; //代表OS可以延时的最少单位
SysTick->CTRL|=SysTick_CTRL_TICKINT_Msk; //开启SYSTICK中断
SysTick->LOAD=reload; //每1/configTICK_RATE_HZ秒中断一次
SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk; //开启SYSTICK
}
3.delay_us()是 us 级延时函数,delay_ms 和 delay_xms()都是 ms 级的延时函数,delay_us()和delay_xms()不会导致任务切换。delay_ms()其实就是对 FreeRTOS 中的延时函数 vTaskDelay()的简单封装,所以在使用 delay_ms()的时候就会导致任务切换。
4 要将 stm32f10x_it.c 中的三个函数:滴答定时器中断服务函数、SVC 中断服务函数和 PendSV 中断服务函数屏蔽掉。
//void SVC_Handler(void)
//{
//}
void DebugMon_Handler(void)
{
}
//void PendSV_Handler(void)
//{
//}
//
//void SysTick_Handler(void)
//{
//}
任务动态创建
动态创建任务, 调用函数内部向系统申请创建新任务所需的内存,包括任务控制块和栈。 所以调用这个函数,在内存堆空间不足或者碎片话的情况下,可能创建新任务失败,需要判断函数执行后是否成功返回。
xTaskCreat();
vTaskDelete();
将 configSUPPORT_STATIC_ALLOCATION 宏设为0
#ifndef configSUPPORT_STATIC_ALLOCATION
/* Defaults to 0 for backward compatibility. */
#define configSUPPORT_STATIC_ALLOCATION 0
#endif
main.c
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "FreeRTOS.h"
#include "task.h"
//开始任务
#define START_STK_SIZE 128
#define START_TASK_PRIO 1
TaskHandle_t StartTask_Hander ;
void start_task( void * pvParameters );
//Task1任务
#define TASK1_STK_SIZE 128
#define TASK1_TASK_PRIO 1
TaskHandle_t Task1Task_Handle ;
void task1_task( void * pvParameters );
//Task2任务
#define TASK2_STK_SIZE 128
#define TASK2_TASK_PRIO 1
TaskHandle_t Task2Task_Handle ;
void task2_task( void * pvParameters );
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4
delay_init(); //延时函数初始化
uart_init(115200); //初始化串口
LED_Init(); //初始化LED
//创建开始任务
xTaskCreate( (TaskFunction_t) start_task,
(char * ) "start_task",
(uint32_t) START_STK_SIZE,
(void * ) NULL,
(UBaseType_t) START_TASK_PRIO,
(TaskHandle_t *) &StartTask_Hander );
vTaskStartScheduler(); //开启任务调度
}
void start_task( void * pvParameters )
{
//创建开始任务1
xTaskCreate( (TaskFunction_t) task1_task,
(char * ) "task1_task",
(uint32_t) TASK1_STK_SIZE,
(void * ) NULL,
(UBaseType_t) TASK1_TASK_PRIO,
(TaskHandle_t *) &StartTask_Hander );
//创建开始任务2
xTaskCreate( (TaskFunction_t) task2_task,
(char * ) "task2_task",
(uint32_t) TASK2_STK_SIZE,
(void * ) NULL,
(UBaseType_t) TASK2_TASK_PRIO,
(TaskHandle_t *) &StartTask_Hander );
vTaskDelete(StartTask_Hander); //删除任务
}
void task1_task( void * pvParameters )
{
/* 可以像普通函数一样定义变量。用这个函数创建的每个任务实例都有一个属于自己的task1_num变
量。但如果task1_num被定义为static,这一点则不成立 – 这种情况下只存在一个变量,所有的任务实
例将会共享这个变量。 */
char task1_num = 0;
/* 任务通常实现在一个死循环中。 */
while(1)
{
/* 完成任务功能的代码将放在这里。 */
if(task1_num == 6 )
{
printf("task1 run %d\r\n",task1_num);
vTaskDelete(Task1Task_Handle);
}
task1_num++;
LED1= ~LED1;
vTaskDelay(1000);
printf("task1 run %d\r\n",task1_num);
}
/* 如果任务的具体实现会跳出上面的死循环,则此任务必须在函数运行完之前删除。传入NULL参数表示删除
的是当前任务 */
//vTaskDelete( NULL );
}
void task2_task( void * pvParameters )
{
char task2_num = 0;
while(1)
{
task2_num++;
LED0 = ~LED0;
vTaskDelay(1000);
printf("task1 run %d\r\n",task2_num);
}
}
任务静态创建
将 configSUPPORT_STATIC_ALLOCATION 宏设为1
#ifndef configSUPPORT_STATIC_ALLOCATION
/* Defaults to 0 for backward compatibility. */
#define configSUPPORT_STATIC_ALLOCATION 1
#endif
vApplicationGetIdleTaskMemory() 空闲任务所需内存
vApplicationGetTimerTaskMemory() 定时器所需内存
main.c
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "FreeRTOS.h"
#include "task.h"
//开始任务
#define START_STK_SIZE 128
#define START_TASK_PRIO 1
StackType_t StartTaskStack[START_STK_SIZE];
TaskHandle_t StartTask_Handle ;
StaticTask_t StartTaskTCB;
void start_task( void * pvParameters );
//Task1任务
#define TASK1_STK_SIZE 128
#define TASK1_TASK_PRIO 1
StackType_t Task1TaskStack[TASK1_STK_SIZE];
TaskHandle_t Task1Task_Handle ;
StaticTask_t Task1TaskTCB;
void task1_task( void * pvParameters );
//Task2任务
#define TASK2_STK_SIZE 128
#define TASK2_TASK_PRIO 1
StackType_t Task2TaskStack[TASK2_STK_SIZE];
TaskHandle_t Task2Task_Handle ;
StaticTask_t Task2TaskTCB;
void task2_task( void * pvParameters );
//空闲任务
static StackType_t IdleTaskStack[configMINIMAL_STACK_SIZE];
static StaticTask_t IdleTaskTCB;
//定时器任务
static StackType_t TimerTaskStack[configTIMER_TASK_STACK_DEPTH];
static StaticTask_t TimerTaskTCB;
//空闲任务所需内存
void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer,
StackType_t **ppxIdleTaskStackBuffer,
uint32_t *pulIdleTaskStackSize )
{
*ppxIdleTaskTCBBuffer = &IdleTaskTCB;
*ppxIdleTaskStackBuffer = IdleTaskStack;
*pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;
}
//定时器所需内存
void vApplicationGetTimerTaskMemory( StaticTask_t **ppxTimerTaskTCBBuffer,
StackType_t **ppxTimerTaskStackBuffer,
uint32_t *pulTimerTaskStackSize )
{
*ppxTimerTaskTCBBuffer = &TimerTaskTCB;
*ppxTimerTaskStackBuffer = TimerTaskStack;
*pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH;
}
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4
delay_init(); //延时函数初始化
uart_init(115200); //初始化串口
LED_Init(); //初始化LED
//创建开始任务
StartTask_Handle = xTaskCreateStatic( (TaskFunction_t) start_task,
(char * ) "start_task",
(uint32_t) START_STK_SIZE,
(void * ) NULL,
(UBaseType_t) START_TASK_PRIO,
(StackType_t *) StartTaskStack,
(StaticTask_t *) &StartTaskTCB );
vTaskStartScheduler(); //开启任务调度
}
void start_task( void * pvParameters )
{
//创建开始任务1
Task1Task_Handle = xTaskCreateStatic( (TaskFunction_t) task1_task,
(char * ) "task1_task",
(uint32_t) TASK1_STK_SIZE,
(void * ) NULL,
(UBaseType_t) TASK1_TASK_PRIO,
(StackType_t *) Task1TaskStack,
(StaticTask_t *) &Task1TaskTCB );
//创建开始任务2
Task2Task_Handle = xTaskCreateStatic( (TaskFunction_t) task2_task,
(char * ) "task2_task",
(uint32_t) TASK2_STK_SIZE,
(void * ) NULL,
(UBaseType_t) TASK2_TASK_PRIO,
(StackType_t *) Task2TaskStack,
(StaticTask_t *) &Task2TaskTCB );
vTaskDelete(StartTask_Handle); //删除任务
}
void task1_task( void * pvParameters )
{
char task1_num = 0;
while(1)
{
if(task1_num == 6 )
{
printf("task1 run %d\r\n",task1_num);
vTaskDelete(Task1Task_Handle);
}
task1_num++;
LED1= ~LED1;
vTaskDelay(1000);
printf("task1 run %d\r\n",task1_num);
}
}
void task2_task( void * pvParameters )
{
char task2_num = 0;
while(1)
{
task2_num++;
LED0 = ~LED0;
vTaskDelay(1000);
printf("task1 run %d\r\n",task2_num);
}
}
版权声明:本文为CSDN博主「林木ovo」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_56380842/article/details/122393436
基本概念
ROTS
RTOS全称:Real time OS,就是实时操作系统,强调的是:实时性。实时操作系统又分为软实时和硬实时。硬实时要求在规定时间内必须完成操作,硬实时不允许超时,软实时里面处理过程超时的后果就没有那么严格。
在实时操作系统中,我们可以把要实现的功能划分为多个任务,每个任务负责实现其中的一部分,每个任务都是一个很简单的程序,通常是一个死循环。
RTOS操作系统:FreeRTOS,UCOS,RTX,RT-THread,DJYOS等
RTOS操作系统的核心内容在于:实时内核。
可剥夺内核
RTOS的内核负责管理所有的任务,内核决定了运行那个任务,何时停止当前任务切换到其他任务,这个是内核的多任务管理能力。多任务管理给人的感觉就是芯片有多个CPU,多任务管理实现了CPU资源的最大化利用,多任务管理有助于实现程序的模块化开发,能够实现复杂的实时利用。
可剥夺性内核顾名思义就是可以剥夺其他任务的CPU使用权,他总是运行就绪任务中优先级最高的任务。
为什么学习FreeRtos
1 因为Freertos开源
2 Freertos免费
3 Freertos是很多第三方组件钦定的系统
FreeRTOS 特点
FreeRTOS 是一个可裁剪的小型 RTOS 系统,其特点包括:
1 任务简单
2 任务没有数量使用限制
3 任务支持抢占
4 任务支持优先级
5 每个任务都拥有堆栈导致了RAM使用量大
6 如果使用抢占的话必须仔细考虑重入问题
FreeRTOS 任务状态
对于单内核的芯片而言,任一任务要么处于运行态,要么处于非运行态。但同一时刻只能有一个任务处于运行态。这也是为什么这个图中①画的任务框是多个叠起来的,而②所示的任务只有一个框的原因。
任务从非运行态转移到运行态被称为”切换入或切入(switched in)”或”交换入(swapped in)”。相反,任务从运行态转移到非运行态被称为”切换出或切出(switched
out)”或”交换出(swapped out)”。FreeRTOS 的调度器是能让任务切入切出的唯一实体。
那么事实上,对于非运行态其内部又被划分出了几个子状态:
挂起态
就绪态
阻塞态
僵尸态
FreeRTOS资料与源码下载
要找资料,官网是最好的地方,FreeRTOS的官网是www.freertos.org。
进入 FreeRTOS 首页,就会看到download下载链接,进入后下载“FreeRTOS 202112.00”文件
FreeRTOS移植
1、添加 FreeRTOS 源码
在基础工程中新建一个名为 FreeRTOS 的文件夹。创建FreeRTOS 文件夹以后就可以将 FreeRTOS 的源码添加到这个文件夹中,我们只需要留下 keil、MemMang 和 RVDS 这三个文件夹,其他的都可以删除掉。
2、向工程分组中添加文件
打开基础工程,新建分组 FreeRTOS_CORE 和 FreeRTOS_PORTABLE,然后向这两个分组中添加文件。
3、添加相应的头文件路径
添加完 FreeRTOS 源码中的 C 文件以后还要添加 FreeRTOS 源码的头文件路径,头文件路径
头文件路径添加完成以后编译一下,看看有没有什么错误,结果会发现提示打不开“FreeRTOSConfig.h”这个文件
打开FreeRTOS 针对 STM32F103 的移植工程文件,从例程中找到这个文件复制过来。
4、修改 SYSTEM 文件
1、修改 sys.h 文件
sys.h 文件修改很简单,在 sys.h 文件里面用宏 SYSTEM_SUPPORT_OS 来定义是否使用 OS,
我们使用了 FreeRTOS,所以应该将宏 SYSTEM_SUPPORT_OS 改为 1。
//0,不支持os
//1,支持os
#define SYSTEM_SUPPORT_OS 1 //定义系统文件夹是否支持OS
2、修改 usart.c 文件
一个是添加 FreeRTOS.h 头文件
#if SYSTEM_SUPPORT_OS
#include "FreeRTOS.h" //FreeRTOS使用
#endif
另外一个就是 USART1 的中断服务函数,在使用 UCOS 的时候进出中断的时候需要添加OSIntEnter()和 OSIntExit(),使用 FreeRTOS 的话就不需要了,所以将这两行代码删除掉。
3、修改 delay.c 文件
delay.c 文件修改的就比较大了,因为涉及到 FreeRTOS 的系统时钟
1 在滴答定时器中断服务函数中调用FreeRTOS 的 API 函数 xPortSysTickHandler()。
extern void xPortSysTickHandler(void);
2 在基础例程中滴答定时器的时钟频率设置的是 AHB 的 1/8,这里为了兼容 FreeRTOS 将滴答定时器的时钟频率改为了 AHB,也就是 72MHz!
void delay_init()
{
u32 reload;
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK);//选择外部时钟 HCLK
fac_us=SystemCoreClock/1000000; //不论是否使用OS,fac_us都需要使用
reload=SystemCoreClock/1000000; //每秒钟的计数次数 单位为M
reload*=1000000/configTICK_RATE_HZ; //根据configTICK_RATE_HZ设定溢出时间
//reload为24位寄存器,最大值:16777216,在72M下,约合0.233s左右
fac_ms=1000/configTICK_RATE_HZ; //代表OS可以延时的最少单位
SysTick->CTRL|=SysTick_CTRL_TICKINT_Msk; //开启SYSTICK中断
SysTick->LOAD=reload; //每1/configTICK_RATE_HZ秒中断一次
SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk; //开启SYSTICK
}
3.delay_us()是 us 级延时函数,delay_ms 和 delay_xms()都是 ms 级的延时函数,delay_us()和delay_xms()不会导致任务切换。delay_ms()其实就是对 FreeRTOS 中的延时函数 vTaskDelay()的简单封装,所以在使用 delay_ms()的时候就会导致任务切换。
4 要将 stm32f10x_it.c 中的三个函数:滴答定时器中断服务函数、SVC 中断服务函数和 PendSV 中断服务函数屏蔽掉。
//void SVC_Handler(void)
//{
//}
void DebugMon_Handler(void)
{
}
//void PendSV_Handler(void)
//{
//}
//
//void SysTick_Handler(void)
//{
//}
任务动态创建
动态创建任务, 调用函数内部向系统申请创建新任务所需的内存,包括任务控制块和栈。 所以调用这个函数,在内存堆空间不足或者碎片话的情况下,可能创建新任务失败,需要判断函数执行后是否成功返回。
xTaskCreat();
vTaskDelete();
将 configSUPPORT_STATIC_ALLOCATION 宏设为0
#ifndef configSUPPORT_STATIC_ALLOCATION
/* Defaults to 0 for backward compatibility. */
#define configSUPPORT_STATIC_ALLOCATION 0
#endif
main.c
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "FreeRTOS.h"
#include "task.h"
//开始任务
#define START_STK_SIZE 128
#define START_TASK_PRIO 1
TaskHandle_t StartTask_Hander ;
void start_task( void * pvParameters );
//Task1任务
#define TASK1_STK_SIZE 128
#define TASK1_TASK_PRIO 1
TaskHandle_t Task1Task_Handle ;
void task1_task( void * pvParameters );
//Task2任务
#define TASK2_STK_SIZE 128
#define TASK2_TASK_PRIO 1
TaskHandle_t Task2Task_Handle ;
void task2_task( void * pvParameters );
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4
delay_init(); //延时函数初始化
uart_init(115200); //初始化串口
LED_Init(); //初始化LED
//创建开始任务
xTaskCreate( (TaskFunction_t) start_task,
(char * ) "start_task",
(uint32_t) START_STK_SIZE,
(void * ) NULL,
(UBaseType_t) START_TASK_PRIO,
(TaskHandle_t *) &StartTask_Hander );
vTaskStartScheduler(); //开启任务调度
}
void start_task( void * pvParameters )
{
//创建开始任务1
xTaskCreate( (TaskFunction_t) task1_task,
(char * ) "task1_task",
(uint32_t) TASK1_STK_SIZE,
(void * ) NULL,
(UBaseType_t) TASK1_TASK_PRIO,
(TaskHandle_t *) &StartTask_Hander );
//创建开始任务2
xTaskCreate( (TaskFunction_t) task2_task,
(char * ) "task2_task",
(uint32_t) TASK2_STK_SIZE,
(void * ) NULL,
(UBaseType_t) TASK2_TASK_PRIO,
(TaskHandle_t *) &StartTask_Hander );
vTaskDelete(StartTask_Hander); //删除任务
}
void task1_task( void * pvParameters )
{
/* 可以像普通函数一样定义变量。用这个函数创建的每个任务实例都有一个属于自己的task1_num变
量。但如果task1_num被定义为static,这一点则不成立 – 这种情况下只存在一个变量,所有的任务实
例将会共享这个变量。 */
char task1_num = 0;
/* 任务通常实现在一个死循环中。 */
while(1)
{
/* 完成任务功能的代码将放在这里。 */
if(task1_num == 6 )
{
printf("task1 run %d\r\n",task1_num);
vTaskDelete(Task1Task_Handle);
}
task1_num++;
LED1= ~LED1;
vTaskDelay(1000);
printf("task1 run %d\r\n",task1_num);
}
/* 如果任务的具体实现会跳出上面的死循环,则此任务必须在函数运行完之前删除。传入NULL参数表示删除
的是当前任务 */
//vTaskDelete( NULL );
}
void task2_task( void * pvParameters )
{
char task2_num = 0;
while(1)
{
task2_num++;
LED0 = ~LED0;
vTaskDelay(1000);
printf("task1 run %d\r\n",task2_num);
}
}
任务静态创建
将 configSUPPORT_STATIC_ALLOCATION 宏设为1
#ifndef configSUPPORT_STATIC_ALLOCATION
/* Defaults to 0 for backward compatibility. */
#define configSUPPORT_STATIC_ALLOCATION 1
#endif
vApplicationGetIdleTaskMemory() 空闲任务所需内存
vApplicationGetTimerTaskMemory() 定时器所需内存
main.c
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "FreeRTOS.h"
#include "task.h"
//开始任务
#define START_STK_SIZE 128
#define START_TASK_PRIO 1
StackType_t StartTaskStack[START_STK_SIZE];
TaskHandle_t StartTask_Handle ;
StaticTask_t StartTaskTCB;
void start_task( void * pvParameters );
//Task1任务
#define TASK1_STK_SIZE 128
#define TASK1_TASK_PRIO 1
StackType_t Task1TaskStack[TASK1_STK_SIZE];
TaskHandle_t Task1Task_Handle ;
StaticTask_t Task1TaskTCB;
void task1_task( void * pvParameters );
//Task2任务
#define TASK2_STK_SIZE 128
#define TASK2_TASK_PRIO 1
StackType_t Task2TaskStack[TASK2_STK_SIZE];
TaskHandle_t Task2Task_Handle ;
StaticTask_t Task2TaskTCB;
void task2_task( void * pvParameters );
//空闲任务
static StackType_t IdleTaskStack[configMINIMAL_STACK_SIZE];
static StaticTask_t IdleTaskTCB;
//定时器任务
static StackType_t TimerTaskStack[configTIMER_TASK_STACK_DEPTH];
static StaticTask_t TimerTaskTCB;
//空闲任务所需内存
void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer,
StackType_t **ppxIdleTaskStackBuffer,
uint32_t *pulIdleTaskStackSize )
{
*ppxIdleTaskTCBBuffer = &IdleTaskTCB;
*ppxIdleTaskStackBuffer = IdleTaskStack;
*pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;
}
//定时器所需内存
void vApplicationGetTimerTaskMemory( StaticTask_t **ppxTimerTaskTCBBuffer,
StackType_t **ppxTimerTaskStackBuffer,
uint32_t *pulTimerTaskStackSize )
{
*ppxTimerTaskTCBBuffer = &TimerTaskTCB;
*ppxTimerTaskStackBuffer = TimerTaskStack;
*pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH;
}
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4
delay_init(); //延时函数初始化
uart_init(115200); //初始化串口
LED_Init(); //初始化LED
//创建开始任务
StartTask_Handle = xTaskCreateStatic( (TaskFunction_t) start_task,
(char * ) "start_task",
(uint32_t) START_STK_SIZE,
(void * ) NULL,
(UBaseType_t) START_TASK_PRIO,
(StackType_t *) StartTaskStack,
(StaticTask_t *) &StartTaskTCB );
vTaskStartScheduler(); //开启任务调度
}
void start_task( void * pvParameters )
{
//创建开始任务1
Task1Task_Handle = xTaskCreateStatic( (TaskFunction_t) task1_task,
(char * ) "task1_task",
(uint32_t) TASK1_STK_SIZE,
(void * ) NULL,
(UBaseType_t) TASK1_TASK_PRIO,
(StackType_t *) Task1TaskStack,
(StaticTask_t *) &Task1TaskTCB );
//创建开始任务2
Task2Task_Handle = xTaskCreateStatic( (TaskFunction_t) task2_task,
(char * ) "task2_task",
(uint32_t) TASK2_STK_SIZE,
(void * ) NULL,
(UBaseType_t) TASK2_TASK_PRIO,
(StackType_t *) Task2TaskStack,
(StaticTask_t *) &Task2TaskTCB );
vTaskDelete(StartTask_Handle); //删除任务
}
void task1_task( void * pvParameters )
{
char task1_num = 0;
while(1)
{
if(task1_num == 6 )
{
printf("task1 run %d\r\n",task1_num);
vTaskDelete(Task1Task_Handle);
}
task1_num++;
LED1= ~LED1;
vTaskDelay(1000);
printf("task1 run %d\r\n",task1_num);
}
}
void task2_task( void * pvParameters )
{
char task2_num = 0;
while(1)
{
task2_num++;
LED0 = ~LED0;
vTaskDelay(1000);
printf("task1 run %d\r\n",task2_num);
}
}
版权声明:本文为CSDN博主「林木ovo」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_56380842/article/details/122393436
暂无评论