Weird Results for a variable named "T9"

This seems like a truly bizarre problem. In trying to help with the question here, I made this little test app which works well to get temperatures from 3 DS18B20’s, except for the variable named T9. I have no idea how this could happen; The value of T9 always comes up as 0, but if I change it to B9 or S9 it works fine. I’ve changed it back and forth several times, retyped everything just to make sure, but I always get the same results. This is the code in the .ino (the full code is in my last post to the question I referenced above).

#include "Dallas.h"

float T1, T2, T3, T4, T5, T6, T7, T8, T9;
float* temps1[] = {&T1, &T2, &T3}; // group sensors by which pin they're connected to
float* temps2[] = {&T4, &T5, &T6};
float* temps3[] = {&T7, &T8, &T9};

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


void loop() {
    getTemperatures(*temps1, 3, D4, 0); // the last argument is used to select which array of addresses is used in the Dallas.cpp file
    getTemperatures(*temps2, 3, D4, 1);
    getTemperatures(*temps3, 3, D4, 2);
    
   if (T7>50) {
       Serial.printf(" T1 = %.1f  T2 = %.1f  T3 = %.1f", T1, T2, T3);
       Serial.println();
       Serial.printf(" T4 = %.1f  T5 = %.1f  T6 = %.1f", T4, T5, T6);
       Serial.println();
       Serial.printf(" T7 = %.1f  T8 = %.1f  T9 = %.1f", T7, T8, T9); // T9 always prints 0
       Serial.println();
       Serial.println();
   }
   
    delay(10000);
}

There’s nothing apparently unique about T9. I can move it in the array so it’s not last, and I still get 0. If I print out the value of temps3[2], which should be T9, I do get the correct temperature.

@Ric, who know’s what’s happening with T9, that is odd! you didn’t post the files with the getTemperatures() function, so it is hard to say…

As a side note, why not just create an extensible member function passing an array of structs so you don’t have to keep the sensor addresses (blindly) in the member function?

something like this, which you can adapt for your temperature functions:

byte tempSensor[][8] = {                         // Array of sensor ID's
  {0x28, 0xFF, 0x0D, 0x4C, 0x05, 0x16, 0x03, 0xC7},
  {0x28, 0xFF, 0x25, 0x1A, 0x01, 0x16, 0x04, 0xCD},
  {0x28, 0xFF, 0x89, 0x19, 0x01, 0x16, 0x04, 0x57},
  {0x28, 0xFF, 0x21, 0x9F, 0x61, 0x15, 0x03, 0xF9},
  {0x28, 0xFF, 0x16, 0x6B, 0x00, 0x16, 0x03, 0x08},
  {0x28, 0xFF, 0x90, 0xA2, 0x00, 0x16, 0x04, 0x76},
  {0x10, 0xE9, 0x6B, 0x0A, 0x03, 0x08, 0x00, 0xAC},
  {0x10, 0x44, 0x4E, 0x0B, 0x03, 0x08, 0x00, 0x1F}
};

struct Sensors {
  float T;
  byte address[8];
};

Sensors mySensors[8];

Sensors* bus1[] = {&mySensors[0], &mySensors[1], &mySensors[2], &mySensors[3]}; // group sensors by which pin they're connected to
Sensors* bus2[] = {&mySensors[4], &mySensors[5], &mySensors[6]};
Sensors* bus3[] = {&mySensors[7]};

void setup()
{
  Serial.begin(9600);
  for (int i = 0; i < 8; i++)
  {
    for (int j = 0; j < 8; j++)
    {
      mySensors[i].address[j] = tempSensor[i][j];
    }
  }
  
  
  myFunction(bus1, sizeof(bus1) / sizeof(bus1[0]));
  myFunction(bus2, sizeof(bus2) / sizeof(bus2[0]));
  myFunction(bus3, sizeof(bus3) / sizeof(bus3[0]));
  for(int i = 0; i < sizeof(mySensors)/sizeof(mySensors[0]); i++)
  {
    Serial.print("T");
    Serial.print(i);
    Serial.print("=");
    Serial.print(mySensors[i].T);
    Serial.print("; ");
  }
  Serial.println();
}

void loop()
{
  
}

void myFunction(struct Sensors** ptrArray, size_t size)  // pointer to array of pointers
{
  for (int i = 0; i < size; i++)
  {
    randomSeed(analogRead(A4));
    ptrArray[i]->T = float(random(32,100)); // just stuffing a number here for demonstration purposes
  }
  Serial.println("Bus elements addresses: ");  // you have access to the Sensors here 
  for (int i = 0; i < size; i++)
  {
    for (int j = 0; j < 8; j++)
    {
      Serial.print(ptrArray[i]->address[j], HEX);
      if (j < 7)  Serial.print(";");
      else  Serial.println();
    }
  }
}

