FreeRTOS学习笔记(2)

3、FreeRTOS系统配置文件

3.1 FreeRTOS系统配置文件详解

FreeRTOSConfig.h配置文件作用:对FreeRTOS进行功能配置和裁剪,以及API函数的使能。

相关宏大致可分为三类:

INCLUDE:配置FreeRTOS中的可选API函数

config:完成FreeRTOS的功能配置和裁剪

其他配置项:PendSV宏定义、SVC宏定义 

代码:

/* 基础配置项 */
#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                            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位无符号数, 无默认需定义 */
#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 */

 钩子函数:即回调函数  

3.2 FreeRTOS的任务创建和删除

任务的创建和删除本质就是调用FreeRTOS的API函数

动态创建任务:任务的任务控制块以及任务的栈空间所需的内存,均由FreeRTOS从FreeRTOS管理的堆中分配。

静态创建任务:任务的控制块以及任务的栈空间所需的内存,需用户分配提供。

动态创建任务函数:

BaseType_t xTaskCreate
( 	TaskFunction_t 				pxTaskCode,		/* 指向任务函数的指针 */					const char * const 				pcName, 		/* 任务名字,最大长度configMAX_TASK_NAME_LEN */
	const 	configSTACK_DEPTH_TYPE 		usStackDepth, 	/* 任务堆栈大小,注意字为单位 */
	void * const 					pvParameters,	/* 传递给任务函数的参数 */
	UBaseType_t 					uxPriority,		/* 任务优先级,范围:0 ~ configMAX_PRIORITIES - 1 */(0~31)
	TaskHandle_t * const 			pxCreatedTask 	/* 任务句柄,就是任务的任务控制块 */
)

返回值:

pdPASS:任务创建成功。

errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY:任务创建失败。

实现动态创建任务流程:

1、将宏configSUPPORT_DYNAMIC_ALLOCATION 配置为 1 

2、定义函数入口参数

3、编写任务函数

此函数创建的任务会立刻进行就绪态,由任务调度器调度运行

内部实现:

1、申请堆栈内存&任务控制块内存-任务控制块可以理解为任务的身份证。

2、TCB结构体成员赋值

3、添加新任务到就绪列表中

静态创建任务函数:

TaskHandle_t xTaskCreateStatic
(
    	TaskFunction_t		pxTaskCode,				/* 指向任务函数的指针 */
    	const char * const		pcName,				/* 任务函数名 */
    	const uint32_t			ulStackDepth, 			/* 任务堆栈大小注意字为单位 */
    	void * const			pvParameters, 			/* 传递的任务函数参数 */
    	UBaseType_t			uxPriority, 				/* 任务优先级 */
    	StackType_t * const		puxStackBuffer, 			/* 任务堆栈,一般为数组,由用户分配 */
    	StaticTask_t * const		pxTaskBuffer				/* 任务控制块指针,由用户分配 */
); 		

返回值:

NULL:任务创建失败

其他值:任务句柄,任务创建成功

静态创建任务使用流程:

1、需将宏configSUPPORT_STATIC_ALLOCATION 配置为 1

2、定义空闲任务&定时器任务的任务堆栈及TCB

3、实现两个接口函数

4、定义函数入口参数

5、编写任务函数

内部实现:

1、TCB结构体成员赋值

2、添加新任务到就绪列表中

任务删除函数:

void vTaskDelete(TaskHandle_t xTaskToDelete);

用于删除已被创建的任务

被删除的任务将从就绪态任务列表、阻塞态任务列表、挂起态任务列表和事件列表中移除

删除任务流程:

1、使用删除任务函数,需将宏INCLUDE_vTaskDelete 配置为 1

2、入口参数输入需要删除的任务句柄(NULL代表删除本身)

内部实现:

1、获取所要删除任务的控制块-通过传入的任务句柄,判断所需要删除哪个任务,NULL代表删除自身

2、将被删除任务,移除所在列表-将该任务在所在列表中移除,包括:就绪、阻塞、挂起、事件等列表

3、判断所需要删除的任务-删除任务自身,需先添加到等待删除列表,内存释放将在空闲任务执行;删除其他任务,释放内存,任务数量--

