4

I am trying to get a 16x2 LCD running on my Raspberry Pi 2, but something is not working. My wiring should be correct and is displayed below. enter image description here When I am using this code:

#import
import RPi.GPIO as GPIO
import time

# Define GPIO to LCD mapping
LCD_RS = 7
LCD_E  = 8
LCD_D4 = 25
LCD_D5 = 24
LCD_D6 = 23
LCD_D7 = 18

# Define some device constants
LCD_WIDTH = 16    # Maximum characters per line
LCD_CHR = True
LCD_CMD = False

LCD_LINE_1 = 0x80 # LCD RAM address for the 1st line
LCD_LINE_2 = 0xC0 # LCD RAM address for the 2nd line

# Timing constants
E_PULSE = 0.0005
E_DELAY = 0.0005

def main():
  # Main program block
  GPIO.setwarnings(False)
  GPIO.setmode(GPIO.BCM)       # Use BCM GPIO numbers
  GPIO.setup(LCD_E, GPIO.OUT)  # E
  GPIO.setup(LCD_RS, GPIO.OUT) # RS
  GPIO.setup(LCD_D4, GPIO.OUT) # DB4
  GPIO.setup(LCD_D5, GPIO.OUT) # DB5
  GPIO.setup(LCD_D6, GPIO.OUT) # DB6
  GPIO.setup(LCD_D7, GPIO.OUT) # DB7

  # Initialise display
  lcd_init()

  while True:

    # Send some test
    lcd_string("Rasbperry Pi",LCD_LINE_1)
    lcd_string("16x2 LCD Test",LCD_LINE_2)

    time.sleep(3) # 3 second delay

    # Send some text
    lcd_string("1234567890123456",LCD_LINE_1)
    lcd_string("abcdefghijklmnop",LCD_LINE_2)

    time.sleep(3) # 3 second delay

    # Send some text
    lcd_string("RaspberryPi-spy",LCD_LINE_1)
    lcd_string(".co.uk",LCD_LINE_2)

    time.sleep(3)

    # Send some text
    lcd_string("Follow me on",LCD_LINE_1)
    lcd_string("Twitter @RPiSpy",LCD_LINE_2)

    time.sleep(3)

def lcd_init():
  # Initialise display
  lcd_byte(0x33,LCD_CMD) # 110011 Initialise
  lcd_byte(0x32,LCD_CMD) # 110010 Initialise
  lcd_byte(0x06,LCD_CMD) # 000110 Cursor move direction
  lcd_byte(0x0C,LCD_CMD) # 001100 Display On,Cursor Off, Blink Off
  lcd_byte(0x28,LCD_CMD) # 101000 Data length, number of lines, font size
  lcd_byte(0x01,LCD_CMD) # 000001 Clear display
  time.sleep(E_DELAY)

def lcd_byte(bits, mode):
  # Send byte to data pins
  # bits = data
  # mode = True  for character
  #        False for command

  GPIO.output(LCD_RS, mode) # RS

  # High bits
  GPIO.output(LCD_D4, False)
  GPIO.output(LCD_D5, False)
  GPIO.output(LCD_D6, False)
  GPIO.output(LCD_D7, False)
  if bits&0x10==0x10:
    GPIO.output(LCD_D4, True)
  if bits&0x20==0x20:
    GPIO.output(LCD_D5, True)
  if bits&0x40==0x40:
    GPIO.output(LCD_D6, True)
  if bits&0x80==0x80:
    GPIO.output(LCD_D7, True)

  # Toggle 'Enable' pin
  lcd_toggle_enable()

  # Low bits
  GPIO.output(LCD_D4, False)
  GPIO.output(LCD_D5, False)
  GPIO.output(LCD_D6, False)
  GPIO.output(LCD_D7, False)
  if bits&0x01==0x01:
    GPIO.output(LCD_D4, True)
  if bits&0x02==0x02:
    GPIO.output(LCD_D5, True)
  if bits&0x04==0x04:
    GPIO.output(LCD_D6, True)
  if bits&0x08==0x08:
    GPIO.output(LCD_D7, True)

  # Toggle 'Enable' pin
  lcd_toggle_enable()

def lcd_toggle_enable():
  # Toggle enable
  time.sleep(E_DELAY)
  GPIO.output(LCD_E, True)
  time.sleep(E_PULSE)
  GPIO.output(LCD_E, False)
  time.sleep(E_DELAY)