outputs:

Do you get any warnings?
Could you try #undef T9?
When you renamed T9, have you renamed all the other T# accordingly?
Does this also happen in a sketch without any ext library?

When I read “T9”, I immediately thought “T9 keyboard” - coincidence?

Actually, the approach you suggest is one that I would prefer, and was working on (for my own self-education purposes), but I was specifically trying to come up with an approach that @FiDel was looking for, where you could access the temperatures directly from a variable name. My knowledge of C is still not up to the level that I would like; still trying to wrap my head around c arrays, pointers, pointers to pointers etc.

1 Like

Got it, we are all always learning! Maybe your function would look something like this:

const byte tempSensor[][8] = {                         // Array of sensor ID's
  {0x28, 0xFF, 0x0D, 0x4C, 0x05, 0x16, 0x03, 0xC7},
  {0x28, 0xFF, 0x25, 0x1A, 0x01, 0x16, 0x04, 0xCD},
  {0x28, 0xFF, 0x89, 0x19, 0x01, 0x16, 0x04, 0x57},
  {0x28, 0xFF, 0x21, 0x9F, 0x61, 0x15, 0x03, 0xF9},
  {0x28, 0xFF, 0x16, 0x6B, 0x00, 0x16, 0x03, 0x08},
  {0x28, 0xFF, 0x90, 0xA2, 0x00, 0x16, 0x04, 0x76},
  {0x10, 0xE9, 0x6B, 0x0A, 0x03, 0x08, 0x00, 0xAC},
  {0x10, 0x44, 0x4E, 0x0B, 0x03, 0x08, 0x00, 0x1F}
};

struct Sensors {
  float T;
  byte address[8];
};

Sensors mySensors[8];

Sensors* bus1[] = {&mySensors[0], &mySensors[1], &mySensors[2], &mySensors[3]}; // group sensors by which pin they're connected to
Sensors* bus2[] = {&mySensors[4], &mySensors[5], &mySensors[6]};
Sensors* bus3[] = {&mySensors[7]};

Sensors** bus[] = {bus1, bus2, bus3};

int busPin[3] = {2,3,4};
void setup()
{
  unsigned long startMillis = millis();
  Serial.begin(9600);
  for (int i = 0; i < 8; i++)
  {
    for (int j = 0; j < 8; j++)
    {
      mySensors[i].address[j] = tempSensor[i][j];
    }
  }
}

void loop()
{
  getTemp(bus1, sizeof(bus1) / sizeof(bus1[0]), busPin[0]);
  getTemp(bus2, sizeof(bus2) / sizeof(bus2[0]), busPin[1]);
  getTemp(bus3, sizeof(bus3) / sizeof(bus3[0]), busPin[2]);
  unsigned long endMillis = millis();
  for(int i = 0; i < sizeof(mySensors)/sizeof(mySensors[0]); i++)
  {
    Serial.print("T");
    Serial.print(i);
    Serial.print("=");
    Serial.print(mySensors[i].T);
    Serial.print("; ");
  }
  Serial.println();
  Serial.print("Sensor readings took ");
  Serial.print(endMillis - startMillis);
  Serial.println("milliseconds total.");
  Serial.println();
  delay(5000);
}

void getTemp(struct Sensors** ptrArray, size_t size, int pin)  // pointer to array of pointers
{
  ow_setPin(pin);
  int res;
  uint8_t subzero, cel, cel_frac_bits;
  ATOMIC_BLOCK()
  {
    DS18X20_start_meas( DS18X20_POWER_EXTERN, NULL ); //(Was DS18X20_POWER_PARASITE ) Asks all DS18x20 devices to start temperature measurement, takes up to 750ms at max resolution
  }
  delay(750);
  for(int i = 0; i < size; i++)
  {
    byte sensorAddress[8];
    memcpy(sensorAddress, ptrArray[i]->address, 8);
    ATOMIC_BLOCK()
    {
      res = DS18X20_read_meas(sensorAddress, &subzero, &cel, &cel_frac_bits);
    }
    if(res == DS18X20_OK)
    {
      char floatString[100];
      int frac = cel_frac_bits * DS18X20_FRACCONV;
      snprintf(floatString, sizeof(floatString), "%c%d.%04d", (subzero) ? "-" : "", cel, frac);
      ptrArray[i]->T = atof(floatString);
    }
  }
}

not compiled, not tested, but I think we are close.

BTW, did #undef T9 work to solve your problem?

