How to make a RS latch?

Hi everybody,

I've spent years to program PLCs and I have discovered Arduino. I want to learn and to understand how to make my own programs and not just to copy and paste what has been done by others.
I start with small and easy programs and I try to increase the difficulty slowly. But now I'm stuck.

Here is what I want to do:
I have 3 inputs connected to 3 switches. Each input controls its own output (a Led), plus an extra output common to the 3 inputs and a last input to reset the common output.
When one input will be HIGH, the corresponding led will blink and the common led to all inputs will also blink.
When the input is going back to LOW, both led will be off.

For now this is working, I succeeded to do it. I don't know if it's the correct way to do it but it works.

Now , when the common led is blinking, I want to switch it off by pressing a button and the led will stay off when the button will be released.
And if another input goes to HIGH, its output led will be on with the common led which will be reset by the press button, and so on.

With a PLC this is very easy to do by using RS latches, but here, I'm lost.

Here is my code:

void loop(){
 loop1();
 loop2();
 loop3();
 loop4();
} 
  
void loop1(){
  
  input1State = digitalRead(input1);

  if (input1State == HIGH) {     
  
  unsigned long currentMillis = millis();
 
  if(currentMillis - previousMillis > interval) {
 
  previousMillis = currentMillis;   

  if (led1State == LOW)
  led1State = HIGH;
  else
  led1State = LOW;

  digitalWrite(led1, led1State);
  }
  } 
  else {
  digitalWrite(led1, LOW); 
  }
}

void loop2(){
  input2State = digitalRead(input2);

  if (input2State == HIGH) {     
   
  unsigned long currentMillis = millis();
 
  if(currentMillis - previousMillis > interval) {
  previousMillis = currentMillis;   

  if (led2State == LOW)
  led2State = HIGH;
  else
  led2State = LOW;

  digitalWrite(led2, led2State);
  }
 } 
  else {
  digitalWrite(led2, LOW); 
  }
}

void loop3(){
  input3State = digitalRead(input3);

  if (input3State == HIGH) {     
   
  unsigned long currentMillis = millis();
 
  if(currentMillis - previousMillis > interval) {
  previousMillis = currentMillis;   

  if (led3State == LOW)
  led3State = HIGH;
  else
  led3State = LOW;

  digitalWrite(led3, led3State);
  }
 } 
  else {
  digitalWrite(led3, LOW); 
  }
}

void loop4(){

  input1State = digitalRead(input1);
  input2State = digitalRead(input2);
  input3State = digitalRead(input3);
  resetState = digitalRead(reset);

  if (input1State | input2State | input3State == HIGH) {     

  unsigned long currentMillis = millis();
 
  if(currentMillis - previousMillis > interval) {
    previousMillis = currentMillis;   

    if (led4State == LOW)
      led4State = HIGH;
    else
      led4State = LOW;

    digitalWrite(led4, led4State);
  }
  }
     else {
    digitalWrite(led4, LOW);
  
  } 
  }

I'm listening all your comments, I'm here to learn :wink:

if (input1State | input2State | input3State == HIGH)

There is an | operator and there is a || operator. They do completely different things.

It looks like you want to do this:

if(input1State == HIGH || input2State == HIGH || input3State == HIGH)

Thanks, first thing I didn't know.

My main problem is still in this loop:

void loop4(){

  input1State = digitalRead(input1);
  input2State = digitalRead(input2);
  input3State = digitalRead(input3);
  resetState = digitalRead(reset);

 if(input1State == HIGH || input2State == HIGH || input3State == HIGH) {    

  unsigned long currentMillis = millis();

  if(currentMillis - previousMillis > interval) {
    previousMillis = currentMillis;  

    if (led4State == LOW)
      led4State = HIGH;
    else
      led4State = LOW;

    digitalWrite(led4, led4State);
  }
  }
     else {
    digitalWrite(led4, LOW);
  
  }
  }

Input1, 2 and 3 are switches and reset is a push button.

When one input will be HIGH, its own led + led4 will blink. I want to switch off led4 with the push button. Led4 will stay off as long as a new input switches to HIGH.

What I'm doing is a simple alarm with 3 zones. When one zone is activated, its led will blink and a buzzer will buzz :slight_smile: The reset push button is to acknowledge it and stop the buzz.

Anybody to help me? :frowning:

What I'm doing is a simple alarm with 4 zones.

Then, you should have variables named zone1Pin, zone1State, etc.

  input1State = digitalRead(input1);
  input2State = digitalRead(input2);
  input3State = digitalRead(input3);

Are these the 4 zone states?

    if (led4State == LOW)
      led4State = HIGH;
    else
      led4State = LOW;

This can be simplified

led4State = !led4State;

Is LED 4 the buzzer?

What type is previousMillis and interval? What do they represent?

It appears that you can only shut the buzzer off after some period of time (interval). Why is that?

Then, you should have variables named zone1Pin, zone1State, etc.

You 're right, but instead I named them input1, input1State, input2, input2State,... and it's 3 zones not 4 like I mentioned earlier.

Is LED 4 the buzzer?

What type is previousMillis and interval? What do they represent?

It appears that you can only shut the buzzer off after some period of time (interval). Why is that?

Yes, for now the buzzer is represented by a LED that why I named it led4.

I don't want a continuous sound for the buzzer I want it to "blink" like a LED.

I use the same code for the LEDs to blink:

int led1State = LOW; 
int led2State = LOW;
int led3State = LOW;
int led4State = LOW;

long previousMillis = 0; 

  
long interval = 800;
void loop3(){
  input3State = digitalRead(input3);

  if (input3State == HIGH) {    
  
  unsigned long currentMillis = millis();

  if(currentMillis - previousMillis > interval) {
  previousMillis = currentMillis;  

  if (led3State == LOW)
  led3State = HIGH;
  else
  led3State = LOW;

  digitalWrite(led3, led3State);
  }
 }
  else {
  digitalWrite(led3, LOW);
  }
}

The blinking is fine, it's just this reset which is not working.

You 're right, but instead I named them input1, input1State, input2, input2State,... and it's 3 zones not 4 like I mentioned earlier.

My comment was a hint. When the variable names mean something it is much easier to follow the program logic than when state1, pin 1 type names are used.

The blinking is fine, it's just this reset which is not working.

The loop4() function reads the state of the reset switch, and store it in resetState. That's the last reference to resetState that I see.

The loop4() function reads the state of the reset switch, and store it in resetState. That's the last reference to resetState that I see.

It's just because I really don't know how to do.

If any zone LED pin is set HIGH, the buzzer pin is set HIGH, too. Right?

Create 3 instances of the Button class, one for each zone.

You probably want three functions (although you really only need one) that will set the zone LED pin HIGH, if the zone switch has changed state (Button::uniquePress). Set the buzzer pin HIGH, too.

Then, create a 4th function that checks the reset switch state, and turns off the buzzer pin if the reset switch state is HIGH.

By the way, function names, like variable names, should be meaningful. checkZone1() means a lot more than loop1().

If any zone LED pin is set HIGH, the buzzer pin is set HIGH, too. Right?

That's correct!

Create 3 instances of the Button class, one for each zone.

You probably want three functions (although you really only need one) that will set the zone LED pin HIGH, if the zone switch has changed state (Button::uniquePress). Set the buzzer pin HIGH, too.

Then, create a 4th function that checks the reset switch state, and turns off the buzzer pin if the reset switch state is HIGH.

By the way, function names, like variable names, should be meaningful. checkZone1() means a lot more than loop1().

Ok, thanks a lot, I will try that. And thanks for the last advise, I will follow it now :wink:

Quote:
Create 3 instances of the Button class, one for each zone.

You probably want three functions (although you really only need one) that will set the zone LED pin HIGH, if the zone switch has changed state (Button::uniquePress). Set the buzzer pin HIGH, too.

Then, create a 4th function that checks the reset switch state, and turns off the buzzer pin if the reset switch state is HIGH.

By the way, function names, like variable names, should be meaningful. checkZone1() means a lot more than loop1().

I must be very stupid, I tried a lot of different things, I read and read and read tutorials, other forum posts and I'm still with the same problem and at the same point :frowning:

I must be very stupid

I doubt that.

I tried a lot of different things,

I believe that.

I read and read and read tutorials, other forum posts

Reading and understanding aren't the same thing, but I'll give you credit for trying.

I'm still with the same problem and at the same point

So, you've tried a lot of different things. One thing you haven't tried is posting your latest code. Why don't you give that a try.

Reading and understanding aren't the same thing, but I'll give you credit for trying.

