STM32进阶之串口环形缓冲区实现(转载)

2023-05-16

转载自微信公众号“玩转单片机”,感谢原作者“杰杰”。

队列的概念

在此之前,我们来回顾一下队列的基本概念:队列 (Queue):是一种先进先出(First In First Out ,简称 FIFO)的线性表,只允许在一端插入(入队),在另一端进行删除(出队)。

 

队列的特点

类似售票排队窗口,先到的人看到能先买到票,然后先走,后来的人只能后买到票


队列的常见两种形式

在计算机中,每个信息都是存储在存储单元中的,比喻一下吧,上图的一些小正方形格子就是一个个存储单元,你可以理解为常见的数组,存放我们一个个的信息。

 

当有大量数据的时候,我们不能存储所有的数据,那么计算机处理数据的时候,只能先处理先来的,那么处理完后呢,就会把数据释放掉,再处理下一个。那么,已经处理的数据的内存就会被浪费掉。因为后来的数据只能往后排队,如过要将剩余的数据都往前移动一次,那么效率就会低下了,肯定不现实,所以,环形队列就出现了。

它的队列就是一个环,它避免了普通队列的缺点,就是有点难理解而已,其实它就是一个队列,一样有队列头,队列尾,一样是先进先出(FIFO)。我们采用顺时针的方式来对队列进行排序。

 

队列头 (Head) :允许进行删除的一端称为队首。

队列尾 (Tail) :允许进行插入的一端称为队尾。

 

环形队列的实现:在计算机中,也是没有环形的内存的,只不过是我们将顺序的内存处理过,让某一段内存形成环形,使他们首尾相连,简单来说,这其实就是一个数组,只不过有两个指针,一个指向列队头,一个指向列队尾。指向列队头的指针(Head)是缓冲区可读的数据,指向列队尾的指针(Tail)是缓冲区可写的数据,通过移动这两个指针(Head) &(Tail)即可对缓冲区的数据进行读写操作了,直到缓冲区已满(头尾相接),将数据处理完,可以释放掉数据,又可以进行存储新的数据了。

 

实现的原理:初始化的时候,列队头与列队尾都指向0,当有数据存储的时候,数据存储在‘0’的地址空间,列队尾指向下一个可以存储数据的地方‘1’,再有数据来的时候,存储数据到地址‘1’,然后队列尾指向下一个地址‘2’。当数据要进行处理的时候,肯定是先处理‘0’空间的数据,也就是列队头的数据,处理完了数据,‘0’地址空间的数据进行释放掉,列队头指向下一个可以处理数据的地址‘1’。从而实现整个环形缓冲区的数据读写。

 

看图,队列头就是指向已经存储的数据,并且这个数据是待处理的。下一个CPU处理的数据就是1;而队列尾则指向可以进行写数据的地址。当1处理了,就会把1释放掉。并且把队列头指向2。当写入了一个数据6,那么队列尾的指针就会指向下一个可以写的地址。

 

如果你懂了环形队列,那就跟着歌曲来一步步用代码实现吧:

 

从队列到串口缓冲区的实现

 

串口环形缓冲区收发:在很多入门级教程中,我们知道的串口收发都是:接收一个数据,触发中断,然后把数据发回来。这种处理方式是没有缓冲的,当数量太大的时候,亦或者当数据接收太快的时候,我们来不及处理已经收到的数据,那么,当再次收到数据的时候,就会将之前还未处理的数据覆盖掉。那么就会出现丢包的现象了,对我们的程序是一个致命的创伤。

 

