Unexpected behavior with arrays

I have a simple program, I create a float array with 4 elements as a global variable and then at one point in the program I try to do different math functions i.e.

float temp = 5;
myArray[0] += temp;

But when I look using Serial.println(myArray[0]); it's always equal to zero.

The follow code

float temp = 5;
myArray[0] = temp;

will show that myArray[0] does equal 5 like you would expect and

myArray[0] = 5;
float temp = myArray[0];

Will also equal 5, but as soon as I do something like

myArray[0] = 5;
float temp = myArray[0];
temp += 5;

it will show temp as equaling zero.

My gut tells me that my array is not behaving like I think it should. That somehow instead of telling it to equal the actual value in myArray[0], I'm telling it to equal the memory location, and when I tell it to add 5 I'm moving it 5 indexies down the array line to some random memory address (which coincidently is zero). Can someone point me in the right direction here to make sure that I'm accessing the actual value stored in a specific index?

Please post all of your code.

#include <Wire.h>
#include <math.h>

#define I2C_ADDR 0x03 // Set I2C Address of Arduino
#define NUM_PROBES 2 // The maximum number of probes connected to the Arduino

#define PROBE1 14 // The One Wire Pin used for Probe 1
#define PROBE2 15 // The One Wire Pin used for Probe 2

#define COMMINTERVAL 140 // Time to wait in seconds before assuming there is a comm failure


float Temperature[2*NUM_PROBES]; // Each Probe stores two temperatures C and F
int CommCheck = 0; // used to check comm status between Arduino and Raspbery Pi
unsigned long LastComm = 0; // time (in millis) that last comm occured
int scanCount = 0; // Number of scans between readings, used to average temperature readings
int CommCounter = 0;

// Prepare program
void setup()
{
  Serial.begin(9600);
  Wire.begin(I2C_ADDR);
  Wire.onRequest(requestEvent); // Register i2c request handler
  
  for (int x = 0; x < 4; x++){
    Temperature[x] = 0;
  }
}

// Main program area
void loop()
{
  delay(250);
  
  commCheck();
  getTemp();
  
  delay(5000);
}


// Function sends current conents of temperature readings
void requestEvent()
{
  for (int x = 0; x < (NUM_PROBES*2); x++) {
    Temperature[x] /= scanCount;
    Serial.print("Temp #");Serial.print(x);Serial.print(": ");Serial.println(Temperature[x]);
  }
  
  Wire.write((byte*) &Temperature[0], 2*NUM_PROBES*sizeof(float));
  CommCounter += 1;
  if (CommCounter >= 32766) {
    CommCounter = 0;
  }
  LastComm = millis();
  scanCount = 0;

    // Make sure all values are zero at the beginning of each loop
  for (int i = 0; i<4; i++)
  {
    Temperature[i] = 0.0;
  }
}

// Gets current values from temperature ADC and converts reading to temperature
void getTemp()
{
  float p1TempC = 0.0; 
  float p2TempC = 0.0;

  p1TempC = 25.0;
  float tempTemp = Temperature[0];

   tempTemp += p1TempC;  
    
    Temperature[0] = tempTemp;
    Temperature[1] += (p1TempC*1.8)+32;
    Temperature[2] += p2TempC;    
    Temperature[3] += (p2TempC*1.8)+32;
    
    for (int x = 0; x < 4; x++){
      Serial.println(Temperature[x]);
    }
    scanCount += 1;
}

// Basic check to see if communications are working between pi and arduino
// Does not check to see if data is actually transferred or if data is corrupted
void commCheck() {
  
  // Get the current up time, millis represents milliseconds elapsed since the arduino was turned on, 
  // it reaches its max value and rolls over back to 0 approximately every 49 days.
  unsigned long currentTime = millis();
  
  // Check to see if milliseconds have rolled over to zero since the last comm occured
  if (currentTime < LastComm) {
   LastComm = currentTime; 
  }  
  Serial.println(LastComm);
  Serial.println(currentTime);
  // If the CommCheck does not equal the CommCounter then there was a comm request, update the CommCheck variable
  if (CommCheck != CommCounter) {
    CommCheck = CommCounter;
  // Otherwise, check to see if the time between comms has been greater than the comm time out variable
  } else {
    if ((currentTime - LastComm) > (COMMINTERVAL * 1000)) {

    } else {

    }
  }
}
  Wire.onRequest(requestEvent); // Register i2c request handler

...

