当前位置: 首页 > news >正文

FreeRTOS - 基于ESP32 串口数据收发

这篇是基于FreeRTOS 针对数据收发做了个集成化处理 这样保证引入该文件后 外界只需要调用收发接口 就能做到对数据的收发 。

  • 目前是在ESP32的开发环境下做了个简单的串口数据收发
    • 1.核心思想

)

目前是在ESP32的开发环境下做了个简单的串口数据收发

1.核心思想

既然是数据收发 避免不了超时、堵塞、流控等这些机制。
既然是基于FreeRTOS 就要好好利用它的一些特性 帮助我们更好的维护数据。

在开始说FreeRTOS的前 不妨先发散下思维 想一想 假如你也不熟悉RTOS特性 你要怎么设计 才能保证数据收发过程中 数据不会丢失呢。
数据收发 不外乎就2种场景 好理解点 以下把收到数据叫做生产者 因为生产数据嘛
把发送数据叫做消费者。
场景1.生产者生产的数量 > 消费者消费的数量 这种可以叫做 “供大于求”
场景2.生产者生产的数量 <= 消费者消费的数量 这种可以叫做 “供不应求”

那场景1呢 我们就想着 要在缓存满了的情况下 让生产者不生产了 这样就不会出现生产者一直生产 但消费者来不及消费 导致那些生产的数据丢失了

场景2呢 就是完全可以接受 在缓冲区足够的情况下 进行收发。
所以我们要针对场景1做处理。

FreeRTOS有锁 信号量 堵塞等机制 我们利用好这俩机制就能解决场景1的问题。

//基于以上 我们可以创建这样一个结构体 用来存放我们的数据
//其中buf用来存放数据
//read write分别是读写指针 由于buf空间有限 我们可以通过读写指针做一个环形缓冲区
//count是当前写入的数据量
//queue 是数据队列
//mutex 是锁
//ready_semaphore 是信号量

typedef struct {uint8_t *buf;size_t read;size_t write;size_t count;QueueHandle_t queue;SemaphoreHandle_t mutex;SemaphoreHandle_t ready_semaphore;
} DATA_T;

目前用EPS32的串口数据收发做举例

