16x2 LCD nearly works - but has a few strange characters. Why???

Hi everyone,

I am a beginner so please excuse my lack of knowledge about how to get LCD's to work (let alone I2C LCD's).

Project Aim:
Display the serial number of an RFID tag onto a 16x2 I2C LCD.

Hardware:

  1. Arduino Uno SMD R2;
  2. Innovations ID-20LA RFID reader and one RFID card (to wave in front of it);
  3. 16x2 serial Clear Victory 1602-1 LCD module with an I2C backpack (GY-IICLCD). Both cheap off ebay;

Software:

  1. Arduino IDE 1.0.5 (and I use the serial monitor to display the RFID card number);
  2. New LiquidCrystal library (by F Malpartida).

What Happens:
When I wave the RFID card in front of the RFID reader, it beeps to indicate a successful read, then the RFID card number is displayed via the serial monitor correctly, however when it appears on the LCD screen it has 1 x strange character before it, and 3 strange characters after it. The actual RFID number in between the strange characters is correct however.

My Code:
As I am new, I found two pieces of code and put them together to try and achieve my aim - I did not write any of it. I assume that there is some problem in the way I have combined the two sketches. Code below:

/* YourDuino.com Example Software Sketch
 16 character 2 line I2C Display
 NEW TYPE Marked "Arduino-IIC-LCD GY-LCD-V1"
 terry@yourduino.com */
/*-----( Import needed libraries )-----*/ 
#include <Wire.h>
#include <LCD.h>
#include <LiquidCrystal_I2C.h>  // F Malpartida's NewLiquidCrystal library
#include <SoftwareSerial.h>
SoftwareSerial id20(3,2); // virtual serial port
char i;


/*-----( Declare Constants )-----*/
#define I2C_ADDR    0x20  // Define I2C Address for the PCF8574A 
//---(Following are the PCF8574 pin assignments to LCD connections )----
// This are different than earlier/different I2C LCD displays
#define En_pin  4
#define Rw_pin  5
#define Rs_pin  6
#define D4_pin  0
#define D5_pin  1
#define D6_pin  2
#define D7_pin  3


/*-----( Declare objects )-----*/  
LiquidCrystal_I2C  lcd(I2C_ADDR,En_pin,Rw_pin,Rs_pin,D4_pin,D5_pin,D6_pin,D7_pin);

void setup()   /*----( SETUP: RUNS ONCE )----*/
{
  lcd.begin (16,2);  // initialize the lcd 
  Serial.begin(9600);
  id20.begin(9600);

}// END Setup

void loop()   /*----( LOOP: RUNS OVER AND OVER AGAIN )----*/
{

// Reset the display  
  if(id20.available())
    {
    i = id20.read(); // receive character from ID20
    Serial.print(i); // send character to serial monitor
    lcd.print(i);
    }
 
 
} // END Loop

Any feedback would be most appreciated.

I have attached a photo of what the LCD screen looks like (note the single garbage character before and the three garbage characters after the correct RFID card number).

Best Regards
John

LCD with strange characters.jpg

It looks like you've done a good job of getting the LCD to communicate and display. I suspect that your serial input is the source of your garbage characters.

Have you checked the output from i = id20.read(); // receive character from ID20 ?

Are the garbage characters always the same? Could you just check the incoming string and ignore those characters or just ignore all characters that are not alpha-numeric?

