How to make symbold in LCD


18 posts
by kodak » Tue Jan 08, 2013 8:04 pm
I have used this guide:
http://www.raspberrypi-spy.co.uk/2012/08/20x4-lcd-module-control-using-python/
Bt i want to se som more defrind symbols in my LCD
how do i make any of this symbols:
http://www.line-web.dk/rpi/lcd-4x20/
Posts: 58
Joined: Wed Dec 26, 2012 6:20 pm
by bgreat » Wed Jan 09, 2013 2:17 am
The link you provided shows an inverse character set. The default capability for a character LCD is support for 8 custom characters. The characters are displayed using character codes 00 through 07. To define the bit pattern for the characters you must update the CGRAM locations for the characters.

0x40-0x47 pattern for character 00
0x48-0x4f pattern for character 01
0x50-0x57 pattern for character 02
0x58-0x5f pattern for character 03
0x60-0x67 pattern for character 04
0x68-0x6f pattern for character 05
0x70-0x77 pattern for character 06
0x78-0x7f pattern for character 07

For specific detailed information refer to your display's data sheet.

A good internet resource on character displays is: http://www.geocities.com/dinceraydin/lcd/index.html
Specific information on character graphics: http://www.geocities.com/dinceraydin/lcd/custom.htm
Also, has a simulator page that allows testing your command sequences: http://www.geocities.com/dinceraydin/djlcdsim/djlcdsim.html

Enjoy!
Bill
User avatar
Posts: 235
Joined: Mon Jan 23, 2012 2:09 pm
by rickseiden » Wed Jan 09, 2013 2:58 am
Here's my code, mixed in with other code to run the display. It uses a class I designed around driving the display using a shift register, but it will work fine normally.

Code: Select all
#!/usr/bin/python
#
# HD44780 LCD Test Script for
# Raspberry Pi
#
# Author : Rick Seiden (based on the work of Matt Hawkins)
# Site   : http://www.raspberrypi-spy.co.uk
#
# Date   : 10/20/2012
#

# The wiring for the LCD is as follows:
# 1 : GND
# 2 : 5V
# 3 : Contrast (0-5V)*
# 4 : RS (Register Select)
# 5 : R/W (Read Write)       - GROUND THIS PIN
# 6 : Enable or Strobe
# 7 : Data Bit 0             - NOT USED
# 8 : Data Bit 1             - NOT USED
# 9 : Data Bit 2             - NOT USED
# 10: Data Bit 3             - NOT USED
# 11: Data Bit 4
# 12: Data Bit 5
# 13: Data Bit 6
# 14: Data Bit 7
# 15: LCD Backlight +5V**
# 16: LCD Backlight GND

#import
import RPi.GPIO as GPIO
import time
from datetime import datetime
from shifter import Shifter
# Define Shifter to LCD mapping
LCD_RS = 16 #Bin value
LCD_E  = 32 #Bin value
LCD_D4 = 1
LCD_D5 = 2
LCD_D6 = 4
LCD_D7 = 8

# Define some device constants
LCD_WIDTH = 40    # 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
LCD_CHARS = [0x40,0x48,0x50,0x58,0x60,0x68,0x70,0x78]

# Timing constants
E_PULSE = 0.0005
E_DELAY = 0.0005

def lcd_custom(charPos,charDef):

  lcd_byte(LCD_CHARS[charPos],LCD_CMD)
  for line in charDef:
    lcd_byte(line,LCD_CHR)

def main():
  # Main program block

  shifter.clear()

  # Initialise display
  lcd_init()
  lcd_custom(0,[0x04,0x02,0x0F,0x12,0x14,0x10,0x10,0x10])
  lcd_custom(1,[0x1B,0x1B,0x00,0x04,0x00,0x1F,0x11,0x0E])
  running=True
  while running==True:
    try:
      lcd_byte(LCD_LINE_1, LCD_CMD)
      lcd_string(chr(0)+" "+datetime.now().strftime("%I:%M:%S %p")+" "+chr(1))
      lcd_byte(LCD_LINE_2, LCD_CMD)
      lcd_string(datetime.now().strftime("%A, %B %e, %Y"))
      time.sleep(0.5)
    except (KeyboardInterrupt):
      running=False
 
  lcd_byte(0x01,LCD_CMD)
def lcd_init():
  # Initialise display
  lcd_byte(0x33,LCD_CMD)
  lcd_byte(0x32,LCD_CMD)
  lcd_byte(0x28,LCD_CMD)
  lcd_byte(0x0C,LCD_CMD) 
  lcd_byte(0x06,LCD_CMD)
  lcd_byte(0x01,LCD_CMD) 

def lcd_string(message):
  # Send string to display

  message = message.center(LCD_WIDTH," ") 

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

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

  if (mode==True):
    value=LCD_RS
  else:
    value=0

  # High bits
  if bits&0x10==0x10:
    value=value+LCD_D4
  if bits&0x20==0x20:
    value=value+LCD_D5
  if bits&0x40==0x40:
    value=value+LCD_D6
  if bits&0x80==0x80:
    value=value+LCD_D7
  #print (value)
  # Toggle 'Enable' pin
  value=value+LCD_E
  time.sleep(E_DELAY)
  shifter.setValue(value)
  time.sleep(E_PULSE)
  shifter.clear()
  time.sleep(E_DELAY)     

  # Low bits
  if (mode==True):
    value=LCD_RS
  else:
    value=0
  if bits&0x01==0x01:
    value=value+LCD_D4
  if bits&0x02==0x02:
    value=value+LCD_D5
  if bits&0x04==0x04:
    value=value+LCD_D6
  if bits&0x08==0x08:
    value=value+LCD_D7

  # Toggle 'Enable' pin
  value=value+LCD_E
  time.sleep(E_DELAY)
  shifter.setValue(value)
  time.sleep(E_PULSE)
  shifter.clear()
  time.sleep(E_DELAY)

