Interfacing LCD 4-Bit with arduino

Am new in elecronics ans i have been trying to desplay in my GDM1602K 16x2 LCD from spukfun but in vain, the only thing i get is the LED Backlight, no data at all. I have carefully followed the connections found in this site"http://www.skpang.co.uk/content/view/29/42/"
This is the code that i have been trying to use...

#include <LiquidCrystal.h>

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

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

void loop()
{  
  selectLineOne();
  delay(100);
  Serial.print(millis());
  selectLineTwo();
  delay(100);
  Serial.print(millis()/2);
  delay(100);
}

void selectLineOne(){  //puts the cursor at line 0 char 0.
   Serial.print(0xFE, BYTE);   //command flag
   Serial.print(128, BYTE);    //position
}
void selectLineTwo(){  //puts the cursor at line 0 char 0.
   Serial.print(0xFE, BYTE);   //command flag
   Serial.print(192, BYTE);    //position
}
void goTo(int position) { //position = line 1: 0-15, line 2: 16-31, 31+ defaults back to 0
if (position<16){ Serial.print(0xFE, BYTE);   //command flag
              Serial.print((position+128), BYTE);    //position
}else if (position<32){Serial.print(0xFE, BYTE);   //command flag
              Serial.print((position+48+128), BYTE);    //position 
} else { goTo(0); }
}

void clearLCD(){
   Serial.print(0xFE, BYTE);   //command flag
   Serial.print(0x01, BYTE);   //clear command.
}
void backlightOn(){  //turns on the backlight
    Serial.print(0x7C, BYTE);   //command flag for backlight stuff
    Serial.print(157, BYTE);    //light level.
}
void backlightOff(){  //turns off the backlight
    Serial.print(0x7C, BYTE);   //command flag for backlight stuff
    Serial.print(128, BYTE);     //light level for off.
}
void serCommand(){   //a general function to call the command flag for issuing all other commands   
  Serial.print(0xFE, BYTE);
}

I have also tried to use the LiquidCrystal example but nothing desplays..

#include <LiquidCrystal.h>

// LiquidCrystal display with:
// rs on pin 12
// rw on pin 11
// enable on pin 10
// d0, d1, d2, d3 on pins 5, 4, 3, 2
LiquidCrystal lcd(12, 11, 2, 7, 8, 9, 10);

void setup()
{
  // Print a message to the LCD.
  lcd.print("hello, world!");
}

void loop()
{
}

Another question please. How do these sketch below (given as LCD 4-Bit example that i just downloaded and added to my environment)determines the arduino pins number and they are not declared. Or does the sketch allocate pins by default

/* Analog in to LCD 4 bits
* ---------
* Adapted from the "analog_read_send" and "lcd_8bits" tutorials. 
* This example uses 4 less pins on the Arduino than the 8 bit example.
* It will take a reading from a 'K' Type thermocouple ice point reference chip 
* on Analog Input 2 and display the temperature in degrees Centigrade on the LCD. 
* One can also set a target temperature for turning a relay off, say for a heater,
* at a given setpoint temperature. This is done on digital pin 4.
*
* These are the pins used on the LCD:
* 
* - DI(register select), RW, DB4..DB7, Enable (7 in total)
*
* the pinout for LCD displays is standard and there is plenty
* of documentation to be found on the internet.
*
* 2006, Dave Sopchak  glasspusher at outofoptions dot net
*
*/

int DI = 12; // register select
int RW = 11;
int DB[] = {7, 8, 9, 10};
int Enable = 2;

//int temperaturePin = 2;    // select the input pin for the temperature
//int ledPin = 13;           // pin for the LED

void tickleEnable()
{
// send a pulse to enable
digitalWrite(Enable,HIGH);
delayMicroseconds(1);  // pause 1 ms according to datasheet
digitalWrite(Enable,LOW);
delayMicroseconds(1);  // pause 1 ms according to datasheet
} 

void cmdWriteSet()
{
digitalWrite(Enable,LOW);
delayMicroseconds(1);  // pause 1 ms according to datasheet
 digitalWrite(DI,0);
 digitalWrite(RW,0);
}
void LcdCommandWrite(int value) 
{
int i = 0;

 for (i=DB[3]; i >= DB[0]; i--) // high nybble first
 {
   digitalWrite(i, value & 128);
   value <<= 1;
 }
   cmdWriteSet();
   tickleEnable();

 for (i=DB[3]; i >= DB[0]; i--) // low nybble next
 {
   digitalWrite(i, value & 128);
   value <<= 1;
 }
   cmdWriteSet();
   tickleEnable();
}

