One Button Two Functions bug fix

Hello all, back again with a teeny problem I would love some insight on.

My first post on the forum was about making one button do a latching state and a quick momentary state. With the help with the forum, I got a result that worked pretty well. I later found a problem with trying to incorporate a 5v latching low signal relay in the mix.

//LATCHING & MOMENTARY CODE

// constants won't change. They're used here to set pin numbers:

const int SW = 2;     // the number of the pushbutton pin
const int RELAYP = 4;    //+ RELAY COIL
const int RELAYN = 7;   //- RELAY COIL
const int LED =  13;      // the number of the LED pin


const unsigned long Debounce = 20;
const unsigned long LongPress = 500;

unsigned long ButtonStateChangeTime = 0; // Debounce timer

boolean ButtonWasPressed = false;
boolean Effect = false;

void setup() {

//SET PINS:
pinMode(SW, INPUT);
pinMode(LED, OUTPUT);
pinMode(RELAYP, OUTPUT);
pinMode(RELAYN, OUTPUT);

//Set SW pin to HIGH to monitor state.
digitalWrite(SW, HIGH);

//RESET BACK TO EFFECT BYPASS AFTER START UP:
Serial.begin(9600);
Serial.println("Start");//DEBUGGING

digitalWrite(RELAYP, LOW);
digitalWrite(RELAYN, HIGH);
delay(1);
digitalWrite(RELAYN, LOW);
}

void loop(){

unsigned long currentTime = millis();
boolean buttonIsPressed = digitalRead(SW) == LOW;  // Active LOW

// Check for button state change debounce.
if (buttonIsPressed != ButtonWasPressed &&
currentTime  -  ButtonStateChangeTime > Debounce){
// Button state has changed.
ButtonWasPressed = buttonIsPressed;

if (ButtonWasPressed){
Serial.println("Press");
digitalWrite(LED, HIGH);
digitalWrite(RELAYP, HIGH);
delay(1);
digitalWrite(RELAYP, LOW);
}

else{

//Released after 500ms has passed:
if (currentTime - ButtonStateChangeTime >= LongPress){
Serial.println("Momentary");
digitalWrite (LED, LOW);
digitalWrite(RELAYN, HIGH);
delay(1);
digitalWrite(RELAYN, LOW);
}

if (currentTime - ButtonStateChangeTime <= LongPress && Effect == false){
Serial.println("Latch On");
Effect = true;
digitalWrite(LED, HIGH);
digitalWrite(RELAYP, HIGH);
delay(1);
digitalWrite(RELAYP, LOW);
}
else{
if (Effect == true){
Serial.println("Latch off");
Effect = false;
digitalWrite(LED, LOW);
digitalWrite(RELAYN, HIGH);
delay(1);
digitalWrite(RELAYN, LOW);
}
}
}
//Time reset.
ButtonStateChangeTime = currentTime;
}
}//End.

Basically what I'm trying to get around is the fact when the LED is on in the latch mode, if you press the button again, it'll activate the Relay positive pin again and then neutral pin, causing the coil to lag.

I'm mainly trying to use an ATtiny13/85, otherwise I'd use multiple loops which I haven't been able to get to work on the chip.

Relay is driven by the microcontroller and works fine that way.

I have a simulation on Tinkercad to illustrate the operation:

The two multimeters in the sketch show the signal pulse in volts.

How would I go about isolating the momentary part of the code and the latching part?

Thank you!

Edit: Taking a look at the serial monitor, when it’s in latch on mode and the switch is pressed again, it refers to this part of the code:


if (ButtonWasPressed){
Serial.println("Press");
digitalWrite(LED, HIGH);
digitalWrite(RELAYP, HIGH);
delay(1);
digitalWrite(RELAYP, LOW);
}

before going back to:


if (Effect == true){
Serial.println("Latch off");
Effect = false;
digitalWrite(LED, LOW);
digitalWrite(RELAYN, HIGH);
delay(1);
digitalWrite(RELAYN, LOW);
}

I don’t know how to go about avoiding this. Another variable storing the button press?

You ought to use the autoformat function in the IDE. That way it looks like code, not text. Much easier to read especially indentations.

//LATCHING & MOMENTARY CODE

// constants won't change. They're used here to set pin numbers:

const int SW = 2;     // the number of the pushbutton pin
const int RELAYP = 4;    //+ RELAY COIL
const int RELAYN = 7;   //- RELAY COIL
const int LED =  13;      // the number of the LED pin


