STM32 UART串口环形缓冲区的实现思路和代码

2023-05-16

同名微信公众号“固件工人”同步发布的文章,欢迎同时关注,及时获取最新文章。

1.1 环形缓冲区的实现思路

单片机程序开发一般都会用到UART串口通信,通过通信来实现上位机和单片机程序的数据交互。通信中为了实现正常的收发,一般都会有对应的发送和接收缓存来暂存通信数据。这里使用环形缓冲区的方式来设计数据收发的缓存,即缓冲区溢出后,从缓冲区数组的起始索引处重新进行数据的存储,这样可以比较高效地使用缓冲区。

环形缓冲区的设计思路参考以下链接。

https://www.cnblogs.com/zengzy/p/5139582.html

核心思路摘抄如下。规定以下所有方案,在缓冲区满时不可再写入数据,缓冲区空时不能读数据。

常规数组环形缓冲区思路:

设缓冲区大小为N,队头out,队尾in,out、in均是下标表示。

  • 初始时,in = out = 0

  • 队头队尾的更新用取模操作,out = (out + 1) % N,in = (in + 1) % N

  • out == in表示缓冲区空,(in + 1) % N == out表示缓冲区满

  • 入队que[in] = value; in = (in + 1) % N;

  • 出队ret = que[out]; out = (out + 1) % N;

  • 数据长度 len = (in - out + N) % N

改进版数组环形缓冲区思路:

同样假设缓冲区大小为N,队头out,队尾in,out、in为数组下标,但数据类型为unsigned int。

  • 初始时,in = out = 0

  • 上调缓冲区大小N为2的幂,假设为M

  • 队头队尾更新不再取模,直接++out,++in

  • out == in表示缓冲区空,(in - out) == M表示缓冲区满

  • 入队que[in & (M - 1)] = value; ++in;

  • 出队ret = que[out & (M - 1)] ; ++out;

  • in - out表示数据长度

1.2 环形缓冲区的代码实现

本文对应的工程代码链接如下。该工程基于eclipse IDE开发,编译器使用arm-none-eabi-gcc,使用的硬件是STM32F429I-DISCO开发板。

https://download.csdn.net/download/goodrenze/85163032

根据以上的环形缓冲区设计思路,先定义缓存对应的结构体类型如下。

typedef struct _UartBuf_t
{
#if UART_RECORD_LOST_NUM
    uint32_t TxLostNum;
#endif
    uint8_t* TxBuf;
#if UART_BUF_SIZE_IS_2POW
    uint16_t TxIn;
    uint16_t TxOut;
    uint16_t TxSize;
#else
    int16_t TxIn;
    int16_t TxOut;
    int16_t TxSize;
#endif
​
#if UART_RECORD_LOST_NUM
    uint32_t RxLostNum;
#endif
    uint8_t* RxBuf;
#if UART_BUF_SIZE_IS_2POW
    uint16_t RxIn;
    uint16_t RxOut;
    uint16_t RxSize;
#else
    int16_t RxIn;
    int16_t RxOut;
    int16_t RxSize;
#endif
}UartBuf_t;

以上结构体中,UART_RECORD_LOST_NUM宏定义用于设置是否记录丢失的数据个数,UART_BUF_SIZE_IS_2POW宏定义用于设置收发缓存的长度是否是2的幂,如果缓存长度是2的幂,则缓存索引和长度使用无符号数,否则使用有符号数。TxBuf和RxBuf指针用于指向对应的发送和接收的缓存数组。

本例程的UART串口发送和接收都是用串口中断来实现的,串口中断处理函数的代码实现如下,只需要在对应的串口中断入口函数中调用该函数进行串口数据的收发处理即可。

