In meinem Hardware-Fundus hatte ich noch ein 16×2 Zeichen LCD Display wiederentdeckt, das wollte ich schon länger mal am Raspberry Pi testen und in Betrieb nehmen. Was liegt da näher, um für einen Funktionstest, die aktuelle Uhrzeit und die IP-Adresse meines Mini-Rechners auf dem Display auszugeben. In diesem kleinen Raspberry Pi Projekt zeige ich euch wie ihr ein 16×2 Zeichen LCD an den RasPi anschließt und via Python Script ansteuert.
Material
Folgendes Material habe ich verwendet
- QC1602a 16×2 Zeichen LCD Display
- Drehpotentiometer 50k Ohm
- Breadboard
- Steckbrettkabel Male-Male
- GPIO Breakout
Falls ihr noch kein Breadboard und Kabel besitzt, das Ganze gibt es auch als Set inkl LCD und Poti.
Verkabelung des LCD Display
Die Verkabelung des Display scheint auf den ersten Blick recht komplex, habt ihr allerdings die die Funktion einmal verstanden ist das Setup recht einfach.
Das LCD-Display hat 16 Pins. In der unten stehenden Tabelle habe ich die Verkabelung des Display dargestellt. Da ich, wie ihr auf den Bild erkennen könnt, ein GPIO Breakout verwende habe ich in der letzten Spalte die Verkabelung mit meinem Breakout dokumentiert.
Falls ihr das Display über ein anderes Breakout oder direkt am RasPi bzw. via Breadboard verkabeln wollt habe ich die RasPi GPIO Pins aufgeführt, wie immer ist es die Nummer des Pins auf der Leiste P1. Falls ihr euch unsicher bei der Zuordnung der Pins seit könnt ihr einen Blick auf mein GPIO Pin Worksheet werfen dort die Verbindungen eintragen.
LCD Pin | LCD Funktion | RasPi Funktion | RasPi GPIO-Pin | Mein Breakout (T-Cobbler) |
01 | GND | GND | GPIO Pin 6 | GND |
02 | +5V | +5V | GPIO Pin 2 | 5V0 |
03 | Contrast | GND | GPIO Pin 6 | Potentiometer (mittlerer Pin) |
04 | RS | GPIO7 | GPIO Pin 26 | CE1 |
05 | RW | GND | GPIO Pin 6 | GND |
06 | E | GPIO8 | GPIO Pin 24 | CE0 |
07 | Data 0 | |||
08 | Data 1 | |||
09 | Data 2 | |||
10 | Data 3 | |||
11 | Data 4 | GPIO25 | GPIO Pin 22 | GPIO6 |
12 | Data 5 | GPIO24 | GPIO Pin 18 | GPIO5 |
13 | Data 6 | GPIO23 | GPIO Pin 16 | GPIO4 |
14 | Data 7 | GPIO18 | GPIO Pin 12 | GPIO1 |
15 | +5V | GPIO Pin 2 | 5V0 | |
16 | GND | GPIO Pin 6 | GND |
Alternativ gibt es auf der Adafruit Seite ein passendes Verkabelungsdiagramm, allerdings verwenden die wieder eine anderes Breakout.
LCD Display am Raspberry Pi einrichten
Wir steuern das LCD Display via Python an, daher installieren wir als erstes die notwendigen Python Programme und Abhängigkeiten nachdem wir unser System aktualisiert via apt aktualisiert haben.
1 2 3 4 |
sudo apt-get -y update && sudo apt-get -y upgrade sudo apt-get install -y python-dev python-setuptools python-pip git sudo easy_install -U distribute sudo pip install rpi.gpio |
Dann können wir direkt loslegen, das Python Script, welches ich vorbereitet haben laden wir uns via wget ins Home und machen es via chmod ausführbar.
1 2 3 |
cd ~ wget -O raspberry.tips.lcd.py /wp-content/uploads/2014/12/raspberry.tips_.lcd_.py_.txt chmod +x raspberry.tips.lcd.py |
Zum Testen eures LCD-Display können wir das Script nun direkt ausführen und uns die Ausgabe auf dem Display ansehen.
1 |
sudo python raspberry.tips.lcd.py |
Eventuell müsst ihr noch über den Drehpoti den Kontrast eures LCDs einstellen, erhaltet ihr keine oder eine falsche Ausgabe liegt dies vermutlich an der falschen Verkabelung. Falls die angezeigte Uhrzeit nicht stimmt müsst ihr eure Zeitzone via Raspi-config auf die Deutsche (GMT +1) umstellen.
Wer möchte kann mit den unten aufgeführten Script die Ausgabe nach jedem Neustart des RasPi aktivieren. Hierzu müsst ihr den Code in die Datei /etc/init.d/lcd kopieren und dann folgende Befehle ausführen um /etc/init.d/lcd zum automatischen Start hinzuzufügen (via rc).
1 2 |
sudo chmod +x /etc/init.d/lcd sudo update-rc.d lcd defaults |
LCD Python Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 |
#!/usr/bin/python # based on code from lrvick, LiquidCrystal and Adafruit from time import sleep class Adafruit_CharLCD(object): # 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=7, pin_e=8, pins_db=[25, 24, 23, 18], 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 GPIO.setwarnings(False) 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.clear() def begin(self, cols, lines): if (lines > 1): self.numlines = lines self.displayfunction |= self.LCD_2LINE def home(self): self.write4bits(self.LCD_RETURNHOME) # set cursor position to zero self.delayMicroseconds(3000) # this command takes a long time! def clear(self): 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])) 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 off """ self.displaycontrol &= ~self.LCD_CURSORON self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol) def cursor(self): """ Turns the underline cursor on """ self.displaycontrol |= self.LCD_CURSORON self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol) def noBlink(self): """ Turn the blinking cursor off """ self.displaycontrol &= ~self.LCD_BLINKON self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol) def blink(self): """ Turn the blinking cursor on """ 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 else: self.write4bits(ord(char), True) if __name__ == '__main__': lcd = Adafruit_CharLCD() cmd = "ip addr show eth0 | grep inet | awk '{print $2}' | cut -d/ -f1" lcd.begin(16, 1) def run_cmd(cmd): p = Popen(cmd, shell=True, stdout=PIPE) output = p.communicate()[0] return output while 1: lcd.clear() ipaddr = run_cmd(cmd) lcd.message(datetime.now().strftime('%b %d %H:%M:%Sn')) lcd.message('IP %s' % (ipaddr)) sleep(2) |
Autostart Script
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
### BEGIN INIT INFO # Provides: LCD - date / time / ip address # Required-Start: $remote_fs $syslog # Required-Stop: $remote_fs $syslog # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: Liquid Crystal Display # Description: date / time / ip address ### END INIT INFO #! /bin/sh # /etc/init.d/lcd export HOME case "$1" in start) echo "Starting LCD" /home/pi/raspberry.tips.lcd.py 2>&1 & ;; stop) echo "Stopping LCD" LCD_PID=`ps auxwww | grep raspberry.tips.lcd.py | head -1 | awk '{print $2}'` kill -9 $LCD_PID ;; *) echo "Usage: /etc/init.d/lcd {start|stop}" exit 1 ;; esac exit 0 |