First code

Hi everyone!

Well, I made the jump and wrote my first code. I was wondering if you could check it and tell me your thoughts

The idea is to control 4 heat tapes under 4 different reptiles terrariums. I have 4 LM35 temp sensors connected to the Analog pins and a 4 Relay module connected to the Digital pins. I found different codes and made a “frankenstein” monster.
If this works, I’m gonna upgrade it with an LCD to read temps and, after that, a WiFi Module to be able to check the terrariums from my PC, but that’s gonna take time, having in mind I have no idea of C++ language…

Anyway, here’s the code. Please share your thoughts with me so I can improve it:

float tempC1;
int reading1;
int tempPin1 = A1;
#define RELAY1  6   

float tempC2;
int reading2;
int tempPin2 = A2;
#define RELAY2  7

float tempC3;
int reading3;
int tempPin3 = A3;                        
#define RELAY3  8

float tempC4;
int reading4;
int tempPin4 = A4;                        
#define RELAY4  9


void setup()
{
analogReference(INTERNAL);
Serial.begin(9600);
pinMode(RELAY1, OUTPUT);       
pinMode(RELAY2, OUTPUT);
pinMode(RELAY3, OUTPUT);
pinMode(RELAY4, OUTPUT);
}

void loop()
{
reading1 = analogRead(tempPin1);
tempC1 = reading1 / 9.31;
if (tempC1 < 24){
  digitalWrite(RELAY1,LOW);
}

reading2 = analogRead(tempPin2);
tempC2 = reading2 / 9.31;
if (tempC2 < 24){
  digitalWrite(RELAY1,LOW);
}

reading3 = analogRead(tempPin3);
tempC3 = reading3 / 9.31;
if (tempC3 < 24){
  digitalWrite(RELAY1,LOW);
}

reading4 = analogRead(tempPin4);
tempC4 = reading4 / 9.31;
if (tempC4 < 24){
  digitalWrite(RELAY1,LOW);
}



Serial.println(tempC1);
delay(1000);
Serial.println(tempC2);
delay(1000);
Serial.println(tempC3);
delay(1000);
Serial.println(tempC4);
delay(1000);
}

Get rid of your delay()s. Do you really need floats? If a byte type works don't use an int Maybe add hysteresis to your control sections. When do the heaters turn off? You only use RELAY1 :o

Your a little inconsistent in the declaration of the pins. You use an int for the temp pins but a #define for the relay pins.

float tempC1;
int reading1;
int tempPin1 = A1;
#define RELAY1  6

Make that either

float tempC1;
int reading1;
#define tempPin1  A1
#define RELAY1  6

Or

float tempC1;
int reading1;
int tempPin1 = A1;
int RELAY1 = 6;

As it’s very unlikely that you will ever have over 256 pins, you can change the type in the latter to byte (instead of int).
If you want the compiler to warn you if you try by accident to change the pin number, add the const keyword to it

float tempC1;
int reading1;
const byte tempPin1 = A1;
const byte RELAY1 = 6;

You also might want to make sure in setup that the relays are off (or on); add a digitalWrite for each relay in setup().

The biggest flaw in your code is that you never switch the relays off. In the below, I’ve added this; the heater switches off again at 25 degrees.

  reading1 = analogRead(tempPin1);
  tempC1 = reading1 / 9.31;
  if (tempC1 < 24) {
    digitalWrite(RELAY1, LOW);
  }
  else if(tempC1 > 25)
  {
    digitalWrite(RELAY1, HIGH);
  }

Note that hard-coded values are a mission to maintain. You have to dig through your code to find thhe temperature limit.

You can use something like

#define LOWER 24
#define UPPER 25

And change the above to

  reading1 = analogRead(tempPin1);
  tempC1 = reading1 / 9.31;
  if (tempC1 < LOWER) {
    digitalWrite(RELAY1, LOW);
  }
  else if(tempC1 > UPPER)
  {
    digitalWrite(RELAY1, HIGH);
  }

You can also store your pins, readings etc in arrays. And even neater might be a struct. But that’s a little more advanced.

That way you can loop through the reading of the sensors and the setting of the relays.

Thank you a lot for your help, it's been very useful!

One question, how should I add hysteresis? I was thinking of making a mean with the last, say, 10 values, but that would make me create 10 more variables...

@sterretje has mentioned LOWER and UPPER limits and attached an example.

You could also use something like:
<limit
then

limit+1
or
limit+hysteresis

Hysteresis is where the value of the change is different going up than it is going down - there is a small bit of temperature (or whatever is being measured/controlled) overlap. It keeps an automated device from getting stuck in a 'switching off/switching on' loop it cant get out of.

