i2c display aansluiten aan de Raspberry Pi

Tijdje terug was er bij Banggood een i2c (oftewel iic) [ie-kwadraad-c] display te koop met 20 tekens over 4 regels.
Omdat ik al wat HD44780-compatible displays had en vond dat deze teveel io poorten in gebruik namen. Dus die maar niet aangesloten.

I2C bus is maar 4 touwtjes, dus die maar eens gekocht.
http://www.banggood.com/IIC-Or-I2C-2004-204-20-X-4-Character-LCD-Display-Module-Yellow-Green-p-908821.html

Dit is een 5V i2c device en de raspberry is 3.3V. Echter, als je goed kijkt wat de PCF8574 IOExpander doet, moet hij ook aan te sluiten zijn op 5V zonder schade aan de raspberry en het display.


Hardware

Aansluitschema:
Rechtstreeks op de 5V
i2c aansluiten raspberry pi
Zelf heb ik voor deze oplossing gekomen, omdat ik de level converter te laat besteld heb.
En aangesloten met 3.3V naar 5V level converter
i2c bus op de raspberry met level converter

 
PINOUT I2C bus display
PIN DESCRIPTION
1 GND
2 VCC (+5V)
3 SDA
4 SCL

Het display zelf:
Display - voorkant
Display - achterkant



Dit is bij Adafruit de level converter:
https://www.adafruit.com/products/757

Je kunt ook even op ebay zoeken naar
i2c level conversion
en dan even sorteren op prijs en free shipping.
straatprijs van $ 2.28 is haalbaar.


Software


Natuurlijk eerst voordat we ook maar iets gaan doen, even alles actueel maken:
pi@rpi-a:~$ sudo apt-get update
Get:1 http://raspberrypi.collabora.com wheezy Release.gpg [836 B]
Get:2 http://mirrordirector.raspbian.org wheezy Release.gpg [490 B]           
Get:3 http://raspberrypi.collabora.com wheezy Release [3,640 B]               
...
Fetched 7,457 kB in 10h 33min 4s (196 B/s)                                    
Reading package lists... Done
pi@rpi-a:~$ sudo apt-get upgrade
Reading package lists... Done
Building dependency tree      
Reading state information... Done
The following packages have been kept back:
  pypy-upstream
The following packages will be upgraded:
...
38 upgraded, 0 newly installed, 0 to remove and 1 not upgraded.
Need to get 121 MB of archives.
After this operation, 1,176 kB of additional disk space will be used.
Do you want to continue [Y/n]? y
...
Setting up raspi-config (20131216-1) ...
Processing triggers for libgdk-pixbuf2.0-0:armhf ...
Processing triggers for menu ...
pi@rpi-a:~$ sudo rpi-update
 *** Raspberry Pi firmware updater by Hexxeh, enhanced by AndrewS
 *** Performing self-update
--2013-12-22 20:11:18--  https://github.com/Hexxeh/rpi-update/raw/master/rpi-update
Resolving github.com (github.com)... 192.30.252.129
Connecting to github.com (github.com)|192.30.252.129|:443... connected.
HTTP request sent, awaiting response... 302 Found
Location: https://raw.github.com/Hexxeh/rpi-update/master/rpi-update [following]
--2013-12-22 20:11:24--  https://raw.github.com/Hexxeh/rpi-update/master/rpi-update
Resolving raw.github.com (raw.github.com)... 185.31.16.133
Connecting to raw.github.com (raw.github.com)|185.31.16.133|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 7174 (7.0K) [text/plain]
Saving to: `/usr/bin/rpi-update.tmp'

100%[======================================>] 7,174       --.-K/s   in 0.004s 

2013-12-22 20:11:30 (1.84 MB/s) - `/usr/bin/rpi-update.tmp' saved [7174/7174]

 *** Relaunching after update
 *** Raspberry Pi firmware updater by Hexxeh, enhanced by AndrewS
 *** ARM/GPU split is now defined in /boot/config.txt using the gpu_mem option!
 *** Setting up firmware (this may take a few minutes)
