State change detection

Hi. New to arduino programming and this forum. I want a code for turning a relay on and off from a momentary pushbutton, one click on, next click off. Found this public code: https://www.arduino.cc/en/Tutorial/StateChangeDetection and changed the if (buttonPushCounter % 4 == 0) { to if (buttonPushCounter % 2 == 0) { and it worked...

But is this the most efficiant way to achieve the purpouse?

Br
Staffan

If you only need two states just use a Boolean with true false values.

Thanks, will read up. Is there a library thingie for this to import or do I write it myself?

you may need to remove switch bounce

No library. Just a variable. If you don't know what Boolean is then you should click at the top of this page on learning -> reference and do a day or two worth of reading.

Thank you. I am reading up whenever I have time, it is fun but a bit rusty in the beginning. I found another example on how to solve it. Long debounce time tho. What do you think about using that?
https://www.arduino.cc/en/tutorial/switch

It's fine, although just an example. You can change the debounce time to any value you want.

An alternative to software debounce is hardware debounce with a cap (0.1uf) across the switch. The example uses a switch wired to Vcc and a pulldown resistor. The more common way is to wire the switch to ground and use the internal pullup resistor (enabled with pinMode(pin, INPUT_PULLUP). The switch input will be HIGH when not pressed and LOW when pressed.

Thanks. The reason for me fiddling with Aurdino and SW-control for the first time is for that I am going for controlling several tube lab supplies remote, to be able to switch their outputs all on and off at the set voltage at the same time by config.

Additional to that I will use a mosfet to pull down the power tube grids so the output dc goes near zero and then with a small delay totally disconnect the supplies with a relay. It is not so cool to switch 300+ vdc with a general purpouse cheap relay.

Neat starting project :stuck_out_tongue:

Think long and hard about controlling high voltage with software, especially if programming is not your forte.

Thank you gfvalvo, I have many years of hv experience so I dont trust anything before measuring, this is just to simplify things a bit.

stajo:
Thank you gfvalvo, I have many years of hv experience so I dont trust anything before measuring, this is just to simplify things a bit.

OK, good. It's just that I've seen some projects proposed on this forum where the only thing standing between the user and release of potentially dangerous energy is a hobbyist microcontroller board and their own firmware. Engineering high-rel, fail-safe firmware is a complex process (not to mention failure modes of the microcontroller and hardware itself). It was quickly obvious by looking at their code that they didn't know what they were doing.

This is the simplest i could come up with going boolean as Delta_G sugested and without hw debouncing. Seems to work like a charm. Comments, flaws?

// Momentary pusbutton connected between ground and an up-pulled input toggles an output

const int switchPin = 2;                // Declares the variable switchPin and initializes its value as pin 2 globaly
const int toggleoutPin = 13;          // Declares the variable toggleoutPin and initializes its value as pin 13 globaly

boolean on = false;                      // Declares the variable state and initializes its value as LOW globaly. 
                                                  // This gives it a starting value but can later change.
void setup()
{
  pinMode(switchPin, INPUT_PULLUP);     // Declares the switchPin as being in input mode and connects the internal 
                                                            // 20k resistor between input and 5V rail

  pinMode(toggleoutPin, OUTPUT);           // Declares the toggleoutPin as being in output mode
}
void loop()
{
  if (digitalRead(switchPin) == LOW)        // Reads if the value on swithPin goes low because shorted by momentary switch button
  {  
    delay(200);                                        // Delays 200 ms to debounce switch
    on = !on;                                           // Toggles boolean variable on row 4 from false to true and vice versa
    digitalWrite(toggleoutPin, on);              // Indicates via built in LED on pin 13 that toogleoutPin toggles in this example
  }
}

Comments, flaws?

I have not followed this thread closely but I thought that you wanted to detect a change of state of an input pin. That is not what this code is actually doing.

There is actually no need for the boolean if you do

digitalWrite(toggleoutPin, !digitalRead(toggleoutPin));

Another comment. Why use int variables for pin numbers when their value is not larger than 255 ?

I don't think that code is going to have the behavior you wanted.

I want a code for turning a relay on and off from a momentary pushbutton, one click on, next click off.

What happens if you push the button and hold it down for exactly one quarter second? What happens if you hold it down for an entire second? These are not rhetorical questions. I would really like to see your answers.

Jimmus:
I don't think that code is going to have the behavior you wanted.

What happens if you push the button and hold it down for exactly one quarter second? What happens if you hold it down for an entire second? These are not rhetorical questions. I would really like to see your answers.

Hence my comment in reply #13

Thank you very much for good comments and questions! I had to attend a formal dinner so I couldnt answer immediately.

Headline: State change detection, well that's just a noob trying to find what I thought I was after.

Why do I use Int? Good question, what should I have used?

What happens if I hold down the button? Well it starts to toggle 3-4 times per second. Clearly a flaw.

Since I just went and baught a little starting kit, having done some starter experiments I dont know very much what I am doing. I think the only way for me to learn is to find experiments that is similar to what I am trying to achieve, copy some example code and try to write comments after every snippet what I think the code is doing. So that is what I am doing and then ask stupid questions here of course.

So thanks again for valuable feedback, every point in the right direction, codelines, explanations is very valuable and welcome for me.

When you use variables to save the state for later use, you have to make sure you're working with the state of the right thing. The code you posted used the boolean to keep track of the state of LED on the output pin. That's not really necessary, because you are the one who controls the output pin, and you can check it any time. What you really want is to check the state of the button on the input pin.

This can be done with a boolean, but then you have to assign a meaning, like true = HIGH and false = LOW, and then you have to have logic to check those separately. It's easier for me to use the same type of variable as the thing I'm checking the state of. In this case, it's a digitalRead() which returns an int, so I would use an int for the state variable.

Loose algorithm. Will need to be adapted to your program:

int lastSwitchPinState = HIGH;              // This will be used to keep track of what state the switchPin WAS last time we checked it
                                            // This assumes the button is not pressed at startup
void loop()
{
  int currentSwitchPinState = digitalRead(switchPin);

  if (currentSwitchPinState != lastSwitchPinState)  // If the state has changed, we have a state change.  Imagine that!
  {
    if (currentSwitchPinState == LOW)       // State change was HIGH to LOW.  Button was pressed, not released.
    {
      // toggle the output
    }
    delay(20);    // debounce
    lastSwitchPinState = currentSwitchPinState;
  }
}

Notice that even after we have detected the state change, we're not done. The state changes whenever the button gets pressed, or released, or when bounces happen. We only want to toggle the LED when the button is pressed, which means the previous state was HIGH and the current state is LOW. Otherwise, we want to ignore the state change, except that in either case we still want to debounce and update the state variable.

Why do I use Int? Good question, what should I have used?

You probably used int because many of the examples do and it works but it is not good programming practice as it wastes memory, albeit only one byte for each variable, but a waste nevertheless.

It would have been better to use byte variables for pin numbers as their value will never exceed 255.

In practice this would not make any difference in your program but it is important to get into good habits. For instance I have seen arrays of ints declared that only ever have a value of 0 or 1. This can waste massive amounts of memory and would use only half as much were they bytes. Better still, use the bits of the bytes to hold the 0/1 and compared with using ints the memory used is reduced to one sixteenth of the original,

Thanks alot for valuable comments, and yes UKHeliBob, I am copying and modifying examples, tests how they behave and tries to understand what the command lines do. My learning works best that way, theory without practice is not my strong side.

Jimmus, thank you very much for guidance code and explanational comments, very nice. I have taken a first peak at it (at work, no arduino board here, dont tell anyone) and tried to interprete it with further noob comments and questions. Please dont take it for lecturing from my side, it is quite the opposite.

int lastSwitchPinState = HIGH;              // This will be used to keep track of what state the switchPin WAS last time we checked it
                                            // This assumes the button is not pressed at startup

Comment Staffan: As I understand this DECIDES that the lastSwitchPinState was HIGH and assumes that since the button was not pressed under startup the state is HIGH with the pullup resistor. This is for the program to know what the state next change should be. This value gets changed by lastSwitchPinState = currentSwitchPinState; in the loop when button is pressed.
Question: Why is this an int when it can only have two values?

  int currentSwitchPinState = digitalRead(switchPin);

Comment Staffan: This reads the state of the switchPin and declares it to be the currentSwitchPinState, is that the way to interprete it?

  if (currentSwitchPinState != lastSwitchPinState)  // If the state has changed, we have a state change.  Imagine that!

Comment Staffan: OK, this is a way of DETECTING a state change, and works together with the next if command? It compares the value current with last?

    if (currentSwitchPinState == LOW)       // State change was HIGH to LOW.  Button was pressed, not released.

Comment Staffan: Together with the former if command it is querying if the state change was from HIGH to LOW, ie button was pressed.

      // toggle the output
    }
    delay(20);    // debounce
    lastSwitchPinState = currentSwitchPinState;

Comments Staffan: If the above if-queries was true go ahead and change lastSwitchPinState to currentSwitchPinState, but it doesn’t toggle any output, that is code I have to add, correct?