const unsigned long Debounce = 20;
const unsigned long LongPress = 500;

unsigned long ButtonStateChangeTime = 0; // Debounce timer

boolean ButtonWasPressed = false;
boolean Effect = false;

void setup() {

  //SET PINS:
  pinMode(SW, INPUT);
  pinMode(LED, OUTPUT);
  pinMode(RELAYP, OUTPUT);
  pinMode(RELAYN, OUTPUT);

  //Set SW pin to HIGH to monitor state.
  digitalWrite(SW, HIGH);

  //RESET BACK TO EFFECT BYPASS AFTER START UP:
  Serial.begin(9600);
  Serial.println("Start");//DEBUGGING

  digitalWrite(RELAYP, LOW);
  digitalWrite(RELAYN, HIGH);
  delay(1);
  digitalWrite(RELAYN, LOW);
}

void loop() {

  unsigned long currentTime = millis();
  boolean buttonIsPressed = digitalRead(SW) == LOW;  // Active LOW

  // Check for button state change debounce.
  if (buttonIsPressed != ButtonWasPressed &&
      currentTime  -  ButtonStateChangeTime > Debounce) {
    // Button state has changed.
    ButtonWasPressed = buttonIsPressed;

    if (ButtonWasPressed) {
      Serial.println("Press");
      digitalWrite(LED, HIGH);
      digitalWrite(RELAYP, HIGH);
      delay(1);
      digitalWrite(RELAYP, LOW);
    }

    else {

      //Released after 500ms has passed:
      if (currentTime - ButtonStateChangeTime >= LongPress) {
        Serial.println("Momentary");
        digitalWrite (LED, LOW);
        digitalWrite(RELAYN, HIGH);
        delay(1);
        digitalWrite(RELAYN, LOW);
      }

      if (currentTime - ButtonStateChangeTime < LongPress && Effect == false) {
        Serial.println("Latch On");
        Effect = true;
        digitalWrite(LED, HIGH);
        digitalWrite(RELAYP, HIGH);
        delay(1);
        digitalWrite(RELAYP, LOW);
      }
      else {
        if (Effect == true) {
          Serial.println("Latch off");
          Effect = false;
          digitalWrite(LED, LOW);
          digitalWrite(RELAYN, HIGH);
          delay(1);
          digitalWrite(RELAYN, LOW);
        }
      }
    }
    //Time reset.
    ButtonStateChangeTime = currentTime;
  }
}//End.

I was mainly editing the code in tinkercad directly which doesn't have an auto format function.

I got that feeling later. How do You manage to read the code in tinkercad?

Post a link for that relay.

I usually use one of these two:

https://b2b-api.panasonic.eu/file_stream/pids/fileversion/4514

What "neutral pin"?

To trigger the relay you add 5v to one side of the coil, 0v to the other side and vice versa. I only need to send a pulse to one side at a time. the positive and negative is just to keep track whats the orientation of the coil at that time

I see no relay in the simulation. It's not clear at all, what the circuit is supposed to do, exactly.

I've already mentioned that the multimeters in the tinkercad sketch show the pulses that go on one pin or the other at a time. I couldnt find a relay in tinkercad that worked well for emulation. Circuit controls the relay coil position which is wired for an audio signal while the LED is just an indicator whether the audio is on or off.

Pressing the button will activate the relay (RELAYP variable pulse) and turn the LED on. If the button is held for 500ms or more it continues to stay on until it's released and should shut off the led and switch the relay coil in the off position (RELAYN). Pressing the button and releasing the button for 500ms or less should keep the LED and switch the RELAYP on and keep it on ad then when the button is pressed and released again it should switch off (latching function).

But you could find another way to show us the relay connection. Really, it's confusing unless you already have it in front of you, as you presumably do. Like a schematic or wiring diagram. How is the relay driven? I/O pins really don't have enough power for most relays.

Also if the relay is at all unconventional, please link to some specs.

Yes but that information is singularly unhelpful.

this information was already provided in the post.

The coil current exceeds the safe operating region of most Arduino I/O pins. Still waiting for a connection diagram. Unless I missed that too. From that maybe I can see if you have freewheeling diodes.

I have not fried any pins on arduino or an attiny with this relay.

Okay, will that makes it easier to understand. Software wise, what I would do is make functions to do the repetitive things like

          Effect = false;
          digitalWrite(LED, LOW);
          digitalWrite(RELAYN, HIGH);
          delay(1);
          digitalWrite(RELAYN, LOW);

