Thermal Printer Help

Hey everyone.

I'm doing a project for my engineering class and I'm at a standstill here. I have my Arduino Uno, a monochrome LCD (https://www.sparkfun.com/products/255), three momentary switches and a thermal printer (https://www.sparkfun.com/products/10438).

Basically with two of the pushbuttons it's supposed to add 1 to my can or bottle value and display it on the LCD. If I press the third button, I want it to print out what I have written in the code.

One issue I have is that I have to hold down the button for a while before it's registered. I know it's because it's in the beginning of the loop but not sure how to have it constantly checking this.
The second problem is that my printer is not printing when I press the third button. Originally I had "if (val3 == LOW)" instead of my "do...while" command. Not sure why it's not getting the command to print. I've checked my wiring numerous times to try and see if there's something wrong there but it should all be working in that aspect.

#include <LiquidCrystal.h>
#include <SoftwareSerial.h>

LiquidCrystal lcd(7, 8, 9, 10, 11, 12);
SoftwareSerial Thermal(2, 3);

int heatTime = 150;
int heatInterval = 255;
char printDensity = 15;
char printBreakTime = 15;
int ButtonPin1 = 4;
int ButtonPin2 = 5;
int ButtonPin3 = 6;
int Can = 0;
int Bottle = 0;
int val1 = 0;
int val2 = 0;
int val3 = 0;

void setup()
{
  Serial.begin(57600);
  Thermal.begin(19200);
  initPrinter();
  lcd.begin(16,2);
  lcd.clear();
  pinMode(ButtonPin1, INPUT);
  pinMode(ButtonPin2, INPUT);
  pinMode(ButtonPin3, INPUT);
}

void initPrinter()
{
  Thermal.write(27);
  Thermal.write(55);
  Thermal.write(7);
  Thermal.write(heatTime);
  Thermal.write(heatInterval);
  Thermal.write(18);
  Thermal.write(35);
  int printSetting = (printDensity<<4) | printBreakTime;
  Thermal.write(printSetting);
  Serial.println();
  Serial.println("Print ready");
}

void loop()
{
  val1 = digitalRead(ButtonPin1);
  val2 = digitalRead(ButtonPin2);
  val3 = digitalRead(ButtonPin3);
  
  if (val1 == LOW)
{
  Can += 1;
  delay(200);
}

  if (val2 == LOW)
{
  Bottle += 1;
  delay(200);
}

{
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("Current Cans:");
  lcd.print(Can);
 delay(3000);
 lcd.clear();
 lcd.home();
  lcd.print("Current Bottles:");
  lcd.setCursor(0,1);
  lcd.print(Bottle);
  delay(3000);
}


do
{ 
  Thermal.println("Thank you for recycling!");
  Thermal.write(10);
  Thermal.println("Voucher is good for one two-way trip");
  Thermal.write(10);
  Thermal.println("on any TriMet public system");
  Thermal.write(10);
  Thermal.print("Number of cans:");
  Thermal.println(Can);
  Thermal.write(10);
  Thermal.print("Number of bottles:");
  Thermal.println(Bottle);
  Thermal.write(10);
  Thermal.write(10);
  Thermal.write(10);
} while (val3 == LOW);
}

Any help would be greatly appreciated. Thank you.

moderator update: added code tags ==> #button above the smileys

One issue I have is that I have to hold down the button for a while before it's registered. I know it's because it's in the beginning of the loop but not sure how to have it constantly checking this.

The buttons are being checked each time through the loop() function but that is not happening as fast as it could because of your use of the delay() function in your program. Until the delay() is over the program stops and can do nothing else.

There is an example in the IDE called BlinkWithoutDelay that shows how to use the millis() function for timing. Basically you note the start time of an action and check each time through loop() whether the required period has elapsed. If so, act on it, if not do something else like reading inputs and acting on them.

  {
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("Current Cans:");
    lcd.print(Can);
    delay(3000);
    lcd.clear();
    lcd.home();
    lcd.print("Current Bottles:");
    lcd.setCursor(0,1);
    lcd.print(Bottle);
    delay(3000);
  }

This is the section of code causing most of your problem in responding to button presses although you have other unnecessary delays elsewhere too. Why do you need the delays in this section anyway and why is it enclosed in braces ?

Why the delays after updating the bottle and can counts ?

Do you want to increment or decrement the counter when the switch IS pressed? Or when it BECOMES pressed?

The code does the former. The state change detection example illustrates the latter.

Why do you need the delays in this section anyway and why is it enclosed in braces ?

Why the delays after updating the bottle and can counts ?

So the delays are just simply to let the LCD screen show that reading (Like "Current cans: 10") for a little while instead of instantly switching to the next screen. As far as why it's in braces, I thought it needed to be. I'm very new to programming and that's one of the things I struggle with the most in this coding is trying to figure out when braces are needed or not.

Do you want to increment or decrement the counter when the switch IS pressed? Or when it BECOMES pressed?

I'm wanting it to change when it IS pressed so I will check out that state change code and give that a shot.

To anyone else, I still need help with the printer aspect of it. I'm gonna mess with my circuitry again today and see check if it's something wrong there because it seems like it should be working code-wise? (Please correct me if I'm wrong)

I'm wanting it to change when it IS pressed

So, if you press and hold the switch, you want the count to increment over and over? That's what reading IS pressed will do. Determining when the switch BECOMES pressed (is now; was not last time) means that you increment once, regardless of how long you hold the switch down.

So, if you press and hold the switch, you want the count to increment over and over?

Ok thanks for the clarification. No that is not what I was looking for. I want to press it once and it will increment one time regardless of time.

So, you want to increment when the switch BECOMES pressed. That is what the state change detection example illustrates.

Ok great. I will change the code for that. Thank you.

Any clue if that'll help my printing issue at all?

Any clue if that'll help my printing issue at all?

Not a bit.

do
{ 
  Thermal.println("Thank you for recycling!");
  Thermal.write(10);
  Thermal.println("Voucher is good for one two-way trip");
  Thermal.write(10);
  Thermal.println("on any TriMet public system");
  Thermal.write(10);
  Thermal.print("Number of cans:");
  Thermal.println(Can);
  Thermal.write(10);
  Thermal.print("Number of bottles:");
  Thermal.println(Bottle);
  Thermal.write(10);
  Thermal.write(10);
  Thermal.write(10);
} while (val3 == LOW);

First, I suggest that you get rid of the do/while statement. It is almost always misused, as it appears to be here. The action happens at least once, regardless of the termination condition. That is almost always not what you want to do.

The termination condition is not affected by anything that happens in the do/while loop, so, once the loop starts, it will never terminate.

First, I suggest that you get rid of the do/while statement. It is almost always misused, as it appears to be here.

Yeah originally I had it as:

if (val3 == LOW)
{
  Thermal.println("Thank you for recycling!");
  Thermal.write(10);
  Thermal.println("Voucher is good for one two-way trip");
  Thermal.write(10);
  Thermal.println("on any TriMet public system");
  Thermal.write(10);
  Thermal.print("Number of cans:");
  Thermal.println(Can);
  Thermal.write(10);
  Thermal.print("Number of bottles:");
  Thermal.println(Bottle);
  Thermal.write(10);
  Thermal.write(10);
  Thermal.write(10);
}

This wasn't working for me so I gave the do...while a shot to see if it would help things any. I'm gonna be changing the button to the state change code instead of how I have it set up now because I only want it to print once per button press. The problem is getting it to print period though... I have an example code that I copied pretty much verbatim. I only changed what I wanted it to say and added a button so one of those two things must be what's causing my problem.

Forget your main program for now. Does the printer work if you run the sample program from the page you linked to ?

Does the printer work if you run the sample program from the page you linked to ?

Yes I've gotten the printer to run just fine using the example program. I changed the words a bit from the original but it still printed just fine using the following code.

/*
 Example 38.1 - Sparkfun Thermal Printer Test (COM-10438)
 http://tronixstuff.com/tutorials > chapter 38
 Based on code by Nathan Seidle of Spark Fun Electronics 2011
*/
#include <SoftwareSerial.h>
SoftwareSerial Thermal(2, 3);
int heatTime = 150;
int heatInterval = 255;
char printDensity = 15; 
char printBreakTime = 15;
void setup() 
{
 Serial.begin(57600); // for debug info to serial monitor
 Thermal.begin(19200); // to write to our new printer
 initPrinter();
}
void initPrinter()
{
 //Modify the print speed and heat
 Thermal.write(27);
 Thermal.write(55);
 Thermal.write(7); //Default 64 dots = 8*('7'+1)
 Thermal.write(heatTime); //Default 80 or 800us
 Thermal.write(heatInterval); //Default 2 or 20us
 //Modify the print density and timeout
 Thermal.write(18);
 Thermal.write(35);
 int printSetting = (printDensity<<4) | printBreakTime;
 Thermal.write(printSetting); //Combination of printDensity and printBreakTime
 Serial.println();
 Serial.println("Printer ready"); 
}
void loop()
{
 Thermal.println(" Thank you ");
 Thermal.write(10); //Sends the LF to the printer, advances the paper
 Thermal.println(" Good For One ");
 Thermal.println(" Two-Way Trip");
 Thermal.write(10);
 Thermal.write(10); 
 do { } while (1>0);
}

Well, I guess I'll have to retract that last reply. I just tried to upload simply that last program again to see if it would print it out and alas there was nothing printed. So I've done something wrong. I had it working before but at least I have a little bit of direction now.

I have the RX plugged into Pin 2 Tx into PIN 3 and the other to ground which is really the only wiring (besides the external power supply coming from my 9v AC adapter) so not sure what's not working here. I'll keep looking to see if I can find out what the problem is...

Alright well this is a bit frustrating but I got it going. Either the printer is labeled wrong or the example I was using gave me wrong info bc I had the TX and RX backwards. I switched them and the code is doing as I want.... Mostly..... The buttons are still quite slow to respond. I tried using the example of the blink without delay and here's what I have, didn't seem to make much difference.

#include <LiquidCrystal.h>
#include <SoftwareSerial.h>

LiquidCrystal lcd(7, 8, 9, 10, 11, 12);
SoftwareSerial Thermal(2, 3);

//Constats
const int heatTime = 150;
const int heatInterval = 255;
const char printDensity = 15;
const char printBreakTime = 15;
const int ButtonPin1 = 4;
const int ButtonPin2 = 5;
const int ButtonPin3 = 6;

// Variables
int Can = 0;
int Bottle = 0;
int ButtonState1 = 0;              //Can Button
int ButtonState2 = 0;             //Bottle Button
int ButtonState3 = 0;             //Printer Button
int LastButtonState1 = 0;
int LastButtonState2 = 0;
int LastButtonState3 = 0;
long previousMillis = 0;          
long interval = 2000;            //interval at which to check buttons 

void setup()
{
  Serial.begin(57600);
  Thermal.begin(19200);
  initPrinter();
  lcd.begin(16,2);
  lcd.clear();
  pinMode(ButtonPin1, INPUT);
  pinMode(ButtonPin2, INPUT);
  pinMode(ButtonPin3, INPUT);
}

void initPrinter()
{
  Thermal.write(27);
  Thermal.write(55);
  Thermal.write(7);
  Thermal.write(heatTime);
  Thermal.write(heatInterval);
  Thermal.write(18);
  Thermal.write(35);
  int printSetting = (printDensity<<4) | printBreakTime;
  Thermal.write(printSetting);
  Serial.println();
  Serial.println("Print ready");
}

void loop()
{
  ButtonState1 = digitalRead(ButtonPin1);
  ButtonState2 = digitalRead(ButtonPin2);
  ButtonState3 = digitalRead(ButtonPin3);
  
  if (ButtonState1 != LastButtonState1 ){
     if (ButtonState1 == HIGH){
  Can += 1;
}}

LastButtonState1 = ButtonState1;

  if (ButtonState2 != LastButtonState2 ){
     if (ButtonState2 == HIGH){
  Bottle += 1;
}}

LastButtonState2 = ButtonState2;

  if (ButtonState3 != LastButtonState3){
    if (ButtonState3 == HIGH)
{
  Thermal.println("Thank you for recycling!");
  Thermal.write(10);
  Thermal.println("Voucher is good for one two-way trip");
  Thermal.write(10);
  Thermal.println("on any TriMet public system");
  Thermal.write(10);
  Thermal.print("Number of cans:");
  Thermal.println(Can);
  Thermal.write(10);
  Thermal.print("Number of bottles:");
  Thermal.println(Bottle);
  Thermal.write(10);
  Thermal.write(10);
  Thermal.write(10);
}

LastButtonState3 == ButtonState3;
}


unsigned long currentMillis = millis();

if (currentMillis - previousMillis > interval) {
  previousMillis = currentMillis;
  
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("Current Cans:");
  lcd.print(Can);
  delay(2000);
 lcd.clear();
 lcd.home();
  lcd.print("Current Bottles:");
  lcd.setCursor(0,1);
  lcd.print(Bottle);
  delay(2000);
}}

Either the printer is labeled wrong or the example I was using gave me wrong info bc I had the TX and RX backwards.

It's a matter of perspective, probably. Is the device receiving data, or is the other end receiving data, from the RX pin?

How are the switches wired? I'm guessing that the pins are floating, so most of the time, you are not reading them correctly.

Use the internal pullup resistors (INPUT_PULLUP, not INPUT), and connect one leg to ground and one to the digital pin. LOW will mean pressed.

What are those delays still doing in there ?
Another thing. All of your timing variables need to be unsigned longs to ensure that the elapsed time calculations continue to work.

How are the switches wired?

one leg goes into the breadboard's power, which is connected to the 5v on the arduino. The other leg goes into row 1 of the breadboard. Row 1 also has a 10k resistor going to ground and a pin going to the arduino's 4 pin (just one for example, the others are all similar).

What are those delays still doing in there ?

I tried taking the delays out completely and the LCD would just sit there showing "Current Bottles: 0" It wouldn't rotate between that one and "Current cans:"

Rewire your switches. Get rid of the external resistor. One leg to ground. One leg to the pin you want to read. Turn on the internal pullup resistor. LOW is pressed. HIGH is not pressed.

Get rid of the delays.

Fix this crap:

}}

