DallasTemperature or OneWire Library slowing down the clock of NANO

I am using arduino NANO for my project. But when I use the DallasTemperature or OneWire Library, it slows down my controller. I'm guessing it scans every 1 second. Even on the serial monitor it shows output after 1 second. The same code was working perfectly on Mega. Does anyone know what the problem might be?

#include <OneWire.h>
#include <DallasTemperature.h>

/***************** Temperature Initialization ************************************************************/
#define ONE_WIRE_BUS A4
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);

/***************** Datatype Initialization ************************************************************/

unsigned long currentMillis = 0;
unsigned long current_time;
unsigned long a;
unsigned long b;
unsigned long c;
unsigned long d;
unsigned long e;
unsigned long f;

bool RF = 1;
bool LW = 0;
bool LF = 1;
bool RW = 0;
bool EQ = 1;
bool MTR = 0;

int SR = 0;

int val = 0;
int val1 = 0;

void setup()
{
 // Serial.begin(9600);
  sensors.begin();

  /******************* PinMode and Read/Write *******************************************************/

  pinMode(7, OUTPUT);            // Motor Output
  pinMode(4, OUTPUT);            // EQ Valve
  pinMode(6, OUTPUT);            // RF Valve
  pinMode(3, OUTPUT);            // LW Valve
  pinMode(2, OUTPUT);            // LF Valve
  pinMode(5, OUTPUT);            // RW Valve
  pinMode(8, OUTPUT);            // buzzer
  pinMode(10, OUTPUT);            // yelow
  pinMode(11, OUTPUT);            // green
  pinMode(12, OUTPUT);            // red

  delay(3000);                    // Initial Delay to open waste valves
}

void loop()
{
  /************************* Read Values **************************************************************/

  val = analogRead(A7);                                            // O2
  val1 = analogRead(A5);                                           // Flow (LPM)

  /*********************** Display Values *************************************************************/

  float oxy = val * (100.0 / 511.0);                       // Convert to percentage
  //  Serial.println(oxy);

  float Flow = val1 * (10.0 / 511.0);                      // Convert to Flow/Minute
  // Serial.println(Flow);
  motor1();
  Seq ();
  Valves();
  Temp();

}
void motor1()
{
  digitalWrite(7, LOW);
}

void Seq ()
{
  if (SR == 0) {
    current_time = millis();
 //   Serial.println("SR0");
    if (RF == 1 && LW == 0 && LF == 1 && RW == 0 && EQ == 1 && SR == 0) {
      RF = 1;
      LW = 1;
      LF = 0;
      RW = 0;
      EQ = 0;
      currentMillis = millis();
      SR = 1;
    }
  }

  else if (SR == 1) {
    a = millis();
   // Serial.println("SR1");
    if (RF == 1 && LW == 1 && LF == 0 && RW == 0 && EQ == 0 && SR == 1 && a - currentMillis >= 2000) {
      RF = 1;
      LW = 1;
      LF = 0;
      RW = 0;
      EQ = 1;
      currentMillis = millis();
      SR = 2;
    }
  }

  else if (SR == 2) {
    b = millis();
  //  Serial.println("SR2");
    if (RF == 1 && LW == 1 && LF == 0 && RW == 0 && EQ == 1 && SR == 2 && b - currentMillis >= 0) {
      RF = 1;
      LF = 1;
      LW = 0;
      RW = 0;
      EQ = 1;
      currentMillis = millis();
      SR = 3;
    }
  }

  else if (SR == 3) {
    c = millis();
   // Serial.println("SR3");
    if (LW == 0 && RF == 1 && LF == 1 && RW == 0 && EQ == 1 && SR == 3 && c - currentMillis >= 0) {
      RW = 1;
      LF = 1;
      RF = 0;
      LW = 0;
      EQ = 0;
      currentMillis = millis();
      SR = 4;
    }
  }

  else if (SR == 4) {
    d = millis();
  //  Serial.println("SR4");
    if (LW == 0 && RF == 0 && LF == 1 && RW == 1 && EQ == 0 && SR == 4 && d - currentMillis >= 2000)  {
      RW = 1;
      LF = 1;
      RF = 0;
      LW = 0;
      EQ = 1;
      currentMillis = millis();
      SR = 5;
    }
  }

  else if (SR == 5) {
    e = millis();
  //  Serial.println("SR5");
    if (LW == 0 && RF == 0 && LF == 1 && RW == 1 && EQ == 1 && SR == 5 && e - currentMillis >= 0) {
      RF = 1;
      LF = 1;
      RW = 0;
      LW = 0;
      EQ = 1;
      currentMillis = millis();
      SR = 6;
    }
  }

  else if (SR == 6) {
    f = millis();
  //  Serial.println("SR6");
    if (LW == 0 && RF == 1 && LF == 1 && RW == 0 && EQ == 1 && SR == 6 && f - currentMillis >= 0) {
      current_time = 0;
      currentMillis = millis();
      SR = 0;
    }
  }
}

