Über unsMediaKontaktImpressum
René Krooß 19. April 2022

Der Raspberry Pi Pico - Einführung mit Praxisbeispielen

Viele Leser werden wahrscheinlich bereits den Original Raspberry Pi kennen und unter Umständen schon einmal mit diesem gearbeitet haben. Vielleicht fragen auch Sie sich nun, warum es schon wieder eine neue Pi-Version gibt und warum gerade diese neue Version für nicht einmal 10 Euro zu haben ist. Vielleicht haben Sie dann auch schon einmal im Internet nach dem Raspberry Pi Pico gesucht und sich gewundert, wie denn ein vollständiger Pi auf eine so kleine Platine passen kann, wo man dort eine SD-Karte einstecken oder einen HDMI-Monitor anschließen soll. Die Antwort ist, dass es eine solche Möglichkeit beim Raspberry Pi Pico nicht gibt und auch nicht geben soll. Denn im Unterschied zu den "großen Brüdern" ist der Pico ein reiner Mikrocontroller. Dies bedeutet unter anderem, dass es für den Pico kein Linux-Betriebssystem gibt und dass Sie natürlich auch keinen Desktop auf den Pico aufspielen können – der Pico kann von sich aus keine TV-Signale ausgeben.

Wenn dies aber so ist, warum hat die Raspberry Pi Foundation dann eine so stark beschnittene Version ihres beliebten Pi herausgegeben? Die Antwort, ist, dass der Standard-Raspberry-Pi oft einfach zu groß ist. Ferner braucht ein moderner Raspberry Pi der Version 4 auch sehr viel Strom (bis zu 4 A) und dies ist oft nicht erwünscht. Ein Standard-Beispiel aus meinem Bastler-Alltag macht dies deutlich. Ich wollte meinen alten C64 wieder zum Leben erwecken, der noch einen 6510-Prozessor enthält. Leider sind inzwischen weder der 6510, noch der Speicher in einfacher Weise erhältlich. Also emulierte ich beides mit einem Raspberry Pi Pico und durch den geringen Stromverbrauch dieser Platine konnte ich auch alle zusätzlichen Komponenten (VIC, SID, CIA) problemlos mit dem alten Netzteil betreiben.

