Funktionen
Oft kommt es vor, dass man auf unterschiedliche Eingaben mit der gleichen Ausgabe reagieren möchte.
Dabei helfen Funktionen
-Blöcke (Methoden) in MakeCode, große Programme in kleine, leicht verständliche Teile zu zerlegen. Man kann einmal geschriebenen Code mehrfach verwenden, was Zeit spart und Fehler reduziert. Durch klare Namen für Methoden weiß jeder sofort, was sie tun, ohne den ganzen Code lesen zu müssen. Komplizierte Abläufe werden einfacher, weil man sich nur auf die Eingaben und Ergebnisse konzentrieren muss.
ohne "Funktionen"-Block
Im folgenden Beispiel reagieren wir sowohl auf die Erkennung eines Hindernisses durch den linken Hindernis-Sensor, als auch durch den rechten Hindernis-Sensor, mit sich wiederholendem, sekündlichen Ein- und Ausschalten der Scheinwerfer.
JoyCar.initJoyCar(RevisionMainboard.OnepThree)
basic.forever(function () {
if (JoyCar.obstacleavoidance(SensorLRSelection.Left)) {
JoyCar.light(ToggleSwitch.On)
basic.pause(1000)
JoyCar.light(ToggleSwitch.Off)
basic.pause(1000)
JoyCar.light(ToggleSwitch.On)
basic.pause(1000)
JoyCar.light(ToggleSwitch.Off)
basic.pause(1000)
} else if (JoyCar.obstacleavoidance(SensorLRSelection.Right)) {
JoyCar.light(ToggleSwitch.On)
basic.pause(1000)
JoyCar.light(ToggleSwitch.Off)
basic.pause(1000)
JoyCar.light(ToggleSwitch.On)
basic.pause(1000)
JoyCar.light(ToggleSwitch.Off)
basic.pause(1000)
}
})
Der Beispielcode in MicroPython ist da, weil es ihn auch in MakeCode gibt. Das ist super praktisch, denn wenn du schon mit MakeCode klar kommst, kannst du viel leichter mit MicroPython loslegen. Indem wir Beispielcodes in beiden Umgebungen haben, kannst du ohne große Unterbrechung weiterlernen. So verstehst du besser, wie Programmierung funktioniert und kannst sehen, wie man dieselben Sachen in verschiedenen Programmiersprachen macht.
# Notwendige Bibliotheken importieren
from microbit import *
import neopixel
# Definiere deine Joy Car Mainboard Revision
joycar_rev = 1.3
# Objekt für die LEDs definieren
np = neopixel.NeoPixel(pin0, 8)
# Initialisierung der I2C-Schnittstelle für das Joy Car Mainboard
i2c.init(freq=400000, sda=pin20, scl=pin19)
# Werte für die Lichter definieren
# welche LEDs aktiviert werden sollen
headlights = (0, 3)
backlights = (5, 6)
indicator_left = (1, 4)
indicator_right = (2, 7)
indicator_warning = (1, 2, 4, 7)
# welche Farbe auf den LEDs angezeigt werden soll
led_white = (60, 60, 60)
led_red = (60, 0, 0)
led_off = (0, 0, 0)
led_red_br = (255, 0, 0)
led_orange = (100, 35, 0)
# Methode zum Aktivieren/Deaktivieren von Lichtern
def lights(on = True):
if on:
for x, y in zip(headlights, backlights):
# Weiß für die Scheinwerfer definieren
np[x] = led_white
# Dunkelrot für die Rücklichter definieren
np[y] = led_red
else:
for x, y in zip(headlights, backlights):
# Schwarz für die Scheinwerfer und Rücklichter definieren
np[x] = led_off
np[y] = led_off
np.show()
# alle Sensordaten abrufen
def fetchSensorData():
# Da die zfill-Funktion nicht in micro:bit Micropython enthalten ist,
# muss sie als Funktion eingefügt werden
def zfill(s, width):
return '{:0>{w}}'.format(s, w=width)
# Hexadezimale Daten lesen und in binäre Daten umwandeln
data = "{0:b}".format(ord(i2c.read(0x38, 1)))
# Füllen Sie die Daten bei Bedarf auf 8 Stellen auf.
data = zfill(data, 8)
# bol_data_dict as dictionary deklarieren
bol_data_dict = {}
# Zähler für die Schleife, die die Daten aus data in bol_data_dict einträgt
bit_count = 7
# Übertragen Sie die Daten von data nach bol_data_dict
for i in data:
if i == "0":
bol_data_dict[bit_count] = False
bit_count -= 1
else:
bol_data_dict[bit_count] = True
bit_count -= 1
# Ab Mainboard-Revision 1.3 sind die Geschwindigkeitssensoren auf separaten Pins
if joycar_rev >= 1.3:
bol_data_dict[8], bol_data_dict[9] = bol_data_dict[0], bol_data_dict[1]
bol_data_dict[0] = bool(pin14.read_digital())
bol_data_dict[1] = bool(pin15.read_digital())
# Bit 0 = GeschwindigkeitLinks, Bit 1 = GeschwindigkeitRechts, Bit 2 = LineTrackerLinks,
# bit 3 = LineTrackerMitte, bit 4 = LineTrackerRechts,
# bit 5 = HindernisLinks, bit 6 = HindernisRechts, bit 7 = freier Pin(7)
# (bit 8 = frei (pin0) bit 9 = frei (pin1)) - nur mit Revision 1.3 oder neuer
return bol_data_dict
while True:
# Sensordaten vom Mainboard lesen
sensor_data = fetchSensorData()
# Linken Hindernissensor prüfen
if not sensor_data[5]:
# Abblendlicht anschalten
lights()
# 1 Sekunde lang warten
sleep(1000)
# Abblendlicht abschalten
lights(on = False)
# 1 Sekunde lang warten
sleep(1000)
# Abblendlicht anschalten
lights()
# 1 Sekunde lang warten
sleep(1000)
# Abblendlicht abschalten
lights(on = False)
# 1 Sekunde lang warten
sleep(1000)
# Rechten Hindernissensor prüfen
elif not sensor_data[6]:
# Abblendlicht anschalten
lights()
# 1 Sekunde lang warten
sleep(1000)
# Abblendlicht abschalten
lights(on = False)
# 1 Sekunde lang warten
sleep(1000)
# Abblendlicht anschalten
lights()
# 1 Sekunde lang warten
sleep(1000)
# Abblendlicht abschalten
lights(on = False)
# 1 Sekunde lang warten
sleep(1000)
Vorteil von Funktionen
Dies kann jedoch sehr schnell unübersichtlich werden. Benötigen wir bestimmte Abläufe mehrfach, so können wir diese in sogenannte Funktionen auslagern.
Funktionen bestehen prinzipiell erst einmal aus zwei Teilen. Dem Funktionskopf und dem Funktionsrumpf. Im Kopf wird zunächst der Funktionsname definiert. Im Funktionsrumpf befinden sich dann alle Anweisungsblöcke, die mit dieser Funktion ausgeführt werden sollen.
Die Funktion kann dann im Hauptablauf des Programms aufgerufen werden. Bei jedem Aufruf werden alle Anweisungen ausgeführt, die wir zuvor dem Funktionsrumpf hinzugefügt haben.
Im folgenden Beispiel haben wir den Lichtwechsel in die Funktion light_sequence
ausgelagert. So können wir den Ablauf sowohl bei einer Erkennung durch den linken Hindernis-Sensor, als auch durch den rechten Hindernis-Sensor, wiederverwenden. Dies garantiert nicht nur, dass in beiden Fällen auf jeden Fall die gleichen Blöcke ausgeführt werden, sondern macht unseren dauerhaft
-Block auch noch viel übersichtlicher!
function light_sequence () {
JoyCar.light(ToggleSwitch.On)
basic.pause(1000)
JoyCar.light(ToggleSwitch.Off)
basic.pause(1000)
JoyCar.light(ToggleSwitch.On)
basic.pause(1000)
JoyCar.light(ToggleSwitch.Off)
basic.pause(1000)
}
JoyCar.initJoyCar(RevisionMainboard.OnepThree)
basic.forever(function () {
if (JoyCar.obstacleavoidance(SensorLRSelection.Left)) {
light_sequence()
} else if (JoyCar.obstacleavoidance(SensorLRSelection.Right)) {
light_sequence()
}
})
Der Beispielcode in MicroPython ist da, weil es ihn auch in MakeCode gibt. Das ist super praktisch, denn wenn du schon mit MakeCode klar kommst, kannst du viel leichter mit MicroPython loslegen. Indem wir Beispielcodes in beiden Umgebungen haben, kannst du ohne große Unterbrechung weiterlernen. So verstehst du besser, wie Programmierung funktioniert und kannst sehen, wie man dieselben Sachen in verschiedenen Programmiersprachen macht.
# Notwendige Bibliotheken importieren
from microbit import *
import neopixel
# Definiere deine Joy Car Mainboard Revision
joycar_rev = 1.3
# Objekt für die LEDs definieren
np = neopixel.NeoPixel(pin0, 8)
# Initialisierung der I2C-Schnittstelle für das Joy Car Mainboard
i2c.init(freq=400000, sda=pin20, scl=pin19)
# Werte für die Lichter definieren
# welche LEDs aktiviert werden sollen
headlights = (0, 3)
backlights = (5, 6)
indicator_left = (1, 4)
indicator_right = (2, 7)
indicator_warning = (1, 2, 4, 7)
# welche Farbe auf den LEDs angezeigt werden soll
led_white = (60, 60, 60)
led_red = (60, 0, 0)
led_off = (0, 0, 0)
led_red_br = (255, 0, 0)
led_orange = (100, 35, 0)
# Methode zum Aktivieren/Deaktivieren von Lichtern
def lights(on = True):
if on:
for x, y in zip(headlights, backlights):
# Weiß für die Scheinwerfer definieren
np[x] = led_white
# Dunkelrot für die Rücklichter definieren
np[y] = led_red
else:
for x, y in zip(headlights, backlights):
# Schwarz für die Scheinwerfer und Rücklichter definieren
np[x] = led_off
np[y] = led_off
np.show()
# alle Sensordaten abrufen
def fetchSensorData():
# Da die zfill-Funktion nicht in micro:bit Micropython enthalten ist,
# muss sie als Funktion eingefügt werden
def zfill(s, width):
return '{:0>{w}}'.format(s, w=width)
# Hexadezimale Daten lesen und in binäre Daten umwandeln
data = "{0:b}".format(ord(i2c.read(0x38, 1)))
# Füllen Sie die Daten bei Bedarf auf 8 Stellen auf.
data = zfill(data, 8)
# bol_data_dict as dictionary deklarieren
bol_data_dict = {}
# Zähler für die Schleife, die die Daten aus data in bol_data_dict einträgt
bit_count = 7
# Übertragen Sie die Daten von data nach bol_data_dict
for i in data:
if i == "0":
bol_data_dict[bit_count] = False
bit_count -= 1
else:
bol_data_dict[bit_count] = True
bit_count -= 1
# Ab Mainboard-Revision 1.3 sind die Geschwindigkeitssensoren auf separaten Pins
if joycar_rev >= 1.3:
bol_data_dict[8], bol_data_dict[9] = bol_data_dict[0], bol_data_dict[1]
bol_data_dict[0] = bool(pin14.read_digital())
bol_data_dict[1] = bool(pin15.read_digital())
# Bit 0 = GeschwindigkeitLinks, Bit 1 = GeschwindigkeitRechts, Bit 2 = LineTrackerLinks,
# bit 3 = LineTrackerMitte, bit 4 = LineTrackerRechts,
# bit 5 = HindernisLinks, bit 6 = HindernisRechts, bit 7 = freier Pin(7)
# (bit 8 = frei (pin0) bit 9 = frei (pin1)) - nur mit Revision 1.3 oder neuer
return bol_data_dict
# eigene Methode zum Aktivieren/Deaktivieren der Lichter definieren
def light_sequence():
# Abblendlicht anschalten
lights()
# 1 Sekunde lang warten
sleep(1000)
# Abblendlicht abschalten
lights(on = False)
# 1 Sekunde lang warten
sleep(1000)
# Abblendlicht anschalten
lights()
# 1 Sekunde lang warten
sleep(1000)
# Abblendlicht abschalten
lights(on = False)
# 1 Sekunde lang warten
sleep(1000)
while True:
# Sensordaten vom Mainboard lesen
sensor_data = fetchSensorData()
# Linken Hindernissensor prüfen
if not sensor_data[5]:
# Aufruf der definierten Methode
light_sequence()
# Rechten Hindernissensor prüfen
elif not sensor_data[6]:
# Aufruf der definierten Methode
light_sequence()
Rückgabe von Werten
Optional können Funktionen auch sogenannte Rückgabewerte liefern. Hierbei sendet die Funktion, jedes Mal, wenn sie aufgerufen wird, eine Antwort zurück. Dieser Rückgabewert, also die Antwort, kann innerhalb der Funktion bestimmt werden. So können hier also beispielsweise Berechnungen durchgeführt werden und das Ergebnis zurück an die Hauptfunktion geliefert werden.
Im nächsten Beispiel erstellen wir die Funktion sonar_sensor
. Diese prüft, sobald diese aufgerufen wird, den Ultraschallsensor und liefert, abhängig vom Abstandswert, den der Sensor liefert, entweder eine 0, eine 1, oder eine 2 zurück an die Hauptfunktion. Abhängig von dem gelieferten Wert schalten wir die Scheinwerfer und den Warnblinker des Joy-Cars in unterschiedliche Zustände.
Ist die gemessene Distanz zum Hindernis 50 cm oder größer, wird eine 0 zurückgegeben, also das Licht eingeschaltet und die Warnblinker ausgeschaltet. Ist die gemessene Distanz kleiner als 50 cm wird eine 1 zurückgeben, also werden die Warnblinker eingeschaltet und das Licht ausgeschaltet. Sollte ein Fehler auftreten und der Rückgabewert des Sensors nicht in den definierten Bereichen liegen, wird eine 2 zurückgegeben. In diesem Fall gehen sowohl Licht als auch die Warnblinker an.
function sonar_sensor () {
if (JoyCar.sonar() >= 50) {
return 0
} else if (JoyCar.sonar() < 50) {
return 1
} else {
return 2
}
}
JoyCar.initJoyCar(RevisionMainboard.OnepThree)
basic.forever(function () {
if (sonar_sensor() == 1) {
JoyCar.light(ToggleSwitch.Off)
JoyCar.hazardlights(ToggleSwitch.On)
} else if (sonar_sensor() == 0) {
JoyCar.light(ToggleSwitch.On)
JoyCar.hazardlights(ToggleSwitch.Off)
}
})
Der Beispielcode in MicroPython ist da, weil es ihn auch in MakeCode gibt. Das ist super praktisch, denn wenn du schon mit MakeCode klar kommst, kannst du viel leichter mit MicroPython loslegen. Indem wir Beispielcodes in beiden Umgebungen haben, kannst du ohne große Unterbrechung weiterlernen. So verstehst du besser, wie Programmierung funktioniert und kannst sehen, wie man dieselben Sachen in verschiedenen Programmiersprachen macht.
# Notwendige Bibliotheken importieren
from microbit import *
import neopixel
import gc
from machine import time_pulse_us
# Definiere deine Joy Car Mainboard Revision
joycar_rev = 1.3
# Objekt für die LEDs definieren
np = neopixel.NeoPixel(pin0, 8)
# Initialisierung der I2C-Schnittstelle für das Joy Car Mainboard
i2c.init(freq=400000, sda=pin20, scl=pin19)
# Pins für Ultraschallsensor definieren
trigger = pin8
echo = pin12
# Initialisierung der Pins für den Ultraschallsensor
trigger.write_digital(0)
echo.read_digital()
# Werte für die Lichter definieren
# welche LEDs aktiviert werden sollen
headlights = (0, 3)
backlights = (5, 6)
indicator_left = (1, 4)
indicator_right = (2, 7)
indicator_warning = (1, 2, 4, 7)
# welche Farbe auf den LEDs angezeigt werden soll
led_white = (60, 60, 60)
led_red = (60, 0, 0)
led_off = (0, 0, 0)
led_red_br = (255, 0, 0)
led_orange = (100, 35, 0)
# Variablen für die Lichter
last_ind_act = 0
last_state_hazard = False
last_state_lights = False
# Methode zur Berechnung der Entfernung vom Ultraschallsensor
def get_distance():
# Garbage Collector aktivieren
gc.collect()
# kurzen Impuls auf den Trigger-Pin setzen
trigger.write_digital(1)
trigger.write_digital(0)
# Messung der Zeit, bis der Echo-Pin hoch wird
duration = time_pulse_us(echo, 1)
# Entfernung berechnen
distance = ((duration / 1000000) * 34300) / 2
# Rückgabe der Entfernung, gerundet auf 2 Dezimalstellen
return round(distance, 2)
# Methode zum Aktivieren/Deaktivieren von Lichtern
def lights(on = True):
if on:
for x, y in zip(headlights, backlights):
# Weiß für die Scheinwerfer definieren
np[x] = led_white
# Dunkelrot für die Rücklichter definieren
np[y] = led_red
else:
for x, y in zip(headlights, backlights):
# Schwarz für die Scheinwerfer und Rücklichter definieren
np[x] = led_off
np[y] = led_off
np.show()
# Methode zum Aktivieren/Deaktivieren der Blinker.
# Variable für die Methode, um zu vergleichen, wann die Lichter zuletzt aktiv waren.
last_ind_act = running_time()
def lightsIndicator(direction, on = True):
# um die globale Variable ändern zu können
global last_ind_act
# Garbage Collector aktivieren
gc.collect()
# wenn Sie die Blinker ausschalten wollen
if on is False:
# LEDs deaktivieren
for x in direction:
np[x] = led_off
np.show()
# Schließen der Methode
return
# Aktivierung/Deaktivierung der Blinker nach 400 ms
if running_time() - last_ind_act >= 400:
# LEDs aktivieren, wenn die LEDs aus sind
if np[direction[0]] == led_off:
for x in direction:
np[x] = led_orange
# Deaktivieren Sie die LEDs, wenn sie eingeschaltet sind
else:
for x in direction:
np[x] = led_off
np.show()
# Globale Variable auf aktuelle Laufzeit setzen
last_ind_act = running_time()
# Methode zur Überprüfung der Entfernung
def sonar_sensor():
# 0 zurückgeben, wenn der Abstand größer als 50cm ist, sonst 1 zurückgeben
distance = get_distance()
if distance >= 50:
return 0
else:
return 1
while True:
# Informationen von der Methode sonar_sensor abrufen
sonar = sonar_sensor()
# wenn Abstand < 50 cm
if sonar == 1:
# Abblendlicht ausschalten (wenn es noch an ist)
lights(on = False)
# Warnblinker einschalten
lightsIndicator(indicator_warning)
else:
# Deaktivieren Sie die Warnblinkanlage (wenn sie noch eingeschaltet ist)
if last_state_hazard is True:
# Warnblinkanlage deaktivieren
lightsIndicator(indicator_warning, on = False)
# Abblendlicht einschalten (wenn es noch ausgeschaltet ist)
if last_state_lights is False:
# Abblendlicht einschalten
lights()