One wire DS18B20 reading +85°C, then -127°C and Arduino hanging up completely

Dear "alto777",

I can read your answer a lot of times, but I think my English is too weak to understand what is the sense of your post. I just don't get all parts of it. What, for instance do you exactly mean, by putting the following sentence under quotes "Have you ever had your [numerous tech devices] having a software-crash? No !" and then conclude with a "Yes!" So yes or no? And what do you mean by "crashing itself you don't even know about" ? I will know, if it was crashing and then will be reset by a watchdog, because if I change e.g. with some switches some parameters, and then it one time will be reset, then it will load the default values again, and so I WILL KNOW that there happened a reset by the watchdog.
And yes, of course it would be better, that this never crashes by itself and a watchdog is not necessary, but the reality says different in this project. And I do not understand why this should be such a bad solution for this case? If the thing will crash, say, after some days, and the watchdog resets it (which takes less than, say, 30 seconds overall) and then it works again for some days, it would be absolutely fine for me, because the application (to cool e.g. 100 literes of water) does absolutely not care if it is interrupted by 30 sec. !! Do you agree?

This link will show you how to upload code using the ICSP technique AND how burn the boot loader if needed be.

Note: burning your code with ICSP, will remove the boot loader from your target board.

https://docs.arduino.cc/built-in-examples/arduino-isp/ArduinoISP

I think modern embedded software is sometimes not all it could be, and as you seem to have understood, I take a dim view of solving solvable problems by use of the watchdog mechanism.

Watch dog timers have their place, but getting the most out of them is not simple.

My comments were not directed at you or your use case or your software or hardware. I just laughed out loud literally at @StefanL38's assertion that microprocessors were so reliably reliable. Yes, I see malfunctions and what I suppose are crashes in many of the devices around here, even the ones I did not program myself. :expressionless:

Please if you do want to use one, read

and


Ganssle's website is full of good stuff, he's one of the very few people worth spending lotsa time reading.

HTH and your English is better than my <any not English language>.

a7

Hello guys,

I soldered now a Arduino Nano as a ISCP Programmer with a reference mixture of the following 2 sources:
*) https://docs.arduino.cc/built-in-examples/arduino-isp/ArduinoISP
*) https://www.instructables.com/Arduino-Nano-ISP-Dongle/
Now, I get all the time error messages, like

avrdude: stk500_getsync() attempt 10 of 10: not in sync: resp=0x03

I have read already some things in the internet, and played around with different COMs and used different USB connectors of my computer, etc. but it simply does not want to work!
What a shitty problem! Now, I am close to program my stuff over ISCP to get a shorter power-up time, but I am fighting now with this stupid error!

By the way, my application is running now since my last post without any failure (still of course without the watchdog).

Bye,
bernd2700

Here is results from burning a Sketch two different ways:

The sketch simply makes pin 12 of an Arduino Pro Mini go HIGH at power on time.

void setup()
{
  pinMode(12, OUTPUT);
  digitalWrite(12, HIGH);
}

void loop()
{
}


  • Sketch uploaded using the Boot Loader



  • Sketch uploaded using the Arduino as Programmer



That's 1,460ms versus 64ms difference.

i.e. ~23 times faster.




FYI

Dear "LarryD",