Natürlich musste ich die Spannungspegel des Raspberry Pi Pico mit zusätzlichen elektronischen Schaltungen an das Niveau des C64 angleichen, aber dies ist kein so großes Problem: Für den Angleich von Spannungspegeln gibt es fertige Bausätze. Der Einsatzbereich des Raspberry Pi Pico ist hiermit auch schon sehr gut umrissen: Er kann überall dort verwendet werden, wo man einen relativ leistungsfähigen, trotzdem aber günstigen Mikrocontroller benötigt, der nicht viel Strom und Platz verbraucht. Da die Platine des Raspberry Pi Pico auch keine nach außen geführten Pins besitzt (nur Lötpunkte), kann man die Platine auch durchaus fest in ein Gerät einbauen.

    Die technischen Daten des Raspberry Pi Pico können sich durchaus sehen lassen:

    • Ein extra von der Raspberry Pi Foundation angepasster 32-Bit-ARM-Cortex-Mikroprozessor der M0-Reihe mit 2 Kernen und 166 MHz Taktfrequenz (genaue Bezeichnung: Dual ARM Cortex RP2040),
    • 264 kB RAM, hiervon 256 kB frei nutzbar (allerdings müssen sich Programme und Daten den Speicher teilen),
    • ein bis zu 16 MB Flash-Speicher für externe Dateien kann zusätzlich angeschlossen werden,
    • die bereits vom Raspberry Pi 1 bekannten GPIO-Pins, von denen auch beim Pico 26 frei benutzbar sind, sind auch beim Pico vorhanden,
    • 2 serielle Schnittstellen (UART), 2 SPI-Schnittstellen, 2 I2C-Schnittstellen und 1 USB 1.1-Schnittstelle für Maus oder Tastatur (leider kein Hub nutzbar).

    Mit welchen Apps kann der Pico programmiert werden?

    Vielleicht können Sie bereits etwas C oder Python, weil Sie diese Programmiersprachen schon für eine der bekannten Versionen des Raspberry Pi verwendet haben. Vermutlich haben Sie dann den GCC-Compiler für Linux oder den vorinstallierten Python-Interpreter benutzt, um z. B. Code-Beispiele aus einem Computermagazin auszuführen. Den Raspberry Pi Pico können Sie nun genau so verwenden, nämlich als vorkonfigurierte Platine, die auch bereits einen Micro-USB-Anschluss besitzt. Über diesen USB-Port können Sie dann Python-Skripte auf den Pico übertragen.

    Ferner gibt es Entwicklungsumgebungen, mit denen Sie den Pico auch in C programmieren können. Eine der zahlreichen Möglichkeiten, die Programmiersprache C zu verwenden, werde ich auch in diesem Artikel vorstellen: Sie programmieren den Pico so, wie andere Mikrocontroller auch, und verwenden dazu einfach die Arduino-IDE. Diese Möglichkeit wählen Sie wahrscheinlich genau dann, wenn Sie sich bereits mit dem Arduino (oder auch mit dem ESP) auskennen und auch den Raspberry Pi Pico weiterhin in C programmieren wollen. Alles, was Sie in diesem Fall tun müssen, ist die aktuelle Arduino-IDE von der Webseite herunterzuladen [1]. Alle Versionen ab 1.8.13 unterstützen von Haus aus den Raspberry Pi Pico. Wenn Sie noch kein C können, nutzen Sie am besten die zweite Möglichkeit und verwenden Micro Python. Genauso wie C, funktioniert Python fast einwandfrei zusammen mit dem Pico. Dass ich an dieser Stelle das Wort "fast" verwende, hat spezielle Gründe, die mit einigen Einschränkungen des Prozessors des Pico zusammenhängen und die eigentlich nur Hardware-Experten interessieren müssen. So laufen einige Speicherzugriffsvarianten, die z. B. C normalerweise unterstützen müsste, ins Leere und lassen den Pico abstürzen.

    Die dritte Möglichkeit, auf die ich aber in diesem Artikel nicht detailliert eingehen kann, ist die Verwendung von MicroBASIC. MicroBASIC (eine Variante von Commodore BASIC R3) ist in der Tat ein BASIC-Interpreter, mit dem Sie Programme im Stil der 80-er Jahre entwickeln können: Mit Zeilennummern und GOTO-Anweisungen. MicroBASIC selbst wurde in C programmiert und kann mit der Arduino-IDE auf den Pico, aber auch auf ein ESP32-Board (z. B. das Node MCU 2.0) aufgespielt werden. Leider ist die Version für den Pico sehr beschränkt: Während Sie mit MicroBASIC für den Pico nur Programme für die serielle Konsole schreiben können, bietet die Version für den ESP32 sogar ein analoges TV-Out-Signal mit immerhin 16 Farben über den DAC-Pin 26 an. Da das TV-Signal durch eine VIC-Emulation erzeugt wird, funktionieren sogar die Pokes, die Sie vom C64 her kennen. Die Geschwindigkeit, mit der die TV-Ausgabe auf dem ESP32 läuft, ist in der Tat beeindruckend und es sind sogar Sprites möglich.

    Auf diese Weise komme ich dann auch zu den Beschränkungen des Raspberry Pi Pico, die einfach dadurch entstehen, dass der Prozessor gerade mal einen Euro kostet:

    • Fehlende DAC-Ports, es können deshalb keine analogen Signale und auch keine Audio-Signale ausgegeben werden.
    • Kein linearer Speicherzugriff durch den Prozessor, weil der Speicher in Bänke aufgeteilt ist. Dadurch kommt es zu Verzögerungen, die den Prozessor ausbremsen, vor allem bei Schleifen und Funktionsaufrufen. Manche Dinge, wie z. B. die Benutzung von typenlosen Zeigern (void*) sind schlicht nicht möglich und führen zum Absturz des Pico (dieser friert dann ein und lässt sich nur mit Tricks neu starten)
    • Die GPIO-Anschlüsse vertragen (wie auch schon die "großen Brüder" Raspberry Pi 1-4) kaum Strom, die Lötkontakte können gerade mal mit 5-10 mA beschickt werden. Eine Gesamtstromaufnahme von über 250 mA (für sämtliche Kontaktstellen) führt schon zu einer Beschädigung der Platine. Deshalb müssen für die Kommunikation mit anderen Bauteilen und Geräten stets zusätzliche Bauteile wie z. B. Level Shifter verwendet werden.
    • Der Spannungsregler ist sehr klein dimensioniert und liegt direkt neben dem Bootsel-Knopf. Eine stabile externe Spannungsversorgung ist hier sehr wichtig.

    Wenn man sich mit den Einschränkungen einmal arrangiert hat, ist der Raspberry Pi Pico jedoch ein leistungsfähiger Mikrocontroller, der z. B. die Standard-Arduinos weit hinter sich lässt. Die Standard-Arduinos bieten übrigens ebenfalls (bis auf den sehr teuren Arduino Due) DAC-Pins an, und können ebenfalls keine TV-Signale oder hochwertigen Töne erzeugen. Sie können also mit dem Raspberry Pi Pico nicht viel falsch machen, wenn Sie vorhaben, in die Mikrocontroller-Programmierung einzusteigen. Der Pico ist auch gut geeignet, um z. B. Schülern in einer Elektronik-AG diesen Einstieg zu ermöglichen. Im weiteren Verlauf möchte ich nun die verschiedenen Varianten, den Pico zu programmieren, etwas näher erläutern.

    Programmierung des Pico mit der Arduino-IDE

    Die Arduino-IDE ist, wie der Name schon andeutet, eigentlich dafür gedacht, C-Programme auf Arduino-Mikrocontrollern auszuführen. C-Programme werden stets kompiliert, das heißt in Maschinencode übersetzt. Diese Tatsache macht die Arduino-Programme so schnell und leistungsfähig. Da es auch von dem Arduino mit der Zeit eine unüberschaubare Anzahl von Varianten gab, hatte die Entwicklergemeinde irgendwann mit großen Problemen zu kämpfen und einige Varianten (wie z. B. der Yun) liefen auch nie richtig stabil. Die Lösung für diese Probleme war, offene Standards zu entwickeln und möglichst viele Mikrocontroller durch die IDE zu unterstützen – auch Mikrocontroller fremder Hersteller. Die Rechnung ging auf und mittlerweile werden bis zu 100 verschiedene Mikrocontroller unterstützt, darunter ist inzwischen auch der ESP32-Mikrocontroller für IoT-Anwendungen und der neue Raspberry Pi Pico. Auch bei der Installation der IDE hat sich vieles vereinfacht. Um die IDE aufzuspielen, wählen Sie auf der Arduino-Webseite Software aus (s. Abb. 1).

    Im Downloadbereich sollte nun möglichst die Software-Version 1.8.19 ausgewählt werden, denn ältere Versionen können Probleme mit dem neuen Pico haben. Diese Probleme können sich z. B. darin äußern, dass mehrere Versuche benötigt werden, um ein Programm aufzuspielen oder einige mathematische Operationen, wie die Exponentialfunktion oder der Logarithmus zur Basis 2, fehlen.

    Da die IDE in Java programmiert wurde, unterstützt die Version für Windows ab 7 auch Windows 8, 10 und 11. Für Linux gibt es die IDE zwar inzwischen auch über Standard-Paketmanager wie APT oder RPM, auf anderen Plattformen als dem Raspberry Pi ist die IDE jedoch nur selten von Haus aus aktuell. In diesem Fall müssen Sie sich das entsprechende Archiv in Form einer ZIP-Datei per Hand herunterladen und auch per Hand installieren. Wie dies geht, erfahren Sie in den zahlreichen How-tos, die z. B. in Form einer README-Datei in dem entsprechenden Archiv enthalten ist. Lesen Sie auf jeden Fall die How-tos durch, denn die Installation kann sich von Fall zu Fall unterscheiden. Unter Windows ist die Sache deutlich einfacher, denn dort gibt es nur eine EXE-Datei, die Sie einfach ausführen müssen, um die Installation zu starten.

    Wenn Sie die entsprechende Version ausgewählt haben, erscheint unter Umständen noch ein Spendenaufruf der Arduino-Community, mit der Bitte, einen bestimmten Betrag zu spenden. Diese Spende ist freiwillig, Sie können die Arduino-IDE also auch herunterladen, ohne etwas zu spenden. Klicken Sie hierzu auf den Button "just download". Wenn Sie etwas spenden wollen (was sehr viele Benutzer in der Tat tun), dann klicken Sie auf "contribute and download". Die Installation selbst ist nun sehr einfach. Zuerst müssen Sie die GPL-Lizenz akzeptieren, die oft für freie Open-Source-Software verwendet wird. Anschließend wird die Installation gestartet, die im Allgemeinen einfach durchläuft, und sich am Ende mit "installation completed" meldet. Es wird auch immer ein Desktop-Symbol für die Arduino-IDE angelegt. Wenn dies nicht geschieht, dann haben Sie ein ernstes Problem mit Ihrem Gerät oder Ihrer Systemkonfiguration, das aber dieser Artikel nicht lösen kann. Ich setze nun voraus, dass dies nicht der Fall ist und dass Sie die Software nun durch einen Klick auf das entsprechende Symbol starten können.

    Dieser Artikel kann Ihnen natürlich nur einen ersten Einblick bieten, und natürlich erst recht kein umfassendes Fachbuch für den Raspberry Pi Pico ersetzen. Deshalb kann ich auch nur schrittweise beschreiben, wie Sie den Raspberry Pi Pico dazu veranlassen können, den Text "Hallo Welt" einmal in der Sekunde in der Konsole auszugeben, sowie die interne LED blinken zu lassen. Schließen Sie nun Ihren Pico an einen freien USB-Port an und warten einige Zeit, bis Windows die entsprechenden Treiber installiert hat (unter Umständen müssen Sie die Installation auch separat bestätigen).

    Wenn die Installation fertig ist, öffnet sich ein USB-Laufwerk. In diesem Laufwerk befinden sich zwei Dateien: INFO_UF2.txt und INDEX.htm. Diese Dateien werden bei der Arduino-IDE nicht benötigt, Sie können also das Fenster für das USB-Laufwerk direkt schließen. Starten Sie nun die Arduino-IDE und installieren zunächst einmal den Board-Treiber für den Pico. Dies ist nicht so schwer, denn im Endeffekt müssen Sie nur den richtigen Menüeintrag auswählen: Wählen Sie im Menü "Werkzeuge" den Eintrag "Board" aus und anschließend das Untermenü "Boardverwalter".

    Es öffnet sich nun ein weiteres Fenster mit einer Liste aller von der Arduino-IDE unterstützten Boards. Um den Treiber für den Raspberry Pi Pico zu suchen, müssen Sie unter Umständen etwas scrollen, denn meistens befindet sich der Treiber am unteren Ende der Liste. Ferner muss der richtige Treiber ausgewählt werden, denn Sie dürfen auf keinen Fall die Version installieren, die mit "deprecated" (veraltet) gekennzeichnet ist. Die richtige Version trägt hier die Bezeichnung "Arduino Mbed OS RP2040 Boards" und enthält unter anderem auch den Raspberry Pi Pico. Für die Installation der Treiber genügt ein Klick auf "Installieren".

    Wenn der korrekte Board-Treiber installiert wurde, kann nun ein neues C-Programm für den Pico geschrieben werden. Beim Start der Arduino-IDE wird schon automatisch ein Programmgerüst angelegt, das die Funktionen setup() und loop() enthält. Die Funktion setup() wird genau einmal aufgerufen, die Funktion loop() immer wieder neu in einer Endlosschleife. Dies ist deshalb so, weil Mikrocontroller oft Bestandteil von anderen elektronischen Geräten sind, die z. B. immer wieder den Status der Bedientasten abfragen müssen. Das Setup wird aber immer nur beim Start des Gerätes aufgerufen. Im nächsten einfachen Beispiel wird setup() ebenfalls genau einmal aufgerufen, um die serielle Schnittstelle mit 9600 Baud zu initialisieren, loop() dagegen jede Sekunde einmal. Starten Sie nun die Arduino-IDE neu und ändern das vorgefertigte Programm auf die folgende Weise ab:

    void setup()
    {
    	Serial.begin(9600);
    }
    void loop()
    {
    	Serial.println(“Hallo, ich bin Ihr neuer Raspberry Pi Pico.“);
    	delay(1000);
    }

    Die Funktion setup() initialisiert die serielle Schnittstelle mit 9600 Baud (Standardrate), und loop() gibt den Text "Hallo, ich bin Ihr neuer Raspberry Pi Pico" mit Zeilenumbruch aus. An dem Punkt hinter "Serial" können Sie erkennen, dass die Standardbibliothek objektorientiert programmiert wurde, um viele Dinge zu erleichtern (im Endeffekt programmieren Sie also hier in C++). So ist die serielle Schnittstelle dann auch ein Objekt, das z. B. die Methoden begin() und println() anbietet, um die Schnittstelle zu initialisieren oder einen Text in der Konsole auszugeben.

    Nun wollen Sie sicherlich den Konsolentext auch lesen können. Sie müssen nun zunächst Ihr Programm, das in der Arduino-Fachsprache auch Sketch genannt wird, kompilieren und auf den Pico übertragen. Hierzu dient wieder das "Werkzeug"-Menü. Zunächst müssen Sie hier wieder den Eintrag "Board" auswählen, und anschließend den Unterpunkt "Arduino Mbed OS RP2040 Boards", das dann den Eintrag "Raspberry Pi Pico" enthält. Anschließend müssen Sie dann noch unter "Port" den korrekten Port auswählen, bei mir ist dies beispielsweise "COM5".

    Nun kann das Programm aufgespielt werden. Wenn der Punkt "Port" allerdings ausgegraut dargestellt wird, dann ist der Pico nicht richtig installiert worden, oder aber Sie haben noch nie einen Sketch aufgespielt. Nun stoßen Sie auf die erste echte Schwierigkeit beim Pico, nämlich die Ersteinrichtung für die Arduino-IDE. Wenn Sie nämlich den Pico aus der Packung nehmen, dann ist dort noch keine Firmware aufgespielt worden, die dafür sorgt, dass der Mikrocontroller richtig starten kann. Normalerweise übertragen Sie in diesem Fall dann die Firmware für den Python-Interpreter auf das Laufwerk, das sich direkt nach dem ersten Anschluss des Pico an den PC öffnet. Nun wollen Sie aber ein C-Programm kompilieren und dieses auf den Pico überspielen, anstatt der Firmware für den Python-Interpreter. Sie müssen nun wie folgt vorgehen:

    • Entfernen Sie den Pico und drücken den Bootsel-Knopf.
    • Halten Sie Bootsel gedrückt und schließen den Pico neu an den gleichen Port an.
    • Wählen Sie bei gehaltenem Bootsel-Kopf den Punkt „hochladen“ im Sketch-Menü aus.
    • Der Sketch wird nun kompiliert. Halten Sie Bootsel gedrückt, bis der Vorgang beendet ist (dies kann etwas dauern).

    Wenn Sie die Initialisierung abgeschlossen haben, und Ihr Programm erfolgreich kompiliert wurde, müsste sich das USB-Laufwerk für Ihren Pico öffnen und kurz darauf wieder schließen. Nun können Sie den Bootsel-Knopf loslassen. Ihr Pico ist nun für die Arduino-IDE eingerichtet, und Sie müssen nun zum erneuten Hochladen von Sketchen den Bootsel-Knopf nicht mehr gedrückt halten. Öffnen Sie nun den seriellen Monitor, indem Sie aus dem Menü "Werkzeuge" den Punkt "serieller Monitor" auswählen. Der serielle Monitor ist quasi die Konsole Ihres Pico, in der alle Meldungen erscheinen, die Sie mit Serial.println() ausgeben. Wenn alles richtig gemacht wurde, und Sie auch die korrekte Baudrate eingestellt haben, erscheint nun jede Sekunde folgender Text neu in der Konsole: Hallo, ich bin Ihr neuer Raspberry Pi Pico.

    Wenn Sie nun Ihr Projekt speichern wollen, dann wählen Sie "speichern unter" aus dem Datei-Menü aus. Je nachdem, wie Ihre IDE konfiguriert ist, öffnet sich der Dialog zum Speichern Ihres Projektes unter Umständen schon, wenn Sie versuchen, Ihr Programm zu kompilieren. Standardmäßig wird Ihr Projekt in einem Unterordner des Verzeichnisses "Arduino" im Ordner "Eigene Dateien" abgelegt, unter Linux befindet sich zu diesem Zweck ein Unterordner "Arduino" im Home-Verzeichnis des Benutzers. Es empfiehlt sich hier, für jedes neue Projekt einen separaten Unterordner anzulegen, und auch eventuelle Include-Dateien, die Sie selbst erstellt haben, dort abzulegen.
     
    Im Internet gibt es viele weitere Beispiele, wie Sie Ihren Pico mit der Arduino-IDE programmieren können, und dort taucht dann natürlich auch immer wieder das Blink-Beispiel auf. Das Blink-Beispiel ist ein beliebtes Beispiel für den Einstieg in die Mikrocontroller-Programmierung, um zu testen, ob Ihr Gerät zuverlässig arbeitet. Um dieses Beispiel auszuführen, müssen Sie allerdings eine LED so an Ihren Pico anlöten, dass die Kathode (Pluspol, kurzer Draht) mit Pin 1 und die Anode (Minuspol, langer Draht) mit Masse (GND) verbunden ist. Um den Pico nicht zu beschädigen, sollten Sie noch einen Widerstand zwischen Pin 1 und die LED löten, der mindestens 470 Ohm besitzt. Anschließend ersetzen Sie die loop()-Funktion des letzten Beispiels durch folgende Zeilen:

    void loop()
    {
    	digitalWrite(1,HIGH);
    	delay(1000);
    	digitalWrite(1,LOW);
    	delay(1000);
    }

    Auf Pin 1 wird nun abwechselnd die Spannung im Sekundentakt auf hohen Pegel (3,3V) und niedrigen Pegel (0V) gesetzt, was dazu führt, dass Ihre LED blinkt. Da Sie einen Vorwiderstand angeschlossen haben, wird Ihre LED und Pin 1 nicht beschädigt, denn es fallen hier nur etwa 1,2V an der LED ab.

    Programmieren des Pico in MicroPython

    Wenn Sie sich nicht so gut mit C auskennen, und auch nicht vorhaben, dies nun zu lernen, können Sie den Pico auch mit Python programmieren. Python wurde ursprünglich für Schüler und Studenten entwickelt, um diesen einen leichten Einstieg in die Programmierung zu ermöglichen. Der Schwierigkeitsgrad ist ungefähr mit dem in den 80-er Jahren populären BASIC vergleichbar, nur ist Python eben moderner. Anstatt sich mit Zeilennummern und GOTO-Anweisungen herumschlagen zu müssen, kann man mit Python wirklich strukturiert programmieren und die Programme auch mit komfortablen Editoren erstellen. Bevor Sie aber einen solchen Editor verwenden können, müssen Sie erst einmal MicroPython auf Ihren Pico aufspielen.

    Scrollen sie dazu auf der Webseite [2] mit der Maus nach unten und folgen Sie der Installationsanleitung. Die Installation von MicroPython ist wirklich ganz einfach, denn hierzu muss man nur die entsprechende UF2-Datei herunterladen und auf den Pico aufspielen. Dazu entfernen Sie den Pico vom USB-Hub, drücken Bootsel und stecken den Pico bei gehaltenem Bootsel-Knopf wieder in den USB-Hub. Wenn der Pico erkannt wurde, lassen Sie den Bootsel-Knopf los. Nun öffnet sich das entsprechende Laufwerk für den Pico. Ziehen Sie nun die heruntergeladene UF2-Datei mit der Maus in den Laufwerksordner des Pico und warten, bis die Installation von MicroPython beendet ist.

    Sie können auch, bevor Sie MircoPython installieren, mit der Maus doppelt auf die HTML-Datei INDEX.htm klicken, die anschließend in Ihrem Browser angezeigt wird. Diese enthält einige zusätzliche Informationen und Links, die Ihren Pico betreffen. Da sich Links aber mit der Zeit ändern können, und auch Homepages ständig aktualisiert werden, sollten Sie trotzdem immer wieder von Zeit zu Zeit im Internet nach neuen Versionen von MicroPhython suchen.

    Nun nützt einem das vorangegangene Installationsbeispiel allein erst einmal herzlich wenig, denn im Endeffekt können auch bei erfolgreich installiertem Python nur spezielle Kommandos über die serielle Schnittstelle an den Pico gesendet werden. Auch, wenn diese Kommandos Python-Befehle enthalten können (wie z. B. print oder eine Wertzuweisung an eine Variable), wünschen sich viele Benutzer doch mehr Komfort, als eine schlichte Kommandozeile. Diesen Komfort bietet z. B. die Thonny-Entwicklungsumgebung, die ich an dieser Stelle deshalb ausgesucht habe, weil sie auch oft von Schulen benutzt wird. Die Installation ist ganz einfach: Gehen Sie auf die Webseite [3] und laden sich die IDE für Ihr Betriebssystem herunter. Es wird Windows, Mac OS, und auch Linux unterstützt (dort sollten Sie aber auf jeden Fall das Installations-How-to durchlesen).

    Starten Sie nun die Thonny-IDE (in dem nächsten Beispiel verwende ich die Version für Windows 10) durch einen Doppelklick auf das entsprechende Desktop-Symbol. Dieses Symbol wird bei der Installation automatisch angelegt, wenn dieses Symbol also nicht erscheint (dies gilt übrigens auch für Linux), dann ist etwas schief gelaufen. Direkt nach der Erstinstallation muss unter Umständen noch die MIT-Lizenz bestätigt werden, unter der Thonny entwickelt wurde. Die MIT-Lizenz gestattet es Ihnen, die Thonny-IDE frei zu kopieren, herunterzuladen und weiterzugeben. Im Gegensatz zur GPL-Lizenz muss jedoch der Quellcode nicht offengelegt werden, allerdings darf Thonny nicht für kommerzielle Zwecke verwendet werden.

    Schauen wir uns nun das nächste Beispiel an, das das C-Programm, das hier zuerst vorgestellt wurde, in Phython überträgt:

    from machine import Timer
    timer=Timer()
    def TextOut(timer):
    print(“Hallo, ich bin Ihr neuer Raspberry Pi Pico.“)
    timer.init(freq=1.0, mode=Timer.PERIODIC, callback=TextOut)

    Wie man an dieser Stelle sieht, verwaltet MicroPython den Microcontroller völlig anders, als die Arduino-IDE. Dies kann vor allem bei einem Umstieg von der Arduino-IDE auf MicroPython verwirrend sein. So gibt es z. B. keine Setup-Funktion und auch keine Routine irgendeiner Art, die so etwas wie ein Hauptprogramm darstellt. Stattdessen wird unter MicroPython der Mikrocontroller als Empfangsgerät betrachtet, der dann und nur dann eine Aktion ausführt, wenn er ein Signal empfängt. Sonst verharrt der Mikrocontroller in einer Art Wartezustand und tut eben nichts (außer, Sie geben über die serielle Konsole ein Python-Kommando ein).

    Aber wie kann dann der Mikrocontroller überhaupt etwas von sich aus in der Konsole ausgeben? Die Antwort ist, dass hier ebenfalls ein Signal gebraucht wird, das die Textausgabe auslöst – und dieses Signal ist die interne Uhr. Um diese Uhr benutzen zu können, muss nun zunächst in der ersten Zeile die Bibliothek "Timer" importiert werden, die eine Unterklasse von "machine" darstellt. Deshalb ist hier der etwas umständliche Ausdruck "from machine import Timer" nötig. Nun ist aber die Uhr noch nicht ansprechbar, da in Python für jedes Gerät immer auch ein Objekt nötig ist, das das Gerät anspricht. Dieses Objekt wird in diesem Fall in der Variablen timer abgelegt, und mit dem Kommando timer=Timer() wird dann die entsprechende Referenz auf die interne Uhr hergestellt.

    Nun kann das Objekt timer benutzt werden, um z. B. den Wert der Systemuhr auszulesen. Dies führt aber in diesem Fall nicht zum Ziel, denn es gibt ja keine Möglichkeit, z. B. eine Wartefunktion immer wieder von sich aus aufzurufen. Deshalb muss mit dem def-Kommando die separate Funktion TextOut definiert werden, die als Parameter das Objekt timer übergeben bekommt, das ebenfalls eine Referenz auf die interne Uhr enthält. Die Funktion TextOut() gibt dann den gewünschten Text in der Konsole aus. Achten Sie an dieser Stelle unbedingt darauf, dass Sie die Zeile mit der print-Anweisung mit der Tabulatortaste einrücken, denn Python strukturiert die einzelnen Programmblöcke nicht wie C durch Klammern. Stattdessen wird Code, der sich z. B. innerhalb einer Funktion befindet, mit der Tabulator-Taste eingerückt.

    Die letzte Zeile, die sich wieder außerhalb der Funktion TextOut() befindet, initialisiert dann den Timer so, dass dieser alle 1,0 Sekunden periodisch ein Signal auslöst (man spricht hier auch von einem Interrupt) und dabei auch die Funktion TextOut() aufruft.

    In diesem Fall nennt man TextOut() auch eine Callback-Funktion. Eine Callback-Funktion ist quasi eine Rückmeldung, dass gerade irgendetwas passiert ist, in diesem Fall mit der Uhr. Natürlich ist immer der Programmierer dafür verantwortlich, die Signale richtig auszuwerten und hierfür die richtigen Callback-Funktionen einzusetzen.

    Bringen wir nun das Python-Skript zum Laufen. An dieser Stelle wird vorausgesetzt, dass Sie die Thonny-IDE schon gestartet haben. Zunächst sollte das Projekt mit "Save as" aus dem Menü "File" in einem separaten Ordner gesichert werden. Wenn dies geschehen ist, muss der Python-Interpreter eventuell noch auf den Pico eingestellt werden. Dies geschieht durch Auswahl des Menüpunkts "Options" aus dem Menü "Tools". In dem Fenster, das sich nun öffnet, kann durch ein Öffnen des Reiters "Interpreter" der Raspberry Pi Pico aus einer Drop-Down-Liste ausgewählt werden.

    Normalerweise wird der korrekte COM-Port automatisch erkannt. Wenn dies nicht der Fall ist, kann einfach per Hand der Port gewählt werden, der normalerweise auch in der Arduino-IDE erscheinen würde.

    Schreiben wir nun das vorige Beispiel so um, dass nun die LED blinkt, die an Pin 25 angeschlossen ist (normalerweise ist dies die interne LED, die fest auf dem Pico aufgelötet ist):

    from machine import Pin, Timer
    LED=Pin(25,Pin.OUT)
    timer = Timer()
    def blink(timer):
    LED.toggle()
    timer.init(freq=1.0, mode=Timer.PERIODIC, callback=blink)

    Das letzte Beispiel ist mit dem vorigen Beispiel fast identisch, nur wird hier die Funktion blink() als Callback-Funktion benutzt, und nicht die Funktion TextOut(). Damit blink() jedoch funktionieren kann, muss vorher zusätzlich zu "Timer" das Modul "Pin" importiert werden. Außerdem muss zusätzlich die Variable LED angelegt werden, die Pin 25 ansprechen kann. Auch hier ist LED wieder ein Objekt, das eine Referenz auf den 25. Pin enthält. Sie hätten also die Variable LED auch Brutzelmutzel nennen können und Ihr Programm wäre genau so gelaufen. Nur ist LED eben ein Name, der mehr aussagt, als Brutzelmutzel. Die Funktion blink() wird nun wieder periodisch aufgerufen, nur gibt blink() keinen Text aus, sondern toggelt Pin 25. Toggeln heißt, den Pin auf LOW zu schalten, wenn er vorher auf HIGH war, und den Pin auf HIGH zu schalten, wenn er vorher auf LOW war. Dadurch blinkt die LED an Pin 25 (also die interne LED im Pico) alle 2 Sekunden. Auch hier ist es so, dass blink() ein Signal benötigt, um überhaupt aufgerufen zu werden.

    Was ist nun besser, MicroPython oder doch die Arduino-IDE?

    Was nun "besser" ist, MicroPython oder doch C, kann leider nicht wirklich beantwortet werden, weil ein großer Teil der Antwort davon abhängt, was man wirklich tun möchte. Ich selbst verwende MicroPython und auch den Pico nicht, denn die Dinge, die ich tun möchte (z. B. Videopac-Emulatoren zu programmieren, die auch eine TV- und Audio-Ausgabe benötigen) kann ich schlicht mit Python nicht umsetzen. Oft benötige ich sogar zusätzlich zu C noch Assembler-Code, der direkt auf den Mikrocontroller (in diesem Fall ist es der ESP32) zugeschnitten ist. Auch das Ansprechen von Spezial-Hardware (Videopac-Joysticks, Infrarotpistolen, ROM-Cartriges vom Flohmarkt) ist mit Python nicht möglich, zu groß ist die Menge Spezialwissen, die man hier benötigt. Wenn man aber nur seinen Schülern den Einstieg in die Programmierung von elektronischen Komponenten erleichtern will, ist der Pico samt MicroPython eine gute Wahl, etwas Einarbeitungszeit mal vorausgesetzt.

    Fazit

    Für den geringen Preis hat der Raspberry Pi Pico eine gute Leistung und es können auch (wenn man in C programmiert) aufwändige Berechnungen, wie z. B. kryptographische Algorithmen, auf diesem ausgeführt werden. Wenn man MicroPython verwendet, kann man sicherlich vielen Schülern zu einem guten Preis den Einstieg in die Programmierung schmackhaft machen. Wenn die Schule dann keine neuen Geräte anschaffen kann, können die Schüler den Pico auch problemlos selbst zahlen. Da es für MicroPython inzwischen zahlreiche kostenlose fertige Bibliotheken gibt, steht sogar einer Roboter-AG nichts im Weg.

    Dem ESP32 muss sich der Pico allerdings geschlagen geben, wie übrigens auch viele Arduinos, die einfach nicht mehr zeitgemäß sind. Wünschenswert für die Zukunft wären deshalb beim Pico mindestens 2 schnelle DAC-Ports, denn der Prozessor ist sicherlich schnell genug, um mit den DACs dann z. B. analoge TV-Signale zu erzeugen. Auch mehr interner Speicher im Megabyte-Bereich wäre sicherlich wünschenswert, denn so könnten auch größere Projekte realisiert werden, die über ein schlichtes Lauflicht oder das Verwenden fertiger Python-Module hinausgehen. Ich persönlich würde Schülern übrigens dann lieber den ESP32 zumuten, denn die 10 Euro, die z. B. eine Node-MCU-Platine der Version 2.0 kostet, liegen immer noch weit unter dem Preis, den man z. B. für eine Lektüre im Deutschunterricht bezahlen muss. In diesem Fall könnte ich dann auch zwischen MicroPython und C wählen, denn auch für den ESP32 gibt es eine MicroPython-Version.

    Autor

    René Krooß

    Rene Krooß arbeitet als Fachbuchautor und Journalist für verschiedene Verlage und Zeitschriften. Er ist Experte für Programmiersprachen und Programmierung, insbesondere im Bereich Hardware-Programmierung, Rechnerstrukturen und…
    >> Weiterlesen
    Das könnte Sie auch interessieren
    Kommentare (5)
    • ASD
      am 28.02.2023
      Hallo, Herr Krooß,

      vielen Dank für Ihren Beitrag für Einsteiger zum Thema Raspberry Pi Pico. Tatsächlich interessiere ich mich für den Pico wegen seiner geringen Abmessungen und seiner für mich ansprechenden Ausstattung, natürlich auch aus Neugier.
      Da ich bisher nur Arduino Nano/Uno/Mega mit Hilfe der Arduino-IDE programmiert hatte, war ich durchaus auch bereit, mich ein bisschen in Python einzuarbeiten. Was mir allerdings gleich zu Anfang dadurch vermiest wurde, dass "import..." partout nicht klappte, also eigentlich gar nichts funktionierte. Das Problem konnte ich mittlerweise lösen, wenn ich auch nicht verstehe, wieso und warum (mittels "lets-encrypt-r3.der", dem Problemlöser sei Dank, hoffentlich).
      Also ging ich erst einmal wieder zurück zur Arduino IDE und habe damit versucht, den Pico zu programmieren. Was mir mittlerweile tatsächlich auch recht gut gelungen ist, nur das Interrupt funktioniert bei mir leider nicht so, wie es soll. Der Pico stürzt mit Eintritt in die Interrupt-Routine ab (ein nur um zu sehen, was überhaupt passiert, eingefügtes
      ---Serial.println("......");---
      wird gerade noch ausgeführt (einmalig, wiederholt schon nicht mehr) , und die LED on Board blinkt abwechselnd kurz und lang. Das scheint unabhängig vom verwendeten Port zu sein. Es liegt auch garantiert nicht an einem zu verprellten Interrupt-Signal, versuchsweise hatte ich ein intern erzeugtes Signal dafür verwendet.
      In irgendeinem Forum hatte mal irgendwer genau das selbe Problem, leider ohne Lösung.
      Vielleicht haben Sie ja eine Idee?
      Hier der leider etwas umfangreiche Code

      [code]
      #include "OneButton.h"
      #include <Wire.h>

      OneButton pushBotton(4, true); // Encoder-SW Pin 6

      enum PinAssignments {
      encoderPinA = 2, // Encoder-CLK Pin 4 rechts
      encoderPinB = 3, // Encoder-DT Pin 5 links
      GRNout = 6, // Port D6 Pin 9
      YELout = 7, // Port D7 Pin10
      REDout = 8, // Port D8 Pin11
      BLUout = 9, // Port D9 Pin12
      };

      #define Delay_P 100 // print delay time

      volatile uint8_t encoderPos = 0; // a counter for the dial
      unsigned long DELAY_P=0; // print delay counter value
      unsigned int lastReportedPos = 1; // change management
      static boolean rotating = false; // debounce management
      boolean CCW = false; // CounterClockWise
      unsigned long temp=0;
      boolean active=false;

      // interrupt service routine vars
      boolean A_set = false;
      boolean B_set = false;

      void setup() {
      pinMode(encoderPinA, INPUT_PULLUP);
      pinMode(encoderPinB, INPUT_PULLUP);

      // Botton control
      pushBotton.attachClick(click);
      pushBotton.attachDoubleClick(doubleclick);
      pushBotton.attachDuringLongPress(longPress);
      pushBotton.attachLongPressStop(longPressStop);

      // Interrupt
      attachInterrupt(2, doEncoderA, CHANGE);
      attachInterrupt(3, doEncoderB, CHANGE);
      //attachInterrupt(digitalPinToInterrupt(encoderPinA), doEncoderA, FALLING);
      //attachInterrupt(digitalPinToInterrupt(encoderPinB), doEncoderB, FALLING);

      // IO Ports
      pinMode(REDout, OUTPUT);
      pinMode(YELout, OUTPUT);
      pinMode(GRNout, OUTPUT);
      pinMode(BLUout, OUTPUT);
      digitalWrite(REDout, LOW);
      digitalWrite(YELout, LOW);
      digitalWrite(GRNout, LOW);
      digitalWrite(BLUout, LOW);

      // SPI
      Serial.begin(9600); // output
      }

      void loop() {
      pushBotton.tick();
      DEL(1000);
      digitalWrite(BLUout,!digitalRead(BLUout)); //toggle blue
      digitalWrite(REDout,HIGH); //red
      digitalWrite(GRNout,LOW);
      DEL(1000);
      digitalWrite(YELout,HIGH); //yellow
      digitalWrite(REDout,LOW);
      DEL(1000);
      digitalWrite(GRNout,HIGH); //green
      digitalWrite(YELout,LOW);
      rotating = true; // reset the debouncer
      showSPI();
      }

      void showSPI(){
      if (lastReportedPos != encoderPos) {
      Serial.print("Index: ");
      Serial.println(encoderPos, DEC);
      lastReportedPos = encoderPos;
      }
      }

      unsigned DEL(uint16_t value){
      if (active==false){
      active=true;
      temp=millis();
      }
      while((millis()-temp)<value){
      pushBotton.tick();
      showSPI();
      delayMicroseconds(500);
      }
      active=false;
      }

      // Interrupt on A changing state
      void doEncoderA() {
      Serial.println("clockwise");
      if ( rotating ) delay (1); // debouncing
      if ( digitalRead(encoderPinA) != A_set ) {
      A_set = !A_set; // if A leads B
      if ( A_set && !B_set )
      encoderPos += 1;
      rotating = false; // no more debouncing
      }
      }
      // Interrupt on B changing state
      void doEncoderB() {
      Serial.println("counterclockwise");
      if ( rotating ) delay (1); // debouncing
      if ( digitalRead(encoderPinB) != B_set ) {
      B_set = !B_set; // if B leads A
      if ( B_set && !A_set )
      encoderPos -= 1;
      rotating = false; // no more debouncing
      }
      }
      void click() {
      Serial.println("Clear ");
      encoderPos = 0;
      }
      void doubleclick() {
      Serial.println("doubleclick");
      }
      void longPress() {
      if(CCW == true)
      encoderPos -= 1;
      else
      encoderPos += 1;
      delay(10);
      showSPI();
      }
      void longPressStop() {
      CCW = !CCW;
      }
      • ASD
        am 02.03.2023
        Hallo Herr Krooß,
        danke für die schnelle Antwort!
        Ich habe das Problem noch nicht gelöst, aber eine für mich brauchbare Lösung gefunden.
        Es kommt mir so vor, als liege das Problem in der Dauer der Interrupt-Routine, denn das Einfügen von delay(), Serial.print(), if...then, while() führt stets dazu, dass der Pico ab Eintritt in die Interrupt-Routine nicht mehr reagiert (die On-Board-LED blinkt 4mal kurz und 4mal lang, die Schnittstelle ist belegt). Ich habe hier zwei Beispiele, wo es mal nicht und mal funktioniert:

        [code]

        -------------------------Funktioniert nicht:-----------------------------

        attachInterrupt(digitalPinToInterrupt(encoderPinA), doEncoderA, CHANGE);
        attachInterrupt(digitalPinToInterrupt(encoderPinB), doEncoderB, CHANGE);

        void doEncoderA() {
        if ( rotating ) delay (1); // debouncing
        if ( digitalRead(encoderPinA) != A_set ) {
        A_set = !A_set; // if A leads B
        if ( A_set && !B_set )
        encoderPos += 1;
        rotating = false; // no more debouncing
        }
        }

        void doEncoderB() {
        if ( rotating ) delay (1); // debouncing
        if ( digitalRead(encoderPinB) != B_set ) {
        B_set = !B_set; // if B leads A
        if ( B_set && !A_set )
        encoderPos -= 1;
        rotating = false; // no more debouncing
        }
        }

        ---------------------------Funktioniert:----------------------------------

        attachInterrupt(digitalPinToInterrupt(encoderPinA),readEncoder,CHANGE);
        attachInterrupt(digitalPinToInterrupt(encoderPinB),readEncoder,CHANGE);

        void readEncoder() {
        encoder_state = (encoder_state << 4) | (digitalRead(encoderPinB) << 1) | digitalRead(encoderPinA);
        switch (encoder_state) {
        case 0x23: encoder_val++; break;
        case 0x32: encoder_val--; break;
        default: break;
        }
        }
        [/code]
      • Rene Krooß
        am 01.03.2023
        @ASD:

        Hallo, Sie haben geschrieben, dass Ihre Interrupt-Routine direkt beim Eintritt abstürzt. Wenn Sie sich die Definition von attachInterrupt ansehen, dann erkennen Sie auch, warum. attachInterrupt() ist wie folgt definiert:

        attachInterrupt(int IRQPin, void* IRQCallbackRoutine, int HandlingMethod);

        HandlingMethod ist in Ihrem Fall FALLING (das ist korrekt), und digitalPinToInterrupt() ermittelt nur die zugehörigen IRQ-Nummern zu Ihren Pins (dies ist auch korrekt). Sie müssen hier also nur statt des Funktionsnamens einen Zeiger auf die Funktion übergeben (durch den Address-Of-Operator vor dem Funktionsnamen). Die korrekte Definition lautet also:

        attachInterrupt(digitalPinToInterrupt(encoderPinA),&doEncoderA,FALLING);
        attachInterrupt(digitalPinToInterrupt(encoderPinB),&doEncoderB,FALLING);

        Allerdings verwende ich inzwischen das C++-SDK, das explizit für den Pico entwickelt wurde, weil die Arduino-IDE immer noch- oder besser gesagt wieder- Probleme macht. Wenn ich dies gewusst hätte, als ich den Artikel schrieb, dann hätte ich für den Einstieg sicherlich nicht die Arduino-IDE empfohlen, sondern gleich das SDK.

        Nun zu MicroPython auf dem Pico. Es gibt einige IDEs, die nicht alle import-Befehle unterstützen, oder sogar zusätzliche import-Kommandos für den Pico haben wollen. Warum dies so ist, kann ich nicht genau sagen. Ich kann nur sagen, dass bei mir persönlch die Thonny-IDE am bestren läuft (auf dieser habe ich auch die Beispiele für den Artikel erstellt und natürlich auch getestet).
    • Andreas
      am 01.05.2022
      In der Einführung sprechen sie noch gezielt an, dass der PICO kein DAC hat und somit keine Audioausgabe möglich ist. Könnte man so stehen lassen, wenn sie nicht im Teil "Was ist nun besser, MicroPython oder doch die Arduino-IDE?" schreiben würden das sie einen PAC-MAN Arcade Automaten damit programmieren möchten. Und hierbei die TV und Audioausgabe als Grund anführen, warum sie das nicht mit µPython tun. Also irgendwie doch etwas widersprüchlich. Zumal es einen VGA-, Audio-Ausgabeadapter gibt, sogar als Open-Hardware-Projekt. Töne kann man sehr wohl mit dem PICO erzeugen, in dem man PWM nutzt, und dieses im Tastverhältnis 50%/50% laufen lässt. Das geht auch mit µPython !
      Dann der nächste nicht ganz aktuelle Beitrag zur Arduino IDE. Klar gibt es dieses Arduino eigene Paket für diesen RB2040 µC , doch der ist immer noch sehr Fehleranfällig. Besser ist hier die Version von Philhower für alle RB2040 Boards, der bedeutend bessere Codes liefert, weniger Probleme beim Flashen machen, und zudem alle anderen Boards die ebenfalls auf dem RB2040 aufbauen unterstützt.
      Und nicht zu vergessen, was immer noch ein Irrglaube der Arduino Fangemeidne ist, dass dieser Compiler einen wirklich effektiven Code abliefert. Allein schon diese Grundaufbaustruktur des Programm mit "setup(void) {} und loop(void) {}" erzeugt einen Overhead im Programm der nicht nur den knappen Speicherplatz sinnlos verschwendet, sondern auch keinen wirklich effektiven Code ausgibt, wenn man die Verabeitungszeit in den µC mal wirklich genauer betrachtet. Hier gibt es mit Geany und anderen C-IDEs bessere OpenSource Lösungen, die zwar für den Einsteiger etwas komplizierter einzurichten sind, aber auch ein echtes HW Debuging unterstützen. Mit der Arduino IDE ist zwar ein relativ einfacher Einstieg möglich, zweifellos. Dennoch sind die Einschränkungen enorm, besonders wenn man mit dieser Oberfläche auch noch ESP, oder AVRs von Atmel / Microchip programmieren will. Hier wird man regelrecht dazu gezwungen relativ banale Dinge mit einem übermächtigen Programmcode zu erschlagen.
      • Rene Krooß
        am 09.05.2022
        @Andreas:
        Hallo Andreas, ich hätte in meinem Artikel wahrscheinlich noch ausführlicher darstellen sollen, dass dieser sich an Einsteiger richtet und die Sache mit dem Emulator für den Videopac (der übrigens kein Arcade-Automat, sondern eine Retro-Spielekonsole ist) einfach weglassen sollen. Denn ein Videopac-Emulator (+Farbe) lässt sich in der Tat nicht mit dem Pico realisieren, denn hier benötigt man einen DAC, weil der Adapter, den auch Sie in Ihrem Kommentar erwähnen, nur Graustufen erzeugt (zumindest bei mir fehlt der sogenannte Color-Burst, der einem Fernseher sagt, dass ein Farbsignal verwendet wird). Auch andere Wellenformen, als ein Rechtechsignal mit variabler Pulsbreite, kann der Pico nicht ausgeben, es sei denn, Sie verwenden einen externen DAC (ggf. in Form eines Adapters).

        In Bezug auf die Arduino-IDE haben Sie sicherlich recht, denn diese wurde nicht auf Geschwindigkeit optimiert, sondern eher so konzipiert, dass sie möglichst viele Mikrocontroller unterstützt. Leider werden hierfür nicht nur suboptimale Assembler-Codes, sondern sogar auch andere Dinge billigend in Kauf genommen, die zum Teil recht nervig sein können. So wird z.B. die switch-sace-Anweisung nicht in Sprungtabellen umgesetzt, sondern einfach in mehrere if-Statements, was sehr, sehr ineffizient ist. Aber auch in diesem Fall hätte ich wahrscheinlich expliziter darauf hinweisen müssen, dass Einsteiger, die einmal mit der Arduino-IDE bzw. den Standard-Boardtreibern angefangen haben, nicht gezwungen sind, diese weiterhin zu nutzen, wenn sie dann zu Profis geworden sind.

    Neuen Kommentar schreiben