Serial.print once and not in loop?

Hey everyone, I'm trying to get Serial information from my code but given that I'm operating inside a loop i'm printing the state of the LED/switch over and over. The momentary switch simply changes the LED's state. Is there a simpler way of getting the state once per state change of the switch in my serial monitor? Thanks!!

Code:

const int switchPin = 5;
const int ledPin = 6
int Val = 0;

void setup() {

pinMode (switchPin, INPUT);
pinMode (ledPin, OUTPUT);
Serial.begin(9600);

}

void loop() {

Val = digitalRead(switchPin); //read the switch
  if (Val == HIGH) { //check input state if HIGH
    digitalWrite(ledPin, LOW); 
      Serial.println(LOW);         
  } else {
    digitalWrite(ledPin, HIGH); 
      //Serial.println(HIGH);      
  }
  
}

Look at the included example sketches in the IDE for the one called "State Change"

Delta_G:
Look at the included example sketches in the IDE for the one called "State Change"

I've played with the example sketch but it seems not to work with my switch. It's giving me on and off in the same cycle of clicking my switch. When I press down it reads one state and when I release it reads another state. Doesn't seem to work for me.

Not just that but the example code has a delay in there which is fundamental to the code. I can't have delays in my code unfortunately, it messes with my loops.

const byte switchPin = 5;
const byte ledPin = 6;
byte doOnceFlag;

void setup() {
  pinMode (switchPin, INPUT);
  pinMode (ledPin, OUTPUT);
  Serial.begin(9600);
}

void loop() {
  if (digitalRead(switchPin) == HIGH) {
    if (doOnceFlag == 0) {
      digitalWrite(ledPin, LOW);
      Serial.println("Low");
      doOnceFlag = 1;
    }
  }
  else {
    digitalWrite(ledPin, HIGH);
    doOnceFlag = 0;
    //Serial.println(HIGH);
  }
}

Your second reply seems to indicate a different problem entirely from your first description. Are you asking how to debounce a switch, or how to send serial data once only for a given input?

Perehama:
Your second reply seems to indicate a different problem entirely from your first description. Are you asking how to debounce a switch, or how to send serial data once only for a given input?

I don't think what I described is actually a debounce issue. I think it's reading the state of each range of motion of the switch. Might just be my type of switch. Btut yes I want serial data for only a given input, once.

ardoyouknowwhoiam:
I don't think what I described is actually a debounce issue. I think it's reading the state of each range of motion of the switch. Might just be my type of switch. Btut yes I want serial data for only a given input, once.

I presented code to address printing once.

Perehama:
I presented code to address printing once.

I just tested that code now, a few things: I am getting a steady LOW reading once from initial state, but if I engage a HIGH state clicking down and holding it repeats over and over. How would i make that display once per click down?

ardoyouknowwhoiam:
I just tested that code now, a few things: I am getting a steady LOW reading once from initial state, but if I engage a HIGH state clicking down and holding it repeats over and over. How would i make that display once per click down?

Do you mean "Low" as I wrote when the digitalRead(switchPin) == HIGH?
Do you have a pull-up resistor on the input pin?
Does the button make contact with GND?
Did you uncomment the other Serial.print?

Perehama:
Do you mean "Low" as I wrote when the digitalRead(switchPin) == HIGH?
Do you have a pull-up resistor on the input pin?
Does the button make contact with GND?
Did you uncomment the other Serial.print?

Low as in the text in the serial monitor.
I did uncomment it, that's how I got the constant "HIGH" numeric reading.

Yes 10k on the switch com to ground and PWM from com to Arduino.

ardoyouknowwhoiam:
Low as in the text in the serial monitor.
I did uncomment it, that's how I got the constant "HIGH" numeric reading.

Yes 10k on the switch com to ground and PWM from com to Arduino.

Look at how I did the high side, make a flag variable with inverse logic and add those lines for the low side. Or, move the logic to the low side if you only want the one output and comment out the high side.

Perehama:
Look at how I did the high side, make a flag variable with inverse logic and add those lines for the low side. Or, move the logic to the low side if you only want the one output and comment out the high side.

I would like to have both sides displayed once per state change. I will give your method a go and post back with the results :wink:

ardoyouknowwhoiam:
I would like to have both sides displayed once per state change. I will give your method a go and post back with the results :wink:

What happens if your switch has a lot of bounce? How are you debouncing the push button? I realize right now, your simply addressing the "Do once" part, but at some point you might realize that when you push a button, it makes and breaks contact several times on the down stroke, and again on the up stroke.

Perehama:
What happens if your switch has a lot of bounce? How are you debouncing the push button? I realize right now, your simply addressing the "Do once" part, but at some point you might realize that when you push a button, it makes and breaks contact several times on the down stroke, and again on the up stroke.

For this particular switch I am okay with bouncing. I am simply using it to monitor a state, there is no actuation (other than LED/GUI visual) taking place as a result of this particular switch. For my other switches I've debounced using state, last state, debounce delay, etc. method.

ardoyouknowwhoiam:
I've played with the example sketch but it seems not to work with my switch. It's giving me on and off in the same cycle of clicking my switch. When I press down it reads one state and when I release it reads another state. Doesn't seem to work for me.

