In dit stappenplan gaan we een generiek LCD scherm (4 regels van 20 karakters) dat is voorzien van een I2C backpack aansluiten op een Raspberry Pi. Het scherm is in verschillende kleuren beschikbaar en kan worden aangesloten zowel 5V als 3.3V.
Het LCD backpack aansturen met behulp van een speciaal Python script waarmee we systeeminformatie op het scherm laten verschijnen. Maar natuurlijk kan je ook zelf informatie op het scherm laten verschijnen.
Gebruikte componenten
• 20×4 Character LCD met IIC/I2C Backpack Module
• Logic Level Shifter Bi-directioneel
• 10x Dupont verbindingskabel (female/female)
Kosten componenten: 4,50€
Raspberry Pi Zero, Raspberry Pi 2, Raspberry Pi 3
Raspbian Jessie (2016-05-27 kernel 4.4.13)
Aansluitschema 3.3V
Je kunt het I2C backpack direct aansluiten op de Raspberry Pi zonder gebruik te maken van een level shifter. Je maakt dan gebruik van de 3.3V pin, het enige nadeel hiervan is dat de helderheid van de backlight iets minder is dan wanneer je 5V gebruikt. Het voordeel: met vier kabeltjes is het LCD scherm aangesloten!
Raspberry Pi | I2C backpack |
---|---|
3.3V (PIN #1) | VCC |
SDA (PIN #3) | SDA |
SCL (PIN #5) | SCL |
GND (PIN #6) | GND |
Aansluitschema 5V
De I2C module kan gevoed worden met 5V of 3.3V maar geeft de beste helderheid als je gebruik maakt van 5V. De GPIO pins van de Raspberry Pi zijn echter niet 5V ’tolerant’ vandaar dat we een I2C level shifter gebruiken. Op de level shifter wordt zowel 3.3V als 5V als referentie aangesloten.
Raspberry Pi | Level Shifter | I2C backpack |
---|---|---|
3.3V (PIN #1) | LV | – |
SDA (PIN #3) | LV1 | – |
SCL (PIN #5) | LV2 | – |
GND (PIN #6) | GND | – |
5V (PIN #2) | HV | – |
5V (PIN #3) | – | VCC |
– | HV1 | SDA |
– | HV2 | SCL |
– | GND | GND |
I2C Activeren
Om tekst op het LCD scherm te krijgen gebruiken we een speciaal Python script dat de I2C interface aanstuurt. Om toegang te krijgen tot de interface dient deze in de Raspberry Pi geactiveerd te zijn. Je kunt deze activeren met behulp van raspi-config.
sudo raspi-config
Selecteer de optie ‘Advanced Options’ ▸ ‘I2C’ en kies ‘YES’ om de I2C interface te activeren.
Controleren werking I2C
Nadat de module is aangesloten op de I2C bus kun je controleren of deze ook daadwerkelijk wordt gedetecteerd. Dit kun je doen met de I2C tools, heb je deze niet geïnstalleerd dan kun je dit doen met behulp van:
sudo apt-get install i2c-tools
Controleer hierna of de module zichtbaar is:
sudo i2cdetect -y 1
De LCD backpack module heeft als ID #03F. Mocht de module niet zichtbaar zijn controleer dan of de kabels goed zijn aangesloten.
Wordt er een andere waarde dan #03F weergeven, wijzig dan in het script de parameter I2C_ADDR
in de waarde die verschijnt in de i2cdetect tool.
LCD scherm Python script
Een demo script om de werking van het LCD display te testen:
#!/usr/bin/python | |
# https://raspberrytips.nl/lcd-scherm-20x4-i2c-raspberry-pi/ | |
import sys | |
import smbus | |
import time | |
import datetime | |
import subprocess | |
I2C_ADDR = 0x3F # I2C device address | |
LCD_WIDTH = 20 # Maximum characters per line | |
# Define some device constants | |
LCD_CHR = 1 # Mode - Sending data | |
LCD_CMD = 0 # Mode - Sending command | |
LCD_LINE_1 = 0x80 # LCD RAM address for the 1st line | |
LCD_LINE_2 = 0xC0 # LCD RAM address for the 2nd line | |
LCD_LINE_3 = 0x94 # LCD RAM address for the 3rd line | |
LCD_LINE_4 = 0xD4 # LCD RAM address for the 4th line | |
LCD_BACKLIGHT = 0x08 # On 0X08 / Off 0x00 | |
ENABLE = 0b00000100 # Enable bit | |
E_PULSE = 0.0005 | |
E_DELAY = 0.0005 | |
bus = smbus.SMBus(1) # Rev 2 Pi uses 1 | |
def run_cmd(cmd): | |
return subprocess.check_output(cmd, shell=True).decode('utf-8') | |
def get_my_ipwlan(): | |
val = run_cmd("/sbin/ifconfig wlan0 | grep 'inet addr:' | cut -d: -f2 | awk '{ print $1}'")[:-1] | |
if val == "": | |
val = "No connection!" | |
return val | |
def get_my_ipeth(): | |
val = run_cmd("/sbin/ifconfig eth0 | grep 'inet addr:' | cut -d: -f2 | awk '{ print $1}'")[:-1] | |
if val == "": | |
val = "No connection" | |
return val | |
def lcd_init(): | |
lcd_byte(0x33,LCD_CMD) # 110011 Initialise | |
lcd_byte(0x32,LCD_CMD) # 110010 Initialise | |
lcd_byte(0x06,LCD_CMD) # 000110 Cursor move direction | |
lcd_byte(0x0C,LCD_CMD) # 001100 Display On,Cursor Off, Blink Off | |
lcd_byte(0x28,LCD_CMD) # 101000 Data length, number of lines, font size | |
lcd_byte(0x01,LCD_CMD) # 000001 Clear display | |
time.sleep(E_DELAY) | |
def lcd_byte(bits, mode): | |
bits_high = mode | (bits & 0xF0) | LCD_BACKLIGHT | |
bits_low = mode | ((bits<<4) & 0xF0) | LCD_BACKLIGHT | |
bus.write_byte(I2C_ADDR, bits_high) | |
lcd_toggle_enable(bits_high) | |
bus.write_byte(I2C_ADDR, bits_low) | |
lcd_toggle_enable(bits_low) | |
def lcd_toggle_enable(bits): | |
time.sleep(E_DELAY) | |
bus.write_byte(I2C_ADDR, (bits | ENABLE)) | |
time.sleep(E_PULSE) | |
bus.write_byte(I2C_ADDR,(bits & ~ENABLE)) | |
time.sleep(E_DELAY) | |
def lcd_string(message,line): | |
message = message.ljust(LCD_WIDTH," ") | |
lcd_byte(line, LCD_CMD) | |
for i in range(LCD_WIDTH): | |
lcd_byte(ord(message[i]),LCD_CHR) | |
def main(): | |
lcd_init() | |
while True: | |
now = datetime.datetime.now() | |
lcd_string("RASPBERRYTIPS.NL",LCD_LINE_1) | |
lcd_string( str(now.day)+'/'+str(now.month)+'/'+str(now.year)+' '+str(now.hour)+':'+str(now.minute),LCD_LINE_2) | |
lcd_string("W:{}".format(get_my_ipwlan()),LCD_LINE_3) | |
lcd_string("E:{}".format(get_my_ipeth()),LCD_LINE_4) | |
time.sleep(60) | |
if __name__ == '__main__': | |
try: | |
main() | |
except KeyboardInterrupt: | |
pass | |
finally: | |
lcd_byte(0x01, LCD_CMD) |
Kopieer of download het Python script:
wget https://raspberrytips.nl/lcd20x4.py
Activeer het script:
sudo python lcd20x4.py
Op het scherm verschijnt nu de url van deze website en op de tweede regel de actuele datum en tijd. Op de derde en vierde regel respectievelijk het WIFI en WLAN IP adres. Je kunt natuurlijk ook zelf informatie weergeven zoals bijvoorbeeld waardes van sensoren.
I2C Script parameters
lcd_init()
Reset en activeer het LCD scherm.
lcd_string("tekst",LCD_LINE_1)
Plaats ’tekst’ maximaal 20 characters op de eerste regel LCD_LINE_1, het getal op het einde geeft de de regel aan waarop de tekst moet worden geplaatst.
Ik heb een raspberry pi 3b met Jessie.
Hallo Richard,
De module is zichtbaar (3F) maar ik krijg geen tekst te zien op het display. Aangezien ik 2 ic2 en 2 displays heb en deze in alle combinaties heb geprobeerd is het hoogstwaarschijnlijk geen hardware probleem. Ik heb een Raspberry Pi 3B met Jessie. Enig idee waar dit aan kan liggen?
*Mijn eerste reactie werd trouwens niet geplaats
Er zit een foutje in de pin-tabel bij “Aansluitschema 5V”.
“5V (PIN #3)” moet denk ik “5V (PIN #4)” zijn, want een paar regels er boven staat al “SDA (PIN #3)” en pin 3 is niet voor de algemene 5V stroom.
Het script werket niet op mijn nieuwe RPi met Buster omdat ifconfig ietwat andere output geeft. Het deel addr: is weg, vandaar dat je een stukje code moet aanpassen.
def get_my_ipwlan():
val = run_cmd(“/sbin/ifconfig wlan0 | grep ‘inet ‘ | cut -d: -f2 | awk ‘{ print $2}'”)[:-1]
if val == “”:
val = “No connection!”
return val
def get_my_ipeth():
val = run_cmd(“/sbin/ifconfig eth0 | grep ‘inet ‘ | cut -d: -f2 | awk ‘{ print $2}'”)[:-1]
if val == “”:
val = “No connection”
return val
Ik heb de code nog wat aangepast voor de laatste versie van Buster (05082021)
#!/usr/bin/python
# https://raspberrytips.nl/lcd-scherm-20×4-i2c-raspberry-pi/
import sys
import smbus
import time
import datetime
import subprocess
#I2C_ADDR = 0x3F # I2C device address
I2C_ADDR = 0x27 # I2C device address
LCD_WIDTH = 20 # Maximum characters per line
# Define some device constants
LCD_CHR = 1 # Mode – Sending data
LCD_CMD = 0 # Mode – Sending command
LCD_LINE_1 = 0x80 # LCD RAM address for the 1st line
LCD_LINE_2 = 0xC0 # LCD RAM address for the 2nd line
LCD_LINE_3 = 0x94 # LCD RAM address for the 3rd line
LCD_LINE_4 = 0xD4 # LCD RAM address for the 4th line
LCD_BACKLIGHT = 0x08 # On 0X08 / Off 0x00
ENABLE = 0b00000100 # Enable bit
E_PULSE = 0.0005
E_DELAY = 0.0005
bus = smbus.SMBus(1) # Rev 2 Pi uses 1
def run_cmd(cmd):
return subprocess.check_output(cmd, shell=True).decode(‘utf-8’)
def get_my_ipwlan():
val = run_cmd(“/sbin/ifconfig wlan0 | grep -w ‘inet’ |cut -c 14-28 | awk ‘{ print $1}'”)[:-1]
if val == “”:
val = “No connection!”
return val
def get_my_ipeth():
val = run_cmd(“/sbin/ifconfig enxb827eb62bee2 | /sbin/ifconfig enxb827eb62bee2 | grep -w ‘inet’ |cut -c 14-28 | awk ‘{ print $1}'”)[:-1]
if val == “”:
val = “No connection”
return val
def lcd_init():
lcd_byte(0x33,LCD_CMD) # 110011 Initialise
lcd_byte(0x32,LCD_CMD) # 110010 Initialise
lcd_byte(0x06,LCD_CMD) # 000110 Cursor move direction
lcd_byte(0x0C,LCD_CMD) # 001100 Display On,Cursor Off, Blink Off
lcd_byte(0x28,LCD_CMD) # 101000 Data length, number of lines, font size
lcd_byte(0x01,LCD_CMD) # 000001 Clear display
time.sleep(E_DELAY)
def lcd_byte(bits, mode):
bits_high = mode | (bits & 0xF0) | LCD_BACKLIGHT
bits_low = mode | ((bits<<4) & 0xF0) | LCD_BACKLIGHT
bus.write_byte(I2C_ADDR, bits_high)
lcd_toggle_enable(bits_high)
bus.write_byte(I2C_ADDR, bits_low)
lcd_toggle_enable(bits_low)
def lcd_toggle_enable(bits):
time.sleep(E_DELAY)
bus.write_byte(I2C_ADDR, (bits | ENABLE))
time.sleep(E_PULSE)
bus.write_byte(I2C_ADDR,(bits & ~ENABLE))
time.sleep(E_DELAY)
def lcd_string(message,line):
message = message.ljust(LCD_WIDTH," ")
lcd_byte(line, LCD_CMD)
for i in range(LCD_WIDTH):
lcd_byte(ord(message[i]),LCD_CHR)
def main():
lcd_init()
while True:
now = datetime.datetime.now()
lcd_string("PA0ESH-10 iGate APRX",LCD_LINE_1)
lcd_string( str(now.day)+'/'+str(now.month)+'/'+str(now.year)+' '+str(now.hour)+':'+str(now.minute),LCD_LINE_2)
lcd_string("W:{}".format(get_my_ipwlan()),LCD_LINE_3)
lcd_string("E:{}".format(get_my_ipeth()),LCD_LINE_4)
time.sleep(60)
if __name__ == '__main__':
try:
main()
except KeyboardInterrupt:
pass
finally:
lcd_byte(0x01, LCD_CMD)
root@hampi:/home/pi# ^C
root@hampi:/home/pi# nano lcd20x4.py
GNU nano 3.2 lcd20x4.py
lcd_init()
while True:
now = datetime.datetime.now()
lcd_string("MY OWN STRING",LCD_LINE_1)
lcd_string( str(now.day)+'/'+str(now.month)+'/'+str(now.year)+' '+str(now.hour)+':'+str(now.minute),LCD_LINE_2)
lcd_string("W:{}".format(get_my_ipwlan()),LCD_LINE_3)
lcd_string("E:{}".format(get_my_ipeth()),LCD_LINE_4)
time.sleep(60)
if __name__ == '__main__':
try:
main()
except KeyboardInterrupt:
pass
finally:
lcd_byte(0x01, LCD_CMD)