if __name__ == '__main__':
  GPIO.setmode(GPIO.BOARD)
  shifter=Shifter()
  main()

There are 10 types of people in this world. Those that understand binary, and those that don't.
Posts: 398
Joined: Thu Aug 02, 2012 12:21 pm
Location: Buffalo, NY, USA
by texy » Wed Jan 09, 2013 7:52 am
"2.8inch TFT LCD + Touch screen" add-on boards for sale here :
http://www.raspberrypi.org/phpBB3/viewtopic.php?f=93&t=65566
50p goes to the Foundation ;-)
Forum Moderator
Forum Moderator
Posts: 2387
Joined: Sat Mar 03, 2012 10:59 am
Location: Berkshire, England
by kodak » Sat Jan 12, 2013 3:27 pm
rickseiden wrote:Here's my code, mixed in with other code to run the display. It uses a class I designed around driving the display using a shift register, but it will work fine normally.

Code: Select all
#!/usr/bin/python
#
# HD44780 LCD Test Script for
# Raspberry Pi
#
# Author : Rick Seiden (based on the work of Matt Hawkins)
# Site   : http://www.raspberrypi-spy.co.uk
#
# Date   : 10/20/2012
#

# The wiring for the LCD is as follows:
# 1 : GND
# 2 : 5V
# 3 : Contrast (0-5V)*
# 4 : RS (Register Select)
# 5 : R/W (Read Write)       - GROUND THIS PIN
# 6 : Enable or Strobe
# 7 : Data Bit 0             - NOT USED
# 8 : Data Bit 1             - NOT USED
# 9 : Data Bit 2             - NOT USED
# 10: Data Bit 3             - NOT USED
# 11: Data Bit 4
# 12: Data Bit 5
# 13: Data Bit 6
# 14: Data Bit 7
# 15: LCD Backlight +5V**
# 16: LCD Backlight GND

#import
import RPi.GPIO as GPIO
import time
from datetime import datetime
from shifter import Shifter
# Define Shifter to LCD mapping
LCD_RS = 16 #Bin value
LCD_E  = 32 #Bin value
LCD_D4 = 1
LCD_D5 = 2
LCD_D6 = 4
LCD_D7 = 8

# Define some device constants
LCD_WIDTH = 40    # 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
LCD_CHARS = [0x40,0x48,0x50,0x58,0x60,0x68,0x70,0x78]

# Timing constants
E_PULSE = 0.0005
E_DELAY = 0.0005

def lcd_custom(charPos,charDef):

  lcd_byte(LCD_CHARS[charPos],LCD_CMD)
  for line in charDef:
    lcd_byte(line,LCD_CHR)

def main():
  # Main program block

  shifter.clear()

  # Initialise display
  lcd_init()
  lcd_custom(0,[0x04,0x02,0x0F,0x12,0x14,0x10,0x10,0x10])
  lcd_custom(1,[0x1B,0x1B,0x00,0x04,0x00,0x1F,0x11,0x0E])
  running=True
  while running==True:
    try:
      lcd_byte(LCD_LINE_1, LCD_CMD)
      lcd_string(chr(0)+" "+datetime.now().strftime("%I:%M:%S %p")+" "+chr(1))
      lcd_byte(LCD_LINE_2, LCD_CMD)
      lcd_string(datetime.now().strftime("%A, %B %e, %Y"))
      time.sleep(0.5)
    except (KeyboardInterrupt):
      running=False
 
  lcd_byte(0x01,LCD_CMD)
def lcd_init():
  # Initialise display
  lcd_byte(0x33,LCD_CMD)
  lcd_byte(0x32,LCD_CMD)
  lcd_byte(0x28,LCD_CMD)
  lcd_byte(0x0C,LCD_CMD) 
  lcd_byte(0x06,LCD_CMD)
  lcd_byte(0x01,LCD_CMD) 

def lcd_string(message):
  # Send string to display

  message = message.center(LCD_WIDTH," ") 

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

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

  if (mode==True):
    value=LCD_RS
  else:
    value=0

  # High bits
  if bits&0x10==0x10:
    value=value+LCD_D4
  if bits&0x20==0x20:
    value=value+LCD_D5
  if bits&0x40==0x40:
    value=value+LCD_D6
  if bits&0x80==0x80:
    value=value+LCD_D7
  #print (value)
  # Toggle 'Enable' pin
  value=value+LCD_E
  time.sleep(E_DELAY)
  shifter.setValue(value)
  time.sleep(E_PULSE)
  shifter.clear()
  time.sleep(E_DELAY)     

  # Low bits
  if (mode==True):
    value=LCD_RS
  else:
    value=0
  if bits&0x01==0x01:
    value=value+LCD_D4
  if bits&0x02==0x02:
    value=value+LCD_D5
  if bits&0x04==0x04:
    value=value+LCD_D6
  if bits&0x08==0x08:
    value=value+LCD_D7

  # Toggle 'Enable' pin
  value=value+LCD_E
  time.sleep(E_DELAY)
  shifter.setValue(value)
  time.sleep(E_PULSE)
  shifter.clear()
  time.sleep(E_DELAY)

if __name__ == '__main__':
  GPIO.setmode(GPIO.BOARD)
  shifter=Shifter()
  main()


It will not work for me.

Code: Select all
Traceback (most recent call last):
  File "lcd.py", line 35, in <module>
    from shifter import Shifter
ImportError: No module named shifter
Posts: 58
Joined: Wed Dec 26, 2012 6:20 pm
by kodak » Sat Jan 12, 2013 3:55 pm
texy wrote:Alternative code here :
viewtopic.php?f=32&t=8021&start=50#p245630


