freertos

任务

创建和销毁

#include “FreeRTOS.h”
#include “task.h”

// 创建任务
BaseType_t xTaskCreate( TaskFunction_t pvTaskCode, 
                    const char * const pcName, 
                    unsigned short usStackDepth, 
                    void *pvParameters, 
                    UBaseType_t uxPriority, 
                    TaskHandle_t *pxCreatedTask );
// 删除任务
void vTaskDelete( TaskHandle_t pxTask );


// 创建任务(静态)
TaskHandle_t xTaskCreateStatic( TaskFunction_t pvTaskCode, 
                    const char * const pcName, 
                    uint32_t ulStackDepth, 
                    void *pvParameters, 
                    UBaseType_t uxPriority, 
                    StackType_t * const puxStackBuffer,
                    StaticTask_t * const pxTaskBuffer );


// 启动调度器
vTaskStartScheduler();

睡眠

void vTaskDelay( TickType_t xTicksToDelay );
void vTaskDelayUntil( TickType_t *pxPreviousWakeTime, TickType_t xTimeIncrement );

空闲钩子

void vApplicationIdleHook( void );

示例

任务基础

/**
    demo.h 中已经包含
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "timers.h"
#include "semphr.h"
*/
#include "demo.h"

// debug
static volatile uint32_t g_idle_timer;


static void task_led0(void *param)
{
    TickType_t xLastWakeTime;
    const TickType_t delay_ms = pdMS_TO_TICKS(250);

#if configUSE_IDLE_HOOK == 1
    uint32_t last_idle_timer = 0;
    uint32_t diff_idle_timer = 0;
#endif

    uart_send("task_led0 start!\n", 0);
    while(1)
    {
        LED0_FLIP;
#if configUSE_IDLE_HOOK == 1
        diff_idle_timer = g_idle_timer - last_idle_timer;
        if(last_idle_timer != g_idle_timer)
        {
            last_idle_timer = g_idle_timer;
        }
        uart_send_hex((uint8_t *)&diff_idle_timer, 4);
        uart_send("\n", 0);
#endif

        vTaskDelayUntil(&xLastWakeTime, delay_ms);
    }
}

#if 0
static void task_led1(void *param)
{
    TickType_t xLastWakeTime;
    const TickType_t delay_ms = pdMS_TO_TICKS(500);
    while(1)
    {
        LED1_FLIP;
        vTaskDelayUntil(&xLastWakeTime, delay_ms);
    }
}
#endif

static void task_uart(void *param)
{
    char *string = (char *)param;

    TickType_t xLastWakeTime;
    const TickType_t delay_ms = pdMS_TO_TICKS(1000);

    while(1)
    {
        uart_send((uint8_t *)string, strlen(string));
        vTaskDelayUntil(&xLastWakeTime, delay_ms);

        // 如果采用这种延时的方式,那么高优先级
        // 始终执行,低优先级永远不会执行。
//      for(int i = 0;i < 0x80000; i++)
//      {
//          ;
//      }
    }
}

#if 0
void task_uart2(void *param)
{
    char *string = (char *)param;
    uart_init();

    TickType_t xLastWakeTime;
    const TickType_t delay_ms = pdMS_TO_TICKS(3000);

    while(1)
    {
        uart_send((uint8_t *)string, strlen(string));
        vTaskDelayUntil(&xLastWakeTime, delay_ms);
    }
}
#endif


/**
    task
 */
void demo_01(void)
{
    xTaskCreate(task_led0, "led0", 32, NULL, 1, NULL);
    //xTaskCreate(task_led1,"led1",32,NULL,1,NULL);
    xTaskCreate(task_uart, "uart1", 128, "uart1 is running!\n", 2, NULL);
    //xTaskCreate(task_uart,"uart2",128,"uart2 is running!\n",2,NULL);

    vTaskStartScheduler();

    while(1)
    {
        ;
    }
}

void vApplicationIdleHook(void)
{
    // idle hook
    g_idle_timer ++;
}

队列

创建和销毁

// 创建队列
QueueHandle_t xQueueCreate( UBaseType_t uxQueueLength, 
                    UBaseType_t uxItemSize );
// 删除队列
void vQueueDelete( TaskHandle_t pxQueueToDelete );

发送和接收

// 消息等待
// 返回队列中消息数量
UBaseType_t uxQueueMessagesWaiting( const QueueHandle_t xQueue );

// 接收
BaseType_t xQueueReceive( QueueHandle_t xQueue, 
                    void *pvBuffer, 
                    TickType_t xTicksToWait );

// 发送
BaseType_t xQueueSend( QueueHandle_t xQueue, 
                    const void * pvItemToQueue, 
                    TickType_t xTicksToWait );
// 发送到队头
BaseType_t xQueueSendToFront( QueueHandle_t xQueue, 
                    const void * pvItemToQueue, 
                    TickType_t xTicksToWait );
