simple sketch for switch and relay

I am a commercial espresso machine technician and I have this project where I want to try forcing a machine to go into an automatic rinse cycle. I am completely new to arduino. I need 2 small relays to be activated depending on the state of one switch. I am starting to learn arduino programing but I am hoping that someone here will write a sketch for me. I want to use arduino uno to monitor and activate:

SwitchA, INPUT , pin8, mechanical switch
R1,OUTPUT pin9, Relay1
R2,OUTPUT pin10, Relay2

the loop should do this:

If switchA is closed then a timer starts at T=0sec. (time elapsed=T)
If T >5 min. then - activate R1 for 1 sec then deactivate.

  • pause 1 sec.
  • activate R2 for 1 sec then deactivate
    -stop timer and reset T to T=0.

Is SwitchA a momentary contact switch or an on/off switch ?
What should happen if SwitchA is turned on/pressed during the cycle ?
What should happen if SwitchA is still on/pressed at the end of the cycle ?

This sounds like a very easy first project. Get writing !

Thanks for your interest.
SwitchA is an on/off switch that closes for about 4 sec. As long as it is closed the loop resets the timer to zero. When the switch opens the count down starts.
If the switch closes during the countdown the loop resets the timer to zero.

I think the code would look something like this. I still dont know how to write a timer variable in arduino

const int SwitchA=8
const int R1=9
const int R2=10

void setup()
pin mode (SwitchA, INPUT)
pin mode (R1, OUTPUT)
pin mode (R2, OUTPUT)

void loop () {
switchstate=digitalread(SwitchA)
IF (switchstate==HIGH) {start timer at T=0
IF(T> 5min.) {digitalwrite(R1=HIGH)
delay 1sec
digitalwrite (R1=LOW)
delay 1sec
digitalwrite(R2=High)
delay 1 sec.
digitalwrite(R2=LOW)
stop timer and reset to T=0}}}

Your 'code' has some of the right ideas in it. Using delay() is simple. The code effectively stops for the period that the delay() is in action. However, you will come to regret using it for that very reason. Suppose that you wanted to add an 'abort' button. It would not be read during any of the delay()s so would be of little value.

A better approach in the long run is to use the technique shown in the BlinkWithoutDelay example in the IDE. This uses the value of millis() to determine whether it is time to do something and if not, go and do something else, such as read a button.

Applying this to your requirement, have a look at this

const byte switchA = 8;
const byte relay1 = 9;
const byte relay2 = 10;
unsigned long fiveMinutes = 5UL * 60 * 1000;
unsigned long oneSecond = 1000;
unsigned long startTime = 0;
byte timingState = 0;

void setup() 
{
  Serial.begin(115200);
  pinMode(switchA, INPUT_PULLUP);
  pinMode(relay1, OUTPUT);
  pinMode(relay2, OUTPUT);
}

void loop() 
{
  if (digitalRead(switchA) == LOW)
  {
    startTime = millis();  
    timingState = 1;
  }

  switch (timingState)
  {
  case 1:

    if (millis() - startTime >= fiveMinutes)
    {
      digitalWrite(relay1, HIGH); 
      startTime = millis();
      timingState = 2;
    }
    break;

  case 2:
    if (millis() - startTime >= oneSecond)
    {
      digitalWrite(relay1, LOW); 
      startTime = millis();
      timingState = 3;
    }
    break;

  case 3:
    if (millis() - startTime >= oneSecond)
    {
      digitalWrite(relay2, HIGH); 
      startTime = millis();
      timingState = 4;
    }
    break;

    case 4:
    if (millis() - startTime >= oneSecond)
    {
      digitalWrite(relay2, LOW);
      timingState = 0; 
    }
    break;
  }
}

At any time the system is in one of 5 states, either waiting for a keypress or waiting for a timing period to end. This is known as a finite state machine and the technique is very useful.

Nice! thanks, I will study this and get back to you if I have any questions

I get it, but I have a question about the internal counter.
what happens when the internal counter millis() reaches the maximum time. I read that this is about 40 days and then it resets to zero. Let's say switchA closes just before that maximum time (millis()=huge number):
The argument in the first if() statment is true so startTime is set to equal that huge number and timingState is set to 1.
The switch() statment keeps calling case 1 until millis() - huge number >= five minutes.
lets say after a few sec. the internal counter reaches its limit and starts back at millis()=0.
now( millis() - huge number >= five minutes) wont be true ever
So unless switchA closes again and startTime is reset to =millis(), the code would just queep looping case 1 and the cleaning cycle( case2, case3, case4) would never be finished.

Because when you are an unsigned value with only n number of bits available 0 - 1 != -1

void setup() {
  Serial.begin(115200);
  unsigned int x = 0;
  Serial.println(x - 1);
}

void loop() {

}

So it isn't an issue when done properly and you seem to have a that figured out. Always subtract from millis() and don't worry about it. You can find more in depth discussions about it.

Yes, strange as it may seem at first, the rollover of millis() to zero does not affect the calculation if it is done as a subtraction of the start time from the current time.

HI UKHeliBob,
The "simple sketch for switch relay" question was a simplified situation of what I want to do, just to get me started. My real life situation is actually more complex. The coffee machine I am modifying has two independent coffee machines (group1 and group2) in one enclosure. Each group has a built in coffee grinder and a brewing chamber. When a coffee is selected from the coffee machine button pad, the grinder turns on for a few seconds and ground coffee falls in the brewing chamber and then the coffee is made. I installed a relay on each coffee grinder so that the switch in the relay closes when the grinder is turned on. I call these 2 relays: switch1 and switch2. The arduino monitors the state of these switches and initiates a rinsing cycle 5 min. after the switch closes. I also added LED lights on each group that light up the coffee cup while a coffee is dispensed and that blinks while the rinsing cycle is happening. So wow! my code got much bigger! But it works perfect...99% of the time. Once in a while weirdness happens (LED that keep blinking forever and rinsing cycles that never end and other weirdness!) . So it's debugging time. I will have to add //explanations// to my code before I send it here because now it looks quite confusing.
Before I do this I have one question to you:
In this section of your code

unsigned long fiveMinutes = 5UL * 60 * 1000;
unsigned long oneSecond = 1000;
unsigned long startTime = 0;

why do you write
unsigned long fiveMinutes = 5UL * 60 * 1000 ???

I just wrote
unsigned long fiveMinutes = 300000

is it important to write it the way you did? If it is, why do you write
unsigned long oneSecond = 1000;
and not
unsigned long oneSecond = 1UL * 1 * 1000;
???

I wrote an extended demo of the Blink Without Delay technique in the first post of this Thread. It may help you to visualize how several things can be controlled.

I am a great believer in putting the different pieces of code in their own functions as I reckon it makes it much easier to see the overall concept of the project and, when necessary, to look at specific details without being confused by other parts.

...R

why do you write
unsigned long fiveMinutes = 5UL * 60 * 1000 ???

I just wrote
unsigned long fiveMinutes = 300000

I wrote the way I did to make it obvious how the 5 minutes was derived, ie 5 times 60 seconds, but it is perfectly acceptable to just assign the total number of milliseconds to the fiveMinutes variable. Writing it the way that I did also prevents more or less zeroes being typed in the total and avoids my old eyes and brain needing to count them.

UKHeliBob:

why do you write
unsigned long fiveMinutes = 5UL * 60 * 1000 ???

I just wrote
unsigned long fiveMinutes = 300000

I wrote the way I did to make it obvious how the 5 minutes was derived, ie 5 times 60 seconds,

+1 for clarity. The compiler works it out and it makes no difference to the final program.

...R