[SOLVED] Thermal Printer prints weird letters at the beginning

My recent quarantine project is an insult printer. So far everything works except that sometimes it prints the first letter weird (N@Ç). I know that I didn't use the smartest solution for my random char printing, but since my Arduino skills are very much at the beginning, I try to experiment and increase them.

It doesn't matter how long those strings are. It results always the same, even with one single word.

Here is a picture how the prints look like:

My current setup:

Arduino Uno R3
Thermal Printer with TTL
PushButton

  • Powered by 9V DC Supply to VIn and Gnd on Arduino plus parallel to the printer.
  • PushButton also has a 1kOhm resistor from pin 10 to Gnd.

Here is my code:

#include "SoftwareSerial.h"
#include "Adafruit_Thermal.h"

int RX_PIN = 2; // green wire
int TX_PIN = 3; // yellow wire
const int Taster = 10;

int buttonState = 0;     // variable for reading the button status
int currState = 0;           // set variables to hold the state of the button
int prevState = 0;

SoftwareSerial mySerial(RX_PIN, TX_PIN); // Declare SoftwareSerial obj first
Adafruit_Thermal printer(&mySerial);

void setup() {
  
pinMode(10, INPUT);  

}

void loop() {

currState = digitalRead(10);

  if (currState == HIGH) {
    printInsult();
   }
    else {
    printer.sleep();  
    }
    
}


void printInsult(){

char* myInsults[16]={
  "Jeder hat das Recht \n haesslich zu sein, aber \n du uebertreibst es wirklich!",
  "Dein Gesicht auf einer \n Briefmarke und die Post \n geht pleite.",
  "Du hinterlaesst eine Luecke \n die dich vollstaendig ersetzt.",
  "Du verschoenerst jeden \n Raum wenn du gehst!",
  "Wow, du hast irgendwie \n das gewisse Nichts!",
  "Erzaehl mal, hast du dich \n absichtlich so angezogen?",
  "Die YouTube Kommentare \n ueber dich sind alle wahr.",
  "Wenn ich dein Gesicht haette,\n wuerde ich lachend in eine \n Kreissaege laufen!", 
  "Das war keine Beleidigung. \n Das war eine exakte \n Beschreibung.",
  "Du bist so ueberfluessig \n wie ein Sandkasten \n in der Sahara!",
  "Wer zuletzt lacht, \n denkt zu langsam.",
  "Bitte, geh auf die \n Autobahn ein paar \n Lichter fangen.",
  "Du bist so ueberfluessig \n wie ein Fundbuero \n in Polen.",
  "Deine Mutter kocht \n Wasser nach Anleitung.",
  "Du bist einzigartig, \n jedenfalls hoffen wir \n das Alle.", 
  "Mehr habe ich von \n dir nicht erwartet...",
};

  int insultChoice = random(0, 16);

  mySerial.begin(19200);   // this is the baud rate of your printer - may vary
  //printer.begin();
  printer.justify('C');
  printer.setSize('M');
  randomSeed(analogRead(0));
  printer.println(myInsults[insultChoice]);
  printer.feed(3); //advance two lines
  printer.sleep();      // Tell printer to sleep

  delay(2000);

}

I also tried to use an example which I found on GitHub - HaterMatic. There it is called the HaterMatic and works with a coin acceptor. In that sketch it reads a random string and saves it to the buffer. Unfortunately I wasn't successful to rewrite it to my needs (remove the coin acceptor and use only one string list).

So I hope someone has at least a solution for my current issue with the weird/wrong/missing letters.

Cheers

This, for example, should be in setup():

mySerial.begin(19200) ;

Not in a function which is called multiple times during the execution of your program.

Oh, I didn't notice that I placed it there. Maybe I shouldn't do such things late nights^^ But it still doesn't solve the issue

Is that printer an Adafruit printer ?
It is possible that the unwanted characters are generated by the library as control characters for a specific printer. It is also possible that the following sequences cause the generation of unwanted characters for your specific printer:

printer.justify('C') ;
printer.setSize('M') ;

The link you supplied contains an example which does not use a library to talk to the printer.

The Adafruit example shows that a printer.begin(); initialisation goes in the setup function.

If you run the Adafruit example, does the printer print as expected?

Steve

