IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> # ringbuffer学习--软件RT-Thread Studio下配置STM32F4xx>>>ringbuffer+串口uart4发送数据-过度+进阶 -> 正文阅读

[嵌入式]# ringbuffer学习--软件RT-Thread Studio下配置STM32F4xx>>>ringbuffer+串口uart4发送数据-过度+进阶

(1)叙述

最近学习并使用ringbuffer,因为要涉及多线程并发以及数据存储等问题,综合情况比较复杂,这个时候使用ringbuffer是一个非常好用的工具。
但是最开始上级跟我说“ringbuffer”这个词的时候,可以说是一脸懵逼,整个人傻掉了。没听过啊,后来通过不断学习,才渐渐理解其中,发现其中的巧妙。
所以本片希望用“原理说明+实验样例”的方式,向看过这篇文章的人说明ringbuffer 是什么东西,咋用等问题。

(2)原理:ringbuffer说明

#(1)ringbuffer是什么(下定义)
一句话解释:ringbuffer就是一个环形的缓冲池,用来存储与读取数据用的。

另外:在维基百科上有如下解释:
“圆形缓冲区(circular buffer),也称作圆形队列(circular queue),循环缓冲区(cyclic buffer),环形缓冲区(ring buffer),是一种用于表示一个固定尺寸、头尾相连的缓冲区的数据结构,适合缓存数据流。”。
在这里插入图片描述
简单说,就是我们平时使用的缓冲区域,都是一个地址一个地址挨着的,而ringbuffer是将一段连续区域首尾相接,形成一个环形的区域。

举一个例子,有个环形的仓库和两个工人,一个(写)工人,只负责往仓库里装东西,有物品或货物来了(写数据),就按照顺序依次向仓储装,一个(读)工人,只负责从仓库取东西,谁需要东西,告诉他,他按照顺序拿物品或货物(取数据)。
那么当(写)工人放东西很快,追上了(读)工人,说明仓库满了。
那么当(读)工人拿东西很快,追上了(写)工人,说明仓库空了。

为了更好说明上述例子,从维基上下载下来一张图片,比较形象。
请添加图片描述

#(2)ringbuffer原理实现
那么如何实现呢,关于实现,维基百科也有介绍,一般有多种方式。
在这里插入图片描述
本片只介绍镜像指示位方式,因为即将使用RT-thread的ringbuffer,内部实现方式就是这种,打开代码,会看到如下内容告诉你,在RT-thread里用ringbuffer的话,用的是镜像指示位。
这种方式可以总结为,是通过增加标志位的方式,来判断是否“空”或者“满”,这种思想非常奇妙,需要一段时间来理解。
在这里插入图片描述
在RT-thread下,也能看到如下英语说明:
在这里插入图片描述

#(3)我们为什么使用ringbuffer
首先可以说,ringbuffer有它自身优点,如果你考虑使用它,那么也需要自身考虑什么时候以及为什么使用它,这里我给你几点使用它的原因吧。

  1. 空间的重复利用。
  2. 在使用过程中,它在很多情况下优于数组。
  3. 网上有很多写好的接口,比较成熟,易于使用。

#(4)如果使用ringbuffer我们关心什么(关注点)
如果你想使用,并实现ringbuffer那么我们其实主要关心函数接口以及如何使用。
使用的时候,反而不用关心原理方面的东西,只要能用起来就可以了。

(3)函数接口

(1)接口函数:以下为罗列函数

//使用静态环形缓冲区前,需要调用该函数进行初始化。该函数将把用户指定的缓冲区空间的指针传递给环形缓冲区控制块,并初始化环形缓冲区控制块的参数
void rt_ringbuffer_init(struct rt_ringbuffer *rb, rt_uint8_t *pool, rt_int16_t size);

//调用此函数将复位环形缓冲区,环形缓冲区控制块中的读写指针被置0
void rt_ringbuffer_reset(struct rt_ringbuffer *rb);

//调用此函数可以往指定环形缓冲区中写入指定长度的数据,如果剩余空间不足将丢弃剩余数据
rt_size_t rt_ringbuffer_put(struct rt_ringbuffer *rb, const rt_uint8_t *ptr, rt_uint16_t length);

//调用此函数可以往指定环形缓冲区中强制写入指定长度的数据,如果剩余空间不足将覆盖原有数据。
rt_size_t rt_ringbuffer_put_force(struct rt_ringbuffer *rb, const rt_uint8_t *ptr, rt_uint16_t length);

//调用此函数可以往指定环形缓冲区中写入一个字节的数据,如果剩余空间不足将写入失败
rt_size_t rt_ringbuffer_putchar(struct rt_ringbuffer *rb, const rt_uint8_t ch);

//调用此函数可以往指定环形缓冲区中强制写入一个字节的数据,如果剩余空间不足将覆盖原有数据。
rt_size_t rt_ringbuffer_putchar_force(struct rt_ringbuffer *rb, const rt_uint8_t ch);

//调用此函数可以从环形缓冲区中读取指定长度的数据。
rt_size_t rt_ringbuffer_get(struct rt_ringbuffer *rb, rt_uint8_t *ptr, rt_uint16_t length);


rt_size_t rt_ringbuffer_peak(struct rt_ringbuffer *rb, rt_uint8_t **ptr);

//调用此函数可以从环形缓冲区中读取一个字节的数据
rt_size_t rt_ringbuffer_getchar(struct rt_ringbuffer *rb, rt_uint8_t *ch);

//调用此函数可以获取环形缓冲区中已被使用的字节数。
rt_size_t rt_ringbuffer_data_len(struct rt_ringbuffer *rb);