Thanks for your demo! What I do not understand, is, that you get start-up times in the ms range (e.g. 64 ms) and I get startup-times which need about 6s (see post #136 and #137, attention, there, it is 2s/div). If I would get power up times in your range, I would be perfectly happy and I would not need to do anything! ==> From where does this HUGE difference come from? (I guess, you will not clock the Arduino with GHz :wink: )
And, what to do against these stupid "not in sync" errors, so that I can finally program the stuff over ISCP?

Thanks a lot,
bernd2700

Seems to me that you're going about this the hard way.

Why not just connect the Watchdog Chip's ~EN input to an Arduino GPIO pin and pull it HIGH with say a 1K resistor? Since all GPIO pins default to inputs at power-up, the ~EN pin will be pulled HIGH, disabling the Watchdog. When your code finally starts up, configure the GPIO as OUPUT and set it low, enabling the Watchdog. Then off you go.

Dear "gfvalvo"!

Yesssss, great idea!! This sounds, at least when quickly reading now your post, very good! This will solve "all" the things with an easy trick! I did not think about that the pins are default "input" state, and with this, then one can of course do what you describe!

Thank you so much for that hint, this will save a lot of time!

Do you follow this process ?

This is very similar to what I suggested 14 posts and 1 week ago

Dear "Stefan38",

Yes, that's pretty similar what you suggested - but there was a tiny, but for me very important detail missing in your post: That the default state of the GPIO pins is "input"! So when this detail is missing, in other words, not having thought of this, the whole thing would simply not work, since before, I have configured the GPIO pin right at the beginning as "output", and the state this has will "overwrite" the 10k pull-up resistor of course!

But thanks, anyway,
bernd2700

Hi guys,

Since I have solved the thing with the watchdog thanks to the help ( = important hint) of "gfvalvo", I can (must!!) start now also to re-write the code as in non-blocking form, as also "gfvalvo" suggested, because to never ever get with the execution time of the loop beyond the fixed 1.6 sec timeout of the watchdog. When I am completed with this task, I can solder and enable the watchdog to my circuitry.
By the way, the whole thing is running now without any failure (still without the watchdog of course) since at least post #145, so for 1 week.

Bye,
bernd2700

Dear guys,

First of all, the whole thing is running since post #145 = since 22 days without any failure now (still without the watchdog), which is very good!

But, as said, I want the whole thing now to do properly. One suggestion I liked very much is from “gfvalvo”, to build the code in “non-blocking” - form and from "alto777" the thing with more "timers". For this, I came 1 step further : I programmed the following code into a 2nd (replica) Arduino Nano board:

// This Arduino sketch reads DS18B20 "1-Wire" digital
// temperature sensors.
// Tutorial:
// http://www.hacktronics.com/Tutorials/arduino-1-wire-tutorial.html


/****************** Include Files ******************************************************/
// "" => Looks in the same directory as the 'C' file I compile
// <> => Looks in the library paths

// OLED-Display
  #include <U8x8lib.h>
  
// 1-wire
  #include <OneWire.h>
  #include <DallasTemperature.h>


/****************** Constants **********************************************************/
// Timing for the endless Arduino program loop
  # define waitTime1 5000   // [ms]
  # define waitTime2  600   // [ms]
  
// 1-wire
  #define ONE_WIRE_BUS 2                  // Data wire is plugged into port 2 on the Arduino;  Make sure a pull-up resistor (e.g. 1k) is connected (so from Data to VCC)
  #define TEMPERATURE_PRECISION 12        // 12 is maximum but slower.
  #define NUM_OW_SENSORS 3                // the number of DS18B20 sensors on the 1-Wire bus.

// Alive / Error LED
  const int AliveErrorLED = 4;                    // Pin "D4"


// ??????????????????????? ****************** WAS IST DAS ?????  **********************************************************`?????????????????????????????/
// 1-wire
// Setup a oneWire instance to communicate with any OneWire devices
  OneWire oneWire(ONE_WIRE_BUS);

// Pass our oneWire reference to Dallas Temperature. 
  DallasTemperature sensors(&oneWire);

// Assign the addresses of your 1-Wire temp sensors.
// See the tutorial on how to obtain these addresses:
// http://www.hacktronics.com/Tutorials/arduino-1-wire-address-finder.html
  DeviceAddress S01_Metal1   = { 0x28, 0x44, 0x4D, 0x15, 0x00, 0x00, 0x00, 0x0B };   // S01_Metal1   = TempSensors_Temps[0]
  DeviceAddress S02_Metal2   = { 0x28, 0x86, 0xBD, 0xEC, 0x32, 0x14, 0x01, 0xA6 };   // S02_Metal2   = TempSensors_Temps[1]
  DeviceAddress S03_TO92  = { 0x28, 0x23, 0x1E, 0x21, 0x16, 0x13, 0x01, 0xAC };   // S03_TO92  = TempSensors_Temps[2]


/****************** Constructors ******************************************************/
// OLED-Display
  U8X8_SH1106_128X64_NONAME_HW_I2C u8x8(/* reset=*/ U8X8_PIN_NONE);       // Please update the pin numbers according to your setup. Use U8X8_PIN_NONE if the reset pin is not connected


/****************** Variables **********************************************************/
// Arduino program loop
  uint32_t currentTime;
  uint32_t timer1;
  uint32_t timer2;
  
// 1-wire
  static float TempSensors_Temps[NUM_OW_SENSORS];                          // Array which holds the current temperatures of all 1-wire temperature sensors

  
// Misc
  static unsigned short uCalive = 1;      // Change value every e.g. 1s and display some character on OLED display
  bool LED_Builtin_HiLoState = 0;
  bool AliveErrorLED_HiLoState = 0;


/***************************************************************************************/
/* Main: Setup          // put your setup code here, to run once:                      */
/***************************************************************************************/
void setup(void)
{
  // System LED  
    pinMode( LED_BUILTIN , OUTPUT );  
  
  // AliveErrorLED
    pinMode( AliveErrorLED , OUTPUT );
  
  // 1-wire
    // Do not wait for conversion
      sensors.setWaitForConversion(false);
    // Start up the library
      sensors.begin();
    // set the resolution to X bit
      sensors.setResolution(S01_Metal1, TEMPERATURE_PRECISION);
      sensors.setResolution(S02_Metal2, TEMPERATURE_PRECISION);
      sensors.setResolution(S03_TO92, TEMPERATURE_PRECISION); 

    // Ask for a 1st conversion
      sensors.requestTemperatures();
      
  // OLED-Display
    u8x8.begin();
    u8x8.setPowerSave(0);
  
  // Write to OLED-Display
    u8x8.setFont(u8x8_font_chroma48medium8_r);
    u8x8.drawString(0,0,"Starting up...");
    u8x8.refreshDisplay();    // only required for SSD1606/7

  // Show setup display 2 seconds long
    delay(2000);
  
  // Clear display in order that some remaining characters are not displayed during the loop. E.g. If here in setup it says "Temperatures:" and later in the loop just say "Temps:" in the same line, that it doesn't write: "Temps:atures:"
//    u8x8.clear();

// Timing for the endless Arduino program loop
  timer1 = millis();
  timer2 = timer1;
}


/***************************************************************************************/
/* Subprogram                                                                          */
/***************************************************************************************/
float printTemperature(DeviceAddress deviceAddress)
{
  float tempC = sensors.getTempC(deviceAddress);
  if (tempC == -127.00) {
    Serial.print("Error getting temperature");
  } else {
    Serial.print("C: ");
    Serial.print(tempC);
    Serial.print(" F: ");
    Serial.print(DallasTemperature::toFahrenheit(tempC));
  }
  return(tempC);
}


/***************************************************************************************/
/* Subprogram                                                                          */
/***************************************************************************************/
void func_Task_exec_every_waitTime1(void)
{
  LED_Builtin_HiLoState = !LED_Builtin_HiLoState;
//  digitalWrite( LED_BUILTIN , LED_Builtin_HiLoState );
}


/***************************************************************************************/
/* Subprogram                                                                          */
/***************************************************************************************/
void func_Task_exec_every_waitTime2(void)
{
  AliveErrorLED_HiLoState = !AliveErrorLED_HiLoState;

      // 1-wire
        // Serial.print("Getting temperatures...\n\r");
digitalWrite( AliveErrorLED , HIGH );
        // Get the temperatures into a variable
          TempSensors_Temps[0] = printTemperature(S01_Metal1);
          TempSensors_Temps[1] = printTemperature(S02_Metal2);
          TempSensors_Temps[2] = printTemperature(S03_TO92);
          
        // Initiate a temperature conversion
          sensors.requestTemperatures();    // If set the command "sensors.setWaitForConversion(false);" is applied in the setup, this command here ("sensors.requestTemperatures();") must be applied AFTER fetching / getting the temperatures ("printTemperature"), otherwise, (a) "+85" reading(s) can/will occur because it does not have the time.
digitalWrite( AliveErrorLED , LOW );
// ==> Takes measured 45 ms

digitalWrite( LED_BUILTIN , HIGH );
      // OLED-Display
        // Blanks for safety if temp sense temp values  "are out of range":
          for (uint8_t i = 0; i < 8; i++) {   // For all 8 lines
              u8x8.drawString(2, i, " ");
              u8x8.drawString(8, i, " ");
              u8x8.drawString(13, i, " ");
          }
  
        // Display the set temperatures
          // Draw blanks at the end of the last 2 lines because to see which line = which sensors controls the compressor
            u8x8.drawString(8, 6, "        ");
            u8x8.drawString(8, 7, "        ");
          
        // Write temperatures to OLED-Display
          u8x8.drawString(0, 0, "CI");   // Cold Into the plate heat exchanger
          u8x8.drawString(0, 1, "CO");   // Cold Out of the plate heat exchanger
          u8x8.drawString(0, 2, "HC");   // Hot out of the Compressor
          u8x8.setCursor(3,0);  // Set cursor to column 3 of display (starting with column "0")
          for (uint8_t i = 0; i < NUM_OW_SENSORS; i++) {  
            u8x8.setCursor(3,i);  // Set cursor to column 3 of display (starting with column "0")
            u8x8.print(TempSensors_Temps[i],2);
          }

        // Show that uC and display is alive and switch "Alive/Error LED":   // If everything ok, then AliveErrorLED = "HI,LO,LO,LO", else "HI,LO,HI,HI" PWM.
          switch (uCalive) {
            case 1:
              u8x8.drawString(15, 0, "-");
              uCalive = 2;
              break;
            case 2:
              u8x8.drawString(15, 0, "\\");
              uCalive = 3;
              break;
            case 3:
              u8x8.drawString(15, 0, "|");
              uCalive = 4;
              break;
            case 4:
              u8x8.drawString(15, 0, "/");
              uCalive = 1;
              break;
            default:
              u8x8.drawString(15, 0, "E");    // Error !
              break; // Wird nicht benötigt, wenn Statement(s) vorhanden sind
          }
          
        // Update OLED-Display
          u8x8.refreshDisplay();    // only required for SSD1606/7
digitalWrite( LED_BUILTIN , LOW );
// ==> Takes measured 75 ms
}


/***************************************************************************************/
/* Main: Loop          // put your main code here, to run repeatedly:                  */
/***************************************************************************************/
void loop(void)
{ 
  // Timing for the endless Arduino program loop  // Scheduler: Especially for flow-sensor
    currentTime = millis();
    
  // Execution every "waitTime1" ms
    if ( currentTime - timer1 > waitTime1 )
    {
      timer1 = currentTime;
      func_Task_exec_every_waitTime1();
    }

  // Execution every "waitTime2" ms
    if ( currentTime - timer2 > waitTime2 )
    {
      timer2 = currentTime;
      func_Task_exec_every_waitTime2();
    }
}

I found one for me strange behavior what I do not understand and I would like to ask you, guys, but slowly one step after the other.

Step 1:

I measured (with oscilloscope) the time it needs for the 1-wire stuff (time between the 2 commands “digitalWrite( AliveErrorLED , ... );” , with following results:

       | Wait for conv.

Resol. | True | False

12 bit | 790 ms | 45 ms

11 bit | 420 ms | 45 ms

10 bit | 230 ms | 45 ms

For the following steps done, I chose “12” bit and applied “sensors.setWaitForConversion(false);”.

Step 2:

Next, I had the following setup: There had been 2 changes with respect to the code shown above:

a) The wait time 2 was still defined with a high value “# define waitTime2 2000

b) The command “sensors.requestTemperatures();” was still applied BEFORE getting the temperature values (with “printTemperature(...)”).