Texy


Traceback (most recent call last):
File "lcd1.py", line 17, in <module>
import wiringpi
ImportError: No module named wiringpi
Posts: 58
Joined: Wed Dec 26, 2012 6:20 pm
by rickseiden » Sat Jan 12, 2013 4:02 pm
kodak wrote:
rickseiden wrote:Here's my code, mixed in with other code to run the display. It uses a class I designed around driving the display using a shift register, but it will work fine normally.

Code: Select all
#!/usr/bin/python
#
# HD44780 LCD Test Script for
# Raspberry Pi
#
# Author : Rick Seiden (based on the work of Matt Hawkins)
# Site   : http://www.raspberrypi-spy.co.uk
#
# Date   : 10/20/2012
#

# The wiring for the LCD is as follows:
# 1 : GND
# 2 : 5V
# 3 : Contrast (0-5V)*
# 4 : RS (Register Select)
# 5 : R/W (Read Write)       - GROUND THIS PIN
# 6 : Enable or Strobe
# 7 : Data Bit 0             - NOT USED
# 8 : Data Bit 1             - NOT USED
# 9 : Data Bit 2             - NOT USED
# 10: Data Bit 3             - NOT USED
# 11: Data Bit 4
# 12: Data Bit 5
# 13: Data Bit 6
# 14: Data Bit 7
# 15: LCD Backlight +5V**
# 16: LCD Backlight GND

#import
import RPi.GPIO as GPIO
import time
from datetime import datetime
from shifter import Shifter
# Define Shifter to LCD mapping
LCD_RS = 16 #Bin value
LCD_E  = 32 #Bin value
LCD_D4 = 1
LCD_D5 = 2
LCD_D6 = 4
LCD_D7 = 8

# Define some device constants
LCD_WIDTH = 40    # 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
LCD_CHARS = [0x40,0x48,0x50,0x58,0x60,0x68,0x70,0x78]

# Timing constants
E_PULSE = 0.0005
E_DELAY = 0.0005

def lcd_custom(charPos,charDef):

  lcd_byte(LCD_CHARS[charPos],LCD_CMD)
  for line in charDef:
    lcd_byte(line,LCD_CHR)

def main():
  # Main program block

  shifter.clear()

  # Initialise display
  lcd_init()
  lcd_custom(0,[0x04,0x02,0x0F,0x12,0x14,0x10,0x10,0x10])
  lcd_custom(1,[0x1B,0x1B,0x00,0x04,0x00,0x1F,0x11,0x0E])
  running=True
  while running==True:
    try:
      lcd_byte(LCD_LINE_1, LCD_CMD)
      lcd_string(chr(0)+" "+datetime.now().strftime("%I:%M:%S %p")+" "+chr(1))
      lcd_byte(LCD_LINE_2, LCD_CMD)
      lcd_string(datetime.now().strftime("%A, %B %e, %Y"))
      time.sleep(0.5)
    except (KeyboardInterrupt):
      running=False
 
  lcd_byte(0x01,LCD_CMD)
def lcd_init():
  # Initialise display
  lcd_byte(0x33,LCD_CMD)
  lcd_byte(0x32,LCD_CMD)
  lcd_byte(0x28,LCD_CMD)
  lcd_byte(0x0C,LCD_CMD) 
  lcd_byte(0x06,LCD_CMD)
  lcd_byte(0x01,LCD_CMD) 

def lcd_string(message):
  # Send string to display

  message = message.center(LCD_WIDTH," ") 

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

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

  if (mode==True):
    value=LCD_RS
  else:
    value=0

  # High bits
  if bits&0x10==0x10:
    value=value+LCD_D4
  if bits&0x20==0x20:
    value=value+LCD_D5
  if bits&0x40==0x40:
    value=value+LCD_D6
  if bits&0x80==0x80:
    value=value+LCD_D7
  #print (value)
  # Toggle 'Enable' pin
  value=value+LCD_E
  time.sleep(E_DELAY)
  shifter.setValue(value)
  time.sleep(E_PULSE)
  shifter.clear()
  time.sleep(E_DELAY)     

  # Low bits
  if (mode==True):
    value=LCD_RS
  else:
    value=0
  if bits&0x01==0x01:
    value=value+LCD_D4
  if bits&0x02==0x02:
    value=value+LCD_D5
  if bits&0x04==0x04:
    value=value+LCD_D6
  if bits&0x08==0x08:
    value=value+LCD_D7

  # Toggle 'Enable' pin
  value=value+LCD_E
  time.sleep(E_DELAY)
  shifter.setValue(value)
  time.sleep(E_PULSE)
  shifter.clear()
  time.sleep(E_DELAY)

if __name__ == '__main__':
  GPIO.setmode(GPIO.BOARD)
  shifter=Shifter()
  main()


It will not work for me.

Code: Select all
Traceback (most recent call last):
  File "lcd.py", line 35, in <module>
    from shifter import Shifter
ImportError: No module named shifter


Shifter is a custom class that is designed to allow the use of a shift register when driving the LCD display. Since you're not using a shift register, even if you had the code for Shifter, it wouldn't work for you. What you need to do is pick out some of the code that's in there to find what makes a custom character. For example,

Code: Select all
def lcd_custom(charPos,charDef):

  lcd_byte(LCD_CHARS[charPos],LCD_CMD)
  for line in charDef:
    lcd_byte(line,LCD_CHR)


and

Code: Select all
  lcd_custom(0,[0x04,0x02,0x0F,0x12,0x14,0x10,0x10,0x10])
  lcd_custom(1,[0x1B,0x1B,0x00,0x04,0x00,0x1F,0x11,0x0E])


and

