Python exemplarisch - RPi Tutorial
deutsch     english

RaspEasy: EIN EXPERIMENTIER-BOARD VON DIDEL

 

Alle Programme können von hier heruntergeladen werden.

Vorbemerkung: Dieses Kapitel kann auch als unabhängige Einführung in die Sensorik behandelt werden. Es enthält daher gewisse Wiederholungen.


 

Einführung

 
In den vorangegangenen Kapiteln haben Sie erfahren, wie man bestimmte elektronische Bauelemente mit dem Raspberry Pi betreiben kann. Oft haben wir dabei eine Steckplatine verwendet, manchmal musste man sogar einige Lötarbeit leisten. Im Prinzip war die Verkabelung einfach, aber der Raspberry Pi kann leicht durch eine Unachtsamkeit beschädigt werden (zum Beispiel wenn man mehr als 3,3 V an einen GPIO-Pin anschliesst). Darüber hinaus müssen Sie alle elektronischen Bauteile als Einzelteile beschaffen (Buttons, LEDs, usw.).   raspeasy0

Um die grundlegenden Experimente mit dem Raspberry Pi zu vereinfachen, empfehlen wir, ein billiges, aber gut durchdachtes Modul von Didel, genannt RaspEasy, zu verwenden. Sie stecken einfach das Modul in den 40-Pin GPIO-Steckplatz ein und schon sind Sie bereit für grundlegende Experimente , ohne sich um die Verbindungskabel kümmern zu müssen.

Bezugsquelle:
http://www.didel.com
Didel, CH-1092 Belmont, Switzerland

Spezifikationen:
  • 2 ADCs MCP3021 (10 bit, I2C)
  • 2 Buttons
  • 2 LEDs
  • Grove/Minigrove-Anschlüsse
  • Überspannungsschutz auf allen Eingängen
  • Zur Verfügung stehen noch kompatible Zusatzteile wie:
    Sieben-Segment und Oled-Display, Potentiometer, Activbuzzer, usw.
    (Mehr Informationen finden Sie auf der Didel-Webseite).

Funktionsschema:

raspeasy22

 

Steckerbelegung:

raspeasy1

 

 

 

Experiment 1: GPIO-Port als digitalen Input/Output verwenden

 

Ziel:
Wenn der Button A gedrückt gehalten wird, leuchtet die LED A. Beim Loslassen des Buttons wird die LED ausgeschaltet. Analog kann mit dem Button B die LED B ein- und ausgeschaltet werden.

Programm: [►]

# RaspEasy1.py
# Button press/release to switch on/off LED

import RPi.GPIO as GPIO


P_BUTTON = 12 # Button A
#P_BUTTON = 13 # Button B
P_LED = 7 # LED A
#P_LED = 11 # LED B

def setup():
    GPIO.setmode(GPIO.BOARD)
    GPIO.setup(P_BUTTON, GPIO.IN)
    GPIO.setup(P_LED, GPIO.OUT)

print "starting..."
setup()
while True:
    if GPIO.input(P_BUTTON) == GPIO.HIGH:
        GPIO.output(P_LED, GPIO.HIGH)
    else:
        GPIO.output(P_LED, GPIO.LOW)
Programmcode markieren (Ctrl+C kopieren, Ctrl+V einfügen)

Bemerkungen:
Auf der Platine sind zwei Tastenschalter A und B fest eingebaut und mit den Pins #12 und #13 verbunden. Wenn ein Button losgelassen wird, wird der Eingang mit einem Widerstand auf Masse heruntergezogen (LOW), wenn der Button gedrückt wird, ist die Eingangsspannung 3.3V (HIGH) und die LED wird eingeschaltet. Diese Polarität wird manchmal als "positive Logik" bezeichnet.

Im obigen Beispiel wird der Zustand des Input-Pins in einer while-True-Schleife abgefragt und das Programm wird erst beendet, wenn der Python-Prozess abgebrochen wird. Dies ist gemäss der GPIO-Dokumentation eigentlich kein sauberes Programmende, da die Funktion GPIO.cleanup() nie aufgerufen wird. (Es können einige GPIO-Zustände bis zur Ausführung des nächsten Python-Programms "überleben".)

