FreeRTOS学习(五)消息队列和二值信号量 xQueue / xSemaphore

消息队列

可以和中断 人物间发送和接受不定长的消息,在消息队列中会使任务进入阻塞。 可以在调度器开始前,创建消息队列。

创建xQueueCreate()

#include "FreeRTOS.h"
#include "queue.h"

//创建成功返回消息队列句柄,失败返回NULL
QueueHandle_t xQueueCreate(
	UBaseType_t uxQueueLength,  //消息队列最大长度
    UbaseType_t uxItemSize		//队列中每个消息的大小
);

xQueueSend()

消息队列发送xQueueSend , xQueueSendToFront / xQueueSendToBack

BaseType_t xQueueSend(
	QueueHandle_t xQueue,		//消息队列句柄
    const void * pvItemToQueue,	//要发送消息的地址
    TickType_t xTicksToWait		//阻塞等待时间
);

xQueueSendFromISR()

在中断中往队列传入消息

xQueueSendFromISR(
	QueueHandle_t xQueue,		//消息队列句柄
    const void * pvItemToQueue,	//要发送消息的地址
    NULL
);

xQueueReceive()

读取消息队列消息

成功pdPASS 失败errQUEUE_EMPTY
BaseType_t xQueueReceive(
	QueueHandle_t xQueue,		//消息队列句柄
    void * pvBuffer,			//要发送消息的地址
    TickType_t xTicksToWait		//阻塞等待时间
);

二值信号量

信号量有很多种,用于同步和互斥。二值信号量底层是消息队列,只不过只有空和满两种状态,底层大多是宏实现。

创建xSemaphoreCreateBinary()

没有参数 返回值是 SemaphoreHandle_t 类型(void *)

xSemaphoreGive()

BaseType_t xSemaphoreGive( SemaphoreHandle_t xSemaphore )
  • @param xSemaphore 要释放信号量的句柄
  • @return pdPASS: 释放信号量成功。
    errQUEUE_FULL: 释放信号量失败。

xSemaphoreGiveFromISR()

在中断中必须使用带FromISR的函数!!!

BaseType_t xSemaphoreGiveFromISR( 
						SemaphoreHandle_t xSemaphore,
						BaseType_t * pxHigherPriorityTaskWoken)
  • @param xSemaphore 要释放信号量的句柄
  • @param pxHigherPriorityTaskWoken 退出此函数以后是否进行任务切换,可以传NULL,也可以定义一个BaseType_t 取地址扔进去。
  • @pdPASS: 释放信号量成功。
    errQUEUE_FULL: 释放信号量失败。

xSemaphoreTake()

BaseType_t xSemaphoreTake(
				SemaphoreHandle_t xSemaphore,
                TickType_t xBlockTime)
  • @param xSemaphore 要获取信号量的句柄
  • @param xBlockTime 阻塞时间。
  • @pdPASS: 获取信号量成功。
    pdFALSE: 获取信号量失败。

xSemaphoreTakeFromISR ()

在中断中必须使用带FromISR的函数!!!

    BaseType_t xSemaphoreTakeFromISR(
    				SemaphoreHandle_t xSemaphore,
                 	BaseType_t * pxHigherPriorityTaskWoken)
  • @param xSemaphore 要获取信号量的句柄
  • @param pxHigherPriorityTaskWoken 退出此函数以后是否进行任务切换,可以传NULL,也可以定义一个BaseType_t 取地址扔进去。
  • @pdPASS: 获取信号量成功。
    pdFALSE: 获取信号量失败。

代码

  • 功能:从UART读取字符串,放入消息队列,LED任务读取队列,设置LED状态。
  • 板载一个蓝色LED,是gpio16,外接一个红色LED在IO4.
  • IO5有一个外接按键(中断方式),按键短按打开蓝色LED,长按(1s)关闭蓝色LED
#include 
#include 
#include 

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "freertos/semphr.h"

#include "driver/gpio.h"
#include "driver/uart.h"

#define LED_RED_PIN 4
#define LED_BLUE_PIN 16
#define BUTTON_PIN 5

#define BUF_SIZE (1024)  //小于1024会报奇怪的错误

static xQueueHandle led_evt_queue = NULL;
static SemaphoreHandle_t intr_sem = NULL;

/**
 *  - 功能:从UART读取字符串,放入消息队列,LED任务读取队列,设置LED状态。
    -  板载一个蓝色LED,是gpio16,外接一个红色LED在IO4.
    - IO5有一个外接按键(中断方式),按键短按打开蓝色LED,长按(1s)关闭蓝色LEDBrief:
*/

static void button_isr_handler(void *arg)
{
    xSemaphoreGiveFromISR(intr_sem,NULL); //给
}

