Controling 2 relays (SRD-50VDC-SL-C) depending on 2 temp sensors (DS18B20)

Hello everyone!
I am a little bit nervous, this is my first post in here, I hope I will do everthing acurate now! Just give me a hint how to do better if I make some mistakes ::slight_smile:

I played around with Arduino for about 1 week now, an I am really enthusiastic, not just about the hole new world to control everything, but also this great community and how people help each other!

After I did the projects in the project book (starter kit) I wanted to make a “real” project, and it was about my heating system, controling the circulation pumps for the boiler and to the radiators:

500L storage tank for storing hot water, connected to a boiler (fire wood)
The pumps shall be controlled depending on the temperature in the storage boiler
A controll LED shall indicate if the sensors have a failure

Using two DS18B20 Temperature sensors DS18B20 (Store, Sweden) to measure
–>01 temperature going into storage tank (at the top, from the boiler)
–>02 temperature going out from storage tank (at the bottom, to the boiler)

Controlling 2 pumps (230VAC, 50Hz) with a 4-relay 4 relay module (store, Sweden) module for
→ Circulation pump, from bottom of storage → boiler → top of the storage tank
→ Circulation pump, pumping the hot water out to the radiators

I tried the sketch with Arduino Uno, did some data logging (copy and paste, guess SD card data logging is my next project :grinning: ) then I put it in a nice little box and used an Adafruit Trinket (due to availability, space and price…hope it is not a hinder to ask questions here when using it?). So the sketch works so far, the pump for the boiler starts when a certain temperature is reached, pump to the radiators starts when storage tank has a certain temp, and if temp becomes low pumps switch off. But I have som questions concerning the code. I will post the questions in a new post here to have a better overview, but here comes the hole sketch so you get a picture of what Ive done so far:

#include <DallasTemperature.h>

/*-----( Declare Constants and Pin Numbers )-----*/
#define ONE_WIRE_BUS_PIN 2


/*-----( Declare objects )-----*/
// Setup a oneWire instance to communicate with any OneWire devices
OneWire oneWire(ONE_WIRE_BUS_PIN);


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


/*-----( Declare Variables )-----*/
// 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 Probe01 = { 0x28, 0xFF, 0x21, 0xB7, 0x61, 0x15, 0x03, 0x95 };
DeviceAddress Probe02 = { 0x28, 0xFF, 0x22, 0xB5, 0x61, 0x15, 0x03, 0xDC };


/*-----( Global variables for the outputs; Pumps and control LED  )-----*/
const int pumpBoiler = 4;
const int pumpRadiator = 3;
const int controlLED = 1;




void setup() {  /****** SETUP: RUNS ONCE ******/

  // set the resolution to 10 bit (Can be 9 to 12 bits .. lower is faster)
  sensors.setResolution(Probe01, 10);
  sensors.setResolution(Probe02, 10);


  //set output pins
  pinMode(controlLED, OUTPUT);
  digitalWrite(controlLED, LOW);

  for (int p = 3; p <= 4; p++) {
    pinMode(p, OUTPUT);
    digitalWrite(p, LOW);
  }

}//--(end setup )---

