How to define OneWire with a configuration file

Hello

I wonder if you could help me with that isue. I know I always want to make it hard for myself :slight_smile:

I have a configuration file to activate or not some sensors. Some of them have setting values.
Actually, I want to be able to use one or more DS18B20 sensors (OneWire). My station allow 5 DS18B20 sensors, but actualy I want to use two of them.

Here is my configuration file station-29.h
Consider only

  • const bool bud1_active; // To activate the sensor for the buds sensors
  • t_ds18b20 bud1_config; // Configuration for the bud sensors
  • const bool temperature_soil_active; // ts; i; // Activate the sensors for soil tempreature
  • t_ds18b20 tsoil_config; // Config for the soil temperature sensors

You will oberved, I forsee a pin to power the sensors, because I want the sensor to be powered only when a measure is taken. As the sensor is into the soil, it's not good to keep it permanently powered.


struct t_ds18b20 { // for DS18B20 calibration
  const byte pinPower;
  const byte pinRead;
  float refMin; // Temperature of the ice
  float refMax; // Temprature of the boiled water
  float tMin;   // Measure in the ice
  float tMax;   // Measure in the boiled water
};

struct ini_station
{
  const char* nom;
  const int station_id;
  const int pcb_version;
  const int analogRResolution;
  bool actif; //Activate station: true/false
  
  const int32_t tx_interval; // // (sec) 15, 30, 60 (1mn), 120 (2mn), 300 (5mn), 900 (15mn), 1800 (30mn), 3600sec (1h)
  const bool mprint;          // Display print in the terminal
  
  const int sd;             //Activate SD card: 0=inactive; 1=active; 2=active and read config from SD
  //boolean conf_from_sd = false;   // If sd is active and conf_from_sd, the sensor configuration from SD will considered instead of the conf from that ino file
  bool logger;         // (sd must be true) If true, the station activity will be saved into the SD card
 
  const bool oled;                // Activate the OLED display
  const bool rtc;                 // Activate the RTC DS3231 clock
  const bool rtc_calibrate;       // Calibrating the RTC DS3231 clock. RTC. RTC must be true (Default false)
  const bool eeprom;              // Activate the EEPROM chip. It must be true to save the LoRaWAN keys
  const bool watchdog;
  const bool sleepMode;
  const int lora;                 // 0=unactivate LoRaWAN; 1=OTAA; 2=ABP
  
  const bool temperature_active;  // te; a;
  const bool pressure_active;     // pr; b;
  const bool humidity_active;     // hu; c
  const bool luminosity_active;   // lu; d;
  const byte wm1_active;          // w1; e;
  const byte wm2_active;          // w2; f;
  const byte wm3_active;          // w3; g;        
  // bool datetime_active;        // da; h;  // date_time_active is always the same than rtc
  const bool temperature_soil_active; // ts; i;  // Must define the analog pin
  t_ds18b20 tsoil_config;
  const byte gauge_active;           // ga; j;
  const bool battery_active;      // ba; k;
  const byte wattering_active;    // ar; l;
  const byte aneno_active;        // an; m;
  const bool irtemp_active;       // ir; n;
  const bool wrm_active;          // wr; o
  const bool bud1_active;         // b1; p;
  t_ds18b20 bud1_config;      
  const bool bud2_active;         // b2; q;
  t_ds18b20 bud2_config;   
  const bool bud3_active;         // b3; r;
  t_ds18b20 bud3_config;  
  const bool bud4_active;         // b4; s;
  t_ds18b20 bud4_config;      
  const byte sun_active;          // su; t;     
  const byte wdirection_active;   // wd; u;
  const byte wdirection_offset;
  const byte sf110bud_active;     // sb; v;
  const byte sf110leaf_active;    // sl; w;
  /*
  const char * nomDuCapteur;
  const uint8_t codeDuCapteur;
  */
};