It is a similar looking printer but not exactly from Adafruit. I guess they are using the same type of printers? At least the version 2.68 is similar.

I tried various constellations where to put the printer.begin(). It also doesn't change a thing. Sometimes, or at least some of the insults are printed correctly

The hater-matic sketch, which you mentioned, HaterMatic/HaterMatic.ino at master · sparkfun/HaterMatic · GitHub is very easy to adapt to remove the coin reader functions:

  1. In the loop(), comment out all the statements beginning with: coinInput.
  2. In the loop just after this statement: static unsigned int cashola = 0 ; add the statement: cashola = 1 ;
    This simulates a single coin and activates the function cheapStrings() ;

This will leave some relics which can be cleaned up later.
If you want to try that, and it does not work, post your complete modified sketch.

6v6gt:
The hater-matic sketch, which you mentioned, HaterMatic/Arduino/HaterMatic/HaterMatic.ino at master · sparkfun/HaterMatic · GitHub is very easy to adapt to remove the coin reader functions:

  1. In the loop(), comment out all the statements beginning with: coinInput.
  2. In the loop just after this statement: static unsigned int cashola = 0 ; add the statement: cashola = 1 ;
    This simulates a single coin and activates the function cheapStrings() ;

This will leave some relics which can be cleaned up later.
If you want to try that, and it does not work, post your complete modified sketch.

Thank you very much. That helped me a lot and I was able to successfully change it to my needs.
Here is how the more clean sketch looks now:

// First things first: let's include the files we need to make all this happen.

#include <SoftwareSerial.h> // Support for the software serial port we'll use
                            //  to talk to the printer.
#include <avr/pgmspace.h>   // Support for reading data (in this case our
                            //  insult strings) from flash memory. This eases
                            //  the burden on the much smaller SRAM, at the
                            //  cost of increased memory access time.
#include "insultStrings.h"  // Header file created for this project, which
                            // contains all the insult strings.

// Some definitions that will help us elsewhere in the code.
//  The definitions for number of insults of each time can be found in the
//  "insultStrings.h" file.

// These are pin redefinitions.
#define COIN_INPUT 7  // Serial (or pulse) input from the coin acceptor.
#define PRINTER_OUTPUT 3 // Serial output to printer
#define GET_INSULT 10 // Pushbutton input from insult request button.
#define INHIBIT 9     // Reject any further coins inserted

// Instantiate a software serial port on pins COIN_INPUT and PRINTER_OUTPUT.
//  Note that the printer communicates at 19200bps and the coin acceptor at
//  9600bps; this isn't a big deal because this is a half-duplex system, so
//  we can change between them at will, and use the INHIBIT signal to prevent
//  coins being accepted during print cycles, so we know no data will come
//  from the coin acceptor when the baud rate is wrong.
SoftwareSerial swser(COIN_INPUT, PRINTER_OUTPUT); // RX, TX

// We'll use two more defines to increase the readability of our code. The
//  preprocessor will simply replace any instance of "coinInput" or
//  "printerOutput" with "swser". Under the hood, it generates the same code,
//  but it lets us keep tabs on what we're doing more easily.
//#define coinInput swser
#define printerOutput swser

// Set up a debug mode. If we define DEBUG to be 0, that will make the
//  necessary code changes later on to route the output to the printer. If we
//  define DEBUG to be 1, it will set up the code
#define DEBUG 0
#if DEBUG == 1
#undef printerOutput
#define printerOutput Serial
#endif

void setup()
{
  // We could use the hardware serial port for communicating with our serial
  //  devices; I've chosen to leave it available for debugging. We can
  //  easily re-route all of our serial data from the printer to the hardware
  //  serial port simply by changing the DEBUG define from 0 to 1.
  Serial.begin(57600);

  pinMode(GET_INSULT, INPUT);
  
}