void loop()   /****** LOOP: RUNS CONSTANTLY ******/
{

  // Command all devices on bus to read temperature
  sensors.requestTemperatures();

  float tempC01 = sensors.getTempC(Probe01);
  float tempC02 = sensors.getTempC(Probe02);

  //Trigger values, values for activating the pumps (relay HIGH)
  const int g01 = 0.5;
  float triggerValue0101 = tempC02 + g01;
  float triggerValue0102 = 63.5;
  float triggerValue0201 = 57 ;

  /*
     Pump to the boiler shall be on if it is running (fire in the boiler is on -> water to the
     boilder is colder than the water from the boiler OR if the water from the boiler reaches
     a certain temperature
  */
  if ((tempC01 >= triggerValue0101) || (tempC01 >= triggerValue0102)) {
    digitalWrite(pumpBoiler, HIGH);
  }
  else {
    digitalWrite(pumpBoiler, LOW);
  }

  /*
     The pump for the hot water to the radiators shall be activated if the storage tank
     has reached a certain temperature (the bottom temp)
  */
  if (tempC02 >= triggerValue0201) {
    digitalWrite(pumpRadiator, HIGH);
  }
  else {
    digitalWrite(pumpRadiator, LOW);
  }

  /*
     If temperature sensor 01 has a failure it reports -127 deg and a control LED
     shall indicate the failure
  */
  if (tempC01 == -127) {
    digitalWrite(pumpRadiator, LOW);
    digitalWrite(pumpBoiler, HIGH);
    controlBlink01();
    delay(1000);
  }

  /*
     If temperature sensor 02 has a failure it reports -127 deg and a control LED
     shall indicate the failure
  */
  if (tempC02 == -127) {
    digitalWrite(pumpRadiator, LOW);
    digitalWrite(pumpBoiler, HIGH);
    controlBlink02();
    delay(1000);
    controlBlink02();
    delay(1000);
  }

  /*
     If both temperature sensors have a failure it reports -127 deg and a control LED
     shall indicate the failure
  */
  if ((tempC02 == -127) && (tempC01 == -127)) {
    digitalWrite(pumpRadiator, LOW);
    digitalWrite(pumpBoiler, HIGH);
    controlBlink03();
  }
}



//--(end main loop )---

/*-----( Declare User-written Functions )-----*/

void controlBlink01() {
  digitalWrite(controlLED, HIGH);
  delay(100);
  digitalWrite(controlLED, LOW);
  delay(100);
  digitalWrite(controlLED, HIGH);
  delay(100);
  digitalWrite(controlLED, LOW);
  delay(100);
  digitalWrite(controlLED, HIGH);
  delay(100);
  digitalWrite(controlLED, LOW);
  delay(100);
}
void controlBlink02() {
  digitalWrite(controlLED, HIGH);
  delay(100);
  digitalWrite(controlLED, LOW);
  delay(100);
  digitalWrite(controlLED, HIGH);
  delay(100);
  digitalWrite(controlLED, LOW);
  delay(100);
  digitalWrite(controlLED, HIGH);
  delay(100);
  digitalWrite(controlLED, LOW);
  delay(500);
  digitalWrite(controlLED, HIGH);
  delay(100);
  digitalWrite(controlLED, LOW);
  delay(100);
  digitalWrite(controlLED, HIGH);
  delay(100);
  digitalWrite(controlLED, LOW);
  delay(100);
  digitalWrite(controlLED, HIGH);
  delay(100);
  digitalWrite(controlLED, LOW);
}



void controlBlink03() {
  digitalWrite(controlLED, HIGH);
  delay(200);
  digitalWrite(controlLED, LOW);
  delay(200);
  digitalWrite(controlLED, HIGH);
  delay(200);
  digitalWrite(controlLED, LOW);
  delay(200);
  digitalWrite(controlLED, HIGH);
  delay(200);
  digitalWrite(controlLED, LOW);
  delay(200);
  digitalWrite(controlLED, HIGH);
  delay(200);
  digitalWrite(controlLED, LOW);
  delay(200);
}
//*********( THE END )***********

Picture: control box with relay module and Trinket

Picture: Heating system

For a small microcontroller, you must know when to use an 'int', 'long', 'float'. It must be very clear in the code which kind of calculation is used.

Even if you know what you are doing (I think you do), you should build in a safety feature. For example a temperature fuse.

Tips:

  • I prefer to use the term 'pin' in the variables for a pin: 'pinLed', 'pinBoilerPump', 'pinRadiatorPump'.
  • You set const variables to 3 and 4 for the pins, but then you use a loop with the (bare) number 3 and 4. A loop of just two is not needed, and I prefer to use the const variables.
  • This is not going to work: "const int g01 = 0.5 ;". Make it a float.
  • Testing a float with the integer -127 is dangerous. Is there a better way to check if the sensors can be read ?

I prefer an ATmega32U4 over a Trinket. That can be a Leonardo, Micro, Pro Micro, Adafruit Feather, and so on.

  const int g01 = 0.5;
  float triggerValue0101 = tempC02 + g01;
  float triggerValue0102 = 63.5;
  float triggerValue0201 = 57 ;

When i went throug my sketch I saw that I kind of mixed int and float, but I did not get any errors (and it seems to work too)...just wondering if you can add, divide etc. int and float in general?

