Arduino Forum

Using Arduino => Programming Questions => Topic started by: myggle on Jun 10, 2015, 05:01 am

Title: Seeking better testing language
Post by: myggle on Jun 10, 2015, 05:01 am
My sketch queries a Real Time Clock, and depending upon the time, a digital pin switches to HIGH or LOW.  I've tried both the Time and TimeAlarms libraries, but have ran into issues, plus have since found the RTClib to work well for me.

I created a few different programmed events based on time, the first of which is triggered to ON at 6am everyday and triggers OFF at midnight every night and this works perfectly, producing a steady output voltage at the respective digital pin.

However, when I get to my second alarm, I fear my knowledge of the code is failing me and keeping me from asking the right question(s) of the RTC.  My thought is that if the hour is 9 and the minute is 0 and equal to or less than 10, that this would create a test that can only be true from 9:00 to 9:09, but the output is buggy.  Every time the sketch loops, the respective pin (D31=Relay_B) pulses HIGH for maybe 100 milliseconds, then goes LOW for the remainder of the loop.  This pulsing process is repeated while the condition is true then goes LOW until tested true again.

Code: [Select]

define# TURN_ON 0  //  TURN_ON/OFF was defined to accommodate relay polarity
define TURN_OFF 1

if (now.hour() == 9 && now.minute() >= 00 && now.minute() < 10) // FeedPump1, ON 9am
  { 
    digitalWrite(Relay_B, TURN_ON);
    Serial.print("\t");
    Serial.println(F("First 10 Minute Feeding"));  //  Text printed to serial monitor
    Serial.print("\t");
  }
  else // Turn off time for FeedPump1, OFF 9:10am
  { 
    digitalWrite(Relay_B, TURN_OFF);
  }


Relay_B is scheduled to be true twice daily, for 10 minutes each time.  I don't know if it matters, but Relay_A will be true during both of Relay_B being true to it's tests.  Can someone please enlighten me how to ask the most efficient questions as I keep getting tied up mentally in semantics of what is true at what given moment in time.

TYIA
Title: Re: Seeking better testing language
Post by: MorganS on Jun 10, 2015, 05:59 am
Please post the whole sketch, or a cut-down sketch that compiles and runs and shows the problem.
Title: Re: Seeking better testing language
Post by: nickgammon on Jun 10, 2015, 06:49 am
Code: [Select]

define# TURN_ON 0  //  TURN_ON/OFF was defined to accommodate relay polarity
define TURN_OFF 1


?
Title: Re: Seeking better testing language
Post by: myggle on Jun 10, 2015, 07:42 am
The defines are because of the relay states are active high and it would confuse me when considering the desired end result.  I will attach my whole sketch.
Title: Re: Seeking better testing language
Post by: UKHeliBob on Jun 10, 2015, 08:25 am
Code: [Select]

define# TURN_ON 0

Code: [Select]

define TURN_OFF 1

Spot the difference
Title: Re: Seeking better testing language
Post by: nickgammon on Jun 10, 2015, 09:19 am
Neither of which is correct, of course.

Code: [Select]
  if (now.hour() == 9 && now.minute() >= 0 && now.minute() < 10) // FeedPump1, ON 9am
  { 
...
  }
  else // Turn off time for FeedPump1, OFF 9:10am
  { 
    digitalWrite(Relay_B, TURN_OFF);
  }
  //******************* 2nd FEED TIME - RELAY B *********************************************//
  if (now.hour() == 18 && now.minute() >= 0 && now.minute() < 10) // FeedPump, ON 6PM
  { 
...
  }
 else 
  {
  digitalWrite(Relay_B, TURN_OFF);
  }



The net effect, surely, is that Relay_B will always be turned off. The hour can't be be both 9 and 18.
Title: Re: Seeking better testing language
Post by: nickgammon on Jun 10, 2015, 09:22 am
Let me put it like this ... if I said:

Quote
If it is not 9 o'clock, slap yourself.
If it is not 6 pm, slap yourself.
Are you going to get a slap? If you aren't sure, try it out. You might even get two slaps. ;)
Title: Re: Seeking better testing language
Post by: Robin2 on Jun 10, 2015, 09:43 am
Spot the difference
Aren't they BOTH wrong?

