iic通信原理_嵌入式硬件通信接口-使用RingBuffer处理数据(一)

文章首发于同名微信公众号:DigCore

欢迎关注同名微信公众号:DigCore,及时获取最新技术博文。

原文链接:https://mp.weixin.qq.com/s/W7QPHS4i6jkvCEYjnuUJlA

(说明:此处的文章从微信公众号拷贝而来,图片或者排版上可能存在一定的瑕疵,欢迎点击原文链接阅读)


前三节完整说明了UART的原理以及实现过程。

《嵌入式硬件通信接口协议-UART(一)协议基础》

《嵌入式硬件通信接口协议-UART(二)不同电气规范下的标准》

《嵌入式硬件通信接口协议-UART(三)快速使用串口及应用》

事实上UART只是一个传输层的协议。

在实际的项目使用中,往往是根据项目的具体需求,在以UART作为物理传输接口的通信方式上,自定义私有的应用层协议,这个应用层协议本质就是数据协议,并且对协议的解析和实现,都需要MCU对数据进行缓存、计算、校验、分析等操作。

说到缓存,在这先卖个关子……

估计大部分人首先想到的是,代码里定义个全局变量的缓存数组,然后从串口的接收寄存器读出数据,并逐个字节地写到缓存数组里,接完一包数据,执行数据分析……

这个想法是对的,逻辑是通的,但是……

多少字节是完整一包数据?

如果是中断接收,第一包收完还未来得及完全处理,有数据进来触发中断,又被写入缓存数组覆盖旧数据呢?

针对这问题,也许有人会想到,多定义几个缓存数组,数据包写满一个缓存数组则开始写到另一缓存数组,或者分析处理前先拷贝出来,再或者分析处理前关串口接收……

c62b095c72213c28438450b077efa2bb.png

说来说去,这样子倒腾数据,一包一包的拷来移去的,太没效率了,还想关中断,这样通信效率也太低了!

针对这里的缓存问题,引入一个经典: 循环缓冲区Circular buffer

有很多叫法:圆形缓冲区(器)、圆形队列…

如此经典,在互联网上的资料也是相当多了,中文版的介绍推荐使用百度百科进行搜索“环形缓冲器”,英文版推荐使用维基百科进行搜索“Circular
buffer”,在此不再赘述。

当你了解循环缓冲区之后,是不是早已磨刀霍霍地想马上敲代码?不着急,先到开源社区网站找一找,这里推荐GitHub。

好的开源项目,有人参与维护,还有人参与使用并给予反馈,使得项目代码更健壮。

到GitHub主页搜索“Circular buffer”找到相关项目,筛选C语言的项目:

c402ee6dd62dd8945f61b8b01c46153d.png

从搜索结果中看到,按照相关程度排序方式下,被星标收藏的项目最多的是“TPCircularBuffer”,点进去后发现它用于音频处理“A
simple, fast circular buffer implementation for audio
processing”,换个精简的来看吧。

返回搜索结果列表,点击第二个的“Ring-Buffer”,它的描述已经说明是用于嵌入式系统“A
simple ring buffer (circular buffer) designed for embedded
systems.”,眼看embedded就亲切,就用这项目参考。

f6c2f51d6d685ad3dceb6b5b34f39b6a.png

目测该项目确实有些久远了,最后一次commit已是两年前的2016年5月了。先不管,好酒也是有年份的!

下载到本地,打开项目文件夹,查看C文件和H文件。

88c371f8222633f8e2d65ddb5969dfd4.png

快速浏览ringbuffer.c文件中对外封装的各个函数,主要有:

  1. 循环缓冲区初始化
  2. 增加一个数据元素
  3. 增加多个数据元素
  4. 读取一个元素
  5. 读取多个元素
  6. 查看某一元素(即不读出,不改变读偏移量)。

从这个项目的“增加一个数据元素”函实现过程,可以看到

buffer->head_index = ((buffer->head_index + 1) & RING_BUFFER_MASK);

这条语句执行的结果是每新增一个元素,写的偏移量递增,并且达到RING_BUFFER_SIZE时又回到0,同样的在读操作中也是如此,这使得在读写元素的时候,偏移量都在缓冲区的范围内。

a75c465a53456ae71ca6c0c5ae45a692.png

事实上这个项目已经把循环缓冲区的基本功能已经设计完全了,基本的使用起来已经OK了。

在这里值得注意的是,源码中的ring_buffer_size_t是uint8_t类型,如果需要操作255个字节以上的内存空间,则需要把ring_buffer_size_t改成uint16_t或者uint32_t类型。

52b4004a91a59bc21e1778e7c30f9e35.png

源码的实现逻辑比较简单,完全可以根据网络的参考资料将这套源码吃透,有兴趣的可以拉下来看看,尝试移植到自己工程中使用。

毕竟是别人做的,但是为了符合自己工程中的需求,还是有必要重新设计自己的循环缓冲区功能处理模块。关于如何设计自己的循环缓冲区处理模块,敬请期待下回分解!

本来要讲数据协议的,写着写着又把环形缓冲区写的多了,关于起止式的数据协议,那就敬请期待下下回分解。

参考资料:

《Circular_buffer》@维基百科

https://en.wikipedia.org/wiki/Circular_buffer

《环形缓冲器》@百度百科

https://baike.baidu.com/item/%E7%8E%AF%E5%BD%A2%E7%BC%93%E5%86%B2%E5%99%A8

《Ring-Buffer》@Github

https://github.com/AndersKaloer/Ring-Buffer


★★★★★推荐文章

《【嵌入式编程】函数返回类型设计》

《【嵌入式编程】平台大小端存储差异解决办法》

《嵌入式硬件通信接口-使用RingBuffer处理数据(二)详细设计过程》

《嵌入式硬件通信接口-使用RingBuffer处理数据(一)》

《快速开发MQTT(一)电子工程师眼中的MQTT》

《快速开发MQTT(二)初识MQTT》

《MQTT客户端搭建-最清晰的MQTT协议架构》

《MQTT服务端搭建-最快方式验证自己开发的客户端》

★★★★★相似文章

《嵌入式硬件通信接口协议-UART(五)数据包设计与解析》

《嵌入式硬件通信接口协议-UART(四)设计起止式的应用层协议》

《嵌入式硬件通信接口协议-UART(三)快速使用串口及应用》

《嵌入式硬件通信接口协议-UART(二)不同电气规范下的标准》

《嵌入式硬件通信接口协议-UART(一)协议基础》

《嵌入式硬件通信接口协议-SPI(三)模拟接口应用》

《嵌入式硬件通信接口协议-SPI(二)分层架构设计模拟接口》

《嵌入式硬件通信接口协议-SPI(一)协议基础》

《嵌入式硬件通信接口协议-IIC(一)协议基础》

★★★★★扩展阅读

《【硬件电路】AltiumDesigner18规则检查含义》

《【硬件电路】N沟道、P沟道MOS管基本原理与应用案例》

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值