Alle Programme können von hier heruntergeladen werden. |
Einführung |
Digitalanzeigen werden bei den Mikroprozessoren oft dazu verwendet, Systeminformationen auszugeben. Sie können aus einfachen LEDs bestehen, die kontinuierlich/blinkend/gedimmt ein- und ausgeschaltet werden. LED-Arrays können in Zeilen oder zweidimensional, zum Beispiel als 7-Segment-Anzeige angeordnet sein. Erhältlich sind auch text- und grafikfähige Displays in verschiedenen Grössen. Mit Ausnahme der einfachsten LED-Anzeigen, ist der Umgang mit Displays nicht trivial und setzt oft die Verwendung von speziellen Software-Bibliotheken, sogenannten Display-Treiber, voraus. Es wird empfohlen, in jedem Mikrocontrollerprojekt einfache Anzeigen zur Statusangabe vorzusehen. Bereits die grün blinkende LED des Raspberry Pi liefert wertvolle Informationen. Die hier zuerst gezeigten 7-Segmentanzeigen stellen einen guter Kompromiss zwischen Einfachheit und Vielseitigkeit dar. Kompliziertere alphanumerische/grafische Displays werden später behandelt. Eine 7-Segmentanzeige besteht aus 7 LEDs (+eventuell einem Dezimalpunkt). Eine 4-stellige Anzeige, die aus 4 Displays besteht, benötigt 28 digitale Outputports, was die Möglichkeiten des GPIO übersteigt (und wenig sinnvoll ist). Es gibt verschiedene Möglichkeiten, die Anschlüsse zu reduzieren. Time Multiplexing:
Codierung:
Mit dieser Codierung benötigt man für die Darstellung der 4 Ziffern (einschliesslich 4 Dezimalpunkte) nur 4 Bytes. Mehr Informationen über die Zeichenzuordnung und welche ASCII Zeichen angezeigt werden können, finden Sie unter mapping sheet. Serielle Datenkommunikation: Das I2C Protokoll benötigt nur 3 Leitungen: GND, SDA (Serial DAta), SCL (Serial CLock). Der Bus-Master (in der Regel der Mikroprozessor) sendet die serialisierten Bits über die SDA-Leitung, wobei SCL wird für die Synchronisation von Master und Slave verantwortlich ist. Jeder Slave wird durch seine I2C Adresse, die aus 7 Bits besteht (0x00 bis 0x7F), identifiziert. Nachdem Sie einen I2C-Device an das GPIO angeschlossen haben, können Sie seine Adresse in einem Linux-Terminal mit i2cdetect -y 1 (für alte Raspberry Pi Typ A i2cdetect -y 0) herausfinden.
In Python wird am häufigsten die SMBus-Bibliothek verwendet, in der die Geräteadressen als 7-bit-Adressen definiert werden. Eine Zusammenfassung der wichtigsten Funktionen finden Sie hier. Ein einfaches Erkennungsprogramm für I2C in Python sendet auf allen möglichen 128 Adressen ein read_byte() Kommando. Falls dabei eine Exception geworfen wird, so ist der Device nicht vorhanden. Erkennungsprogramm für I2C Devices :[►] # I2CDetect.py import smbus def getI2CDevices(): bus = smbus.SMBus(1) addresses = [] for address in range(128): try: bus.read_byte(address) addresses.append(address) except: pass return addresses print "Found I2C devices at:" devices = getI2CDevices() for address in devices: print("0x" + format(address, "02X")) Programmcode markieren
|
Experiment 1: Verwendung des Didel PyTell-Displays |
Bezugsquelle: PyTell Display (http://www.didel.com). Mehrere Musterbeispiele und die PyTell-Treiberbibliothek können hier heruntergeladen werden. PyTell ist ein Low-Power Miniatur 4-Ziffer-Display, das mit 3V (@20mA) bis 5.5V (@30mA) arbeitet. Der Device verwendet ein einfaches Kommunkationsprotokoll über I2C. Nach der Übertragung der Daten übernimmt der eingebaute PIC-Microcontroller die Darstellung auf dem Hex-Display. Dadurch wird der GPIO-Bus vollständig entlastet, nachem die Daten übermittelt wurden. Ziel: Schaltschema:
Programm: zeigt "0123" an [►] # Display1a.py # Write 4 bytes (integers) import smbus i2c_address = 0x20 bus = smbus.SMBus(1) # RPi revision 2 (0 for revision 1) cmd = 1 # segment mode data = [63, 6, 91, 79] # 0123 bus.write_block_data(i2c_address, cmd, data) Bemerkungen: Programm: Zeigt zuerst "run", dann Zahlen von 0 bis 1000 und zuletzt "donE" an [►] # Display1b.py import smbus import time PATTERN = {' ': 0, '!': 134, '"': 34, '#': 0, '$': 0, '%': 0, '&': 0, '\'': 2, '(': 0, ')': 0, '*': 0, '+': 0, ',': 4, '-': 64, '.': 128, '/': 82, '0': 63, '1': 6, '2': 91, '3': 79, '4': 102, '5': 109, '6': 125, '7': 7, '8': 127, '9': 111, ':': 0, ';': 0, '<': 0, '=': 72,'>': 0, '?': 0,'@': 93, 'A': 119,'B': 124,'C': 57, 'D': 94, 'E': 121, 'F': 113, 'G': 61, 'H': 118, 'I': 48, 'J': 14, 'K': 112, 'L': 56, 'M': 85, 'N': 84, 'O': 63, 'P': 115, 'Q': 103, 'R': 80, 'S': 45, 'T': 120, 'U': 62, 'V': 54, 'W': 106, 'X': 73, 'Y': 110, 'Z': 27, '[': 57, '\\': 100, ']': 15, '^': 35, '_': 8, '`': 32, 'a': 119, 'b': 124, 'c': 88, 'd': 94, 'e': 121, 'f': 113, 'g': 61, 'h': 116, 'i': 16, 'j': 12, 'k': 112, 'l': 48, 'm': 85, 'n': 84, 'o': 92, 'p': 115, 'q': 103, 'r': 80, 's': 45, 't': 120, 'u': 28, 'v': 54, 'w': 106, 'x': 73, 'y': 110, 'z': 27, '{': 0, '|': 48, '}': 0, '~': 65} def toSegment(text): data = [] for c in text: data.append(PATTERN[c]) return data i2c_address = 0x20 bus = smbus.SMBus(1) # RPi revision 2 (0 for revision 1) cmd = 1 # segment mode text = "run " data = toSegment(text) bus.write_block_data(i2c_address, cmd, data) time.sleep(3) for i in range(1001): text = "%4d" %i # right adjusted data = toSegment(text) bus.write_block_data(i2c_address, cmd, data) time.sleep(0.01) time.sleep(3) text = "donE" data = toSegment(text) bus.write_block_data(i2c_address, cmd, data) Bemerkungen: Programm: Zeigt den scrollenden und blinkenden Text [►] # Display1c.py from pytell import PyTell import time pt = PyTell() pt.showText("run") time.sleep(3) text = "HELLO Python" pt.showTicker(text, count = 2, speed = 4, blocking = True) text = "8ye" pt.showBlinker(text, dp = [0, 0, 0, 1], count = 4, speed = 2, blocking = True) Bemerkungen: |
Experiment 2: Verwendung des 4tronix Pi2Go Displays |
Bezugsquelle: IP Display Dongle/7-Segment Display (http://www.4tronix.co.uk/store) Diese 4-stellige 7-Segmentanzeige wird in erster Linie dazu verwendet, die IP-Adresse anzuzeigen, wenn ein Pi2Go-Roboter mit einem WLAN-Hotspot verbunden ist. Sie kann aber auch ohne einen Pi2Go-Roboter als allgemeine Anzeige eingesetzt werden. Wie beim PyTell-Display, wird das I2C-Protokoll für den Datentransfer verwendet. Der eingebaute MCP23017 16-bit I/O Expander-Chip stellt die notwendige Anzahl von digitalen Ausgangsleitungen zur Verfügung, um eine einzelne Ziffer anzuzeigen. Es ist dann Aufgabe des Programms, mit Multiplexing alle 4 Ziffern anzuzeigen. Ziel: Schaltschema:
Wie viele andere I2C-Devices verwendet der MCP23017 einen Control-Register, mit welchen der Betriebsmodus ausgewählt wird. Es ist immer wieder eine besondere Anstrengung nötig um herauszufinden, welche Bitwerte in das Control-Register geschrieben werden müssen. Ohne auf Einzelheiten einzugegehen, zeigen wir im folgenden Programm wie das Display unter der Verwendung der SMBus-Bibliothek verwendet wird. Programm: Zeigt ein Zeichen nach dem anderen an [►] # Display2a.py from smbus import SMBus import time def setup(): bus.write_byte_data(i2c_address, 0x00, 0x00) # Set all of bank 0 to outputs bus.write_byte_data(i2c_address, 0x01, 0x00) # Set all of bank 1 to outputs def setValue(val, digit): ''' @param digit: 0: leftmost digit @param val: 0..255: segment value ''' n = (1 << (3 - digit)) ^ 255 bus.write_byte_data(i2c_address, 0x13, n) bus.write_byte_data(i2c_address, 0x12, val) i2c_address = 0x20 bus = SMBus(1) # For revision 2 Raspberry Pi setup() word = [118, 119, 56, 63] # HALO for i in range(4): setValue(word[i], i) time.sleep(2) Bemerkungen: setup() word = [118, 119, 56, 63] # HALO while True: for i in range(4): setValue(word[i], i) time.sleep(0.002) setValue(0, i) time.sleep(0.002) Der Prozessor wird durch das Multiplexing relativ stark belastet. (Daher ist die Verwendung eines On-Board Mikrocontrollers wie bei PyTell-Display besser.) Es ist wiederum eine schöne Programmieraufgabe, einen Display-Treiber zu schreiben, der den Code für das Multiplexing kapselt, sowie Scrollen und Blinken unterstützt. Laden Sie das Modul Disp4tronix.py (und einige nützliche Musterbeispiele) von hier herunter und kopieren Sie es in das Verzeichnis, in dem sich Ihr Programm befindet. Dann können Sie die diversen Display-Funktionen ausprobieren. Programm: Zeigt den scrollenden und blinkenden Text [►] # Display2c.py from Disp4tronix import Disp4tronix import time dp = Disp4tronix() dp.showText("run") time.sleep(3) text = "HELLO Python" dp.showTicker(text, count = 2, speed = 4, blocking = True) text = "8ye" dp.showBlinker(text, dp = [0, 0, 0, 1], count = 4, speed = 2, blocking = True) Bemerkungen: |
Experiment 3: Ein 7-Segment Display im Eigenbau |
Bezugsquelle: ELV (http://www.elv.de), 7-Segment-Anzeige, Bestellnummer 105697 Eine Digitalanzeige kann auch unter der Verwendung eines SAA1064 Display-Treibers gemäss dem unten stehenden Schema (aus dem Internet) selbst aufgebaut werden. Leider wird der SAA1064 im DIL- und SMD-Package nicht mehr hergestellt. Sie finden aber verschiedene Anbieter auf Ebay oder können einen vollständigen Bausatz mit einem 4 Tasten-Panel, einem I2C mit einem Temperatur-Module und verschiedene Frontplatten bei ELV kaufen.
Ziel: Schaltschema: Die Adressenauswahl erfolgt durch einen Spannungsteiler, der die Spannung am ADR-Eingang gemäss folgender Tabelle erzeugt:
Falls ADR auf GND gesetzt ist, so ist also die 7-bit Adresse 0x38 ausgewählt. Die beiden zusätzlichen Transistoren können irgendein NPN-Standardtyp sein (z.B. BC547, 2N2222, usw). Das Display wird mit der 5V-Versorgung des Raspberry Pi (GPIO Pin # 2) betrieben. SDA und SCL sind direkt mit GPIO Pin #3 bzw. Pin #5 verbunden. Obschon das Display mit 5 V versorgt wird, sind keine Pegelwandler oder Pullup-Widerstände notwendig. Das ELV-Panel, das aus einer 4-stelligen Digitalanzeige und vier Buttons besteht, eignet sich vom Konzept her gut für Projekte für Home-Automation mit dem Raspberry Pi als Steuereinheit. Unter alleiniger Verwendung der SMBus-Bibliothek ist die Display-Programmierung etwas trickreich. Das erforderliche Know-how können Sie aus aber dem folgenden Beispiel entnehmen. Programm: "0123" anzeigen [►] # Display3a.py import smbus import time i2c_address = 0x38 bus = smbus.SMBus(1) # RPi revision 2 (0 for revision 1) def setup(): instruction_byte = 0x00 control_byte = 0b00010111 # b0 = 1: dynamic mode (autoincrement digits) # b1 = 1: digit 1/3 not blanked, b2 = 1: digit 2/4 not blanked # b4 = 1: 3 mA segment current # write to control register bus.write_byte_data(i2c_address, instruction_byte, control_byte) def clear(): bus.write_i2c_block_data(i2c_address, 1, [0, 0, 0, 0]) setup() data = [63, 6, 91, 79] # 0123 # write starting from digit 1 bus.write_i2c_block_data(i2c_address, 1, data) time.sleep(5) clear() Bemerkungen: Programm: Zeigt "run", dann nacheinander Zahlen von 1 bis 1000 und "donE" [►] # Display3b.py import smbus import time PATTERN = {' ': 0, '!': 134, '"': 34, '#': 0, '$': 0, '%': 0, '&': 0, '\'': 2, '(': 0, ')': 0, '*': 0, '+': 0, ',': 4, '-': 64, '.': 128, '/': 82, '0': 63, '1': 6, '2': 91, '3': 79,'4': 102, '5': 109, '6': 125, '7': 7, '8': 127, '9': 111, ':': 0, ';': 0, '<': 0, '=': 72, '>': 0, '?': 0, '@': 93, 'A': 119, 'B': 124, 'C': 57, 'D': 94, 'E': 121,'F': 113, 'G': 61, 'H': 118, 'I': 48, 'J': 14, 'K': 112, 'L': 56, 'M': 85, 'N': 84, 'O': 63, 'P': 115, 'Q': 103, 'R': 80, 'S': 45, 'T': 120, 'U': 62, 'V': 54, 'W': 106, 'X': 73, 'Y': 110, 'Z': 27, '[': 57, '\\': 100, ']': 15, '^': 35, '_': 8, '`': 32, 'a': 119, 'b': 124, 'c': 88, 'd': 94, 'e': 121, 'f': 113, 'g': 61, 'h': 116, 'i': 16, 'j': 12, 'k': 112, 'l': 48, 'm': 85, 'n': 84, 'o': 92, 'p': 115, 'q': 103, 'r': 80, 's': 45, 't': 120, 'u': 28, 'v': 54, 'w': 106, 'x': 73, 'y': 110, 'z': 27, '{': 0, '|': 48, '}': 0, '~': 65} i2c_address = 0x38 bus = smbus.SMBus(1) def setup(): instruction_byte = 0x00 control_byte = 0b00010111 # b0 = 1: dynamic mode (autoincrement digits) # b1 = 1: digit 1/3 not blanked, b2 = 1: digit 2/4 not blanked # b4 = 1: 3 mA segment current # write to control register bus.write_byte_data(i2c_address, instruction_byte, control_byte) def toSegment(text): data = [] for c in text: data.append(PATTERN[c]) return data setup() text = "run " data = toSegment(text) bus.write_i2c_block_data(i2c_address, 1, data) time.sleep(3) for i in range(1001): text = "%4d" %i # right adjusted data = toSegment(text) bus.write_i2c_block_data(i2c_address, 1, data) time.sleep(0.01) time.sleep(3) text = "donE" data = toSegment(text) bus.write_i2c_block_data(i2c_address, 1, data) Bemerkungen: Programm: Zeigt scrollenden und blinkenden Text [►] # Display3c.py from py7seg import Py7Seg import time ps = Py7Seg() ps.setBrightness(7) ps.showText("run") time.sleep(3) text = "HELLO Python" ps.showTicker(text, count = 2, speed = 4, blocking = True) text = "8ye" ps.showBlinker(text, dp = [0, 0, 0, 1], count = 4, speed = 2, blocking = True) |
Experiment 4: Verwendung alphanumerischer Displays |
Im Vergleich zu einer einfachen 4-stelligen Digitalanzeige eröffnet ein alphanumerisches oder sogar grafikfähiges Display eine neue Dimension für Benutzerinteraktionen. Wegen ihrem hohen Kontrastverhältnis und dem geringen Stromverbrauch werden immer häufiger OLED-Displays eingesetzt.
Wie zu erwarten, ist die Kommunikation mit dem SSD1306-Controller ziemlich aufwendig. Glücklicherweise schrieb Tony DiCola von Adafruit einen Python-Treiber für die registerbezogenen Aufrufe. Da er für den Display-Reset, der meist nicht benützt wird, einen zusätzlichen GPIO-Port verwendet, haben wir den Treiber leicht modifiziert und stellen ihn als SSD1306.py zur Verfügung. Ausserdem haben wir eine dünne Software-Schicht OLED1306.py darüber gelegt, um die Verwendung des Displays zu vereinfachen. Beide Module (und einige Textfonts, Beispielprogramme und Bilder) können Sie von hier herunterladen. Programm: Zeigt eine Zeile [►] # Display4a.py import RPi.GPIO as GPIO from OLED1306 import OLED1306 disp = OLED1306() disp.setText("Hello Python") Um eine Grafik anzuzeigen, sollte die Bilddatei ein PPM-Format mit der Grösse 128x64 (B/W) haben. Sie können PPM-Bilder beispielsweise mit Photoshop bearbeiten. Verwenden und bearbeiten Sie eines der Beispielbilder, um das spezielle Bildformat kennenzulernen. Programm: Zeigt das Bild /home/pi/Pictures/einstein.ppm kombiniert mit Text [►] # Display4b.py from OLED1306 import OLED1306 disp = OLED1306("/home/pi/Pictures/einstein.ppm") disp.setText("God\ndoes not\nplay dice!", 0, 15, 60) # Parameters: text, line number, font size, indent (pixels) Das OLED1306-Modul unterstützt auch konsolenartiges Scrollen. Programm: Zeigt automatisches Zeilen-Scrollen[►] # Display4c.py from OLED1306 import OLED1306 import time disp = OLED1306() nb = 1 while True: disp.println("Line #" + str(nb)) nb += 1 time.sleep(0.5) Mehr Informationen zur Klasse OLED1306 finden Sie in der Python Doc. Beachten Sie, dass die OpenSans Font Familie, die unter /home/pi/Fonts gespeichert werden muss, als Standardschriftart verwendet wird. |
Experiment 5: Verwendung des TM1637 4-Digit Displays |
Es wird ein spezielles Protokoll verwendet (ähnlich, aber nicht gleich wie I2C). Es gibt viele Bezugsquellen (Arduino/Raspberry Pi-Lieferanten, Grove, eBay, der Preis schwankt zwischen $1 und $10). Mehr Informationen zur Klasse FourDigit finden Sie in der Python Doc. Programm: Endloszähler 0..9999 [►] from TM1637 import FourDigit d = FourDigit() while True: for n in range(10000): d.show(n) Es ist sehr einfach, einen scrollenden Text anzuzeigen. Mit den Methoden toLeft() und toRight() hat man mehr Freiheiten als mit scroll(), die blockiert, bis der Text ganz angezeigt ist. Programm: Lauftext (endlos) [►] from TM1637 import FourDigit d = FourDigit() while True: d.scroll("HELLo PYthon") Als sinnvolle Anwendung wird auf dem Display die aktuelle Uhrzeit angezeigt, wobei der Doppelpunkt im Sekundentakt blinkt. Dazu wir die Realtime-Clock DS1307 verwendet, wie dies im Kapitel Timer beschrieben ist. Dort ist auch zu entnehmen, wie die Uhr gestellt wird. Programm: Digitaluhr [►] from RTC_DS1307 import RTC from time import sleep from TM1637 import FourDigit d = FourDigit() rtc = RTC() showColon = True while True: hr = rtc.getHours() min = rtc.getMinutes() d.show("%02d%02d" %(hr, min)) d.setColon(showColon) showColon = not showColon sleep(0.5) Damit die Vornullen bei einstelligen Stunden und Minuten erscheinen, wird mit dem Stringformat %02d auf den Display geschrieben.
|