那么如何避免这种情况的发生呢,很显然,上面说的一些队列的特性很容易帮我们实现我们需要的情况。将接受的数据缓存一下,让处理的速度有些许缓冲,使得处理的速度赶得上接收的速度,上面又已经分析了普通队列与环形队列的优劣了,那么我们肯定是用环形队列来进行实现了。下面就是代码的实现:

 


  1 //①定义一个结构体:
  2 
  3 typedef struct
  4 {
  5     u16 Head;
  6     u16 Tail;
  7     u16 Lenght;
  8     u8 Ring_Buff[RINGBUFF_LEN];
  9 } RingBuff_t;
 10 
 11 RingBuff_t ringBuff;//创建一个ringBuff的缓冲区
 12 
 13 //②初始化结构体相关信息:使得我们的环形缓冲区是头尾相连的,
 14 //并且里面没有数据,也就是空的队列。
 15 
 16 /**
 17 * @brief  RingBuff_Init
 18 * @param  void
 19 * @return void
 20 * @author 杰杰
 21 * @date   2018
 22 * @version v1.0
 23 * @note   初始化环形缓冲区
 24 */
 25 void RingBuff_Init(void)
 26 {
 27     //初始化相关信息
 28     ringBuff.Head = 0;
 29     ringBuff.Tail = 0;
 30     ringBuff.Lenght = 0;
 31 }
 32 //初始化效果如下:
 33 
 34 
 35 //写入环形缓冲区的代码实现:
 36 
 37 /**
 38 * @brief  Write_RingBuff
 39 * @param  u8 data
 40 * @return FLASE:环形缓冲区已满,写入失败;    TRUE:写入成功
 41 * @author 杰杰
 42 * @date   2018
 43 * @version v1.0
 44 * @note   往环形缓冲区写入u8类型的数据
 45 */
 46 u8 Write_RingBuff(u8 data)
 47 {
 48     if(ringBuff.Lenght >= RINGBUFF_LEN) //判断缓冲区是否已满
 49     {
 50         return FLASE;
 51     }
 52     
 53     ringBuff.Ring_Buff[ringBuff.Tail]=data;
 54     
 55 //    ringBuff.Tail++;
 56     
 57     ringBuff.Tail = ( ringBuff.Tail + 1 ) % RINGBUFF_LEN;//防止越界非法访问
 58     ringBuff.Lenght++;
 59 
 60     return TRUE;
 61 }
 62 
 63 //读取缓冲区的数据的代码实现:
 64 
 65 /**
 66 * @brief  Read_RingBuff
 67 * @param  u8 *rData,用于保存读取的数据
 68 * @return FLASE:环形缓冲区没有数据,读取失败;TRUE:读取成功
 69 * @author 杰杰
 70 * @date   2018
 71 * @version v1.0
 72 * @note   从环形缓冲区读取一个u8类型的数据
 73 */
 74 u8 Read_RingBuff(u8 *rData)
 75 {
 76     if(ringBuff.Lenght == 0)//判断非空
 77     {
 78         return FLASE;
 79     }
 80     
 81     *rData = ringBuff.Ring_Buff[ringBuff.Head];//先进先出FIFO,从缓冲区头出
 82         
 83 //   ringBuff.Head++;
 84     ringBuff.Head = (ringBuff.Head + 1) % RINGBUFF_LEN;//防止越界非法访问
 85     ringBuff.Lenght--;
 86 
 87     return TRUE;
 88 }
 89 
 90 /* 对于读写操作需要注意的地方有两个:
 91 1:判断队列是否为空或者满,如果空的话,是不允许读取数据的,返回FLASE。如果是满的话,也是不允许写入数据的,避免将已有数据覆盖掉。那么如果处理的速度赶不上接收的速度,可以适当增大缓冲区的大小,用空间换取时间。
 92 2:防止指针越界非法访问,程序有说明,需要使用者对整个缓冲区的大小进行把握。
 93 
 94 那么在串口接收函数中: */
 95 
 96 void USART1_IRQHandler(void)
 97 {
 98     if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //接收中断
 99     {
100         USART_ClearITPendingBit(USART1,USART_IT_RXNE);       //清楚标志位
101         Write_RingBuff(USART_ReceiveData(USART1));      //读取接收到的数据
102     }
103 }
104 
105 /* 测试效果
106 
107 测试数据没有发生丢包现象
108 
109 补充
110 对于现在的阶段,杰杰我本人写代码也慢慢学会规范了。所有的代码片段均使用了可读性很强的,还有可移植性也很强的。我使用了宏定义来决定是否开启环形缓冲区的方式来收发数据,移植到大家的代码并不会有其他副作用,只需要开启宏定义即可使用了。 */
111 
112 #define USER_RINGBUFF  1  //使用环形缓冲区形式接收数据
113 #if  USER_RINGBUFF
114 /**如果使用环形缓冲形式接收串口数据***/
115 #define  RINGBUFF_LEN          200     //定义最大接收字节数 200
116 #define  FLASE   1
117 #define  TRUE    0
118 void RingBuff_Init(void);
119 u8 Write_RingBuff(u8 data);
120 u8 Read_RingBuff(u8 *rData);
121 #endif
122 
123 //当然,我们完全可以用空闲中断与DMA传输,效率更高,但是某些单片机没有空闲中断与DMA,那么这种环形缓冲区的作用就很大了,并且移植简便。  

 