As soon as the program execution got from setup (doing one proper temp. conversion and reading e.g. +20°C) to reach the Arduino “loop”, the value for one sensor, namely “S03_TO92” turned immediately into a “+85” reading. The other 2 temperature sensors were reading a correct value.

Step 3:

I changed b), so I put the “sensors.requestTemperatures();” AFTER the “printTemperature(...)” commands, and everything was fine (so the real temperature was read, e.g. +20°C). I said for myself, the reason will be that it has now enough time (namely almost 2 seconds, because of “waitTime2”) from requesting the temperatures until the next loop iteration temperature fetch. ((Maybe this is wrong, see the next Step 4)).

Step 4:

For verification for my established theory in Step 3, I now DECREASED the “waitTime2” to 700 ms, and I expected a “+85” reading. Why? Because it needs, as measured in step 1, 790 ms for a valid temperature conversion, but I allowed it for one whole loop iteration to be only 700 ms! So a whole loop iteration has passed already after 700ms and there it starts finding at the beginning of the sub-program “void func_Task_exec_every_waitTime2(void)” the command “printTemperature” again, but now only after approx. 700ms which should be too short for a 12 bit temperature conversion. To my surprise: It WORKED, so I got a valid temperature conversion (e.g. +20°C).

Step5:

I decreased “waitTime2” in steps of 100ms and finally I found out that with 600 ms the whole thing is still working correctly, and with 500 ms, it starts to fail (again sensor “S03_TO92” reading “+85”, but the other 2 sensors still correct.)

My question now: Can someone explain this, for me, unexpected behaviour? In summary, I would have expected a temp. reading fail (+85) below a loop time (“waitTime2”) of approximately 865ms (790ms for 1-wire reading + 75 ms required for the display), because with e.g. 600ms, it iterates through the Arduino loop and finds much quicker now the “printTemperature” command in the next loop iteration. Could an internal memory storage explain this maybe?

And much more important: Is my “non-blocking” code, having merged all the suggestions from you professional guys, shown above now correctly written? Or do you see a “do not do this!” somewhere inside?

Thanks a lot,

bernd2700

It would seem that you are already doing things properly, and are now looking for problems that aren't really there.

I have dozens of this sensors in place running for years. I assume you are hunting hardware issues (Proper shielded cables) with software guns. Can become a long hunting trip.

Well put!

Dear guys!

Some time has passed since my last post, and the good thing: The whole thing runs WITHOUT ANY ERROR since post #145 = since Okt. 2023 (today is the 11.1.2024) (still without a watchdog circuitry).
I think we can call this now a solution!
Thanks to YOUR help, I managed it now, I think!

SHORT SUMMARY:

For me, the main items why the code before was not working properly (remember , I had intermittent -127°C and +85°C readings on the 1-wire temperature sensors) and now IS working, are as follows:

  1. Use as basis the "Hacktronics tutorial" Arduino 1-Wire Tutorial
  2. Remove all the serial commands from the code
  3. Soldered additional blocking caps between VCC and GND directly onto the Arduino Nano board.

With these 3 measures, the errors were gone I think.

I put 2 more "things" now in the code:

  1. Additionally, I re-programmed my code to non-blocking form (i.e. do not wait for a temperature conversion), as this is good programming style, as suggested.
  2. I added a hardware watchdog circuitry and tested it so far on a replica Arduino Nano board and it works.

So here is my "final" code I think, at least connected to the above written issues I had. Of course in the future, I will add more features, but this is another story... :

// This Arduino sketch reads DS18B20 "1-Wire" digital
// temperature sensors.
// Tutorial:
// http://www.hacktronics.com/Tutorials/arduino-1-wire-tutorial.html


/****************** Include Files ******************************************************/
// "" => Looks in the same directory as the 'C' file I compile
// <> => Looks in the library paths

// OLED-Display
  #include <U8x8lib.h>
  
// 1-wire
  #include <OneWire.h>
  #include <DallasTemperature.h>

// MCP3221  (For I2C)
  #include "MCP3221.h"

/****************** Constants **********************************************************/
// WTD Watchdog "STWD100YNYWY3F": Timeout twd = 1.6 sec. ; tpw = 210 ms
  #define WTD_EN_Q_pin 6     // Pin D6
  #define WTD_WDI_pin 7      // Pin D7

// VCC voltage reference: Used for MCP3221 and internal Arduino ADC
  const float VCC_VREF_V = 5.02;    // Voltage reference ( = VCC) for in units [V] ; Measured / verified with Fluke 289 on 29.12.2023: 5.02V correct directly at added blocking capacitors which were added on 10. and 11.10.2023

// Timing for the endless Arduino program loop
  #define waitTime1 1000   // [ms] // For flow meter 1s
  #define waitTime2 3000   // [ms]
  
// 1-wire
  #define ONE_WIRE_BUS 2                  // Data wire is plugged into port D2 on the Arduino;  Make sure a pull-up resistor (e.g. 4k7) is connected (so from Data to VCC) ; Changed from 1k to 4k7 on 21.10.22.
  #define TEMPERATURE_PRECISION 12        // 12 is maximum but slower.
  #define NUM_OW_SENSORS 8                // the number of DS18B20 sensors on the 1-Wire bus.

// MCP3221  (For I2C)
    //  Each MCP3221 has 1 of 8 possible I2C addresses (factory hardwired & recognized by its specific part number & top marking on the package itself):
    //       PART                  DEVICE I2C ADDRESS          PART
    //      NUMBER             (BIN)      (HEX)     (DEC)     MARKING
    //  MCP3221A0T-E/OT       01001000      0x48       72       GE
    //  MCP3221A1T-E/OT       01001001      0x49       73       GH
    //  MCP3221A2T-E/OT       01001010      0x4A       74       GB
    //  MCP3221A3T-E/OT       01001011      0x4B       75       GC
    //  MCP3221A4T-E/OT       01001100      0x4C       76       GD
    //  MCP3221A5T-E/OT       01001101      0x4D       77       GA
    //  MCP3221A6T-E/OT       01001110      0x4E       78       GF
    //  MCP3221A7T-E/OT       01001111      0x4F       79       GG
    
  const byte SLAVE1 = 0x4E;                 // I2C address of the MCP3221 for measuring the compressor current
  const byte SLAVE2 = 0x4F;                 // I2C address of the MCP3221 for measuring the pump current
  const float MPC3221_VREF_V = VCC_VREF_V;  // Voltage reference ( = VCC) for the MCP3221 in units [V]