4、更新下个任务的阻塞时间-更新下一个任务的阻塞超时时间,以防被删除的任务就是下一个阻塞超时的任务

 3.3 编程实战

动态创建代码:

freertos_demo.c:

/**
 ****************************************************************************************************
 * @file        freertos.c
 * @author      正点原子团队(ALIENTEK)
 * @version     V1.4
 * @date        2022-01-04
 * @brief       FreeRTOS 移植实验
 * @license     Copyright (c) 2020-2032, 广州市星翼电子科技有限公司
 ****************************************************************************************************
 * @attention
 *
 * 实验平台:正点原子 精英F103开发板
 * 在线视频:www.yuanzige.com
 * 技术论坛:www.openedv.com
 * 公司网址:www.alientek.com
 * 购买地址:openedv.taobao.com
 *
 ****************************************************************************************************
 */

#include "freertos_demo.h"
#include "./SYSTEM/usart/usart.h"
#include "./BSP/LED/led.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/KEY/key.h"
/*FreeRTOS*********************************************************************************************/
#include "FreeRTOS.h"
#include "task.h"

/******************************************************************************************************/
/*FreeRTOS配置*/

/* START_TASK 任务 配置
 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务
 */
 #define START_TASK_STACK_SIZE 128
 #define START_TASK_PRIORITY   1
 TaskHandle_t  Start_Task_Handler;
 void start_task( void * pvParameters );
 
 /* Task1 任务 配置
 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务
 */
 #define TASK1_STACK_SIZE 128
 #define TASK1_PRIORITY   2
 TaskHandle_t  Task1_Handler;
 void task1( void * pvParameters );
 
 /* Task2 任务 配置
 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务
 */
 #define TASK2_STACK_SIZE 128
 #define TASK2_PRIORITY   3
 TaskHandle_t  Task2_Handler;
 void task2( void * pvParameters );
 
 /* Task3 任务 配置
 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务
 */
 #define TASK3_STACK_SIZE 128
 #define TASK3_PRIORITY   4
 TaskHandle_t  Task3_Handler;
 void task3( void * pvParameters );
/******************************************************************************************************/
/*
 * @brief       FreeRTOS例程入口函数
 * @param       无
 * @retval      无
 */
void freertos_demo(void)
{
    xTaskCreate(( TaskFunction_t      ) start_task,
               (char *                ) "start_task", 
               (configSTACK_DEPTH_TYPE) START_TASK_STACK_SIZE,
               (void *                ) NULL,
               (UBaseType_t           ) START_TASK_PRIORITY,
               (TaskHandle_t *        ) &Start_Task_Handler );
    vTaskStartScheduler();//开启任务调度器
}

 void start_task( void * pvParameters )
{
    taskENTER_CRITICAL();           /* 进入临界区 */
    /*创建任务1*/
    xTaskCreate(( TaskFunction_t       ) task1,
               (char *                ) "task1", 
               (configSTACK_DEPTH_TYPE) TASK1_STACK_SIZE,
               (void *                ) NULL,
               ( UBaseType_t          ) TASK1_PRIORITY,
               (TaskHandle_t *        ) &Task1_Handler );
    
    /*创建任务2*/
    xTaskCreate(( TaskFunction_t       ) task2,
               (char *                ) "task2", 
               (configSTACK_DEPTH_TYPE) TASK2_STACK_SIZE,
               (void *                ) NULL,
               ( UBaseType_t          ) TASK2_PRIORITY,
               (TaskHandle_t *        ) &Task2_Handler );
               
    /*创建任务3*/
    xTaskCreate(( TaskFunction_t       ) task3,
               (char *                ) "task3", 
               (configSTACK_DEPTH_TYPE) TASK3_STACK_SIZE,
               (void *                ) NULL,
               ( UBaseType_t          ) TASK3_PRIORITY,
               (TaskHandle_t *        ) &Task3_Handler );
    vTaskDelete(NULL);//删除开始任务
    taskEXIT_CRITICAL();            /* 退出临界区 */
}


/*任务一,实现LED0每500ms翻转一次*/
void task1( void * pvParameters )
{
    while(1)
    {
        printf("task1正在运行!!!\r\n");
        LED0_TOGGLE();
        vTaskDelay(500);
    }
}