转载于:https://www.cnblogs.com/CodeWorkerLiMing/p/10738788.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

STM32进阶之串口环形缓冲区实现(转载) 的相关文章

  • c项目makefile多重定义错误

    这个问题是一个对应于创建的repexthis问题 在我的嵌入式 C 项目中 我有两个独立的板 我想为每个板创建两个 c 文件 master c 和 Slave c 其中包含自己的特定main 功能 我使用 stm32cumbemx 生成带有
  • 在 MCU 内部 FLASH 中从一个固件跳转到另一个固件

    我目前正在开发针对 STM32F030C8 的引导加载程序固件应用程序 我在分散文件中指定引导加载程序应用程序将占用主内存位置 0x08000000 到 0x08002FFF 扇区 0 到扇区 2 我还编写了一个主固件应用程序 存储在0x0
  • 优化 ARM Cortex M3 代码

    我有一个 C 函数 它尝试将帧缓冲区复制到 FSMC RAM 这些函数将游戏循环的帧速率降低至 10FPS 我想知道如何分析反汇编的函数 我应该计算每个指令周期吗 我想知道CPU把时间花在哪里 在哪个部分 我确信该算法也是一个问题 因为它的
  • 133-基于stm32单片机停车场车位管理系统Proteus仿真+源程序

    资料编号 133 一 功能介绍 1 采用stm32单片机 4位数码管 独立按键 制作一个基于stm32单片机停车场车位管理系统Proteus仿真 2 通过按键进行模拟车辆进出 并且通过程序计算出当前的剩余车位数量 3 将剩余的车位数量显示到
  • Push_back() 导致程序在进入 main() 之前停止

    我正在为我的 STM32F3 Discovery 板使用 C 进行开发 并使用 std deque 作为队列 在尝试调试我的代码 直接在带有 ST link 的设备上或在模拟器中 后 代码最终在 main 中输入我的代码之前在断点处停止 然
  • STM32F4 通过软复位跳转到引导加载程序,无需 BOOT0 和 BOOT1 引脚

    我问这个问题是因为可以在这里找到类似问题的答案 通过应用程序跳转到 STM32 中的引导加载程序 即从用户闪存在引导模式下使用引导 0 和引导 1 引脚 用户 JF002 JF002回答 当我想跳转到引导加载程序时 我在其中一个备份寄存器中
  • STM32用一个定时器执行多任务写法

    文章目录 main c include stm32f4xx h uint32 t Power check times 电量检测周期 uint32 t RFID Init Check times RFID检测周期 int main Timer
  • 物联网网关

    物联网网关是 连接物联网设备和互联网的重要桥梁 它负责将物联网设备采集到的数据进行处理 存储和转发 使其能够与云端或其它设备进行通信 物联网网关的作用是实现物联网设备与云端的无缝连接和数据交互 物联网网关功能 数据采集 物联网网关可以从物联
  • HAL库学习

    CMSIS简介 CMSIS Cortex Microcontroller Software Interface Standard 微控制器软件接口标准 由ARM和其合作的芯片厂商 ST NXP 软件工具厂商 KEIL IAR 共同制定的标准
  • [MM32硬件]搭建灵动微MM32G0001A6T的简易开发环境

    作为学习单片机的经典 自然是通过GPIO点亮LED 或者是响应按钮的外部中断例程 这我们看看SOP8封装的芯片MM32G0001A6T得引脚 除了VDD和GND固定外 我们可以使用PA14 PA1 PA13 PA15 PA2 PA3这六个G
  • 硬件基础-电容

    电容 本质 电容两端电压不能激变 所以可以起到稳定电压作用 充放电 电容量的大小 想使电容容量大 使用介电常数高的介质 增大极板间的面积 减小极板间的距离 品牌 国外 村田 muRata 松下 PANASONIC 三星 SAMSUNG 太诱
  • 跟着野火学FreeRTOS:第一段(任务定义,切换以及临界段)

    在裸机系统中 系统的主体就是 C P U CPU CP U 按照预先设定的程序逻辑在 m a i n
  • 1.69寸SPI接口240*280TFT液晶显示模块使用中碰到的问题

    1 69寸SPI接口240 280TFT液晶显示模块使用中碰到的问题说明并记录一下 在网上买了1 69寸液晶显示模块 使用spi接口 分辨率240 280 给的参考程序是GPIO模拟的SPI接口 打算先移植到FreeRtos测试 再慢慢使用
  • Freertos低功耗管理

    空闲任务中的低功耗Tickless处理 在整个系统运行得过程中 其中大部分时间都是在执行空闲任务的 空闲任务之所以执行 因为在系统中的其他任务处于阻塞或者被挂起时才会执行 因此可以将空闲任务的执行时间转换成低功耗模式 在其他任务解除阻塞而准
  • systick定时器

    systick定时器 文章目录 前言 一 前期疑惑 二 解答 1 关于systick是阻塞的吗 2 非阻塞 三 软件编写 总结 前言 这边记录systick相关知识点 一 前期疑惑 在学习systick志气啊 其实对于systick还是一脸
  • 核心耦合内存在 STM32F4xx 上可执行吗?

    尝试从 STM32F429s CCM 运行代码 但每当我命中 CCM 中的第一条指令时 我总是会遇到硬故障 并且 IBUSERR 标志被设置 该指令有效且一致 STM32F4xx 是否可能不允许从 CCM 执行 数据访问效果良好 alios
  • STM32内部时钟

    我对 STM32F7 设备 意法半导体的 Cortex M7 微控制器 上的时钟系统感到困惑 参考手册没有充分阐明这些时钟之间的差异 SYSCLK HCLK FCLK 参考手册中阅读章节 gt RCC 为 Cortex 系统定时器 SysT
  • 在 Contiki 程序中使用 malloc

    考虑以下 Contiki 程序 include
  • STM32F0、ST-link v2、OpenOCD 0.9.0:打开失败

    我在用着发射台 http www ti com ww en launchpad about htmlgcc arm none eabi 4 9 2015q2 为 STM32F0 进行编译 现在我想使用该集合中的 arm none eabi
  • 使用 STM32 USB 设备库将闪存作为大容量存储设备

    我的板上有这个闪存IC 它连接到我的STM32F04 ARM处理器 处理器的USB端口可供用户使用 我希望我的闪存在通过 USB 连接到 PC 时被检测为存储设备 作为第一步 我在程序中将 USB 类定义为 MSC 效果很好 因为当我将主板