void Valves()
{
  if (EQ == 0) {
    digitalWrite(4, LOW);
  }
  else {
    digitalWrite(4, HIGH);
  }

  if (RF == 0) {
    digitalWrite(6, LOW);
  }
  else {
    digitalWrite(6, HIGH);
  }

  if (LW == 0) {
    digitalWrite(3, LOW);
  }
  else {
    digitalWrite(3, HIGH);
  }

  if (LF == 0) {
    digitalWrite(2, LOW);
  }
  else {
    digitalWrite(2, HIGH);
  }

  if (RW == 0) {
    digitalWrite(5, LOW);
  }
  else {
    digitalWrite(5, HIGH);
  }
}

void Temp() {
  sensors.requestTemperatures();            
  //Serial.println(sensors.getTempCByIndex(0));
}

Yes and No.

The DS18B20 does not like to be used more than once per two seconds.
You could add a millis-timer that requests the temperature every 5 seconds.
The DallasTemperature has an option to wait for the DS18B20 or not wait for it.

I think those are enough possibilities to improve the responsiveness of your sketch.

If you want more, and get every milliseconds, then it is possible to change the library or use another library to avoid that interrupts are turned of while the Arduino is communicating with the DS18B20.

Did it work better on a Mega ? If there is a bug somewhere, then I don't see it :see_no_evil: I have no explanation for that :cry:

Yes, it worked perfectly on the mega. As and when the code used to get scanned, it used to give me a temperature reading.
But, I don't have a problem if i get the temperature reading in 1 second. But my other processes that is, operation of valves and reading analog value shouldn't slow down.

I would suspect a problem with the way you are using the currentmillis variable and the check of the timing. currentmillis is usually common between all the timing checks, with the individual timing code using different variables to store their individual millis when last executed, the way your code is written all the timing checks will interfere with each other.

I agree to what you're saying. I think they will not interfere, but one CurrentMillis is dependent on the previous CurrentMillis.

Indeed, the DallasTemperature library relies heavily on masking interrupts. It has to, because if it wouldn't, the OneWire timings would go awry pretty quickly and pretty dramatically. I've done quite a bit of work with OneWire over the past few weeks and it's a bit of a handful, that protocol. Especially if you try to run it along with various other tasks on a platform that has no hardware support for it.

1 Like

You have no timing for the loop which surely cannot be a good idea. There is some millis-type stuff lurking away in some corners, but the loop, the thing that counts, appears to running more on luck than management. The required time between readings depends on the resolution. You have not specified the resolution of the sensors, which is fine but suggests you need a reliably controlled loop of at least 750ms for DS18B20 to do its job in an orderly manner. A one second loop should be good enough for anybody, and they will run just fine at that rate. You can be sure that, if they need more time, Dallas would tell you. I think you are blaming the wrong thing. I can't offer comment on the Mega being OK with this code. I don't think there is any difference, the Mega should be just as problematical, and you just got luckier. You might just stick a delay(1000); at the bottom of the loop to see how it goes, and sort out the millis niceties, if any, later.

I won't say i'm new to arduino programming, but i've always done simple programming. I'm actually building an oxygen concentrator. Do you think this type of coding using millis might fail in the long run? I really need help.

There's nothing wrong with millis() per se, but as you have noticed, you can't rely on it for very exact timings particularly if there's lots of interrupt masking flying around all over the place.
I read @Nick_Pyner's comment not so much as a recommendation against millis(), but as a warning about code structure and architecture. A valid one, at that.

No, I'm simply saying the code is dumb, at best, the control over the timing is a confusing mess, and it should fail more or less immediately. I just think millis is misused.
I have no idea what is so time-critical here, if anything, or why you are using millis all over the place. Indeed, you have already said that it is OK to get reading @ 1Hz, so I guess there is nothing that is time critical. As for the DS18B20s, I'm surprised you don't get 85 every time, irrespective of Nano or Mega..
Maybe I'm missing something.
I recall that a Mega is slightly slower than a Uno/Nano. I have no idea why, and I bet that, if true, is the least of your problems anyway.

I believe the library has a method of initiating a read then returning without waiting for the read to complete. You then retrieve the temperature reading after the necessary time delay, the length of time depending on the resolution.

Nothing wrong with using millis for timing, but your implementation does not appear to be correct.

That's right. You have to keep track of time while the sensors do their thing and preferably don't bother them with onewire requests in the meantime.

Okay I'll use a LM35 temperature sensor and i think that will work. But as Nick was asking what is more time critical. So for the concentrator, there are these solenoid valves which work on 230V which i'm controlling via an SSR. There are 2 molecular sieves which contain zeolite, which adsords nitrogen from compresed air (2 bar) and releases nitrogen when decompressed and allowed air to pass through it. So i need to turn on and off these feed and waste valves. RF- Right feed, LW- Left waste.