/*任务二,实现LED1每500ms翻转一次*/
void task2( void * pvParameters )
{
   while(1)
    {
        printf("task2正在运行!!!\r\n");
        LED1_TOGGLE();
        vTaskDelay(500);
    }
}


/*任务三,判断按键KEY0,按下KEY0删除task1*/
void task3( void * pvParameters )
{
    uint8_t Key = 0;
   while(1)
    {
        printf("task3正在运行!!!\r\n");
        Key = key_scan(0);
        if(Key == KEY0_PRES)
        {
            if(Task1_Handler != NULL)
            {
                printf("删除task1任务!!!\r\n");
                vTaskDelete(Task1_Handler);//删除task1
                Task1_Handler = NULL;
            }
        }
        vTaskDelay(10);
    }
}
 
 

注意:如果不进入临界区,当程序运行时,将按照task1、task2、task3的顺序执行,因为尽管task3的优先级最高,但是当执行freertos_demo函数时,首先将创建3个task,而在创建第一个task时,由于其优先级高于start_task,当进入阻塞态时,将优先执行task1,task2同理,所以将会先进行一次执行task1->task2->task3的顺序执行。而当进入临界区后,就会在任务都创建完成后再按照优先级执行任务,就避免了上述情况的发生。

3.4 静态创建任务

相对于动态创建任务,静态创建任务更为繁琐, 需要自己分配内存空间,主要区别就在于(StackType_t *   )

 (StaticTask_t *  )

这两个参数的配置,代码如下:

/**
 ****************************************************************************************************
 * @file        freertos.c
 * @author      正点原子团队(ALIENTEK)
 * @version     V1.4
 * @date        2022-01-04
 * @brief       FreeRTOS 移植实验
 * @license     Copyright (c) 2020-2032, 广州市星翼电子科技有限公司
 ****************************************************************************************************
 * @attention
 *
 * 实验平台:正点原子 精英F103开发板
 * 在线视频:www.yuanzige.com
 * 技术论坛:www.openedv.com
 * 公司网址:www.alientek.com
 * 购买地址:openedv.taobao.com
 *
 ****************************************************************************************************
 */

#include "freertos_demo.h"
#include "./SYSTEM/usart/usart.h"
#include "./BSP/LED/led.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/KEY/key.h"
/*FreeRTOS*********************************************************************************************/
#include "FreeRTOS.h"
#include "task.h"

/******************************************************************************************************/
/*FreeRTOS配置*/

/* START_TASK 任务 配置
 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务
 */
 #define START_TASK_STACK_SIZE 128
 #define START_TASK_PRIORITY   1
 TaskHandle_t  Start_Task_Handler;
 StackType_t Start_Task_Stack[START_TASK_STACK_SIZE];
 StaticTask_t Start_Task_TCB;
 void start_task( void * pvParameters );
 
 /* Task1 任务 配置
 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务
 */
 #define TASK1_STACK_SIZE 128
 #define TASK1_PRIORITY   2
 TaskHandle_t  Task1_Handler;
 StackType_t   Task1_Stack[TASK1_STACK_SIZE];
 StaticTask_t  Task1_TCB;
 void task1( void * pvParameters );
 
 /* Task2 任务 配置
 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务
 */
 #define TASK2_STACK_SIZE 128
 #define TASK2_PRIORITY   3
 TaskHandle_t  Task2_Handler;
 StackType_t   Task2_Stack[TASK2_STACK_SIZE];
 StaticTask_t  Task2_TCB;
 void task2( void * pvParameters );
 
 /* Task3 任务 配置
 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务
 */
 #define TASK3_STACK_SIZE 128
 #define TASK3_PRIORITY   4
 TaskHandle_t  Task3_Handler;
 StackType_t   Task3_Stack[TASK3_STACK_SIZE];
 StaticTask_t  Task3_TCB;
 void task3( void * pvParameters );
/******************************************************************************************************/

/*空闲任务配置*/
StaticTask_t Idle_Task_TCB;
StackType_t Idle_Task_Stack[configMINIMAL_STACK_SIZE];

/*软件定时器任务配置*/
StaticTask_t Timer_Task_TCB;
StackType_t Timer_Task_Stack[configTIMER_TASK_STACK_DEPTH];