def lcd_string(message,line):
  # Send string to display

  message = message.ljust(LCD_WIDTH," ")

  lcd_byte(line, LCD_CMD)

  for i in range(LCD_WIDTH):
    lcd_byte(ord(message[i]),LCD_CHR)

if __name__ == '__main__':

  try:
    main()
  except KeyboardInterrupt:
    pass
  finally:
    lcd_byte(0x01, LCD_CMD)
    lcd_string("Goodbye!",LCD_LINE_1)
    GPIO.cleanup()

I get only blocks in the upper row of the display. I think it is not a contrast problem, as the contrast looks good. My feeling is, that I have a timing problem. But I have no idea in which direction I have to change the timing?

As this script was originally made for a Raspberry Pi 1, are there changes in the GPIO pinout of the Pi? I couldn't find any differences online.

Thanks, Kj

  • 1
    Why are you not using SPI or I2C? – Patrick Cook Nov 12 '15 at 4:00
  • 1
    @PatrickCook Why do you think it has a SPI or I2C interface? 16x2 LCD displays usually have a parallel interface as shown in the circuit diagram. – joan Nov 12 '15 at 9:24
  • I mean the SPI/I2C on the RPi. – Patrick Cook Nov 13 '15 at 3:08
  • Because I need the SPI/IC2 pins for a different device. I have redone my whole wiring. It looks good. So the fault has to be in the script somewhere...just cant figure out where. – Kj Ell Nov 13 '15 at 20:44
  • If those E_PULSE and E_DELAY constraints are critical note you will never get consistent timing that precise in software like this. – goldilocks Aug 11 '16 at 14:10
1

I think I ran into the same issue (and I was using a I2C backpack) - check your configuration settings, particularly for the "Data length, number of lines, font size" - I had a problem with the code I copied only setting it for ONE line display...

def lcd_init():
  # Initialise display
  lcd_byte(0x33,LCD_CMD) # 110011 Initialise
  lcd_byte(0x32,LCD_CMD) # 110010 Initialise
  lcd_byte(0x06,LCD_CMD) # 000110 Cursor move direction
  lcd_byte(0x0C,LCD_CMD) # 001100 Display On, Cursor Off, Blink Off
  lcd_byte(0x28,LCD_CMD) # 101000 Data length, number of lines, font size
  lcd_byte(0x01,LCD_CMD) # 000001 Clear display
  time.sleep(E_DELAY)

The line concerned:

lcd_byte(0x28,LCD_CMD) # 101000 Data length, number of lines, font size

is (according to the useful Wikipedia page):

             RS R/W D7 D6 D5 D4 D3 D2 D1 D0

Function set 0 0 0 0 1 DL N F * * Sets interface data length (DL), number of display line (N), and character font (F).

DL = 1 for 8 bit, 0 for 4 bit mode

N = 1 for two line display, 0 for one line

F = 1 for 5x10 dots, 0 for 5x8 (1 for one line display only?)

which seems to be right...

However the Wikipedia details for those prior "Initialise" does seem to be slightly different and it mentions that afterwards the display WILL BE IN ONE LINE MODE.

Unfortunately my Pi is currently charging it's UPis right now and I haven't got the display or the rest of the kit connected to it. I will update this when I have had a chance to look further.

EDIT: Further reading up revealed that to "force" an initialisation using the interface rather than assuming it happens via the power supply coming up it is necessary for a long delay between writing the first two nibbles of the data for the very first write (as we are using the display in 4-bit mode) - that delay should be at least 4.1 mSec from the data sheets I am seeing on-line.

I had thought that it would be possible to use this to switch the display into a single line LARGE font mode (5x10 dots instead of 5x8) - whilst I was able to do the mode switching (it also alters the duty cycle as a different number of, i.e. less, lines are used {by resetting the number of lines configuration bit to {1 = "two line", 0 = "one line"} so the contrast changes a little) by switching into one line mode the particular unit I had does not change the font and exactly the same pixels are used even when the "font size" bit is changed in the configuration data {1 = "5x10" dots, 0 = "5x8"}. As a result I abandoned the code I had that would reset, reinitialise and recopy the buffered data to the display to change between one and two line modes...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.