No, I don’t get any warnings, and I didn’t change any of the other variable names, only T9. I tried #undef T9, and that didn’t make any difference. I’ve tried various other things as well. I can change the order that I call getTemperatures, so that I call it with temps3 first - same result. I can add a fourth array with variables T10, T11, and T12; that works fine, and T9 still returns 0. If after calling getTemperatures, I just give T9 a value (T9 = 65), then it prints that fine.

To further confound the mystery, if I only call getTemperatures on temps3, T9 prints the correct temperature. If I call it on temps2 and temps3, T9 prints correctly, but if I call it on temps1 and temps3, T9 prints 0.

A further update. I still get the same result in a test app that has no external library. In this case, the Dallas.cpp file is simple this,

#include "Dallas.h"

void getTemperatures(float temps[], int tempsCount, int pin, int select) {
  
    for (int i=0; i<tempsCount; i++) {
     
        temps[i] = 71.2;
  }
}

In this simple app, I tried T10, T11, T37, T100, T999 as variable names, and none of them worked, so it doesn’t seem to be anything specific to the T9 name. But, B10 works. X37 works. Something “T” specific??? But… T1000 works. So, it seems any name from T9 through T999 of the ones I’ve tested, doesn’t wok.

After Edit:

Where T9 is declared also makes a difference. If it is declared first in the line of variables, or on a separate line before I declare T1 through T8, then it works. If it is in any other position in the line of variables, or if it is declared in the line following the declaration of the other 8, it doesn’t work (prints out 0).

No, #undef T9 doesn’t change the outcome. The way I’m passing the array to the function does seem to matter. I’ve simplified the code, and put it all into one file. The code below as written gives me all the T9 weirdness, but if I change the calls to getTemps and the getTemps function to the commented out ones, then there is no problem any more.

float  T1, T2, T3, T4, T5, T6, T7, T8, T9;

float* temps1[] = {&T1, &T2, &T3}; 
float* temps2[] = {&T4, &T5, &T6};
float* temps3[] = {&T7, &T8, &T9};

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


void loop() {
    // getTemps(temps3, 3);
    // getTemps(temps1, 3); 
    // getTemps(temps2, 3);
    
    getTemps(*temps3, 3);
    getTemps(*temps1, 3);
    getTemps(*temps2, 3);
   
    Serial.printf(" T1 = %.1f  T2 = %.1f  T3 = %.1f", T1, T2, T3);
    Serial.println();
    Serial.printf(" T4 = %.1f  T5 = %.1f  T6 = %.1f", T4, T5, T6);
    Serial.println();
    Serial.printf(" T7 = %.1f  T8 = %.1f  T9 = %.1f", T7, T8, T9);
    Serial.println();
    Serial.println();
   
    delay(10000);
}

// void getTemps(float* temps[], int tempsCount) {
  
//     for (int i=0; i<tempsCount; i++) {
//         *temps[i] = 72.3;
//     }
// }

void getTemps(float temps[], int tempsCount) {
  
    for (int i=0; i<tempsCount; i++) {
        temps[i] = 72.3;
    }
}

Is the way I’m doing it wrong, or just not a good way? If wrong, it seems strange that it works most of the time, and that it should matter in which order I declare T1 through T9.

I tried both approaches in Xcode, and they both work there, so something seems to be specific for the Web IDE.

Getting arrays of pointers right like that tricky for sure.

Since the data in the arrays is small, how about making the arrays the main holders of data and making your T variables references to those array cells?

float temps1[3] = {0}; // This sets all values of the array to 0, no matter the size
float temps2[3] = {0};
float temps3[3] = {0};

float &T1 = temps1[0];
float &T2 = temps1[1];
float &T3 = temps1[2];

float &T4 = temps2[0];
float &T5 = temps2[1];
float &T6 = temps2[2];

float &T7 = temps3[0];
float &T8 = temps3[1];
float &T9 = temps3[2];

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


void loop() {
    getTemps(temps3, 3);
    getTemps(temps1, 3); 
    getTemps(temps2, 3);

    Serial.printf(" T1 = %.1f  T2 = %.1f  T3 = %.1f", T1, T2, T3);
    Serial.println();
    Serial.printf(" T4 = %.1f  T5 = %.1f  T6 = %.1f", T4, T5, T6);
    Serial.println();
    Serial.printf(" T7 = %.1f  T8 = %.1f  T9 = %.1f", T7, T8, T9);
    Serial.println();
    Serial.println();
   
    delay(10000);
}

void getTemps(float temps[], int tempsCount) {
  
    for (int i=0; i<tempsCount; i++) {
        temps[i] = 72.3;
    }
}