// ACS723 over MCP3221
  // Sensitivity
    const float SENS_ACS723_05__V_PER_A = 0.4;    // SENSitivity of the "ACS723LLCTR-05AB-T" in units [V/A]
    const float SENS_ACS723_10__V_PER_A = 0.2;    // SENSitivity of the "ACS723LLCTR-10AB-T" in units [V/A] 

// Internal ADC for 12V VBB (VBAT) voltage reading
  const int VBB_MEAS_ANALOG_IN_PIN = A6;          // Pin used for voltage VBB (VBAT) measurement reading through internal Arduino ADC
  const float VBB_MEAS_RES_DIV_GAIN = 4;          // Gain setting of the RESistor DIVider (potentiometer) between the VBB (VBAT) voltage (max. 20V foreseen) to VCC related (approx. 5V nom).

// Alive / Error LED
  const int AliveErrorLED = 4;                    // Pin "D4"

// Switches ( = Pushbuttons)
  #define ERROR_WINDOW_SW 30  // +/- this value
  int AnalogSwPin = 7;   // switch circuit input connected to analog pin 7

// Compressor switch on / off
  #define ComprOnOffPin A3        // An analog hardware is connected to pin A3 which switches the relay off immediately as soon as this pin is going low. If this pin is going high, approx. 7 min has to be waited due to an RC time constant until the relay switches on. 
  
// Misc.
  #define DEBUG_OFF


// ??????????????????????? ****************** WAS IST DAS ?????  **********************************************************`?????????????????????????????/
// 1-wire
// Setup a oneWire instance to communicate with any OneWire devices
  OneWire oneWire(ONE_WIRE_BUS);

// Pass our oneWire reference to Dallas Temperature. 
  DallasTemperature sensors(&oneWire);

// Assign the addresses of your 1-Wire temp sensors.
// See the tutorial on how to obtain these addresses:
// http://www.hacktronics.com/Tutorials/arduino-1-wire-address-finder.html
  DeviceAddress S01_ColdIntoPWT   = { 0x28, 0x41, 0x6B, 0x07, 0xD6, 0x01, 0x3C, 0xAA };   // S01_ColdIntoPWT   = TempSensors_Temps[0]
  DeviceAddress S02_ColdFromPWT   = { 0x28, 0x4F, 0xEA, 0x07, 0xD6, 0x01, 0x3C, 0xBF };   // S02_ColdFromPWT   = TempSensors_Temps[1]
  DeviceAddress S03_HotFromCompr  = { 0x28, 0xCF, 0xC2, 0x07, 0xD6, 0x01, 0x3C, 0x93 };   // S03_HotFromCompr  = TempSensors_Temps[2]
  DeviceAddress S04_HotFromPWT    = { 0x28, 0xD4, 0x45, 0x07, 0xD6, 0x01, 0x3C, 0xAA };   // S04_HotFromPWT    = TempSensors_Temps[3]
  DeviceAddress S05_AmbientOfUnit = { 0x28, 0xC9, 0x05, 0x07, 0xD6, 0x01, 0x3C, 0x52 };   // S05_AmbientOfUnit = TempSensors_Temps[4]
  DeviceAddress S06_InsideFluid   = { 0x28, 0xAA, 0xD5, 0xAC, 0x1D, 0x13, 0x02, 0xE5 };   // S06_InsideFluid   = TempSensors_Temps[5]
  DeviceAddress S07_CoolBoxS01    = { 0x28, 0xD4, 0xD1, 0xEA, 0x32, 0x14, 0x01, 0xDF };   // S07_CoolBoxS01    = TempSensors_Temps[6]
  DeviceAddress S08_CoolBoxS02    = { 0x28, 0xAA, 0xC3, 0xDB, 0x1D, 0x13, 0x02, 0x2B };   // S08_CoolBoxS02    = TempSensors_Temps[7]


/****************** Constructors ******************************************************/
// OLED-Display
  U8X8_SH1106_128X64_NONAME_HW_I2C u8x8(/* reset=*/ U8X8_PIN_NONE);       // Please update the pin numbers according to your setup. Use U8X8_PIN_NONE if the reset pin is not connected


/****************** Variables **********************************************************/
// Arduino program loop
  uint32_t currentTime;
  uint32_t timer1;
  uint32_t timer2;
  
// 1-wire
  static float TempSensors_Temps[NUM_OW_SENSORS];                          // Array which holds the current temperatures of all 1-wire temperature sensors

// Temperature control
  // Inside cooling box, set the initial value to which the system shall control the temperatures of the water e.g.
    float Temp_CoolBoxS0x_Lo = +0.1; // -0.3; Upd#002
    float Temp_CoolBoxS0x_Hi = +0.7; // +0.5; Upd#002
    bool Change_S01_Lo_or_Hi = false;     // If the switches / keys shall change the "Lo" or the "Hi" value of the "S01" temperature sensor.
    int TempSenseForCompressorCtrl = 8;   // Defines the current active tempsens which controls the compressor, either "7" = "Ext. S01" or "8" = "Ext. S02"

// Flow-sensor
  volatile  int   flow_frequency;   // Measures flow sensor pulses
            float l_minute = 0.0;   // Calculated litres/minute
  unsigned  char  flowsensor = 3;   // Sensor Input on port D3

// MCP3221
  //static unsigned int Compr_Cur_DigCode;    // COMPRessor digital code read through MCP3221 ( 0 .. 4095 )
  static float Compr_Cur_DigCode;    // COMPRessor digital code read through MCP3221 ( 0 .. 4095 )
  static float Compr_Cur_A;          // COMPRessor CURrent read through MCP3221 stored in this variable in units "[A]"
  static float Pump_Cur_DigCode;     // PUMP       digital code read through MCP3221 ( 0 .. 4095 )
  static float Pump_Cur_A;           // PUMP       CURrent read through MCP3221 stored in this variable in units "[A]"

// Compressor switch on / off
  bool ComprOnOff = false;        // If the compressor shall be turned on or off

// Internal ADC for 12V VBB (VBAT) voltage reading
  static int   VBBmeas_ADC_val_DigCode = 0;
  static float VBBmeas_ADC_val_V = 0;    // ADC value for VBB (VBAT) measurement in units [V] but still from 0 .. 5V (not converted)
  static float VBBmeas_VBB_V  = 0;       // VBB (VBAT) measurement: VBB measured / converted in(to) units [V]
  
// Misc
  static unsigned short SysErr = 0;       // If there is an error in the system, e.g. overtemperature of the compressor etc.
  static unsigned short uCalive = 1;      // Change value every e.g. 1s and display some character on OLED display

// WTD Watchdog "STWD100YNYWY3F": Timeout twd = 1.6 sec. ; tpw = 210 ms
  bool WTD_WDI = false;

/***************************************************************************************/
/* Interrupt Subprogram / Function                                                     */
/***************************************************************************************/
void flow () // Interrupt function
{
   flow_frequency++;
}