Shouldn't it be #define  ?


Quote
You might even get two slaps
or just continuous slaps ?

If it was my project I would test for the HOUR and then in a subsidiary test check the MINUTES just so I could understand what I was doing
Something like
Code: [Select]
if (HOUR == 9) {
  if (MINUTE >0 && MINUTE < 10) {
    // do whatever
  }
}



...R
Title: Re: Seeking better testing language
Post by: nickgammon on Jun 10, 2015, 09:48 am
They way it is written, yes.

Quote
Aren't they BOTH wrong?
Indeed.
Title: Re: Seeking better testing language
Post by: jurs on Jun 10, 2015, 11:47 am
However, when I get to my second alarm, I fear my knowledge of the code is failing me and keeping me from asking the right question(s) of the RTC.
Perhaps use the IPO principle and do a logical seperation of:
- Input
- Processing
- Output

Do not try to mix input with just a small part of the processing logic and then output directly before all processing is done.


For your relay switching I'd suggest a programming logic like that looping around in the loop() function (untested code):
Code: [Select]

  // Input ==> read the current time from RTC

  // Processing
  boolean relayBstate=false; // initial guess is "relay B is OFF"
  if (now.hour() == 9 && now.minute() >= 00 && now.minute() < 10) relayBstate=true; // 1st 'ON' time
  if (now.hour() == 12 && now.minute() >= 00 && now.minute() < 10) relayBstate=true; // 2nd 'ON' time
  if (now.hour() == 15 && now.minute() >= 00 && now.minute() < 10) relayBstate=true; // 3nd 'ON' time

  // Output
  if (relayBstate==true)
  {
    if (digitalRead(Relay_B)!=TURN_ON) Serial.println("Turn ON relay B");
    digitalWrite(Relay_B, TURN_ON);
  }
  else
  {
     if (digitalRead(Relay_B)!=TURN_OFF) Serial.println("Turn OFF relay B");
     digitalWrite(Relay_B, TURN_OFF);
  }
Title: Re: Seeking better testing language
Post by: myggle on Jun 10, 2015, 12:52 pm
Thanks for the feedback.  I pasted the snippet about the test and mistyped the includes by mistake with hopes I would not have to explain why they were defined in the first place.  Yet here I am again explaining them for other reasons.  I was hoping someone would point out the flaws in my test(s) so I can learn from my mistake(s), but I guess not. 

Thank you jurs for at least giving me a different way of doing things, I will start testing immediately.

Edit - @jurs, can you explain the purpose of using the NOT operator?  I see that it is used in many places throughout the example sketches I've been through and never understood why it is important to ask in code if something is NOT, when the code never told it to be?  Or why is the code testing to see if the light was turned on before the mention of the command to turn it on?

TYIA
Title: Re: Seeking better testing language
Post by: aarg on Jun 10, 2015, 01:05 pm
Thanks for the feedback.  I pasted the snippet about the test and mistyped the includes by mistake with hopes I would not have to explain why they were defined in the first place.  Yet here I am again explaining them for other reasons.  I was hoping someone would point out the flaws in my test(s) so I can learn from my mistake(s), but I guess not. 

Thank you jurs for at least giving me a different way of doing things, I will start testing immediately.
Well, that can happen when you ignore the very first response.

Title: Re: Seeking better testing language
Post by: jurs on Jun 10, 2015, 01:34 pm
Edit - @jurs, can you explain the purpose of using the NOT operator?
The NOT operator will do a little "state change detection" before the OUTPUT is set to its value.

As I have seen in your source code, you want to have a small message on Serial each time the state changes.

So with this code:
Code: [Select]

  if (digitalRead(Relay_B)!=TURN_ON) Serial.println("Turn ON relay B");
  digitalWrite(Relay_B, TURN_ON);

I first check if the relay is already in the ON state, and only if it is NOT in ON state, I show the message.
Then it is set to ON state.

