LCD Smartie used on 16x2 HD44780 LCD connected to an Arduino Uno R3 using I2C

I have connected an 16x2 HD44780 LCD to an Arduino Uno R3 using an I2C module with the PCF8574T chip on it.

I used the code and library from this page, and it worked ok: http://tronixlabs.com.au/news/tutorial-serial-i2c-backpack-for-hd44780compatible-lcd-modules-with-arduino/

Here’s the code for convenience:

/*
Demonstration sketch for PCF8574T I2C LCD Backpack
http://tronixlabs.com/display/lcd/serial-i2c-backpack-for-hd44780-compatible-lcd-modules/
Uses library from https://bitbucket.org/fmalpartida/new-liquidcrystal/downloads
GNU General Public License, version 3 (GPL-3.0)
*/

#include <Wire.h>
#include <LCD.h>
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C	lcd(0x27,2,1,0,4,5,6,7); // 0x27 is the I2C bus address for an unmodified backpack

void setup()
{
  // activate LCD module
  lcd.begin (16,2); // for 16 x 2 LCD module
  lcd.setBacklightPin(3,POSITIVE);
  lcd.setBacklight(HIGH);
}

void loop()
{
  lcd.home (); // set cursor to 0,0
  lcd.print(" tronixlabs.com"); 
  lcd.setCursor (0,1);        // go to start of 2nd line
  lcd.print(millis());
  delay(1000);
  lcd.setBacklight(LOW);      // Backlight off
  delay(250);
  lcd.setBacklight(HIGH);     // Backlight on
  delay(1000);
}

Next, I wanted to use the display with LCD Smartie, through the code found on this page: http://runawaybrainz.blogspot.ro/2013/12/arduino-lcd-smartie-oled-project.html

The code itself is attached as i2c_LCDSmartie_Project_V1_1.ino. I changed the address from 0x20 to 0x27. I ran LCD Smartie, setting the display plugin to matrix.dll and Startup Parameters to COM5,9600. The program does send data to the Arduino, but this only makes the LCD’s backlight flicker. If I fidget with the Contrast and Brightness settings, I can sometimes see unintelligible characters on the board. The flickering is constant as long as LCD Smartie is set to scroll the text. With the scroll turned off, it either remains on or off, correlated loosely to the contrast and brightness slider positions. I also tried using crystal.dll with COM5,9600,2 and COM5,9600,1 respectively. The behavior is pretty much the same.

i2c_LCDSmartie_Project_V1_1.ino (13.9 KB)

The i2c backpack library used by the smartie sketch uses an assumed pin wiring that is different from your backpack.
Fix the smatie sketch code to use the first i2c library you had that allows configuration which works with your backpack.

You will need to change the include to use the library that worked and fix the constructor.

You also have some initialization issues in setup() that need to be dealt with.
The 2nd library uses init() the first does not.

Even your original “working” sketch had some issues in setup().

This code is wrong:

 lcd.setBacklight(HIGH);

This is asking the library to set the backlight intensity to 1/255 of maximum, which is very dim.
You are lucky that it works because the h/w doesn’t support dimming and the library set the backlight on rather than off for such a low dim value.

Here is what I would change:

Change the include to use the original library.

#include <LiquidCrystal_I2C.h>

Change the constructor to this:

LiquidCrystal_I2C lcd(0x27,2,1,0,4,5,6,7,3, POSITIVE);

This tells the library that the backlight is on i/o pin 3 and uses positive logic.
setBacklightPin() is the old way of handling the backlight configuration and has been deprecated so it should not longer be used.
The new way is to specify it in the constructor. When done this way, begin() will automatically turn on the backlight.

replace this code in setup()

 // set up the LCD's number of rows and columns:
  lcd.init();                      // initialize the lcd 
  lcd.backlight();               // not used for OLED
  lcd.begin(numRows, numCols);

with this:

 // set up the LCD's number of rows and columns and turn on backlight
  lcd.begin(numRows, numCols);

— bill

Thank you very much for the reply, Bill.

I have to mention that I have no experience in programming, so figuring things out just can be a little tricky for me.

I've made the required changes and am now getting the following error for multiple lines of code:

C:\Program Files (x86)\Arduino\libraries\NewliquidCrystal/LCD.h:555:9: error: 'void LCD::command(uint8_t)' is private