/***************************************************************************************/
/* Subprogram                                                                          */
/***************************************************************************************/
// I2C Scanner from: "https://forum.arduino.cc/index.php?topic=632881.0" ; This sketch tests the standard 7-bit addresses, Devices with higher bit address might not be seen properly.
// If called stand-alone, it needs "#include <Wire.h>".
void func_I2C_Scanner()
{
  digitalWrite( AliveErrorLED , HIGH );
  byte error, address;
  int nDevices;

  #ifdef DEBUG_ON
    Serial.print(F("\n----------------------\n"));
    Serial.println("Scanning for I2C devices ...");
    nDevices = 0;
  #endif
  
  for(address = 1; address < 127; address++ )
  {
    Wire.beginTransmission(address);
    
    #ifdef DEBUG_ON
      error = Wire.endTransmission();   // The i2c_scanner uses the return value of the Write.endTransmisstion to see if a device did acknowledge to the address.
      if (error == 0)
      {
        Serial.print("I2C device found at address 0x");
        if (address<16)
          Serial.print("0");
        Serial.print(address,HEX);
        Serial.println("  !");   
        nDevices++;
      }
      else if (error==4)
      {
        Serial.print("Unknown error at address 0x");
        if (address<16)
          Serial.print("0");
        Serial.println(address,HEX);
      }
    #endif
  }
  #ifdef DEBUG_ON
    if (nDevices == 0)
      Serial.println("No I2C devices found\n");
    else
      Serial.println("done\n");
  #endif
}


/***************************************************************************************/
/* Subprogram                                                                          */
/***************************************************************************************/
// Read 3 Switches = Pushbuttons over an analog input pin.
// (c) Bernd Cettl, 07/2021, based on script from "Doug LaRue" from "Nov. 2008".

/*
 *   analogPin                 VCC (+5 V)
 *      |                         |
 *      |                         |
 *      o --------------          | 
 *      |              |          |
 *      |              \          |
 *    -----      120R  /          |    
 *    -----  100nF     \          |
 *      |              /          |
 *      |              \          |
 *    _____            |____ \____|
 *     ___  ground     |   SW1    |
 *      _              \          \
 *                     /          /   
 *               1k5   \          \   1k5
 *                     /          /
 *                     \          \
 *                     |____ \____|
 *                     |   SW2    |
 *                     \          \
 *                     /          /   
 *               1k5   \          \   1k5
 *                     /          /
 *                     \          \
 *                     |____ \____|
 *                     |   SW3           
 *                     \
 *               1k5   /   
 *                     \   
 *                     /
 *                     \
 *                     |
 *                   _____   
 *                    ___     ground
 *                     _
 *
 */

int buttonPushed(int pinNum) {
  int val;         // variable to store the read value
    val = analogRead(pinNum);   // read the input pin
    
    #ifdef DEBUG_ON
      Serial.print(F("Switch / Button pressed read ADC value still in digital code (0..1023):  "));
      Serial.print(val);
      Serial.print(F("[]\n"));
    #endif

    if ( val >= (1023-ERROR_WINDOW_SW) and val <= (1023) ) { // 1022 .. 1023
      #ifdef DEBUG_ON
        Serial.println("switch 1 pressed/triggered");
      #endif
      return 1;
    }
    else if ( val >= (681-ERROR_WINDOW_SW) and val <= (681+ERROR_WINDOW_SW) ) { // 681
      #ifdef DEBUG_ON
        Serial.println("switch 2 pressed/triggered");
      #endif
      return 2;
    }
    else if ( val >= (340-ERROR_WINDOW_SW) and val <= (340+ERROR_WINDOW_SW) ) { // 340
      #ifdef DEBUG_ON
        Serial.println("switch 3 pressed/triggered");
      #endif
      return 3;
    }
    else if ( val >= (615-ERROR_WINDOW_SW) and val <= (615+ERROR_WINDOW_SW) ) { // 615
      #ifdef DEBUG_ON
        Serial.println("switch 2 AND 3 at same time pressed/triggered");
      #endif
      return 23;
    }
    else
      return 0;  // no button found to have been pushed
}


/***************************************************************************************/
/* Main: Setup          // put your setup code here, to run once:                      */
/***************************************************************************************/
void setup(void)
{
  // WTD
    pinMode( WTD_WDI_pin , OUTPUT );
    digitalWrite( WTD_WDI_pin , LOW );     // Set any value at setup, hi or lo does not matter, because this pin should toggle anyway. 
    
  // System LED  
    pinMode( LED_BUILTIN , OUTPUT );  
  
  // AliveErrorLED
    pinMode( AliveErrorLED , OUTPUT );
  
  // Compressor switch on / off
    pinMode( ComprOnOffPin , OUTPUT );
  
  // Switches
    pinMode( AnalogSwPin , INPUT );
    
  // start serial port
    #ifdef DEBUG_ON
      Serial.begin(9600);
    #endif

  // 1-wire
    // Do not wait for conversion
      sensors.setWaitForConversion(false);
    // Start up the library
      sensors.begin();
    // set the resolution to X bit
      sensors.setResolution(S01_ColdIntoPWT, TEMPERATURE_PRECISION);
      sensors.setResolution(S02_ColdFromPWT, TEMPERATURE_PRECISION);
      sensors.setResolution(S03_HotFromCompr, TEMPERATURE_PRECISION);
      sensors.setResolution(S04_HotFromPWT, TEMPERATURE_PRECISION);
      sensors.setResolution(S05_AmbientOfUnit, TEMPERATURE_PRECISION);
      sensors.setResolution(S06_InsideFluid, TEMPERATURE_PRECISION);
      sensors.setResolution(S07_CoolBoxS01, TEMPERATURE_PRECISION);
      sensors.setResolution(S08_CoolBoxS02, TEMPERATURE_PRECISION); 

    // Ask for a 1st conversion
      sensors.requestTemperatures();
      
  // Flow-sensor
     pinMode(flowsensor, INPUT);
     digitalWrite(flowsensor, HIGH); // Optional Internal Pull-Up
     attachInterrupt(digitalPinToInterrupt(flowsensor), flow, RISING); // Setup Interrupt


  // Start communication with I2C: Needed for MCP3221
      Wire.begin();   
  
  // I2C devices
    // I2C Scanner
      func_I2C_Scanner();
      
  // MCP3221: Hint from "https://forum.arduino.cc/index.php?topic=550117.0": Summary: It works, if we move the constructors ( = "MCP3221 mcp3221A(SLAVE1);" ; "MCP3221 mcp3221B(SLAVE2);") __INTO_ "loop()", thereby constructing 2 new slave devices at each cycle like so:
    MCP3221 mcp3221A(SLAVE1);
    // Ping
      #ifdef DEBUG_ON
        Serial.print(F("Slave A reading:\t"));
        Serial.print(mcp3221A.ping() ? (F("Not Found\n")) : (F("Found!\n")));
      #endif
    // Set different things
      mcp3221A.setSmoothing(NO_SMOOTHING);
    // Get raw data
      Compr_Cur_DigCode = mcp3221A.getData();
      #ifdef DEBUG_ON
        Serial.print(F("Compressor current still in digital code (0..4095):  "));
        Serial.print(Compr_Cur_DigCode);
        Serial.print(F("[]\n"));
      #endif
    MCP3221 mcp3221B(SLAVE2);
    // Ping
      #ifdef DEBUG_ON
        Serial.print(F("Slave B reading:\t"));
        Serial.print(mcp3221B.ping() ? (F("Not Found\n")) : (F("Found!\n")));
      #endif
    // Set different things
      mcp3221B.setSmoothing(NO_SMOOTHING);
    // Get raw data
      Pump_Cur_DigCode = mcp3221B.getData();
      #ifdef DEBUG_ON
        Serial.print(F("Pump current still in digital code (0..4095):  "));
        Serial.print(Pump_Cur_DigCode);
        Serial.print(F("[]\n"));
      #endif

  // OLED-Display
    u8x8.begin();
    u8x8.setPowerSave(0);
  
  // Write to OLED-Display
    u8x8.setFont(u8x8_font_chroma48medium8_r);
    u8x8.drawString(0,0,"Starting up...");
    u8x8.refreshDisplay();    // only required for SSD1606/7

  // Show setup display 2 seconds long
    delay(2000);
  
  // Clear display in order that some remaining characters are not displayed during the loop. E.g. If here in setup it says "Temperatures:" and later in the loop just say "Temps:" in the same line, that it doesn't write: "Temps:atures:"
    u8x8.clear();

  // Timing for the endless Arduino program loop
    timer1 = millis();
    timer2 = timer1;

  // WTD
    pinMode( WTD_EN_Q_pin , OUTPUT );       // Configure at END of setup as output, so that before it is default input and a pull-up resistor ties it high.
    digitalWrite( WTD_EN_Q_pin , LOW );    // Enable watchdog at when start-up procedure is finished. Should be the last command in "setup", because from this time on, the time "twd" on the watchdog chip is running.
}


