PCF8574 + 20x4 LCD help


8 posts
by Boezelman » Tue Oct 09, 2012 7:15 pm
Hi guys,

I "upgraded" my 16x2 LCD (which I controlled with a PCF857) to this -->20x4 LCD with I2C controller

But I can't figure out how to change the pins in the python program (I really don't understand the -->PCF8574 datasheet)

My "old LCD" uses this pin-out
Code: Select all
   P0 -  - D4
   P1 -  - D5   
   P2 -  - D6
   P3 -  - D7   
   P4 -   - RS
   P5 -   - R/W   
   P6 -   - E   

My new LCD uses this pin-out
Code: Select all
   P0 -  - RS
   P1 -  - RW   
   P2 -  - E
   P4 -  - D4    
   P5 -   - D5
   P6 -   - D6
   P7 -   - D7      

The thing I don't understand is, where and how are the pins defined and how do I change them to my needs?

Old program that worked great with the 16x2 LCD
Code: Select all
import smbus
from time import *

# General i2c device class so that other devices can be added easily
class i2c_device:
   def __init__(self, addr, port):
      self.addr = addr
      self.bus = smbus.SMBus(port)

   def write(self, byte):
      self.bus.write_byte(self.addr, byte)

   def read(self):
      return self.bus.read_byte(self.addr)

   def read_nbytes_data(self, data, n): # For sequential reads > 1 byte
      return self.bus.read_i2c_block_data(self.addr, data, n)


class lcd:
   #initializes objects and lcd
   '''
   pinout is as follows: PCF8574 - HD44780
   P0 - LCD11 - D4
   P1 - LCD12 - D5   
   P2 - LCD13 - D6
   P3 - LCD14 - D7   
   P4 - LCD4  - RS
   P5 - LCD5  - R/W   
   P6 - LCD6  - E   
   '''
   def __init__(self, addr, port):
      self.lcd_device = i2c_device(addr, port)
      self.lcd_device.write(0x03)
      self.lcd_strobe()
      sleep(0.0005)
      self.lcd_strobe()
      sleep(0.0005)
      self.lcd_strobe()
      sleep(0.0005)
      self.lcd_device.write(0x02)
      self.lcd_strobe()
      sleep(0.0005)

      self.lcd_write(0x28)
      self.lcd_write(0x08)
      self.lcd_write(0x01)
      self.lcd_write(0x06)
      self.lcd_write(0x0C)

      self.lcd_write(0x0F)

   # clocks EN to latch command
   def lcd_strobe(self):
      self.lcd_device.write((self.lcd_device.read() | 0x40))
      self.lcd_device.write((self.lcd_device.read() & 0xbF))

   # write a command to lcd
   def lcd_write(self, cmd):
      self.lcd_device.write((cmd >> 4))
      hi= self.lcd_device.read()
      self.lcd_strobe()
      self.lcd_device.write((cmd & 0x0F))
      lo= self.lcd_device.read()
      self.lcd_strobe()
      self.lcd_device.write(0x0)
   #   print 'cmd',cmd,hi,lo

   # write a character to lcd (or character rom)
   def lcd_write_char(self, charvalue):
   #      print "char",charvalue
         self.lcd_device.write((0x10 | (charvalue >> 4)))
         self.lcd_strobe()
         self.lcd_device.write((0x10 | (charvalue & 0x0F)))
         self.lcd_strobe()
         self.lcd_device.write(0x0)

   # put char function
   def lcd_putc(self, char):
      self.lcd_write_char(ord(char))

   # put string function
   def lcd_puts(self, string, line):
      if line == 1:
         self.lcd_write(0x10)
      if line == 2:
         self.lcd_write(0xC0)
      if line == 3:
         self.lcd_write(0x94)
      if line == 4:
         self.lcd_write(0xD4)

      for char in string:
         self.lcd_putc(char)

   # clear lcd and set to home
   def lcd_clear(self):
      self.lcd_write(0x1)
      self.lcd_write(0x2)

   # add custom characters (0 - 7)
   def lcd_load_custon_chars(self, fontdata):
      self.lcd_device.bus.write(0x40);
      for char in fontdata:
         for line in char:
            self.lcd_write_char(line)
Posts: 40
Joined: Sun Aug 05, 2012 3:25 pm
by Serac » Wed Oct 10, 2012 12:17 am
Code: Select all
   # clocks EN to latch command
   def lcd_strobe(self):
         self.lcd_device.write((self.lcd_device.read() | 0x04))
         self.lcd_device.write((self.lcd_device.read() & 0xFB))

   # write a command to lcd
   def lcd_write(self, cmd):
      self.lcd_device.write((cmd & 0xF0))
      hi= self.lcd_device.read()
      self.lcd_strobe()
      self.lcd_device.write((cmd << 4))
      lo= self.lcd_device.read()
      self.lcd_strobe()
      self.lcd_device.write(0x0)
   # write a character to lcd (or character rom)
   def lcd_write_char(self, charvalue):
         self.lcd_device.write((0x01 | (charvalue & 0xF0)))
         self.lcd_strobe()
         self.lcd_device.write((0x01 | (charvalue << 4)))
         self.lcd_strobe()
         self.lcd_device.write(0x0)