Same check happens when turning to OFF state.
Title: Re: Seeking better testing language
Post by: myggle on Jun 10, 2015, 02:07 pm
I just tried a few combinations with, and without the not operator statement, and the result was the same.  I even relocated the whole block to occur before the Relay_A test, and the resulted in Relay_B not even pulsing high momentarily.  So I'm at a loss as to why this is the result.

The funny thing is that this was happening when I was using the Mega with an Ethernet shield on it, but now I am using an EtherMega which rules out hardware issues.  To the best of your knowledge, can you spot why Relay_B is only pulsing HIGH and not steadily HIGH?  Some weeks ago I tested to see if the relay channel was faulty by running the blink sketch for pins 30-37, and all pins went to HIGH for the duration I specified, so I know it has to be something in my code.

@aarg, I did not ignore the first response, I attached my sketch as an attachment because it is too many characters to fit into code brackets.

I will attach an updated version of my sketch as I added the boolean tests that jurs suggested, and modified the println language to be generic to the channel and not the event.  I also cut out the second block for Relay_B as the boolean test can incorporate other tests.
Title: Re: Seeking better testing language
Post by: PaulS on Jun 10, 2015, 02:22 pm
Code: [Select]
  if (now.hour() >= 6 && now.minute() >= 0) {  // Turn on time for Veg Lights, ON at 6am
    digitalWrite(Relay_A, TURN_ON);

    Serial.print("\t");
    Serial.println(F("Vegetative Lights On"));  //  Text printed to serial monitor
    Serial.print("\t");
  }
  else if (now.hour() >= 0 && now.minute() >= 0) // "else if" was needed to create opposition to lights on
  {  // Turn off time for Veg Lights, OFF at 12am
    digitalWrite(Relay_A, TURN_OFF);
    Serial.print("\t");
    Serial.println(F("Vegitative Lights OFf"));  //  Text printed to serial monitor
    Serial.print("\t");
  }

Can you envision a scenario where the hour value is 6 or more, and the minute value is not greater than or equal to 0?

Can you envision a scenario where the else if test would not evaluate to true?
Title: Re: Seeking better testing language
Post by: myggle on Jun 10, 2015, 02:41 pm
Code: [Select]
  if (now.hour() >= 6 && now.minute() >= 0) {  // Turn on time for Veg Lights, ON at 6am
    digitalWrite(Relay_A, TURN_ON);

    Serial.print("\t");
    Serial.println(F("Vegetative Lights On"));  //  Text printed to serial monitor
    Serial.print("\t");
  }
  else if (now.hour() >= 0 && now.minute() >= 0) // "else if" was needed to create opposition to lights on
  {  // Turn off time for Veg Lights, OFF at 12am
    digitalWrite(Relay_A, TURN_OFF);
    Serial.print("\t");
    Serial.println(F("Vegitative Lights OFf"));  //  Text printed to serial monitor
    Serial.print("\t");
  }

Can you envision a scenario where the hour value is 6 or more, and the minute value is not greater than or equal to 0?

Hours count from 0-23, minutes 0-59.  So if hours are 6-23 and minutes are 0-59, the tests becomes true and Relay_A is HIGH

Can you envision a scenario where the else if test would not evaluate to true?

If for example the now.hour is 3, this else test is false as the now.hour is outside of the true state as depicted above.
The test for Relay_A does work flawlessly, but it will only be tested true once every 24 hours and for a duration of 18 hours.  Relay_B will test true no less than twice daily, for the 10 minute period I desire.  Initially I wanted for individualized text outputs on the serial monitor which then justified the need to break up the 24 hour time span for Relay_B into multiple tests that needed to be true in themselve only and false during other tests which further made for more complicated code I'm sure.