Code: Select all
LCD_CHARS = [0x40,0x48,0x50,0x58,0x60,0x68,0x70,0x78]


I found thispost very helpful when creating this code.
There are 10 types of people in this world. Those that understand binary, and those that don't.
Posts: 398
Joined: Thu Aug 02, 2012 12:21 pm
Location: Buffalo, NY, USA
by kodak » Sat Jan 12, 2013 5:29 pm
Can still not make it work

Can you build an exempel
Posts: 58
Joined: Wed Dec 26, 2012 6:20 pm
by bgreat » Sat Jan 12, 2013 7:53 pm
Here is a modified version of code I picked up from the forums and online for an LCD class. I added a bar graph using custom characters.

Code: Select all
#!/usr/bin/python

#
# based on code from lrvick and LiquidCrystal
# lrvic - https://github.com/lrvick/raspi-hd44780/blob/master/hd44780.py
# LiquidCrystal - https://github.com/arduino/Arduino/blob/master/libraries/LiquidCrystal/LiquidCrystal.cpp
#

from time import sleep

class CharLCD:

    # commands
    LCD_CLEARDISPLAY            = 0x01
    LCD_RETURNHOME              = 0x02
    LCD_ENTRYMODESET            = 0x04
    LCD_DISPLAYCONTROL          = 0x08
    LCD_CURSORSHIFT             = 0x10
    LCD_FUNCTIONSET             = 0x20
    LCD_SETCGRAMADDR            = 0x40
    LCD_SETDDRAMADDR            = 0x80

    # flags for display entry mode
    LCD_ENTRYRIGHT              = 0x00
    LCD_ENTRYLEFT               = 0x02
    LCD_ENTRYSHIFTINCREMENT     = 0x01
    LCD_ENTRYSHIFTDECREMENT     = 0x00

    # flags for display on/off control
    LCD_DISPLAYON               = 0x04
    LCD_DISPLAYOFF              = 0x00
    LCD_CURSORON                = 0x02
    LCD_CURSOROFF               = 0x00
    LCD_BLINKON                 = 0x01
    LCD_BLINKOFF                = 0x00

    # flags for display/cursor shift
    LCD_DISPLAYMOVE             = 0x08
    LCD_CURSORMOVE              = 0x00

    # flags for display/cursor shift
    LCD_DISPLAYMOVE             = 0x08
    LCD_CURSORMOVE              = 0x00
    LCD_MOVERIGHT               = 0x04
    LCD_MOVELEFT                = 0x00

    # flags for function set
    LCD_8BITMODE                = 0x10
    LCD_4BITMODE                = 0x00
    LCD_2LINE                   = 0x08
    LCD_1LINE                   = 0x00
    LCD_5x10DOTS                = 0x04
    LCD_5x8DOTS                 = 0x00


    def __init__(self, pin_rs=25, pin_e=24, pins_db=[23, 17, 21, 22], GPIO = None):
        # Emulate the old behavior of using RPi.GPIO if we haven't been given
        # an explicit GPIO interface to use
        if not GPIO:
            import RPi.GPIO as GPIO
        self.GPIO = GPIO
        self.pin_rs = pin_rs
        self.pin_e = pin_e
        self.pins_db = pins_db

        self.GPIO.setmode(GPIO.BCM)
        self.GPIO.setup(self.pin_e, GPIO.OUT)
        self.GPIO.setup(self.pin_rs, GPIO.OUT)

        for pin in self.pins_db:
            self.GPIO.setup(pin, GPIO.OUT)

        self.write4bits(0x33) # initialization
        self.write4bits(0x32) # initialization
        self.write4bits(0x28) # 2 line 5x7 matrix
        self.write4bits(0x0C) # turn cursor off 0x0E to enable cursor
        self.write4bits(0x06) # shift cursor right

        self.displaycontrol = self.LCD_DISPLAYON | self.LCD_CURSOROFF | self.LCD_BLINKOFF

        self.displayfunction = self.LCD_4BITMODE | self.LCD_1LINE | self.LCD_5x8DOTS
        self.displayfunction |= self.LCD_2LINE

        """ Initialize to default text direction (for romance languages) """
        self.displaymode =  self.LCD_ENTRYLEFT | self.LCD_ENTRYSHIFTDECREMENT
        self.write4bits(self.LCD_ENTRYMODESET | self.displaymode) #  set the entry mode

        self.numlines = 2       # default to two line display
        self.currline = 0
        self.row_offsets = [ 0x00, 0x40, 0x14, 0x54 ]

        self.numcols = 16
        self.curcol = 0

        """ Initialize character generator for horizontal bar graph """
        self.write4bits(self.LCD_SETCGRAMADDR+0)
        for i in range(8):
            self.write4bits(0x00,True)
        self.write4bits(self.LCD_SETCGRAMADDR+8)
        for i in range(8):
            self.write4bits(0x10,True)
        self.write4bits(self.LCD_SETCGRAMADDR+16)
        for i in range(8):
            self.write4bits(0x18,True)
        self.write4bits(self.LCD_SETCGRAMADDR+24)
        for i in range(8):
            self.write4bits(0x1c,True)
        self.write4bits(self.LCD_SETCGRAMADDR+32)
        for i in range(8):
            self.write4bits(0x1e,True)
        self.write4bits(self.LCD_SETCGRAMADDR+40)
        for i in range(8):
            self.write4bits(0x1f,True)

        self.clear()

    def begin(self, cols, lines):
        if (lines > 1):
                self.numlines = lines
                self.displayfunction |= self.LCD_2LINE
                self.currline = 0
        self.numcols = cols
        self.curcol = 0


    def home(self):
        self.currline = 0
        self.write4bits(self.LCD_RETURNHOME) # set cursor position to zero
        self.delayMicroseconds(3000) # this command takes a long time!


    def clear(self):
        self.currline = 0
        self.write4bits(self.LCD_CLEARDISPLAY) # command to clear display
        self.delayMicroseconds(3000)    # 3000 microsecond sleep, clearing the display takes a long time


    def setCursor(self, col, row):
        self.row_offsets = [ 0x00, 0x40, 0x14, 0x54 ]

        if ( row > self.numlines ):
                row = self.numlines - 1 # we count rows starting w/0

        self.write4bits(self.LCD_SETDDRAMADDR | (col + self.row_offsets[row]))
        self.currline = row


    def noDisplay(self):
        """ Turn the display off (quickly) """
        self.displaycontrol &= ~self.LCD_DISPLAYON
        self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol)


    def display(self):
        """ Turn the display on (quickly) """
        self.displaycontrol |= self.LCD_DISPLAYON
        self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol)


    def noCursor(self):
        """ Turns the underline cursor on/off """
        self.displaycontrol &= ~self.LCD_CURSORON
        self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol)


    def cursor(self):
        """ Cursor On """
        self.displaycontrol |= self.LCD_CURSORON
        self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol)


    def noBlink(self):
        """ Turn on and off the blinking cursor """
        self.displaycontrol &= ~self.LCD_BLINKON
        self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol)


    def noBlink(self):
        """ Turn on and off the blinking cursor """
        self.displaycontrol &= ~self.LCD_BLINKON
        self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol)


    def DisplayLeft(self):
        """ These commands scroll the display without changing the RAM """
        self.write4bits(self.LCD_CURSORSHIFT | self.LCD_DISPLAYMOVE | self.LCD_MOVELEFT)

    def scrollDisplayRight(self):
        """ These commands scroll the display without changing the RAM """
        self.write4bits(self.LCD_CURSORSHIFT | self.LCD_DISPLAYMOVE | self.LCD_MOVERIGHT);


    def leftToRight(self):
        """ This is for text that flows Left to Right """
        self.displaymode |= self.LCD_ENTRYLEFT
        self.write4bits(self.LCD_ENTRYMODESET | self.displaymode);


    def rightToLeft(self):
        """ This is for text that flows Right to Left """
        self.displaymode &= ~self.LCD_ENTRYLEFT
        self.write4bits(self.LCD_ENTRYMODESET | self.displaymode)


    def autoscroll(self):
        """ This will 'right justify' text from the cursor """
        self.displaymode |= self.LCD_ENTRYSHIFTINCREMENT
        self.write4bits(self.LCD_ENTRYMODESET | self.displaymode)


    def noAutoscroll(self):
        """ This will 'left justify' text from the cursor """
        self.displaymode &= ~self.LCD_ENTRYSHIFTINCREMENT
        self.write4bits(self.LCD_ENTRYMODESET | self.displaymode)


    def write4bits(self, bits, char_mode=False):
        """ Send command to LCD """
        self.delayMicroseconds(1000) # 1000 microsecond sleep

        bits=bin(bits)[2:].zfill(8)

        self.GPIO.output(self.pin_rs, char_mode)

        for pin in self.pins_db:
            self.GPIO.output(pin, False)

        for i in range(4):
            if bits[i] == "1":
                self.GPIO.output(self.pins_db[::-1][i], True)

        self.pulseEnable()

        for pin in self.pins_db:
            self.GPIO.output(pin, False)

        for i in range(4,8):
            if bits[i] == "1":
                self.GPIO.output(self.pins_db[::-1][i-4], True)

        self.pulseEnable()


    def delayMicroseconds(self, microseconds):
        seconds = microseconds / float(1000000) # divide microseconds by 1 million for seconds
        sleep(seconds)


    def pulseEnable(self):
        self.GPIO.output(self.pin_e, False)
        self.delayMicroseconds(1)               # 1 microsecond pause - enable pulse must be > 450ns
        self.GPIO.output(self.pin_e, True)
        self.delayMicroseconds(1)               # 1 microsecond pause - enable pulse must be > 450ns
        self.GPIO.output(self.pin_e, False)
        self.delayMicroseconds(1)               # commands need > 37us to settle


    def message(self, text):
        """ Send string to LCD. Newline wraps to second line"""
        for char in text:
            if char == '\n':
                # self.write4bits(0xC0) # next line
                self.currline += 1
                if (self.currline >= self.numlines):
                        self.currline = self.numlines - 1
                self.setCursor(0, self.currline)
            else:
                self.write4bits(ord(char),True)

    def bar(self, val, limit=100, width=-1):
        """ Draw bargraph of filled for percent """
        if (width == -1):
            width = self.numcols
        bars = (width * 5 * val) / limit
        # print '%d: %d of %d\n' % (val, bars, width*5)
        for i in range(bars/5):
            self.write4bits(0x05, True)
        if (bars <> width*5):
                self.write4bits(bars%5, True)
                for i in range(width-int(bars/5+1)):
                    self.write4bits(0x00, True)