Da mit unseren Entwicklungsumgebungen (TigerJython und Geany) bei jedem Programmstart alle laufenden Python-Prozesse "gekillt" werden, gibt es mit while-True-Schleifen keine Schwierigkeiten. Wenn Sie es aber besser machen möchten, so werfen Sie einen Blick auf Experiment 4.

 

 

ttt

Experiment 2: Zählen von Tastenbetätigungen, Schalterprellen

 

Ziel:
Jedesmal, wenn die Taste gedrückt wird, soll eine Zählvariable um eins erhöht werden. Der aktuelle Zählerstand wird in der Konsole angezeigt.

Auf den ersten Blick scheint alles einfach zu sein: Sie ergänzen das vorhergehende Programm mit einem Zähler.

Programm: [►]

# RaspEasy2.py
# Button counter

import RPi.GPIO as GPIO

P_BUTTON = 12 # Button A

def setup():
    GPIO.setmode(GPIO.BOARD)
    GPIO.setup(P_BUTTON, GPIO.IN)

print "starting..."
setup()
count = 0
while True:
    if GPIO.input(P_BUTTON) == GPIO.HIGH:
        count += 1
        print count
Programmcode markieren (Ctrl+C kopieren, Ctrl+V einfügen)

Bemerkungen:
Sie merken sofort, dass etwas nicht stimmt. Hält man die Taste gedrückt, so wird der Wert der Zählvariablen laufend erhöht. Das ist ja aber auch logisch, denn die Anweisung count += 1 wird wiederholt ausgeführt, solange der Button gedrückt ist. Was ist das Heilmittel?

Am besten betrachten Sie das System als einen Automat, der sich in bestimmten Zuständen befinden kann. Es gibt offenbar zwei Zustände: "Losgelassen" (ButtonUp) und "Gedrückt" (ButtonDown). Nur wenn eine Zustandsänderung von ButtonUp zu ButtonDown eintritt, darf der Zähler um 1 erhöht werden. Für die Umsetzung dieser Idee definiert man am besten eine boolesche Variable isButtonPressed, die je nach Zustand wahr oder falsch ist. Der nächste Versuch sieht dann wie folgt aus:

Programm:[►]

# RaspEasy2a.py
# Button counter, 2nd attempt

import RPi.GPIO as GPIO

P_BUTTON = 12 # Button A

def setup():
    GPIO.setmode(GPIO.BOARD)
    GPIO.setup(P_BUTTON, GPIO.IN)

print "starting..."
setup()
count = 0
isButtonPressed = False
while True:
    if GPIO.input(P_BUTTON) == GPIO.HIGH and not isButtonPressed:
        isButtonPressed = True
        count += 1
        print count
    elif GPIO.input(P_BUTTON) == GPIO.LOW and isButtonPressed:
        isButtonPressed = False
Programmcode markieren (Ctrl+C kopieren, Ctrl+V einfügen)

Bemerkungen:
Das Programm funktioniert schon fast perfekt... aber doch nicht ganz: Drücken Sie schnell hintereinander und mit wenig Kraft die Taste, so bemerken Sie, dass der Zähler manchmal um zwei oder drei erhöht wird, obwohl Sie die Taste nur einmal gedrückt haben. Dieses sporadische Falschverhalten ist sehr ärgerlich und kann das Vertrauen in die Elektronik und Informatik trüben. Was ist der Grund für diese Fehler?

Hier die Erklärung:
Beim Schliessen des Schalters drücken Sie zwei mechanische Kontakte zusammen und erstellen damit eine leitende elektrische Verbindung zwischen den Kontakten. Wenn Sie beim Drücken keine allzu grosse Kraft anwenden, kann sich der Kontakt für eine kurze Zeit wieder öffnen, bis er endgültig geschlossen wird. So kann passieren, dass der Schalter zweimal (oder mehrmals) kurz hintereinander geschlossen wird.
raspeasy6

