[SOLVED] Switch Case Makes Receipt Printer Print Continuously

Hi friends!

I have taken an intro-level electronics class in college, so I think it's fair to say that I am still new to all of this.

For my project, I want my receipt printer to react to a button press. When the button is pressed and released, I want it to spit out a portion of a text. When it's pressed again, I want it to spit out the portion after. and onward until it loops back to the beginning.

I was able to get the printer to react to the button, but what happens is that it will continuously print out that specific section of the text until I press the button. Then it does the same for the next case. What I want to happen is that it prints out the text once and waits until I press again to move on.

I think I understand what's wrong with my code, but I am unsure of how to fix it: the code is constantly referring to its corresponding case and is looping that case until it can move on to the next. I tried to put the printer to sleep at the end of each case, but that didn't work.

I did try looking for the solution online, but I couldn't figure it out. Maybe it's because I don't have the vocabulary to search up my issue yet or maybe there wasn't an answer.

#include "Adafruit_Thermal.h"
#include "SoftwareSerial.h"
#define TX_PIN 6                                  // Arduino transmit  YELLOW WIRE  labeled RX on printer
#define RX_PIN 5                                  // Arduino receive   GREEN WIRE   labeled TX on printer

SoftwareSerial mySerial(RX_PIN, TX_PIN);          // Declare SoftwareSerial obj
Adafruit_Thermal printer(&mySerial, 4);          // Pass addr to printer constructor

const int buttonPin = 3;
int state = 0;                                    //integer to hold current state
int old = 0;                                      //integer to hold last state
int buttonPoll = 0;                               //integer to hold button state
int buttonState = 0;                              // variable for reading the pushbutton status

void setup() {

  pinMode(buttonPin, INPUT);                        // initialize the pushbutton pin as an input:

  mySerial.begin(19200);                            // Initialize SoftwareSerial
  printer.begin();                                  // Init printer (same regardless of serial type)
}

void loop() {
  buttonState = digitalRead(buttonPin);
  printer.justify('R');
  if (buttonState == HIGH) {
    delay(50);
    buttonState = digitalRead(buttonPin);
    if (buttonState == LOW) {
      state = old + 1;
    }
  }
  else {
    delay(100);
  }

  switch (state) {
    case 1:
      printer.println(F("case 1"));
      printer.feed(2);
      // printer.sleep();      // Tell printer to sleep
      //  delay(3000L);         // Sleep for 3 seconds

      printer.setDefault(); // Restore printer to defaults
      old = state;
      break;

    case 2:

      printer.println(F("case 2"));
      printer.feed(2);
      // printer.sleep();      // Tell printer to sleep
      //   delay(3000L);         // Sleep for 3 seconds

      printer.setDefault(); // Restore printer to defaults
      old = state;
      break;

    case 3:

      printer.println(F("case 3"));
      printer.feed(2);
      // printer.sleep();      // Tell printer to sleep
      //   delay(3000L);         // Sleep for 3 seconds

      printer.setDefault(); // Restore printer to defaults
      old = state;
      break;

      delay(700);
  }
}

Thanks in advance for the help! It is much appreciated! :slight_smile:

Move your switch statement under this line:

     state = old + 1;

In general if you want to do something once, you would use a flag (boolean variable) to mean have or have not printed.

Print the set the flag to not print again.

Clear the flag when you transition states.

Also, old doesn't look like it is getting reset to wrap around.

unsigned char printed;  // did we print this case yet

You could clear a print flag when you

state = old + 1;
printed = false;

then in each case

if (printed == false) {
     // do the print
    printed =true;
}

HTH

a7

1 Like

Here is the updated code. Did I do this right?

What it's doing now is spitting out all three cases right when I upload the code onto the Arduino. It's not listening to the button anymore.

I also added a default at the bottom but I don't think it's doing anything.




#include "Adafruit_Thermal.h"
#include "SoftwareSerial.h"
#define TX_PIN 6                                  // Arduino transmit  YELLOW WIRE  labeled RX on printer
#define RX_PIN 5                                  // Arduino receive   GREEN WIRE   labeled TX on printer

SoftwareSerial mySerial(RX_PIN, TX_PIN);          // Declare SoftwareSerial obj
Adafruit_Thermal printer(&mySerial, 4);          // Pass addr to printer constructor

const int buttonPin = 3;
int state = 0;                                    //integer to hold current state
int old = 0;                                      //integer to hold last state
int buttonPoll = 0;                               //integer to hold button state
int buttonState = 0;                              // variable for reading the pushbutton status
unsigned char printed;  // did we print this case yet

void setup() {

  pinMode(buttonPin, INPUT);                        // initialize the pushbutton pin as an input:

  mySerial.begin(19200);                            // Initialize SoftwareSerial
  printer.begin();                                  // Init printer (same regardless of serial type)
}

void loop() {
  buttonState = digitalRead(buttonPin);
  if (buttonState == HIGH) {
    delay(50);
    buttonState = digitalRead(buttonPin);
  }   if  (buttonState == LOW);
  {
    state = old + 1;
    printed = false;
  }


  switch (state) {
    case 1:
    { if (printed == false) {
          printer.println(F("case 1"));
          old = state;
          printed = true;
          break;
        }
      }

    case 2:
    { if (printed == false) {
          printer.println(F("case 2"));
          old = state;
          printed = true;
          break;
        }
      }

    case 3:
    { if (printed == false) {
          printer.println(F("case 3"));
          old = state;
          printed = true;
          break;
        }
      }
    default:
      printed == false;

      delay(700);
  }
}