void LcdDataWrite(int value) 
{
int i = 0;

digitalWrite(DI, HIGH);
DigitalWrite(RW, LOW);
 
 for (i=DB[3]; i >= DB[0]; i--) // high nybble first
 {
   digitalWrite(i, value & 128);
   value <<= 1;
 }
   tickleEnable();

 for (i=DB[3]; i >= DB[0]; i--) // low nybble next
 {
   digitalWrite(i, value & 128);
   value <<= 1;
 }
   tickleEnable();
}

void setup (void) 
{
int i;
for (i=Enable; i <= DI; i++) 
  pinMode(i,OUTPUT);

delay(100);
// initiatize lcd after a short pause
// needed by the LCDs controller
LcdCommandWrite(0x28);  // function set:
 delay(64);             // 4-bit interface, 2 display lines, 5x7 font
                        // other interaces:
                        // 0x20 = 4 bit, 1 display line

LcdCommandWrite(0x28);  // function set:
 delay(64);             // 4-bit interface, 2 display lines, 5x7 font

 LcdCommandWrite(0x06);  // entry mode set:
                        // increment automatically, no display shift
delay(20);                      
LcdCommandWrite(0x0E);  // display control:
                        // turn display on, cursor on, no blinking
delay(20);                      
LcdCommandWrite(0x01);  // clear display, set cursor position to zero  
delay(100);                      
LcdCommandWrite(0x80);  // display control:
                        // turn display on, cursor on, no blinking
delay(20);      
}

void loop (void) 
{
 int i, val = 0;
 
 for(i = 0; i < 20; ++i)
 {
       val += 1;    // read the value from the sensor
       delay(50);
 }
 
 //val /= 4.06;      // conversion value to millivolts
 
digitalWrite(ledPin, HIGH);  // turn the ledPin on
 delay(500);                  // stop the program for some time
digitalWrite(ledPin, LOW);   // turn the ledPin off
 
 if(val > 175 * 10)   // temperature in deg C times 10, since we're measuring to tenths of a degree
     digitalWrite(4,LOW);
  else
    digitalWrite(4,HIGH);

   LcdCommandWrite(0x02);  // set cursor position to zero  
 delay(10);                     
 firstDisplay(val);
}

void firstDisplay(int value)
{
 int first,second, third, fourth;
 
 first = value / 1000;    // 
 second = (value - 1000 * first)/ 100;
 third = (value - 1000 * first - 100 * second)/ 10;
 fourth = (value - 1000 * first - 100 * second - 10 * third);

     LcdDataWrite('T');
     LcdDataWrite('e');
     LcdDataWrite('m');
     LcdDataWrite('p');
     LcdDataWrite(' ');
     LcdDataWrite('=');
     LcdDataWrite(' ');

     LcdDataWrite(value > 999 ? first + 48 :  ' ');  // begin onscreen
     LcdDataWrite(value > 99 ? second + 48 : ' ');
     LcdDataWrite(third + 48);
     LcdDataWrite('.');
     LcdDataWrite(fourth + 48);

     LcdDataWrite(' ');
     LcdDataWrite('C');
     LcdDataWrite(' ');
     LcdDataWrite(' ');
}

What might be up? My LCD is new, can it be faulty yet backlight is working fine? Please help.

I have made a mistake in pasting the wiring link. The link is http://www.skpang.co.uk/content/view/29/42/

Have you wired up a contrast pot?

Kubai:

.. can it be faulty yet backlight is working fine? ...

Yes - they are totally independent.


The first thing you have to do is connect just the power and contrast pins (LCD pins 1, 2, and 3) and adjust the contrast potentiometer until the character boxes on the first part of the display become visible. If you do not have a potentiometer then just connect pin 3 to ground and the boxes should be really dark, but probably usable.

If your display is still blank it is either defective or it is a 'low temperature' device, requiring a negative voltage on the contrast pin. Let us know if your display is blank and I'll explain how to rig up a negative supply for the contrast.