Das Gleiche kann beim Loslassen passieren: Der Kontakt öffnet und schliesst mehrere Male kurz hintereinander. Dieser Effekt, der als Schalterprellen bezeichnet wird, bewirkt bei Anwendungen, bei denen die Anzahl der Schliess- oder Öffnungsoperationen eine Rolle spielt, unvorhersehbare Resultate.

Wie kann man die Auswirkungen des Schalterprellens vermeiden:

Wir können Prellen auf zwei Arten bekämpfen: hardwaremässig oder softwaremässig. Im ersten Fall fügen wir zusätzliche Elektronik-Elemente hinzu (ein RS-Flip-Flop oder ein RC-Glied), oder wir beseitigen das Problem softwaremässig und ändern das Programm gemäss folgender Idee:

Der Wert des Eingangs wird mit GPIO.input() in der Endlosenschleife in sehr kurzen Zeitabständen abgefragt. Wenn das Programm zum ersten Mal ein HIGH erkennt, so ist dies der Beginn einer ButtonPress-Phase. Wir unterbinden nun das Pollen für eine kurze Zeit, sagen wir 100 ms und ignorieren damit die möglicherweise nachfolgenden Zustandswechsel.

raspeasy7


Nachdem der Button losgelassen wurde, betrachten wir dies als Beginn der ButtonRelease-Phase und unterbinden das Pollen für kurze Zeit, wodurch die "Preller" ignoriert werden.
raspeasy7

Programm:[►]

# RaspEasy2b.py
# Button counter, 3rd attempt

import RPi.GPIO as GPIO
import time

P_BUTTON = 12 # Button A

def setup():
    GPIO.setmode(GPIO.BOARD)
    GPIO.setup(P_BUTTON, GPIO.IN)

print "starting..."
setup()
count = 0
isButtonPressed = False
while True:
    if GPIO.input(P_BUTTON) == GPIO.HIGH and not isButtonPressed:
        isButtonPressed = True
        count += 1
        print count
        time.sleep(0.1)
    elif GPIO.input(P_BUTTON) == GPIO.LOW and isButtonPressed:
        isButtonPressed = False
        time.sleep(0.1)
Programmcode markieren (Ctrl+C kopieren, Ctrl+V einfügen)

Bemerkungen:
Wie Sie sehen, haben wir den Befehl time.sleep() in den if- und den elif- Blocks eingebaut. Wäre es nicht eleganter, den Befehl nur einmal ans Ende der while-Scheife zu setzen? Dies würde zwar das Prellen auch beheben, ist aber doch nicht völlig gleichwertig. Denn es gibt damit auch im "Ruhezustand", also wenn die Taste losgelassen ist, eine Verzögerung. Klickt man die Taste nur ganz kurz (kürzer als 100 ms), so könnte dieser Klick möglicherweise unerkannt bleiben.

Wie Sie sehen, gibt es bereits bei der Handhabung eines Tastenschalters einige Tücken.

Für eine lustige Anwendung, die auch ohne angeschlossenes Entwicklungssystem (autonom) Sinn macht, können Sie den Zählerwert auf einem 7-Segment- oder OLED-Display anzeigen.

Programm:[►]

# RaspEasy2c.py
# Button counter, use Oled or PyTell display

import RPi.GPIO as GPIO
import time
from OLED1306 import OLED1306
#from pytell import PyTell

P_BUTTON = 12 # Button A

def setup():
    GPIO.setmode(GPIO.BOARD)
    GPIO.setup(P_BUTTON, GPIO.IN)

print "starting..."
oled = OLED1306()
oled.setFontSize(50)
#pyTell = PyTell()

setup()
count = 0
oled.setText(str(count))
#  pyTell.showText("%4d" %count)
isButtonPressed = False
while True:
    if GPIO.input(P_BUTTON) == GPIO.HIGH and not isButtonPressed:
        isButtonPressed = True
        count += 1
        oled.setText(str(count))