.
.
I should note that I'm partially basing my code on this.
From LearnElectronics on Youtube:

#define button 3                      //Push button on D3
#define redLED 5                      //red LED on D5
#define greenLED 6                  //green LED on D6
#define yellowLED 7                 //yellow LED on D7

int state = 0;
//integer to hold current state
int old = 0;
//integer to hold last state
int buttonPoll = 0;
//integer to hold button state

void setup() {
  pinMode(button, INPUT_PULLUP);
  //button as input
  pinMode(redLED, OUTPUT);
  //LEDs as output
  pinMode(greenLED, OUTPUT);
  pinMode(yellowLED, OUTPUT);

  digitalWrite(redLED, LOW);
  //set initial state as off
  digitalWrite(greenLED, LOW);
  //set initial state as off
  digitalWrite(yellowLED, LOW);
  //set initial state as off
}

void loop() {


  buttonPoll = digitalRead(button);
  if (buttonPoll == 1) {
    delay(50);
    buttonPoll = digitalRead(button);
    if (buttonPoll == 0) {
      state = old + 1;
    }
  }
  else {
    delay(100);
  }
  switch (state) {
    case 1:
      digitalWrite(redLED, HIGH);
      digitalWrite(greenLED, LOW);
      digitalWrite(yellowLED, LOW);
      old = state;
      break;
    case 2:
      digitalWrite(redLED, LOW);
      digitalWrite(greenLED, HIGH);
      digitalWrite(yellowLED, LOW);
      old = state;
      break;
    case 3:
      digitalWrite(redLED, LOW);
      digitalWrite(greenLED, LOW);
      digitalWrite(yellowLED, HIGH);
      old = state;
      break;
    default:
      digitalWrite(redLED, LOW);
      digitalWrite(greenLED, LOW);
      digitalWrite(yellowLED, HIGH);
      old = 0;
      break;
  }
}

I can't study all your code just now, but the line I quote above is a complete if statement.

The stuff after that is executed unconditionally.

Review the syntax of the if statement. Hint: look at that semicolon.

You may have other things like that that aren't doing what you think.

a7

I would suggest you initialise printed to true in setup().

I think your intention at the start of loop() is to detect when your pushbutton is released. I would add a new global variable at the top of your sketch:

int prevButtonState = 0;

In your loop(), I would suggest something like:

buttonState = digitalRead(buttonPin);
if (buttonState != prevButtonState) {
  // button has been pressed or released
  if (buttonState == LOW) {
    // move to the next state
    state++;
    printed = false;
  }
}
// remember the button state for the next time
prevButtonState = buttonState;

Your switch statement then becomes something like:

switch (state) {
    case 1:
      if (printed == false) {
        printer.println(F("case 1"));
        printed = true;
      }
      break;
    case 2:
      if (printed == false) {
        printer.println(F("case 2"));
        printed = true;
      }
      break;
    case 3:
      if (printed == false) {
        printer.println(F("case 3"));
        printed = true;
      }
      break;
    default:
      // reset back to state 0
      state = 0;
      printed = true;

It's untested as i'm on a tablet at the moment, butI hope that helps/works. :grinning:

EDIT: I couldn't see how you've wired up your button. I assume you've wired it between pin 3 and 0v. If you have, then you might want to change your pinMode in setup() to:

pinMode(buttonPin, INPUT_PULLUP);

That should activate the internal pullup resistor on that pin. The pin will read high when not pressed.

Agree. Missing I think is any of the delay() seen in @mantismei's code which had the roll of debouncing the switch.

The simplest debouncing just ignores the switch after detecting a state change, so the switch reacts instant but not again until the debounce interval is passed:

const unsigned char buttonPin = 7;

void setup() {
  Serial.begin(115200);
  Serial.println("Hello\n");

  pinMode(buttonPin, INPUT_PULLUP);
}

# define DEBOUNCE 50    // milliseconds to ignore switch
unsigned char buttonState, prevButtonState;
unsigned long lastButtonTime;

unsigned char state;
unsigned char printed;

void loop() {

  unsigned long now = millis();

  if (now - lastButtonTime > DEBOUNCE) {     // switch still hot from last time? ignore it.

    buttonState = digitalRead(buttonPin);
    if (buttonState != prevButtonState) {
      // button has been pressed or released
      if (buttonState == LOW) {
        // move to the next state
        state++;
        if (state == 4) state = 0;    // reset
        printed = false;
      }
         // remember the button state and time
      prevButtonState = buttonState;
      lastButtonTime = now; 
    }
  }
  
  if (!printed) {
    Serial.println(state);
    printed = true;
  }
}

Of course I did:

The OP may want to do the cases just once, or only print something once and still do the case over and over as the loop(), well, loops. It is not clear which is the problem.

HTH

a7

1 Like

thank you both for the help!

I was able to get it to work with @markd833 's edits :slight_smile:
As for the delay I had included, for some reason, I thought it would act as a good stabilizer. It was really something that I had when it would print non-stop to make it more manageable. So apologies for that! The code works without the debouncing edits for my project, but it is much appreciated, @alto777

These two days have been my first on the Arduino forum and it's really nice knowing there is a community of people that dedicate their time to helping folks like me

Thanks again!

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.