Cloning into '//root/.rpi-firmware'...
remote: Counting objects: 3201, done.
remote: Compressing objects: 100% (2888/2888), done.
Receiving objects:   0% (10/3201), 2.89 MiB | 167 KiB/s    
...
`//root/.rpi-firmware/vc/sdk/opt/vc/src/hello_pi/hello_audio/Makefile' -> `//opt/vc/src/hello_pi/hello_audio/Makefile'
 *** Running ldconfig
 *** Storing current firmware revision
 *** Syncing changes to disk
 *** If no errors appeared, your firmware was successfully updated
 *** A reboot is needed to activate the new firmware
pi@rpi-a:~$ sudo reboot


raspi-config

Voordat je hiermee begint, even de i2c enablen: (verderop leg ik uit hoe dit handmatig te doen)
gej@rpi-a ~ $ sudo raspi-config
│                                                                                    │
│    1 Expand Filesystem                 Ensures that all of the SD card stor        │
│    2 Change User Password              Change password for the default user        │
│    3 Enable Boot to Desktop/Scratch    Choose whether to boot into a deskto        │
│    4 Internationalisation Options      Set up language and regional setting        │
│    5 Enable Camera                     Enable this Pi to work with the Rasp        │
│    6 Add to Rastrack                   Add this Pi to the online Raspberry         │
│    7 Overclock                         Configure overclocking for your Pi          │
│    8 Advanced Options                  Configure advanced settings                 │
│    9 About raspi-config                Information about this configuration        │
│                                                                                    │
│                                                                                    │
│                                                                                    │
│                       <Select>                       <Finish>                      │
│                                                                                    │
└────────────────────────────────────────────────────────────────────────────────────┘

│    A1 Overscan                         You may need to configure overscan i        │
│    A2 Hostname                         Set the visible name for this Pi on         │
│    A3 Memory Split                     Change the amount of memory made ava        │
│    A4 SSH                              Enable/Disable remote command line a        │
│    A5 Device Tree                      Enable/Disable the use of Device Tre        │
│    A6 SPI                              Enable/Disable automatic loading of         │
│    A7 I2C                              Enable/Disable automatic loading of         │
│    A8 Serial                           Enable/Disable shell and kernel mess        │
│    A9 Audio                            Force audio out through HDMI or 3.5m        │
│    A0 Update                           Update this tool to the latest versi        │
│                                                                                    │
│                                                                                    │
│                       <Select>                       <Back>                        │
│                                                                                    │
└────────────────────────────────────────────────────────────────────────────────────┘
Select en reboot, en daarna zijn de modules goed, maar ook die config.txt die vanaf kernel 3.18 ook nodig is.

I2c spullen installeren

Daarna de i2c spullen installeren.

pi@rpi-a ~ $ sudo apt-get install python-smbus i2c-tools
Reading package lists... Done
Building dependency tree       
Reading state information... Done
Suggested packages:
  libi2c-dev
The following NEW packages will be installed:
  i2c-tools python-smbus
0 upgraded, 2 newly installed, 0 to remove and 0 not upgraded.
Need to get 71.0 kB of archives.
After this operation, 317 kB of additional disk space will be used.
Get:1 http://mirrordirector.raspbian.org/raspbian/ wheezy/main i2c-tools armhf 3.1.0-2 [59.5 kB]
Get:2 http://mirrordirector.raspbian.org/raspbian/ wheezy/main python-smbus armhf 3.1.0-2 [11.5 kB]
Fetched 71.0 kB in 0s (189 kB/s)  
Selecting previously unselected package i2c-tools.
(Reading database ... 67417 files and directories currently installed.)
Unpacking i2c-tools (from .../i2c-tools_3.1.0-2_armhf.deb) ...
Selecting previously unselected package python-smbus.
Unpacking python-smbus (from .../python-smbus_3.1.0-2_armhf.deb) ...
Processing triggers for man-db ...
Setting up i2c-tools (3.1.0-2) ...
/run/udev or .udevdb or .udev presence implies active udev.  Aborting MAKEDEV invocation.
Setting up python-smbus (3.1.0-2) ...
pi@rpi-a ~ $