// 发送到队尾
BaseType_t xQueueSendToBack( QueueHandle_t xQueue, 
                    const void * pvItemToQueue, 
                    TickType_t xTicksToWait );

示例

队列基础

// 2020-12-31
#include "demo.h"

static QueueHandle_t g_queue;

// debug
static volatile uint32_t g_tick_timer;

static void task_cmd(void *param)
{
    (void)param;

    BaseType_t status;
    const TickType_t tick_wait = pdMS_TO_TICKS(100);

    uint8_t str[32] = {0};
    uint32_t len;
    while(1)
    {
        len = uart_recv(str, 32);
        if(len == 0)
        {
            continue;
        }

        status = xQueueSendToBack(g_queue, &str, tick_wait);
        if(status != pdPASS)
        {
            uart_send("send to queue failed!\n", 0);
        }
        else
        {
            uart_send("send to the cmd : ", 0);
            uart_send(str, 1);
            uart_send("\n", 0);
        }
    }
}

#if 0
static void task_parse(void *param)
{
    (void)param;

    BaseType_t status;
    const TickType_t tick_wait = pdMS_TO_TICKS(500);
    uint8_t cmd;

    while(1)
    {
        if(uxQueueMessagesWaiting(g_queue) != 0)
        {
            uart_send("queue should have been empty!\n", 0);
        }

        status = xQueueReceive(g_queue, &cmd, tick_wait);
        if(status != pdPASS)
        {
            // uart_send("could not receive from the queue\n",0);
            continue;
        }

        // cmd parse
        uart_send("recv the cmd : ", 0);
        uart_send(&cmd, 1);
        uart_send("\n", 0);
        switch(cmd)
        {
        case 0x31:
        {
            LED1_ON;
        }
        break;
        case 0x32:
        {
            LED1_OFF;
        }
        break;
        case 0x33:
        {
            LED1_FLIP;
        }
        break;
        default:
        {

        }
        }
    }
}
#else
static void task_parse(void *param)
{
    uint32_t period = *(uint32_t *)param / 2;       //ms

    BaseType_t status;
    const TickType_t tick_wait = pdMS_TO_TICKS(period);
    uint8_t cmd;

    while(1)
    {
#if configUSE_IDLE_HOOK == 1
        /*
            之所以打印的时候显示0x32 = 50为步长。
            是由于
            1. 配置tick中断为10ms
            2. 队列接收函数配置的等待时间为500ms = 1000/2
            因此是合理的。
            也即tick_hook函数进入的次数,就是tick中断发生的次数。
        */
        uart_send("tick_timer = ", 0);
        uart_send_hex((uint8_t *)&g_tick_timer, 4);
        uart_send("\n", 0);
#endif
        if(uxQueueMessagesWaiting(g_queue) != 0)
        {
            uart_send("queue should have been empty!\n", 0);
        }

        status = xQueueReceive(g_queue, &cmd, tick_wait);
        if(status != pdPASS)
        {
            // uart_send("could not receive from the queue\n",0);
        }
        else
        {
            // cmd parse
            uart_send("recv the cmd : ", 0);
            uart_send(&cmd, 1);
            uart_send("\n", 0);
            LED1_OFF;
        }

        switch(cmd)
        {
        case 0x31:
        {
            LED1_ON;
        }
        break;
        case 0x32:
        {
            LED1_OFF;
        }
        break;
        case 0x33:
        {
            LED1_FLIP;
        }
        break;
        default:
        {

        }
        }
    }
}
#endif

/**
    queue
 */
void demo_02(void)
{
    uint32_t period = 1000;
    g_queue = xQueueCreate(3, sizeof(uint8_t));

    if(g_queue != NULL)
    {
        xTaskCreate(task_cmd, "cmd", 128, NULL, 1, NULL);
        xTaskCreate(task_parse, "parse", 128, &period, 2, NULL);
    }

    vTaskStartScheduler();
    while(1)
    {
        ;
    }
}

void vApplicationTickHook(void)
{
    g_tick_timer ++;
}

定时器

创建和销毁

// 创建定时器
TimerHandle_t xTimerCreate( const char *pcTimerName,    // 定时器名称
                    const TickType_t xTimerPeriod,      // 定时周期
                    const UBaseType_t uxAutoReload,     // 自动重载
                    void * const pvTimerID,             // 定时器ID
                    TimerCallbackFunction_t pxCallbackFunction );   // 回调函数
// 删除定时器
BaseType_t xTimerDelete( TimerHandle_t xTimer, TickType_t xTicksToWait );

启动和停止

BaseType_t xTimerStart( TimerHandle_t xTimer, TickType_t xTicksToWait );
BaseType_t xTimerStop( TimerHandle_t xTimer, TickType_t xTicksToWait );

周期