void command(uint8_t value);

^

i2c_LCDSmartie_Project_V1_1:265: error: within this context

lcd.command(0b00001111);

Help, please.

ah... bummer. But it is easily fixed. The issue is that this code wants to send lcd commands directly to the display using the command() function and the library did not make it available to sketches.

To fix that. Go in an edit LCD.h in the library and look for the function declaration for command() It needs to in the public section vs the private section.

Based on the line number reported, I'm assuming you are using fm's library version 1.3.4 So you can just move the line that looks like this: on line 542

private:

down to just below this line: (line 555)

  void command(uint8_t value);

By move that down, it will move the command() declaration into the public section.

That should fix it.

--- bill

Haha, in hindsight, it did seem ridiculously easy, but not to someone who almost no understanding of the code they're messing with.

I did what you told me to, and, oh my God, it... almost works!

I flashed the Arduino and was greeted with the splash screen rendered perfectly but, when I opened LCD Smartie, I received a mess of unidentifiable characters: http://i.imgur.com/NyWtih2.jpg

Still, it's a significant small victory, so I'm happy for the moment. If you have any ideas of what could be the issue now, please tell me. :)

Is the backlight on and do you see the initial banner on the display? when the Arduino powers up?

* i2C  Smartie *
*    Arduino   *

If you do not see this, then there is a library issue, most likely the constructor is incorrect. That must be corrected before going any further.

If do you see this, then the switch between libraries for the sketch is correct and it something else.

It could be a timing issue because of the sketch using command()

I had a look at the sketch to see what it was really doing. It is calling command() to send raw lcd commands when it could (and should) be calling library functions to do the same thing. There are lcd library functions to do all the things the sketch is doing and there should be no need to be using a command() function.

