FreeRTOS学习

1、动态创建任务

#include "main.h"
#include "driver_led.h"
#include "driver_key.h"
void FreeRTOS_Start(void);
int main(void)
{
    // 初始化HAL库函数必须要调用此函数
    HAL_Init();
    // 系统时钟即AHB/APB时钟配置
    SystemClock_Config();

    // 初始化LED
    LedGpioInit();
    KeyInit();
    FreeRTOS_Start();
}
TaskHandle_t start_task_handle;
TaskHandle_t task1_handle;
TaskHandle_t task2_handle;
TaskHandle_t task3_handle;

void StartTask(void);
void Task1(void);
void Task2(void);
void Task3(void);
void FreeRTOS_Start(void)
{
    xTaskCreate(
        (TaskFunction_t)    StartTask,              //任务函数的地址          
        (char *)            "StartTask",            //任务函数的名称
        (uint16_t)          128,                    //任务函数栈空间大小
        (void *)            NULL,                   //任务函数的参数
        (UBaseType_t)       1,                      //任务函数的优先级
        (TaskHandle_t*)     &start_task_handle      //任务函数的句柄
    );

    //启动调度器
    vTaskStartScheduler();

}

void StartTask(void)
{
    taskENTER_CRITICAL();
    xTaskCreate(
        (TaskFunction_t)    Task1,
        (char *)            "Task1",
        (uint16_t)          128,
        (void *)            NULL,
        (UBaseType_t)       2,
        (TaskHandle_t*)     &task1_handle
    );
    xTaskCreate(
        (TaskFunction_t)    Task2,
        (char *)            "Task2",
        (uint16_t)          128,
        (void *)            NULL,
        (UBaseType_t)       3,
        (TaskHandle_t*)     &task2_handle
    );
    xTaskCreate(
        (TaskFunction_t)    Task3,
        (char *)            "Task3",
        (uint16_t)          128,
        (void *)            NULL,
        (UBaseType_t)       4,
        (TaskHandle_t*)     &task3_handle
    );
    vTaskDelete(NULL);
    taskEXIT_CRITICAL();
}

void Task1(void)
{
    while(1)
    {
        LED_TOGGLE(LED0_GPIO_PORT,LED0_GPIO_PIN);
        vTaskDelay(500);
    }
}
void Task2(void)
{
    while(1)
    {
        LED_TOGGLE(LED1_GPIO_PORT,LED1_GPIO_PIN);
        vTaskDelay(500);
    }
}
void Task3(void)
{
    while(1)
    {
        if(KeyScan() == 0)
        {
            if(task1_handle != NULL) vTaskDelete(task1_handle);
            task1_handle = NULL;
        }
    vTaskDelay(500);
    }
}

2、静态创建任务

#include "main.h"
#include "driver_led.h"
#include "driver_key.h"

/* 启动任务的配置 */
#define START_TASK_STACK 128
#define START_TASK_PRIORITY 1
TaskHandle_t start_task_handle;
StackType_t start_task_stack[START_TASK_STACK]; // 静态任务的任务栈,以数组形式存储
StaticTask_t start_task_tcb;                    // 静态任务的TCB结构体类型
void start_task(void);

/* 任务1的配置 */
#define TASK1_STACK 128
#define TASK1_PRIORITY 2
TaskHandle_t task1_handle;
StackType_t task1_stack[TASK1_STACK]; // 静态任务的任务栈,以数组形式存储
StaticTask_t task1_tcb;               // 静态任务的TCB结构体类型
void task1(void);

/* 任务2的配置 */
#define TASK2_STACK 128
#define TASK2_PRIORITY 3
TaskHandle_t task2_handle;
StackType_t task2_stack[TASK2_STACK]; // 静态任务的任务栈,以数组形式存储
StaticTask_t task2_tcb;               // 静态任务的TCB结构体类型
void task2(void);

/* 任务3的配置 */
#define TASK3_STACK 128
#define TASK3_PRIORITY 4
TaskHandle_t task3_handle;
StackType_t task3_stack[TASK3_STACK]; // 静态任务的任务栈,以数组形式存储
StaticTask_t task3_tcb;               // 静态任务的TCB结构体类型
void task3(void);

/* ======================= 静态创建方式,需要手动指定2个特殊任务的资源=============================== */
/* 空闲任务的配置 */
StackType_t idle_task_stack[configMINIMAL_STACK_SIZE]; // 静态任务的任务栈,以数组形式存储
StaticTask_t idle_task_tcb;                            // 静态任务的TCB结构体类型

/* 软件定时器任务的配置 */
StackType_t timer_task_stack[configTIMER_TASK_STACK_DEPTH]; // 静态任务的任务栈,以数组形式存储
StaticTask_t timer_task_tcb;                            // 静态任务的TCB结构体类型

/* 分配空闲任务的资源 */
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;
}