/***************************************************************************************/
/* Subprogram                                                                          */
/***************************************************************************************/
float func_getTemperature(DeviceAddress deviceAddress)
{
  float tempC = sensors.getTempC(deviceAddress);
    #ifdef DEBUG_ON
      if (tempC == -127.00) {
        Serial.print("Error getting temperature");
      } else {
        Serial.print("C: ");
        Serial.print(tempC);
        Serial.print(" F: ");
        Serial.print(DallasTemperature::toFahrenheit(tempC));
      }
    #endif
  return(tempC);
}


/***************************************************************************************/
/* Subprogram                                                                          */
/***************************************************************************************/
void func_Task_exec_every_waitTime1(void)
{
  // WTD: Toggle
    WTD_WDI = !WTD_WDI;
    digitalWrite( WTD_WDI_pin , WTD_WDI );
        
  // Flow-sensor: Shall be the 1st entry in the loop (except Debug) because it shall be best exactly 1000ms and the difference how much it is more than 1000ms is calibrated away "(currentTime - cloopTime)", but if there are other time-consuming variable tasks in-between, this calibration is not good anymore. the 
    if(flow_frequency != 0){
      // Flow sensor "YF-S201": Frequency (Hz) = 7.5 * Flow rate (L/min) ; Pulses per Liter: 450 ;  Pulse frequency (Hz) = 7.5Q, Q is flow rate in L/min.  //l_minute = (flow_frequency / 7.5);   // (Pulse frequency x 60 min) / 7.5Q = flowrate in L/hour
      l_minute = 1000.0 / ( currentTime - timer1 ) * ( flow_frequency / 7.5 );     // Because the variables "currentTime" and e.g. "timer1" are both in units [ms], also the difference is e.g. 2000ms. So 1000/2000 = * 0.5, if executed every 2 seconds. Because if e.g. executed every 2 seconds, with same flow rate, the pulses are doubled ( flow_frequency * 2 ), and the time passed also "currentTime - timer1", so e.g. "1000.0/(2000)" = *0.5 ==> And with *2*0.5 = 1 again.
      flow_frequency = 0; // Reset Counter
      //Serial.print(l_minute, DEC); // Print litres/min
      //Serial.println(" l/min");
      l_minute = l_minute * 0.9;  // Correction: 3.0 l/min from Wasseruhr, YF-S201 displayed 3.33 l/min.  => After this correction measured approx. correct at least with flow rates checked with 1 (one) l/min, and 3 l/min (on 21.02.2021).
    }
    else {
      l_minute = 0;   // To not keep the last value forever if there is no more flow.
    }
    
  // Reset the time count right after (in order that not even more time passes than 1000ms) the Flow-Sensor but also not before it (otherwise calibration of flow sensor will fail, see there).
//    cloopTime = currentTime; // Updates cloopTime

  // 1-wire
    #ifdef DEBUG_ON
      Serial.print("Getting temperatures...\n\r");
    #endif

    // Get the temperatures into a variable         // Takes 100 ms getting all 8 temperatures into a variable ( = as follows ) , measured on 30.12.2023:  
      TempSensors_Temps[0] = func_getTemperature( S01_ColdIntoPWT );
      TempSensors_Temps[1] = func_getTemperature( S02_ColdFromPWT );
      TempSensors_Temps[2] = func_getTemperature( S03_HotFromCompr );
      TempSensors_Temps[3] = func_getTemperature( S04_HotFromPWT );
      TempSensors_Temps[4] = func_getTemperature( S05_AmbientOfUnit );
      TempSensors_Temps[5] = func_getTemperature( S06_InsideFluid );
      TempSensors_Temps[6] = func_getTemperature( S07_CoolBoxS01 );
      TempSensors_Temps[7] = func_getTemperature( S08_CoolBoxS02 );

    // Initiate a temperature conversion         // Takes 2.5 ms initiating a temperature conversion ( = as follows ) , measured on 30.12.2023:  
      sensors.requestTemperatures();    // If set the command "sensors.setWaitForConversion(false);" is applied in the setup, this command here ("sensors.requestTemperatures();") must be applied AFTER fetching / getting the temperatures ("func_getTemperature"), otherwise, (a) "+85" reading(s) can/will occur because it does not have the time.
      // Check if there is a temperature above 70°C, and if yes, set a "systen error" ("SysErr")
        int countAbove70 = 0;
          for( int i=0; i<NUM_OW_SENSORS; i++)
          {
            if( TempSensors_Temps[i] > 70.0)
            {
              countAbove70++;
            }
          }
          #ifdef DEBUG_ON
            Serial.print(F( "There are "));
            Serial.print( countAbove70);
            Serial.println(F( " sensors above 70.0"));
          #endif
          if( countAbove70 > 0)           // at least one sensor above 70 degrees
          {
            SysErr = 1;
          }
          else
          {
            SysErr = 0;
          }

  // MCP3221:     // Takes approx. only 220 us the complete MCP3221 ( = as follows ) , measured on 30.12.2023.        // Hint from "https://forum.arduino.cc/index.php?topic=550117.0": Summary: It works, if we move the constructors ( = "MCP3221 mcp3221A(SLAVE1);" ; "MCP3221 mcp3221B(SLAVE2);") __INTO_ "loop()", thereby constructing 2 new slave devices at each cycle like so:
    // Set different things and get raw data    
      MCP3221 mcp3221A(SLAVE1);
      mcp3221A.setSmoothing(NO_SMOOTHING);      // Obviously has to be repeated here in the loop. Is not enough to once define it in the setup.
      Compr_Cur_DigCode = mcp3221A.getData();
      MCP3221 mcp3221B(SLAVE2);
      mcp3221B.setSmoothing(NO_SMOOTHING);      // Obviously has to be repeated here in the loop. Is not enough to once define it in the setup.
      Pump_Cur_DigCode = mcp3221B.getData();
    // Print raw data to serial
      #ifdef DEBUG_ON
        Serial.print(F("Compressor current still in digital code (0..4095):  "));
        Serial.print(Compr_Cur_DigCode);
        Serial.print(F("[]\n"));
        Serial.print(F("Pump current still in digital code (0..4095):  "));
        Serial.print(Pump_Cur_DigCode);
        Serial.print(F("[]\n"));
      #endif
    // Convert raw data to current
      Compr_Cur_A = MPC3221_VREF_V * ( 2 * Compr_Cur_DigCode - 4096 ) / ( 4096 * 2 * SENS_ACS723_10__V_PER_A );
      Pump_Cur_A  = MPC3221_VREF_V * ( 2 * Pump_Cur_DigCode  - 4096 ) / ( 4096 * 2 * SENS_ACS723_05__V_PER_A );
    // Print converted currents to Amperes to serial
      #ifdef DEBUG_ON
        Serial.print(F("Compressor current in units [A]:  "));
        Serial.print(Compr_Cur_A);
        Serial.print(F("[]\n"));
        Serial.print(F("Pump current in units [A]:  "));
        Serial.print(Pump_Cur_A);
        Serial.print(F("[]\n"));
      #endif

  // 12V VBB (VBAT) voltage reading (internal ADC)           // Takes approx. only 130 us the complete 12V VBB (VBAT) voltage meas. ( = as follows ) , measured on 30.12.2023.
    VBBmeas_ADC_val_DigCode = analogRead( VBB_MEAS_ANALOG_IN_PIN );
    VBBmeas_ADC_val_V = VBBmeas_ADC_val_DigCode * ( VCC_VREF_V / 1024 );
    VBBmeas_VBB_V = VBBmeas_ADC_val_V * VBB_MEAS_RES_DIV_GAIN;

  // Switches
      int buttNum = buttonPushed(AnalogSwPin);
      
      #ifdef DEBUG_ON
        Serial.print("Button "); Serial.print(buttNum); Serial.println(" was pushed.");  
      #endif
      
      if ( Change_S01_Lo_or_Hi == false ) {           // If "Change_S01_Lo_or_Hi" = e.g. Lo ( = e.g. "false") ==> Allow to modify the "Lo" value with the switches / keys.
        if ( buttNum == 1 ) {
          Temp_CoolBoxS0x_Lo = Temp_CoolBoxS0x_Lo + 0.1;
        }
        else if ( buttNum == 2 ) {
          Temp_CoolBoxS0x_Lo = Temp_CoolBoxS0x_Lo - 0.1;
        }   
      }
      else {                                          // If "Change_S01_Lo_or_Hi" = e.g. Hi ( = e.g. "true") ==> Allow to modify the "Hi" value with the switches / keys.
        if ( buttNum == 1 ) {
          Temp_CoolBoxS0x_Hi = Temp_CoolBoxS0x_Hi + 0.1;
        }
        else if ( buttNum == 2 ) {
          Temp_CoolBoxS0x_Hi = Temp_CoolBoxS0x_Hi - 0.1;
        }
      }

      if ( buttNum == 3 ) {                           // Button nr. 3 changes the modification of either the "Lo" or "Hi" value of the "S01".
        Change_S01_Lo_or_Hi = !Change_S01_Lo_or_Hi;
      }

      if ( buttNum == 23 ) {                           // Button nr. 2 and 3 at same time changes the tempsense for active compressor control
        if ( TempSenseForCompressorCtrl == 7 ) {
          TempSenseForCompressorCtrl = 8;                             // Change the tempsense for active compressor control
          #ifdef DEBUG_ON
            Serial.println("TempSenseForCompressorCtrl = 8 was set");
          #endif
        }
        else if ( TempSenseForCompressorCtrl == 8 ) {
          TempSenseForCompressorCtrl = 7;                             // Change the tempsense for active compressor control
          #ifdef DEBUG_ON
            Serial.println("TempSenseForCompressorCtrl = 7 was set");
          #endif
        }
      }

    // Higher limit must be higher than the lower limit, because it does only cooling
      if ( Temp_CoolBoxS0x_Lo >= Temp_CoolBoxS0x_Hi ) {
        Temp_CoolBoxS0x_Hi = Temp_CoolBoxS0x_Lo + 1;
      }
      
      #ifdef DEBUG_ON
        Serial.print("Temp_CoolBoxS0x_Lo = "); Serial.println(Temp_CoolBoxS0x_Lo);
        Serial.print("Temp_CoolBoxS0x_Hi = "); Serial.println(Temp_CoolBoxS0x_Hi);
      #endif
    
  // Compressor switch on / off control
    if ( SysErr == 1 ) {                                    // If a system error ( = e.g. critical temperature is reached anywhere) occurred ...
      ComprOnOff = false;                                   // ... turn off the compressor
    }
    else {
      if ( TempSensors_Temps[TempSenseForCompressorCtrl-1] < Temp_CoolBoxS0x_Lo ) {      // If the temperature of sensor "S0x" (so ext. Sensor "S01" or "S02") is <= as the minimum set temperature ...
        ComprOnOff = false;                                   // ... turn off the compressor
      }
      if ( TempSensors_Temps[TempSenseForCompressorCtrl-1] > Temp_CoolBoxS0x_Hi ) {      // If the temperature of sensor "S0x" (so ext. Sensor "S01" or "S02") is <= as the minimum set temperature ...
        ComprOnOff = true;                                    // ... turn on the compressor
      }
    }

    if ( ComprOnOff == false ) {
      digitalWrite( ComprOnOffPin , LOW );
    }
    if ( ComprOnOff == true ) {
      digitalWrite( ComprOnOffPin , HIGH );
    }

  // OLED-Display    // Takes 220 .. 230 ms writing the complete display ( = as follows ) , measured on 30.12.2023.
    // Blanks for safety if temp sense temp values  "are out of range" or if the decimal point (".") changes position due to the minus sign ("-"). To write the full display with blank characters / strings does not look nice because it is too slow.
      for (uint8_t i = 0; i < NUM_OW_SENSORS; i++) {   // For all 8 lines
        u8x8.drawString(2, i, " ");
        u8x8.drawString(7, i, " ");
        u8x8.drawString(8, i, " ");
        u8x8.drawString(13, i, " ");
      }

    // Draw blanks at the end of the last 2 lines because to see which line = which sensors controls the compressor
      u8x8.drawString(8, 6, "        ");
      u8x8.drawString(8, 7, "        ");

    // Write temperatures to OLED-Display
    	u8x8.drawString(0, 0, "CI");   // Cold Into the plate heat exchanger
    	u8x8.drawString(0, 1, "CO");   // Cold Out of the plate heat exchanger
    	u8x8.drawString(0, 2, "HC");   // Hot out of the Compressor
    	u8x8.drawString(0, 3, "HO");   // Hot Out of the plate heat exchanger
    	u8x8.drawString(0, 4, "AT");   // Ambient Temperature
    	u8x8.drawString(0, 5, "IF");   // Inside Fluid
    	u8x8.drawString(0, 6, "S1");   // CoolBox inside Sensor 01
    	u8x8.drawString(0, 7, "S2");   // CoolBox inside Sensor 02
    	for (uint8_t i = 0; i < NUM_OW_SENSORS; i++) {  
    	  u8x8.setCursor(3,i);  // Set cursor to column 3 of display (starting with column "0")
    	  u8x8.print(TempSensors_Temps[i],2);
    	}

    // Write flow rate to OLED-Display
      u8x8.drawString(9, 1, "     ");  // Obviously additionally needed to clear this part of the display, otherwise could happen, that if number falls below 4 digits (e.g. "1000"), then the last "0" remains, so e.g. if first was "1234mV" displayed, then only "980mV" that the display showed "9804mV".
      u8x8.setCursor(9,1);
      u8x8.print(l_minute,2);
      u8x8.drawString(9, 0, "CAL!");  // Durchfluss-Sensor brauch erneute Kalibration nachdem die LoopTime ohne Delay umgestellt worden ist!!
      u8x8.drawString(14, 1, "FR");
  
    // Write compressor and pump current to OLED-Display
      u8x8.drawString(9, 2, "     ");  // Obviously additionally needed to clear this part of the display, otherwise could happen, that if number falls below 4 digits (e.g. "1000"), then the last "0" remains, so e.g. if first was "1234mV" displayed, then only "980mV" that the display showed "9804mV".
      u8x8.setCursor(9,2);
      u8x8.print(Compr_Cur_A , 1);     // Although "unsigned int", "1" decimal place necessary; with "0", it doesn't display the voltage
      u8x8.drawString(14, 2, "CC");   // CC = Compressor Current
      u8x8.drawString(9, 3, "     ");  // Obviously additionally needed to clear this part of the display, otherwise could happen, that if number falls below 4 digits (e.g. "1000"), then the last "0" remains, so e.g. if first was "1234mV" displayed, then only "980mV" that the display showed "9804mV".
      u8x8.setCursor(9,3);
      u8x8.print(Pump_Cur_A , 1);      // Although "unsigned int", "1" decimal place necessary; with "0", it doesn't display the voltage
      u8x8.drawString(14, 3, "PC");   // PC = Pump Current
    
    // Write VBB voltage to OLED-Display
      u8x8.drawString(9, 4, "     ");  // Obviously additionally needed to clear this part of the display, otherwise could happen, that if number falls below 4 digits (e.g. "1000"), then the last "0" remains, so e.g. if first was "1234mV" displayed, then only "980mV" that the display showed "9804mV".
      u8x8.setCursor(9,4);
      u8x8.print(VBBmeas_VBB_V , 1);     // Although "unsigned int", "1" decimal place necessary; with "0", it doesn't display the voltage
      u8x8.drawString(14, 4, "VB");   // VB = VBB (VBAT) = nom. 12V

    // Switches
      // u8x8.setCursor(15,5);
      // u8x8.print(buttNum , 1);     // Although "unsigned int", "1" decimal place necessary; with "0", it doesn't display the voltage
    
    // Compressor state
      if ( ComprOnOff == false ) {
        u8x8.drawString(13, 5, "OFF");
      }
      if ( ComprOnOff == true ) {
        u8x8.drawString(13, 5, " ON");
      }

    // Display the set 2 temperature threshold values (switch-on and switch-off threshold)
      // Lower value
        u8x8.drawString(8, TempSenseForCompressorCtrl-1, "    ");
        if ( Temp_CoolBoxS0x_Lo < 0 ) {
          u8x8.drawString(8, TempSenseForCompressorCtrl-1, "-");
        }
        else {
          u8x8.drawString(8, TempSenseForCompressorCtrl-1, "+");
        }
        u8x8.setCursor(9,TempSenseForCompressorCtrl-1);
        u8x8.print( abs(Temp_CoolBoxS0x_Lo) , 1);     // Although "unsigned int", "1" decimal place necessary; with "0", it doesn't display the voltage

      // Higher value
        u8x8.drawString(12, TempSenseForCompressorCtrl-1, "   ");      // One blank " " less thank above ( = with "Temp_CoolBoxS0x_Lo") because end column of display. 
        if ( Temp_CoolBoxS0x_Hi < 0 ) {
          u8x8.drawString(12, TempSenseForCompressorCtrl-1, "-");
        }
        else {
          u8x8.drawString(12, TempSenseForCompressorCtrl-1, "+");
        }
        u8x8.setCursor(13,TempSenseForCompressorCtrl-1);
        u8x8.print( abs(Temp_CoolBoxS0x_Hi) , 1);     // Although "unsigned int", "1" decimal place necessary; with "0", it doesn't display the voltage

    // Show that uC and display is alive and switch "Alive/Error LED":   // If everything ok, then AliveErrorLED = "HI,LO,LO,LO", else "HI,LO,HI,HI" PWM.
      switch (uCalive) {
        case 1:
          u8x8.drawString(15, 0, "-");
          uCalive = 2;
          digitalWrite( LED_BUILTIN , HIGH ); 
          digitalWrite( AliveErrorLED , HIGH );
          break;
        case 2:
          u8x8.drawString(15, 0, "\\");
          uCalive = 3;
          digitalWrite( LED_BUILTIN , LOW ); 
          digitalWrite( AliveErrorLED , LOW );
          break;
        case 3:
          u8x8.drawString(15, 0, "|");
          uCalive = 4;
          if ( SysErr >= 1 )
            digitalWrite( AliveErrorLED , HIGH );
          break;
        case 4:
          u8x8.drawString(15, 0, "/");
          uCalive = 1;
          break;
        default:
          u8x8.drawString(15, 0, "E");    // Error !
          break; // Wird nicht benötigt, wenn Statement(s) vorhanden sind
      }

    // Update OLED-Display
      u8x8.refreshDisplay();    // only required for SSD1606/7
}