And can you have float as an const?

I would change it to

 const float g01 = 0.5;
  const float triggerValue0101 = tempC02 + g01;
  const float triggerValue0102 = 63.5;
  const float triggerValue0201 = 57 ;

I guess that would be better?

Great, thanks for your great tips and suggestions Koepel!

I made some changes as you suggested:

#include <OneWire.h>


#include <DallasTemperature.h>

/*-----( Declare Constants and Pin Numbers )-----*/
#define ONE_WIRE_BUS_PIN 2


/*-----( Declare objects )-----*/
// Setup a oneWire instance to communicate with any OneWire devices
OneWire oneWire(ONE_WIRE_BUS_PIN);


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


/*-----( Declare Variables )-----*/

DeviceAddress Probe01 = { 0x28, 0xFF, 0x21, 0xB7, 0x61, 0x15, 0x03, 0x95 };
DeviceAddress Probe02 = { 0x28, 0xFF, 0x22, 0xB5, 0x61, 0x15, 0x03, 0xDC };


/*-----( Global variables for the outputs; Pumps and control LED  )-----*/
const int pinBoilerPump = 4;
const int pinRadiatorPump = 3;
const int pinControlLED = 1;




void setup() {  /****** SETUP: RUNS ONCE ******/

  // set the resolution to 10 bit (Can be 9 to 12 bits .. lower is faster)
  sensors.setResolution(Probe01, 10);
  sensors.setResolution(Probe02, 10);


  //set output pins
  pinMode(pinControlLED, OUTPUT);
  digitalWrite(pinControlLED, LOW);


    pinMode(pinBoilerPump, OUTPUT);
    digitalWrite(pinBoilerPump, LOW);

    pinMode(pinRadiatorPump, OUTPUT);
    digitalWrite(pinRadiatorPump, LOW);

}//--(end setup )---

void loop()   /****** LOOP: RUNS CONSTANTLY ******/
{

  // Command all devices on bus to read temperature
  sensors.requestTemperatures();

  float tempC01 = sensors.getTempC(Probe01);
  float tempC02 = sensors.getTempC(Probe02);

  //Trigger values, values for activating the pumps (relay HIGH)
  const float g01 = 0.5;
  const float triggerValue0101 = tempC02 + g01;
  const float triggerValue0102 = 63.5;
  const float triggerValue0201 = 57 ;

  /*
     Pump to the boiler shall be on if it is running (fire in the boiler is on -> water to the
     boilder is colder than the water from the boiler OR if the water from the boiler reaches
     a certain temperature
  */
  if ((tempC01 >= triggerValue0101) || (tempC01 >= triggerValue0102)) {
    digitalWrite(pinBoilerPump, HIGH);
  }
  else {
    digitalWrite(pinBoilerPump, LOW);
  }

  /*
     The pump for the hot water to the radiators shall be activated if the storage tank
     has reached a certain temperature (the bottom temp)
  */
  if (tempC02 >= triggerValue0201) {
    digitalWrite(pinRadiatorPump, HIGH);
  }
  else {
    digitalWrite(pinRadiatorPump, LOW);
  }

  /*
     If temperature sensor 01 has a failure it reports -127 deg and a control LED
     shall indicate the failure
  */
  if (tempC01 == -127) {
    digitalWrite(pinRadiatorPump, LOW);
    digitalWrite(pinBoilerPump, HIGH);
    controlBlink01();
    delay(1000);
  }

  /*
     If temperature sensor 02 has a failure it reports -127 deg and a control LED
     shall indicate the failure
  */
  if (tempC02 == -127) {
    digitalWrite(pinRadiatorPump, LOW);
    digitalWrite(pinBoilerPump, HIGH);
    controlBlink02();
    delay(1000);
    controlBlink02();
    delay(1000);
  }

  /*
     If both temperature sensors have a failure it reports -127 deg and a control LED
     shall indicate the failure
  */
  if ((tempC02 == -127) && (tempC01 == -127)) {
    digitalWrite(pinRadiatorPump, LOW);
    digitalWrite(pinBoilerPump, HIGH);
    controlBlink03();
  }
}
  • I agree, if I ever write more extensive sketches, it is good to know that a variable is for a pin
  • I made a for loop, just because I read about it and wanted to actualy use it, but I changed it, want to clean up as much as possible
  • Jepp, you were just too fast with your reply, changed that too
  • …I will look it up. That was inclueded in the example sketch I used (wikispaces-DS18B20), so I actually did not think about it so much.

