Ratgeber · 10 Min. Lesezeit

Raspberry Pi Pico PIO und zwei Kerne: _thread, setup1, WS2812B

Raspberry Pi Pico PIO erklärt: State Machines, Rechtecksignal und WS2812B-Beispiel, beide Kerne mit MicroPython _thread und Arduino setup1/loop1, Pico 2.

Der Raspberry Pi Pico PIO-Block und die zwei Kerne sind die beiden Merkmale, die dieses kleine Board von den meisten Mikrocontrollern seiner Preisklasse abheben. Im RP2040, dem Herz des Pico, stecken zwei getrennte Prozessorkerne und 8 PIO-State-Machines. Dank der Kerne kannst du auf der einen Seite Sensoren auslesen, während auf der anderen ein Display oder eine LED-Animation ohne Ruckeln weiterläuft. PIO dagegen sind winzige Timing-Maschinen, die unabhängig vom Prozessor arbeiten: Sie erzeugen das nanosekundengenaue Signal für WS2812B-LEDs, einen zusätzlichen UART oder ein Rechtecksignal, ohne die CPU zu belasten.

In dieser Anleitung startest du beide Kerne zuerst mit dem Modul _thread in MicroPython und dann mit setup1() und loop1() in der Arduino IDE. Danach lernst du, wie PIO funktioniert, wie viele State Machines es gibt und welche Befehle sie kennen, und schreibst zwei echte Programme: einen Rechteckgenerator, der Töne auf einem Buzzer spielt, und einen WS2812B-Regenbogen. Zum Schluss schauen wir uns an, was der Pico 2 (RP2350) ändert und wann du diese Funktionen wirklich brauchst. Wenn der Pico neu für dich ist, lies vorher Was ist der Raspberry Pi Pico? und Was ist MicroPython?.

Raspberry Pi Pico Entwicklungsboard
Raspberry Pi Pico: Im RP2040 in der Mitte stecken zwei Cortex-M0+-Kerne und zwei PIO-Blöcke. Alle 26 GPIO-Pins lassen sich mit PIO verbinden.

Was sind die zwei Kerne und die PIO des Raspberry Pi Pico?

Der RP2040 besitzt zwei identische Cortex-M0+-Prozessoren namens Core 0 und Core 1. Beim Programmstart läuft nur Core 0; Core 1 schläft, bis du ihn startest. Beide Kerne teilen sich dieselben 264 KB RAM und dieselben Pins. Daten auszutauschen ist daher einfach, aber sie dürfen nicht gleichzeitig dieselbe Variable beschreiben. Dafür hat der Chip eine kleine Hardware-Warteschlange in beide Richtungen (FIFO, je 8 Wörter) und 32 Hardware-Sperren (Spinlocks). PIO ist eine völlig getrennte Welt: Jeder der zwei PIO-Blöcke hat 4 State Machines, einen gemeinsamen Programmspeicher für 32 Befehle und direkten Zugriff auf die Pins. Einmal gestartet, arbeitet eine State Machine ihr Programm Takt für Takt ab, auch wenn der Prozessor gerade etwas anderes erledigt.

RessourceRP2040 (Pico, Pico W)Wofür?
Prozessorkern2 x Cortex-M0+, 133 MHz (laut aktuellen Unterlagen bis 200 MHz)Zwei getrennte Programme wirklich gleichzeitig ausführen
FIFO zwischen den Kernen8 x 32 Bit je RichtungZahlen und Befehle zwischen den Kernen senden
Hardware-Sperre (Spinlock)32Abwechselnder Zugriff auf gemeinsame Daten
PIO-Block2 (PIO0, PIO1)Zeitkritische Pin-Arbeit vom Prozessor fernhalten
State Machine4 pro Block, insgesamt 8Jede führt ihr eigenes PIO-Programm aus
PIO-Programmspeicher32 Befehle pro BlockWird von den 4 State Machines des Blocks geteilt
PIO-FIFOTX 4 + RX 4 Wörter pro Maschine (verbunden 8)Daten zwischen Prozessor und State Machine

Der zweite Kern in MicroPython: das Modul _thread

In MicroPython nutzt du Core 1 mit dem Aufruf _thread.start_new_thread(funktion, argumente). Auf dem Pico startet dieser Aufruf die Funktion auf dem zweiten Kern, während dein Hauptprogramm auf Core 0 weiterläuft. Es kann immer nur ein zusätzlicher Thread laufen, denn einen dritten Kern gibt es nicht. Im folgenden Beispiel liest Core 0 ein Potentiometer an GP26 und gibt den Wert aus, Core 1 lässt die Onboard-LED in dem Tempo blinken, das das Potentiometer vorgibt. Das sleep_ms() auf Core 1 bremst Core 0 überhaupt nicht; auf einem einzigen Kern bräuchtest du dafür einen Timer oder asyncio.

