格式化打印到循环缓冲区

dcc*_*ter 5 c printf stm32 circular-buffer

我正在为STM32F3 mc(STM32F3-Discovery)编写嵌入式代码.我需要输出一些数据,UART和我的使用DMA此,因为这可以让我专注于传感器读取和数据处理,而不是等待字节传输完成.然而问题是我必须结合:

  1. 格式化输出(即来自printf的一些)
  2. 连续多次打印(在上一次打印完成之前发生)

所以我在想循环缓冲区.但我不认为我知道如何使sprintf尊重缓冲区的结束并继续写入缓冲区的开头.我当然可以创建另一个临时缓冲区,在那里打印,并逐字节复制,但它对我来说并不优雅.

jun*_*nix 2

一种解决方案可能是实现您自己的解决方案,sprintf该解决方案能够与环形缓冲区一起使用。不幸的是,这不会帮助您解决一个更基本的问题:如果您的环形缓冲区已满并且您调用了,您会做什么sprintf

如果您的内存情况可以承受,我建议您使用另一种解决方案来解决此问题:

这个想法基于两个缓冲区链接列表(一个列表用于空闲缓冲区,一个列表作为传输队列)。缓冲区大小相同,因此可以存储最坏情况长度的字符串。缓冲区构建一个简单的堆,其中分配/解除分配仅将元素从空闲列表或传输列表中出队/入队。

拥有相同大小的缓冲区可以保证您在动态分配内存时不会受到外部碎片效应(例如“棋盘”)的影响。为此工作构建自己的堆还可以让您完全控制可用于传输任务的总缓冲区大小。

我可以想象这个运行如下:

  1. 您从空闲列表中分配一个缓冲区来将数据渲染到其中。
  2. 使用渲染函数(例如 sprintf)渲染缓冲区中的数据
  3. 将要发送的数据追加到传输队列(必要时触发传输)

对于 DMA 传输,您处理传输结束 IRQ。在那里,您将刚刚传输的缓冲区移动到“空闲列表”,并为队列中的下一个缓冲区设置传输。

该解决方案不会是内存效率最高的,但运行时效率很好,因为您只写入内存一次,并且分配/释放只是在某处获取/存储指针。当然,您必须确保应用程序和分配/释放的 IRQ 之间不会出现竞争条件。

也许这个想法会给你带来解决你的需求的灵感。