…so for the microcontroller -127 is an int? If it shall be a float I have actually to write -127.0 ? So than I should NOT do:

float triggerValue0201 = 57 ;

instead:

float triggerValue0201 = 57.0 ;

Little question about global and local variables…in my case I would like to have all constanses and outputs in the very beginning, that makes it easy to change triggervalues etc, but the they all would be global varables, and I red that this can cause much trouble? So the best regarding code would be, to have no globals at all?

Then I have another thought: When the temp gets low and the boilerPump is going to be switched off, the temp fluctuate around the triggerValue0102, and that results in that the pup is switched off and on several times befor it remains off. So now I am thnking about using a for loop, so that it count how many loops the temp was below triggerValue, and if that was the case for several times pinBoilerPump gets LOW…something like:

  for (int i = 0; i <= 100; i++) {
    if (tempC01 < triggerValue0102) {
    }
    else {
      i = 0;
    }
  }
  if ((tempC01 < triggerValue0101) || (tempC01 < triggerValue0102) && i == 100) {
    digitalWrite(pinBoilerPump, LOW);
  }

That dont work.I guess I have to do it as a function which returns the value for i in some way? Or maybe there is a totally different way to handle this ? (I dont want to use the delay() statement though). Would be thankful for suggestions…

this is untested as I don’t have a dallas library. I think it will compile.

Its a little rewrite of your code to remove all the delays. Its not finished code just something to give you a different way to look at the program.

#include <DallasTemperature.h>

/*-----( Declare Constants and Pin Numbers )-----*/
#define ONE_WIRE_BUS_PIN 2


/*-----( Declare objects )-----*/
// Setup a oneWire instance to communicate with any OneWire devices
OneWire oneWire(ONE_WIRE_BUS_PIN);


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


/*-----( Declare Variables )-----*/
// 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 Probe01 = { 0x28, 0xFF, 0x21, 0xB7, 0x61, 0x15, 0x03, 0x95 };
DeviceAddress Probe02 = { 0x28, 0xFF, 0x22, 0xB5, 0x61, 0x15, 0x03, 0xDC };


/*-----( Global variables for the outputs; Pumps and control LED  )-----*/
const int pumpBoiler = 4;
const int pumpRadiator = 3;
const int controlLED = 1;
unsigned long currentMillis = 0;
unsigned long previousMillis1 = 0;
unsigned long previousMillis2 = 0;
unsigned long interval = 100;

//Trigger values, values for activating the pumps (relay HIGH)
const float g01 = 0.5;
float triggerValue0101 = tempC02 + g01;
float triggerValue0102 = 63.5;
float triggerValue0201 = 57 ;

void setup() {

  // set the resolution to 10 bit (Can be 9 to 12 bits .. lower is faster)
  sensors.setResolution(Probe01, 10);
  sensors.setResolution(Probe02, 10);


  //set output pins
  pinMode(controlLED, OUTPUT);
  digitalWrite(controlLED, LOW);

  for (int p = 3; p <= 4; p++) {
    pinMode(p, OUTPUT);
    digitalWrite(p, LOW);
  }
}