if __name__ == '__main__':
    lcd = CharLCD()

    # Using a 20x4 LCD
    lcd.begin(20,4);

    lcd.clear()
    lcd.message("++ Gertboard 20x4 ++\n    Standard LCD\n")
    lcd.message("Line 3 -- \0\1\2\3\4\5\n")
    lcd.message("Line 4 -- ")
    lcd.bar(50,width=10)


In the '__init__' function, I load the first 6 character generator locations with a vertical bar pattern for a bar graph display.

I am using a 20 character by 4 line LCD display. You can update the example at the end for your display width and line count.

Enjoy!
Bill
User avatar
Posts: 235
Joined: Mon Jan 23, 2012 2:09 pm
by kodak » Sat Jan 12, 2013 9:17 pm
bgreat wrote:Here is a modified version of code I picked up from the forums and online for an LCD class. I added a bar graph using custom characters.

Code: Select all
#!/usr/bin/python

#
# based on code from lrvick and LiquidCrystal
# lrvic - https://github.com/lrvick/raspi-hd44780/blob/master/hd44780.py
# LiquidCrystal - https://github.com/arduino/Arduino/blob/master/libraries/LiquidCrystal/LiquidCrystal.cpp
#

from time import sleep

class CharLCD:

    # commands
    LCD_CLEARDISPLAY            = 0x01
    LCD_RETURNHOME              = 0x02
    LCD_ENTRYMODESET            = 0x04
    LCD_DISPLAYCONTROL          = 0x08
    LCD_CURSORSHIFT             = 0x10
    LCD_FUNCTIONSET             = 0x20
    LCD_SETCGRAMADDR            = 0x40
    LCD_SETDDRAMADDR            = 0x80

    # flags for display entry mode
    LCD_ENTRYRIGHT              = 0x00
    LCD_ENTRYLEFT               = 0x02
    LCD_ENTRYSHIFTINCREMENT     = 0x01
    LCD_ENTRYSHIFTDECREMENT     = 0x00

    # flags for display on/off control
    LCD_DISPLAYON               = 0x04
    LCD_DISPLAYOFF              = 0x00
    LCD_CURSORON                = 0x02
    LCD_CURSOROFF               = 0x00
    LCD_BLINKON                 = 0x01
    LCD_BLINKOFF                = 0x00

    # flags for display/cursor shift
    LCD_DISPLAYMOVE             = 0x08
    LCD_CURSORMOVE              = 0x00

    # flags for display/cursor shift
    LCD_DISPLAYMOVE             = 0x08
    LCD_CURSORMOVE              = 0x00
    LCD_MOVERIGHT               = 0x04
    LCD_MOVELEFT                = 0x00

    # flags for function set
    LCD_8BITMODE                = 0x10
    LCD_4BITMODE                = 0x00
    LCD_2LINE                   = 0x08
    LCD_1LINE                   = 0x00
    LCD_5x10DOTS                = 0x04
    LCD_5x8DOTS                 = 0x00


    def __init__(self, pin_rs=25, pin_e=24, pins_db=[23, 17, 21, 22], GPIO = None):
        # Emulate the old behavior of using RPi.GPIO if we haven't been given
        # an explicit GPIO interface to use
        if not GPIO:
            import RPi.GPIO as GPIO
        self.GPIO = GPIO
        self.pin_rs = pin_rs
        self.pin_e = pin_e
        self.pins_db = pins_db

        self.GPIO.setmode(GPIO.BCM)
        self.GPIO.setup(self.pin_e, GPIO.OUT)
        self.GPIO.setup(self.pin_rs, GPIO.OUT)

        for pin in self.pins_db:
            self.GPIO.setup(pin, GPIO.OUT)

        self.write4bits(0x33) # initialization
        self.write4bits(0x32) # initialization
        self.write4bits(0x28) # 2 line 5x7 matrix
        self.write4bits(0x0C) # turn cursor off 0x0E to enable cursor
        self.write4bits(0x06) # shift cursor right

        self.displaycontrol = self.LCD_DISPLAYON | self.LCD_CURSOROFF | self.LCD_BLINKOFF

        self.displayfunction = self.LCD_4BITMODE | self.LCD_1LINE | self.LCD_5x8DOTS
        self.displayfunction |= self.LCD_2LINE

        """ Initialize to default text direction (for romance languages) """
        self.displaymode =  self.LCD_ENTRYLEFT | self.LCD_ENTRYSHIFTDECREMENT
        self.write4bits(self.LCD_ENTRYMODESET | self.displaymode) #  set the entry mode

        self.numlines = 2       # default to two line display
        self.currline = 0
        self.row_offsets = [ 0x00, 0x40, 0x14, 0x54 ]

        self.numcols = 16
        self.curcol = 0

        """ Initialize character generator for horizontal bar graph """
        self.write4bits(self.LCD_SETCGRAMADDR+0)
        for i in range(8):
            self.write4bits(0x00,True)
        self.write4bits(self.LCD_SETCGRAMADDR+8)
        for i in range(8):
            self.write4bits(0x10,True)
        self.write4bits(self.LCD_SETCGRAMADDR+16)
        for i in range(8):
            self.write4bits(0x18,True)
        self.write4bits(self.LCD_SETCGRAMADDR+24)
        for i in range(8):
            self.write4bits(0x1c,True)
        self.write4bits(self.LCD_SETCGRAMADDR+32)
        for i in range(8):
            self.write4bits(0x1e,True)
        self.write4bits(self.LCD_SETCGRAMADDR+40)
        for i in range(8):
            self.write4bits(0x1f,True)

        self.clear()

    def begin(self, cols, lines):
        if (lines > 1):
                self.numlines = lines
                self.displayfunction |= self.LCD_2LINE
                self.currline = 0
        self.numcols = cols
        self.curcol = 0


    def home(self):
        self.currline = 0
        self.write4bits(self.LCD_RETURNHOME) # set cursor position to zero
        self.delayMicroseconds(3000) # this command takes a long time!


    def clear(self):
        self.currline = 0
        self.write4bits(self.LCD_CLEARDISPLAY) # command to clear display
        self.delayMicroseconds(3000)    # 3000 microsecond sleep, clearing the display takes a long time


    def setCursor(self, col, row):
        self.row_offsets = [ 0x00, 0x40, 0x14, 0x54 ]

        if ( row > self.numlines ):
                row = self.numlines - 1 # we count rows starting w/0

        self.write4bits(self.LCD_SETDDRAMADDR | (col + self.row_offsets[row]))
        self.currline = row


    def noDisplay(self):
        """ Turn the display off (quickly) """
        self.displaycontrol &= ~self.LCD_DISPLAYON
        self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol)


    def display(self):
        """ Turn the display on (quickly) """
        self.displaycontrol |= self.LCD_DISPLAYON
        self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol)


    def noCursor(self):
        """ Turns the underline cursor on/off """
        self.displaycontrol &= ~self.LCD_CURSORON
        self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol)


    def cursor(self):
        """ Cursor On """
        self.displaycontrol |= self.LCD_CURSORON
        self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol)


    def noBlink(self):
        """ Turn on and off the blinking cursor """
        self.displaycontrol &= ~self.LCD_BLINKON
        self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol)


    def noBlink(self):
        """ Turn on and off the blinking cursor """
        self.displaycontrol &= ~self.LCD_BLINKON
        self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol)


    def DisplayLeft(self):
        """ These commands scroll the display without changing the RAM """
        self.write4bits(self.LCD_CURSORSHIFT | self.LCD_DISPLAYMOVE | self.LCD_MOVELEFT)

    def scrollDisplayRight(self):
        """ These commands scroll the display without changing the RAM """
        self.write4bits(self.LCD_CURSORSHIFT | self.LCD_DISPLAYMOVE | self.LCD_MOVERIGHT);


    def leftToRight(self):
        """ This is for text that flows Left to Right """
        self.displaymode |= self.LCD_ENTRYLEFT
        self.write4bits(self.LCD_ENTRYMODESET | self.displaymode);


    def rightToLeft(self):
        """ This is for text that flows Right to Left """
        self.displaymode &= ~self.LCD_ENTRYLEFT
        self.write4bits(self.LCD_ENTRYMODESET | self.displaymode)


    def autoscroll(self):
        """ This will 'right justify' text from the cursor """
        self.displaymode |= self.LCD_ENTRYSHIFTINCREMENT
        self.write4bits(self.LCD_ENTRYMODESET | self.displaymode)


    def noAutoscroll(self):
        """ This will 'left justify' text from the cursor """
        self.displaymode &= ~self.LCD_ENTRYSHIFTINCREMENT
        self.write4bits(self.LCD_ENTRYMODESET | self.displaymode)


    def write4bits(self, bits, char_mode=False):
        """ Send command to LCD """
        self.delayMicroseconds(1000) # 1000 microsecond sleep

        bits=bin(bits)[2:].zfill(8)

        self.GPIO.output(self.pin_rs, char_mode)

        for pin in self.pins_db:
            self.GPIO.output(pin, False)

        for i in range(4):
            if bits[i] == "1":
                self.GPIO.output(self.pins_db[::-1][i], True)

        self.pulseEnable()

        for pin in self.pins_db:
            self.GPIO.output(pin, False)

        for i in range(4,8):
            if bits[i] == "1":
                self.GPIO.output(self.pins_db[::-1][i-4], True)

        self.pulseEnable()


    def delayMicroseconds(self, microseconds):
        seconds = microseconds / float(1000000) # divide microseconds by 1 million for seconds
        sleep(seconds)


    def pulseEnable(self):
        self.GPIO.output(self.pin_e, False)
        self.delayMicroseconds(1)               # 1 microsecond pause - enable pulse must be > 450ns
        self.GPIO.output(self.pin_e, True)
        self.delayMicroseconds(1)               # 1 microsecond pause - enable pulse must be > 450ns
        self.GPIO.output(self.pin_e, False)
        self.delayMicroseconds(1)               # commands need > 37us to settle


    def message(self, text):
        """ Send string to LCD. Newline wraps to second line"""
        for char in text:
            if char == '\n':
                # self.write4bits(0xC0) # next line
                self.currline += 1
                if (self.currline >= self.numlines):
                        self.currline = self.numlines - 1
                self.setCursor(0, self.currline)
            else:
                self.write4bits(ord(char),True)

    def bar(self, val, limit=100, width=-1):
        """ Draw bargraph of filled for percent """
        if (width == -1):
            width = self.numcols
        bars = (width * 5 * val) / limit
        # print '%d: %d of %d\n' % (val, bars, width*5)
        for i in range(bars/5):
            self.write4bits(0x05, True)
        if (bars <> width*5):
                self.write4bits(bars%5, True)
                for i in range(width-int(bars/5+1)):
                    self.write4bits(0x00, True)