The issue with that is that some lcd commands take a considerable amount of time and if another command is sent too soon, things can get screwed up. The library will do the proper timing when its functions are called but if command() is called, the sketch must handle the timing. (and it isn't doing anything with respect to timing)

fm's library is significantly faster than other libraries so it could result in a timing issue because of the way the sketch is using the interface by calling command() directly. (hence why the command() function was originally private)

If you did see the banner and want to see if it is timing issue you can put a delay in the loop processing and see if that helps.

I would add the delay right at the top of the loop() function. 4 ms should be more than enough to verify if this is the issue. so add a delay(4); just before reading the serial interface at this line:

  rxbyte = serial_getch();

If that clears up the trash on the display, then there is a timing issue and the sketch is violating the lcd timing by using command() The delay can remain (if everything works with it), or the sketch will need to be fixed to use the lcd functions and stop using the command() interface.

--- bill

Is the backlight on and do you see the initial banner on the display? when the Arduino powers up?

The backlight remains on for the duration of the time the arduino's powered up and yes, I do see the initial banner.

I've added delay(4); just before rxbyte = serial_getch(); as per instructions, and that didn't bring a noticeable difference.

Just to mess around with it, I changed the delay to 100. This simply made the updating of the characters significantly slower, but the garbage remained.

I should point out that the characters displayed are not consistent with themselves. For example, if I entered "123" in LCD Smartie to be displayed, I would get different results every time I powered the unit on.

Thanks again for all the help.

I’ve attached the code as it looks right now. As I said, I don’t have any coding experience so, if anyone would be willing to help me out further, even for a fee (although I don’t know if this is in lines with the forum rules), let me know.

All the progress so far can be deduces from this topic.

lcd smartie.txt (9.65 KB)

Given that the startup banner is displaying correctly, it not longer appears to be an Arduino or lcd library issue. It could be a smartie configuration issue, like baud rate or smartie device type.

You might get better help and support over on the smartie forum as that is where the people with that type of knowledge are more likely to be hanging out.

--- bill

That's something I should look into, but, at least at surface level, Smartie doesn't come with a lot of settings. I basically lets you select device type, screen size and ports.

http://lcdsmartie.sourceforge.net/MOSetup.html

EDIT: Nevermind, I'm an idiot. :D

I figured out what the baud rate was and what I should change it to (which seems to be 19200 in my case).

It's working fine for the first time right now.

Thanks again Bill, I owe the success to you. If you're ever in Romania, I need to buy you a beer or 10.

Hi. I am trying to run a sketch of post 7 to arduino micro. Lcd smartie gives me garbage on the display. The same code for arduino nano works correctly. What may be the problem? I used the library newliquidcrystal. The file LCD.h “void command (uint8_t value);” I made a non-private and compiled without problem.

Googling, testing and have a little step forward. Sometimes it runs well but after restart again displays garbage. See attachments. I add delay 10000 after serial.begin()
my code:

#include <Wire.h>
#include <avr/interrupt.h>
#include <avr/io.h>
#include <TimerOne.h>

//#include <LiquidCrystal_I2C_PCF8574.h>
#include <LiquidCrystal_I2C.h>

// these constants won't change.  But you can change the size of
// your LCD using them: 
const int numRows = 4;
const int numCols = 20;

 
//LiquidCrystal_I2C_PCF8574 lcd(0x27,numCols,numRows);  // set the LCD address to 0x20
LiquidCrystal_I2C lcd(0x27,2,1,0,4,5,6,7,3, POSITIVE);





void setup() { 
 // pinMode(13, OUTPUT);  //we'll use the debug LED to output a heartbeat


 // digitalWrite(13,LOW);
  Serial.begin(9600);
  delay(10000);



  // set up the LCD's number of rows and columns:
//  lcd.init();                      // initialize the lcd 
//  lcd.backlight();               // not used for OLED
  lcd.begin(numRows, numCols);
 
  lcd.clear();
  
  lcd.setCursor(0,0);

  lcd.print("* i2C  Smartie *");
 
  lcd.setCursor(0,1);

  lcd.print("*    Arduino   *");

  Serial.flush();

  lcd.setCursor(0,0);
}


byte serial_getch(){

  int incoming;  
  while (Serial.available()==0){
  }
  // read the incoming byte:
  incoming = Serial.read();

  return (byte) (incoming &0xff);
}



void loop(){

  byte rxbyte;
  byte temp;
  byte col;
  byte row;

  rxbyte = serial_getch();
  if (rxbyte == 254) //Matrix Orbital uses 254 prefix for commands
  {
    switch (serial_getch())
    {
    case 66: //backlight on (at previously set brightness)
      // not implemented        

      break;
    case 70: //backlight off
      // not implemented        
      break;
    case 71:  //set cursor position
      temp = (serial_getch() - 1);  //get column byte
      switch (serial_getch())  //get row byte
      {
        //line 1 is already set up
      case 2:
        temp += 0x40;
        break;
      case 3:
        temp += 0x14;
        break;
      case 4:
        temp += 0x54;
        break;
      default:
        break;
      }
      lcd.command(0b10000000 + temp);
      break;
    case 72:  //cursor home (reset display position)
      lcd.command(2);
      break;
    case 74:  //show underline cursor
      lcd.command(0b00001110);
      break;
    case 75:  //underline cursor off
    case 84:  //block cursor off
      lcd.command(0b00001100);
      break;
    case 76:  //move cursor left
      lcd.command(16);
      break;
    case 77:  //move cursor right
      lcd.command(20);
      break;
    case 78:  //define custom char
      lcd.command(64 + (serial_getch() * 8));  //get+set char address
      for (temp = 7; temp != 0; temp--)
      {
        lcd.write(serial_getch()); //get each pattern byte // change to lcd.write(serial_getch()) from lcd.print(serial_getch())   Arduino IDE 1+
      }
      break;
    case 83:  //show blinking block cursor
      lcd.command(0b00001111);
      break;
    case 86:  //GPO OFF
      //implement later
      break;
    case 87:  //GPO ON
      /*temp = serial_getch();
              if (temp == 1)
              {
                GPO1 = GPO_ON;
              }
       */
      break;
    case 88:  //clear display, cursor home
      lcd.command(1);
      break;
    case 152: //set and remember (doesn't save value, though)

    

    case 153: // Set backlight brightness (1 parameter, brightness)


      break;

      //these commands ignored (no parameters)
    case 35: //read serial number
    case 36: //read version number
    case 55: //read module type
    case 59: //exit flow-control mode
    case 65: //auto transmit keypresses
    case 96: //auto-repeat mode off (keypad)
    case 67: //auto line-wrap on
    case 68: //auto line-wrap off
    case 81: //auto scroll on
    case 82: //auto scroll off
    case 104: //init horiz bar graph
    case 109: //init med size digits
    case 115: //init narrow vert bar graph
    case 118: //init wide vert bar graph
      break;
    default:
      //all other commands ignored and parameter byte discarded
      temp = serial_getch();  //dump the command code
      break;
    }
    return;
  } 

  //END OF COMMAND HANDLER

  //change accented char to plain, detect and change descenders
  //NB descenders only work on 5x10 displays. This lookup table works
  //  with my DEM-20845 (Display Elektronik GmbH) LCD using KS0066 chip.
  switch (rxbyte)
  {
    //chars that have direct equivalent in LCD charmap
    /*    case 0x67: //g
          rxbyte = 0xE7;
          break;
        case 0x6A: //j
          rxbyte = 0xEA;
          break;
        case 0x70: //p
          rxbyte = 0xF0;
          break;
        case 0x71: //q
          rxbyte = 0xF1;
          break;
        case 0x79: //y
          rxbyte = 0xF9;
          break;
     */
  case 0xE4: //ASCII "a" umlaut
    rxbyte = 0xE1;
    break;
  case 0xF1: //ASCII "n" tilde
    rxbyte = 0xEE;
    break;
  case 0xF6: //ASCII "o" umlaut
    rxbyte = 0xEF; //was wrong in v0.86
    break;
  case 0xFC: //ASCII "u" umlaut
    rxbyte = 0xF5;
    break;

    //accented -> plain equivalent
    //and misc symbol translation
  case 0xA3: //sterling (pounds)
    rxbyte = 0xED;
    break;
    /*    case 0xB0: //degrees symbol
          rxbyte = 0xDF;
          break;
     */
  case 0xB5: //mu
    rxbyte = 0xE4;
    break;
  case 0xC0: //"A" variants
  case 0xC1:
  case 0xC2:
  case 0xC3:
  case 0xC4:
  case 0xC5:
    rxbyte = 0x41;
    break;
  case 0xC8: //"E" variants
  case 0xC9:
  case 0xCA:
  case 0xCB:
    rxbyte = 0x45;
    break;
  case 0xCC: //"I" variants
  case 0xCD:
  case 0xCE:
  case 0xCF:
    rxbyte = 0x49;
    break;
  case 0xD1: //"N" tilde -> plain "N"
    rxbyte = 0x43;
    break;
  case 0xD2: //"O" variants
  case 0xD3:
  case 0xD4:
  case 0xD5:
  case 0xD6:
  case 0xD8:
    rxbyte = 0x4F;
    break;
  case 0xD9: //"U" variants
  case 0xDA:
  case 0xDB:
  case 0xDC:
    rxbyte = 0x55;
    break;
  case 0xDD: //"Y" acute -> "Y"
    rxbyte = 0x59;
    break;
    /*    case 0xDF: //beta  //mucks up LCDSmartie's degree symbol??
          rxbyte = 0xE2;
          break;
     */
  case 0xE0: //"a" variants except umlaut
  case 0xE1:
  case 0xE2:
  case 0xE3:
  case 0xE5:
    rxbyte = 0x61;
    break;
  case 0xE7: //"c" cedilla -> "c"
    rxbyte = 0x63;
    break;
  case 0xE8: //"e" variants
  case 0xE9:
  case 0xEA:
  case 0xEB:
    rxbyte = 0x65;
    break;
  case 0xEC: //"i" variants
  case 0xED:
  case 0xEE:
  case 0xEF:
    rxbyte = 0x69;
    break;
  case 0xF2: //"o" variants except umlaut
  case 0xF3:
  case 0xF4:
  case 0xF5:
  case 0xF8:
    rxbyte = 0x6F;
    break;
  case 0xF7: //division symbol
    rxbyte = 0xFD;
    break;
  case 0xF9: //"u" variants except umlaut
  case 0xFA:
  case 0xFB:
    rxbyte = 0x75;
    break;
  default:
    break;
  }

  lcd.write(rxbyte);  //otherwise a plain char so we print it to lcd, change to lcd.write(rxbyte) from lcd.print(rxbyte)   Arduino IDE 1+
  return;

}