/*
* In the below configuration, make sure there is not analog pin conflict. For exemple, the Pyranometer (A2) can not be used with BUD station
* Watermark (Irrigation) can not be used with Bud sensor as they use the same analog pin.
*
* WATTERING must be used with A4 (18)
* RAIN GAUGE must be used with A0 (14)
* BUD sensors use A0 to A3
* WATTERMAR use A0 to A3
* WIND sensor use A0
*/
ini_station station = {
    "Station 29",   // Station name
    29,             // station ID
    3,              // PCB VERSION IS :0 = v2; 1 > v2; 3 = fox-board_full_mcp-v3
    12,             // analogReadResolution
    true,           // station active (true or false)
    120,            // TX INTERVAL (sec) 15, 30, 60 (1mn), 120 (2mn), 300 (5mn), 900 (15mn), 1800 (30mn), 3600sec (1h)
    true,           // mprint
    0,              // SD card: 0=inactive; 1=active; 2=active and read config from SD
    false,          // LOGGER: (SD must not be 0) If true, the station activity will be saved into the SD card
    false,          // OLED: Active or not
    true,          // RTC DS3231 I2C
    false,          // RTC CALIBRATE RTC Must be true. Do not forget to have it back to fase after calibrating
    false,           // EEMPROM: Active or not
    false,          // Watchdog
    false,          // SLEEP: Active the sleep mode (Arduinolowpower)
    1,              // LoRaWAN: 0=unactivate; 1=OTAA; 2=ABP;
    false,          // te; a;
    false,          // pr; b;
    false,          // hu; c
    true,          // lu; d;
    15,              // w1; e;     // 0=Unactive; 14=A0; *15=A1*; 16=A2; 17=A3; 18=A4; 19=A5
    16,              // w2; f;     // 0=Unactive; 14=A0; 15=A1; *16=A2*; 17=A3; 18=A4; 19=A5
    17,              // w3; g;     // 0=Unactive; 14=A0; 15=A1; 16=A2; *17=A3*; 18=A4; 19=A5
    //true,         // da; h;     // date_time_active is always the same than rtc
    true,          // ts; i;     // Must define the analog pin
    {4,19,0,97,0, 97},      // ts: ds18b20 calibration: Analog pin, refMin, refMax, min, max
    0,              // ga; j;     // 0=Unactive; 14=A0; 15=A1; 16=A2; *17=A3*; 18=A4; 19=A5
    true,          // ba; k;
    18,              // ar; l;     // WATTERING // 0=Unactive; 14=A0; 15=A1; 16=A2; 17=A3; *18=A4*; 19=A5
    0,              // an; m;     // WWIND SPEED // 0=Unactive; *14=A0*; 15=A1; 16=A2; 17=A3; 18=A4; 19=A5
    false,           // ir; n;
    false,          // wr; o
    true,             // b1; p;     // 0=Unactive; *14=A0*; 15=A1; 16=A2; 17=A3; 18=A4; 19=A5
    {1,14,0,97,0,0},    // b1; ds18b20 calibration: Analog pin, refMin, refMax, min, max
    false,             // b2; q;     // 0=Unactive; 14=A0; *15=A1*; 16=A2; 17=A3; 18=A4; 19=A5
    {2,15,0,97,0,0},    // b2; ds18b20 calibration: Analog pin, refMin, refMax, min, max
    false,             // b3; r;     // 0=Unactive; 14=A0; 15=A1; *16=A2*; 17=A3; 18=A4; 19=A5
    {3,16,0,97,0,0},    // b3; ds18b20 calibration: Analog pin, refMin, refMax, min, max
    false,             // b4; s;     // 0=Unactive; 14=A0; 15=A1; 16=A2; *17=A3*; 18=A4; 19=A5
    {4,17,0,97,0,0},    // b4; ds18b20 calibration: Analog pin, refMin, refMax, min, max
    0,              // su; t;     // SUN: // 0=Unactive; 14=A0; 15=A1; *16=A2*; 17=A3; 18=A4; 19=A5
    0,              // wd; u;     // WIND DIRECTION 0=Unactive; 14=A0; *15=A1*; 16=A2; 17=A3; 18=A4; 19=A5 and the WindDirectionOffset
    0,              // Offset of the wind direction bar from the Noth (Degree). 0 if the bar point to the North
    0,              // sb; v;     // 0=Unactive; 14=A0; 15=A1; *16=A2*; 17=A3; 18=A4; 19=A5
    0,              // sl; w;     // 0=Unactive; 14=A0; 15=A1; *16=A2*; 17=A3; 18=A4; 19=A5
    
};