if __name__ == '__main__':
    lcd = CharLCD()

    # Using a 20x4 LCD
    lcd.begin(20,4);

    lcd.clear()
    lcd.message("++ Gertboard 20x4 ++\n    Standard LCD\n")
    lcd.message("Line 3 -- \0\1\2\3\4\5\n")
    lcd.message("Line 4 -- ")
    lcd.bar(50,width=10)


In the '__init__' function, I load the first 6 character generator locations with a vertical bar pattern for a bar graph display.

I am using a 20 character by 4 line LCD display. You can update the example at the end for your display width and line count.

Enjoy!
Bill


yes this works but how du i change the symbol
to exempel an node or a bell -symbol?
Posts: 58
Joined: Wed Dec 26, 2012 6:20 pm
by bgreat » Sat Jan 12, 2013 11:06 pm
I initialize the characters I use for the bar graph here:
Code: Select all
        """ Initialize character generator for horizontal bar graph """
        self.write4bits(self.LCD_SETCGRAMADDR+0)
        for i in range(8):
            self.write4bits(0x00,True)
        self.write4bits(self.LCD_SETCGRAMADDR+8)
        for i in range(8):
            self.write4bits(0x10,True)
        self.write4bits(self.LCD_SETCGRAMADDR+16)
        for i in range(8):
            self.write4bits(0x18,True)
        self.write4bits(self.LCD_SETCGRAMADDR+24)
        for i in range(8):
            self.write4bits(0x1c,True)
        self.write4bits(self.LCD_SETCGRAMADDR+32)
        for i in range(8):
            self.write4bits(0x1e,True)
        self.write4bits(self.LCD_SETCGRAMADDR+40)
        for i in range(8):
            self.write4bits(0x1f,True)