/**
 * @description: 启动FreeRTOS
 * @return {*}
 */
void FreeRTOS_Start(void)
{
    /* 1.创建一个启动任务 */
    start_task_handle = xTaskCreateStatic(
        (TaskFunction_t)start_task,       // 任务函数的地址
        (char *)"start_task",             // 任务名字符串
        (uint32_t)START_TASK_STACK,       // 任务栈大小,默认最小128,单位4字节
        (void *)NULL,                     // 传递给任务的参数
        (UBaseType_t)START_TASK_PRIORITY, // 任务的优先级
        (StackType_t *)start_task_stack,  // 我们创建的任务栈(数组存储)的地址
        (StaticTask_t *)&start_task_tcb   // 我们创建的tcb的地址
    );

    /* 2.启动调度器:会自动创建空闲任务和软件定时器(如果开启),
       静态创建的方式需要去实现2个分配资源的接口函数 */
    vTaskStartScheduler();
}

int main(void)
{
    // 初始化HAL库函数必须要调用此函数
    HAL_Init();
    // 系统时钟即AHB/APB时钟配置
    SystemClock_Config();

    // 初始化LED
    LedGpioInit();
    KeyInit();
    FreeRTOS_Start();
}

/**
 * @description: 启动任务:用来创建其他Task
 * @param {void} *pvParameters
 * @return {*}
 */
void start_task(void)
{
    /* 进入临界区:保护临界区里的代码不会被打断 */
    taskENTER_CRITICAL();

    /* 使用静态创建3个任务 */
    task1_handle = xTaskCreateStatic(
        (TaskFunction_t)task1,
        (char *)"task1",
        (configSTACK_DEPTH_TYPE)TASK1_STACK,
        (void *)NULL,
        (UBaseType_t)TASK1_PRIORITY,
        (StackType_t *)task1_stack, // 我们创建的任务栈(数组存储)的地址
        (StaticTask_t *)&task1_tcb  // 我们创建的tcb的地址
    );

    task2_handle = xTaskCreateStatic(
        (TaskFunction_t)task2,
        (char *)"task2",
        (configSTACK_DEPTH_TYPE)TASK2_STACK,
        (void *)NULL,
        (UBaseType_t)TASK2_PRIORITY,
        (StackType_t *)task2_stack, // 我们创建的任务栈(数组存储)的地址
        (StaticTask_t *)&task2_tcb  // 我们创建的tcb的地址
    );

    task3_handle = xTaskCreateStatic(
        (TaskFunction_t)task3,
        (char *)"task3",
        (configSTACK_DEPTH_TYPE)TASK3_STACK,
        (void *)NULL,
        (UBaseType_t)TASK3_PRIORITY,
        (StackType_t *)task3_stack, // 我们创建的任务栈(数组存储)的地址
        (StaticTask_t *)&task3_tcb  // 我们创建的tcb的地址
    );

    /* 启动任务只需要执行一次即可,用完就删除自己 */
    vTaskDelete(NULL);

    /* 退出临界区 */
    taskEXIT_CRITICAL();
}

void task1(void)
{
    while(1)
    {
        LED_TOGGLE(LED0_GPIO_PORT,LED0_GPIO_PIN);
        vTaskDelay(500);
    }
}
void task2(void)
{
    while(1)
    {
        LED_TOGGLE(LED1_GPIO_PORT,LED1_GPIO_PIN);
        vTaskDelay(500);
    }
}
void task3(void)
{
    while(1)
    {
        if(KeyScan() == 0)
        {
            if(task1_handle != NULL) vTaskDelete(task1_handle);
            task1_handle = NULL;
        }
    vTaskDelay(500);
    }
}

3、任务挂起与回复

3.1、任务挂起

/*传入参数为任务句柄,若传入NULL,则代表挂起当前任务*/
vTaskSuspend(task1_handle);

3.2 任务恢复

/* 任务恢复,传入参数为任务句柄*/
vTaskResume(task1_handle);

3.3 挂起任务调度器

仅执行当前任务

vTaskSuspendAll();

3.4 恢复任务调度器

xTaskResumeAll();

3.5 打印任务状态

/* 传入参数为字符串 */
vTaskList(str);

3.6 中断管理

/*执行此函数后,在中断优先级阈值以下的中断将被屏蔽*/
portDISABLE_INTERRUPTS();

/* 使能中断 */
portENABLE_INTERRUPTS();

5、时间函数

/* 相对延时,每隔n个时间片执行一次代码,不能保证代码执行时间相同 */
vtaskDelay(n);
/* 绝对延时,代码整体执行时间为n个时间片,保证代码执行周期*/
xTaskDelayUntil();

6、任务之间通过队列传输数据

#include "main.h"
#include "driver_led.h"
#include "driver_key.h"
#include "driver_uart.h"

void StartTask(void);
void Task1(void);
void Task2(void);
void FreeRTOS_Start(void);