// 以下环形缓冲区的设计思路参考以下链接:
// https://www.cnblogs.com/zengzy/p/5139582.html
void UartIrqService(USART_TypeDef* UartX, UartBuf_t* Buf)
{
  uint32_t SR = UartX->SR;
  uint32_t CR1 = UartX->CR1;
  uint32_t CR3 = UartX->CR3;
​
  UNUSED(CR3);
​
  while(SR & USART_SR_RXNE)
  {
#if UART_RECORD_LOST_NUM
    if(SR & USART_SR_ORE)
    {
      Buf->RxLostNum++;
    }
#endif
​
#if UART_BUF_SIZE_IS_2POW
    if ((Buf->RxIn - Buf->RxOut) != Buf->RxSize)
    {
      Buf->RxBuf[Buf->RxIn & (Buf->RxSize - 1)] = (uint8_t)(UartX->DR & (uint8_t)0x00FF);
      Buf->RxIn++;
    }
#else
    if (((Buf->RxIn + 1) % Buf->RxSize) != Buf->RxOut)
    {
      Buf->RxBuf[Buf->RxIn++] = (uint8_t)(UartX->DR & (uint8_t)0x00FF);
      Buf->RxIn %= Buf->RxSize;
    }
#endif
    else
    {
      Buf->RxBuf[Buf->RxIn] = (uint8_t)(UartX->DR & (uint8_t)0x00FF);
#if UART_RECORD_LOST_NUM
      Buf->RxLostNum++;
#endif
    }
​
    SR = UartX->SR;
  }
​
  if((SR & USART_SR_TXE) && (CR1 & USART_CR1_TXEIE))
  {
    if(Buf->TxIn != Buf->TxOut)
    {
#if UART_BUF_SIZE_IS_2POW
      UartX->DR = (uint8_t)(Buf->TxBuf[Buf->TxOut & (Buf->TxSize - 1)] & (uint8_t)0x00FF);
      Buf->TxOut++;
#else
      UartX->DR = (uint8_t)(Buf->TxBuf[Buf->TxOut++] & (uint8_t)0x00FF);
      Buf->TxOut %= Buf->TxSize;
#endif
    }
    else
    {
      CLEAR_BIT(UartX->CR1, USART_CR1_TXEIE);
    }
  }
}

以上代码就是上面提到的环形缓冲区思路的具体实现。当缓冲区的数据长度是2的幂的时候,可以省去求余的运算,可以提高代码的执行速度。所以如果要求代码的执行时间尽量短,可以考虑将缓冲区的长度设置成2的幂。

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

STM32 UART串口环形缓冲区的实现思路和代码 的相关文章