void loop() {
  // put your main code here, to run repeatedly:
  currentMillis = millis();//used by timers

  // Command all devices on bus to read temperature
  sensors.requestTemperatures();

  float tempC01 = sensors.getTempC(Probe01);
  float tempC02 = sensors.getTempC(Probe02);

  /*
       Pump to the boiler shall be on if it is running (fire in the boiler is on -> water to the
       boilder is colder than the water from the boiler OR if the water from the boiler reaches
       a certain temperature
    */

  if (currentMillis - previousMillis2 >= 5000) {//5 second update delay should stop relay chatter
    if ((tempC01 >= triggerValue0101) || (tempC01 >= triggerValue0102)) {
      digitalWrite(pumpBoiler, HIGH);
    }
    else {
      digitalWrite(pumpBoiler, LOW);
    }
    /*
          The pump for the hot water to the radiators shall be activated if the storage tank
          has reached a certain temperature (the bottom temp)
       */
    if (tempC02 >= triggerValue0201) {
      digitalWrite(pumpRadiator, HIGH);
    }
    else {
      digitalWrite(pumpRadiator, LOW);
    }
    previousMillis2 = currentMillis;//new time stamp
  }


  if ((tempC01 > 0) && (tempC02 > 0)) {//most common result first
    //this gives the program a easy way to skip the rest of the else ifs
    controlBlink(0);//led will not blink
  }
  else if ((tempC01 <= 0) && (tempC02 <= 0)) {// if this is true we know others are
    controlBlink(10);//led will blink 10 times then wait then repeat
    digitalWrite(pumpRadiator, LOW);
    digitalWrite(pumpBoiler, HIGH);
  }
  else if (tempC02 <= 0) {
    controlBlink(6);//led will blink 6 times then wait then repeat
    digitalWrite(pumpRadiator, LOW);
    digitalWrite(pumpBoiler, HIGH);
  }
  else if (tempC01 <= 0) {
    controlBlink(3);//led will blink 3 times then wait then repeat
    digitalWrite(pumpRadiator, LOW);
    digitalWrite(pumpBoiler, HIGH);
  }

}

void controlBlink(byte times) {
  byte flashcode = times * 2 - 1 ;
  static byte counter;
  if (counter < flashcode) {
    interval = 200;//1000 per second fast flash
  }
  else {
    interval = 1300;//1000 per second gap between flashing codes
  }
  if (times != 0) {
    if (currentMillis - previousMillis1 >= interval) {
      digitalWrite(controlLED, !digitalRead(controlLED));//toggle led
      counter++;
      previousMillis1 = currentMillis;
    }
  } else {
    digitalWrite(controlLED, LOW);
  }
  if (counter > flashcode) {
    counter = 0;
  }
}

Concerning your connections:
Are you using a separate 5VDC supply for the relay board?
Is it configured for isolation from the Arduino (jumper removed)?

Connections for power and opto-isolation:

  • VCC + GND = 5VDC and GND (separate supply)
  • IN1 to IN4 = your 5V outputs, COM = your GND from Arduino
  • Jumper removed

dlloyd is right, the relay board could influence the 5V, and that could cause trouble on the 1-Wire bus. Or perhaps a cheap and bad quality power supply.

gpop1 uses delays. But also adding hysteris might work. Or a running average.
Hysteresis is turning something on at 9 degrees and off at 11 degrees instead of switching at 10 degrees.
A running average is like a filter, it slows things down, which is often good for slow things (like heating 500 liters).

When an integer is multiplied with a float, the compiler selects float math. Therefor mixing int and float is often no problem. But I would like to show to myself what I'm doing :wink: so I prefer that I make the decisions when a int or float is used, and not let the compiler try to make sense of it.

// okay
float triggerValue0201 = 57 ;             // the 57 is an integer

// better
float triggerValue0201 = 57.0 ;

This is great, thanks for your help!
As I said before I am new to programming, so I have som work to do to understand all this, and I maybe will ask some unusual questions which are "unususal" (because obvious for experienced programmers). So I guess it may be either annoying or exhilarating :wink:

So where to start...
Perhaps the easiest baics, data types, summary from Arduino.cc - learning - references

  • char - holds 1byte / 8bit - signed and unsigned
  • byte - holds 1byte / 8bit - unsigned
  • int- holds 2byte / 16bit - signed and unsigned
  • long- holds 4byte / 32bits - signed and unsigned
  • word- holds 2byte / 16bits - unsigned
  • short- holds 2byte / 16bits - signed
  • float - holds 4byte / 32bits - 3.4028235E+38 to 3.4028235E+38