#        pyTell.showText("%4d" %count)
        time.sleep(0.1)
    elif GPIO.input(P_BUTTON) == GPIO.LOW and isButtonPressed:
        isButtonPressed = False
        time.sleep(0.1)
Programmcode markieren (Ctrl+C kopieren, Ctrl+V einfügen)

Bemerkungen:
Je nach Display müssen Sie entweder das Modul pytell.py oder OLED1306.py Modul importieren (und dieses, sowie beim Oled auch SSD1306.py auf den Raspberry Pi kopieren). Die Dateien befinden sich in der Distribution.

 

 

ttt

Experiment 3: LED Umschalter

 

Ziel:
Wenn eine Taste gedrückt wird, leuchtet eine LED auf und bleibt eingeschaltet, bis die Taste erneut gedrückt wird.

Programm:[►]

# RaspEasy3.py
# LED switcher

import RPi.GPIO as GPIO
import time

P_BUTTON = 12 # Button A
P_LED = 7 # LED A

def setup():
    GPIO.setmode(GPIO.BOARD)
    GPIO.setup(P_BUTTON, GPIO.IN)
    GPIO.setup(P_LED, GPIO.OUT)
    GPIO.output(P_LED, GPIO.LOW) # Turn off LED

print "starting..."
setup()
isLedOn = False
isButtonPressed = False
while True:
    if GPIO.input(P_BUTTON) == GPIO.HIGH and not isButtonPressed:
        isButtonPressed = True
        if isLedOn:
            isLedOn = False
            GPIO.output(P_LED, GPIO.LOW)
        else:
            isLedOn = True
            GPIO.output(P_LED, GPIO.HIGH)
        time.sleep(0.1)
    elif GPIO.input(P_BUTTON) == GPIO.LOW and isButtonPressed:
        isButtonPressed = False
        time.sleep(0.1)
Programmcode markieren (Ctrl+C kopieren, Ctrl+V einfügen)

Bemerkungen:
Dieses Experiment ist ähnlich wie dasjenige mit dem Zähler, nur wird anstelle einer Zählvariable eine LED verwendet. Der Zähler wird sozusagen beim Drücken der Taste von 0 auf 1 erhöht und beim nächsten Drücken statt inkrementiert wieder auf 0 zurückgesetzt. Da der Zähler nur zwei Werte hat, kann er durch eine boolesche Variable isLedOn =False oder True ersetzt werden. Diese Variable ist eine "Zustandsvariable ", weil sie den aktuellen Zustand der LED beschreibt.

 

 

ttt

Experiment 4: Start/Stop/Exit-Manager

 

Ziel::
Buttons werden oft verwendet, um einen Programmablauf interaktiv zu steuern. In unserem Beispiel wird beim Drücken der Taste A ein Zählprozess gestartet bzw. beendet. Wenn die Taste B gedrückt wird, wird das Programm beendet.

Programm:[►]

# RaspEasy4.py
# Start/Stop, Terminate

import RPi.GPIO as GPIO
import time

RUN_BUTTON = 12 # Button A
EXIT_BUTTON = 13 # Button B

def setup():
    GPIO.setmode(GPIO.BOARD)
    GPIO.setup(RUN_BUTTON, GPIO.IN)
    GPIO.setup(EXIT_BUTTON, GPIO.IN)

setup()
count = 0
isCounting = False
isRunButtonPressed = False
print "Stopped"
isExiting = False
while not isExiting:
    if GPIO.input(RUN_BUTTON) == GPIO.HIGH and not isRunButtonPressed:
        isRunButtonRunPressed = True
        if not isCounting:
            isCounting = True
            print "Counting..."
        else:
            isCounting = False
            print "Stopped"
        time.sleep(0.1)
    elif GPIO.input(RUN_BUTTON) == GPIO.LOW and isRunButtonPressed:
        isRunButtonPressed = False
        time.sleep(0.1)

    if isCounting:
        count += 1
        print count
        time.sleep(0.01)

    if GPIO.input(EXIT_BUTTON) == GPIO.HIGH:
        isExiting = True
 
