2

I am having an issue that I can't seem to get my head wrapped around. What I am trying to accomplish is to have a minutes worth of sensor data in an array (reading every 5 seconds) so I'll have 12 values in this after one minute.

I want to keep the array to 12 values so I need to keep moving all the values in it down one index per new value hitting index [0] to make sure that each reading has a lifetime of 60 seconds on the array. Here is my code so far:

void add_readings_to_averages() {
  // At this point, I am moving values down the array to make room at the beginning.
  for (int a = 11; a >= 0; a--) {
    Serial.print("The value at temperature_c_minute_avg[");
    Serial.print(a);
    Serial.print("] is ");
    Serial.print(temperature_c_minute_avg[a]);
    Serial.println();
    if (a == 11) {
      Serial.println("At 12 so need to overwrite this value");
    }

    if (a <= 10) {
      Serial.print("a is ");
      Serial.println(a);
      temperature_c_minute_avg[a] = temperature_c_minute_avg[a + 1];  // This moves each entry down one index in the array creating an empty space at index[0]
    }

    if (a == 0) {
      temperature_c_minute_avg[a] = temperature_c;
    }
  }

I've loaded my array at the time of initialization with some dummy data so I could see what was going on. First run displays as you would expect.

The value at temperature_c_minute_avg[11] is 120.00
At 12 so need to overwrite this value
The value at temperature_c_minute_avg[10] is 110.00
a is 10
The value at temperature_c_minute_avg[9] is 100.00
a is 9
The value at temperature_c_minute_avg[8] is 90.00
a is 8
The value at temperature_c_minute_avg[7] is 80.00
a is 7
The value at temperature_c_minute_avg[6] is 70.00
a is 6
The value at temperature_c_minute_avg[5] is 60.00
a is 5
The value at temperature_c_minute_avg[4] is 50.00
a is 4
The value at temperature_c_minute_avg[3] is 40.00
a is 3
The value at temperature_c_minute_avg[2] is 30.00
a is 2
The value at temperature_c_minute_avg[1] is 20.00
a is 1
The value at temperature_c_minute_avg[0] is 10.00
a is 0
2018/11/2 11:4:39  -  Running for a total of 0 hours 0 minutes and 7         seconds

But the second time through the loop() my array is trashed.

The value at temperature_c_minute_avg[11] is 120.00
At 12 so need to overwrite this value
The value at temperature_c_minute_avg[10] is 120.00
a is 10
The value at temperature_c_minute_avg[9] is 120.00
a is 9
The value at temperature_c_minute_avg[8] is 120.00
a is 8
The value at temperature_c_minute_avg[7] is 120.00
a is 7
The value at temperature_c_minute_avg[6] is 120.00
a is 6
The value at temperature_c_minute_avg[5] is 120.00
a is 5
The value at temperature_c_minute_avg[4] is 120.00
a is 4
The value at temperature_c_minute_avg[3] is 120.00
a is 3
The value at temperature_c_minute_avg[2] is 120.00
a is 2
The value at temperature_c_minute_avg[1] is 120.00
a is 1
The value at temperature_c_minute_avg[0] is 0.00
a is 0
2018/11/2 11:4:44  -  Running for a total of 0 hours 0 minutes and 12     seconds

The entire array was overwritten with the last value and the new value was not added. The array itself is setup as a global variable. The initialization at the top.

float temperature_c_minute_avg[12] = {10.0,20.0,30.0,40.0,50.0,60.0,70.0,80.0,90.0,100.0,110.0,120.0};

What am I missing here? Been staring at this for some time, but this is the first time I've tried to use an Arduino array so I can totally believe the issue is PBKAC! :)

2

Your issue is a C programming issue and has nothing to do with the Arduino specifically. You should research how to implement a circular buffer. You don't want to move around the values within the array, but rather just increment array index values. Keep two index values, one of the current index position (the place where the next recorded value will be placed) and another of the number of values recorded. Eventually the number of values recorded will be equal to your maximum array size and only the index position will increment. When the array index exceeds the maximum array size it wraps back to 0.

  • Guys, thanks for the assistance. I've gone down the path of a circular buffer to solve this. – Craig Nov 2 '18 at 21:25
1

To expand on Jeff Wahaus's answer, a quick google search turns up several circular buffer libraries for Arduino. I downloaded the first one on the list, github rlogiacco CircularBuffer, and made a simple sketch to test some of it's functionality.

#include <CircularBuffer.h>

CircularBuffer<unsigned int, 12> buffer;

byte counter = 0;

void setup(){
  Serial.begin(9600);
}

void loop(){

  // Add the next reading to the "head" of the buffer.
  buffer.unshift(counter);

  // Sensor data simulation.
  counter += 10;
  if(counter > 254){counter = 1;}

  // Non-destructive read. Gives you the last reading stored.
  if(!buffer.isEmpty()){
    Serial.println(buffer.first());
  }

  delay(500);
}

Using the unshift() function, you can repeatedly add to the beginning of the buffer and it will automatically "forget" the last item in the buffer once its full. I'm using the first() function to see whats in the first buffer location (the latest reading). If you wanted to retrieve all of the readings stored, you could use the shift() function and loop through the items in the buffer until it is empty. There are plenty of functions included with this library to interact with the buffer, such as, isEmpty(), isFull(), size(), available(), capacity(), clear().

EDIT

You could also use an array to store the readings. Take a look at the output of this sketch.

byte arrayIndex = 0;
const byte arraySize = 12;
float temperature_c_minute_avg[arraySize] = {0.0};

// Simulate sensor data.
float counter = 10.0;

void setup(){
  Serial.begin(9600);
}

void loop(){

  // Add a reading to the array.
  temperature_c_minute_avg[arrayIndex] = counter;

  // Test output: Print out the array's contents.
  Serial.print("Array index = ");
  Serial.println(arrayIndex);
  for(byte i = 0; i < arraySize; i++){
    Serial.print("temperature_c_minute_avg[");
    Serial.print(i);
    Serial.print("] = ");
    Serial.println(temperature_c_minute_avg[i]);
  }
  Serial.println();

  // Update array index.
  arrayIndex++;
  if(arrayIndex > (arraySize - 1)){arrayIndex = 0;}

  // Simulate sensor data.
  counter += 10.0;
  if(counter > 2400.0){counter = 0.0;}
  delay(1000);

}

Right after you add a reading to the array, it becomes the "latest reading". It's index will be temperature_c_minute_avg[arrayIndex] until you update the array index at the end of the loop(). To retrieve all of the readings from the array, you could use a for loop that executes 12 times as specified in the arraySize variable, and starts at the arrayIndex. You can decrement the arrayIndex in the for loop. Keep in mind, that you can't use negative numbers to access an array index, so you'll have to reset the index in the for loop to arraySize - 1, before it goes negative.

0

In your if (a <= 10) block, you are inside a for loop that is decreasing and replacing each value with the value inside index+1. This means that as you are going down the indices, you are carrying the 11th index value with you. Here is how it is without variables (allow me to shorten the variable name to t):

t[10] = t[11];
t[9] = t[10];
t[8] = t[9];

And so forth. Whatever was in a[11] is being dragged through each of the variables of lower indices.

I strongly suggest going the other way around with either your loop or which way you are pushing the data. For instance (continuing with array name t):

for (int i = 11; i >=0; i--) {
    if (i > 0)
        t[i] = t[i-1]; // shift data from index 10->11, 9->10, etc.
}
t[0] = arbitrary_data; // fill in new 'empty' space

Or, alternatively if you still want to put new data in index 11:

for (int i = 0; i <= 11; i++) {
    if (i < 11)
        t[i] = t[i+1]; // shift data from index 1->0, 2->1, etc.
}
t[i] = arbitrary_data; // fill in new 'empty' space

This is my solution for your current data management method. Another answer suggested a circular buffer where you simply keep track of which datum is being changed at a time and is far more efficient.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.