Arduino如何处理串行缓冲区溢出?


27

Arduino如何处理串行缓冲区溢出?它会丢弃最新的输入数据还是最旧的数据?缓冲区可以容纳多少个字节?

serial 

Answers:


13

对于硬件串行端口,您可以在HardwareSerial.cpp中看到缓冲区大小根据特定AVR上可用的RAM量而变化:

#if (RAMEND < 1000)
    #define SERIAL_BUFFER_SIZE 16
#else
    #define SERIAL_BUFFER_SIZE 64
#endif

对于SoftwareSerial.h中的软件串行端口,接收器缓冲区大小_SS_MAX_RX_BUFF定义为64个字节。在这两种情况下,它都会停止尝试在接收到的数据已满时将其插入队列中,因此您可以根据从队列中检索数据的方式来混合新旧数据。

理想情况下,最好确保始终以迅速的方式清空缓冲区以避免缓冲区填充。如果您的问题与阻塞主循环的其他代码有关,则也许看一下计时器并实现一个简单的状态机。


我得到的印象是,如果我将数据传输到Arduino,并且在Arduino端没有有效的数据“拉取器”,那么如果到达的数据量超出缓冲区的容量,则将其丢弃。你能确认吗?我天真地假设发送器将阻塞,直到可以用来保存数据的空间可用为止。
Kolban 2015年

我只是浏览了所有代码(在/usr/share/arduino/hardware/arduino/core/arduino/HardwareSer‌ial.cpp下),并可以确认您在这里写的内容。我唯一要补充的是,由于SRAM是2K(RAMEND> 1000),因此if语句在Nano或Uno上将始终使用64而不是16。因此,如果要扩大环形缓冲区的大小,可以更改它
SDsolar

5

接收

您可以从HardwareSerial的源中看到,如果传入字节找到环形缓冲区已满,则将其丢弃:

inline void store_char(unsigned char c, ring_buffer *buffer)
{
  int i = (unsigned int)(buffer->head + 1) % SERIAL_BUFFER_SIZE;

  // if we should be storing the received character into the location
  // just before the tail (meaning that the head would advance to the
  // current location of the tail), we're about to overflow the buffer
  // and so we don't write the character or advance the head.
  if (i != buffer->tail) {
    buffer->buffer[buffer->head] = c;
    buffer->head = i;
  }
}

我得到的印象是,如果我将数据传输到Arduino,并且在Arduino端没有有效的数据“拉取器”,那么如果到达的数据量超出缓冲区的容量,则将其丢弃。你能确认吗?

是的,它将被丢弃。除非您实施自己的软件,否则没有软件或硬件流控制。

但是,如果使用64字节的缓冲区并以(例如)9600波特接收数据,则每1.04 ms会得到一个字节,因此填充缓冲区需要66.6 ms。在16 MHz处理器上,您应该能够经常检查缓冲区以至于缓冲区不满。如果您现在不想处理数据,那么您真正要做的就是将数据从HardwareSerial缓冲区移到您自己的缓冲区中。

#if (RAMEND < 1000)检查中可以看出,具有1000字节以上RAM的处理器将获得64字节的缓冲区,而那些RAM较少的处理器将获得16字节的缓冲区。


正在发送

您写入的数据放置在相同大小的缓冲区(16或64字节)中。如果发送缓冲区是否已满,则发送代码“块”,等待中断以将下一个字节发送出串行端口。

如果中断被关闭,则将永远不会发生,因此您不会在中断服务程序内进行串行打印。


我相信您的工作能力提高了一个数量级:在9600波特时,您每〜0.1 ms会得到一个字节,因此填充缓冲区仅需6.6 ms。
埃里克·丹德

1
在9600波特下,您每秒可获得9600 。由于每个字节为10位(8个数据+ 1个起始位+ 1个停止位),因此每秒可获得960个字节。1/960 = 0.001042 s-每1.04毫秒一个字节。
尼克·加蒙

当然,位不是字节!感谢您的更正。
埃里克·丹德

因此,尼克,请为我回答:如果我有一个运行Python的Pi坐在ser.readline()上,等待作为数据记录器输入,并且它是由Arduino通过串行馈送的,以获取读数,然后将它们作为批处理发送给Tab分隔符,然后使用delay(120000),这样每两分钟就会批处理一次,Python内脏可能会立即读取每个字符,直到遇到换行符,这时它将整个行作为返回值释放。因此,即使我总共发送80个字符,我也不必担心Arduino缓冲区的大小,是吗?这是一个很好的假设吗?
SDsolar

是的,在这种情况下,发送缓冲区的大小无关紧要。较小的缓冲区会(稍微)减慢发送速度,但是如果您要进行较长的延迟,则不会在意。
尼克·加蒙
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.