GPIO.cleanup()        
print "Programm terminated"
Programmcode markieren (Ctrl+C kopieren, Ctrl+V einfügen)

Bemerkungen:
Das Programm-Design ist typisch: Die while-Schleife wird so lange ausgeführt, bis der Exit-Button (B) gedrückt wird. Um die Schleife abzubrechen, wird das Flag isExiting verwendet. Durch Drücken des Exit-Buttons wird das Flag auf False gesetzt, wodurch der weitere Schleifendurchlauf abgebrochen wird. Nach dem Verlassen der Schleife können nun die nötigen "Aufräumarbeiten" durchgeführt werden, bevor das Programm terminiert. Das zweite Flag isCounting wird auf True oder False gesetzt, je nachdem, ob sich das Programm im zählenden oder nicht-zählenden Zustand befindet. Diese Zustandsänderung wird durch Drücken der Taste A bewirkt.

Man könnte die while-Schleife auch mit einem break verlassen und damit auf das Flag isExiting verzichten:

while True:
    ...
    if GPIO.input(EXIT_BUTTON) == GPIO.HIGH:
        break
    ...

 

ttt

Experiment 5: Morsecode mit einem Buzzer abspielen

 

Ziel::
Ein Aktiv-Buzzer reagiert ähnlich wie eine LED: Wenn das Eingangssignal hoch ist, wird ein Ton mit einer vordefinierten Frequenz und Lautstärke abgespielt. Verwenden Sie einen Buzzer, um einige Morse-Zeichen zu spielen.

Programm:[►]

# RaspiEx5.py

import RPi.GPIO as GPIO
import time
#from OLED1306 import OLED1306

P_BUZZER = 40 # adapt to your wiring
dt = 0.1 # adapt to your Morse speed

morse = {
'a':'.-'   , 'b':'-...' , 'c':'-.-.' , 'd':'-..'  , 'e':'.'    ,
'f':'..-.' , 'g':'--.'  , 'h':'....' , 'i':'..'   , 'j':'.---' ,
'k':'-.-'  , 'l':'.-..' , 'm':'--'   , 'n':'-.'   , 'o':'---'  ,
'p':'.--.' , 'q':'--.-' , 'r':'.-.'  , 's':'...'  , 't':'-'    ,
'u':'..-'  , 'v':'...-' , 'w':'.--'  , 'x':'-..-' , 'y':'-.--' ,
'z':'--..' , '1':'.----', '2':'..---', '3':'...--', '4':'....-',
'5':'.....', '6':'-....', '7':'--...', '8':'---..', '9':'----.',
'0':'-----', '-':'-....-', '?':'..--..', ',':'--..--', ':':'---...',
'=':'-...-'}

def s(n):  # wait
    time.sleep(n * dt)

def setup():
    GPIO.setmode(GPIO.BOARD)
    GPIO.setup(P_BUZZER, GPIO.OUT)
    GPIO.output(P_BUZZER, GPIO.LOW) # Turn off buzzer
    
def dot():
    GPIO.output(P_BUZZER, GPIO.HIGH)
    s(1)
    GPIO.output(P_BUZZER, GPIO.LOW)
    s(1)

def dash():
    GPIO.output(P_BUZZER, GPIO.HIGH)
    s(3)
    GPIO.output(P_BUZZER, GPIO.LOW)
    s(1)

def transmit(text):
#    sent = "" # initialize string buffer
    for c in text:
#        sent += c 
#        oled.setText(sent)
        if c == " ":
            s(4)
        else:
            c = c.lower()
            if c in morse:
                k = morse[c]
                for x in k:
                    if x == '.':
                        dot()
                    else:
                        dash()
            s(2)

print "starting..."
#oled = OLED1306()
#oled.setFontSize(16)
setup()
transmit("cq de hb9abh")
GPIO.cleanup()
print "all done"
Programmcode markieren (Ctrl+C kopieren, Ctrl+V einfügen)

Bemerkungen:
Beim Morsecode ist jedes Zeichen eine Sequenz aus Punkten und Strichen. Das Timing ist sehr wichtig. Suchen Sie im Internet, wie das Timing für den Morsecode standardmässig festgelegt ist.

