FreeRTOS学习笔记---队列基础操作(基于ESPIDF)

参考文档与视频百问网《FreeRTOS入门与工程实践-基于STM32F103》教程-基于DShanMCU-103(STM32F103) | 百问网

【2024最新版 ESP32教程(基于ESP-IDF)】ESP32入门级开发课程 更新中 中文字幕_哔哩哔哩_bilibili

队列

队列的意义(实现任务协调工作)

队列API

上面没有提到队列已满但是强制发送消息到队列中的方法,故问了一下AI解答如下:
覆盖发送:如果你希望新消息覆盖最旧的消息(队列头部的消息),可以使用xQueueOverwrite()函数。这个函数会将新消息写入队列头部的位置,而不考虑队列是否已满。

xQueueOverwrite(xQueue, &var);

队列实验

知道了上面的知识后,立马叫AI生成一个实验代码

(我想用ESPIDF写一个队列实验,监测按键时候按下,如果按下就发送消息,当接收到消息后串口打印一个日志过来)

#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "driver/gpio.h"
#include "esp_log.h"

static const char *TAG = "QueueExample";

// 定义队列句柄
QueueHandle_t xQueue;

// 按键的GPIO引脚
#define BUTTON_GPIO 0

// 按键检测任务
void button_task(void *pvParameters) {
    while (1) {
        // 读取按键状态
        int button_state = gpio_get_level(BUTTON_GPIO);
        if (button_state == 0) {  // 按键按下
            // 发送消息到队列
            xQueueSend(xQueue, &button_state, portMAX_DELAY);
            vTaskDelay(pdMS_TO_TICKS(200));  // 去抖动
        }
        vTaskDelay(pdMS_TO_TICKS(10));  // 降低CPU占用率
    }
}

// 日志打印任务
void log_task(void *pvParameters) {
    int button_state;
    while (1) {
        // 从队列接收消息
        if (xQueueReceive(xQueue, &button_state, portMAX_DELAY) == pdTRUE) {
            ESP_LOGI(TAG, "Button pressed! State: %d", button_state);
        }
    }
}

void app_main(void) {
    // 创建队列
    xQueue = xQueueCreate(10, sizeof(int));
    if (xQueue == NULL) {
        ESP_LOGE(TAG, "Failed to create queue");
        return;
    }

    // 配置GPIO 这里可以发现和STM32标准库差不多
    gpio_config_t io_conf;
    io_conf.intr_type = GPIO_INTR_DISABLE;
    io_conf.mode = GPIO_MODE_INPUT;
    io_conf.pin_bit_mask = (1ULL << BUTTON_GPIO);
    io_conf.pull_up_en = GPIO_PULLUP_ENABLE;
    io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
    gpio_config(&io_conf);

    // 创建任务
    xTaskCreate(button_task, "Button Task", 2048, NULL, 5, NULL);
    xTaskCreate(log_task, "Log Task", 2048, NULL, 5, NULL);
}

实验成功现象,按键按下时串口打印信息

