CircularBuffer is a circular buffer template for Arduino. The template takes two parameters:
- the type of data to store
- the maximum number of items to store in the buffer
The buffer starts empty. Items are added to the end of the buffer and can be removed from the start of the buffer. If more items are added than there is room in the buffer, the oldest ones are overwritten.
Forward and reverse iterators are implemented to walk through all the items in the buffer. Forward iterators start with the oldest item in the buffer. Reverse iterators start with the newest item in the buffer. The iterators are children of the CircularBuffer class.
The circular buffer uses a fixed size array to store inserted items. It does no dynamic memory allocation.
Example
This example uses a circular buffer to monitor a switch between pin 3 and ground being closed. Most switches don’t turn on immediately but ‘bounce‘. The time of each bounce is stored in the circular buffer. The buffer is printed every few seconds.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
/* ***************************************************************************** * Demo for circular buffer. * Records the time-stamp for button pushes in a circular buffer and * periodically writes them to the serial port. * ***************************************************************************** */ #include "CircularBuffer.h" #include "ArduinoTimer.h" // The buffer which will hold button presses. We use the time stamp from // the micros timer to store the time a button press was registered. So // the buffer must store unsigned long values. Up to 20 button times // will be stored before old ones are overwritten. typedef CircularBuffer<unsigned long, 20> ButtonTimeBuffer; ButtonTimeBuffer ButtonTimes; // The pin that the button is connected to. The other side of the button // should be connected to ground. const int ButtonPin = 3; // The amount of time between writing out all the data in the circular buffer // and a timer to keep track if that amount of time has passed yet. const int PrintingPeriod = 10; // seconds ArduinoTimer PrintingTimer; void setup() { Serial.begin(9600); pinMode(ButtonPin, INPUT_PULLUP); } void loop() { bool ButtonPressed = digitalRead(ButtonPin) == 0; static bool WasPressed = false; if (ButtonPressed) { if (!WasPressed) { WasPressed = true; unsigned long CurrentTime = micros(); ButtonTimes.Add(CurrentTime); } } else { WasPressed = false; } if (PrintingTimer.TimePassed_Seconds(PrintingPeriod)) { for(ButtonTimeBuffer::ForwardIterator Iterator(ButtonTimes); Iterator.AtEnd() == false; Iterator.Next()) { Serial.print(Iterator.ItemNumber()); Serial.print('\t'); Serial.println(Iterator.CurrentValue()); } ButtonTimes.Clear(); } } |
Declaration
A circular buffer variable can be declared using:
CircularBuffer<unsigned long, 15> MyCircularBuffer
The first template parameter (between the < and >) sets the type of data that will be stored in the buffer. It can be a simple type (such as an int
, float
etc), or a complex type (class
or struct
).
The second parameter is the maximum number of items to store in the circular buffer.
Because the ForwardIterator
and ReverseIterator
are children of the CircularBuffer
, it may be helpful to use a type definition to save repeating the template parameters every time you want an iterator. Define a type for your buffer as follows:
typedef CircularBuffer<unsigned long, 15> MyCircularBufferType
.
Then create a buffer variable using:
MyCircularBufferType MyBuffer
and iterators as:
MyCircularBufferType::ForwardIterator MyIterator(MyBuffer);
MyCircularBufferType::ReverseIterator MyIterator(MyBuffer);
Circular Buffer Functions
ElementSize()
Returns the number of bytes used by each item stored in the buffer.
IsEmpty()
Returns true if the buffer contains no items, or false if it contains 1 or more items.
Add(data)
Adds the item data
to the end of the circular buffer. If the buffer is full, the oldest item in the buffer will be overwritten.
Head()
Returns the last value (the one most recently added) in the buffer.
Tail()
Returns the oldest value that is still in the buffer. It might not be the first item added if the buffer has already wrapped.
PopTail()
Removes the oldest value from the buffer.
DropRecords(RecordCount)
Removes RecordCount
items from the start of the buffer.
Clear()
Removes all items from the buffer.
MaxSize()
Returns the maximum number of items that can be stored in the buffer.
Dump(Destination)
Writes the content of the buffer to a print stream. For example, MyBuffer.Dump(Serial);
will write the content of the buffer to the serial port.
Iterator Functions
These functions are available for both forward and reverse iterators. Iterators are child classes of the CircularBuffer
. They are both created with a single parameter: the circular buffer to iterate over.
CurrentValue()
Returns the current iterator value. Undefined if AtEnd()
is true.
CurrentIndex()
Returns the current item number.
CurrentIndex()
Returns the position of the current item in the internal buffer.
Next()/Previous()
Moves the iterator to the next (ForwardIterator
) or previous (ReverseIterator
) item in the buffer, if it isn’t already at the end. If it is at the end, the iterator doesn’t move.
AtEnd()
Returns true if the iterator is at the end of the buffer and there are no more items to read.