int main(void)
{
    // 初始化HAL库函数必须要调用此函数
    HAL_Init();
    // 系统时钟即AHB/APB时钟配置
    SystemClock_Config();

    // 初始化LED
    LedInit();
    KeyInit();
    UartInit(115200);
    FreeRTOS_Start();

    while(1)
    {
        HAL_Delay(1000);
        UartSendData("hello\r\n");
        LED_TOGGLE(LED0_GPIO_PORT,LED0_GPIO_PIN);
    }
}
/* 任务句柄,用以保存不同任务的配置 */
TaskHandle_t start_task_handle;
TaskHandle_t task1_handle;
TaskHandle_t task2_handle;

/*
 * 函数作用:常规写法,起始任务,用以创建其他任务
 * 输入参数:无
 * 返回值:无
 * 作者:LSK
*/
void FreeRTOS_Start(void)
{
    xTaskCreate(
        (TaskFunction_t)    StartTask,              //任务函数的地址          
        (char *)            "StartTask",            //任务函数的名称
        (uint16_t)          128,                    //任务函数栈空间大小
        (void *)            NULL,                   //任务函数的参数
        (UBaseType_t)       1,                      //任务函数的优先级
        (TaskHandle_t*)     &start_task_handle      //任务函数的句柄
    );

    /* 启用调度器,负责任务切换*/
    vTaskStartScheduler();

}

/* 队列句柄*/
QueueHandle_t handle1;

void StartTask(void)
{
    /* 创建一个队列 */
    handle1 = xQueueCreate(1,sizeof(char *));
    if(handle1 == NULL) UartSendData("task err");

    /* 进入临界保护区,保证在临界区的代码不会被打断*/
    taskENTER_CRITICAL();
    xTaskCreate(
        (TaskFunction_t)    Task1,
        (char *)            "Task1",
        (uint16_t)          128,
        (void *)            NULL,
        (UBaseType_t)       2,
        (TaskHandle_t*)     &task1_handle
    );
    xTaskCreate(
        (TaskFunction_t)    Task2,
        (char *)            "Task2",
        (uint16_t)          128,
        (void *)            NULL,
        (UBaseType_t)       4,
        (TaskHandle_t*)     &task2_handle
    );
    vTaskDelete(NULL);  //删除任务本身
    /* 退出临界保护区*/
    taskEXIT_CRITICAL();
}
/*
 * 函数作用:负责创建一个字符串,通过队列发送出去
 * 输入参数:无
 * 返回值:无
 * 作者:LSK
*/
void Task1(void)
{
    char* str = "tehsjncncncncc";
    while(1)
    {
        if(KeyScan() == KEY0)
        {
            /* 往队列插入一个值,并设置阻塞等待*/
            xQueueSend(handle1,&str,portMAX_DELAY);
            UartSendData("Send Pass\r\n");
        }
        vTaskDelay(20);
    }
}

/*
 * 函数作用:接收数据任务
 * 输入参数:无
 * 返回值:无
 * 作者:LSK
*/
void Task2(void)
{
    char *buffer;
    BaseType_t res;
    while(1)
    {
        /* 接收队列的任务,并进入阻塞等待*/
        res = xQueueReceive(handle1,&buffer,portMAX_DELAY);
        if(res == pdPASS) 
        {
            UartSendData("buffer:\r\n");
            UartSendData(buffer);
            UartSendData("\r\n");
        }
        vTaskDelay(500);
    }
}

7、二进制信号量释放与接收

7.1 二进制信号量

#include "main.h"

void StartTask(void);
void Task1(void);
void Task2(void);
void FreeRTOS_Start(void);

int main(void)
{
    // 初始化HAL库函数必须要调用此函数
    HAL_Init();
    // 系统时钟即AHB/APB时钟配置
    SystemClock_Config();

    // 初始化LED
    LedInit();
    KeyInit();
    UartInit(115200);
    FreeRTOS_Start();

    while(1)
    {
        HAL_Delay(1000);
        UartSendData("hello\r\n");
        LED_TOGGLE(LED0_GPIO_PORT,LED0_GPIO_PIN);
    }
}
/* 任务句柄,用以保存不同任务的配置 */
TaskHandle_t start_task_handle;
TaskHandle_t task1_handle;
TaskHandle_t task2_handle;

/*
 * 函数作用:常规写法,起始任务,用以创建其他任务
 * 输入参数:无
 * 返回值:无
 * 作者:LSK
*/
void FreeRTOS_Start(void)
{
    xTaskCreate(
        (TaskFunction_t)    StartTask,              //任务函数的地址          
        (char *)            "StartTask",            //任务函数的名称
        (uint16_t)          128,                    //任务函数栈空间大小
        (void *)            NULL,                   //任务函数的参数
        (UBaseType_t)       1,                      //任务函数的优先级
        (TaskHandle_t*)     &start_task_handle      //任务函数的句柄
    );

    /* 启用调度器,负责任务切换*/
    vTaskStartScheduler();

}