// 修改定时器周期
BaseType_t xTimerChangePeriod( TimerHandle_t xTimer, 
                    TickType_t xNewPeriod,
                    TickType_t xTicksToWait );

// 获取定时器周期
TickType_t xTimerGetPeriod( TimerHandle_t xTimer );

复位

// 复位定时器
BaseType_t xTimerReset( TimerHandle_t xTimer, TickType_t xTicksToWait );

单位变换

TickType_t xTicksToWait = pdMS_TO_TICKS( xTimeInMs );;

示例

// 2020-12-31
#include "demo.h"

static void timer_callback(xTimerHandle timer);

static xTimerHandle g_timer;
static xTimerHandle g_timer_ont_shot;

static void uart_parse(void *param)
{
    (void)param;

    const TickType_t tick_wait = pdMS_TO_TICKS(0);

    uint8_t str[32] = {0};
    uint32_t len;
    uint32_t peroid_div2 = 0;

    while(1)
    {
        len = uart_recv(str, 32);
        if(len != 1)
        {
            continue;
        }

        switch(str[0])
        {
        case 0x31:
        {
            peroid_div2 = 100;
        }
        break;
        case 0x32:
        {
            peroid_div2 = 500;
        }
        break;
        case 0x33:
        {
            peroid_div2 = 2000;
        }
        break;
        default:
        {
            LED0_OFF;
            LED1_OFF;
            xTimerStop(g_timer, tick_wait);
            xTimerStop(g_timer_ont_shot, tick_wait);

            uart_send("Turn off the backlight manually!\n", 0);
            continue;
        }
        }

        LED0_ON;
        uart_send("Turn on the backlight manually!\n", 0);
        xTimerReset(g_timer_ont_shot, tick_wait);
        xTimerChangePeriod(g_timer, pdMS_TO_TICKS(peroid_div2), tick_wait);
    }
}


/**
    software timer
 */
void demo_03(void)
{
    BaseType_t st_timer, st_timer_one_shot;

    // 创建定时器
    g_timer = xTimerCreate("blinkled", pdMS_TO_TICKS(500), pdTRUE, 0, timer_callback);
    g_timer_ont_shot = xTimerCreate("backlight", pdMS_TO_TICKS(5000), pdFALSE, 0, timer_callback);

    if(g_timer != NULL && g_timer_ont_shot != NULL)
    {
        st_timer = xTimerStart(g_timer, 0);
        st_timer_one_shot = xTimerStart(g_timer_ont_shot, 0);
        if(st_timer != pdFALSE && st_timer_one_shot != pdFALSE)
        {
            LED0_ON;
            uart_send("The backlight is on!\n", 0);

            // 串口命令处理
            xTaskCreate(uart_parse, "uart", 128, NULL, 1, NULL);

            vTaskStartScheduler();
        }
    }

    while(1)
    {
        ;
    }
}

static void timer_callback(xTimerHandle timer)
{
    // 当然了,也可以分成两个函数
    // 这里主要是显示如何在一个函数中实现区分
    if(timer == g_timer)
    {
        LED1_FLIP;
    }
    else if(timer == g_timer_ont_shot)
    {
        LED0_OFF;
        uart_send("The backlight turn off automatically!\n", 0);
    }
    else
    {
        uart_send("It won't get here\n", 0);
    }
}

信号量

创建和删除

// 创建信号量

// 互斥信号量
SemaphoreHandle_t xSemaphoreCreateMutex( void );

获取和释放

// 获取信号量
BaseType_t xSemaphoreTake( SemaphoreHandle_t xSemaphore, TickType_t xTicksToWait );
// 释放信号量
BaseType_t xSemaphoreGive( SemaphoreHandle_t xSemaphore );

示例

信号量基础

// 2020-12-31
#include "demo.h"

static SemaphoreHandle_t g_mutex;

static void task_uart(void *param)
{
    char *string = (char *)param;
    uart_init();

    TickType_t xLastWakeTime;
    const TickType_t delay_ms = pdMS_TO_TICKS(20);

    while(1)
    {
        // the use of mutex
        xSemaphoreTake(g_mutex, portMAX_DELAY);
        uart_send((uint8_t *)string, strlen(string));
        xSemaphoreGive(g_mutex);

        vTaskDelayUntil(&xLastWakeTime, delay_ms);
    }
}

/**
    mutex
 */
void demo_04(void)
{
    g_mutex = xSemaphoreCreateMutex();

    if(g_mutex != NULL)
    {
        xTaskCreate(task_uart, "uart1", 128, ""
                    "----------------------------------------------------"
                    "----------------------------------------------------"
                    "----------------------------------------------------"
                    "----------------------------------------------------"
                    "\n", 1, NULL);

        xTaskCreate(task_uart, "uart2", 128, "uart2 is running!\n", 2, NULL);

        vTaskStartScheduler();
    }
    while(1)
    {
        ;
    }
}