/***************************************************************************************/
/* Subprogram                                                                          */
/***************************************************************************************/
void func_Task_exec_every_waitTime2(void)
{
  // delay(50);
}


/***************************************************************************************/
/* Main: Loop          // put your main code here, to run repeatedly:                  */
/***************************************************************************************/
void loop(void)
{ 
  // Timing for the endless Arduino program loop  // Scheduler: Especially for flow-sensor
    currentTime = millis();
    
  // Execution every "waitTime1" ms
    if ( currentTime - timer1 > waitTime1 )
    {
      func_Task_exec_every_waitTime1();
      timer1 = currentTime;                         // Assign this variable only at the end after (all the) function call(s) (execution(s)), because inside those execution(s), the timer variable(s) (such es e.g. "timer1" , "timer2") might be used. If this line would be placed before the function calls, the timer variables woulld have the very same value as the variable "currentTime".)
    }

  // Execution every "waitTime2" ms
    if ( currentTime - timer2 > waitTime2 )
    {
      func_Task_exec_every_waitTime2();
      timer2 = currentTime;                         // Assign this variable only at the end after (all the) function call(s) (execution(s)), because inside those execution(s), the timer variable(s) (such es e.g. "timer1" , "timer2") might be used. If this line would be placed before the function calls, the timer variables woulld have the very same value as the variable "currentTime".)
    }
}

Thank you so much for all your help, have a nice year 2024, and bye,
bernd2700

Since both your wait times exceed the DS18B20 conversion time, the above is probably a pointless waste of code.

Dear Nick_Pyner,

I don't think so that it is "a pointless waste of code", since the 12 bit takes 790ms (of course I could, as already said, decrease the resolution, but that's what it is now given with this code) plus processing the OLED display takes another 230ms ==> is already >1s together, so only those 2 would already violate the 1s loop time. So I think therefore it's not waste of code, correct? Now, with the option set "do not wait for conversion" , it takes only 100ms + 230ms OLED + other stuff = well below the 1s loop time.

No.
If your loop time is one second, you have allowed for the 750ms needed by the sensor to do its job. The sensor operates independently from Arduino. All you have to do is not request an answer too frequently.

I think the tutorial has a 2 second loop, but that is misleading and it works fine with one second.