/* 队列句柄*/
QueueHandle_t handle1;
SemaphoreHandle_t semaphore_handle;

void StartTask(void)
{
    /* 创建一个信号量 */
    vSemaphoreCreateBinary(semaphore_handle);
    if(semaphore_handle != NULL) UartSendData("Create success!\r\n");

    /* 创建一个队列 */
    handle1 = xQueueCreate(1,sizeof(char *));
    if(handle1 == NULL) UartSendData("task err");

    /* 进入临界保护区,保证在临界区的代码不会被打断*/
    taskENTER_CRITICAL();
    xTaskCreate(
        (TaskFunction_t)    Task1,
        (char *)            "Task1",
        (uint16_t)          128,
        (void *)            NULL,
        (UBaseType_t)       2,
        (TaskHandle_t*)     &task1_handle
    );
    xTaskCreate(
        (TaskFunction_t)    Task2,
        (char *)            "Task2",
        (uint16_t)          128,
        (void *)            NULL,
        (UBaseType_t)       4,
        (TaskHandle_t*)     &task2_handle
    );
    vTaskDelete(NULL);  //删除任务本身
    /* 退出临界保护区*/
    taskEXIT_CRITICAL();
}
/*
 * 函数作用:释放信号量
 * 输入参数:无
 * 返回值:无
 * 作者:LSK
*/
void Task1(void)
{
    BaseType_t res;   
    while(1)
    {
        if(KeyScan() == KEY0)
        {
            /* 释放信号量 */
            res = xSemaphoreGive(semaphore_handle);
            if (res == pdPASS) UartSendData("Send Pass\r\n");
        }
        vTaskDelay(20);
    }
}

/*
 * 函数作用:接收信号量
 * 输入参数:无
 * 返回值:无
 * 作者:LSK
*/
void Task2(void)
{
    BaseType_t res;
    while(1)
    {
        /* 接收信号量是否释放 */
        res = xSemaphoreTake(semaphore_handle, portMAX_DELAY);
        if(res == pdPASS) 
        {
            UartSendData("Take success!\r\n");
            UartSendData("\r\n");
        }
        vTaskDelay(500);
    }
}

7.2 互斥二进制信号量

它会将阻塞高优先级的低优先级提升,从而保证高优先级不会被低优先级阻塞。

8、计数信号量释放与接收

#include "main.h"

void StartTask(void);
void Task1(void);
void Task2(void);
void FreeRTOS_Start(void);

int main(void)
{
    // 初始化HAL库函数必须要调用此函数
    HAL_Init();
    // 系统时钟即AHB/APB时钟配置
    SystemClock_Config();

    // 初始化LED
    LedInit();
    KeyInit();
    UartInit(115200);
    FreeRTOS_Start();

    while(1)
    {
        HAL_Delay(1000);
        UartSendData("hello\r\n");
        LED_TOGGLE(LED0_GPIO_PORT,LED0_GPIO_PIN);
    }
}
/* 任务句柄,用以保存不同任务的配置 */
TaskHandle_t start_task_handle;
TaskHandle_t task1_handle;
TaskHandle_t task2_handle;

/*
 * 函数作用:常规写法,起始任务,用以创建其他任务
 * 输入参数:无
 * 返回值:无
 * 作者:LSK
*/
void FreeRTOS_Start(void)
{
    xTaskCreate(
        (TaskFunction_t)    StartTask,              //任务函数的地址          
        (char *)            "StartTask",            //任务函数的名称
        (uint16_t)          128,                    //任务函数栈空间大小
        (void *)            NULL,                   //任务函数的参数
        (UBaseType_t)       1,                      //任务函数的优先级
        (TaskHandle_t*)     &start_task_handle      //任务函数的句柄
    );

    /* 启用调度器,负责任务切换*/
    vTaskStartScheduler();

}

char str[100];
/* 队列句柄*/
QueueHandle_t handle1;

void StartTask(void)
{
    UBaseType_t Count = 0;
    /* 创建一个信号量 */
    handle1 = xSemaphoreCreateCounting(100, 0);
    if(!(handle1 == NULL))
    {
        UartSendData("Create success!\r\n");
        Count = uxSemaphoreGetCount(handle1);
        sprintf(str, "the init count: %d", Count);
        UartSendData(str);
    } 

    /* 进入临界保护区,保证在临界区的代码不会被打断*/
    taskENTER_CRITICAL();
    xTaskCreate(
        (TaskFunction_t)    Task1,
        (char *)            "Task1",
        (uint16_t)          128,
        (void *)            NULL,
        (UBaseType_t)       3,
        (TaskHandle_t*)     &task1_handle
    );
    xTaskCreate(
        (TaskFunction_t)    Task2,
        (char *)            "Task2",
        (uint16_t)          128,
        (void *)            NULL,
        (UBaseType_t)       4,
        (TaskHandle_t*)     &task2_handle
    );
    vTaskDelete(NULL);  //删除任务本身
    /* 退出临界保护区*/
    taskEXIT_CRITICAL();
}