Now I need to initiate the ds18b20 library and the exemple start as the following before the setup()

#include <OneWire.h>
  OneWire ds18x20[] = {10,11} //ds18b20_pinRead;
  const int oneWireCount = sizeof(ds18x20)/sizeof(OneWire);
  Ecods18b20 sensor[oneWireCount];

10 and 11 are the reading ping. It read the value returned by the sensors. I need to have the reading pin only for the active sensors.

Now, my problem starts and how to make it efficient?

First,I start has the following, but it does not filter the inactive sensors yet.

const uint8_t ds18b20_pinRead[]={station.tsoil_config.pinRead,station.bud1_config.pinRead,station.bud2_config.pinRead,station.bud3_config.pinRead,station.bud4_config.pinRead};
const uint8_t ds18b20_pinPower[]={station.tsoil_config.pinPower, station.bud1_config.pinPower, station.bud2_config.pinPower, station.bud3_config.pinPower, station.bud4_config.pinPower};

The idea is later to loop the two array and to get the power pin regarding the index of the arrays.
I do not know if it's a good way to start.

If now I change to


#include <OneWire.h>
OneWire ds18x20[] = ds18b20_pinRead; //{1,2}
const int oneWireCount = sizeof(ds18x20)/sizeof(OneWire);
Ecods18b20 sensor[oneWireCount];

I got the follwoing error

initializer fails to determine size of 'ds18x20'

Keeping in mind, ds18b20_pinRead is not dynamic, but it can have a different size when the board start, depending of the amount of active sensors.

Lastly, what it look more complicate is how to build

  • uint8_t ds18b20_pinRead
  • uint8_t ds18b20_pinPower