MicroPython
1# Pico - iki çekirdek (MicroPython _thread) / two cores (MicroPython _thread)
2import _thread
3import time
4from machine import Pin, ADC
5
6led = Pin("LED", Pin.OUT)          # Pico ve Pico W dahili LED / onboard LED on Pico and Pico W
7pot = ADC(26)                      # GP26 = ADC0, potansiyometre / potentiometer
8
9lock = _thread.allocate_lock()     # ortak veri kilidi / shared data lock
10blink_ms = 500                     # çekirdek 0 yazar, çekirdek 1 okur / core 0 writes, core 1 reads
11running = True                     # durdurma bayrağı / stop flag
12
13
14def core1_task():
15    # Çekirdek 1: LED'i kendi hızında yakıp söndürür / Core 1: blinks the LED at its own pace
16    while running:
17        with lock:
18            period = blink_ms
19        led.toggle()
20        time.sleep_ms(period)
21    led.off()
22
23
24_thread.start_new_thread(core1_task, ())   # ikinci çekirdekte başlat / start on the second core
25
26try:
27    while True:
28        # Çekirdek 0: sensörü okur ve hızı ayarlar / Core 0: reads the sensor and sets the speed
29        raw = pot.read_u16()                     # 0-65535
30        with lock:
31            blink_ms = 50 + raw * 950 // 65535   # 50-1000 ms
32        print("ham / raw:", raw, "ms:", blink_ms)
33        time.sleep_ms(200)
34except KeyboardInterrupt:
35    running = False                              # çekirdek 1'e dur de / tell core 1 to stop
36    time.sleep_ms(1100)
  • Die mit allocate_lock() erzeugte Sperre sorgt dafür, dass innerhalb eines with lock:-Blocks nur ein Kern die gemeinsame Variable anfasst.
  • Das Flag running sagt Core 1, dass er seine Schleife verlassen soll, wenn du das Programm mit Strg+C stoppst; sonst blinkt die LED weiter.
  • Pin("LED") findet die Onboard-LED auf dem Pico und dem Pico W; beim Pico W hängt die LED am Funkchip, deshalb funktioniert Pin(25) dort nicht.
  • Eine gute Aufteilung: lange Berechnungen, Display-Zeichnen oder genaues Timing auf Core 1, WLAN, Menüs und Bedienung auf Core 0.
Der Stopp-Knopf in Thonny unterbricht nur das Programm auf Core 0. Läuft auf Core 1 noch eine Endlosschleife, wirkt das Board beschäftigt und neuer Code lässt sich nicht hochladen. Zieh dann das USB-Kabel ab und steck es wieder ein, oder setze das Board zurück, indem du den RUN-Pin kurz mit GND verbindest. Verwende immer ein Stopp-Flag wie im Beispiel und vermeide im zusätzlichen Thread große Speicheranforderungen (lange Listen, viele String-Verkettungen); Mehrkern-Unterstützung gilt in MicroPython noch als experimentell.

Zwei Kerne in der Arduino IDE: setup1() und loop1()

Das meistgenutzte Pico-Paket für die Arduino IDE ist der Core Raspberry Pi Pico/RP2040/RP2350 von Earle Philhower (arduino-pico). Damit beide Kerne zu nutzen ist erstaunlich einfach: Die gewohnten Funktionen setup() und loop() laufen auf Core 0; fügst du dem Sketch setup1() und loop1() hinzu, startet Core 1 automatisch und führt diese beiden aus. Daten zwischen den Kernen schickst du mit dem Objekt rp2040.fifo. Das offizielle Paket "Arduino Mbed OS RP2040" kennt setup1() nicht, wähle im Boardverwalter also das richtige Paket.

