Go Down

Topic: First code (Read 4928 times) previous topic - next topic

Morke

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:

Code: [Select]

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);
}

What, a zoologist????

larryd

#1
May 22, 2016, 03:59 am Last Edit: May 22, 2016, 04:11 am by LarryD
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
No technical PMs.
If you are asked a question, please respond with an answer.
If you are asked for more information, please supply it.
If you need clarification, ask for help.

sterretje

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.

Code: [Select]

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


Make that either
Code: [Select]

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

Or
Code: [Select]

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
Code: [Select]

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.

Code: [Select]

  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
Code: [Select]

#define LOWER 24
#define UPPER 25

And change the above to
Code: [Select]

  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.
If you understand an example, use it.
If you don't understand an example, don't use it.

Electronics engineer by trade, software engineer by profession. Trying to get back into electronics after 15 years absence.

Morke

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...
What, a zoologist????

larryd

#4
May 22, 2016, 05:40 am Last Edit: May 22, 2016, 05:43 am by LarryD
@sterretje has mentioned LOWER and UPPER limits and attached an example.

You could also use something like:
<limit
then
>limit+1
or
>limit+hysteresis
No technical PMs.
If you are asked a question, please respond with an answer.
If you are asked for more information, please supply it.
If you need clarification, ask for help.

ChrisTenone

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.
What, I need to say something else too?

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.

Code: [Select]

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.
The internet is a great thing. Use it.
:s/internet/mind/g
Real Programmers use ++C

BulldogLowell

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.

Code: [Select]


  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().

Rupert909

...  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!
The internet is a great thing. Use it.
:s/internet/mind/g
Real Programmers use ++C

Morke

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.
What, a zoologist????

Morke

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:
Code: [Select]

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
What, a zoologist????

UKHeliBob

Quote
once I uploaded the code,
Please post teh code here
Please do not send me PMs asking for help.  Post in the forum then everyone will benefit from seeing the questions and answers.

larryd

Also show your schematic.

.
No technical PMs.
If you are asked a question, please respond with an answer.
If you are asked for more information, please supply it.
If you need clarification, ask for help.

Morke

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:
Code: [Select]

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);
}

What, a zoologist????

UKHeliBob

Quote
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 ?
Please do not send me PMs asking for help.  Post in the forum then everyone will benefit from seeing the questions and answers.

Go Up