随机推荐

  • HTTP认证之摘要认证——Digest(二)

    导航 HTTP认证之基本认证 Basic xff08 一 xff09 HTTP认证之基本认证 Basic xff08 二 xff09 HTTP认证之摘要认证 Digest xff08 一 xff09 HTTP认证之摘要认证 Digest x
  • 关于AD10如何输出自己想要的BOM表

    新年新开始 xff0c 过完年来上班 xff0c 脑子里面的东西很多又忘光了 xff0c 索性写下来做个备忘录 xff0c 今天为了输出一个自己想要的BOM表 xff0c 结果发现去年会弄的 xff0c 但是现在尴尬的又忘了怎么弄了 xff
  • authorization权限控制_shiro入门学习--授权(Authorization)|筑基初期

    写在前面 经过前面的学习 xff0c 我们了解了shiro中的认证流程 xff0c 并且学会了如何通过自定义Realm实现应用程序的用户认证 在这篇文章当中 xff0c 我们将学习shiro中的授权流程 授权概述 这里的授权指的是授予某一系
  • Spring Boot+Spring Security+JWT 实现 RESTful Api 认证(二)

    摘要 上一篇Spring Boot 43 Spring Security 43 JWT 实现 RESTful Api 认证 xff08 一 xff09 我们已经sql教程 实现了基本的登录和token认证接口 xff0c 但是这里有个问题
  • vmware vsphere各版本差别,及各套件差别

    最近要开始全面支持虚拟化了 xff0c 客户私有云环境用的多的为vmware vsphere xff0c 特地恶补下vmware vsphere的各个差别 首先是vSphere xff0c ESXi和vCenter 的区别 ESXi vSp
  • 第五周课程总结&试验报告(三)

    第五周课程总结 xff1a 一 xff1a String类 1 xff1a 实例化String对象 xff0c String可以采取直接赋值的方式进行操作 xff1b 2 xff1a 61 61 可以用来进行内容的比较 xff0c 但是单纯
  • CSS3 选择器

    CSS3 选择器 在 CSS 中 xff0c 选择器是一种模式 xff0c 用于选择需要添加样式的元素 34 CSS 34 列指示该属性是在哪个 CSS 版本中定义的 xff08 CSS1 CSS2 还是 CSS3 xff09 选择器例子例
  • JavaScript中使用typeof运算符需要注意的几个坑

    typeof是一个运算符 xff0c 它对操作数返回的结果是一个字符串 xff0c 有6种 只针对ES xff0c 不包含HOST环境对象 1 39 undefined 39 2 39 boolean 39 3 39 string 39 4
  • unity视频教程

    英雄联盟教程 http pan baidu com s 1i3rkMS9 密码 bv6r https pan baidu com share link shareid 61 2589856556 amp uk 61 371904234 li
  • 相册列表 鼠标悬停显示照片介绍

    lt DOCTYPE HTML PUBLIC 34 W3C DTD HTML 4 01 Transitional EN 34 34 http www w3 org TR html4 loose dtd 34 gt lt html gt lt
  • 图书管理系统(毕业论文)

    毕 业 设 计 论 文 题 目 xff1a 图书管理系统 院 系 xff1a 计算机学院 专 业 xff1a 软件技术 姓 名 xff1a XXX 指导教师 xff1a XX 2017年 10 月 23 日 1 引言 5 2 相关技术突破
  • C#中定义数组--字符串及数组操作

    一 一维 xff1a int numbers 61 new int 1 2 3 4 5 6 不定长 int numbers 61 new int 3 1 2 3 定长 二 多维 int numbers 61 new int 1 2 3 1
  • 迭代器分类

    输入迭代器 读 xff0c 不能写 xff1b 只支持自增运算 istream iterator 61 61 61 43 43 gt 输出迭代器 写 xff0c 不能读 xff1b 只支持自增运算 ostream iterator 43 4
  • VC++中隐藏代码

    1 引言 在VS编辑器中可以对类中的方法 注释等内容进行隐藏 xff0c 单击左侧的 号即可完成隐藏 xff0c 隐藏后变为 43 xff0c 单击 43 号可以将隐藏的代码展开 2 隐藏任意代码 如果想在编辑器中隐藏任意代码段 xff0c
  • 常见签名算法之SHA256withRSA

    概述 在https blog csdn net chinoukin article details 100934995章节中 xff0c 我介绍了用Hmac算法用于签名算法中的方法 xff0c 本章节中将对常见的签名算法 SHA256wit
  • httpclient4封装类与HttpParser封装类

    httpclient4封装类与HttpParser封装类 最近工作中需要做一个爬虫去抓取指定页面的一些内容 xff0c 准备使用HttpParser来解析页面结构 xff0c 顺便看了一下httpclient4 xff0c 可以将它们配合使
  • 【Linux操作系统分析】进程——进程切换,进程的创建和撤销

    1 进程 进程是程序执行时的一个实例 xff0c 可以把它看作充分描述程序已经执行到何种程度的数据结构的汇集 从内核的观点看 xff0c 进程的目的是担当分配系统资源 xff08 CPU时间 xff0c 内存等 xff09 的实体 xff0
  • C++中的.和::和:和->的区别

    在学习C 43 43 的过程中我们经常会用到 和 和 xff1a 和 gt xff0c 在此整理一下这些常用符号的区别 1 A B则A为对象或者结构体 xff1b 2 A gt B则A为指针 xff0c gt 是成员提取 xff0c A g
  • 通过Curl 对url进行encode操作

    最近做项目的时候 xff0c 通过 Gflags Reload 时候 发现对于某些value中包含 61 中文等字符的支持不够好 xff0c value被截断了 经过分析后 xff0c 发现程序对url切分是用 61 amp 为标准的 xf
  • STM32进阶之串口环形缓冲区实现(转载)

    转载自微信公众号 玩转单片机 xff0c 感谢原作者 杰杰 队列的概念 在此之前 xff0c 我们来回顾一下队列的基本概念 xff1a 队列 Queue xff1a 是一种先进先出 First In First Out 简称 FIFO 的线