/*空闲任务内存分配*/
void vApplicationGetIdleTaskMemory( StaticTask_t ** ppxIdleTaskTCBBuffer,
                                    StackType_t ** ppxIdleTaskStackBuffer,
                                    uint32_t * pulIdleTaskStackSize ) 
{
    * ppxIdleTaskTCBBuffer = &Idle_Task_TCB;
    * ppxIdleTaskStackBuffer = Idle_Task_Stack;
    * pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;
}

/*软件定时器内存分配*/
void vApplicationGetTimerTaskMemory( StaticTask_t ** ppxTimerTaskTCBBuffer,
                                     StackType_t ** ppxTimerTaskStackBuffer,
                                     uint32_t * pulTimerTaskStackSize )
{
    * ppxTimerTaskTCBBuffer = &Timer_Task_TCB;
    * ppxTimerTaskStackBuffer = Timer_Task_Stack;
    * pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH;
}
/*
 * @brief       FreeRTOS例程入口函数
 * @param       无
 * @retval      无
 */
void freertos_demo(void)
{
   Start_Task_Handler = xTaskCreateStatic(( TaskFunction_t  ) start_task,
                                          (char *          ) "start_task", 
                                          (uint32_t        ) START_TASK_STACK_SIZE,
                                          (void *          ) NULL,
                                          (UBaseType_t     ) START_TASK_PRIORITY,
                                          (StackType_t *   ) Start_Task_Stack,
                                          (StaticTask_t *  ) &Start_Task_TCB );
    vTaskStartScheduler();//开启任务调度器
}

 void start_task( void * pvParameters )
{
    taskENTER_CRITICAL();           /* 进入临界区 */
    
    /*创建Task1*/
    Task1_Handler = xTaskCreateStatic(( TaskFunction_t  ) task1,
                                      (char *          ) "task1", 
                                      (uint32_t        ) TASK1_STACK_SIZE,
                                      (void *          ) NULL,
                                      (UBaseType_t     ) TASK1_PRIORITY,
                                      (StackType_t *   ) Task1_Stack,
                                      (StaticTask_t *  ) &Task1_TCB );
                       
    /*创建Task2*/
    Task2_Handler = xTaskCreateStatic(( TaskFunction_t  ) task2,
                                      (char *          ) "task2", 
                                      (uint32_t        ) TASK2_STACK_SIZE,
                                      (void *          ) NULL,
                                      (UBaseType_t     ) TASK2_PRIORITY,
                                      (StackType_t *   ) Task2_Stack,
                                      (StaticTask_t *  ) &Task2_TCB );
                       
    /*创建Task3*/
    Task3_Handler = xTaskCreateStatic(( TaskFunction_t  ) task3,
                                      (char *          ) "task3", 
                                      (uint32_t        ) TASK3_STACK_SIZE,
                                      (void *          ) NULL,
                                      (UBaseType_t     ) TASK3_PRIORITY,
                                      (StackType_t *   ) Task3_Stack,
                                      (StaticTask_t *  ) &Task3_TCB );
    vTaskDelete(Start_Task_Handler);//删除开始任务
    taskEXIT_CRITICAL();            /* 退出临界区 */
}


/*任务一,实现LED0每500ms翻转一次*/
void task1( void * pvParameters )
{
    while(1)
    {
        printf("task1正在运行!!!\r\n");
        LED0_TOGGLE();
        vTaskDelay(500);
    }
}


/*任务二,实现LED1每500ms翻转一次*/
void task2( void * pvParameters )
{
   while(1)
    {
        printf("task2正在运行!!!\r\n");
        LED1_TOGGLE();
        vTaskDelay(500);
    }
}


/*任务三,判断按键KEY0,按下KEY0删除task1*/
void task3( void * pvParameters )
{
    uint8_t Key = 0;
   while(1)
    {
        printf("task3正在运行!!!\r\n");
        Key = key_scan(0);
        if(Key == KEY0_PRES)
        {
            if(Task1_Handler != NULL)
            {
                printf("删除task1任务!!!\r\n");
                vTaskDelete(Task1_Handler);//删除task1
                Task1_Handler = NULL;
            }
        }
        vTaskDelay(10);
    }
}
 
 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值