i2c modules laden

Even de i2c software modules laden

pi@rpi-a ~ $ sudo modprobe i2c-dev
pi@rpi-a ~ $ sudo modprobe i2c-bcm2708
pi@rpi-a ~ $ lsmod
Module                  Size  Used by
i2c_bcm2708             3949  0
i2c_dev                 5557  0
snd_bcm2835            16165  0
snd_pcm                81593  1 snd_bcm2835
snd_page_alloc          5156  1 snd_pcm
snd_seq                53769  0
snd_seq_device          6473  1 snd_seq
snd_timer              20133  2 snd_pcm,snd_seq
snd                    58895  5 snd_bcm2835,snd_timer,snd_pcm,snd_seq,snd_seq_device
r8712u                168753  0
leds_gpio               2059  0
led_class               3688  1 leds_gpio
pi@rpi-a ~ $

Voortaan automatisch modules laden

Even permanent maken:
(het # voor de modules zetten in raspi-blacklist.conf)
pi@rpi-a ~ $ sudo vi /etc/modprobe.d/raspi-blacklist.conf

# blacklist spi and i2c by default (many users don't need them)

#blacklist spi-bcm2708
#blacklist i2c-bcm2708

en:
(i2c-dev toevoegen aan de autostart modules)
pi@rpi-a ~ $ sudo vi /etc/modules

# /etc/modules: kernel modules to load at boot time.
#
# This file contains the names of kernel modules that should be loaded
# at boot time, one per line. Lines beginning with "#" are ignored.
# Parameters can be specified after the module name.

snd-bcm2835
i2c-dev

config.txt aanpassen

Denk eraan dit ook in je boot.txt toe te voegen, of doe dit automatisch met raspi-config

gej@rpi-a ~ $ sudo vi /boot/config.txt
...
dtparam=i2c_arm=on
gej@rpi-a ~ $

Controleren of alles werkt

pi@rpi-a ~ $ tail -f /var/log/messages

Dec 17 19:55:38 rpi-a kernel: [ 1727.847225] i2c /dev entries driver
Dec 17 19:55:46 rpi-a kernel: [ 1736.043513] bcm2708_i2c_init_pinmode(0,0)
Dec 17 19:55:46 rpi-a kernel: [ 1736.043544] bcm2708_i2c_init_pinmode(0,1)
Dec 17 19:55:46 rpi-a kernel: [ 1736.049754] bcm2708_i2c bcm2708_i2c.0: BSC0 Controller at 0x20205000 (irq 79) (baudrate 100k)
Dec 17 19:55:46 rpi-a kernel: [ 1736.049910] bcm2708_i2c_init_pinmode(1,2)
Dec 17 19:55:46 rpi-a kernel: [ 1736.049929] bcm2708_i2c_init_pinmode(1,3)
Dec 17 19:55:46 rpi-a kernel: [ 1736.050513] bcm2708_i2c bcm2708_i2c.1: BSC1 Controller at 0x20804000 (irq 79) (baudrate 100k)
pi@rpi-a ~ $ sudo i2cdetect -y 0
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --                        
pi@rpi-a ~ $ sudo i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- 27 -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --                        
pi@rpi-a ~ $


En daar is ie, de 27.
Dat wil zeggen, dat op bus i2c bus 1, op adres 27 het lcd scherm zit.
Eigenlijk moet je dat nog zelfs anders lezen:
Op poort 27 van de i2c bus zit een pcf8574 remote 8 bit I/O expander voor de i2c bus. En daaraan zit dus een HD44780-compatible lcd display.

Stukje hierna moet je eigenlijk niet gebruiken. Dit is het kaal aanspreken van de i2c bus en mij is het niet gelukt wat op het scherm te toveren op deze manier.

Licht uitzetten:
root@rpi-a:/home/pi# i2cset -y 1 0x27 0x01


Der Wert nach der Adresse gibt das Bitmuster an, das auf die Ausgänge geschalten wird,
0x01 nur Ausgang 1 an
0x02 nur Ausgang 2 an
0x03 Ausgang 1 und 2 an

Ein Bit in diesem Wert gesetzt (=1) schaltet den Ausgang ein, dieses Bit auf 0 schaltet den Ausgang aus.

pi@rpi-a ~/code/LCM1602-IIC $ i2cget -y 1 0x27
Error: Could not open file `/dev/i2c-1': Permission denied
Run as root?
pi@rpi-a ~/code/LCM1602-IIC $ sudo i2cget -y 1 0x27
0xf7
pi@rpi-a ~/code/LCM1602-IIC $

Aansturing van de regels:

20x4 display
Let op, als je dus zonder "extra code" de regels wil schrijven, dan is de volgorde:
1
3
2
4
beetje raar maar waar.

LCD aansturen (20x4)

na veel avonden zoeken heb ik toch een makkelijke manier van het schrijven naar het display gevonden.
Hier ga ik er vanuit dat je display (de pcf8574 i2c port extender) aangesloten zit op bus 1, adres 27.

Juiste code gevonden:
http://www.instructables.com/id/Raspberry-Pi-Snail-Mail-System/

De gast die dit geschreven heeft, heeft een python script waarmee ik op makkelijke manier het lcd display kan bedienen.

Let wel, dit gaat over een 20 karakter breed, 4 lijns display. Een stukje verderop beschrijf ik het verschil met het 16 karakter breed display

pi@rpi-a:~$ mkdir lcd
pi@rpi-a:~$ cd lcd
pi@rpi-a ~/lcd $ git clone https://github.com/paulbarber/raspi-gpio.git
Cloning into 'raspi-gpio'...
remote: Counting objects: 31, done.
remote: Compressing objects: 100% (25/25), done.
remote: Total 31 (delta 10), reused 26 (delta 5)
Unpacking objects: 100% (31/31), done.
pi@rpi-a ~/lcd $ cd raspi-gpio/
pi@rpi-a ~/lcd/raspi-gpio $ ls
fswebcam.conf  inquiry.py            lcd_dice.py     led_dice.py  mysql_test.py             startup_script.sh
i2c_lib.py     inquiry-with-rssi.py  lcd_display.py  led_rand.py  README.md                 take_picture_and_email.py
inoutboard.py  lcd_4dice.py          lcd_test.py     led_test.py  send_gmail_attachment.py  whoshome.py
pi@rpi-a ~/lcd/raspi-gpio $

het gaat nu om de volgende drie bestanden. lcd_display.py, i2c_lib.py en lcd_test.py.

Even het adres van het lcd display goed zetten:
pi@rpi-a ~/lcd/raspi-gpio $ vi lcd_display.py

# LCD Address
#ADDRESS = 0x3F
ADDRESS = 0x27

En vervolgens even de breedte op 20 karakters zetten en de hoogte op 4 lijnen.

pi@rpi-a ~/lcd/raspi-gpio $ vi lcd_display.py
..
  def display_string(self, string, line):
    """display a string on the given line of the display, 1 or 2, string is truncated to 20 chars and centred"""
    centered_string = string.center(20)
    if line == 1:
      self.write(0x80)
    if line == 2:
      self.write(0xC0)
    if line == 3:
      self.write(0x94)
    if line == 4:
      self.write(0xD4)

En dan even testen:

pi@rpi-a ~//raspi-gpio $ vi lcd_test.py
from lcd_display import lcd

my_lcd = lcd()
my_lcd.display_string("Hello World", 1)
my_lcd.display_string("YwRobot LCM1602 IIC V1 display", 2)
my_lcd.display_string("aan de Raspberry Pi", 3)
my_lcd.display_string("via gejanssen.com", 4)

pi@rpi-a ~/lcd/raspi-gpio $ sudo python lcd_test.py
Het display in werking

Oftewel de complete setup:

lcd display in werking


Je kunt de code/scripts ook hier downloaden.
i2c-2004-display-raspberrypi-ywrobot.zip

LCD aansturen (16x4)

Na een tijdje prutsen kwam ik erachter dat als je een 16 karakter breed display had in plaats van een 20, dat de lijnen dan een beetje door elkaar liepen.
dat komt omdat de displays (eigenlijk) de karakters zich als volgt laten plaatsen:
20x4 display
2004_display

16x4 display
1604 display

Je ziet dat als je de laatste 4 karakters schrijft in naar een 16x4 display, dat ze dan op de eerste 4 karakters komen van de 3e regel.
Hiervoor moet je even de "het begin van de regels" opnieuw instellen. We centreren dan gelijk even naar links.

karater 1 is locatie 0x80 (hex dus)
16 erbij, dan kom je op regel 3.
voor het gemak neem ik dus voor regel 3, 0x80+16

Als het display dan toch weer 20 karakters wordt, kun je het makkelijker aanpassen.

Links centreren

Voor sommige doeleinden is het handig links uit te centeren in plaats van in het midden.

Pas hiervoor de lcd_display als volgt aan:
    centered_string = string.center(20)
gaat naar:
    centered_string = string.ljust(14)

root@rpi-a:/home/gej# vi lcd_display.py
...
  def display_string(self, string, line):
    """display a string on the given line of the display, 1 or 2, string is truncated to 16 chars and centred"""
    """ do not center, centered_string = string.center(16) """
    centered_string = string.ljust(14)
    if line == 1:
      self.write(0x80)
    if line == 2:
      self.write(0xC0)
    if line == 3:
      self.write(0x80+16)
    if line == 4:
      self.write(0xC0+16)
...
root@rpi-a:/home/gej#

En dan nu het gebruik

4 regel script

Het makkelijkse aansturen is als je de 4 regels vanuit het script aan kunt sturen.

Hiervoor heb ik een script lcd_4lines.py gemaakt.

root@rpi-a:/home/gej# vi lcd_4lines.py
from lcd_display import lcd
import sys

line1=(sys.argv[1])
line2=(sys.argv[2])
line3=(sys.argv[3])
line4=(sys.argv[4])

my_lcd = lcd()
my_lcd.display_string(line1, 1)
my_lcd.display_string(line2, 2)
my_lcd.display_string(line3, 3)
my_lcd.display_string(line4, 4)
root@rpi-a:/home/gej#


Gewenst resultaat:

regel 1
Temperatuur
regel 2
Luchtvochtigheid
regel 3
Luchtdruk
regel 4
Ip adres rpi

Om deze nu aan te roepen doe ik het volgende:

Script

root@rpi-a:/home/gej# vi uitlezen.sh

# Temp
temperature=`/usr/bin/python /home/gej/get1temp.py 28-000005162710`

# humidity
# DHT11 (hij leest niet goed uit, dus net zo lang doorgaan tot ik een goede reading heb)
while [ -z "$DHT11" ]
do
        DHT11=`/home/pi/Adafruit-Raspberry-Pi-Python-Code/Adafruit_DHT_Driver/Adafruit_DHT 11 17 | /bin/grep Temp`
        /bin/sleep 5
done
luchtvochtigheid=`echo $DHT11 | /usr/bin/awk '{print $7}'`

# Pressure
luchtdruk=`/usr/bin/sudo /home/gej/bmp085/testBMP085 | /bin/grep Press | /usr/bin/awk '{print $2}'`

# ip adres wlan0
ip=`/sbin/ifconfig wlan0 | /bin/grep "inet " | /usr/bin/awk '{print $2}' | /usr/bin/awk -F : '{print $2}'`

# En schrijven naar de lcd display
/usr/bin/python /home/gej/lcd_4lines.py  "Temp $temperature C" "Humidity $luchtvochtigheid %" "Pressure $luchtdruk hPa" "IP $ip"

root@rpi-a:/home/gej#

Paden en dir's natuurlijk aanpassen naar eigen inzicht.

Scriptjes zijn hier te downloaden:
4lines.zip

De techniek erachter

Eigenlijk is het simpel..... Maar dat is alles als je er in gedoken bent.
De displays die het meest gebruikt worden in de markt zijn Hitachi HD44780 LCD controller. Deze zijn over 4 draadjes makkelijk aan te sturen, maar kosten in totaal dus 6 IO pins + 1 * 5V en Ground/massa.
Dat is heel veel.

Zie hier:
(eerlijk gejat van http://www.raspberrypi-spy.co.uk/2012/08/20x4-lcd-module-control-using-python/)

Here is how I wired up my HD44780 LCD :

LCD Pin Function Pi Function Pi Pin
01 GND GND P1-06
02 +5V +5V P1-02
03 Contrast

04 RS GPIO7 P1-26
05 RW GND P1-06
06 E GPIO8 P1-24
07 Data 0

08 Data 1

09 Data 2

10 Data 3

11 Data 4 GPIO25 P1-22
12 Data 5 GPIO24 P1-18
13 Data 6 GPIO23 P1-16
14 Data 7 GPIO18 P1-12
15 +5V via 560 ohm

16 GND
P1-06

Dit kan dus makkelijker, als je de i2c bus hiervoor gebruikt. Dit is een soort van seriele bus waar je meer devices op aan kunt sluiten, die vervolgens allemaal een eigen adres krijgen.
In ons geval op poort 27 van de i2c bus zit een pcf8574 remote 8 bit I/O expander voor de i2c bus. En daaraan zit dus een HD44780-compatible lcd display.

Om de lcd display te besturen via die pcf8574 zijn er dus al heeeel veeel gekken bezig geweest om die aan de gang te krijgen met de arduino, en andere gekken hebben dat weer omgezet naar de raspberry pi.
Na het werk van al deze gekken kom ik pas in aktie.

Van deze pcf8574 i2c io poort naar display converter zijn er meer versies.
Deze heeft iemand bij elkaar gezet op:
http://arduino-info.wikispaces.com/LCD-Blue-I2C

Wij hebben versie #1.
http://arduino-info.wikispaces.com/LCD-Blue-I2C#v1

Verder is de PCF8574 van adres te wijzigen. Dat wil zeggen dat hij dus een ander adres dan #27 krijgt.
hiervoor moet poort A0, A1 of A2 gewijzigd worden, maar dit is met onze versie niet mogelijk.
PCF8574 i2c io extender



Deze site heeft een variabele python versie gemaakt om die lcd's aan te sturen:
http://think-bowl.com/raspberry-pi/i2c-python-library-lcd-with-the-raspberry-pi/
Ik heb hem nog niet getest, maar met de pinlayout van de arduino-info versie moet die wel aan de gang te krijgen zijn.

En als laatste info
Bij Banggood hebben ze ook die i2c port extenders:
http://www.banggood.com/IIC-Or-I2C-Or-TWI-Or-SP-Serial-Interface-Module-Port-For-5V-Arduino-1602LCD-p-80365.html
IIC/I2C/TWI/SP Serial Interface Module Port For 5V Arduino 1602LCD
SKU077364

Omdat ik nog 3
HD44780 displays heb liggen, heb ik er maar vast twee laten versturen. Als ik die aan de gang heb, zal ik het hier posten.

Links

Voor verdere referentie

voorbeeld over hoe de i2cset e.d. te gebruiken zijn:

http://www.raspberrypi-spy.co.uk/2013/07/how-to-use-a-mcp23017-i2c-port-expander-with-the-raspberry-pi-part-1/

oplossing voor de 5 en de 3.3v i2c bus
http://www.raspberrypi.org/phpBB3/viewtopic.php?f=63&t=48204

en dan, als alles werkt, de i2c besturen met python
http://www.recantha.co.uk/blog/?p=4849