void loop()
{
  
  // Catch our button press and issue an insult, but only if we've paid for it!
  if (digitalRead(GET_INSULT) == HIGH)
  { 

    
    // We use the current time value to randomize our insult selection. This
    //  isn't, of course, *truly* random; a determined attacker could break it.
    //  It's good enough for this purpose; it will be random to almost everyone
    //  who uses the device.
    
    long time = millis();
    
    // We need just the low byte, and we'll only need a subset of that. Cast
    //  away the higher bytes.
    byte stringSelect = (byte)time;
    
    // This little block is needed when we're not debugging. It changes the
    //  baud rate on the soft serial port so it can talk to the printer rather
    //  than the coin acceptor, then feeds out a bit of paper before printing
    //  the insult.
    
   // #if DEBUG == 0
    printerOutput.begin(19200);
    //feed();
    //#endif
    
    insultStrings(stringSelect % NUM_L);
    
    feed();
    printerOutput.flush();
    feed();
    printerOutput.end();
    
    delay(2000);

  }
}


void insultStrings(byte stringSelect)
{
  char buffer[150];
  strcpy_P(buffer, (char*)pgm_read_word(&(insultStringList[stringSelect])));
  printerOutput.println(buffer);
}

// Feed out half an inch or so of paper, so the "receipt" is of a fair size.
void feed()
{
  printerOutput.print("\n\n");
}

#insultStrings.h

#define NUM_L 17  // Number of insults, for those who have everything.

const char ls1[] PROGMEM = "Jeder hat das Recht \nhaesslich zu sein, aber \ndu uebertreibst es wirklich!";
const char ls2[] PROGMEM = "Dein Gesicht auf einer \nBriefmarke und die Post \ngeht pleite.";
const char ls3[] PROGMEM = "Du hinterlaesst eine Luecke \ndie dich vollstaendig ersetzt.";
const char ls4[] PROGMEM = "Du verschoenerst jeden \nRaum wenn du gehst!";
const char ls5[] PROGMEM = "Wow, du hast irgendwie \ndas gewisse Nichts!";
const char ls6[] PROGMEM = "Erzaehl mal, hast du dich \nabsichtlich so angezogen?";
const char ls7[] PROGMEM = "Die YouTube Kommentare \nüber dich sind alle wahr.";
const char ls8[] PROGMEM = "Wenn ich dein Gesicht haette,\nwuerde ich lachend in eine \nKreissaege laufen!";
const char ls9[] PROGMEM = "Das war keine Beleidigung. \nDas war eine exakte \nBeschreibung.";
const char ls10[] PROGMEM = "Du bist so ueberfluessig \nwie ein Sandkasten \nin der Sahara!";
const char ls11[] PROGMEM = "Wer zuletzt lacht, \ndenkt zu langsam.";
const char ls12[] PROGMEM = "Bitte, geh auf die \nAutobahn ein paar \nLichter fangen.";
const char ls13[] PROGMEM = "Du bist so ueberfluessig \nwie ein Fundbuero \nin Polen.";
const char ls14[] PROGMEM = "Deine Mutter kocht \nWasser nach Anleitung.";
const char ls15[] PROGMEM = "Du bist einzigartig, \njedenfalls hoffen wir \ndas Alle.";
const char ls16[] PROGMEM = "Mehr habe ich von \ndir nicht erwartet...";
const char ls17[] PROGMEM = "Dank dir fuehle ich mich \nwie ein besserer Mensch.";

PGM_P const insultStringList[] PROGMEM =
{
  ls1,
  ls2,
  ls3,
  ls4,
  ls5,
  ls6,
  ls7,
  ls8,
  ls9,
  ls10,
  ls11,
  ls12,
  ls13,
  ls14,
  ls15,
  ls16,
  ls17
};

OK. I'm pleased that worked out. Just to complete it, post your list of insult strings from:

#include "insultStrings.h"

No need to translate !

6v6gt:
OK. I'm pleased that worked out. Just to complete it, post your list of insult strings from:

#include "insultStrings.h"

No need to translate !

Done :slight_smile:

Beautiful. Just the sort of little message you may find in a fortune cookie !

Just a note, it is not necessary to copy the text from PROGMEM to a ram buffer before printing, cast the pointer to __FlashStringHelper* instead of char* and the println() function will handle it correctly.

void insultStrings(byte stringSelect)
{
  //char buffer[150];
  //strcpy_P(buffer, (char*)pgm_read_word(&(insultStringList[stringSelect])));
  //printerOutput.println(buffer);
  printerOutput.println((__FlashStringHelper*)pgm_read_word(&(insultStringList[stringSelect])));
}

Thanks for that note. Since I am complete noob when it comes to Arduino I am thankful for all tips :slight_smile:

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