[0;32mI (234353) QueueExample: Button pressed! State: 0[0m
[0;32mI (234563) QueueExample: Button pressed! State: 0[0m
[0;32mI (234773) QueueExample: Button pressed! State: 0[0m
[0;32mI (234983) QueueExample: Button pressed! State: 0[0m
[0;32mI (235193) QueueExample: Button pressed! State: 0[0m
[0;32mI (235403) QueueExample: Button pressed! State: 0[0m
[0;32mI (235613) QueueExample: Button pressed! State: 0[0m
[0;32mI (235823) QueueExample: Button pressed! State: 0[0m
[0;32mI (236033) QueueExample: Button pressed! State: 0[0m

由于我很好奇ESPIDF中的UART是如何实现收发的,所以又叫AI写了个程序,但是在这个过程中,我发现ESPIDF与STM32标准库有点不太一样,ESPIDF并没有UART接收中断服务函数,而是定义了一个结构体 “uart_event_t” 用这个结构体中的数据去判断UART现在是处于什么状态(如下代码)

            switch (event.type) {
                case UART_DATA:
                    // 读取数据
                    int len = uart_read_bytes(UART_PORT_NUM, data, event.size, portMAX_DELAY);
                    if (len > 0) {
                        // 处理接收到的数据,这里简单地打印到日志
                        for (int i = 0; i < len; i++) {
                            ESP_LOGI(TAG, "Received: %c", data[i]);
                        }
                    }
                    break;
                case UART_FIFO_OVF:
                    ESP_LOGW(TAG, "UART FIFO overflow");
                    uart_flush_input(UART_PORT_NUM);
                    break;
                case UART_BUFFER_FULL:
                    ESP_LOGW(TAG, "UART buffer full");
                    uart_flush_input(UART_PORT_NUM);
                    break;
                default:
                    ESP_LOGI(TAG, "Unknown UART event type: %d", event.type);
                    break;
            }

下面是完整代码

#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "driver/uart.h"
#include "esp_log.h"

static const char *TAG = "UART_Example";

// 定义队列句柄
QueueHandle_t xQueue;

// 串口配置
#define UART_PORT_NUM UART_NUM_0  // 选择串口1
#define BUF_SIZE (1024)            // 串口缓冲区大小
#define RD_BUF_SIZE (BUF_SIZE)     // 读缓冲区大小

// 声明事件处理任务
static void uart_event_task(void *pvParameters);

/**
 * @brief 初始化串口和队列
 */
void uart_init(void) {
    const uart_config_t uart_config = {  // 配置串口参数
        .baud_rate = 115200,              // 波特率
        .data_bits = UART_DATA_8_BITS,    // 数据位
        .parity = UART_PARITY_DISABLE,    // 校验位
        .stop_bits = UART_STOP_BITS_1,    // 停止位
        .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,  // 流控
        .source_clk = UART_SCLK_DEFAULT,  // 时钟源
    };

    // 配置串口
    uart_param_config(UART_PORT_NUM, &uart_config);
    // 安装串口驱动程序,并启用事件队列
    uart_driver_install(UART_PORT_NUM, BUF_SIZE * 2, 0, 20, &xQueue, 0);

    // 创建任务处理串口事件
    xTaskCreate(uart_event_task, "UART Event Task", 2048, NULL, 12, NULL);
}

/**
 * @brief 串口事件处理任务
 * @param pvParameters 任务参数(这里未使用)
 */
static void uart_event_task(void *pvParameters) {
    uart_event_t event;
    uint8_t *data = (uint8_t *)malloc(RD_BUF_SIZE);

    while (1) {
        // 从队列接收事件
        if (xQueueReceive(xQueue, (void *)&event, (TickType_t)portMAX_DELAY)) {
            switch (event.type) {
                case UART_DATA:
                    // 读取数据
                    int len = uart_read_bytes(UART_PORT_NUM, data, event.size, portMAX_DELAY);
                    if (len > 0) {
                        // 处理接收到的数据,这里简单地打印到日志
                        for (int i = 0; i < len; i++) {
                            ESP_LOGI(TAG, "Received: %c", data[i]);
                        }
                    }
                    break;
                case UART_FIFO_OVF:
                    ESP_LOGW(TAG, "UART FIFO overflow");
                    uart_flush_input(UART_PORT_NUM);
                    break;
                case UART_BUFFER_FULL:
                    ESP_LOGW(TAG, "UART buffer full");
                    uart_flush_input(UART_PORT_NUM);
                    break;
                default:
                    ESP_LOGI(TAG, "Unknown UART event type: %d", event.type);
                    break;
            }
        }
    }

    free(data);
}

void app_main(void) {
    // 初始化串口和队列
    uart_init();
}

和标准库还是很像的,没有什么很难的地方,下面是打印信息

I (66313) UART_Example: Received: l
I (66313) UART_Example: Received: b
I (66313) UART_Example: Received: w

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值