/*
 * 函数作用:释放信号量
 * 输入参数:无
 * 返回值:无
 * 作者:LSK
*/
void Task1(void)
{
    BaseType_t res;   
    while(1)
    {
        if(KeyScan() == KEY0)
        {
            /* 释放信号量 */
            res = xSemaphoreGive(handle1);
            if (res == pdPASS) UartSendData("Send Pass\r\n");
        }
        vTaskDelay(20);
    }
}

/*
 * 函数作用:接收信号量
 * 输入参数:无
 * 返回值:无
 * 作者:LSK
*/
void Task2(void)
{
    char str[100];
    UBaseType_t Count = 0;
    BaseType_t res;
    while(1)
    {
        /* 接收信号量是否释放 */
        res = xSemaphoreTake(handle1, portMAX_DELAY);
        if(res == pdPASS) 
        {
           UartSendData("Take success!\r\n");
           UartSendData("\r\n");
           UartSendData(str);
        }
        Count = uxSemaphoreGetCount(handle1);
        sprintf(str, "the init count: %d\r\n", Count);
        UartSendData(str);
        vTaskDelay(1000);
    }
}

9、队列集

10、事件标志组

比信号量更灵活,每一个bit位都代表一个信号量。

#include "main.h"

void StartTask(void);
void Task1(void);
void Task2(void);
void FreeRTOS_Start(void);

int main(void)
{
    // 初始化HAL库函数必须要调用此函数
    HAL_Init();
    // 系统时钟即AHB/APB时钟配置
    SystemClock_Config();

    // 初始化LED
    LedInit();
    KeyInit();
    UartInit(115200);
    FreeRTOS_Start();

    while(1)
    {
        HAL_Delay(1000);
        UartSendData("hello\r\n");
        LED_TOGGLE(LED0_GPIO_PORT,LED0_GPIO_PIN);
    }
}

/* 任务句柄,用以保存不同任务的配置 */
TaskHandle_t start_task_handle;
TaskHandle_t task1_handle;
TaskHandle_t task2_handle;

/*
 * 函数作用:常规写法,起始任务,用以创建其他任务
 * 输入参数:无
 * 返回值:无
 * 作者:LSK
*/
void FreeRTOS_Start(void)
{
    xTaskCreate(
        (TaskFunction_t)    StartTask,              //任务函数的地址          
        (char *)            "StartTask",            //任务函数的名称
        (uint16_t)          128,                    //任务函数栈空间大小
        (void *)            NULL,                   //任务函数的参数
        (UBaseType_t)       1,                      //任务函数的优先级
        (TaskHandle_t*)     &start_task_handle      //任务函数的句柄
    );

    /* 启用调度器,负责任务切换*/
    vTaskStartScheduler();

}

char str[100];
EventGroupHandle_t event_handle;

void StartTask(void)
{
    UBaseType_t Count = 0;
    /* 创建一个信号量 */
    event_handle = xEventGroupCreate();
    if(!(event_handle == NULL))
    {
        UartSendData("Create success!\r\n");
    } 
    /* 进入临界保护区,保证在临界区的代码不会被打断*/
    taskENTER_CRITICAL();
    xTaskCreate(
        (TaskFunction_t)    Task1,
        (char *)            "Task1",
        (uint16_t)          128,
        (void *)            NULL,
        (UBaseType_t)       3,
        (TaskHandle_t*)     &task1_handle
    );
    xTaskCreate(
        (TaskFunction_t)    Task2,
        (char *)            "Task2",
        (uint16_t)          128,
        (void *)            NULL,
        (UBaseType_t)       4,
        (TaskHandle_t*)     &task2_handle
    );
    vTaskDelete(NULL);  //删除任务本身
    /* 退出临界保护区*/
    taskEXIT_CRITICAL();
}

/*
 * 函数作用:发送事件
 * 输入参数:无
 * 返回值:无
 * 作者:LSK
*/
#define EVENTBIT_0 (1 << 0)
#define EVENTBIT_1 (1 << 1)

void Task1(void)
{
    EventBits_t res;   
    while(1)
    {

        xEventGroupSetBits(event_handle, 1<<3);
        if(KeyScan() == KEY0)
        {
            /* 设置标志位*/
            res = xEventGroupSetBits(event_handle, EVENTBIT_0);
            sprintf(str,"event flag: %#x\r\n", res);
            UartSendData(str);
            res = xEventGroupSetBits(event_handle, EVENTBIT_1);
            sprintf(str,"event flag: %#x\r\n", res);
            UartSendData(str);

            UartSendData("KEY0 PRESS!\r\n");
        }
        vTaskDelay(20);
    }
}