#include "driver/uart.h"
#include "driver/gpio.h"#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include <esp_log.h>
#include "freertos/semphr.h"
#include "freertos/queue.h"#define UART_NUM UART_NUM_1
#define UART_TX_PIN 18
#define UART_RX_PIN 17
#define UART_BUF_SIZE 1024typedef struct {uint8_t *buf;size_t length;uint32_t timestamp;
} DATA_PACKET_T;typedef struct {uint8_t *buf;size_t read;size_t write;size_t count;QueueHandle_t queue;SemaphoreHandle_t mutex;SemaphoreHandle_t ready_semaphore;
} DATA_T;static DATA_T data_t;
static const char *UART_TAG = "example:uart";int buffer_get_used_space(void)
{return data_t.count;
}int buffer_get_remain_space(void)
{return UART_BUF_SIZE - buffer_get_used_space();
}bool buffer_is_empty(void)
{return data_t.count == 0;
}bool buffer_is_full(void)
{return data_t.count >= UART_BUF_SIZE;
}void uart_init(void)
{memset(&data_t, 0, sizeof(data_t));data_t.ready_semaphore = xSemaphoreCreateBinary();data_t.mutex = xSemaphoreCreateMutex();data_t.buf = malloc(UART_BUF_SIZE);data_t.read = data_t.write = data_t.count = 0;if (data_t.buf == NULL) {ESP_LOGI(UART_TAG, "缓冲区分配失败\n");return;}uart_config_t uart_config = {.baud_rate = 230400,                        // 设置波特率.data_bits = UART_DATA_8_BITS,              // 设置数据位为 8 位.parity    = UART_PARITY_DISABLE,           // 不使用校验位.stop_bits = UART_STOP_BITS_1,              // 使用一个停止位.flow_ctrl = UART_HW_FLOWCTRL_DISABLE       // 禁用硬件流控};ESP_ERROR_CHECK(uart_driver_install(UART_NUM, UART_BUF_SIZE, 0, 20, &data_t.queue, 0)); // 串口驱动安装ESP_ERROR_CHECK(uart_param_config(UART_NUM, &uart_config)); // 串口参数配置ESP_ERROR_CHECK(uart_set_pin(UART_NUM, UART_TX_PIN, UART_RX_PIN, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE)); // 串口引脚配置ESP_ERROR_CHECK(uart_enable_rx_intr(UART_NUM)); //使能串口中断
}void buffer_write_data(uint8_t *data, size_t length)
{if (length == 0) return;if (xSemaphoreTake(data_t.mutex, pdMS_TO_TICKS(100)) == pdTRUE) {for (size_t i = 0; i < length; i++) {data_t.buf[data_t.write] = data[i];data_t.write = (data_t.write + 1) % UART_BUF_SIZE;data_t.count++;xSemaphoreGive(data_t.ready_semaphore);}xSemaphoreGive(data_t.mutex);//ESP_LOGI(UART_TAG, "缓冲区写入 %d 字节,当前数据量: %d\n", length, data_t.count);}
}// 非阻塞读取,立即返回可用数据
size_t buffer_read_nonblocking(uint8_t *output, size_t max_length)
{size_t total_read = 0;if (xSemaphoreTake(data_t.mutex, pdMS_TO_TICKS(10)) == pdTRUE) {while (!buffer_is_empty() && total_read < max_length) {output[total_read] = data_t.buf[data_t.read];data_t.read = (data_t.read + 1) % UART_BUF_SIZE;data_t.count--;total_read++;}//ESP_LOGI(UART_TAG, "RX noblock %d  %d/%d\n", total_read, data_t.read, data_t.write);xSemaphoreGive(data_t.mutex);}return total_read;
}// 从缓冲区读取数据(阻塞等待)
size_t buffer_read_blocking(uint8_t *output, size_t required_length, TickType_t timeout)
{size_t total_read = 0;uint32_t start_time = xTaskGetTickCount();while (total_read < required_length) {// 检查超时if ((xTaskGetTickCount() - start_time) > timeout) {ESP_LOGI(UART_TAG, "读取超时,已读取 %d/%d 字节\n", total_read, required_length);break;}// 一次性读取尽可能多的数据size_t available = buffer_get_used_space();if (available > 0) {size_t to_read = (available < (required_length - total_read)) ? available : (required_length - total_read);// 等待数据信号量if (xSemaphoreTake(data_t.ready_semaphore, pdMS_TO_TICKS(100)) == pdTRUE) {if (xSemaphoreTake(data_t.mutex, pdMS_TO_TICKS(50)) == pdTRUE) {// 计算连续可读的数据长度size_t contiguous = (data_t.read <= data_t.write) ?  (data_t.write - data_t.read) : (UART_BUF_SIZE - data_t.read);size_t actual_read = (to_read < contiguous) ? to_read : contiguous;memcpy(output + total_read, data_t.buf + data_t.read, actual_read);//ESP_LOGI(UART_TAG, "RX block  %d/%d\n",  data_t.read, data_t.write);data_t.read = (data_t.read + actual_read) % UART_BUF_SIZE;data_t.count -= actual_read;total_read += actual_read;xSemaphoreGive(data_t.mutex);}}} else {vTaskDelay(1 / portTICK_PERIOD_MS);}}return total_read;
}void data_recv_proc(void *param)
{int len;int temp;uint8_t buf[256];uart_event_t event;uart_init();// 检查队列是否创建成功if (data_t.queue == NULL) {ESP_LOGE(UART_TAG, "UART事件队列创建失败,任务退出");vTaskDelete(NULL);return;}while (1) {if (xQueueReceive(data_t.queue, &event, portMAX_DELAY)) {switch (event.type) {case UART_DATA:// 有数据到达if (!event.size) {break;}temp = buffer_get_remain_space();temp = event.size > temp ? temp : event.size;temp = sizeof(buf) > temp ? temp : sizeof(buf);// 读取数据到缓冲区len = uart_read_bytes(UART_NUM, buf, temp, pdMS_TO_TICKS(100));if (len > 0) {buffer_write_data(buf, len);}break;case UART_FIFO_OVF:case UART_BUFFER_FULL:ESP_LOGI(UART_TAG, "UART %s\n", (event.type == UART_FIFO_OVF) ? "FIFO 溢出" : "缓冲区满");uart_flush_input(UART_NUM);xQueueReset(data_t.queue);break;default:ESP_LOGI(UART_TAG, "UART 事件类型: %d\n", event.type);break;}}}
}void uart_send_data(uint8_t *data, size_t length)
{if (length == 0) return;int sent = uart_write_bytes(UART_NUM, data, length);if (sent == length) {ESP_LOGI("UART", "成功发送 %d 字节", sent);} else {ESP_LOGE("UART", "发送失败,期望: %d, 实际: %d", length, sent);}
}
http://www.dtcms.com/a/528982.html

相关文章:

  • 【释义】摩尔定律性能收益在减弱
  • REFLECTOOL: Towards Reflection-Aware Tool-Augmented Clinical Agents
  • 基于android的体育馆预约使用系统
  • 免费psd模板网站商标注册申请需要什么材料
  • 【开题答辩全过程】以 查寝打卡系统为例,包含答辩的问题和答案
  • mvc 网站开发平度市城市建设局网站
  • 旅行社网站建设规划的内容wordpress 评论模板
  • EtherCAT转EtherNet/IP工业数据采集网关:保障编码器与工控机稳定交互的整合案例
  • 网络层网际协议IP
  • 凡科免费建站平台渭南定制网站建设公司
  • 哪款纳米研磨机能将药物颗粒做到≤100nm?需要多少小时?
  • 《C语言疑难点 --- 字符函数和字符串函数专题(上)》
  • 株洲网站建设联系方式知名的家居行业网站开发
  • 华为堡垒机
  • Wordpress做什么网站赚钱外贸英文网站建设
  • MyBatis注解与XML使用对比
  • Connector
  • 招标网免费查看什么是优化师
  • 商城网站开发哪家好室内装饰设计费收费标准
  • 自动驾驶中的传感器技术70——Navigation(7)
  • 个人接装修活怎样给网站做seo优化
  • php做购物网站wordpress 3.4.2
  • 阮一峰《TypeScript 教程》学习笔记——namespace
  • WEB前端技术基础(第三章:css-网页美化的衣装-上)
  • 大学生网站开发项目计划书范文南宁营销型网站设计
  • C++ 游戏开发示例:简单的贪吃蛇游戏
  • 东莞小学网站建设培训学校网站建设要点
  • 网络安全编程——TCP客户端以及服务端Python实现
  • 基于多尺度特征融合的自注意力度量学习的小样本故障诊断
  • UVa 1227 The Longest Constant Gene