C++ (Arduino IDE)
1// Raspberry Pi Pico - iki çekirdek (Arduino-Pico çekirdeği) / two cores (Arduino-Pico core)
2const int POT_PIN = 26;        // GP26 = ADC0, potansiyometre / potentiometer
3
4// ---- Çekirdek 0 / Core 0 ----
5void setup() {
6  Serial.begin(115200);
7}
8
9void loop() {
10  int raw = analogRead(POT_PIN);   // 0-1023 (varsayılan 10 bit / default 10-bit)
11  rp2040.fifo.push_nb(raw);        // FIFO doluysa bekleme, değeri atla / skip the value if the FIFO is full
12  Serial.print("pot: ");
13  Serial.println(raw);
14  delay(100);
15}
16
17// ---- Çekirdek 1 / Core 1 ----
18void setup1() {
19  pinMode(LED_BUILTIN, OUTPUT);
20}
21
22void loop1() {
23  static uint32_t periodMs = 500;
24  uint32_t value;
25  while (rp2040.fifo.pop_nb(&value)) {           // FIFO'yu boşalt, sonuncuyu kullan / drain the FIFO, keep the last one
26    periodMs = map(value, 0, 1023, 50, 1000);
27  }
28  digitalWrite(LED_BUILTIN, HIGH);
29  delay(periodMs);                               // yalnız çekirdek 1'i bekletir / only blocks core 1
30  digitalWrite(LED_BUILTIN, LOW);
31  delay(periodMs);
32}
FunktionWas sie macht
rp2040.fifo.push(x)Schickt einen 32-Bit-Wert an den anderen Kern; wartet auf Platz, wenn die Warteschlange voll ist
rp2040.fifo.push_nb(x)Versucht ohne Warten zu senden; gibt false zurück, wenn die Warteschlange voll ist
rp2040.fifo.pop()Liest einen Wert vom anderen Kern; wartet, wenn die Warteschlange leer ist
rp2040.fifo.pop_nb(&x)Schreibt einen vorhandenen Wert in x und gibt true zurück, sonst sofort false
rp2040.fifo.available()Liefert die Anzahl der Werte, die auf das Lesen warten
rp2040.idleOtherCore() / resumeOtherCore()Hält den anderen Kern kurz an und lässt ihn weiterlaufen (z. B. beim Schreiben in den Flash)
Nutze ein einzelnes Gerät wie die serielle Schnittstelle, ein Display oder einen SPI-Bus nicht gleichzeitig von beiden Kernen aus. Gib wie im Beispiel jede Peripherie einem Kern und lass den anderen Kern ihm Zahlen über die FIFO schicken. So vermeidest du ohne Sperren durcheinandergeratenen Text und kaputte Displayinhalte.

Was ist PIO? So funktioniert programmierbare Ein-/Ausgabe

Bei den meisten Mikrocontrollern sind Kommunikations- und Signalblöcke wie UART, SPI, I2C und PWM fest im Chip verbaut; brauchst du ein Protokoll, das nicht auf der Liste steht, schaltet der Prozessor die Pins einzeln ein und aus (Bit-Banging). Das hält den Prozessor beschäftigt, und sobald ein Interrupt dazwischenkommt, stimmt das Timing nicht mehr. PIO (Programmable Input/Output) löst das grundsätzlich: Jede State Machine ist ein winziger Prozessor mit neun Befehlen, der nur für Pin-Arbeit gebaut ist. Jeder Befehl dauert genau einen Takt, und an sein Ende lässt sich eine Verzögerung von 0 bis 31 Takten hängen. So weißt du durch einfaches Takte-Zählen exakt, nach wie vielen Nanosekunden jede Flanke kommt. Das Tempo der State Machine stellst du ein, indem der Systemtakt durch einen Teiler zwischen 1 und 65536 geteilt wird.

BefehlAufgabe
set(pins, v)Schreibt einen festen Wert 0-31 auf Pins oder in die Register X/Y
out(ziel, n)Schiebt n Bit aus dem Ausgabe-Schieberegister (OSR) auf Pins oder nach X/Y
in_(quelle, n)Schiebt n Bit von Pins oder Registern in das Eingabe-Schieberegister (ISR)
pull() / push()Holt ein Wort aus der TX-FIFO ins OSR, schiebt das ISR-Wort in die RX-FIFO
jmp(bedingung, label)Springt abhängig von einer Bedingung (X null, Pin high, X-- usw.)
wait(polarität, quelle, nr)Wartet, bis ein Pin oder IRQ-Flag den gewünschten Pegel hat
mov(ziel, quelle)Kopiert zwischen Registern, auf Wunsch mit invertierten Bits
irq(nr)Setzt ein Interrupt-Flag für die CPU oder eine andere State Machine
nop() und .side(v)Leerbefehl; Side-Set ändert einen Pin im selben Takt wie jeder Befehl

In MicroPython sind PIO-Programme Python-Funktionen mit dem Dekorator @rp2.asm_pio; die Funktion wird nicht aufgerufen, sondern von MicroPython in Maschinencode übersetzt. Anschließend lädst du sie mit rp2.StateMachine(nr, programm, freq=..., set_base=...) in eine State Machine. Beim Pico gehören die Nummern 0-3 zu PIO0 und 4-7 zu PIO1. freq ist die Anzahl der Befehlstakte pro Sekunde und darf nicht unter 1/65536 des Systemtakts liegen; bei 125 MHz sind das etwa 1,9 kHz, bei 150 MHz etwa 2,3 kHz. Brauchst du ein langsameres Signal, nimm Verzögerungen oder Schleifen mit den Zählern X/Y.

Rechtecksignal mit PIO: dein erstes State-Machine-Programm