// Function sends current conents of temperature readings
void requestEvent()
{
  for (int x = 0; x < (NUM_PROBES*2); x++) {
    Temperature[x] /= scanCount;
    Serial.print("Temp #");Serial.print(x);Serial.print(": ");Serial.println(Temperature[x]);
  }

Don't do serial prints inside an ISR.


float Temperature[2*NUM_PROBES]; // Each Probe stores two temperatures C and F

Since you share Temperature between and ISR and a not-ISR it should be declared volatile.


  for (int x = 0; x < 4; x++){
    Temperature[x] = 0;
  }

Prefer:

  for (int x = 0; x < (2*NUM_PROBES); x++){
    Temperature[x] = 0;
  }

Are these the lines?

  float p1TempC = 0.0;
  float p2TempC = 0.0;

  p1TempC = 25.0;
  float tempTemp = Temperature[0];

   tempTemp += p1TempC; 
   
    Temperature[0] = tempTemp;

Can you print before and after? Just to prove what you are saying. And post the output here?

The Serial.println in the ISR was just for my diagnostic purposes as were the hard coded for loop limits, don't worry :wink:

So I added 4 println statements such that the end code looks like this:

  float p1TempC = 0.0;
  float p2TempC = 0.0;

  p1TempC = 25.0;
  Serial.println(p1TempC);
  
  float tempTemp = Temperature[0];
  
  Serial.println(tempTemp);

   tempTemp += p1TempC;

   Serial.println(tempTemp);   
    Temperature[0] = tempTemp;

  Serial.println(Temperature[0];

The output is

25.0
0
0
0

As an interesting side note I did some printlns for my comm check section and I found that when I did my

COMMINTERVEAL * 1000

and got 8928 instead of 140000 like one would expect

and got 8928 instead of 140000 like one would expect

I wouldn't expect 1000 * 140 to fit in a 16 bit "int"

void setup()
{
  Serial.begin(9600);
  Wire.begin(I2C_ADDR);
  Wire.onRequest(requestEvent); // Register i2c request handler
 
  for (int x = 0; x < 4; x++){
    Temperature[x] = 0;
  }
}

The elements of "Temperature" are all already zero - no need for belt-and-braces.

Serial.println(Temperature[0];

Does that compile ?

UKHeliBob:

Serial.println(Temperature[0];

Does that compile ?

Sorry, that was a typo i made typing it in. In the arduino i have the closing )

abishur:
Sorry, that was a typo i made typing it in. In the arduino i have the closing )

Copy and paste is good. Retyping is not.

What version of the IDE are you using? Which Arduino are you using?

Adding 25 to 0 and getting 0 sounds like you have NaN.

I'm using the Arduino IDE version 1.0.1 on the Raspberry Pi

Actually Nick, don't worry about it, the statement you made about it acting like the values where NAN, got me looking through my code and yes, at one point I had accidentally set my array to empty data. I know it doesn't show it in the code, but like I said I had to type it in (I'm not able to copy/paste it from the IDE with the way things are set up between this computer and where I'm developing) and I missed that line :-[ :roll_eyes:

What I did to fix this problem, was to add a simple isnan(p1TempC) check before doing all my math stuff and it started working the way you'd expect. Thanks so much!

at one point I had accidentally set my array to empty data.

What I did to fix this problem, was to add a simple isnan(p1TempC) check before doing all my math stuff

Why not just remove the code that set the array to empty data ?

Because the end application will be I take a set of readings from some probes and the code here is just me fleshing things out and testing functionality. If I ask for a temperature reading and it doesn't have one yet (such as in the event of an initial power on) I don't want a bunch of bad data messing up my code. So a simple isnan check confirms that the data is at least not blatantly bad.

abishur:
... at one point I had accidentally set my array to empty data. I know it doesn't show it in the code, ...

A while back we noticed that NaN was printing as zero, and suggested that the library be changed to show NaN and Inf where applicable. That early version of the IDE probably does not do that.

@Nick: Any problem with:

    Temperature[x] = 0;

when Temperature[] is a float? Should it be "0.0"? I would do it that way if for no other reason than documentation.

I think a float zero and an int zero are the same thing here. I suppose you could make it 0.0, but then you'll get people doing:

unsigned long counter = 0UL;
long foo = 0L;

And so on. Zero is zero, I don't bother dressing it up usually myself.

Egads...I do both of those! I understand when it's zero, but doing it consistently makes you also do it when the constant is non-zero; something that can cause problems in mixed-type expressions. I also do explicit casts when the compiler will do a silent cast for me. And, as I said before, such things do document your intentions.

I'm wary of unnecessary explicit casts, because one day you will cast something to a type you didn't mean, and you have just done away with a compiler warning or error.

@Nick:

I'm guessing you dream in C++.