The ASCII data structure contains a start byte (0x02) followed by 10 bytes of data, followed by a 2 byte check sum, followed by carriage return and line feed characters, finally terminated by an end byte (0x03) (from datasheet: http://www.hobbytronics.co.uk/datasheets/sensors/ID-12LA-ID-20LA.pdf). You will need to handle the extra information surrounding the data you are interested in. This code (http://playground.arduino.cc/Code/ID12#.Uz8M6FdWXaQ) will probably do what you want.

Create a counter that counts the number of characters you are receiving.
Increase the counter every time you fetch a new value for i, and println it to your serial interface.
You'll probably see your cards serial number starting at the second character coming in and ending at the 13th character (with 3 more to go).

The characters you see as garbage will probably be a start signal, end signal and a checksum.
That would also mean that they will be the same for this one card, but not for a second card.
The second card would then have different last characters.

Maybe you can find out more about this by studying what is sent (apart from the serial number) with these RFID methods.

Thanks arloG, Christo and MAS3 - comments below for each of your posts.

arloG
No I haven't checked the output from i = id20.read(); // receive character from ID20 ? What is the best way to do this, simply print it to the Serial Monitor or are you suggesting something else (can you please expand, thank you).

Yes, garbage characters are always the same regardless of RFID tag that is read - I have 4 x RFID tags and have tried all four, the 4 strange characters are always the same. Yes I could check incoming string and ignore those characters (or non alpha numeric characters). I will give that a go and re-post the outcome. Much appreciated.

Christo
Thank you very much for this. I had no idea about the data structure that you have enlightened me about (I can see this is going to have a steep learning curve - but fun). I will study the datasheet you provided in detail. Agree with you that I will need to handle the extra data as advised. I will review the code you provided with great interest. Thanks so much on both points - greatly appreciated.

MAS3
Thanks for the counter suggestion, I will try this after first reviewing the code suggested by Christo (above).
When you say 'Maybe you can find out more about this by studying what is sent (apart from the serial number) with these RFID methods', how exactly would I do this?

Question to all:

  1. Why does the Serial Monitor strip off of extra data - does it remove this additional information prior to displaying it?
  2. Is there a way that I can display this extra data through the Serial Monitor? (then I could see the actual values of the data and then write some code to filter these out)? It would be really helpful if I could see the hex value of the extra data coming in so I can write the code to filter. Perhaps this is in the data sheet, which I am going to read now.

Appreciate everyones feedback greatly.
John

LCD with strange characters 2.jpg

jawbam:
When you say 'Maybe you can find out more about this by studying what is sent (apart from the serial number) with these RFID methods', how exactly would I do this?

By reading that datasheet that you now have.

Question to all:

  1. Why does the Serial Monitor strip off of extra data - does it remove this additional information prior to displaying it?
  2. Is there a way that I can display this extra data through the Serial Monitor? (then I could see the actual values of the data and then write some code to filter these out)? It would be really helpful if I could see the hex value of the extra data coming in so I can write the code to filter. Perhaps this is in the data sheet, which I am going to read now.
  1. You are printing to serial, meaning you want to display characters.
  2. Write to serial, you are now sending values instead of characters.
Serial.write(i)

Those codes should be in that datasheet.

Thanks MAS3,

I will review the datasheet in detail.

Thanks also for highlighting to me the difference between 'print' and 'write'. Appreciated.

Thanks again for your help. I will have a go over the weekend and provide an update to all on my progress.

Regards
John

What is the best way to do this, simply print it to the Serial Monitor or are you suggesting something else (can you please expand, thank you).

Yes, I think that's a good approach. Something like this:

#include <SoftwareSerial.h>
SoftwareSerial id20(3,2); // virtual serial port
int i;

void setup() 
{   Serial.begin(9600);
    id20.begin(9600);
}

void loop() 
{   if(id20.available())
    {  i = id20.read();                // receive character from ID20
       Serial.print("ASCII: ");        //send "ASCII:" to the serial monitor
       Serial.write(i);                //if the received character is not a printable ASCII character, you may see your garbage.
                                       //Christo says to expect 02 and 03 in your input stream.  In my tests, these two characters
                                       //print as blanks in the serial monitor.
       Serial.print("  Hex Value: ");
       Serial.println(i, HEX);         //send the hex value.  Christo says expect "2" and "3",
    }
    
    delay(100);
}

I haven't fully checked this and I don't have your RFID reader so I can't duplicate your stream. If you're getting three characters, there is going to be an additional character besides the ones Christo notes. You can determine what that character is by referring to an ASCII table afer you get the hex value.

It's possible your screen is getting the ASCII codes for the carriage return and new line. When you see what is printed on the serial monitor see if they are 10 & 13.

Christo:
The ASCII data structure contains a start byte (0x02) followed by 10 bytes of data, followed by a 2 byte check sum, followed by carriage return and line feed characters, finally terminated by an end byte (0x03) (from datasheet). You will need to handle the extra information surrounding the data you are interested in. This code will probably do what you want.

Many, if not all of the apparently spurious codes are in the first sixteen possible byte values which includes 0x0A (line feed) and 0x0D (carriage return). These correspond in the LCD to the Character Generator RAM (CGRAM) which you can define with your own (8 - the second 8 are duplicated) character font but which if you have not done so, will be somewhat random, but will tend to fall into similar patterns each time you power up the display.

You may care to run the following code which lists the first 16 characters from CGRAM on the first line and the next 16 characters on the second line - that second 16 characters actually display as blanks but I was just checking anyway. :smiley: You will recognise your spurious characters from this display. :smiley:

// Display intrinsic character values of CGRAM and orphan row
#include <Wire.h> 
#include <LiquidCrystal_I2C.h>

#define lcdAddr 0x20 // set the address of the I2C device the LCD is connected to

// create an lcd instance with correct constructor for how the lcd is wired
//  to the I2C chip.  In this case, the www.mjkdz.com module
LiquidCrystal_I2C lcd(lcdAddr, 4, 5, 6, 0, 1, 2, 3, 7, NEGATIVE); // addr, EN, RW, RS, D4, D5, D6, D7, Backlight, POLARITY

void setup()
{
  lcd.begin(16,2);  // initialize the lcd as 20x4 (16,2 for 16x2)
  lcd.setBacklight(1); // switch on the backlight
  lcd.home();
  for ( int i = 0; i < 16; i++ )
    lcd.print (char(i));
  lcd.setCursor ( 0, 1 );
  for ( int i = 17; i < 31; i++ )
    lcd.print (char(i));
}

void loop()
{
}