Wenn Sie einen OLED-Display haben, entfernen # aus den auskommentierte Zeilen. Dann wird das Zeichen, das abgespielt wird, auch gleichzeitig angezeigt. Das ist sehr praktisch, vor allem, wenn Sie nicht gelernt haben, den Morsecode akustisch zu entschlüsseln.

 

 

ttt

Experiment 6: Button-Events verwenden

 

Die Programmierung mit Events (Ereignissen) kann den Programmcode erheblich vereinfachen, da dadurch mehrere Programmaktivitäten voneinander entkoppelt werden. Das Grundprinzip ist Folgendes: Sie definieren eine sogenannte Callbackfunktion (oder kurz Callback), die nie explizit von Ihrem Programm, sondern vom System aufgerufen wird, wenn ein bestimmtes Ereignis auftritt. Der Name der Callbackfunktion wird dem System durch eine sogenannte Registrierung mitgeteilt.

(Event-Programmierung kann aber auch zu unvorhersehbaren Verhalten führen, da der Callback meist in einem separaten Thread aufgerufen wird, der mit anderen Programm-Threads in Konflikt stehen kann, wenn gemeinsame Ressourcen verwendet werden.)

Ziel:
Schreiben Sie eine ereignisgesteuerte Version des Tasten-Zählprogramms. Jedesmal, wenn die Taste gedrückt wird, sollte der Zähler um eins erhöht werden.

Das GPIO Modul unterstützt GPIO-Events: Die Funktion add_event_detect() registriert den Callback. Gleichzeitig wird dem System mitgeteilt, um welchen GPIO-Port es sich handelt und ob der Event beim Übergang von LOW auf HIGH, umgekehrt oder in beiden Fällen ausgelöst werden soll.

Programm:[►]

# RaspEasy6.py
# Using button events

import RPi.GPIO as GPIO
import time

COUNT_BUTTON = 12 # Button A
EXIT_BUTTON = 13 # Button B

def onCountButtonEvent(channel):
    global count, btnReady
    if btnReady and GPIO.input(COUNT_BUTTON) == GPIO.HIGH:
        btnReady = False
        count += 1
    else:
        btnReady = True
    time.sleep(0.1)    

def onExitButtonEvent(channel):
    global isExiting
    isExiting = True

def setup():
    GPIO.setmode(GPIO.BOARD)
    GPIO.setup(COUNT_BUTTON, GPIO.IN)
    GPIO.setup(EXIT_BUTTON, GPIO.IN)
    GPIO.add_event_detect(COUNT_BUTTON, GPIO.BOTH, onCountButtonEvent)
    GPIO.add_event_detect(EXIT_BUTTON, GPIO.BOTH, onExitButtonEvent)

setup()
btnReady = True
count = 0
oldCount = 0
print "starting..."
isExiting = False
while not isExiting:
    if count != oldCount:
        oldCount = count
        print count
    time.sleep(0.001)

GPIO.cleanup()        
print "Programm terminated"
Programmcode markieren (Ctrl+C kopieren, Ctrl+V einfügen)

Bemerkungen:
Wir registrieren den Callback onCountButtonEvent() für beide Ereignisse "PressEvent" und "ReleaseEvent" unter Verwendung des Parameterwerts GPIO.BOTH.

Im Widerspruch zur GPIO-Dokumentation beseitigt der zusätzliche Parameter bouncetime in add_event_detect () das Schalterprellen nicht vollständig. Deshalb deaktivieren wir weitere PressEvents mit dem btnReady Flag so lange, bis ein Release-Event eintritt. Zusätzlich deaktivieren wir die Events für 0,1 s durch Aufruf von time.sleep(0.1) in der Callbackfunktion, obwohl man generell Verzögerungen in Callbacks vermeiden sollte.

 

 

ttt

Experiment 7: Lesen von Analogdaten

 