where

  • 1 byte = 8bit, unsignded = 0 to 255 (decimal) (0 to 2^8-1
  • 1 byte = 8bit, signded = -128 to 127 (decimal)
  • 2 byte = 16bit, unsignded = 0 to 65535 (decimal) (0 to 2^16-1
  • 2 byte = 16bit, signded = -32 768 to 32767 (decimal)
  • 4 byte = 32bit, unsignded = 0 to 4 294 967 295 (decimal) (0 to 2^32-1
  • 4 byte = 32bit, signded = -2 147 438 648 to 2 147 483 647 (decimal)

I understand that

  • unsigned char & byte
  • signed int & short
  • unsigned int & word

in priciple are the same data type?

As I have seen it is very comon to declare variables for pins as an int, but from the point of memory usage it would be better to:

//common way  
int pinLED = 13;
pinMode (pinLED, OUTPUT);

//to spare memory space??
byte pinLED = 13;
pinMode (pinLED, OUTPUT);

...or is there something else I haven not thought about which make that not work?

Thanks gpopl for taking time to help me with that piece of code. For me it is dificult to understand the controlBlink function, but I really try hard...I guess I will come back with some questions later ::slight_smile:

Koepel:
dlloyd is right, the relay board could influence the 5V, and that could cause trouble on the 1-Wire bus. Or perhaps a cheap and bad quality power supply.

gpop1 uses delays. But also adding hysteris might work. Or a running average.
Hysteresis is turning something on at 9 degrees and off at 11 degrees instead of switching at 10 degrees.
A running average is like a filter, it slows things down, which is often good for slow things (like heating 500 liters).

When an integer is multiplied with a float, the compiler selects float math. Therefor mixing int and float is often no problem. But I would like to show to myself what I'm doing :wink: so I prefer that I make the decisions when a int or float is used, and not let the compiler try to make sense of it.

// okay

float triggerValue0201 = 57 ;             // the 57 is an integer

// better
float triggerValue0201 = 57.0 ;

Koepel is correct Hysteresis is the better option especially if you are monitoring a averaged reading.

the basics are

1/ the sensor needs time to get the information ready for the arduino. Im not sure if the dallas library takes care of this but I know that if you use one wire the sensor will require about 750ms between reads. (may require a millis timer in your code)

2/ take 10 readings add them together then divide by 10 for the result. Again im not sure if the dallas library does any thing like this for you (if the sensor seems to take a few seconds between updates then it probably does. If the sensor update is fast then it probably doesn't)

3/ instead of going from a "if" to a digital write you will need to instead set a flag. Something like pumpRequest that will be used later to start or stop the pump

4/ add simple "if" arguments like if higher than 58 request pump. If lower than 56 remove the pump request.

I was going to do something like this in the example code I posted but to be honest I couldn't stand using
triggerValue0201 as a variable. I find it confusing to see a number that's not being used as a number. its the same as trying to read a program that's in a different language (Spanish, french, etc).
I know C++ works with any variable names but its distracting and harder to read when you have to stop and think about every variable. (not a complaint but something to think about when choosing variable names)

You know, there is no Arduino board I know of that can reliably energize 2 of these relays at the same time, unless, possibly if you are using USB 5V. The Arduino's regulator provides less current as Vin increases. You'll probably only have around 100-150mA available if Vin is at 12V. Just one relay and its led driver energized draws about 100mA.

Problems that can arise from a noisy or overloaded supply can range from inaccurate or unstable readings or control issues to locked up or self resetting or component failure.

Just looked in during my lunch break, some more information later :relaxed:
I am using USB 5V. Right now I can not try to use an external supply for the relay module (do not have things needed around). But it feels not that this is the problem, USB 5V from trinket is rated to 500mA, should be enough. And the relay "chatter" occurs just if the boiler is not fully loaded, and the hole storage tank has about the trigger / threshold temperature. And relay do not turn on/off in high frequency, it is more like 0.5 to 2 sec interval for 1-2min, but I will try external supply asap too.

I chose to store the threshold tempertures in var, because it is easier to adjusts them (instead of changing every temp in the hole sketch), but yes, I can imagine how annoying it is. I will do a new sketch with real numbers in the if statements, just for testing things and be able to hook up a testing circuit on my broadbord.

I have seen there are some good threats about hysteresis, will look at them to see if I get the idea, seems like a good idea to use that method in my case.

Thx and have a great day

DennisGu, you have not convinced me that the power is okay. The USB 5V is used for the relays, without any voltage regulator in between I guess. With a bad USB cable, things can go hairy.

All the int and unsigned you mentioned are for an Arduino Uno, and probably for an ATtiny as well.
The basic Arduino boards use a 8-bit microcontroller, and the compiler defaults to 16-bit integers. So the compiler has to do some extra work to make it work on a 8-bit microcontroller.
The newer ARM Cortext M0 and M3 processors are 32-bit and defaults to a 32-bit integer.
The is why also variables like "uint8_t" and "int16_t" are used. They will be the same for everything.

Don't try to outsmart the compiler :wink:
The compiler can optimize in many ways.
This is the preferred way:

// preferred way 
const int pinLED = 13;
pinMode (pinLED, OUTPUT);

Using the "const int" probably means that the compiler doesn't need a memory location at all. The compiler just uses the number "13" directly in the code.

The compiler can keep data in the registers. The Arduino optimizes for size, so the memory usage is already minimal.
For global variables and arrays it will help to use byte instead of int, but I think that should not be your first concern. If you need more memory, get a ATmega32U4 :o

Your USB port may not be delivering 500mA:

You have a lot connected, so an external 1A (min) 5V supply will not only resolve power issues, but allow for full isolation of the relay board from the Arduino (very, very important when controlling AC power). It will also allow use of all 4 relays simultaneously.

If contact-arc interference creates problems, using a suitable MOV across the contacts (COM-NO) will usually resolve this. Since your pumps are 230VAC, make sure the MOVs are rated for at least 275VAC working voltage (clamping voltage will be higher).

DennisGu:
Just looked in during my lunch break, some more information later :relaxed:
I am using USB 5V. Right now I can not try to use an external supply for the relay module (do not have things needed around). But it feels not that this is the problem, USB 5V from trinket is rated to 500mA, should be enough. And the relay "chatter" occurs just if the boiler is not fully loaded, and the hole storage tank has about the trigger / threshold temperature. And relay do not turn on/off in high frequency, it is more like 0.5 to 2 sec interval for 1-2min, but I will try external supply asap too.

I chose to store the threshold tempertures in var, because it is easier to adjusts them (instead of changing every temp in the hole sketch), but yes, I can imagine how annoying it is. I will do a new sketch with real numbers in the if statements, just for testing things and be able to hook up a testing circuit on my broadbord.

I have seen there are some good threats about hysteresis, will look at them to see if I get the idea, seems like a good idea to use that method in my case.

Thx and have a great day

storing the threshold in a variable is not the problem. Its the name of the variable

triggerValue0201 makes very little sense unless 0201 has a meaning

why not call it something that makes more sense.

boilerPumpStartTemp ? (compiler removes all of this before it uploads to the arduino so use long names that make sense)

Thanks gpopl for taking time to help me with that piece of code. For me it is dificult to understand the controlBlink function, but I really try hard...I guess I will come back with some questions later ::slight_smile:

im more than willing to explain the code line by line if you don't understand something. Its basically a function call with a additional byte attached to tell the function how many times to flash a led

so
controlBlink(6);

should flash the led rapidly 6 times then wait about 1 second and repeat the 6 flashes until the fault is cleared (e.g the sensor sends a reading that's higher than 0 degrees).

That was an excellent example for me to try to understand functions. I wrote some comments (and answers), and hope that my thoughts are right…

  void controlBlink(byte times) {
  byte flashcode = times * 2 - 1 ;//DennisGu times is how often led shall flash, must be twice for LOW periods
  static byte counter; //DennisGu: if no number mentioned, equal with zero then?
  //What is static? --> the value in the var will not be reseted after ending the function
  if (counter < flashcode) {// go through this if as long as it not has gone through it as many times as set in void loop (controlBlink(6) eg)
    interval = 200;//1000 per second fast flash DennisGu: ...guess 5 times per sec?
  }
  else {
    interval = 1300;//1000 per second gap between flashing codes, DennisGu: just curious how you now that led will be low, even number?
  }
  if (times != 0) {
    if (currentMillis - previousMillis1 >= interval) {//DennisGu: as soon as diference is bigger than interval --> (interval will be approx equal to millisec) until led toggles again
      digitalWrite(controlLED, !digitalRead(controlLED));//toggle led , DennisGu: can you digitalRead an output?
      counter++;//DennisGu Counts how often the led has been toggled
      previousMillis1 = currentMillis;
    }
  } else {//DennisGu --> if times is zero
    digitalWrite(controlLED, LOW);
  }
  if (counter > flashcode) {
    counter = 0;
  }
  }

I tried to use the same function to blink 3 different LED

Ok below I tried to use the blink function to blink 3 different LED depending on the temp (temp36 sensor from the starter kit).
But I am not sure how functions really work: is it the same function which is called during one loop. I mean if there would be 3 if statements in void loop, and all 3 calls the same function, and in the function is a counter++, would counter increase by 3 during one loop?

When using this function for 3 different LED then 1 LED is always blinking correctly, but quite often other LED are HIGH permanently. I guess it is because the function is not called any more while LED was high, and then it stays like this until it activily is set to something else?

/*
   Arduino Uno, from the book in the starta kit "Project book"
   Temp36 sensor to pin A0, 3 LED to pin 2-4
*/
const int sensorPin = A0;
const float baselineTemp = 20.0;
unsigned long currentMillis = 0 ;
unsigned long previousMillis1 = 0;
unsigned long interval = 0;

void setup() {
  Serial.begin(9600);
  for (int pinNumber = 2; pinNumber < 5; pinNumber++) {
    pinMode(pinNumber, OUTPUT );
    digitalWrite(pinNumber, LOW);
  }
}

void loop() {
  currentMillis = millis();
  int sensorVal = analogRead(sensorPin);
  Serial.print ("Sensor value ");
  Serial.print(sensorVal);
  float voltage = (sensorVal / 1024.0) * 5.0;
  Serial.print(", Volts ");
  Serial.print(voltage);
  Serial.print(", degrees C ");
  float temperature = (voltage - .5) * 100;
  Serial.println(temperature);


  if (temperature < baselineTemp) {
    ledBlink(4 , 2);
  }

  else if ((temperature >= baselineTemp + 2) && (temperature < baselineTemp + 4 )) {
    ledBlink(3 , 3);
  }
  else if ((temperature >= baselineTemp + 4) && (temperature < baselineTemp + 10 )) {
    ledBlink(2, 4);
  }

}


void ledBlink (byte times, byte pin) {
  byte flashCode = times * 2 - 1;
  static byte counter;
  if (counter < flashCode) {
    interval = 300;
  } else {
    digitalWrite(pin, LOW);//This is needed so the LED is LOW for this interval
    interval = 2000;
  }
  if (times != 0) {
    if (currentMillis - previousMillis1 >= interval) {
      digitalWrite (pin, !digitalRead(pin));
      counter++;
      previousMillis1 = currentMillis;
    }
    //When following else statement is activated, then the LED will blik twice as often as the var "times"(blinktimes seems to be halv too)
    /* else {
        digitalWrite(pin, LOW);
       }*/
  }
  if (counter > flashCode) {
    counter = 0;
  }
}

you seem to have a good understanding of what the original function code I wrote does and I believe you are now discovering that the function does not have enough parts/code to be used multiply times on different pins.

If you look at the code I posted originally you will see that I handled calling the function based on the simple concept that the code is read top to bottom left to right.

That means you can say

x=1;
x=5;
x=10;

the arduino will set x to 1 and 5 but really x will only ever = 10 as that's the last line (compiler is smart and will just delete the others as they are worthless code)

now if you use "if" then the last executed line wins

(not code example)
if then x=1
if then x=5 (only this one is true)
if then x=10

then on this loop x=5

(not code example)
if then x=1 (this is true)
if then x=5 (this is true)
if then x=10

then on this loop x=5 as the last line wins

ok so the code said something like

blink will equal 0 when happy (you always start with the most used result especially in a "if/else" as it allows the processor to skip the other code with out checking. 0 is needed to stop the flashing)

any fault is a number of blinks (humans don't count zero or want to work out that 3 flashes is 6 toggles so simple maths takes care of that In the function)

The first fault is if both fails the last fault is if one fails which is simply a concept that if both failed then one would have failed so theres no need to check thus only one blink number is transferred to the function

If you want to send the pin number then each pin would require some code like counter etc.

now you could send the pin number and use a "if" argument to sort out which counter etc but its easier just to copy the function and rename it (including renaming any globals). That way each pin (led) has its own function.