This is possibly beyond your current understanding of C++, but the following code compiles and should be reasonably easy to follow. Creating a class and four instances of it, means you don’t have to duplicate the code. This implementation also introduces an overlap of temperatures, so that the heaters don’t get switched on and off too frequently.

class Heater {
  private:
    int switchOnBelowTemp;
    int switchOffAboveTemp;
    int tempPin;
    int relayPin;
  public:
    Heater (int switchOnBelowTemp, int switchOffAboveTemp, int tempPin, int relayPin) {
      this->switchOnBelowTemp=switchOnBelowTemp;
      this->switchOffAboveTemp=switchOffAboveTemp;
      this->tempPin=tempPin;
      this->relayPin=relayPin;
      
      pinMode(tempPin, INPUT);
      pinMode(relayPin, OUTPUT);
      digitalWrite(relayPin, LOW);
    }
    void check() { // called from loop()
      int reading=analogRead(tempPin);
      float temp = reading / 9.31;
      if (temp < switchOnBelowTemp){
        digitalWrite(relayPin,HIGH);
      } else if (temp > switchOffAboveTemp) {
        digitalWrite(relayPin,LOW);
      }
    }
};

Heater h1(22,24,A1,6);
Heater h2(22,24,A2,7);
Heater h3(22,24,A3,8);
Heater h4(22,24,A4,9);

void setup() {
}

void loop() {
  h1.check();
  h2.check();
  h3.check();
  h4.check();
}

Sketch uses 1 870 bytes (6%) of program storage space. Maximum is 30 720 bytes.
Global variables use 43 bytes (2%) of dynamic memory, leaving 2 005 bytes for local variables. Maximum is 2 048 bytes.

Rupert909: This is possibly beyond your current understanding of C++, but the following code compiles and should be reasonably easy to follow. Creating a class and four instances of it, means you don't have to duplicate the code. This implementation also introduces an overlap of temperatures, so that the heaters don't get switched on and off too frequently.

  public:
    Heater (int switchOnBelowTemp, int switchOffAboveTemp, int tempPin, int relayPin) {
      this->switchOnBelowTemp=switchOnBelowTemp;
      this->switchOffAboveTemp=switchOffAboveTemp;
      this->tempPin=tempPin;
      this->relayPin=relayPin;
      
      pinMode(tempPin, INPUT);
      pinMode(relayPin, OUTPUT);
      digitalWrite(relayPin, LOW);
    }

Agreed you are climbing up a steep curve, but you shouldn't forget that setting pinMode before setup isn't guaranteed to make that work.

you should create a method (i.e. begin()) to set the pinMode during setup().

BulldogLowell: ... you shouldn't forget that setting pinMode before setup isn't guaranteed to make that work.

you should create a method (i.e. begin()) to set the pinMode during setup().

Good point. Thank you!

Thank you all for your help. I updated the code and now i'm investigating to add LCD and some wifi functions.

Classes are a bit over my head, but i'll try to transform the code once it's working.

Ok so I have a problem and a question

First of all, once I uploaded the code, it started working BUT, the moment the If condition gets:

if (tempC1 < LOWER)
  {
  digitalWrite(RELAY1,LOW);
  }

The port stops working and I can’t get any more readings until I change the COM number and replug the USB.
The program keeps running, because I can see the relay switching off and on, but the port bugs and gets me this Error message:

Error while setting serial port parameters: 9,600 N 8 1

What’s going on?

The other question is:
The temps change quite a bit and I want to have an Array to calculate AVG temperature for the last, let’s say, 20 readings and make THAT variable the one that the IF condition reads to get on/off the relay.
How can I make an operation to read the LAST 20 readings and keep erasing old ones and recording new ones?

Thank you all

once I uploaded the code,

Please post teh code here

Also show your schematic.

.

I’m not sure how to draw the schematics… i’ll try my best and then upload them.
The Arduino powers the 4 LM35 temp sensors, and a YwRobot Power supply powers the 4 relay module externaly to avoid issues.
I placed a 1k resistor and 100uF between each output and GND pins on the LM35 sensors to clear the signal.

The bug happens like this:
I connect the USB to the Arduino and I turn on the External Power supply to power the 4 Relay Module. I open the Serial Port Monitor and start checking the temp readings. The program starts working fine and all the temps keep coming through the Serial Monitor. BUT once one of the relays turns off and then turns ON AGAIN, the Monitor stops working and no more temps get through it. I know the program keeps working because I can see and hear the relay switching off and on while I check the temperatures with an external temp sensor. The problem is in the Serial Monitor.
To get it working again, I have to change the COM port Number the Arduino was on, unplug and then plug again the Arduino and voila, it works again UNTIL the same situation happens again and it gets bug.

Here’s the code:

float tempC1;
int reading1;
const byte tempPin1 = A1;
const byte RELAY1 = 6;

float tempC2;
int reading2;
const byte tempPin2 = A2;
const byte RELAY2 = 7;

float tempC3;
int reading3;
const byte tempPin3 = A3;                        
const byte RELAY3 = 8;

float tempC4;
int reading4;
const byte tempPin4 = A4;                        
const byte RELAY4 = 9;

#define LOWER 26
#define UPPER 32

void setup()
{
analogReference(INTERNAL);
Serial.begin(9600);
pinMode(RELAY1, OUTPUT);       
pinMode(RELAY2, OUTPUT);
pinMode(RELAY3, OUTPUT);
pinMode(RELAY4, OUTPUT);
digitalWrite(RELAY1, HIGH);
digitalWrite(RELAY2, HIGH);
digitalWrite(RELAY3, HIGH);
digitalWrite(RELAY4, HIGH);
}

void loop()
{
reading1 = analogRead(tempPin1);
tempC1 = reading1 / 9.31;
if (tempC1 < LOWER)
  {
  digitalWrite(RELAY1,LOW);
  }
else if (tempC1 > UPPER)
  {
    digitalWrite(RELAY1, HIGH);
  }

reading2 = analogRead(tempPin2);
tempC2 = reading2 / 9.31;
if (tempC2 < LOWER)
  {
  digitalWrite(RELAY2,LOW);
  }
else if (tempC2 > UPPER)
  {
    digitalWrite(RELAY2, HIGH);
  }
  
reading3 = analogRead(tempPin3);
tempC3 = reading3 / 9.31;
if (tempC3 < LOWER)
  {
  digitalWrite(RELAY3,LOW);
  }
 else if (tempC3 > UPPER)
  {
    digitalWrite(RELAY4, HIGH);
  }

reading4 = analogRead(tempPin4);
tempC4 = reading4 / 9.31;
if (tempC4 < LOWER)
  {
  digitalWrite(RELAY4,LOW);
  }
else if (tempC4 > UPPER)
  {
    digitalWrite(RELAY4, HIGH);
  }


Serial.println(tempC1);
delay(1000);
Serial.println(tempC2);
delay(1000);
Serial.println(tempC3);
delay(1000);
Serial.println(tempC4);
delay(1000);
}

The Arduino powers the 4 LM35 temp sensors, and a YwRobot Power supply powers the 4 relay module externaly to avoid issues.

Have the two supplies got a common GND ?

UKHeliBob: Have the two supplies got a common GND ?

No, that would defeat the purpose of being isolated from each other and the Arduino could be damaged if something happened to the Relays.

Morke: No, that would defeat the purpose of being isolated from each other and the Arduino could be damaged if something happened to the Relays.

Lets see. The Arduino has a power supply, usually USB, at least while developing, then later perhaps a cell phone charger. Let's call this ArduinoPower.

Then there are the relays. Relays have two sides. There is the control connection and GND, and there is the controlled pins, 2 or 3 of those.

Now, are we talking solid-state relays that require very little current, say less than 30-40 mA, and are happy to work on 5V, or are we talking mechanical ones, which may even require 12V to operate, and definitely require more current than an Arduino pin can supply?

I seem to recall you saying something about your Arduino having to be reset, following an event involving the relays? Might this possibly be due to excessive current draw?

So ... if the Arduino can not control the relays directly, you will need an additional power supply for that, controlled via some transistor (MOSFET or other). Let's call that power supply RelayControl. Now, RelayControl and ArduinoPower must have common GND, for this to work.

If the Arduino directly controls the relay, then still the control-side of the relay must be connected to ArduinoPower, for common reference. Voltage is voltage only relative to something.

Then, finally, we come to the business end of the relays, the load to be switched on and off, and consequently requiring a power supply of its own. This power supply may be the same that I called RelayControl. But it may also be separate. Lets call it ActionPower, as it powers the "action".

(cheesy)

If ActionPower is separate from RelayControl, then at least for mechanical relays, this part may well exist electrically isolated from the control side, and needs not share GND with the beforementioned two. This is because (mechanical) relays are simple switches.

If ActionPower and RelayControl are one and the same, which means it is used both to control the relays, with transistor between relay and Arduino, and run the "action", then it must share GND with ArduinoPower.

As for solid state relays, I've never used those, so they may have other requirements.

So there we are. Any questions?? :-)

[Edited]

It's a mechanical Relay, but anyway that's not the issue. The problem seems to be related to the Serial print..... that's the only thing that bugs. The arduino keeps working.

Morke: It's a mechanical Relay, but anyway that's not the issue.

If you know what the issue is, why ask us?

Are there diodes across the relays to prevent back EMF when they turn off ?