natbett
Posts: 6
Joined: Mon Feb 18, 2013 9:42 pm

20x4 i2c lcd lines out of order.

Mon Feb 18, 2013 10:06 pm

I've been working with this 20x4 i2c LCD from Sainsmart (i2c board is branded that, LCD board is labeled J204A) The problem I am having is when I write out to it, if the line is over 20 characters it doesn't flow over onto the next line. It skips a line (Attached image shows) and I'm not entirely sure why. The driver I'm using is basically the Arduino driver converted to python by an Amazon reviewer. Here is the code I've been using, any help is appreciated.

i2c_lib.py:

Code: Select all

import smbus
from time import *

class i2c_device:
	def __init__(self, addr, port=1):
		self.addr = addr
		self.bus = smbus.SMBus(port)	

# Write a single command
	def write_cmd(self, cmd):
		self.bus.write_byte(self.addr, cmd)
		sleep(0.0001)

# Write a command and argument
	def write_cmd_arg(self, cmd, data):
		self.bus.write_byte_data(self.addr, cmd, data)
		sleep(0.0001)

# Write a block of data
	def write_block_data(self, cmd, data):
		self.bus.write_block_data(self.addr, cmd, data)
		sleep(0.0001)

# Read a single byte
	def read(self):
		return self.bus.read_byte(self.addr)

# Read 
	def read_data(self, cmd):
		return self.bus.read_byte_data(self.addr, cmd)

# Read a block of data
	def read_block_data(self, cmd):
		return self.bus.read_block_data(self.addr, cmd)
lcddriver.py:

Code: Select all

import i2c_lib
from time import *

# LCD Address
ADDRESS = 0x3f

# 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
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

# flags for backlight control
LCD_BACKLIGHT = 0x08
LCD_NOBACKLIGHT = 0x00

En = 0b00000100 # Enable bit
Rw = 0b00000010 # Read/Write bit
Rs = 0b00000001 # Register select bit

class lcd:
	#initializes objects and lcd
	def __init__(self):
		self.lcd_device = i2c_lib.i2c_device(ADDRESS)

		self.lcd_write(0x03)
		self.lcd_write(0x03)
		self.lcd_write(0x03)
		self.lcd_write(0x02)

		self.lcd_write(LCD_FUNCTIONSET | LCD_2LINE | LCD_5x8DOTS | LCD_4BITMODE)
		self.lcd_write(LCD_DISPLAYCONTROL | LCD_DISPLAYON)
		self.lcd_write(LCD_CLEARDISPLAY)	
		self.lcd_write(LCD_ENTRYMODESET | LCD_ENTRYLEFT)
		sleep(0.2)	

	# clocks EN to latch command
	def lcd_strobe(self, data):
		self.lcd_device.write_cmd(data | En | LCD_BACKLIGHT)
		sleep(.0005)
		self.lcd_device.write_cmd(((data & ~En) | LCD_BACKLIGHT))
		sleep(.0001)	

	def lcd_write_four_bits(self, data):
		self.lcd_device.write_cmd(data | LCD_BACKLIGHT)
		self.lcd_strobe(data)

	# write a command to lcd
	def lcd_write(self, cmd, mode=0):
		self.lcd_write_four_bits(mode | (cmd & 0xF0))
		self.lcd_write_four_bits(mode | ((cmd << 4) & 0xF0))

	# put string function
	def lcd_display_string(self, string, line):
		if line == 1:
			self.lcd_write(0x80)
		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_write(ord(char), Rs)

	# clear lcd and set to home
	def lcd_clear(self):
		self.lcd_write(LCD_CLEARDISPLAY)
		self.lcd_write(LCD_RETURNHOME)
lcd.py:

Code: Select all

import lcddriver
from time import *

lcd = lcddriver.lcd()