/*
 * 函数作用:接收事件
 * 输入参数:无
 * 返回值:无
 * 作者:LSK
*/
void Task2(void)
{
    EventBits_t res;
    while(1)
    {
        /* 接收信号量是否释放 */
        res = xEventGroupWaitBits(
            event_handle,                // 事件句柄
            ((EVENTBIT_0 | EVENTBIT_1)), // 等待的标志位
            pdTRUE,                      // 是否清楚标志位
            pdTRUE,                      // 是否等待标志位
            portMAX_DELAY                // 等待事件
        );
        sprintf(str, "task2: %x\r\n", res);
        UartSendData(str);
    }
}

11 任务通知

11.1 任务通知模拟信号量

#include "main.h"
#include "portmacro.h"
#include "projdefs.h"
#include <stdint.h>


void StartTask(void);
void Task1(void);
void Task2(void);
void FreeRTOS_Start(void);

int main(void)
{
    // 初始化HAL库函数必须要调用此函数
    HAL_Init();
    // 系统时钟即AHB/APB时钟配置
    SystemClock_Config();
    // 初始化LED
    LedInit();
    KeyInit();
    UartInit(115200);
    FreeRTOS_Start();

    while(1)
    {
        HAL_Delay(1000);
        UartSendData("hello\r\n");
        LED_TOGGLE(LED0_GPIO_PORT,LED0_GPIO_PIN);
    }
}

/* 任务句柄,用以保存不同任务的配置 */
TaskHandle_t start_task_handle;
TaskHandle_t task1_handle;
TaskHandle_t task2_handle;

/*
 * 函数作用:常规写法,起始任务,用以创建其他任务
 * 输入参数:无
 * 返回值:无
 * 作者:LSK
*/
void FreeRTOS_Start(void)
{
    xTaskCreate(
        (TaskFunction_t)    StartTask,              //任务函数的地址          
        (char *)            "StartTask",            //任务函数的名称
        (uint16_t)          128,                    //任务函数栈空间大小
        (void *)            NULL,                   //任务函数的参数
        (UBaseType_t)       1,                      //任务函数的优先级
        (TaskHandle_t*)     &start_task_handle      //任务函数的句柄
    );

    /* 启用调度器,负责任务切换*/
    vTaskStartScheduler();

}
char str[100];

void StartTask(void)
{
    /* 进入临界保护区,保证在临界区的代码不会被打断*/
    taskENTER_CRITICAL();
    xTaskCreate(
        (TaskFunction_t)    Task1,
        (char *)            "Task1",
        (uint16_t)          128,
        (void *)            NULL,
        (UBaseType_t)       3,
        (TaskHandle_t*)     &task1_handle
    );
    xTaskCreate(
        (TaskFunction_t)    Task2,
        (char *)            "Task2",
        (uint16_t)          128,
        (void *)            NULL,
        (UBaseType_t)       4,
        (TaskHandle_t*)     &task2_handle
    );
    vTaskDelete(NULL);  //删除任务本身
    /* 退出临界保护区*/
    taskEXIT_CRITICAL();
}

/*
 * 函数作用:任务通知发送
 * 输入参数:无
 * 返回值:无
 * 作者:LSK
*/
void Task1(void)
{
    EventBits_t res;   
    while(1)
    {
        if(KeyScan() == KEY0)
        {
            /* 实际使取出task2的通知值,然后+1*/
            xTaskNotifyGive(task2_handle); 
            UartSendData("KEY0 PRESS!\r\n");
        }
        vTaskDelay(200);
    }
}

/*
 * 函数作用:任务通知接收
 * 输入参数:无
 * 返回值:无
 * 作者:LSK
*/
void Task2(void)
{
    uint32_t res_notify;
    while(1)
    { 
        res_notify = ulTaskNotifyTake(
            pdTRUE,             //接收完通知后,是否对通知值处理,pdTRUE:置0;pdFALSE:-1
            portMAX_DELAY       //设置等待时间
        );
        sprintf(str, "task2 notify: %d\r\n", res_notify);
        UartSendData(str);
    }
}

11.2 任务通知模拟消息队列(邮箱)

#include "main.h"
#include "portmacro.h"
#include "projdefs.h"
#include <stdint.h>


void StartTask(void);
void Task1(void);
void Task2(void);
void FreeRTOS_Start(void);

int main(void)
{
    // 初始化HAL库函数必须要调用此函数
    HAL_Init();
    // 系统时钟即AHB/APB时钟配置
    SystemClock_Config();
    // 初始化LED
    LedInit();
    KeyInit();
    UartInit(115200);
    FreeRTOS_Start();

    while(1)
    {
        HAL_Delay(1000);
        UartSendData("hello\r\n");
        LED_TOGGLE(LED0_GPIO_PORT,LED0_GPIO_PIN);
    }
}

