参考文档与视频百问网《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
2243

被折叠的 条评论
为什么被折叠?