lcd.lcd_display_string("11111111111111111111222222222222222222223333333333333333333344444444444444444444", 1)
Attachments
rpi_lcd.jpg
rpi_lcd.jpg (44.06 KiB) Viewed 21879 times

User avatar
Feyd
Posts: 5
Joined: Tue Dec 25, 2012 5:46 pm
Location: Poland
Contact: Website

Re: 20x4 i2c lcd lines out of order.

Tue Feb 19, 2013 12:18 am

Hi,

Usually the LCD has a buffer for a single line longer than the number of characters to display, so you could shift them. Try to play with "LCD_CURSORSHIFT" command from your code.

Take a look on the internals of lcd_display_string() function and you will notice, that to move to next line it issues 0xC0 command. So, or you start using the 'line' parameter correctly, setting the 0..4 or you can create own 'lcd_display_text()' function, that will scan your input text and in case of '\n', issue the 0xC0 automatically.

Cheers,
Paweł

User avatar
bgreat
Posts: 235
Joined: Mon Jan 23, 2012 2:09 pm

Re: 20x4 i2c lcd lines out of order.

Tue Feb 19, 2013 1:32 am

The display and code are working correctly. The standard character addressing for a 20 character by 4 line display with an HD44780 controller is:
LCD-20x4-memory(b).gif
LCD-20x4-memory(b).gif (4.61 KiB) Viewed 21865 times
If you sequentially write 80 characters to the display, they will display on line 1, followed by line 3, followed by line 2, followed by line 4.

If you want to have line wrapping in your expected top to bottom order, you need to provide your own code to update the next character address after the last character of a line has been written.

Enjoy!
Bill

User avatar
recantha2
Posts: 259
Joined: Wed Nov 14, 2012 9:34 am
Location: Potton, Bedfordshire
Contact: Website

Re: 20x4 i2c lcd lines out of order.

Fri Jun 28, 2013 8:16 pm

natbett, you're a genius. Thank you. I got this one from Hobby Components:
http://www.hobbycomponents.com/index.ph ... uct_id=285
And your code works brilliantly. Thank you!
--
Michael Horne - @recantha
Raspberry Pi blog - http://www.recantha.co.uk/blog

Cambridge Raspberry Jam
Website: http://camjam.me
Facebook: https://www.facebook.com/cambridgeraspberryjam
Follow the Cambridge Raspberry Jam on Twitter - @cambridgejam

lolouk44
Posts: 25
Joined: Sat Oct 20, 2012 11:01 pm

Re: 20x4 i2c lcd lines out of order.

Tue Jul 02, 2013 6:47 am

Hi @nabett,

I've been trying to drive the same LCD (Sainsmart 20x4 I2C).
When I run your code, I get this message:
Image

Any idea?

Also just out of interest, can you confirm how you've wired your LCD screen? Is it powered by +5V or +3.3V? (mine only gets detected if powered by +3.3V)

MdeJong
Posts: 4
Joined: Tue Jul 02, 2013 7:58 pm

Re: 20x4 i2c lcd lines out of order.

Tue Jul 02, 2013 8:06 pm

Hello,

I had the same problem with the i2c backpack and a 6x20 LCD: http://learn.adafruit.com/i2c-spi-lcd-backpack

You will need a level convert for the I2C bus.

The raspberry PI is 3,3 Volt, but the display needs 5 volt.

After I used the P82B96 Level converter it is working.

See the Fig.10 on page 10 on the datasheet: http://www.nxp.com/documents/data_sheet/P82B96.pdf

Regards Mark,

lolouk44
Posts: 25
Joined: Sat Oct 20, 2012 11:01 pm

Re: 20x4 i2c lcd lines out of order.

Sun Jul 21, 2013 3:47 pm

lolouk44 wrote:Hi @nabett,

I've been trying to drive the same LCD (Sainsmart 20x4 I2C).
When I run your code, I get this message:
Image

Any idea?

Also just out of interest, can you confirm how you've wired your LCD screen? Is it powered by +5V or +3.3V? (mine only gets detected if powered by +3.3V)