/* 任务句柄,用以保存不同任务的配置 */
TaskHandle_t start_task_handle;
TaskHandle_t task1_handle;
TaskHandle_t task2_handle;

/*
 * 函数作用:常规写法,起始任务,用以创建其他任务
 * 输入参数:无
 * 返回值:无
 * 作者:LSK
*/
void FreeRTOS_Start(void)
{
    xTaskCreate(
        (TaskFunction_t)    StartTask,              //任务函数的地址          
        (char *)            "StartTask",            //任务函数的名称
        (uint16_t)          128,                    //任务函数栈空间大小
        (void *)            NULL,                   //任务函数的参数
        (UBaseType_t)       1,                      //任务函数的优先级
        (TaskHandle_t*)     &start_task_handle      //任务函数的句柄
    );

    /* 启用调度器,负责任务切换*/
    vTaskStartScheduler();

}
char str[100];

void StartTask(void)
{
    /* 进入临界保护区,保证在临界区的代码不会被打断*/
    taskENTER_CRITICAL();
    xTaskCreate(
        (TaskFunction_t)    Task1,
        (char *)            "Task1",
        (uint16_t)          128,
        (void *)            NULL,
        (UBaseType_t)       3,
        (TaskHandle_t*)     &task1_handle
    );
    xTaskCreate(
        (TaskFunction_t)    Task2,
        (char *)            "Task2",
        (uint16_t)          128,
        (void *)            NULL,
        (UBaseType_t)       4,
        (TaskHandle_t*)     &task2_handle
    );
    vTaskDelete(NULL);  //删除任务本身
    /* 退出临界保护区*/
    taskEXIT_CRITICAL();
}

/*
 * 函数作用:模拟消息队列发送
 * 输入参数:无
 * 返回值:无
 * 作者:LSK
*/
void Task1(void)
{
    EventBits_t res;   
    while(1)
    {
        if(KeyScan() == KEY0)
        {
            xTaskNotify(task2_handle,          // 要发送的任务句柄
                        100,                   // 要发送的数据
                        eSetValueWithOverwrite // 发送方式
            );
            UartSendData("KEY0 PRESS!\r\n");
        }
        vTaskDelay(200);
    }
}

/*
 * 函数作用:模拟消息队列接收
 * 输入参数:无
 * 返回值:无
 * 作者:LSK
*/
void Task2(void)
{
    uint32_t res_notify;
    while(1)
    {
      xTaskNotifyWait(
          0x00000000,   // 接收通知前是否清楚通知值,按位,全为0表示不不清楚
          0xffffffff,   // 接收通知后是否要清楚通知值,按位,全为f表示清楚
          &res_notify,  // 接受值存放地址
          portMAX_DELAY // 等待事件
      );
      sprintf(str, "task2 notify: %d\r\n", res_notify);
      UartSendData(str);
    }
}

11.3 模拟事件标志组

#include "main.h"
#include "portmacro.h"
#include "projdefs.h"
#include <stdint.h>


void StartTask(void);
void Task1(void);
void Task2(void);
void FreeRTOS_Start(void);

int main(void)
{
    // 初始化HAL库函数必须要调用此函数
    HAL_Init();
    // 系统时钟即AHB/APB时钟配置
    SystemClock_Config();
    // 初始化LED
    LedInit();
    KeyInit();
    UartInit(115200);
    FreeRTOS_Start();

    while(1)
    {
        HAL_Delay(1000);
        UartSendData("hello\r\n");
        LED_TOGGLE(LED0_GPIO_PORT,LED0_GPIO_PIN);
    }
}

/* 任务句柄,用以保存不同任务的配置 */
TaskHandle_t start_task_handle;
TaskHandle_t task1_handle;
TaskHandle_t task2_handle;

/*
 * 函数作用:常规写法,起始任务,用以创建其他任务
 * 输入参数:无
 * 返回值:无
 * 作者:LSK
*/
void FreeRTOS_Start(void)
{
    xTaskCreate(
        (TaskFunction_t)    StartTask,              //任务函数的地址          
        (char *)            "StartTask",            //任务函数的名称
        (uint16_t)          128,                    //任务函数栈空间大小
        (void *)            NULL,                   //任务函数的参数
        (UBaseType_t)       1,                      //任务函数的优先级
        (TaskHandle_t*)     &start_task_handle      //任务函数的句柄
    );

    /* 启用调度器,负责任务切换*/
    vTaskStartScheduler();

}
char str[100];

void StartTask(void)
{
    /* 进入临界保护区,保证在临界区的代码不会被打断*/
    taskENTER_CRITICAL();
    xTaskCreate(
        (TaskFunction_t)    Task1,
        (char *)            "Task1",
        (uint16_t)          128,
        (void *)            NULL,
        (UBaseType_t)       3,
        (TaskHandle_t*)     &task1_handle
    );
    xTaskCreate(
        (TaskFunction_t)    Task2,
        (char *)            "Task2",
        (uint16_t)          128,
        (void *)            NULL,
        (UBaseType_t)       4,
        (TaskHandle_t*)     &task2_handle
    );
    vTaskDelete(NULL);  //删除任务本身
    /* 退出临界保护区*/
    taskEXIT_CRITICAL();
}