Die meisten Sensoren liefern eine Spannung, die proportional (oder in einer Relation) zu der gemessenen physikalischen Grösse ist. Damit man diese Werte mit einem Computer verarbeiten kann, muss die Spannung mit einem Analog-Digital-Wandler (ADC) in ein digitales Signal umgewandelt werden. Mit einem einfachen Potentiometer (variabler Widerstand) kann man die variable Ausgangsspannung eines Sensors simulieren. Es kann direkt auf die 3-poligen Eingangsbuchsen des ADCs gesteckt werden.

Ziel:
Messen Sie jede Sekunde die Spannung und schreiben Sie die Werte mit dem print-Befehl aus.

raspeasy13
raspeasy14

Programm:[►]

# RaspEasy7.py
# Read ADC0 or ADC1 and write value to stdout

import smbus
import time

print "starting..."
bus = smbus.SMBus(1) 
adc_address = 0x48  # ADC0
# adc_address = 0x4D  # ADC 1

while True:
    # Reads word (16 bits) as int
    rd = bus.read_word_data(adc_address, 0)
    # Exchanges high and low bytes
    data = ((rd & 0xFF) << 8) | ((rd & 0xFF00) >> 8)
    # Ignores two least significiant bits
    data = data >> 2
    print "data:", data
    time.sleep(1)
Programmcode markieren (Ctrl+C kopieren, Ctrl+V einfügen)

Bemerkungen:
Der MCP3021 ist ein ADC mit einem I2C-Protokoll. Unter Verwendung des Moduls SMBus wird ein Messwert mit der Funktion read_word_data(Adresse, cmd) geholt (der Parameter cmd wird dabei nicht verendet und ist auf 0 gesetzt). Der Rückgabewert ist in den zwei niederwertigen Bytes eines Integers gespeichert, allerdings in verkehrter Reihenfolge. Daher müssen die Bytes zuerst vertauscht werden. Wie aus dem Datenblatt des MC3021 entnommen werden kann, erhält man die 10 Bit des Messwerts nach einem Rechtsschieben um zwei Bit.

Diese "Bitschieberei" ist zwar etwas unangenehm und echte Low-Level-Programmierung, aber in der Sensorik nicht zu vermeiden. Nehmen Sie es sportlich. Damit Sie die Sache ein für alle Mal erledigt haben, schreiben Sie eine Funktion readdata(), die Sie später immer wieder verwenden können, ohne das "Innere" zu beachten. Dies ist ja gerade der Sinn der prozeduralen Programmierung.

Programm:[►]

# RaspEasy7a.py
# Read ADC with a function call

import smbus
import time

def readData(port = 0):
    if port == 0:
        adc_address = 0x48
    elif port == 1:    
        adc_address = 0x4D
    rd = bus.read_word_data(adc_address, 0)
    data = ((rd & 0xFF) << 8) | ((rd & 0xFF00) >> 8)
    data = data >> 2
    return data

print "starting..."
bus = smbus.SMBus(1) 
while True:
    v = readData()
    print "data:", v
    time.sleep(1)
Programmcode markieren (Ctrl+C kopieren, Ctrl+V einfügen)

Bemerkungen:
Unter Verwendung der Funktion readData() wird das Programm extrem einfach. Sie können die Sensorwerte auch auf einem angeschlossenen Display anzeigen.

Programm:[►]

# RaspEasy7b.py
# Read ADC and show on Oled or 7-segment display

import smbus
import time
from OLED1306 import OLED1306
#from pytell import PyTell

def readData(port = 0):
    if port == 0:
        adc_address = 0x48
    elif port == 1:    
        adc_address = 0x4D
    rd = bus.read_word_data(adc_address, 0)
    data = ((rd & 0xFF) << 8) | ((rd & 0xFF00) >> 8)
    data = data >> 2
    return data

print "starting..."
oled = OLED1306()
oled.setFontSize(50)
#pyTell = PyTell()

bus = smbus.SMBus(1) 
while True:
    v = readData()
    oled.setText(str(v))
#    pyTell.showText("%4d" %v)
    time.sleep(1)
Programmcode markieren (Ctrl+C kopieren, Ctrl+V einfügen)