ONE } per line. NOTHING else on the same line. Use Tools + Auto Format.

Post your code again, with a description of what happens when you press one switch (and rell us which one that was).

So the LCD screen constantly shows ""Current Bottles: " When I press the button (Button2) for the bottles it went to 3, pressed again, went to 6, pressed again went 7,8,9 and then 16.
Button1 which is for the cans, there's no telling what it's doing because the display won't show anything but the bottle count.
Button3 for printing will not make the printer run.

#include <LiquidCrystal.h>
#include <SoftwareSerial.h>

LiquidCrystal lcd(7, 8, 9, 10, 11, 12);
SoftwareSerial Thermal(2, 3);

//Constats
const int heatTime = 150;
const int heatInterval = 255;
const char printDensity = 15;
const char printBreakTime = 15;
char barCode[]={ 
  '9','2','3','0','5','6','4','8','9','8','4','4'};
int zero=0;
const int ButtonPin1 = 4;
const int ButtonPin2 = 5;
const int ButtonPin3 = 6;

// Variables
int Can = 0;
int Bottle = 0;
int ButtonState1 = 0;              //Can Button
int ButtonState2 = 0;             //Bottle Button
int ButtonState3 = 0;             //Printer Button
int LastButtonState1 = 0;
int LastButtonState2 = 0;
int LastButtonState3 = 0;
long previousMillis = 0;          
long interval = 2000;            //interval at which to check buttons 