Im ersten Beispiel spielen wir auf einem passiven Buzzer an GP15 eine Tonleiter und lassen danach ein dauerhaftes 1-kHz-Rechtecksignal laufen. Das Programm besteht aus nur zwei Befehlen: Pin auf HIGH setzen und 9 Takte warten, Pin auf LOW setzen und 9 Takte warten. Weil jeder Befehl selbst 1 Takt dauert, umfasst eine Periode 20 Takte; du gibst der State Machine also einfach das 20-Fache der gewünschten Tonfrequenz. Schließe den Pluspol des Buzzers an GP15 und den Minuspol an GND an. Statt des Buzzers kannst du auch ein Oszilloskop oder eine LED mit 220-Ohm-Widerstand nehmen; den Widerstand bestimmst du mit dem LED-Vorwiderstandsrechner.

MicroPython
1# PIO ile kare dalga ve buzzer notaları / square wave and buzzer notes with PIO
2import time
3import rp2
4from machine import Pin
5
6
7@rp2.asm_pio(set_init=rp2.PIO.OUT_LOW)
8def square():
9    wrap_target()
10    set(pins, 1)   [9]     # 1 + 9 = 10 döngü HIGH / 10 cycles HIGH
11    set(pins, 0)   [9]     # 1 + 9 = 10 döngü LOW / 10 cycles LOW
12    wrap()                 # başa dön, işlemci karışmaz / loop back, no CPU involved
13
14
15def tone(freq_hz):
16    # Bir periyot 20 döngü: durum makinesi frekansı = 20 x ton
17    # One period is 20 cycles: state machine frequency = 20 x tone
18    sm = rp2.StateMachine(0, square, freq=freq_hz * 20, set_base=Pin(15))
19    sm.active(1)
20    return sm
21
22
23notes = [262, 294, 330, 349, 392, 440, 494, 523]   # Do-Re-Mi ... / C4 ... C5
24for n in notes:
25    sm = tone(n)
26    time.sleep_ms(300)        # işlemci boşta, ses PIO'dan / CPU is idle, PIO makes the sound
27    sm.active(0)
28
29sm = tone(1000)               # 1 kHz sürekli kare dalga / continuous 1 kHz square wave
30print("GP15: 1 kHz kare dalga / square wave")

Die Formel ist einfach: Tonfrequenz = Frequenz der State Machine / Anzahl der Takte. Für 1000 Hz läuft die Maschine mit 20.000 Hz, also deutlich über der Untergrenze. Entfernst du die Verzögerungen und lässt nur die zwei set()-Befehle stehen, schrumpft eine Periode auf 2 Takte; bei 125 MHz erhältst du dann ein 62,5-MHz-Rechtecksignal am Pin. Vergiss nicht, dass Hardware-PWM dasselbe kann: Für einen einfachen Ton oder die LED-Helligkeit reicht PWM. Der Unterschied bei PIO ist, dass du die Form des Signals komplett selbst bestimmst; mit wenigen Zeilen erzeugst du Impulse variabler Breite, eine genaue Anzahl von Impulsen oder Ausgänge, die auf einen Eingang reagieren.

WS2812B-LEDs (NeoPixel) mit PIO ansteuern

WS2812B RGB-LED-Ring mit 24 LEDs
WS2812B-Ring mit 24 LEDs: Jede LED hat einen eigenen Controller und erhält ihre Farbe als 24 Bit über eine einzige Datenleitung.

WS2812B-LEDs erwarten pro Bit einen Impuls von etwa 1,25 Mikrosekunden; ob ein Bit 1 oder 0 ist, ergibt sich daraus, wie lange der Impuls HIGH bleibt. Ein Lehrbuchfall für PIO. Das folgende Programm basiert auf dem offiziellen MicroPython-Beispiel von Raspberry Pi: Die State Machine läuft mit 8 MHz, jedes Bit dauert genau 10 Takte, also werden 800.000 Bit pro Sekunde gesendet. Dank autopull holt die Maschine alle 24 Bit eine neue Farbe aus der FIFO; der Prozessor legt das Array nur mit sm.put() in die FIFO. Passe die LED-Anzahl an deinen Streifen an; wie der WS2812B funktioniert und welche Farbreihenfolge er nutzt, steht im WS2812B-NeoPixel-Ratgeber.