Been busy but found out the issue. I've got a Rev1 board and by default the port was set to 1 when I needed port 0.
For those with the same issue, edit i2c_lib.py and on line 8 change def __init__(self, addr, port=1): to def __init__(self, addr, port=0):

lolouk44
Posts: 25
Joined: Sat Oct 20, 2012 11:01 pm

Re: 20x4 i2c lcd lines out of order.

Sun Jul 21, 2013 3:54 pm

MdeJong wrote:Hello,

I had the same problem with the i2c backpack and a 6x20 LCD: http://learn.adafruit.com/i2c-spi-lcd-backpack

You will need a level convert for the I2C bus.

The raspberry PI is 3,3 Volt, but the display needs 5 volt.

After I used the P82B96 Level converter it is working.

See the Fig.10 on page 10 on the datasheet: http://www.nxp.com/documents/data_sheet/P82B96.pdf

Regards Mark,
Hi MdeJong,
I bought the P82B96 but for me it does not seem to work. Maybe I did something wrong with the wiring. Anyway I managed to get the LCD to work when powered on 3.3v. Using the same LCD as OP.

smithypi
Posts: 1
Joined: Tue Aug 20, 2013 1:36 pm

Re: 20x4 i2c lcd lines out of order.

Tue Aug 20, 2013 1:50 pm

I've tried to use your code to run my own J204A LCD. I've worked through various errors, but I cannot solve this one.

Can anyone share any insight? Thanks.

Code: Select all

 [email protected] ~/projects/python/lcd $ python lcd.py
Traceback (most recent call last):
  File "lcd.py", line 4, in <module>
    lcd = lcddriver.lcd()
  File "/home/pi/projects/python/lcd/lcddriver.py", line 56, in __init__
    self.lcd_device = i2c_lib.i2c_device(ADDRESS)
  File "/home/pi/projects/python/lcd/i2c_lib.py", line 7, in __init__
    self.bus = smbus.SMBus(port)
IOError: [Errno 2] No such file or directory
[email protected] ~/projects/python/lcd $ ^C
[email protected] ~/projects/python/lcd $ 
 

rafasgj
Posts: 1
Joined: Sat Apr 19, 2014 11:48 pm

Re: 20x4 i2c lcd lines out of order.

Sat Apr 19, 2014 11:53 pm

Thank you very much for this!
I've been fighting an I2C HD44780 LCD Display for nearly a week and your code made it finally work.

prodrigue
Posts: 2
Joined: Tue Jul 08, 2014 3:36 pm

Re: 20x4 i2c lcd lines out of order.

Sun Sep 07, 2014 4:52 am

Hi.

I'm using this code, and is working well.

However i would like to make scroll in different directions.

I only can do simple things like that.

lcd.lcd_display_string(strftime('%d-%m-%Y %H:%M:%S'), 1)
lcd.lcd_display_string(' IP: %s' % address, 2)
lcd.lcd_display_string(' IP: %s' % get_inet_ips(), 3)
lcd.lcd_display_string('RAM:{} {} {}'.format(totalRAM, usedRAM, percentRAM),4)

Wich code i must add to do text scrolling from right to left for example ?

I would like to show twitter messages scrolling in one line, but i don't see other way of showing that without scrolling it.

And about use custom characters ? is possible ? Is possible show time using 20x4 display in 4 lines with big numbers.

suppenfritz
Posts: 1
Joined: Mon Dec 15, 2014 8:12 am

Re: 20x4 i2c lcd lines out of order.

Mon Dec 15, 2014 8:23 am

:idea: Add this function for char(s) positioning on LCD into file: lcddriver.py:

Code: Select all

   def lcd_display_string_pos(self, string, line, pos):
      if line == 1:
          pos_new = pos
      elif line == 2:
          pos_new = 0x40 + pos
      elif line == 3:
          pos_new = 0x14 + pos
      elif line == 4:
          pos_new = 0x54 + pos

      self.lcd_write(0x80 + pos_new)

      for char in string:
         self.lcd_write(ord(char), Rs)

drzume
Posts: 1
Joined: Tue Jan 13, 2015 9:17 pm

Re: 20x4 i2c lcd lines out of order.

Tue Jan 13, 2015 9:26 pm

This code works for me fine. But I like to switch off and on backlight.

I tried with additional code inside lcddriver.py without success:

Code: Select all

   def lcd_led_off(self):
      self.lcd_write(LCD_NOBACKLIGHT)

   def lcd_led_on(self):
      self.lcd_write(LCD_BACKLIGHT)
Any idea how to turn on/off lcd backlight

denis_hr
Posts: 17
Joined: Fri Jun 06, 2014 1:11 pm
Location: Croatia
Contact: Website

Re: 20x4 i2c lcd lines out of order.

Sun Feb 08, 2015 4:43 pm

drzume wrote:This code works for me fine. But I like to switch off and on backlight.

I tried with additional code inside lcddriver.py without success:
I use this one, and it works (lifted it from somewhere else, not sure where... so, it's not my code...):

Code: Select all

# define backlight on/off (lcd.backlight(1); off= lcd.backlight(0)
   def backlight(self, state): # for state, 1 = on, 0 = off
      if state == 1:
         self.lcd_device.write_cmd(LCD_BACKLIGHT)
      elif state == 0:
         self.lcd_device.write_cmd(LCD_NOBACKLIGHT)
And I use it like this in my Python code:

Code: Select all

lcd.backlight(0)
or

Code: Select all

lcd.backlight(1)
Simple...

On the other hand, has anyone been able to find out how to use custom characters with this I2C LCD?
Banging my head for the past couple of days.... :(
I need a couple of custom characters, but this library has no custom char function, and my attempts so far to make some other snippets work have not been successful...

denis_hr
Posts: 17
Joined: Fri Jun 06, 2014 1:11 pm
Location: Croatia
Contact: Website

Re: 20x4 i2c lcd lines out of order.

Mon Feb 09, 2015 3:48 pm

After some serious hacking (hah! just joking, I'm out of my depth here...), I've created a new, modified library for this type of LCDs (the ones which use I2C, as described above).
I've joined two previous libraries (i2c_lib.py and lcddriver.py) into a single library: RPi_I2C_driver.py
I've put it on Gist, together with a test script with some examples.

Most of it was lifted from other people's publicly accessible code, so I really can't take credit for this.

Anyway, it enables you to create and use custom characters - in the example script on gist I've shown how to use several "sets" of custom characters in the same script. There's also an example of a "progress bar" using custom characters, which is the actual reason why I went into this in the first place :)
The link is: https://gist.github.com/DenisFromHR/cc8 ... e19dce359d
Hope this helps someone else, too.

There is surely room for improvement: I'm not a programmer, and I'm also a beginner in Python :)
If you do make any improvements, please share!
Thanks and regards,
Denis

BMS Doug
Posts: 3824
Joined: Thu Mar 27, 2014 2:42 pm
Location: London, UK

Re: 20x4 i2c lcd lines out of order.

Sat Oct 01, 2016 11:13 pm

A bit of a post necromancy but I found the thread very handy, I modified the sample code a bit, to display keyboard input.

Code: Select all

import lcddriver
from time import *

lcd = lcddriver.lcd()

# initial display values
line1 = "initialising"
line2 = "enter desired text"
line3 = "max 20 characters"
line4 = "per line"
blankline = "                    " # used to overwrite existing characters on a line

while True:
    lcd.lcd_display_string(line1, 1)
    lcd.lcd_display_string(line2, 2)
    lcd.lcd_display_string(line3, 3)
    lcd.lcd_display_string(line4, 4)

    inputText = raw_input("Input Text: ")
    longText = inputText + blankline
    line4 = line3
    line3 = line2
    line2 = line1
    line1 = longText [0:20]
Doug.
Building Management Systems Engineer.

bertoteo
Posts: 2
Joined: Mon Sep 05, 2016 12:24 pm

Re: 20x4 i2c lcd lines out of order.

Sun Mar 19, 2017 1:15 pm

When trying the "llcd.backlight(0)" command, the lcd become black but nothing is displayed.
In the driver.py file both LCD_DISPLAYOFF and LCD_NOBACKLIGHT constants are the same value 0x00
It's possible to show up text with backlight off?
Thanks

dre3ed
Posts: 25
Joined: Tue Mar 28, 2017 8:29 pm

Re: 20x4 i2c lcd lines out of order.

Thu Mar 30, 2017 2:57 pm

bump on the lcd backlight ?

Fusseldieb
Posts: 1
Joined: Mon May 08, 2017 2:49 pm

Re: 20x4 i2c lcd lines out of order.

Mon May 08, 2017 3:44 pm

dre3ed wrote:bump on the lcd backlight ?
Yeah, it's quite easy...
When copying and pasting code, you should at least read those files, because they contain some useful information...
The backlight is already coded in the lcddriver.py, just not used.
When you look inside the file, you'll find:

Code: Select all

# flags for backlight control
LCD_BACKLIGHT = 0x08
LCD_NOBACKLIGHT = 0x00
And now you'll be asking: How do I implement that? How do I send those code to the I2C module? It's simple...
Later in the code, you'll see that every command is sent to the I2C with:

Code: Select all

self.lcd_write( ... )
So... Since we already have the codes declared at the beginning, we can use "LCD_BACKLIGHT" or "LCD_NOBACKLIGHT" to change the backlight of the LCD (Instead those 0x codes).
Now you have two options:
[*]Write the code directly into your python script, leaving lcddriver.py untouched...
or
[*]Implement the code cleanly into the lcddriver.py
Both ways are easy to do!

Smashing the code directly into your python script, can be done writing this:

Code: Select all

lcd.lcd_write( LCD_BACKLIGHT )
and later to turn of... You guessed it:

Code: Select all

lcd.lcd_write( LCD_NOBACKLIGHT )
If you want to do it more clean, you can implement it cleanly into the lcddriver.py, adding those lines of code below at the end of the file:

Code: Select all

   def lcd_setBacklight(self, state):
      if state == 1:
         self.lcd_write(LCD_BACKLIGHT)
      elif state == 0:
         self.lcd_write(LCD_NOBACKLIGHT)
And we use it in our script like this:

Code: Select all

lcd.lcd_setBacklight(0)
On mine it happened that the screen got blank, but the backlight LED don't turned off. Sooo... I've looked into someones Arduino I2C LCD library and found out that...:

Code: Select all

// Turn the integrated backlight off/on

// setBacklight
void LiquidCrystal_I2C_ByVac::setBacklight( uint8_t value ) 
{
  Wire.beginTransmission(_Addr);
  Wire.write(0x03); 					//  ByVac command code 0x03 for backlight
  if (value==0) Wire.write(1); else Wire.write((byte)0); 	// 1 for off since polarity is NEGATIVE
  Wire.endTransmission();
}
... they write "0x03" and then later a "1" or a "0 (Byte)" to turn it off or on. Notice that they also commented "1 for off since polarity is NEGATIVE", so that make some sense too.
(But Fusseldieb, wait! Why are you using someones Arduino library? This has nothing to do with python and raspberry!!
Yes, it has. I used Arduino and there the library works just fine with the backlight, so I used the codes that I found and ported it into python. Simple.)

Continuing... Reading lcddriver.py a bit more, I found out that to send multiple bytes they used:

Code: Select all

self.lcd_device.write_cmd( ... | ... )
I think now you guessed it again, we can simply smash following in your python script:

Code: Select all

lcd.lcd_device.write_cmd( 0x03 | 1 )
And it will turn off. And to turn on:

Code: Select all

lcd.lcd_device.write_cmd( 0x03 | 0xFF )
FOR THE LAZY AND CTRL+C + CTRL+V GUYS, BEGIN READING HERE:
(Everything before this was a explanation of how I got here)


Now to do some nice clean integration, we write following in our lcddriver.py:

Code: Select all

   def lcd_setBacklight(self, state):
      if state == 1:
         self.lcd_device.write_cmd(0x03 | 0xFF)
      elif state == 0:
         self.lcd_device.write_cmd(0x03 | 1)
One is 0x00 (This text here I pasted after the EDIT2: I don't know why, but sending 0 as a byte "0x00" doesn't work. I smashed some random value into and it worked, so replace the 0x00 with 0xFF (workaround).) and the other one 1, becuse in the other library, remember that to turn it off they only wrote "Wire.write(1);" and to turn it on "Wire.write((byte)0);"? That "(byte)" means that they wrote "0" as a byte, which we can write as 0x00 in python. And yes, on and off are inverted too, because you remember it is "NEGATIVE"?

And now you can go to your script and do:

Code: Select all

lcd.lcd_setBacklight(0)
And it will turn off. To turn it on again, I don't need to even explain, or need I?!?

Note that I'm also a beginner in python and such things and I figured it out - on my own. I registered on this site only to help some poor guy out... (And maybe some others later too). But... I wrote that huge text explaining all kind of things to motivate you guys to read those damn files!! They are also commented, so it isn't that hard!! :)