Which would also make it easier to understand, and perhaps easier to spot the error.

Another weakness, you treat the differential drive pins separately, so that the state has to be managed by the consecutive flow of logic. This is not really good. You need to encapsulate the correct relay drive sequences of both pins in functions or object methods. It is the best way to avoid the confusion about program flow. As it is likely not directly related to relay logic itself, which when considered separately is a straightforward and foolproof task.

like I said in my initial post, Im using attiny and havent been able to format it to call multiple loops. if theres a way to do it on the chip (like void1, void2...), i would do that.

I will worry about the relay pulse on/off code clean up later, for now I need to figure out a way to format the flow. I edited my first post what i reported in the serial monitor

changed up the format a bit:

void loop() {

  unsigned long currentTime = millis();
  boolean buttonIsPressed = digitalRead(SW) == LOW;  // Active LOW

  // Check for button state change debounce.
  if (buttonIsPressed != ButtonWasPressed &&
      currentTime  -  ButtonStateChangeTime > Debounce) {
    // Button state has changed.
    ButtonWasPressed = buttonIsPressed;

    if (ButtonWasPressed) {
      Serial.println("Press");
      digitalWrite(LED, HIGH);
      digitalWrite(RELAYP, HIGH);
      delay(1);
      digitalWrite(RELAYP, LOW);
      
       
      
    } else {
      
      //released before 500ms has passed:
      if (currentTime - ButtonStateChangeTime < LongPress) {

        Serial.println("Latch");

        LEDState = ! LEDState;

        RelayNstate = ! RelayNstate;
        delay(1);
        digitalWrite(RELAYN, LOW);
      

      digitalWrite(LED, LEDState);

      digitalWrite(RELAYN, RelayNstate);
      delay(1);
      digitalWrite(RELAYN, LOW);  
       
      } else {

    //Released after 500ms has passed:
    if (currentTime - ButtonStateChangeTime > LongPress) {
      Serial.println("Momentary");
      digitalWrite (LED, LOW);
      digitalWrite(RELAYN, HIGH);
      delay(1);
      digitalWrite(RELAYN, LOW);
    } 
      }
    }
    //Time reset.
    ButtonStateChangeTime = currentTime;
  }
}//End.

But its still pulsing the relay pin + before pulsing the relay pin -.

would want it to flow like:

void loop() {

 //debounce

//press which turns on the light/pulse (relay pin 10 on schematic) relay pin+ at same time

//if released  LESS than 500ms (quick press), keep light on  (latching on).
//if pressed again in this state, ONLY turn relaypin- on to switch relay position and turn light off while in this state (latch off).

//if released  MORE than 500ms (continuous hold until released), pulse relay pin- (relay pin1 on schematic)  and turn off LED.

 //Time reset.
  
}//End.

Hopefully this explanation helps any future user that stumbles upon this post. Thank you.

Attiny is programmed using the same language, C/C++. The full language is available to you, except for some library functions that were removed to make the compiled code smaller. You can absolutely create new functions like void1() void2() but with better names of course. Even object oriented code is supported.

Ok well then that's good to read, I guess Im just doing something wrong on that.

as a test i did this to see if i can even get a serial monitor message but no luck.

// constants won't change. They're used here to set pin numbers:

const int SW = 2;     // the number of the pushbutton pin
const int LED =  13;      // the number of the LED pin

const unsigned long Debounce = 20;

unsigned long ButtonStateChangeTime = 0; // Debounce timer

boolean ButtonWasPressed = false;

void setup() {

//SET PINS:
pinMode(SW, INPUT);

//Set SW pin to HIGH to monitor state.
digitalWrite(SW, HIGH);

//RESET BACK TO EFFECT BYPASS AFTER START UP:
Serial.begin(9600);
Serial.println("Start");//DEBUGGING

}

void loop(){

  
  
unsigned long currentTime = millis();
boolean buttonIsPressed = digitalRead(SW) == LOW;  // Active LOW

// Check for button state change debounce.
if (buttonIsPressed != ButtonWasPressed &&
currentTime  -  ButtonStateChangeTime > Debounce) {
// Button state has changed.
ButtonWasPressed = buttonIsPressed;

if (ButtonWasPressed) {

void button();

}
//Time reset.
ButtonStateChangeTime = currentTime;
}
}//End Main Loop.

void button(){
    
Serial.println("Press");  
  
}//Loop 2 End.

debounce in the main loop and then move on to the other loop. no message though.