void setup()
{
  Serial.begin(57600);
  Thermal.begin(19200);
  initPrinter();
  lcd.begin(16,2);
  lcd.clear();
  pinMode(ButtonPin1, INPUT_PULLUP);
  pinMode(ButtonPin2, INPUT_PULLUP);
  pinMode(ButtonPin3, INPUT_PULLUP);
}

void initPrinter()
{
  Thermal.write(27);
  Thermal.write(55);
  Thermal.write(7);
  Thermal.write(heatTime);
  Thermal.write(heatInterval);
  Thermal.write(18);
  Thermal.write(35);
  int printSetting = (printDensity<<4) | printBreakTime;
  Thermal.write(printSetting);
  Serial.println();
  Serial.println("Print ready");
}
void printBarcode(char zz[])
{
  Thermal.write(29); //GS
  Thermal.write(107); //k
  Thermal.write(zero); //m = 0
  for (int z=0; z<12; z++)
  {
    Thermal.write(zz[z]);
  }
  Thermal.write(zero); // bar code terminator
  delay(3000); // necessary delay
  Thermal.write(10); 
  Thermal.write(10); 
  Thermal.write(10); 
}

void loop()
{
  ButtonState1 = digitalRead(ButtonPin1);
  ButtonState2 = digitalRead(ButtonPin2);
  ButtonState3 = digitalRead(ButtonPin3);

  if (ButtonState1 != LastButtonState1 ){
    if (ButtonState1 == LOW){
      Can += 1;
    }
  }

  LastButtonState1 = ButtonState1;

  if (ButtonState2 != LastButtonState2 ){
    if (ButtonState2 == LOW){
      Bottle += 1;
    }
  }

  LastButtonState2 = ButtonState2;

  if (ButtonState3 != LastButtonState3){
    if (ButtonState3 == LOW)
    {
      Thermal.println("Thank you for recycling!");
      Thermal.write(10);
      Thermal.println("Voucher is good for one two-way trip");
      Thermal.write(10);
      Thermal.println("on any TriMet public system");
      Thermal.write(10);
      Thermal.print("Number of cans:");
      Thermal.println(Can);
      Thermal.write(10);
      Thermal.print("Number of bottles:");
      Thermal.println(Bottle);
      Thermal.write(10);
      Thermal.write(10);
      Thermal.write(10);
      printBarcode(barCode);
    }

    LastButtonState3 == ButtonState3;
  }


  unsigned long currentMillis = millis();

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

    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("Current Cans:");
    lcd.print(Can);
    lcd.clear();
    lcd.home();
    lcd.print("Current Bottles:");
    lcd.setCursor(0,1);
    lcd.print(Bottle);
  }
}
int ButtonState1 = 0;              //Can Button
int ButtonState2 = 0;             //Bottle Button
int ButtonState3 = 0;             //Printer Button

I have to wonder why the names don't match the comments.

    LastButtonState3 == ButtonState3;

Really? What if they are equal?

You have too much going on in this code. Put the printer in a drawer, with the LCD, until you accurately read the switch states. Show a schematic of the wiring.