了解FreeRTOS
任务相关API
FreeRTOS任务创建API
FreeRTOS 中,任务的创建有两种方法,一种是使用动态创建,一种是使用静态创建。动态创建时,任务控制块和栈的内存是创建任务时动态分配的,任务删除时,内存可以释放。静态创建时,任务控制块和栈的内存需要事先定义好,是静态的内存 ,任务删除时 ,内存不能释放 。
动态创建API:xTaskCreate()
BaseType_t xTaskCreate(
TaskFunction_t pxTaskCode,
const char * const pcName,
const uint16_t usStackDepth,
void * const pvParameters,
UBaseType_t uxPriority,
TaskHandle t* const pxCreatedTask
)
返回值:
pdPASS:任务创建成功
errCIOULD_NOT_ALLOCATE_REQUIRED_MEMORY:任务创建失败,因为内存不足
静态创建API:xTaskCreateStatic()
TaskHandle xTaskCreateStatic(
TaskFunction_t pxTaskCode,
const char * const pcName,
const uint16_t usStackDepth,
void * const pvParameters,
UBaseType_t uxPriority,
StaticType_t *const puStackBuffer,
StaticTask_t *const pxTaskBuffer)
返回值:
NULL:任务创建失败
其他:任务创建成功,返回任务句柄
删除任务API
vTaskDelete():删除一个任务。
vTaskDelete(TaskHandle_t xTaskToDelete)
参数:
xTaskToDelete:要删除的任务的句柄
任务挂起和恢复API
任务挂起:vTaskToSuspend
此函数用于将某个任务设置为挂起态, 进入挂起态的任务永远都不会进入运行态。退出挂
起态的唯一方法就是调用任务恢复函数 vTaskResume()或 xTaskResumeFromISR()。
void vTaskToSuspend(TaskHandle_t xTaskSuspend)
参数:
任务恢复
vTaskResume():恢复一个任务的运行。
将一个任务从挂起态恢复到就绪态, 只有通过函数 vTaskSuspend()设置为挂起态的任务才可以使用 vTaskRexume()恢复!
void vTaskResume(TaskHandleToResume)
xTaskResumeFromISR():中断服务函数中恢复一个任务的运行
此函数是 vTaskResume()的中断版本,用于在中断服务函数中恢复一个任务后
BaseType_t xTaskResumeFromISR(Task_Handle_t xTaskToResume)
参数:
xTaskToResume:要恢复的任务句柄
任务创建参考代码
对开始任务进入临界态再创建任务存在疑问
#include "sys.h"
#include "usart.h"
#include "gpio.h"
#include "delay.h"
#include "FreeRTOS.h"
#include "task.h"
//LCD刷屏时使用的颜色
//任务优先级
#define START_TASK_PRIO 4
//任务堆栈大小
#define START_STK_SIZE 128
//任务句柄
TaskHandle_t StartTask_Handler;
//任务函数
void start_task(void *pvParameters);
//任务优先级
#define LED0_TASK_PRIO 0
//任务堆栈大小
#define LED0_STK_SIZE 20
//任务句柄
TaskHandle_t LED0Task_Handler;
//任务函数
void led0_task(void *pvParameters);
//任务优先级
#define LED1_TASK_PRIO 0
//任务堆栈大小
#define LED1_STK_SIZE 20
//任务句柄
TaskHandle_t LED1Task_Handler;
//任务函数
void led1_task(void *pvParameters);
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4
delay_init(); //延时函数初始化
My_USART_Init(); //初始化串口
MX_GPIO_Init(); //初始化GPIO
//创建开始任务
xTaskCreate((TaskFunction_t )start_task, //任务函数
(const char* )"start_task", //任务名称
(uint16_t )START_STK_SIZE, //任务堆栈大小
(void* )NULL, //传递给任务函数的参数
(UBaseType_t )START_TASK_PRIO, //任务优先级
(TaskHandle_t* )&StartTask_Handler); //任务句柄
vTaskStartScheduler(); //开启任务调度
}
//开始任务任务函数
void start_task(void *pvParameters)
{
taskENTER_CRITICAL(); //进入临界区
//创建LED0任务
xTaskCreate((TaskFunction_t )led0_task,
(const char* )"led0_task",
(uint16_t )LED0_STK_SIZE,
(void* )NULL,
(UBaseType_t )LED0_TASK_PRIO,
(TaskHandle_t* )&LED0Task_Handler);
//创建LED1任务
xTaskCreate((TaskFunction_t )led1_task,
(const char* )"led1_task",
(uint16_t )LED1_STK_SIZE,
(void* )NULL,
(UBaseType_t )LED1_TASK_PRIO,
(TaskHandle_t* )&LED1Task_Handler);
vTaskDelete(StartTask_Handler); //删除开始任务
taskEXIT_CRITICAL(); //退出临界区
}
//LED0任务函数
void led0_task(void *pvParameters)
{
while(1)
{
LED0 = !LED0;
vTaskDelay(500);
}
}
/* jwiw */
//LED1任务函数
void led1_task(void *pvParameters)
{
uint16_t flag=0;
while(1)
{
if(flag==0)
{
flag=1;vTaskDelay(200);
}
else flag=0;
GPIO_ResetBits(GPIOE,GPIO_Pin_5);
vTaskDelay(200);
GPIO_SetBits(GPIOE,GPIO_Pin_5);
vTaskDelay(800);
}
}
队列相关API
了解队列
队列是为了任务与任务、任务与中断之间的通信而准备的,可以在任务与任务、任务与中断之间传递消息,队列中可以存储有限的、大小固定的数据项目。任务与任务、任务与中断之间要交流的数据保存在队列中,叫做队列项目。队列所能保存的最大数据项目数量叫做队列的长度,创建队列的时候会指定数据项目的大小和队列的长度。 由于队列用来传递消息的,所以也称为消息队列。 FreeRTOS 中的信号量的也是依据队列实现的! 所以有必要深入的了解FreeRTOS 的队列。
特点:先进先出,固定大小/长度
读取队列的两种方式
如果读取时队列 Q 是空
不阻塞:阻塞时间决定的,这个阻塞时间单位是时钟节拍数。 阻塞时间为 0 的话就是不阻塞,没有数据的话就马上返回任务继续执行接下来的代码。
阻塞:如果阻塞时间为 0~ portMAX_DELAY, 当任务没有从队列中获取到消息的话就进入阻塞态,阻塞时间指定了任务进入阻塞态的时间,当阻塞时间到了以后还没有接收到数据的话就退出阻塞态,返回任务接着运行下面的代码,如果在阻塞时间内接收到了数据就立即返回,执行任务中下面的代码