/*
 * 函数作用:模拟事件标志组发送
 * 输入参数:无
 * 返回值:无
 * 作者:LSK
*/
void Task1(void)
{
    EventBits_t res;   
    while(1)
    {
      if (KeyScan() == KEY0) {
        xTaskNotify(task2_handle, // 要发送的任务句柄
                    1 << 8,       // 要发送的数据位
                    eSetBits      // 发送方式
        );
        UartSendData("KEY0 PRESS!\r\n");
      }
        vTaskDelay(200);
    }
}

/*
 * 函数作用:模拟事件标志组接收
 * 输入参数:无
 * 返回值:无
 * 作者:LSK
*/
void Task2(void)
{
    uint32_t res_notify;
    while (1) {
      xTaskNotifyWait(
          0x00000000,   // 接收通知前是否清楚通知值,按位,全为0表示不不清楚
          0xffffffff,   // 接收通知后是否要清楚通知值,按位,全为f表示清楚
          &res_notify,  // 接受值存放地址
          portMAX_DELAY // 等待时间
      );
      sprintf(str, "task2 notify: %0x\r\n", res_notify);
      UartSendData(str);
    }
}

12、软件定时器

#include "main.h"
#include <stdint.h>


void StartTask(void);
void Task1(void);
void FreeRTOS_Start(void);

int main(void)
{
    // 初始化HAL库函数必须要调用此函数
    HAL_Init();
    // 系统时钟即AHB/APB时钟配置
    SystemClock_Config();
    // 初始化LED
    LedInit();
    KeyInit();
    UartInit(115200);
    FreeRTOS_Start();
}

/* 任务句柄,用以保存不同任务的配置 */
TaskHandle_t start_task_handle;
TaskHandle_t task1_handle;


/*
 * 函数作用:常规写法,起始任务,用以创建其他任务
 * 输入参数:无
 * 返回值:无
 * 作者:LSK
*/
void FreeRTOS_Start(void)
{
    xTaskCreate(
        (TaskFunction_t)    StartTask,              //任务函数的地址          
        (char *)            "StartTask",            //任务函数的名称
        (uint16_t)          128,                    //任务函数栈空间大小
        (void *)            NULL,                   //任务函数的参数
        (UBaseType_t)       1,                      //任务函数的优先级
        (TaskHandle_t*)     &start_task_handle      //任务函数的句柄
    );

    /* 启用调度器,负责任务切换*/
    vTaskStartScheduler();

}
char str[100];

void TimerCallBack_1(TimerHandle_t timer);

TimerHandle_t timer_handle_1;

/*
 * 函数作用:开始任务回调函数
 * 输入参数:无
 * 返回值:无
 * 作者:LSK
*/
void StartTask(void)
{
    /* 创建软件定时器,由软件定时器任务(通过定义宏,由系统创建)控制*/
    timer_handle_1 = xTimerCreate("time_1",       // 创建名称
                                  500,            // 定时器延迟时间
                                  pdTRUE,         // 是否重载(周期/一次)
                                  (void *)1,      // 定时器唯一ID
                                  TimerCallBack_1 // 定时器回调函数
    );

    /* 进入临界保护区,保证在临界区的代码不会被打断*/
    taskENTER_CRITICAL();
    xTaskCreate((TaskFunction_t)Task1, (char *)"Task1", (uint16_t)128,
                (void *)NULL, (UBaseType_t)3, (TaskHandle_t *)&task1_handle);

    vTaskDelete(NULL); // 删除任务本身
    /* 退出临界保护区*/
    taskEXIT_CRITICAL();
}

/*
 * 函数作用:开启软件定时器
 * 输入参数:无
 * 返回值:无
 * 作者:LSK
*/
void Task1(void)
{
    EventBits_t res;
    while (1) {
      if (KeyScan() == KEY0) {
        /* 开启软件定时器*/
        xTimerStart(timer_handle_1, // 定时器句柄
                    portMAX_DELAY); // 等待时间
        UartSendData(("timer start!\r\n"));
      }
        vTaskDelay(200);
    }
}

/*
 * 函数作用:定时器回调函数
 * 输入参数:定时器句柄
 * 返回值:无
 * 作者:LSK
*/
void TimerCallBack_1(TimerHandle_t timer)
{
    if(timer == timer_handle_1)
    {
        UartSendData("Call back!\r\n");
        LED_TOGGLE(LED0_GPIO_PORT, LED0_GPIO_PIN);
    }
}
posted @ 2025-11-02 22:27  比特向阳  阅读(5)  评论(0)    收藏  举报