Now with using jurs scheme of using the boolean tests and my decision to change the output language to a one phrase fits all, the code no longer needs to reflect individualized blocks for individualized events.  This all of course is predicated that I can find why Relay_B is only pulsing when it should be constant HIGH like that of Relay_A.
Title: Re: Seeking better testing language
Post by: PaulS on Jun 10, 2015, 02:46 pm
Quote
This all of course is predicated that I can find why Relay_B is only pulsing when it should be constant HIGH like that of Relay_A.
Do the pulses match the serial output? If not, you have a hardware problem that no amount of software tweaking is going to fix.
Title: Re: Seeking better testing language
Post by: myggle on Jun 10, 2015, 03:45 pm
Do the pulses match the serial output? If not, you have a hardware problem that no amount of software tweaking is going to fix.
I don't know what serial output is but the serial monitor shows the text with every iteration of the loop, the same as it does for the Relay_A condition which is true 75% of the time.  I just tested the hardware with this sketch;
Code: [Select]
void setup() {
  // initialize digital pin 13 as an output.
  pinMode(30, OUTPUT);
  pinMode(31, OUTPUT);
}

// the loop function runs over and over again forever
void loop() {
  digitalWrite(30, HIGH);   // turn the LED on (HIGH is the voltage level)
  digitalWrite(31, HIGH);
  delay(1000);              // wait for a second
  digitalWrite(30, LOW);    // turn the LED off by making the voltage LOW
  digitalWrite(31, LOW);
  delay(3000);              // wait for a second
}

... and it resulted in the relays turning on the test lights for 3 seconds and off for 1 second as expected, so it has to be code?
Title: Re: Seeking better testing language
Post by: PaulS on Jun 10, 2015, 04:02 pm
Quote
I don't know what serial output is but the serial monitor shows
The Serial Monitor is an application that runs on the PC. It displays serial data that the Arduino output.

Since the simple sketch works, add to it.

Put all the code for printing the time to the serial port in a function. Call that function from loop(). Do NOT clutter up loop with a bazillion lines of code to print the time.

Get rid of the useless curly braces and the useless comments. Everybody knows that delay() causes a delay. It really isn't necessary to add a comment that says that delay() delays.
Title: Re: Seeking better testing language
Post by: jurs on Jun 10, 2015, 06:32 pm
This all of course is predicated that I can find why Relay_B is only pulsing when it should be constant HIGH like that of Relay_A.
You don't try to drive a relay directly from the 20mA that an Arduino output pin can deliver, don't you?

When you write 'relay' you mean something like 'relay driving transistor' or 'circuit on a relay board' or something like that?