I am initializing the first six character generator entries with symbols for a bar graph. Each character is made up of 8 bytes, where the binary bits define the dot state. A bit set to '1' is on and a bit set to '0' is off. Each character is 5 dots wide and 8 dots high. I store the same character pattern for every row of the special character to make a vertical bar that fills from left to right.

For character 0x03 (at offset 24), I store a 0x1c at all 8 locations. This gives:
Code: Select all
CG+24: 0x1c = . . . X X X - -
CG+25: 0x1c = . . . X X X - -
CG+26: 0x1c = . . . X X X - -
CG+27: 0x1c = . . . X X X - -
CG+28: 0x1c = . . . X X X - -
CG+29: 0x1c = . . . X X X - -
CG+30: 0x1c = . . . X X X - -
CG+31: 0x1c = . . . X X X - -


To get something different, just define the pattern you want. As an example for character code 0x07 (at offset 56):
Code: Select all
CG+56: 0x00 = . . . - - - - -
CG+57: 0x04 = . . . - - X - -
CG+58: 0x0e = . . . - X X X -
CG+59: 0x0a = . . . - X - X -
CG+60: 0x11 = . . . X - - - X
CG+61: 0x1f = . . . X X X X X
CG+62: 0x16 = . . . - - X X -
CG+63: 0x00 = . . . - - - - -