But I tried to understand. I've now spent few days trying to find the solution by myself and the forum is my last chance. I ordered few books but they are not arrived.

I followed your advises and renamed everything to make it more understandable.
Here is my latest code (which is almost working except that when I release the reset button, the reset led starts to blink again.

/*
Alarm 3 zones

 */

const int zone1pin = 1;
const int zone2pin = 2;
const int zone3pin = 3;
const int resetpin = 4;

const int led1pin =  5;    
const int led2pin =  6;
const int led3pin =  7;
const int ledResetpin =  8;

int zone1State = 0;  
int zone2State = 0;
int zone3State = 0;
int resetState = LOW;


int led1State = LOW;
int led2State = LOW;
int led3State = LOW;
int ledResetState = LOW;

long previousMillis1 = 0;
long previousMillis2 = 0;
long previousMillis3 = 0;
long previousMillis4 = 0;

long interval1 = 300;  
long interval2 = 800;

void setup() {

pinMode(led1pin, OUTPUT);    
pinMode(led2pin, OUTPUT);  
pinMode(led3pin, OUTPUT);
pinMode(ledResetpin, OUTPUT);  

pinMode(zone1pin, INPUT);
pinMode(zone2pin, INPUT);
pinMode(zone3pin, INPUT);  
pinMode(resetpin, INPUT);

digitalWrite(resetpin, LOW);

}

void loop(){
checkZone1();
checkZone2();
checkZone3();
Reset();
}

  
void checkZone1(){

zone1State = digitalRead(zone1pin);
resetState=digitalRead(resetpin);

if (zone1State == HIGH) {        
unsigned long currentMillis1 = millis();

if(currentMillis1 - previousMillis1 > interval1) {
previousMillis1 = currentMillis1;  
    
led1State = !led1State;

digitalWrite(led1pin, led1State);
}
}
else {
digitalWrite(led1pin, LOW);
}
}

void checkZone2(){

zone2State = digitalRead(zone2pin);

if (zone2State == HIGH) {    
  
unsigned long currentMillis2 = millis();

if(currentMillis2 - previousMillis2 > interval1) {

previousMillis2 = currentMillis2;  

led2State = !led2State;

digitalWrite(led2pin, led2State);
}
}
else {

digitalWrite(led2pin, LOW);
}
}

void checkZone3(){

zone3State = digitalRead(zone3pin);

if (zone3State == HIGH) {    
  
unsigned long currentMillis3 = millis();

if(currentMillis3 - previousMillis3 > interval1) {
  
previousMillis3 = currentMillis3;  

led3State = !led3State;

digitalWrite(led3pin, led3State);
}
}
else {

digitalWrite(led3pin, LOW);
}
}

void Reset(){

zone1State = digitalRead(zone1pin);
zone2State = digitalRead(zone2pin);
zone3State = digitalRead(zone3pin);  
resetState = digitalRead(resetpin);

  
if(resetState == LOW && (zone1State == HIGH || zone2State == HIGH  || zone3State == HIGH))  {    

  
         unsigned long currentMillis4 = millis();

            if(currentMillis4 - previousMillis4 > interval2) {

            previousMillis4 = currentMillis4;  

            ledResetState = !ledResetState;

            digitalWrite(ledResetpin, ledResetState);

 
 }
       }
  else {

  digitalWrite(ledResetpin, LOW);
  
  }

}

I don't know what is happening to your indenting when you post code here. I hope it looks better for you.

Some comments in the code would be helpful, too. I don't understand what the stuff with millis() is in the Reset() function. It looks like the reset switch has to be held down for a while in order to reset the system.

You need to add another variable, a boolean, isReset. It needs an initial value, either true or false.

The value in that variable needs to be checked before turning the "buzzer" LED on, in each checkZone function.

The value needs to be set (to true) in Reset(), when the "buzzer" LED is turned off.

At some point, you'll want to set it back to false. I would want to keep track of the old zoneNState values. If a zone goes HIGH it causes the zone and buzzer LEDs to be lit. If the reset switch is pressed, it causes the buzzer LED to be turned off. If the zone then goes LOW, and HIGH again, you would want the "buzzer" LED to be lit again, I would think. The only way to do this is to compare the current setting to the previous setting. If the current setting is HIGH, and it was LOW, isReset whould be set to false, and the "buzzer" LED should be lit again.