static void Button_task()
{
    TickType_t last_tick = xTaskGetTickCount(); 
    TickType_t this_tick= xTaskGetTickCount();

    const char red_on[8] = "RED_ON";
    const char red_off[8] = "RED_OFF";
    while (1)
    {
        last_tick = xTaskGetTickCount(); 
        xSemaphoreTake(intr_sem,portMAX_DELAY); //拿
        
        
        if(gpio_get_level(BUTTON_PIN) == 0)
        {
            vTaskDelay(2);
            if(gpio_get_level(BUTTON_PIN) == 0)
            {
                continue;
            }
        }
       
        this_tick = xTaskGetTickCount();
        if(this_tick - last_tick >=0 && this_tick - last_tick < 50 )
        {
            //短按
            for(int i = 0;i< 8;++i)
                xQueueSend(led_evt_queue,red_on+i,1);
        } 
        else if(this_tick - last_tick >= 50 && this_tick - last_tick < 200 )
        {
            //长按
            for(int i = 0;i< 8;++i)
                xQueueSend(led_evt_queue,red_off+i,1);
        }
    }
}

static void LED_task()
{
    gpio_config_t io_conf;
    memset(&io_conf,0,sizeof(gpio_config_t));
    io_conf.mode = GPIO_MODE_OUTPUT;//设置为输出
    io_conf.pin_bit_mask = ((1ULL<<LED_RED_PIN)|(1ULL<<LED_BLUE_PIN)) ;
    gpio_config(&io_conf);

    char *data = (char *) malloc(BUF_SIZE);

    while(1)
    {
        int i = 1;
        memset(data,0,BUF_SIZE);

        //阻塞等待接收队列的第一个元素
        xQueueReceive(led_evt_queue, data, portMAX_DELAY);
        //循环接收第二个开始的元素,直到10个tick没收到数据
        while(xQueueReceive(led_evt_queue, data+i, 10))
            i++;
        //解析
        if(strstr(data,"RED_ON") != NULL)
        {
            gpio_set_level(LED_RED_PIN,0);//设置GPIO 点亮LED
        }
        else if(strstr(data,"RED_OFF") != NULL)
        {
            gpio_set_level(LED_RED_PIN,1);
        }
        else if(strstr(data,"BLUE_ON") != NULL)
        {
            gpio_set_level(LED_BLUE_PIN,0);
        }
        else if(strstr(data,"BLUE_OFF") != NULL)
        {
            gpio_set_level(LED_BLUE_PIN,1);
        }
    }
}

#if 1
static void UART_task()
{
    //串口配置
    uart_config_t uart_config = {
        .baud_rate = 74880,
        .data_bits = UART_DATA_8_BITS,
        .parity    = UART_PARITY_DISABLE,
        .stop_bits = UART_STOP_BITS_1,
        .flow_ctrl = UART_HW_FLOWCTRL_DISABLE
    };
    uart_param_config(UART_NUM_0, &uart_config);
    uart_driver_install(UART_NUM_0, BUF_SIZE * 2, 0, 0, NULL, 0);

    // 分配临时空间
    uint8_t *data = (uint8_t *) malloc(BUF_SIZE);

    while (1) {
        memset(data,0,BUF_SIZE);
        // Read data from the UART
        int len = uart_read_bytes(UART_NUM_0, data, BUF_SIZE, 20 / portTICK_RATE_MS);
        // Write data back to the UART
        for(int i = 0; i < len; ++i)
        {
            xQueueSend(led_evt_queue,data+i,portMAX_DELAY);
        }
    }
}
#endif


void app_main(void)
{
    //1. 按键中断设置
    gpio_config_t io_conf;
    memset(&io_conf,0,sizeof(gpio_config_t));
    io_conf.mode = GPIO_MODE_INPUT;//设置为输入
    io_conf.pin_bit_mask = 1ULL<<BUTTON_PIN;
    //io_conf.intr_type = GPIO_INTR_POSEDGE;
    io_conf.intr_type = GPIO_INTR_ANYEDGE; //上升沿下降沿均触发
    io_conf.pull_up_en = 1;
    gpio_config(&io_conf);

    //2. 创建队列
    led_evt_queue =  xQueueCreate(BUF_SIZE, sizeof(uint8_t));
    intr_sem =  xSemaphoreCreateBinary();

    //3. 启动任务
    xTaskCreate(LED_task, "LED_task", 2048, NULL, 2, NULL);
    xTaskCreate(UART_task, "UART_task", 2048, NULL, 3, NULL); 
    xTaskCreate(Button_task, "Button_task", 2048, NULL, 3, NULL); 

    //4. 连接IO中断服务函数
    gpio_set_intr_type(BUTTON_PIN, GPIO_INTR_NEGEDGE);
    gpio_install_isr_service(0);
    gpio_isr_handler_add(BUTTON_PIN, button_isr_handler, NULL);

    //5. 主任务空闲
    while(1)
    {
        vTaskDelay(1000 / portTICK_RATE_MS);
    }
}

FreeRTOS学习(五)消息队列和二值信号量 xQueue / xSemaphore_第1张图片

实物

FreeRTOS学习(五)消息队列和二值信号量 xQueue / xSemaphore_第2张图片

你可能感兴趣的:(ESP,RTOS,数据结构)