Not just that but the example code has a delay in there which is fundamental to the code. I can't have delays in my code unfortunately, it messes with my loops.

I thought this was the desired behavior, to print the state once for each change. So when the state changes to pressed it prints once and when it is unpressed it prints once.

If that is not the desired behavior then can you please define EXACTLY what you want this switch to do?

Delta_G:
I thought this was the desired behavior, to print the state once for each change. So when the state changes to pressed it prints once and when it is unpressed it prints once.

If that is not the desired behavior then can you please define EXACTLY what you want this switch to do?

The behaviour is acceptable however a delay is fundamentally incompatible with what I want to do. I can't have a 50ms delay in my loop.

Perehama:
Look at how I did the high side, make a flag variable with inverse logic and add those lines for the low side. Or, move the logic to the low side if you only want the one output and comment out the high side.

I can't seem to make this work.Do you have any pointers?

I had posted this sample code (state machine) in another thread to represent what happens with the bouncing. There is no delay in that code. all states are depicted so you could combine this with some of the ideas above depending on your needs


If you were to depict what states you go through when you press the button and then release the button, this could look like this:

You start from being idle, you receive a press (so pin goes LOW because of the input pull-up), you enter a theoretical bouncing state for a certain time. If the pin goes back HIGH after that time it's a glitch, you can't consider the button was really pressed, but if the pin is still LOW, then you can consider the button to be pressed.
Then same goes upon release

The resulting code for this small state machine (with everything coded so that it's easy to read, no optimization / code factoring) could be:

enum : byte {BUTTON_IDLE, BUTTON_BOUCING_DOWN, BUTTON_PRESSED, BUTTON_BOUNCING_UP} buttonState;
enum buttonAction_t : byte {BUTTON_NOCHANGE, BUTTON_DOWN, BUTTON_GLITCH_DOWN, BUTTON_DOWN_CONFIRMED, BUTTON_UP, BUTTON_GLITCH_UP, BUTTON_UP_CONFIRMED};

const byte buttonPin = 7;
const unsigned long buttonTimeOut = 15; // ms

buttonAction_t testButton()
{
  static unsigned long startTime = 0;
  buttonAction_t result = BUTTON_NOCHANGE;

  byte bState = digitalRead(buttonPin);

  switch (buttonState) {

    case BUTTON_IDLE:
      if (bState == LOW) {
        startTime = millis();
        buttonState = BUTTON_BOUCING_DOWN;
        result = BUTTON_DOWN;
      }
      break;

    case BUTTON_BOUCING_DOWN:
      if (millis() - startTime >= buttonTimeOut) {
        if (bState == LOW) {
          result = BUTTON_DOWN_CONFIRMED;
          buttonState = BUTTON_PRESSED;
        } else {
          result = BUTTON_GLITCH_DOWN;
          buttonState = BUTTON_IDLE;
        }
      }
      break;

    case BUTTON_PRESSED:
      if (bState == HIGH) {
        startTime = millis();
        buttonState = BUTTON_BOUNCING_UP;
        result = BUTTON_UP;
      }
      break;

    case BUTTON_BOUNCING_UP:
      if (millis() - startTime >= buttonTimeOut) {
        if (bState == LOW) {
          result = BUTTON_GLITCH_UP;
          buttonState = BUTTON_PRESSED;
        } else {
          result = BUTTON_UP_CONFIRMED;
          buttonState = BUTTON_IDLE;
        }
      }
      break;
  }
  return result;
}

void setup()
{
  Serial.begin(115200);
  pinMode(buttonPin, INPUT_PULLUP);
}

void loop()
{
  buttonAction_t buttonState = testButton();
  switch (buttonState) {
    case BUTTON_NOCHANGE: break;
    case BUTTON_DOWN: Serial.println(F("BUTTON_DOWN")); break;
    case BUTTON_GLITCH_DOWN: Serial.println(F("BUTTON_GLITCH_DOWN")); break;
    case BUTTON_DOWN_CONFIRMED: Serial.println(F("BUTTON_DOWN_CONFIRMED")); break;
    case BUTTON_UP: Serial.println(F("BUTTON_UP")); break;
    case BUTTON_GLITCH_UP: Serial.println(F("BUTTON_GLITCH_UP")); break;
    case BUTTON_UP_CONFIRMED: Serial.println(F("BUTTON_UP_CONFIRMED")); break;
  }
}

ardoyouknowwhoiam:
The behaviour is acceptable however a delay is fundamentally incompatible with what I want to do. I can't have a 50ms delay in my loop.

then take the delay out. It's just there in the example. It's not the point of the example. The point of the example is keeping track of the last state of the button in a variable so you can tell if it changed or not.

Delta_G:
then take the delay out. It's just there in the example. It's not the point of the example. The point of the example is keeping track of the last state of the button in a variable so you can tell if it changed or not.

Yeah but if you take it out then you get a flicker in the LED behaviour which then requires a debounce to correct. I would rather not have to correct that behaviour in order to get a Serial.print for one value. It doesn't seem efficient. Maybe i'm expecting too much for little effort, not sure but there must be a sleek solution to this.