...Should get you close - The main difference is the data is transmitted in the upper nibble whilst the control lines are on the lower nibble with your new module. So it is just a case of shifting the data in the other direction and swapping the hexadecimal numbers round.
Posts: 124
Joined: Wed Jul 18, 2012 2:49 pm
by Boezelman » Wed Oct 10, 2012 6:14 pm
Thanks for your replay and code! I will try it soon!

The thing that's really bugging me is:

I thought I'd only needed to change the hexadecimal adresses of the PCF8574 to match the connection on my new LCD (P0,1,2,3,4,5,6,7) But I can't figure out where the addresses are defined in the python code.
And I can't find / don't understand the datasheet to see the addresses of P0,1,2,3,4,5,6,7.

What i'm trying to figure out is:

for example:
Code: Select all
Pin       Input        Output
P0        0x3F         0x33
P1        0x8E         0x12
etc.
etc.
Posts: 40
Joined: Sun Aug 05, 2012 3:25 pm
by Boezelman » Wed Oct 10, 2012 6:56 pm
Boezelman wrote:Thanks for your replay and code! I will try it soon!


Your code work great, thanks.
only problem is that the backlight LED goes out when I run the code!?!
So maybe it's connected to 1 of the PCF8574 pins?

* well almost great, the lcd stay blank sometime and also showing some strange characters..

But hey, better then nothing right?! :)
Last edited by Boezelman on Wed Oct 10, 2012 7:13 pm, edited 1 time in total.
Posts: 40
Joined: Sun Aug 05, 2012 3:25 pm
by techpaul » Wed Oct 10, 2012 7:11 pm
Boezelman wrote:Thanks for your replay and code! I will try it soon!

The thing that's really bugging me is:

I thought I'd only needed to change the hexadecimal adresses of the PCF8574 to match the connection on my new LCD (P0,1,2,3,4,5,6,7) But I can't figure out where the addresses are defined in the python code.
And I can't find / don't understand the datasheet to see the addresses of P0,1,2,3,4,5,6,7.
Firstly you are giving things the wrong names so it will be confusing to match anyuthing in datasheet or code.

PCF89574 has an I2C address to slect it on the I2C bus of which 3 bits match the A0-A2 pins on the PCF8574.

The data I/O pins on the PCF8574 have names P0 to P7 matching data bit 0 to data bit 7 in a data byte sent on I2C to the PCF8574, when it is addressed.
Boezelman wrote:]What i'm trying to figure out is:

for example:
Code: Select all
Pin       Input        Output
P0        0x3F         0x33
P1        0x8E         0x12
etc.
P0 is bit 0 has value of 1 (almost any number base)
P1 is bit 1 has value of 2
through to
P6 is bit 6 has value of 64 (hex 0x40)
P7 is bit 7 has value of 128 (hex 0x80)

What each data bit represents to the outside world is down to how the PCF8574 is wired up.
Just another techie on the net - For GPIO boards see http:///www.facebook.com/pcservicesreading
or http://www.pcserviceselectronics.co.uk/pi/
Posts: 1509
Joined: Sat Jul 14, 2012 6:40 pm
Location: Reading, UK
by Boezelman » Wed Oct 10, 2012 7:31 pm
Thanks for you explanation!

So if i get it right:
Code: Select all
            7 - 128 - 0x80
            6 - 64   - 0x40
            5 - 32   - 0x20
            4 - 16   - 0x10
            3 - 8     - 0x08
            2 - 4     - 0x04
            1 - 2     - 0x02
            0 - 1     - 0x01


Would complete the list?!

One step closer in "understanding" the code rather than just "copy/past" and go: Whow it works! :)
Posts: 40
Joined: Sun Aug 05, 2012 3:25 pm
by techpaul » Wed Oct 10, 2012 8:12 pm
Yes standard bit weightings for binary to deciaml and hexadecimal.
Just another techie on the net - For GPIO boards see http:///www.facebook.com/pcservicesreading
or http://www.pcserviceselectronics.co.uk/pi/
Posts: 1509
Joined: Sat Jul 14, 2012 6:40 pm
Location: Reading, UK
by ufux » Sun Jul 28, 2013 1:01 pm
Even this post is a little bit old ... I started with the code and the hints here, but I thought there is space for improvement. So I double checked the documentation of the HD44780U controller and modified the code. It works with and without backlight and it also allows to not double initialize after the display had been powered once. Check it out here: https://gist.github.com/ufux/6094977

Hope this is helpful.

Ufux
Posts: 2
Joined: Sun Jul 28, 2013 12:57 pm