If your character boxes are visible then you have another problem, one that a lot of people seem to being experiencing. The controller on your LCD module may not be getting initialized properly.

The official LiquidCrystal library in Arduino v12-15 does not use the recommended 'software initialization' for the LCD controller. The library relies on the internal reset circuitry of the LCD controller to do the initialization, which only works properly if the power supply meets certain criteria.

The 4-bit LCD library (neillzero) makes an attempt at the 'software initialization' but has some (in my opinion) errors that most likely cause problems.

I'm working on a solution but the problem is that my experience is in assembly language and I am not yet proficient in C programming. I know this seems backwards but no one ever accused me of being totally normal.

floresta

I'm working on a solution but the problem is that my experience is in assembly language and I am not yet proficient in C programming.

floresta, if you post (or pm me) the commented assembler or pseudocode and I will help you convert it to C code.

Thanks to all who offered me the help ;). It seems that am heading somewhere ;D now the LiquidCrystal Example and the LCD 4-Bit library are having problem. I have used this sketch and i can get the dislplay

#define LCD_RS      8      // Register select
#define LCD_EN      9      // Enable
#define LCD_D4 10      // Data bits
#define LCD_D5 11      // Data bits
#define LCD_D6 12      // Data bits
#define LCD_D7 13      // Data bits




void lcd_strobe()
{
      digitalWrite(LCD_EN,HIGH);
      digitalWrite(LCD_EN,LOW);
}

/* write a byte to the LCD in 4 bit mode */

void lcd_write(byte c)
{
      if(c & 0x80) digitalWrite(LCD_D7,HIGH); else  digitalWrite(LCD_D7,LOW);
      if(c & 0x40) digitalWrite(LCD_D6,HIGH); else  digitalWrite(LCD_D6,LOW);
      if(c & 0x20) digitalWrite(LCD_D5,HIGH); else  digitalWrite(LCD_D5,LOW);
      if(c & 0x10) digitalWrite(LCD_D4,HIGH); else  digitalWrite(LCD_D4,LOW);
      lcd_strobe();
      if(c & 0x08) digitalWrite(LCD_D7,HIGH); else  digitalWrite(LCD_D7,LOW);
      if(c & 0x04) digitalWrite(LCD_D6,HIGH); else  digitalWrite(LCD_D6,LOW);
      if(c & 0x02) digitalWrite(LCD_D5,HIGH); else  digitalWrite(LCD_D5,LOW);
      if(c & 0x01) digitalWrite(LCD_D4,HIGH); else  digitalWrite(LCD_D4,LOW);
      lcd_strobe();
      delayMicroseconds(40);
}

/*
 *       Clear and home the LCD
 */

void
lcd_clear(void)
{
      digitalWrite(LCD_RS,LOW);

      lcd_write(0x1);
      delay(2);
}

/* write a string of chars to the LCD */

void
lcd_puts(const char * s)
{
    digitalWrite(LCD_RS,HIGH);      // write characters

      while(*s) lcd_write(*s++);
}

/* write one character to the LCD */

void
lcd_putch(byte c)
{
    digitalWrite(LCD_RS,HIGH); // write characters

      lcd_write(c);
}


/*
 * Go to the specified position
 */

void
lcd_goto(byte pos)
{
    digitalWrite(LCD_RS,0);

      lcd_write(0x80 + pos);
}

/* initialise the LCD - put into 4 bit mode */

void
lcd_init(void)
{
      pinMode(LCD_D7,OUTPUT);
      pinMode(LCD_D6,OUTPUT);
      pinMode(LCD_D5,OUTPUT);
      pinMode(LCD_D4,OUTPUT);
      pinMode(LCD_EN,OUTPUT);
      pinMode(LCD_RS,OUTPUT);

      digitalWrite(LCD_RS, LOW);      // write control bytes

      delay(15);// power on delay

      digitalWrite(LCD_D4, HIGH);      // init!
      digitalWrite(LCD_D5, HIGH); //
      lcd_strobe();
      delay(5);

      lcd_strobe();// init!
      delayMicroseconds(100);

      lcd_strobe();// init!
      delay(5);

      digitalWrite(LCD_D4, LOW);      // set 4 bit mode
      lcd_strobe();
      delayMicroseconds(40);

      lcd_write(0x28);// 4 bit mode, 1/16 duty, 5x8 font, 2lines
      lcd_write(0x0C);// display on
      lcd_write(0x06);// entry mode advance cursor
      lcd_write(0x01);// clear display and reset cursor
}