随机推荐

  • 【python视图2】基于networkx的10个绘图技巧

    目录 一 说明 二 简单图操作种种 2 1 简单的无向图 2 2 简单的有向图 2 3 二维网格grid图 和边数据读写 2 4 环图 2 5 全连接神经网络 2 6 分布直方图 度秩图 连同子图 2 7 随机生成 2 8 渐变颜色化 2
  • ESP32控制TDC-GP22测量超声传播时间(超声流量计)

    TDC GP22控制的资料 xff0c 网上的资源都是基于STM32或者MSP430主控的 xff0c 但现在这两款芯片都太贵了 xff0c 因此就想用便宜点的ESP32 xff0c 折腾了快一周 xff0c 终于弄好了 工程源码和参考资料
  • 【python视图3】networkx图操作示例

    目录 一 说明 二 神奇制图 2 1 绘制彩虹图 2 2 随机地理图 2 3 旅行商问题 2 4 权重的灵活绘制 2 5 barabasi albert模型1 2 6 barabasi albert模型2 2 7 igraph操作 一 说明
  • 【python视图1】networkx操作Graph图

    目录 一 说明 二 生成图 xff08 Creating a graph xff09 2 1 创建一个没有节点和边的空图 2 2 在空图追加节点 2 3 追加边 xff08 Edges xff09 2 4 删除节点 2 5 查询 三 使用图
  • 【python】错误TypeError: ‘dict_values‘ object does not support indexing when的改出

    一 说明 在使用python的dict和索引时 xff0c 在早期的python可以 xff0c 但后来不可以了 因此 xff0c 在python执行语句 xff1a names i d values i for i in range le
  • 【Python知识】 可哈希和不可哈希对象

    目录 一 说明 二 可哈希 在Python中是什么意思 xff1f 2 1 什么是哈希 hashable xff1f 2 2 python的可哈希对象 2 3 实验和说明 2 4 什么是不可哈希 unhashable xff1f 三 更深的
  • 【python知识】推导式和生成器

    目录 一 说明 二 列表生成式 2 1 语法 2 2 列表推导式实例 三 字典的推导式 3 1 语法字典推导式 3 2 示例 四 集合推导式 4 1 集合推导的语法 4 2 实例 五 元组推导式 5 1 元组推导式基本格式 5 2 元组推导
  • 【python知识】运算符博览

    目录 目录 一 说明 二 基本数值运算符 2 1 基本运算符的列举 2 2 基本运算符的示例 2 3 复数基本运算符的示例 三 整数进制转化 3 1 进制转换运算符 3 2 实验代码和说明 四 整数按位运算 4 1 全部位运算符号 4 2
  • 【python知识】__init__.py的来龙去脉

    目录 一 说明 二 包 模块 函数结构 2 1 包 模块 函数的关系 2 2 init py的角色 2 3 识别包 三 init py的功效 3 1 建立一个工程包 3 2 用 init py简化工程包 3 3 过滤 3 4 设置顶级全局变
  • 【python知识】importlib包详解

    importlib The implementation of import Python 3 11 3 documentation 目录 一 说明 二 模块导入简介 2 1 最简单的 importlib用途 2 2 importlib 包
  • 【python】如何用conda更新软件的问题

    一 说明 在实现anancoda的软件更新问题 xff0c 需要明确几个问题 xff1a 1 xff09 是python包吗 xff1f 2 xff09 是C 43 43 包吗 xff1f 更新的方法有别 python包可以pip访问 C
  • 【射影几何08】仿射映射

    目录 一 说明 二 仿射映射 2 1 直线上的仿射映射定义 2 2 平面间的仿射映射定义 三 仿射不变性性质 四 平面到自身的透视仿射 五 透视仿射和透视映射的关系 5 1 射影透视变换和仿射的关系 5 2 仿射函数和线性函数的区别 一 说
  • 百度云python客户端bypy的上传命令(upload)

    命令 xff1a bypy upload localfile cloudfile 说明 xff1a 1 xff09 localfile为本地文件路径 2 xff09 cloudfile为云端文件路径 3 xff09 由于百度的限制 xff0
  • 【量化投资02】股票的概念知多少?(1)

    目录 一 说明 二 股票一般概念 nbsp 2 1 什么是股票 2 2 股票的类型
  • 【量化分析】用mplfinance显示交易图时,处理 Expect data.index as DatetimeIndex?

    目录 一 说明 二 程序代码和出错描述 三 合理化建议 3 1 读入数据时指定索引 3 2 读入数据后 xff0c 使用数据前指定日期 xff08 时间戳 xff09 索引 一 说明 我打算从比特币数据中获取烛台图 这是我在加载 csv 文
  • 【Win10错误】从0x80190001错误码恢复

    目录 一 说明 二 操作过程和错误显示 三 一个可行的修复过程 四 推荐的另一个修复过程 4 1 由控制面板进入 4 2 删除cooki 4 3 进入Tab 高级 gt 重置 4 4 运行命令重新启动后 xff1b 执行 xff1a 五 网
  • MySQL数据库的多种连接方式

    一 MySQl命令行客户端 在Mysql安装完成后 xff0c Mysql命令行会自动配置在计算机上 xff0c 在菜单中找到MySql 8 0 Command Line Client 输入密码即可进入 xff08 密码在安装过程中设定的
  • 如何在120行内实现一个有协程并支持tbus的服务器框架

    目前协程很火 xff0c 于是决定搞一个框架试试 xff0c 下面的代码很短 xff0c 不过麻雀虽小 xff0c 五脏俱全 目前支持tbus xff0c 配上boost asio xff0c 可以很容易的支持tcp udp 异步文件读写等
  • 基于深度学习的含未知复合故障多传感器信号故障诊断

    文章目录 目的网络实验结果存在的问题 CNN LSTM FCM 目的 1 未知复合故障诊断 2 复合故障解耦 网络 折叠层 xff1a 将输入的序列构建成测量数据帧 序列展开层 扁平化层 xff1a 恢复序列结构 输出矢量序列 卷积 xff
  • STM32 UART串口环形缓冲区的实现思路和代码

    同名微信公众号 固件工人 同步发布的文章 xff0c 欢迎同时关注 xff0c 及时获取最新文章 1 1 环形缓冲区的实现思路 单片机程序开发一般都会用到UART串口通信 xff0c 通过通信来实现上位机和单片机程序的数据交互 通信中为了实