before the startup() according to the configuration file? (in my point of view ds18b20_pinRead and ds18b20_pinPower, does not need to be const.

How would you recommand me to do the second step?

Many thanks and I wish you a nice day!

If you declare an array of objects, the parameterized initialization list must be inline, so your approach will not succeed. This is how you would do it dynamically:

//config.h
//Declaration method 1
const uint8_t PINS[] = { 1, 2, 3 };
const uint8_t PIN_COUNT = sizeof(PINS) / sizeof(*PINS);

//Declaration method 2
#define PIN_COUNT 3
const uint8_t PINS[PIN_COUNT] = { 1, 2, 3 };

//Sketch.ino
#include "config.h"

OneWire wires[PIN_COUNT];

void setup()
{
  for (int i = 0; i < PIN_COUNT; i++) wires[i].begin(PINS[i]);
  ...
}

If you insist on using the parameterized approach, it must be done like this:

OneWire wires[] = {station.tsoil_config.pinRead,station.bud1_config.pinRead, ...};

//OR
OneWire wires[] = { ds18b20_pinRead[0], ds18b20_pinRead[1], ...};

But that would require both config and sketch to be modified when pins change, so that would not make much sense.

EDIT: Another problem with the parameterized method is that the OneWire constructor which takes a pin number as argument calls OneWire::begin(pin) which again initializes the hardware which may not yet be available because it is invoked before "setup()", so...

Thanks,

I have different problem with the ds18b20 and I do not want to create a new post. This is beacuse I need to solve it before looking for your reply

My goal is to have ds18b20 library.I will continue with the "advanced" version but as I have to deploy my staton into the field asap, I work with a simplest version. (I have to make it working asap at least with on sensors, when done i will work with different sensos, as I wrote in that message)

I started my ino file as the following according to that library

Here is an example ino file. But my case, I use a PCH8574 to power the sensor, that the reason why, it's a bit different

#include <OneWire.h>
#include <Ecods18b20.h>

OneWire ds(19); // read the sensors at the pin19 (A5)
float temperature_soil;

Ecods18b20 ecods18b20;

setup(){
Serial.begin(9600);

ecods18b20.start(&ds);`

// Power the sensor wit pcf7584
expander.digitalWrite(station.tsoil_config.pinPower,HIGH);
if(ecods18b20.get_temperature(&temperature_soil, true)==1)
{
    Serial.print((int16_t)temperature_soil); Serial.println(F("C"));
}
expander.digitalWrite(station.tsoil_config.pinPower,LOW);

The library bug here. It looks like _ds does not work, but it should work as I pass it in start(), isn't?

When it will work, I will be concentred on your solution that I pain to understant but I will clarify my question later.

many thanks!!!!!

Which Arduino board are you using ?

Hello
It's a board based on the Arduino Zero with ATSAMD21G18 ARM Cortex M0

Short correction: pin 19 is egual to A5 and not to A1

Ok, I think, I solved my first problem
I changed this and this.
I removed start(&ds).

Now it's work!

Now the thinks I really need to do, here I define one bus.
If you connect serveral DS18B20 in that bus, it easy, but in my PCB, I can not link all wire/bus together.

Then I have one bus for each DS18B20 and I can have up to 5 DS18B20. As I wrote above, I have a configuration file, where I define the bus and the power pin of one sensors


struct t_ds18b20 { // for DS18B20 calibration
  const byte pinPower;
  const byte pinRead;
  float refMin; // Temperature of the ice
  float refMax; // Temprature of the boiled water
  float tMin;   // Measure in the ice
  float tMax;   // Measure in the boiled water
};

struct ini_station
{
  const char* nom;
  const int station_id;
  const int pcb_version;
  const int analogRResolution;
  bool actif; //Activate station: true/false
  
  const int32_t tx_interval; // // (sec) 15, 30, 60 (1mn), 120 (2mn), 300 (5mn), 900 (15mn), 1800 (30mn), 3600sec (1h)
  const bool mprint;          // Display print in the terminal
  
  const int sd;             //Activate SD card: 0=inactive; 1=active; 2=active and read config from SD
  //boolean conf_from_sd = false;   // If sd is active and conf_from_sd, the sensor configuration from SD will considered instead of the conf from that ino file
  bool logger;         // (sd must be true) If true, the station activity will be saved into the SD card
 
  const bool oled;                // Activate the OLED display
  const bool rtc;                 // Activate the RTC DS3231 clock
  const bool rtc_calibrate;       // Calibrating the RTC DS3231 clock. RTC. RTC must be true (Default false)
  const bool eeprom;              // Activate the EEPROM chip. It must be true to save the LoRaWAN keys
  const bool watchdog;
  const bool sleepMode;
  const int lora;                 // 0=unactivate LoRaWAN; 1=OTAA; 2=ABP
  
  const bool temperature_active;  // te; a;
  const bool pressure_active;     // pr; b;
  const bool humidity_active;     // hu; c
  const bool luminosity_active;   // lu; d;
  const byte wm1_active;          // w1; e;
  const byte wm2_active;          // w2; f;
  const byte wm3_active;          // w3; g;        
  // bool datetime_active;        // da; h;  // date_time_active is always the same than rtc
  const bool temperature_soil_active; // ts; i;  // Must define the analog pin
  t_ds18b20 tsoil_config;
  const byte gauge_active;           // ga; j;
  const bool battery_active;      // ba; k;
  const byte wattering_active;    // ar; l;
  const byte aneno_active;        // an; m;
  const bool irtemp_active;       // ir; n;
  const bool wrm_active;          // wr; o
  const bool bud1_active;         // b1; p;
  t_ds18b20 bud1_config;      
  const bool bud2_active;         // b2; q;
  t_ds18b20 bud2_config;   
  const bool bud3_active;         // b3; r;
  t_ds18b20 bud3_config;  
  const bool bud4_active;         // b4; s;
  t_ds18b20 bud4_config;      
  const byte sun_active;          // su; t;     
  const byte wdirection_active;   // wd; u;
  const byte wdirection_offset;
  const byte sf110bud_active;     // sb; v;
  const byte sf110leaf_active;    // sl; w;
  /*
  const char * nomDuCapteur;
  const uint8_t codeDuCapteur;
  */
};

/*
* In the below configuration, make sure there is not analog pin conflict. For exemple, the Pyranometer (A2) can not be used with BUD station
* Watermark (Irrigation) can not be used with Bud sensor as they use the same analog pin.
*
* WATTERING must be used with A4 (18)
* RAIN GAUGE must be used with A0 (14)
* BUD sensors use A0 to A3
* WATTERMAR use A0 to A3
* WIND sensor use A0
*/
ini_station station = {
    "Station 29",   // Station name
    29,             // station ID
    3,              // PCB VERSION IS :0 = v2; 1 > v2; 3 = fox-board_full_mcp-v3
    12,             // analogReadResolution
    true,           // station active (true or false)
    120,            // TX INTERVAL (sec) 15, 30, 60 (1mn), 120 (2mn), 300 (5mn), 900 (15mn), 1800 (30mn), 3600sec (1h)
    true,           // mprint
    0,              // SD card: 0=inactive; 1=active; 2=active and read config from SD
    false,          // LOGGER: (SD must not be 0) If true, the station activity will be saved into the SD card
    false,          // OLED: Active or not
    true,          // RTC DS3231 I2C
    false,          // RTC CALIBRATE RTC Must be true. Do not forget to have it back to fase after calibrating
    false,           // EEMPROM: Active or not
    false,          // Watchdog
    false,          // SLEEP: Active the sleep mode (Arduinolowpower)
    1,              // LoRaWAN: 0=unactivate; 1=OTAA; 2=ABP;
    false,          // te; a;
    false,          // pr; b;
    false,          // hu; c
    true,          // lu; d;
    15,              // w1; e;     // 0=Unactive; 14=A0; *15=A1*; 16=A2; 17=A3; 18=A4; 19=A5
    16,              // w2; f;     // 0=Unactive; 14=A0; 15=A1; *16=A2*; 17=A3; 18=A4; 19=A5
    17,              // w3; g;     // 0=Unactive; 14=A0; 15=A1; 16=A2; *17=A3*; 18=A4; 19=A5
    //true,         // da; h;     // date_time_active is always the same than rtc
    true,          // ts; i;     // Must define the analog pin
    {4,19,0,97,0, 97},      // ts: ds18b20 calibration: Analog pin, refMin, refMax, min, max
    0,              // ga; j;     // 0=Unactive; 14=A0; 15=A1; 16=A2; *17=A3*; 18=A4; 19=A5
    true,          // ba; k;
    18,              // ar; l;     // WATTERING // 0=Unactive; 14=A0; 15=A1; 16=A2; 17=A3; *18=A4*; 19=A5
    0,              // an; m;     // WWIND SPEED // 0=Unactive; *14=A0*; 15=A1; 16=A2; 17=A3; 18=A4; 19=A5
    false,           // ir; n;
    false,          // wr; o
    true,             // b1; p;     // 0=Unactive; *14=A0*; 15=A1; 16=A2; 17=A3; 18=A4; 19=A5
    {1,14,0,97,0,0},    // b1; ds18b20 calibration: Analog pin, refMin, refMax, min, max
    false,             // b2; q;     // 0=Unactive; 14=A0; *15=A1*; 16=A2; 17=A3; 18=A4; 19=A5
    {2,15,0,97,0,0},    // b2; ds18b20 calibration: Analog pin, refMin, refMax, min, max
    false,             // b3; r;     // 0=Unactive; 14=A0; 15=A1; *16=A2*; 17=A3; 18=A4; 19=A5
    {3,16,0,97,0,0},    // b3; ds18b20 calibration: Analog pin, refMin, refMax, min, max
    false,             // b4; s;     // 0=Unactive; 14=A0; 15=A1; 16=A2; *17=A3*; 18=A4; 19=A5
    {4,17,0,97,0,0},    // b4; ds18b20 calibration: Analog pin, refMin, refMax, min, max
    0,              // su; t;     // SUN: // 0=Unactive; 14=A0; 15=A1; *16=A2*; 17=A3; 18=A4; 19=A5
    0,              // wd; u;     // WIND DIRECTION 0=Unactive; 14=A0; *15=A1*; 16=A2; 17=A3; 18=A4; 19=A5 and the WindDirectionOffset
    0,              // Offset of the wind direction bar from the Noth (Degree). 0 if the bar point to the North
    0,              // sb; v;     // 0=Unactive; 14=A0; 15=A1; *16=A2*; 17=A3; 18=A4; 19=A5
    0,              // sl; w;     // 0=Unactive; 14=A0; 15=A1; *16=A2*; 17=A3; 18=A4; 19=A5
    
};

From that file, I can activate or unactivate a DS18B20 sensors, but I do not have to modify my ino file

See:

  • const bool bud1_active; // To activate the sensor for the buds sensors
  • t_ds18b20 bud1_config; // Configuration for the bud sensors
  • const bool temperature_soil_active; // ts; i; // Activate the sensors for soil tempreature
  • t_ds18b20 tsoil_config; // Config for the soil temperature sensors

The difficulties for me is how to have a "dynamic" way to initiate my OneWire? @Danois90 wrote me this

//Declaration method 1
const uint8_t PINS[] = { 1, 2, 3 };
const uint8_t PIN_COUNT = sizeof(PINS) / sizeof(*PINS);

but as I am before my setup(), how can I have (without editing the ino file)

const uint8_t PINS[] = { 15, 16,19 }; // if I have 3 actived sensors
const uint8_t PINS[] = { 15,16}; // if I have 2 actived sensors
const uint8_t PINS[] = { 15, 16 ,17,18,19}; // if I have 5 actived  sensor

I have to leave and I will be abck in a coupe of hours, but I just found that

oneWirePtr =  new OneWire(One_Wire_Bus)

is there a way with that to modify my OneWire instance in the setup, just after a script check the active and inactive sensors to have the appropriate PIN[] value?

I will better investigate when back

Sure there is. Look in OneWire.h for the proper constructor and begin() function.

If you want dynamic allocation, you could use something like:

OneWire *wires = new OneWire[PIN_COUNT];

void setup()
{
  for (int i = 0; i < PIN_COUNT; i++) wires[i].begin(PINS[i]);  
}

Dear All,

Thanks a lot for your replies!!
I just realized, I have to finish another task for tomorrow. I will investigate on your suggestion and give you a feed back later
Many thanks

Hello

I am sorry, but I am very confuse about how to do that.
I am starting with this

From here,I am checking the active sensors and I fill an array

Here, I need to reinitiate, but I can not, because oneWireCount does not have the same value as the array is bigger!!!

Here ya go a Sealed, Waterproof DS18B20. Keep it powered all the time a simplify your code -- should be fine as long as your project isn't battery-powered.

Thanks a lot gfvalvo,
I am not convinced (at least for my application) , it's a good idea to keep the sensor powered, as I place the sensor(s) into the soil/ground while it could be wet after the rain.
Even if the sensors it permanently power or not, I still have to find a way initiate the OneWire with the number of activate sensors, in the setup(). I think here

Or do you? Would it not be better to do something like this (pseudo-code):

#include <OneWire.h>

OneWire oneWire;

void loop()
{
  for (int i = 0; i < SENSOR_COUNT; i++)
  {
    powerUpSensor(SENSOR_POWER_PINS[i]);
    oneWire.begin(SENSOR_DATA_PINS[i]);
    value = readSensorValue(&oneWire);
    powerDownSensor(SENSOR_POWER_PINS[i]
  }
}

This will not require multiple instances of "OneWire" and only one sensor is powered up at a time and only for as short time as possible.

Hello @Danois90
Thanks a lot for your suggestion
I just wrote that example, and it look to work fine.

Any comments?

Many thanks

May I ask you again a question.

Regarding my DS18B20 library, I have a configuration file

I just look for very old script, I observed I already use a such configuration, a long time ago.
But on this one, at the top, I have this

#ifndef _siconfig_h_
#define _siconfig_h_

On my recent configuration file, shoulsd I have

#ifndef _station-29_h_
#define _station-29_h_

What is the use of those two line? Is mandatory??

Thanks and have a good day

No, they are not mandatory. They are called header guards and prevent the same code from being included multiple times and thus reducing the size of the final binary. With modern compilers/pre-processors you would probably use #pragma once instead.

Thanks a lot and have a nice day

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.