I hope that I helped some of you.

EDIT: 0x00 is INCOMPLETE: The lcd won't turn on, only off. I'm searching why... Stay tuned.
EDIT2: Fixed. Some random value I tried (0xFF) turn it back on... I don't know how neither why... But it works!

rhubarbdog
Posts: 47
Joined: Mon Dec 11, 2017 9:58 pm

Re: 20x4 i2c lcd lines out of order.

Sun May 13, 2018 11:13 am

Hi
@natbett i found this code and have used it on my raspberry pi.
I have ported it to micro:bit code and was going to put it in a repository on GitHub what license should i use. I personally use the GNU license when i authored the code from an empty text editor, but if i port it i always leave the license and credits intact even if there is very little of the original project left

thanks
rhubarbdog

B.Goode
Posts: 6544
Joined: Mon Sep 01, 2014 4:03 pm
Location: UK

Re: 20x4 i2c lcd lines out of order.

Sun May 13, 2018 11:36 am

While respecting your wish to be honourable in dealing with one of the contributors to the script, have you taken into account the fact that @natbett does not appear to have logged into these forums for over 5 years?

rhubarbdog
Posts: 47
Joined: Mon Dec 11, 2017 9:58 pm

Re: 20x4 i2c lcd lines out of order.

Sun May 13, 2018 12:45 pm

I am a bit of a novice on this forum, i couldn't find how to send a user a private message or track a user down by any means.
How did you achieve finding that @natbett hadn't logged in in ages?

B.Goode
Posts: 6544
Joined: Mon Sep 01, 2014 4:03 pm
Location: UK

Re: 20x4 i2c lcd lines out of order.

Sun May 13, 2018 12:55 pm

How did you achieve finding that @natbett hadn't logged in in ages?
Click on the username natbett at the top of any message they have posted and look at the details in their user profile.

(That means people can see the same information about you..)

rhubarbdog
Posts: 47
Joined: Mon Dec 11, 2017 9:58 pm

Re: 20x4 i2c lcd lines out of order.

Sun May 13, 2018 1:58 pm

I've done some research and the initial fork from Arduino put the code in public domain, I'm going to use the GNU license and hope the guy on Amazon who did some of the conversion to raspberry pi didn't put a license on it.

Return to “Python”