Bemerkungen:
Verwenden Sie die auskommentierten Zeilen, wenn Sie ein PyTell 7-Segment-Display angeschlossen haben.

Da Sie nun wissen, wie man einen analogen Wert einliest, können Sie das RaspEasy Modul verwenden, um Sensorwerte irgendeines analogen Sensors zu verarbeiten.

 

 

Experiment 8: Verwendung eines Temperatursensors

 

Die Temperaturmessung ist in vielen Situationen sehr wichtig. Daher gibt es viele verschiedene Temperatursensoren. In dieser Übung verwenden wir den LM35, einen 3-Pin Gerät und einer Ausgangspannung, die (nahezu) linear zur Temperatur ist. Der Sensor benötigt keine Kalibrierung. Mehr Informationen finden Sie im Datenblatt.

Ziel:
Messen Sie periodisch die Raumtemperatur und zeigen Sie diese an.

Schaltschema:
Man braucht keine zusätzlichen Komponenten. Schliessen Sie einfach die 3 Anschlussleitungen wie unten abgebildet an einem der ADC-Buchsen an.

raspeasy10
raspeasy5

Das Programm zeigt die aktuelle Temperatur in Grad Celsius an. Betrachten Sie die folgende Umwandlung: Da der Sensor eine Spannung von a = 0.01 V pro Grad Celsius abgibt, gilt für die Ausgangsspannung u = 0.01 * T . Der 10-bit ADC, der mit 3.3V versorgt ist, gibt bei einer Eingangsspannung von 3.3V den digitalen Wert 1023 ab. Liegt also die Spannung u am ADC, so ist sein digitaler Ausgabewert v = u / 3.3 * 1023. Die Beziehung zwischen der Temperatur und dem digitalen Wert lautet daher v = 0.01 / 3.3 * 1023 * T = 3.1 * T.

Programm:[►]

# RaspEasy7c.py
# LM35 temperature sensor

import smbus
import time
#from OLED1306 import OLED1306

def readData(port = 0):
    if port == 0:
        adc_address = 0x48
    elif port == 1:    
        adc_address = 0x4D
    rd = bus.read_word_data(adc_address, 0)
    data = ((rd & 0xFF) << 8) | ((rd & 0xFF00) >> 8)
    data = data >> 2
    return data

print "starting..."
#oled = OLED1306()
#oled.setFontSize(50)

bus = smbus.SMBus(1) 
while True:
    v = readData()
    T = v / 3.1
    print "T = %4.1f centigrades" %T
#    oled.setText(str(int(T + 0.5))) # rounded to int
    time.sleep(1)
Programmcode markieren (Ctrl+C kopieren, Ctrl+V einfügen)

 

 

Experiment 9: Verwendung eines Lichtsensors (LDR)

 

Ziel:
Messen Sie periodisch die Helligkeit und zeigen Sie diese an.

Schaltschema:
Ein LDR (Light Dependent Resistor) kann sehr einfach angeschlossen werden. Löten Sie den LDR mit einem 1 kOhm Widerstand auf eine einreihige 3-Pin Steckerleiste und stecken Sie diese in den ADC-Port A oder B.

rspeasy9

Sie müssen nur ein Paar Zeilen im Programm RaspEasy7c.py ändern.

Programm:[►]

# RaspEasy7d.py
# LDR sensor

import smbus
import time
#from OLED1306 import OLED1306

def readData(port = 0):
    if port == 0:
        adc_address = 0x48
    elif port == 1:    
        adc_address = 0x4D
    rd = bus.read_word_data(adc_address, 0)
    data = ((rd & 0xFF) << 8) | ((rd & 0xFF00) >> 8)
    data = data >> 2
    return data

print "starting..."
#oled = OLED1306()
#oled.setFontSize(50)

bus = smbus.SMBus(1) 
while True:
    v = readData()
    print "v =", v
#    oled.setText(str(v))
#    time.sleep(0.1)
Programmcode markieren (Ctrl+C kopieren, Ctrl+V einfügen)