Except of very small "reed relays" with a "extra sensitive rating" you will need much more current than 20mA to switch a relay.
Title: Re: Seeking better testing language
Post by: myggle on Jun 10, 2015, 07:19 pm
I have a Sainsmart 8 channel Relay Module that is rated to be driven from Arduino's source capabilities.  I do intend to ultimately put it on external power supply, but b/c of a shortcoming with EtherMega, I need to keep it with USB power for the time being.  I do wish to point out that I am able to set all 8 channels to HIGH, as in the blink sketch, and all 8 relays change states as desired, but for some reason, channel 2 only clicks to produce the pulse when used in the Phase_1 sketch.  Here is a pic of my AC wiring to help convey what I built thus far.
(http://i1.wp.com/skydroponics.com/wp-content/uploads/2015/05/IMG_20150528_1952451.jpg)
After this pic was taken, I put the connecting wires from N.O. to each receptacle.  Everything is 14 AWG.

The Serial Monitor is an application that runs on the PC. It displays serial data that the Arduino output.

Since the simple sketch works, add to it.

Put all the code for printing the time to the serial port in a function. Call that function from loop(). Do NOT clutter up loop with a bazillion lines of code to print the time.

Get rid of the useless curly braces and the useless comments. Everybody knows that delay() causes a delay. It really isn't necessary to add a comment that says that delay() delays.
Sorry, I'm still too new to code and languages, I don't yet know what constitutes as a useless curly brace.  Useless comments I will nix.  Will putting all of time blocks into a function make the sketch smaller or run smoother? 
Title: Re: Seeking better testing language
Post by: PaulS on Jun 10, 2015, 07:59 pm
Quote
Will putting all of time blocks into a function make the sketch smaller or run smoother? 
No. But, if you say that printing the time works fine, then we don't need to look, at the code to see what the "not working fine" code is doing.

As for the "useless curly braces" comment, sorry about that. It was code in another thread that had them.
Title: Re: Seeking better testing language
Post by: jurs on Jun 10, 2015, 08:18 pm
for some reason, channel 2 only clicks to produce the pulse when used in the Phase_1 sketch.
Did you already post the full code of your "Phase_1 sketch"?
Which is the sketch that causes the faulty relay switching?
Title: Re: Seeking better testing language
Post by: nickgammon on Jun 10, 2015, 10:47 pm
Quote
I pasted the snippet about the test and mistyped the includes by mistake with hopes I would not have to explain why they were defined in the first place.  Yet here I am again explaining them for other reasons.
The point is, that when you post code that clearly doesn't compile, we wonder whether you retyped the whole thing. In other words, are we looking at the code you actually tested? Maybe you reversed a > and a < somewhere? I don't want to seem pedantic, but copying and pasting the whole sketch is the way to go.

http://snippets-r-us.com/ (http://snippets-r-us.com/)




You seem to have ignored my comments about why it was doing what it was, but just to check I've looked at your newer code. Look at this:

Code: [Select]
 if (relayBstate == true)
  {
    digitalWrite(Relay_B, TURN_ON);
    Serial.print("\t");
    Serial.println(F("Feeding the plants"));  //  Text printed to serial monitor
    Serial.print("\t");
  }
  else relayBstate = false;  // Turn off time for FeedPump1, OFF 9:10am
  {  
    digitalWrite(Relay_B, TURN_OFF);
  }
 


First, you normally don't test a boolean for "== true" because this looks cleaner:

Code: [Select]

  if (relayBstate)


Now, you think "what does 'true' or 'false' mean for a relay"? It is like saying "is my door true or false?".

Surely a better test would be:

Code: [Select]
 if (relayBClosed) ...


Now we know that "true" means "closed" and "false" means "not closed".




Moving on ...

Code: [Select]
 if (relayBstate == true)
  {
  ...
  }
  else relayBstate = false;  // Turn off time for FeedPump1, OFF 9:10am


If the relayBstate is false, make it false. How does this do anything useful?




Next:

Code: [Select]
   if (relayBstate == true)
    {
    ...
    }
  else
     relayBstate = false;  // Turn off time for FeedPump1, OFF 9:10am


// this is always done ! ---------------------------
    {  
      digitalWrite(Relay_B, TURN_OFF);
    }



If you indented your code with the auto-indent tool you might have spotted this. Regardless of relayBstate you always turn the relay off. Presumably not what you intend. Those lines do not fall under the scope of the else.
Title: Re: Seeking better testing language
Post by: nickgammon on Jun 10, 2015, 10:50 pm
I was hoping someone would point out the flaws in my test(s) so I can learn from my mistake(s), but I guess not.  
I did point out the flaws, with my analogy about slapping yourself. Presumably you thought that was a joke and decided to ignore it. I try to re-cast programming problems as real-life problems to force people to think beyond "why does C do this" to "what is my logic doing"?
Title: Re: Seeking better testing language
Post by: myggle on Jun 11, 2015, 03:18 am
If you indented your code with the auto-indent tool you might have spotted this. Regardless of relayBstate you always turn the relay off. Presumably not what you intend. Those lines do not fall under the scope of the else.
It took me some time to digest what you said and it dawned on me that "else relayBstate = false;" needed to be cut, so I did, uploaded, same result.  I commented out digitalWrite(Relay_B, TURN_OFF);, uploaded and relay_B went high and stayed (yay!).  I then uncommented that digitalWrite and uploaded again and all of a sudden, relay_B behaved as intended.  I tested it for a 10 minute lapse of time and it went LOW at the intended time.  One observation is that one of the climate sensor conditions was also true (Relay_E) and the respective relay was high for the duration of the feed time test, so perhaps there is a bug in the relay module.  I will change the code for the climate tests to stay LOW and have the feed test become true to see if the relay pulses again.

In short, I do not know why, but my issue seems to have resolved itself for the time being.  I will keep reading to try and build a programmers thought pattern.
Title: Re: Seeking better testing language
Post by: Robin2 on Jun 11, 2015, 11:08 am
I will keep reading to try and build a programmers thought pattern.
Maybe have a look at planning and implementing a program (http://forum.arduino.cc/index.php?topic=261445.0) ?

...R