:D My crude attempt at a bell shape :D

A good way of designing the characters by hand is to use a piece of graph paper. Mark out a 5x8 grid. Fill in the dots you want as black, then write out the binary representation. Then convert the binary to hexadecimal or decimal. Put this in an array to transfer to the character generator.

Example (following not tested... my Pi does not have the LCD connected right now):
Code: Select all
    cgBell = [0x00,0x04,0x0e,0x0a,0x11,0x11,0x1f,0x16,0x00]
    self.write4bits(self.LCD_SETCGRAMADDR+56)
    for b in cgBell:
        self.write4bits(b,True)

Now, anywhere you output a 0x07 character to the display, you will have a "bell" character.

Code: Select all
  lcd.clear()
  lcd.message(" Bells ringing\n    \x07 \x07 \x07")

Should display the new character on the second line of the display three times.

Enjoy!
Bill
User avatar
Posts: 235
Joined: Mon Jan 23, 2012 2:09 pm
by bgreat » Sun Jan 13, 2013 1:19 am
Small typo... should be:
Code: Select all
    cgBell = [0x00,0x04,0x0e,0x0a,0x11,0x1f,0x16,0x00]


Enjoy!
Bill
User avatar
Posts: 235
Joined: Mon Jan 23, 2012 2:09 pm
by kodak » Sun Jan 13, 2013 3:18 pm
and i am back to not working.
Posts: 58
Joined: Wed Dec 26, 2012 6:20 pm
by bgreat » Sun Jan 13, 2013 3:31 pm
Go back to the prior version of code that was working for you. Confirm it is still working. Then, make a backup, and add the lines for setting up the other character generator location and accessing. Note that I did not confirm the indent on the code I posted. You will need to put it in the code with the correct indent.

If you still have problems, post the error message, your code, and I will hook my display up again this evening and check it out.

BTW. I tried the bell graphic with a different LCD (84x48 graphics) and it is passable. :shock:

Enjoy!
Bill
User avatar
Posts: 235
Joined: Mon Jan 23, 2012 2:09 pm
by bgreat » Sun Jan 13, 2013 7:59 pm
OK. Hooked an LCD display back to the Pi to check the CGRAM code.

:oops: Found another typo. Should read:
Code: Select all
    cgBell = [0x00,0x04,0x0e,0x0a,0x11,0x1f,0x06,0x00]

0x06 instead of 0x16...

Here's the output from the example with text updated for a 20x4 LCD:
CGRAM_small.jpg
CGRAM Example Output
CGRAM_small.jpg (62.46 KiB) Viewed 1446 times

Line 3 shows the custom characters (added a degree symbol as character 0x06 in addition to the bell at 0x07). On line 4 is an example bar graph.

Enjoy!
Bill
User avatar
Posts: 235
Joined: Mon Jan 23, 2012 2:09 pm
by -rst- » Mon Jan 14, 2013 2:56 pm
Nice one ...though the bar graph at 55% or maybe 52% would have demoed better ;)
http://raspberrycompote.blogspot.com/ - Low-level graphics and 'Coding Gold Dust'
Posts: 900
Joined: Thu Nov 01, 2012 12:12 pm
Location: Dublin, Ireland
by bgreat » Mon Jan 14, 2013 8:06 pm
:D I know... but it was a quick test. I was busy testing various outputs and 50% was my last test. :D

I implemented to provide a CPU load % display. Very handy.

Enjoy!
Bill
User avatar
Posts: 235
Joined: Mon Jan 23, 2012 2:09 pm
by rickseiden » Mon Jan 14, 2013 8:14 pm
bgreat wrote::D I know... but it was a quick test. I was busy testing various outputs and 50% was my last test. :D

I implemented to provide a CPU load % display. Very handy.

Enjoy!
Bill


One would imagine measuring CPU usage this way is much like trying to measure quantum particles. The act of measuring it, changes it. :P
There are 10 types of people in this world. Those that understand binary, and those that don't.
Posts: 398
Joined: Thu Aug 02, 2012 12:21 pm
Location: Buffalo, NY, USA