WS2812B-AnschlussPico-PinHinweis
DIN (Dateneingang)GP16 (physischer Pin 21)Ein 330-Ohm-Serienwiderstand schützt das Signal
5V / VCCVBUS (Pin 40)5 V vom USB; bei vielen LEDs ein externes 5-V-Netzteil nutzen
GNDGND (z. B. Pin 38)Auch die Masse des externen Netzteils gehört hierher
MicroPython
1# PIO ile WS2812B (NeoPixel) gökkuşağı / WS2812B (NeoPixel) rainbow with PIO
2import array
3import time
4import rp2
5from machine import Pin
6
7NUM_LEDS = 24          # halka ya da şeritteki LED sayısı / LEDs in the ring or strip
8LED_PIN = 16           # DIN bağlantısı / DIN connection
9BRIGHTNESS = 0.2       # 0.0-1.0, akımı düşük tutar / keeps current low
10
11
12@rp2.asm_pio(sideset_init=rp2.PIO.OUT_LOW, out_shiftdir=rp2.PIO.SHIFT_LEFT,
13             autopull=True, pull_thresh=24)
14def ws2812():
15    T1 = 2
16    T2 = 5
17    T3 = 3
18    wrap_target()
19    label("bitloop")
20    out(x, 1)               .side(0)    [T3 - 1]   # 1 biti al, hat LOW / take 1 bit, line LOW
21    jmp(not_x, "do_zero")   .side(1)    [T1 - 1]   # hat HIGH / line HIGH
22    jmp("bitloop")          .side(1)    [T2 - 1]   # bit 1: uzun HIGH / long HIGH
23    label("do_zero")
24    nop()                   .side(0)    [T2 - 1]   # bit 0: kısa HIGH / short HIGH
25    wrap()
26
27
28# Bit başına 10 döngü x 8 MHz = 800 kHz / 10 cycles per bit x 8 MHz = 800 kHz
29sm = rp2.StateMachine(0, ws2812, freq=8_000_000, sideset_base=Pin(LED_PIN))
30sm.active(1)
31
32pixels = array.array("I", [0] * NUM_LEDS)
33
34
35def set_pixel(i, r, g, b):
36    r = int(r * BRIGHTNESS)
37    g = int(g * BRIGHTNESS)
38    b = int(b * BRIGHTNESS)
39    pixels[i] = (g << 16) | (r << 8) | b    # WS2812B sırası GRB / byte order is GRB
40
41
42def show():
43    sm.put(pixels, 8)      # 24 biti sola hizala / left-align the 24 bits
44
45
46def wheel(pos):
47    # 0-255 arası değeri renge çevir / turn 0-255 into a colour
48    pos %= 255
49    if pos < 85:
50        return 255 - pos * 3, pos * 3, 0
51    if pos < 170:
52        pos -= 85
53        return 0, 255 - pos * 3, pos * 3
54    pos -= 170
55    return pos * 3, 0, 255 - pos * 3
56
57
58step = 0
59while True:
60    for i in range(NUM_LEDS):
61        set_pixel(i, *wheel(i * 255 // NUM_LEDS + step))
62    show()
63    step = (step + 3) % 255
64    time.sleep_ms(30)      # kare arası bekleme, aynı zamanda reset / frame gap, also the reset time

Gehen wir das Programm Zeile für Zeile durch. out(x, 1) holt ein Bit aus dem OSR ins Register X, während Side-Set die Leitung LOW hält (3 Takte). Dann geht die Leitung auf HIGH und X wird geprüft (2 Takte). Ist das Bit 1, bleibt die Leitung 5 weitere Takte HIGH; ist es 0, wird sie auf LOW gezogen und die Maschine wartet 5 Takte. Beide Wege ergeben 10 Takte, also 1,25 µs. pull_thresh=24 sagt der Maschine, dass sie von jedem Wort nur 24 Bit verwendet; deshalb wird die Farbe auf der Python-Seite nach links geschoben (sm.put(pixels, 8)). Die Farbreihenfolge ist GRB, nicht RGB; sind Rot und Grün vertauscht, liegt es daran. Da 24 LEDs bei vollem Weiß bis zu 1,4 A ziehen können, ist die Helligkeit im Beispiel auf 20 % begrenzt.

Wenn du nur LEDs leuchten lassen willst, reicht auch das eingebaute MicroPython-Modul neopixel: np = neopixel.NeoPixel(Pin(16), 24), np[0] = (255, 0, 0), np.write(). Der Vorteil der PIO-Version: Der Prozessor bleibt während der Übertragung frei, und du kannst dieselbe Technik auf andere Protokolle übertragen.

Was ändert sich mit dem Pico 2 (RP2350)?

Der Raspberry Pi Pico 2 ist die neue Generation mit gleicher Größe und gleicher Pinbelegung, aber mit einem RP2350 im Inneren. Er hat weiterhin zwei Kerne, doch diesmal wählst du beim Start zwischen zwei Arm-Cortex-M33-Kernen und zwei Hazard3-RISC-V-Kernen. Der gesamte Code dieses Artikels läuft unverändert auf dem Pico 2: _thread ist in MicroPython gleich, im Arduino-Pico-Core heißen setup1()/loop1() und rp2040.fifo genauso. Bei PIO kommt ein dritter Block hinzu, es gibt also 12 State Machines (in MicroPython 0-11) sowie einige neue Befehlsoptionen.

MerkmalPico (RP2040)Pico 2 (RP2350)
Kerne2 x Cortex-M0+2 x Cortex-M33 oder 2 x Hazard3 RISC-V
Takt133 MHz150 MHz
RAM264 KB520 KB
Flash auf dem Board2 MB4 MB
PIO2 Blöcke, 8 State Machines3 Blöcke, 12 State Machines
GleitkommaIn Software (schnelle ROM-Routinen)Hardware-FPU (einfache Genauigkeit) + Koprozessor für doppelte Genauigkeit
SicherheitKeineTrustZone, Secure Boot, 8 KB OTP
MicroPython-DateiRPI_PICO (.uf2)RPI_PICO2 (.uf2)

In der Praxis ist der größte spürbare Unterschied des Pico 2 die Geschwindigkeit: Dank Hardware-FPU laufen gleitkommalastige Aufgaben (Filter, Sensorfusion, Audioverarbeitung) um ein Mehrfaches schneller, und der doppelte RAM bietet Platz für große Display-Puffer. Achte nur darauf, die passende UF2-Datei zu flashen; die Datei für den Pico läuft nicht auf dem Pico 2. Frühe RP2350-Versionen hatten ein bekanntes Hardwareproblem (E9) bei Eingängen mit internem Pull-down, das in der Revision A4 behoben wurde; ein externer Widerstand beim Anschließen von Tastern ist in jedem Fall die sichere Wahl.

Wann brauchst du zwei Kerne und wann PIO?

AnforderungBeste LösungWarum?
LED-Helligkeit, Servo, einfacher TonHardware-PWMFertiger Block, eine Zeile Code
Ein paar Sensoren + Display + TasterEin Kern, millis() oder asyncioKeine zusätzliche Komplexität nötig
Flüssige Animation bei langen BerechnungenZwei KerneDie Berechnung auf Core 1 friert das Display nicht ein
Lückenlose Messung neben WLANZwei KerneNetzwerkverzögerungen stören das Messintervall nicht
WS2812B, zusätzlicher UART, IR-Sender, EncoderPIONanosekundengenau, CPU bleibt frei
VGA/DVI-Bild, I2S-Audio, sehr schnelle SignalePIO + DMADatenraten, bei denen die CPU nicht mitkäme

Kurz gesagt: Denk an den zweiten Kern, wenn sich Aufgaben in der Software in die Quere kommen, und an PIO, wenn die Pins Genauigkeit unter einer Mikrosekunde brauchen. Die meisten Hobbyprojekte kommen ohne beides aus; aber wenn deine WS2812B-Animation eines Tages während einer WLAN-Anfrage ruckelt oder dem Board die UARTs ausgehen, wartet die Lösung schon im Pico.

Projektideen mit Pico PIO und zwei Kernen

  • Musikgesteuerter LED-Ring: Core 1 verarbeitet Mikrofonwerte, PIO steuert den WS2812B-Ring und Core 0 fragt die Taster ab.
  • Achtkanaliger Pulsgenerator: Jede State Machine erzeugt ein Rechtecksignal mit eigener Frequenz für Schrittmotortreiber oder Prüfaufbauten.
  • Lückenloser Datenlogger: Core 1 liest alle 10 ms den ADC, Core 0 sendet die Daten per WLAN; auch bei langsamem Netz geht kein Messwert verloren.
  • Zusätzliche serielle Schnittstellen: Mit PIO einen dritten und vierten UART öffnen und GPS und Bluetooth-Modul gleichzeitig anschließen.
  • Drehencoder-Zähler: PIO zählt Encoder-Impulse ohne einen einzigen zu verpassen; der Prozessor liest nur das Ergebnis.
  • Atmendes Nachtlicht: Weiche PWM-Übergänge auf Core 1, den Lichtsensor auf Core 0.

Häufige Fehler und Lösungen

SymptomUrsacheLösung
Board reagiert nach dem Stoppen nichtDie Schleife auf Core 1 läuft nochStopp-Flag nutzen; notfalls USB ab- und wieder anstecken
start_new_thread schlägt beim zweiten Mal fehlDer Pico erlaubt nur einen zusätzlichen ThreadKeinen neuen starten, bevor der alte beendet ist
Variablen haben zeitweise unsinnige WerteBeide Kerne schreiben ohne Sperreallocate_lock() oder die FIFO verwenden
StateMachine meldet ValueErrorfreq liegt unter Systemtakt / 65536Frequenz erhöhen, mit Verzögerungen verlangsamen
PIOASMError: delay too largeSide-Set-Bits haben das Verzögerungsfeld verkleinertVerzögerung aufteilen oder nop() einfügen
Rot und Grün beim WS2812B vertauschtDie Farbreihenfolge ist GRBFormat (g << 16) | (r << 8) | b verwenden
setup1() läuft nieDas Paket Arduino Mbed RP2040 ist gewähltDas Paket Raspberry Pi Pico/RP2040 von Earle Philhower installieren
Schreib beim PIO-Programmieren die Taktzahl jedes Befehls auf und prüfe, ob die Summe der gewünschten Zeit entspricht. Ein Oszilloskop oder ein günstiger Logikanalysator hilft sehr; alternativ senkst du die Frequenz der State Machine vorübergehend auf 2-3 kHz und beobachtest den Pin mit einer LED, so siehst du Fehler mit bloßem Auge.

Zwei Kerne und PIO machen aus dem Pico mehr als einen LED-Blinker, nämlich ein ernstzunehmendes Embedded-System; doch alles baut auf derselben Grundlage auf: Pins, Timing und LEDs gut zu kennen. In der BlueGrays-App findest du Raspberry-Pi-Pico-Projekte wie LED-Blinken, Lauflicht, Knight-Rider-Effekt, eine tastergesteuerte State Machine und einen PWM-Atemeffekt, jeweils mit Schaltplan und MicroPython-Code Schritt für Schritt, und kannst die Techniken aus diesem Artikel darauf aufbauen.

Häufige Fragen

Was ist PIO beim Raspberry Pi Pico?

PIO (programmierbare Ein-/Ausgabe) sind kleine State Machines in den Chips RP2040 und RP2350, die unabhängig vom Prozessor arbeiten. Jede führt ein Programm in einer einfachen Sprache mit neun Befehlen taktgenau aus. So erledigt sie zeitkritische Aufgaben wie WS2812B-LEDs, zusätzliche UARTs, IR-Senden oder Encoder-Auswertung, ohne die CPU zu belasten.

Wie viele Kerne hat der Raspberry Pi Pico?

Der RP2040 auf Pico und Pico W hat zwei Cortex-M0+-Kerne. Auch der RP2350 auf dem Pico 2 hat zwei Kerne, wobei du beim Start zwischen Cortex-M33 und Hazard3 RISC-V wählen kannst. Beim Programmstart läuft nur Core 0; Core 1 startest du selbst.

Wie viele PIO State Machines hat der Pico?

Der RP2040 hat zwei PIO-Blöcke mit je 4 State Machines, also insgesamt 8. Der Programmspeicher von 32 Befehlen pro Block wird von den Maschinen dieses Blocks geteilt. Der RP2350 im Pico 2 hat drei PIO-Blöcke und damit 12 State Machines.

Kann MicroPython beide Kerne des Pico nutzen?

Ja. Eine mit _thread.start_new_thread() gestartete Funktion läuft auf dem Pico auf dem zweiten Kern. Es kann nur ein zusätzlicher Thread gleichzeitig laufen, und gemeinsame Daten schützt du mit einer Sperre aus _thread.allocate_lock(). Da die Mehrkern-Unterstützung in MicroPython noch experimentell ist, vermeidest du im zweiten Thread besser speicherintensive Arbeit.

Wie nutze ich den zweiten Kern des Pico in der Arduino IDE?

Nach der Installation des Pakets Raspberry Pi Pico/RP2040/RP2350 von Earle Philhower fügst du deinem Sketch einfach setup1() und loop1() hinzu; Core 1 führt sie automatisch aus. 32-Bit-Werte tauschen die Kerne mit rp2040.fifo.push() und rp2040.fifo.pop() aus. Das Mbed-basierte RP2040-Paket von Arduino bietet diese Funktion nicht.

Muss ich für WS2812B-LEDs PIO verwenden?

Nein. Das eingebaute MicroPython-Modul neopixel und die Adafruit-NeoPixel-Bibliothek in Arduino funktionieren auf dem Pico problemlos. Der Vorteil einer eigenen PIO-Lösung ist, dass der Prozessor während der Übertragung frei bleibt und du die Technik auf andere zeitkritische Protokolle übertragen kannst.

Alle Projekte ansehen
Raspberry Pi Pico Onboard-LED Blinken (Pico und Pico W)
#147Anfänger

Raspberry Pi Pico Onboard-LED Blinken (Pico und Pico W)

Das Eröffnungsprojekt der Raspberry Pi Pico-Serie! Wir bringen die grüne interne LED zum Blinken, um zu überprüfen, ob die Platine funktioniert — ein klassisches "Hello World"-Erstexperiment. Keine externen Komponenten, nur Pico und USB-Kabel. Der Code ist in MicroPython geschrieben (die offiziell von der Raspberry Pi Foundation unterstützte Sprache). Lerne die machine.Pin-Klasse, Pin.OUT-Modus, led.on()/off()-Methoden und time.sleep() in Thonny IDE. Verfolge jede Umsch

5.0(1)
10
Raspberry Pi Pico: Externe LED zum Leuchten bringen (Steckbrett)
#148Anfänger

Raspberry Pi Pico: Externe LED zum Leuchten bringen (Steckbrett)

Der nächste Schritt nach der integrierten LED des Pico: Eine externe LED an das Breadboard anschließen und über den GP14-Pin steuern. In diesem Projekt lernst du, wie du einen beliebigen universellen GPIO-Pin des Pico als Ausgang nutzen kannst, welche Polarität die LED hat (langes Bein = Anode/+, kurzes Bein = Kathode/–) und warum ein Strombegrenzungswiderstand (220 Ω) erforderlich ist. Wenn du den Widerstand weglässt, fließt zu viel Strom durch die LED und sie kann durchbrennen. Die Schaltung i

4.5(2)
7
Raspberry Pi Pico Ampel-Simulator (3 LEDs sequenziell)
#150Anfänger

Raspberry Pi Pico Ampel-Simulator (3 LEDs sequenziell)

Wir simulieren eine echte Ampel mit roten, gelben und grünen LEDs. Grün 4 Sek "gehen", gelb 1,5 Sek "bereit", rot 3 Sek "stopp" und rot+gelb 1 Sek "starten" (europäisches Ampelmuster). Lerne Funktionsdefinition, Zustandsmaschinen-Logik und Multi-GPIO-Synchronisation. Sehr einfache Schaltung: 3 LEDs an GP11/GP12/GP13, jeweils mit 220Ω Widerstand.

4.0(1)
12
Raspberry Pi Pico Lauflicht (6 LEDs)
#153Anfänger

Raspberry Pi Pico Lauflicht (6 LEDs)

Klassische "Lauflicht"-Animation mit Pico — 6 LED Version! 6 LEDs leuchten sequenziell von links nach rechts. Lerne Python-Liste, List Comprehension ([Pin(p, Pin.OUT) for p in LED_PINS]), for-Schleife mit Pin-Kontrolle und enumerate(). 6 LEDs an GP9-GP14, jeweils mit 220Ω Widerstand. Sehr sauberer Code: statt 6 LEDs einzeln zu definieren, verwenden wir eine Liste — du kannst LEDs entsprechend der Anzahl freier, nutzbarer GPIO-Pins hinzufügen, jeweils mit einem eigenen Vorwiderstand. Für 100 unab

0.0(0)
8
Raspberry Pi Pico Knight Rider LED-Scanner (6 LED Hin-Zurück)
#154Anfänger

Raspberry Pi Pico Knight Rider LED-Scanner (6 LED Hin-Zurück)

Klassischer "Knight Rider"-LED-Scanner-Effekt mit Pico! 6 LEDs gehen von links nach rechts, dann von rechts nach links, für immer. Lerne reversed() und zwei getrennte for-Schleifen für Hin-Zurück-Muster.

0.0(0)
13
Raspberry Pi Pico-Ampel mit 4-Modus-Tastenwahlschalter (Zustandsmaschine)
#158Mittel

Raspberry Pi Pico-Ampel mit 4-Modus-Tastenwahlschalter (Zustandsmaschine)

4 verschiedene Modi für die Ampel mit nur einer Taste! Mit jedem Tastendruck wechselt der Modus: Normaler Zyklus (nacheinander rot → gelb → grün), Nur Rot (Haltebefehl), Gelb blinkend (Achtung/Nachtmodus), Aus (Wartung). Lerninhalte: Zustandsmaschine (die Variable mode bestimmt, welches Verhalten ausgeführt wird), Modulo-Modus-Zyklus ((mode + 1) % 4 → 0→1→2→3→0 – endloser Zyklus), non-blocking timing (die LED-Phasen werden mit time.ticks_ms() + time.ticks_diff(

5.0(1)
15
Raspberry Pi Pico Taster Debounce: IRQ vs Software Polling
#159Mittel
Premium

Raspberry Pi Pico Taster Debounce: IRQ vs Software Polling

Einmal Taster gedrückt, Code zählt 3-4? Das ist Contact Bounce! Vergleiche 2 Zählmethoden in Serial: RAW Polling (fängt Bounce, zählt falsch) vs IRQ + Software Debounce (genau). Lerne Contact Bounce Physik, Software Debounce, Pin.irq() Interrupt, IRQ_FALLING Trigger, ISR Handler, global Variablen ISR-Sicherheit.

0.0(0)
12
Raspberry Pi Pico PWM LED Fade (Atem-Effekt)
#160Anfänger

Raspberry Pi Pico PWM LED Fade (Atem-Effekt)

Die LED blinkt nicht mehr nur — sie atmet! Mit der PWM (Pulsweitenmodulation) des Raspberry Pi Pico steigt die Helligkeit langsam an und fällt wieder ab. Lerne die machine.PWM-Klasse, duty_u16() (16-Bit-Helligkeit 0–65535), PWM-Frequenz, range()-Schleifen und analogähnliche Ausgabe. Grundlage für RGB-Farbmischung, Motorsteuerung, Servos und Buzzer.

0.0(0)
4