#include <OneWire.h>
#include <DallasTemperature.h>

/***************** Temperature Initialization ************************************************************/
#define ONE_WIRE_BUS A4
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);

/***************** Datatype Initialization ************************************************************/

unsigned long currentMillis = 0;
unsigned long current_time;
unsigned long a;
unsigned long b;

bool RF = 1;
bool LW = 0;
bool LF = 1;
bool RW = 0;
bool MTR = 0;

int SR = 0;

int val = 0;
int val1 = 0;

void setup()
{
 // Serial.begin(9600);
  sensors.begin();

  /******************* PinMode and Read/Write *******************************************************/

  pinMode(7, OUTPUT);            // Motor Output
  pinMode(6, OUTPUT);            // RF Valve
  pinMode(3, OUTPUT);            // LW Valve
  pinMode(2, OUTPUT);            // LF Valve
  pinMode(5, OUTPUT);            // RW Valve

  delay(3000);                    // Initial Delay to open waste valves
}

void loop()
{
  /************************* Read Values **************************************************************/

  val = analogRead(A7);                                            // O2
  val1 = analogRead(A5);                                           // Flow (LPM)

  /*********************** Display Values *************************************************************/

  float oxy = val * (100.0 / 511.0);                       // Convert to percentage

  float Flow = val1 * (10.0 / 511.0);                      // Convert to Flow/Minute

  motor1();
  Seq ();
  Valves();
  Temp();

}
void motor1()
{
  digitalWrite(7, HIGH);
}

void Seq ()
{
  if (SR == 0) {
    current_time = millis();
    if (RF == 1 && LW == 0 && LF == 1 && RW == 0 && EQ == 1 && SR == 0) {
      RF = 1;
      LW = 1;
      LF = 0;
      RW = 0;
      currentMillis = millis();
      SR = 1;
    }
  }

  else if (SR == 1) {
    a = millis();
    if (RF == 1 && LW == 1 && LF == 0 && RW == 0 && EQ == 0 && SR == 1 && a - currentMillis >= 2000) {
      RF = 0;
      LW = 0;
      LF = 1;
      RW = 1;
      currentMillis = millis();
      SR = 2;
    }
  }

  else if (SR == 2) {
    b = millis();
    if (RF == 1 && LW == 1 && LF == 0 && RW == 0 && EQ == 1 && SR == 2 && b - currentMillis >= 2000) {
      current_time = 0;
      currentMillis = millis();
      SR = 0;
    }
  }
}

void Valves()
{
  if (RF == 0) {
    digitalWrite(6, LOW);
  }
  else {
    digitalWrite(6, HIGH);
  }

  if (LW == 0) {
    digitalWrite(3, LOW);
  }
  else {
    digitalWrite(3, HIGH);
  }

  if (LF == 0) {
    digitalWrite(2, LOW);
  }
  else {
    digitalWrite(2, HIGH);
  }

  if (RW == 0) {
    digitalWrite(5, LOW);
  }
  else {
    digitalWrite(5, HIGH);
  }
}

void Temp() {
  sensors.requestTemperatures();            
  //Serial.println(sensors.getTempCByIndex(0));
}

I've updated the code, removed unnecessary lines.

Question about the process. Is it potentially dangerous? Industrial or commercial scale?

If so, do you think the controller is best implemented using a hobbyist-quality microcontroller board with firmware written by someone of limited expience?

Sure, but there's nothing wrong with your DS18B20's either...
@Nick_Pyner emphasized some conceptual problems with your code. Exchanging hardware isn't going to solve this.

That explains nothing about "time-critical". Being OK with readings every second means nothing is time critical as far as Arduino is concerned. I suspect you are just making things harder than they should be. I doubt that changing to an LM35 will fix anything. The problem is in your code, not your peripherals.

Okay, firstly I've run this code for like 2-3 hours and its worked properly, giving me 90% oxygen level output. I just wanna know one thing when you guys say the problem is the code, What changes do i do?
And Nick, temperature is not the problem, even if i get the temperature 2 seconds late, I can turn of the compressor 2 seconds late. Won't make much of a difference.
But the amount of time the solenoid valves are on and off is critical. If they are not 2 seconds, the oxygen concentration might decrease

My main concern with your code is maintainability. For something fairly simple in its function, it's a pretty complex knot of multi-condition if-statements governing system behavior.

Furthermore, the way you have defined and run the motor and valve functions, there's no real protection against them alternating rapidly between states (effectively being PWM driven) other than the complex knot hiding in the seq() function.

Redundancy is another issue in how you for instance handle the different valves, hardcoding the link between non-intuitively formulated variables and individual outputs.

I entirely believe you when you say it works fine. I've made code like this that has worked for years. But I wouldn't even dare touch it ever again because I know that whatever modification I make, each problem I solve will give rise to 3 new ones.