void setup() {
  lcd_init();
}

void loop() {
  lcd_puts("hello world");

}

Am now working on this sketch for perfection and see whether it works with other LCD makes.
Foresta may you please post the pseudocode so that guy smart in c/c++ can came up with the sketch which might work better. Personally good in c/c++.

mem:

I actually have some working C code that I wrote when I first started tinkering with the Arduino last fall. Since then I have been working in assembly language, and while doing so I discovered some minor errors in my logic and that is what I am 'working on' right now.

The best thing to do in the short run is to patch up LiquidCrystal.cpp so that it will work better than it does right now. Due to it's structure I don't think it can be fixed properly for the 4-bit mode without being rewritten. Here is what I have come up with so far. This patch adds some of the missing software initialization steps but does not deal with the missing time delays, most of which are probably satisfied by the time it takes to execute the microprocessor instructions. I have tested this on one module, in 4-bit mode, and it seems to intitialize the module properly almost all of the time. (I posted this information on the Modern Device forum a day or so ago but I haven't heard back to see if it works on anyone elses modules.)

The following patches go in the file LiquidCrystal.cpp

8-bit initialization patch
Original code:

    for (int i = 0; i < 8; i++)
    pinMode(_data_pins[i], OUTPUT);

    command(0x38); // function set: 8 bits, 1 line, 5x8 dots
    command(0x0C); // display control: turn display on, cursor off, no blinking
    command(0x06); // entry mode set: increment automatically, display shift, right shift

New Code:

    for (int i = 0; i < 8; i++)
    pinMode(_data_pins[i], OUTPUT);

    command(0x30); // reset
    command(0x30); // reset
    command(0x30); // reset

    command(0x38); // function set: 8 bits, 1 line, 5x8 dots
    command(0x0C); // display control: turn display on, cursor off, no blinking
    command(0x06); // entry mode set: increment automatically, display shift, right shift

4-bit initialization patch
Original code:

    for (int i = 0; i < 4; i++)
    pinMode(_data_pins[i], OUTPUT);

    command(0x28); // function set: 4 bits, 1 line, 5x8 dots
    command(0x0C); // display control: turn display on, cursor off, no blinking
    command(0x06); // entry mode set: increment automatically, display shift, right shift

New Code:

    for (int i = 0; i < 4; i++)
    pinMode(_data_pins[i], OUTPUT);

/*  At this point the module is still in the 8-bit mode.  Each of these next two commands will be broken in 
    two and sent, one nibble at a time to the LCD instruction register.  Each nibble will be interpreted by 
    the controller as an eight bit instruction with the lower four bits as 0's (according to the data sheet 
    the D0-D3 pins are supposed to be grounded - although I have never done so).  The problem is that there 
    is no way to easily insert the required time delay between the first and second instruction (which is 
    supposed to be 4.1mS) and between the third and fourth instruction (which is much shorter, 40 uS).
*/ 
    command(0x33); // reset, reset
    command(0x32); // reset, 4-bit

    command(0x28); // function set: 4 bits, 1 line, 5x8 dots
    command(0x0C); // display control: turn display on, cursor off, no blinking
    command(0x06); // entry mode set: increment automatically, display shift, right shift

There is an interesting comment in LiquidCrystal.cpp:

    // Note, however, that resetting the Arduino doesn't reset the LCD, so we
    // can't assume that its in that state when a sketch starts (and the
    // LiquidCrystal constructor is called).

If the recommended 'software initialization' for the LCD controller had been implemented in the first place this

problem would go away.

floresta

Kubai:

You slipped your response in while I was constructing my reply to mem. I'll look at your code and possibly make some suggestions. After a quick glance it appears that you are not using any of the LCD libraries which is the approach that I recommend and one that I can deal with when programming in C.

floresta

I found that doing the init commands in the constructor did not work. I created a new method called begin and call that from setup

void LiquidCrystal::begin()
{
  delay(15);  
  command(0x28);  // function set: 4 bits, 1 line, 5x8 dots
  delay(5);
  command(0x0C);  // display control: turn display on, cursor off, no blinking
  delay(5); 
  command(0x06);  // entry mode set: increment automatically, display shift, right shift
  delay(5); 
  clear();
}

mem:

My advice to you and everyone else is to forget (for now) about LiquidCrystal because, as I see it, there is a basic flaw in it's implementation.

Here's how I interpret its code. At the very beginning LiquidCrystal.cpp determines whether four or eight data lines were specified as parameters, and either sets or clears a '_four_bit_mode' flag. I am not sure how it determines this, perhaps someone can explain it to me.

It then decides, on the basis of this flag, which of two initialization sequences to use. The problem is neither of the initialization sequences include the 'software initialization' steps specified in the data sheet.

When you try to add in the 'software initialization' steps for the 4-bit mode you run into a problem. The send() function checks the '_four_bit_mode' flag and determines whether to write all eight bits at once or four at a time, the HIGH four bits, followed by the LOW four bits. Well, to correctly switch the module into the 4-bit mode, the first four of the omitted software initialization instructions have to be written all eight bits at once (even though there are only four data lines), while the remainder of the software initialization instructions, and everything else to follow, has to be written four at a time.

I think that the easiest way to fix this problem, and it may even be trivial, is to temporarily change the '_four_bit_mode' flag during the beginning of the four-bit 'software initialization'.

I haven't finished analyzing your program, but your initialization looks basically correct to me.

floresta

Oops - this was meant for Kubai

I haven't finished analyzing your program, but your initialization looks basically correct to me.

floresta

Same problem with me, my lcd never initializes. I was just copying and pasting my LCD datasheet link here and I realised that Seeedstudio guys added a connection scheme and a arduino example for it ;D. I will check if my LCD wake-up now !

http://www.seeedstudio.com/depot/lcd-82-characters-blue-back-light-p-120.html

I don't think that diagram matches their example code. The code has Arduino pin 8 connected to lcd db0, the diagram shows Arduino pin 4 connected to db0

The data connections that match the example code are:

LCD Arduino
RS–4 A0 (14)
RW-5 A1 (15)
E -6 A2 (16)
D0-7 8
D1-8 9
D2-9 10
D3-10 11
D4-11 4
D5-12 5
D6-13 6
D7-14 7

Note that this code and wiring uses 8 bit mode, the OP was looking to use 4 bit mode

Men,

You are right the scheme was with lines D4-D7 inverted with D8-D11. I correct it and added a 10K potentiometer with center in Vo (pin3). Also VDD (pin 2)=5V not GND.

Now my LCD is ALIVE !! ;D. Thanks for the help !! :slight_smile:

Originally I was trying to operate LCD with 4 bits but since it even initialized it was better to test firstly with 8 bits, by now It´s OK,next step is to test with 4 bits.

I took a picture but I don´t know yet how to post it in here :-? , any suggestion ?

good to hear you have it going. You can only post a link to a picture here, so put the picture on one of the public sites like flickr and then post a link here (there is an 'insert image' icon that creates the tags for the link)

This is the LCD operating, spaghetti wiring, but work out !

Imgur

Thanks Again!

Now it´s my turn of struggling with LCD 4bits, It seems to work fine but sometimes LCD doesn´t initialize "alone"..., it is need a press on reset switch from Arduino to get LCD initialized and running.

#include <LiquidCrystal.h>

// LiquidCrystal display with:
// rs on pin 14
// rw on pin 15
// enable on pin 16
// d4, d5, d6, d7 on pins 4, 5, 6, 7
LiquidCrystal lcd(14, 15, 16, 4, 5, 6, 7);

void setup()
{
  // Print a message to the LCD.
  lcd.setCursor(0,0);
  lcd.print("Arduino");
lcd.setCursor(0,1);
  lcd.print("4 BITS");  
  
}

void loop()
{
}

This other code with LCD instructions inside the loop, looks to solve this extra reset need :

#include <LiquidCrystal.h>

// LiquidCrystal display with:
// rs on pin 14
// rw on pin 15
// enable on pin 16
// d4, d5, d6, d7 on pins 4, 5, 6, 7
LiquidCrystal lcd(14, 15, 16, 4, 5, 6, 7);

void setup()
{
}
void loop()

{
  // Print a message to the LCD.
  lcd.setCursor(0,0);
  lcd.print("Arduino");
lcd.setCursor(0,1);
  lcd.print("4 BITS");  
  
}