(2)查函数的API手册:如果对于哪个函数不了直接查手册
https://www.rt-thread.org/document/api/group__ringbuffer.html#gafca4decdbf6545339b4ef09cbf92a4f0

在这里插入图片描述

(4)测试环境

软件环境:RT-Thread Studio
硬件环境:STM32F407ZGT6(正点开发板)

(5)先行步骤

如果之前没有使用过RT-thread studio的话,建议一定要先看下之前文章,里面有很多配置细节,调试不好,很容易一头雾水,自己做本次实验也是基于之前代码,有很多坑都可以避免到,不必重复造轮子。

软件RT-Thread Studio下配置STM32F4xx串口uart2和uart4发送数据-基础样例

(6)步骤说明

那么可以说回本次实验了,如果看到这里,那么默认你会使用RT-Thread Studio这款软件,能单独使用串口发出数据了。

具体使用ringbuffer步骤,共计6步:

  1. 命名初始化结构体
    在这里插入图片描述

  2. 调用初始化函数
    在这里插入图片描述

  3. 往里存数据函数
    在这里插入图片描述

  4. 往外读取数据函数,在函数内部
    在这里插入图片描述

  5. 发送走
    在这里插入图片描述

以上就是具体步骤了,接下来我们将配合代码具体说明

(7) 代码细节

如下,为本次测试主要功能代码了,因为要使用uart4发送数据,所以留了uart4的配置

/*
 * Copyright (c) 2006-2022, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2022-01-03     RT-Thread    first version
 */

#include <rtthread.h>
#define DBG_TAG "main"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>
//包含下文件。
#include "drivers/serial.h"
//>>>注意>>包含ringbuffer部分
#include <rtdevice.h>

rt_thread_t u2_dev;
rt_thread_t u4_dev;

struct serial_configure u2_configs=RT_SERIAL_CONFIG_DEFAULT;
struct serial_configure u4_configs=RT_SERIAL_CONFIG_DEFAULT;

//>>>第一步 初始化结构体
#define UART4_TX_Buffer_Len  1024  //定义大小
rt_uint8_t uart4_tx_buffer[UART4_TX_Buffer_Len] = {0};
struct rt_ringbuffer uart4_txrb;


int main(void)
{
    rt_err_t ret=0;
//~~~//
//......
//~~~//
/uart4///
//第一步:找设备
//rt_err_t ret=0;
u4_dev =rt_device_find("uart4");
if (u4_dev==RT_NULL) {
    LOG_E("RT_device_find[uart4] failed ....\n ");
    return -EINVAL;
}
//第二步:找到了设备就打开设备
ret=rt_device_open(u4_dev, RT_DEVICE_FLAG_RDWR|RT_DEVICE_FLAG_INT_RX);
if (ret<0) {
    LOG_E("rt_device_open[uart2] failed ....\n ");
    return ret;
}
//第三步:打开了设备就控制 配置参数
rt_device_control(u4_dev, RT_DEVICE_CTRL_CONFIG, (void *)&u4_configs);
//第四步:使用uart2发送数据
rt_device_write(u4_dev, 0, "uart4 config...\n", rt_strlen("uart4 config...\n"));
rt_thread_delay(1000);

//ringbuffer测试


//>>>第二步 初始化
rt_ringbuffer_init(&uart4_txrb,uart4_tx_buffer,UART4_TX_Buffer_Len);

//>>>循环
while(1)
{
    //>>>第三步 向ringbuffer里写入数据
    rt_ringbuffer_put(&uart4_txrb,"uart4_ringbuffer_out", sizeof("uart4—ringbuffer_out"));
    rt_thread_delay(1000);
    //>>>第四步 构建一个函数从ringbuffer里面读出来
    fnUart4_ringbuffer_422_send_msg_handle();
    rt_thread_delay(1000);
}


return RT_EOK;

}

void fnUart4_ringbuffer_422_send_msg_handle(void)
{

    static rt_uint8_t Uart4read_len = 0;
    static rt_uint8_t uartx_msg_temp[UART4_TX_Buffer_Len];
     //>>>第五步读下,看看有没有数据
    Uart4read_len = rt_ringbuffer_data_len(&uart4_txrb);
     //有数据则进入
    if(Uart4read_len > 0)
    {
        //>>>读出来,放在零食数组内
        rt_ringbuffer_get(&uart4_txrb,uartx_msg_temp,Uart4read_len);
        //>>>>发走 这么做在多线程比较适用
        rt_device_write(u4_dev, 0, uartx_msg_temp, rt_strlen(uartx_msg_temp));
    }
}

(8) 踩坑细节

(1)找到自己目录下的文件配置,自己也是使用之前文章里dome-test代码进行调试的,下下来,一编译发现了错了,按照之前介绍的,配置好文件后,就没有了,所以配置着,配置不好很容易陷在这里。
在这里插入图片描述
(2)第一个就是在使用ringbuffer的时候,记得一定要包含头文件,否者会报如下错误。
在这里插入图片描述
包含如下。
在这里插入图片描述

(9) 代码链接

https://download.csdn.net/download/qq_22146161/85195223

(10) 后期验证

设备没有任何增加,所以还是使用串口读取数据,效果图如下。
在这里插入图片描述

(11) 后续说明

这里着只是说明ringbuff原理与初步使用,一般在并发和多线程中,会使用ringbuffer,并且“读-写”相互是不受影响的,但是在多个线程中“读-读”和“写-写”直接要考虑加锁的问题,避免同时访问,具体论述会再写一篇。

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2022-04-23 11:00:36  更:2022-04-23 11:00:51 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 3:37:17-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码