[SOLVED] How to read ds18b20 address from progmem?

Hi all,

I have some problems to read ds18b20 sensors addresses from progmem. I stored all the addresses into an array, and i call one by one each adress from the array to be readed by dallas temperature library. Everythings works perfect.
However, to save ram, i moved the array to flash memory by the use of progmem. Now, dallas temperature library is not able to read the addresses.

I know, i know, it is my fault, because to call a constant from RAM is different than from PROGMEM. And here is where i have the problem. I found in internet many examples about how to call arrays of strings, but not about arrays of bytes such as this i need.

This is how i declare the array:

const uint8_t PROGMEM sensors[17][8] ={
  {0x28,0xF0,0xF0,0x60,0x05,0x00,0x00,0x6F},
  {0x28,0x98,0xF1,0x60,0x05,0x00,0x00,0xC0},
  {0x28,0x64,0xED,0x60,0x05,0x00,0x00,0x92},
  {0x28,0x42,0x0D,0x61,0x05,0x00,0x00,0xC3},
  {0x28,0x22,0xA1,0x60,0x05,0x00,0x00,0x9D},
  {0x28,0xE2,0x7D,0x61,0x05,0x00,0x00,0xF2},
  {0x28,0xAA,0x6D,0x61,0x05,0x00,0x00,0x5A},
  {0x28,0xEA,0x01,0x61,0x05,0x00,0x00,0x1F},
  {0x28,0x7E,0xB2,0x60,0x05,0x00,0x00,0xFC},
  {0x28,0x41,0xFD,0x60,0x05,0x00,0x00,0xB3},
  {0x28,0x91,0x7E,0x61,0x05,0x00,0x00,0x7D},
  {0x28,0x31,0x25,0x61,0x05,0x00,0x00,0xC4},
  {0x28,0x55,0x1E,0x61,0x05,0x00,0x00,0x2F},
  {0x28,0x8D,0x97,0x60,0x05,0x00,0x00,0xFD},
  {0x28,0x13,0xF0,0x60,0x05,0x00,0x00,0x1F},
  {0x28,0xD3,0xF4,0x60,0x05,0x00,0x00,0x9F},
  {0x28,0xA7,0x09,0x61,0x05,0x00,0x00,0x1E}
};

And here is where i try to use it:

SensorsBus.requestTemperatures(); 
        for (byte d = 0; d < 21; d++) { 
          temp = SensorsBus[c].getTempC(Sensors[d]);
          datafile.print(temp);

Here is where i have the problem to read the addresses:

getTempC(Sensors[d])

If i remove “PROGMEM” command from the array declaration, it works. Evidently, i should use some other command to read the array from the flash memory.

Could you give me some tips about how to solve it?
Thanks!

Hello,

Look this page: ttp://www.arduino.cc/en/Reference/PROGMEM

Edit: I suppose you have problems reading from a multidimensional array? If so, here is a quick example:

for ( uint8_t i = 0; i < sizeof( sensors ) / sizeof( sensors[0] ); i++ )
{
  for ( uint8_t j = 0; j < sizeof( sensors[0] ); j++ )
  {
    Serial.print( pgm_read_byte( &sensors[i][j] ), HEX );
    Serial.print( " " );
  }
  Serial.println();
}

Thanks @Guix.
Yes, i was reading that and many other webpages about how to read from progmem. In fact, i clearly said in my first post that there are many examples about string arrays, but i was not able to apply to my case.

Thanks to your nice example, i solved some part of the problem.

Now, the case is a little more complex, because i do not have a unique array of ID, but 5 of them, connected by a pointer:

const PROGMEM byte sensorsnumber[5] = {1,21,1,1,17};                // Number of temperature sensors in each bus
boolean ActiveSensors[5] = {1,0,0,0,0};                             // Definition of active sensors on the device
const PROGMEM byte Precision = 12;                                  // DS18B20 precision configuration to 12 bits (0.0625ºC)

//  Sensors identification
const PROGMEM uint8_t airsensors[1][8] = {                           // Air temperature sensors
  {0x28,0x25,0x30,0x09,0x06,0x00,0x00,0x85}                          // Sensor at 160 cm heigth
};
const PROGMEM uint8_t snowsensors[21][8] = {                         // Snow temperature sensors
  {0x28,0xBC,0x0F,0x60,0x05,0x00,0x00,0xAE},                         // Sensor at 0 cm height
  {0x28,0xA2,0xF3,0x60,0x05,0x00,0x00,0x61},                         // Sensor at 2.5 cm height
  {0x28,0xE2,0xA8,0x60,0x05,0x00,0x00,0xF1},                         // Sensor at 5 cm height
  {0x28,0x46,0x10,0x61,0x05,0x00,0x00,0x8F},                         // Sensor at 10 cm height
  {0x28,0xB6,0xFF,0x60,0x05,0x00,0x00,0xC7},                         // Sensor at 20 cm height
  {0x28,0xC9,0xEF,0x60,0x05,0x00,0x00,0x07},                         // Sensor at 30 cm height
  {0x28,0xF9,0xF5,0x60,0x05,0x00,0x00,0x2B},                         // Sensor at 40 cm height
  {0x28,0x55,0xA4,0x60,0x05,0x00,0x00,0x52},                         // Sensor at 50 cm height
  {0x28,0xF5,0x70,0x5D,0x05,0x00,0x00,0x9A},                         // Sensor at 60 cm height
  {0x28,0xDD,0x74,0x60,0x05,0x00,0x00,0x47},                         // Sensor at 70 cm height
  {0x28,0xE3,0x96,0x60,0x05,0x00,0x00,0xE0},                         // Sensor at 80 cm height
  {0x28,0xD3,0xFB,0x60,0x05,0x00,0x00,0xF0},                         // Sensor at 90 cm height
  {0x28,0x1B,0xEA,0x60,0x05,0x00,0x00,0x7F},                         // Sensor at 100 cm height
  {0x28,0x1B,0xEA,0x60,0x05,0x00,0x00,0x7F},                         // Sensor at 110 cm height
  {0x28,0x67,0xB4,0x5F,0x05,0x00,0x00,0x7F},                         // Sensor at 120 cm height
  {0x28,0x1B,0xEA,0x60,0x05,0x00,0x00,0x7F},                         // Sensor at 130 cm height
  {0x28,0x6F,0x09,0x61,0x05,0x00,0x00,0x20},                         // Sensor at 140 cm height
  {0x28,0x1B,0xEA,0x60,0x05,0x00,0x00,0x7F},                         // Sensor at 150 cm height
  {0x28,0xDF,0x06,0x61,0x05,0x00,0x00,0x48},                         // Sensor at 160 cm height
  {0x28,0x1B,0xEA,0x60,0x05,0x00,0x00,0x7F},                         // Sensor at 170 cm height
  {0x28,0x1B,0xEA,0x60,0x05,0x00,0x00,0x7F},                         // Sensor at 180 cm height
};
const PROGMEM uint8_t BTSsensors[1][8] = {                           // Bottom Temperature of Snow Cover sensor
  {0x28,0x90,0xC1,0x0A,0x06,0x00,0x00,0x8A}                          // Sensor at 2 cm heigth
};
const PROGMEM uint8_t surfacesensors[1][8] = {                       // Surface temperatue sensors
  {0x28,0xFC,0x4F,0x20,0x05,0x00,0x00,0xD2}                          // Sensor at 1 cm depth  
};
const PROGMEM uint8_t groundsensors[17][8] ={                        // Ground temperature sensors
  {0x28,0xF0,0xF0,0x60,0x05,0x00,0x00,0x6F},                         // Sensor at 0 cm depth
  {0x28,0x98,0xF1,0x60,0x05,0x00,0x00,0xC0},                         // Sensor at 2.5 cm depth
  {0x28,0x64,0xED,0x60,0x05,0x00,0x00,0x92},                         // Sensor at 5 cm depth
  {0x28,0x42,0x0D,0x61,0x05,0x00,0x00,0xC3},                         // Sensor at 10 cm depth
  {0x28,0x22,0xA1,0x60,0x05,0x00,0x00,0x9D},                         // Sensor at 20 cm depth
  {0x28,0xE2,0x7D,0x61,0x05,0x00,0x00,0xF2},                         // Sensor at 30 cm depth
  {0x28,0xAA,0x6D,0x61,0x05,0x00,0x00,0x5A},                         // Sensor at 40 cm depth
  {0x28,0xEA,0x01,0x61,0x05,0x00,0x00,0x1F},                         // Sensor at 50 cm depth
  {0x28,0x7E,0xB2,0x60,0x05,0x00,0x00,0xFC},                         // Sensor at 60 cm depth
  {0x28,0x41,0xFD,0x60,0x05,0x00,0x00,0xB3},                         // Sensor at 70 cm depth
  {0x28,0x91,0x7E,0x61,0x05,0x00,0x00,0x7D},                         // Sensor at 80 cm depth
  {0x28,0x31,0x25,0x61,0x05,0x00,0x00,0xC4},                         // Sensor at 90 cm depth
  {0x28,0x55,0x1E,0x61,0x05,0x00,0x00,0x2F},                         // Sensor at 100 cm depth
  {0x28,0x8D,0x97,0x60,0x05,0x00,0x00,0xFD},                         // Sensor at 110 cm depth
  {0x28,0x13,0xF0,0x60,0x05,0x00,0x00,0x1F},                         // Sensor at 120 cm depth
  {0x28,0xD3,0xF4,0x60,0x05,0x00,0x00,0x9F},                         // Sensor at 130 cm depth
  {0x28,0xA7,0x09,0x61,0x05,0x00,0x00,0x1E}                          // Sensor at 140 cm depth
}; 
const uint8_t (*SensorsID[5])[8] = {airsensors, snowsensors, BTSsensors, surfacesensors, groundsensors};

Now, i am tryint to read each sensor inside this loop:

for (byte c = 0; c < 5; c++) {
      float temp;                                                     // Temporally store temperature data
      if (ActiveSensors[c] == HIGH){                                  // If the sensors bus is active...
        SensorsBus[c].requestTemperatures();                          // Request temperatures from that temperature bus
        for (byte d = 0; d < sensorsnumber[c]; d++) {                 // For each sensor in that temperature bus
          temp = SensorsBus[c].getTempC(SensorsID[c][d]);                          // Read temperature sensor
          datafile.print(temp);                                       // Save temperature data
          datafile.print(symbols[0]);                                 // Save divider symbol
          if ((temp == -127)||(temp == 85)){                          // Check for errors on the temperature sensor value
            e = 7 + c;                                                // Error #07: problems reading Air temperature sensors
          }
          delay(10);                                                  // Give time to save the data
        }
      }
      else {                                                          // If that sensors bus is not active...
        for (byte f = 0; f < sensorsnumber[c]; f++) {                 // For the expected number of sensors in that bus...
          datafile.print(symbols[4]);                                 // Save "Non available sensor" symbol
          datafile.print(symbols[0]);                                 // Save divider symbol
        }
      }
      delay(10);                                                      // Give time to save the data
    }

[Continue from previous post]

Then, now my problem is again how to call each sensor address here:

temp = SensorsBus[c].getTempC(SensorsID[c][d]);

Following your idea, i think that the process should be to declare a variable what is an empty array of 8 elements, and to copy there each address before it is readed from the flash memory, and then use this address to read the temperature.

In pseudocode, something like this:

unint8_t ID[8];
for (byte i = 0; i < 8; i++){
 ID[i] = pgm_read_byte(SensorsID[c][d][i];
}
temp = SensorsBus[c].getTempC(ID);

Evidently "pgm_read_byte(SensorsID

[d][i])" is not the correct way to call each byte of the array of arrays of arrays.

Whatis the correct way? I do not see how to figure it out.
Thanks!

SOLVED!!

After some more try-error, i get the solution:

for (byte d = 0; d < sensorsnumber[c]; d++) {                 // For each sensor in that temperature bus
          uint8_t ID[8];
          for (byte s = 0; s < 8; s++) {
            ID[s] = pgm_read_byte(&(SensorsID[c][d])[s]);
          }
          temp = SensorsBus[c].getTempC(ID);
          if ((temp == -127)||(temp == 85)){                          // Check for errors on the temperature sensor value
            e = 7 + c;                                                // Error #07: problems reading Air temperature sensors
          }
          temp += pgm_read_float(&SensorsOffset[c][d]);               // Correct the temperature data with the corresponding sensor offset
          datafile.print(temp);                                       // Save temperature data
          datafile.print(symbols[0]);                                 // Save divider symbol
          delay(10);                                                  // Give time to save the data
        }

These lines were the key:

uint8_t ID[8];
          for (byte s = 0; s < 8; s++) {
            ID[s] = pgm_read_byte(&(SensorsID[c][d])[s]);
          }

The problem/solution was a couple of parenthesis…

I hope the couple of weeks i spent tryint to solve could be useful to others interesting on use many sensors on different arrays, and save RAM!

You can read the addresses in advance

#include <OneWire.h>
OneWire  ds(3);  // Connect your 1-wire device to pin 3

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

void discoverOneWireDevices(void) {
  byte i;
  byte present = 0;
  byte data[12];
  byte addr[8];
  
  Serial.print("Looking for 1-Wire devices...\n\r");
  while(ds.search(addr)) {
    Serial.print("\n\rFound \'1-Wire\' device with address:\n\r");

    for( i = 0; i < 8; i++) {
      Serial.print("0x");
      if (addr[i] < 16) {
        Serial.print('0');
      }
      Serial.print(addr[i], HEX);

      if (i < 7) {
        Serial.print(", ");

      }
    }
    if ( OneWire::crc8( addr, 7) != addr[7]) {
        Serial.print("CRC is not valid!\n");
        return;
    }
  }
  Serial.print("\n\r\n\rThat's it.\r\n");
  ds.reset_search();
  return;
}

void loop(void) {
  // nothing to see here
}

then simply include them in your programme setup

byte InThermo[8] =  {0x28, 0x69, 0xC2, 0xB0, 0x03, 0x00, 0x00, 0x9F };
byte OutThermo[8] = {0x28, 0x7A, 0x8B, 0xC0, 0x03, 0x00, 0x00, 0x2F};
byte DrainThermo[8] = {0x28, 0x54, 0xF7, 0x2D, 0x04, 0x00, 0x00, 0x68}; 
byte ShrThermo[8] = {0x28,  0x7E, 0X54, 0XA2, 0X04, 0X00, 0X00, 0X21};

and read them in the loop

  sensors.requestTemperatures();
  InTemp = sensorValue(InThermo);
  OutTemp = sensorValue(OutThermo);  
  DrainTemp = sensorValue(DrainThermo); 
  ShrTemp = sensorValue(ShrThermo);

Thanks @Nick_Pyner!!

I will study your option too.
Cheers,