Actually, the arrays won’t be that small in the actual app that @FiDel is trying to make; my code is just a test app to show him a structure that will meet his needs. He has 30 sensors that will be divided into three buses. Anyway, the code (the commented out version) I have in my last post fixes the problem.

1 Like

Actually, it will be closer to 60 sensors:

We can show you how to use a Union to save space. I don't think that will be too big a concern.

Are you certain you want to Control all of that with one (WiFi) device?

@Ric/@FiDel , have either of you tried what I gave you above?

like this:

const byte tempSensor[][8] = {                         // Array of sensor ID's
  {0x28, 0xFF, 0x0D, 0x4C, 0x05, 0x16, 0x03, 0xC7},
  {0x28, 0xFF, 0x25, 0x1A, 0x01, 0x16, 0x04, 0xCD},
  {0x28, 0xFF, 0x89, 0x19, 0x01, 0x16, 0x04, 0x57},
  {0x28, 0xFF, 0x21, 0x9F, 0x61, 0x15, 0x03, 0xF9},
  {0x28, 0xFF, 0x16, 0x6B, 0x00, 0x16, 0x03, 0x08},
  {0x28, 0xFF, 0x90, 0xA2, 0x00, 0x16, 0x04, 0x76},
  {0x10, 0xE9, 0x6B, 0x0A, 0x03, 0x08, 0x00, 0xAC},
  {0x10, 0x44, 0x4E, 0x0B, 0x03, 0x08, 0x00, 0x1F}
};

struct Sensors {
  float T;
  byte address[8];
};

Sensors mySensors[8];

Sensors* bus1[] = {&mySensors[0], &mySensors[1], &mySensors[2], &mySensors[3]}; // group sensors by which pin they're connected to
Sensors* bus2[] = {&mySensors[4], &mySensors[5], &mySensors[6]};
Sensors* bus3[] = {&mySensors[7]};

Sensors** bus[] = {bus1, bus2, bus3};

int busPin[3] = {2,3,4};
void setup()
{
  unsigned long startMillis = millis();
  Serial.begin(9600);
  for (int i = 0; i < 8; i++)
  {
    for (int j = 0; j < 8; j++)
    {
      mySensors[i].address[j] = tempSensor[i][j];
    }
  }
}

void loop()
{
  getTemp(bus1, sizeof(bus1) / sizeof(bus1[0]), busPin[0]);
  getTemp(bus2, sizeof(bus2) / sizeof(bus2[0]), busPin[1]);
  getTemp(bus3, sizeof(bus3) / sizeof(bus3[0]), busPin[2]);
  unsigned long endMillis = millis();
  for(int i = 0; i < sizeof(mySensors)/sizeof(mySensors[0]); i++)
  {
    Serial.print("T");
    Serial.print(i);
    Serial.print("=");
    Serial.print(mySensors[i].T);
    Serial.print("; ");
  }
  Serial.println();
  Serial.print("Sensor readings took ");
  Serial.print(endMillis - startMillis);
  Serial.println("milliseconds total.");
  Serial.println();
  delay(5000);
}

void getTemp(struct Sensors** ptrArray, size_t size, int pin)  // pointer to array of pointers
{
  ow_setPin(pin);
  int res;
  uint8_t subzero, cel, cel_frac_bits;
  ATOMIC_BLOCK()
  {
    DS18X20_start_meas( DS18X20_POWER_EXTERN, NULL ); //(Was DS18X20_POWER_PARASITE ) Asks all DS18x20 devices to start temperature measurement, takes up to 750ms at max resolution
  }
  delay(750);
  for(int i = 0; i < size; i++)
  {
    byte sensorAddress[8];
    memcpy(sensorAddress, ptrArray[i]->address, 8);
    ATOMIC_BLOCK()
    {
      res = DS18X20_read_meas(sensorAddress, &subzero, &cel, &cel_frac_bits);
    }
    if(res == DS18X20_OK)
    {
      char floatString[100];
      int frac = cel_frac_bits * DS18X20_FRACCONV;
      snprintf(floatString, sizeof(floatString), "%c%d.%04d", (subzero) ? "-" : "", cel, frac);
      ptrArray[i]->T = atof(floatString);
    }
  }
}
1 Like

Thanks for your response again @BulldogLowell!
I am not experienced enough to judge about your proposal, but if it can improve the approach of my goal(s) I am ready to make any change you guys propose.
But I think it’s better to continue this development in the original thread, don’t we?
:+1: :older_man:

No judgement is needed. Rather, just try it!

You are right, I will move this over to the other post.