Raspberry Pi Pico: PIO e dual-core com _thread, setup1 e WS2812B
Guia de PIO no Raspberry Pi Pico: máquinas de estados, onda quadrada e exemplo com WS2812B, dois núcleos com _thread no MicroPython e setup1/loop1 no Arduino, e mudanças no Pico 2.
O bloco PIO do Raspberry Pi Pico e seus dois núcleos são os dois recursos que diferenciam essa pequena placa da maioria dos microcontroladores na mesma faixa de preço. O chip RP2040, no coração do Pico, tem dois núcleos de processamento separados e 8 máquinas de estados PIO. Graças aos núcleos, você pode ler sensores de um lado enquanto um display ou uma animação de LEDs continua funcionando sem travar do outro. Já o PIO é um conjunto de pequenos mecanismos de temporização que funcionam independentemente do processador: eles produzem o sinal com precisão de nanossegundos de que os LEDs WS2812B precisam, uma UART extra ou uma onda quadrada sem sobrecarregar a CPU.
Neste guia, você primeiro vai executar os dois núcleos com o módulo _thread no MicroPython e depois com setup1() e loop1() na Arduino IDE. Em seguida, vai aprender como o PIO funciona, quantas máquinas de estados existem e quais instruções elas entendem, e escrever dois programas reais: um gerador de onda quadrada que toca notas em um buzzer e um arco-íris com WS2812B. As últimas seções mostram o que muda no Pico 2 (RP2350) e quando você realmente precisa desses recursos. Se você está começando com o Pico, recomendo ler primeiro O que é Raspberry Pi Pico? e O que é MicroPython?.

O que são os dois núcleos e o PIO do Raspberry Pi Pico?
O RP2040 tem dois processadores Cortex-M0+ idênticos, chamados núcleo 0 e núcleo 1. Quando seu programa inicia, apenas o núcleo 0 funciona; o núcleo 1 fica em repouso até você iniciá-lo. Ambos compartilham os mesmos 264 KB de RAM e os mesmos pinos, então transferir dados entre eles é fácil, mas eles não devem escrever na mesma variável ao mesmo tempo. Para isso, o chip tem uma pequena fila bidirecional em hardware (FIFO, 8 palavras em cada direção) e 32 travas de hardware (spinlocks). O PIO é um mundo completamente separado: cada um dos dois blocos PIO tem 4 máquinas de estados, uma memória de programa compartilhada de 32 instruções e acesso direto aos pinos. Depois de iniciada, uma máquina de estados executa seu próprio programa ciclo a ciclo, mesmo enquanto o processador está ocupado com outra tarefa.
| Recurso | RP2040 (Pico, Pico W) | Para que serve? |
|---|---|---|
| Núcleo de processamento | 2 x Cortex-M0+, 133 MHz (até 200 MHz nos documentos atuais) | Executar dois programas separados realmente ao mesmo tempo |
| FIFO entre núcleos | 8 x 32 bits em cada direção | Enviar números e comandos entre os núcleos |
| Trava de hardware (spinlock) | 32 | Acessar dados compartilhados alternadamente |
| Bloco PIO | 2 (PIO0, PIO1) | Tirar do processador as tarefas dos pinos que exigem temporização precisa |
| Máquina de estados | 4 por bloco, 8 no total | Cada uma executa seu próprio programa PIO |
| Memória de programa PIO | 32 instruções por bloco | Compartilhada pelas 4 máquinas de estados desse bloco |
| FIFO do PIO | TX 4 + RX 4 palavras por máquina (8 quando unidas) | Dados entre o processador e uma máquina de estados |
O segundo núcleo no MicroPython: o módulo _thread
No MicroPython, a forma de usar o núcleo 1 é a chamada _thread.start_new_thread(function, args). No Pico, ela inicia a função no segundo núcleo, enquanto seu programa principal continua no núcleo 0. Apenas uma thread extra pode funcionar por vez, porque não existe um terceiro núcleo. No exemplo abaixo, o núcleo 0 lê um potenciômetro no GP26 e imprime o resultado, enquanto o núcleo 1 pisca o LED integrado na velocidade definida pelo potenciômetro. A espera de sleep_ms() no núcleo 1 não afeta em nada o núcleo 0; em um único núcleo, você precisaria de um temporizador ou de asyncio para isso.
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)- A trava criada com allocate_lock() garante que, dentro de um bloco with lock:, apenas um núcleo acesse a variável compartilhada.
- A flag running avisa ao núcleo 1 para sair do laço quando você interrompe o programa com Ctrl+C; caso contrário, o LED continua piscando.
- Escrever Pin("LED") localiza o LED integrado tanto no Pico quanto no Pico W; no Pico W, o LED está ligado ao chip sem fio, então Pin(25) não funciona.
- Uma boa divisão é deixar cálculos demorados, desenho no display ou temporização precisa no núcleo 1, e Wi-Fi, menus e interação com o usuário no núcleo 0.
Dois núcleos na Arduino IDE: setup1() e loop1()
O pacote do Pico mais usado na Arduino IDE é o core Raspberry Pi Pico/RP2040/RP2350, de Earle Philhower (arduino-pico). Usar os dois núcleos com ele é surpreendentemente fácil: as conhecidas funções setup() e loop() executam no núcleo 0; se você adicionar setup1() e loop1() ao sketch, o núcleo 1 inicia automaticamente e executa essas duas funções. Os dados são enviados entre os núcleos com o objeto rp2040.fifo. O pacote oficial “Arduino Mbed OS RP2040” do Arduino não oferece suporte a setup1(), então escolha o pacote correto no Gerenciador de Placas.
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}| Função | O que faz |
|---|---|
| rp2040.fifo.push(x) | Envia um valor de 32 bits ao outro núcleo; espera por espaço se a fila estiver cheia |
| rp2040.fifo.push_nb(x) | Tenta enviar sem esperar; retorna false se a fila estiver cheia |
| rp2040.fifo.pop() | Lê um valor do outro núcleo; espera se a fila estiver vazia |
| rp2040.fifo.pop_nb(&x) | Escreve um valor em x e retorna true se houver um disponível; caso contrário, retorna false imediatamente |
| rp2040.fifo.available() | Retorna quantos valores estão esperando para serem lidos |
| rp2040.idleOtherCore() / resumeOtherCore() | Pausa brevemente e retoma o outro núcleo (por exemplo, ao escrever na memória flash) |
O que é PIO? Como funciona a entrada/saída programável
Na maioria dos microcontroladores, os blocos de comunicação e sinal, como UART, SPI, I2C e PWM, são fixos no silício; se você precisa de um protocolo que não está na lista, o processador cuida dele ligando e desligando os pinos um a um (bit-banging). Isso mantém o processador ocupado, e a temporização falha sempre que uma interrupção interfere. O PIO (entrada/saída programável) resolve isso na raiz: cada máquina de estados é um pequeno processador com nove instruções projetadas apenas para trabalhar com pinos. Cada instrução executa em exatamente um ciclo de clock, e é possível adicionar um atraso de 0 a 31 ciclos ao final dela. Assim, basta contar os ciclos para saber exatamente quantos nanossegundos cada borda de um sinal leva. A velocidade da máquina de estados é definida dividindo o clock do sistema por um divisor entre 1 e 65.536.
| Instrução | Finalidade |
|---|---|
| set(pins, v) | Escreve uma constante de 0–31 nos pinos ou nos registradores X/Y |
| out(dest, n) | Move n bits do registrador de deslocamento de saída (OSR) para os pinos ou X/Y |
| in_(src, n) | Desloca n bits dos pinos ou registradores para o registrador de deslocamento de entrada (ISR) |
| pull() / push() | Retira uma palavra da FIFO TX para o OSR e envia a palavra do ISR para a FIFO RX |
| jmp(cond, label) (instrução de salto condicional) | Salta conforme uma condição (X igual a zero, pino em nível alto, X-- e assim por diante) |
| wait(polarity, src, idx) (instrução de espera) | Espera até que um pino ou uma flag IRQ atinja o nível desejado |
| mov(dest, src) (instrução de cópia entre registradores) | Copia entre registradores, com a opção de inverter os bits |
| irq(idx) | Envia uma flag de interrupção à CPU ou a outra máquina de estados |
| nop() e .side(v) | Instrução vazia; side-set altera um pino no mesmo ciclo de qualquer instrução |
No MicroPython, programas PIO são funções Python escritas com o decorador @rp2.asm_pio; a função não é chamada, o MicroPython a monta em código de máquina. Depois, você a carrega em uma máquina de estados com rp2.StateMachine(id, program, freq=..., set_base=...). No Pico, as máquinas de número 0–3 pertencem ao PIO0, e as de 4–7 ao PIO1. O valor de freq é o número de ciclos de instrução por segundo e não pode ser menor que 1/65.536 do clock do sistema; a 125 MHz, isso equivale a cerca de 1,9 kHz, e a 150 MHz, cerca de 2,3 kHz. Se você precisa de um sinal mais lento, use atrasos ou laços com os contadores X/Y.
Onda quadrada com PIO: seu primeiro programa de máquina de estados
No primeiro exemplo, vamos tocar uma escala em um buzzer passivo conectado ao GP15 e depois deixar uma onda quadrada contínua de 1 kHz funcionando. O programa tem apenas duas instruções: colocar o pino em HIGH e esperar 9 ciclos, colocar o pino em LOW e esperar 9 ciclos. Como cada instrução leva 1 ciclo, um período tem 20 ciclos, então basta fornecer à máquina de estados 20 vezes a frequência do tom desejado. Conecte o terminal positivo do buzzer ao GP15 e o negativo ao GND. No lugar do buzzer, você também pode usar um osciloscópio ou um LED com um resistor de 220 ohms; escolha o resistor com a calculadora de resistor para LED.
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")A fórmula aqui é simples: frequência do tom = frequência da máquina de estados / número de ciclos. Para 1.000 Hz, a máquina funciona a 20.000 Hz, bem acima do limite mínimo. Se você remover os atrasos e mantiver apenas as duas instruções set(), um período cai para 2 ciclos; executar a máquina a 125 MHz gera então uma onda quadrada de 62,5 MHz no pino. Lembre que o PWM de hardware pode fazer o mesmo trabalho: para um tom simples ou o brilho de um LED, PWM é suficiente. O diferencial do PIO é que você decide a forma exata do sinal; com poucas linhas, pode gerar pulsos de largura variável, uma quantidade precisa de pulsos ou saídas que reagem a uma entrada.
Controlando LEDs WS2812B (NeoPixel) com PIO

Os LEDs WS2812B esperam um pulso de cerca de 1,25 microssegundos por bit; o tempo que o pulso permanece em HIGH determina se o bit é 1 ou 0. É um caso clássico para o PIO. O programa abaixo se baseia no exemplo oficial de MicroPython da Raspberry Pi: a máquina de estados funciona a 8 MHz e cada bit leva exatamente 10 ciclos, então são enviados 800.000 bits por segundo. Graças ao autopull, a máquina retira uma nova cor da FIFO a cada 24 bits; o processador apenas coloca o array na FIFO com sm.put(). Ajuste a quantidade de LEDs à sua fita; para entender o funcionamento do WS2812B e sua ordem de cores, veja o guia de WS2812B NeoPixel.
| Pino do WS2812B | Pino do Pico | Observação |
|---|---|---|
| DIN (entrada de dados) | GP16 (pino físico 21) | Um resistor de 330 ohms em série protege o sinal |
| 5V / VCC | VBUS (pino 40) | 5 V do USB; use uma fonte externa de 5 V para muitos LEDs |
| GND | GND (por exemplo, pino 38) | O GND da fonte externa também deve ser conectado aqui |
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 timeVamos acompanhar o programa linha por linha. out(x, 1) retira um bit do OSR e o coloca no registrador X enquanto side-set mantém a linha em LOW (3 ciclos). Depois, a linha vai para HIGH e X é verificado (2 ciclos). Se o bit for 1, a linha permanece em HIGH por mais 5 ciclos; se for 0, a linha é levada a LOW e a máquina espera 5 ciclos. Ambos os caminhos somam 10 ciclos, ou seja, 1,25 µs. pull_thresh=24 informa à máquina que deve usar apenas 24 bits de cada palavra, e por isso a cor é deslocada para a esquerda no lado do Python (sm.put(pixels, 8)). A ordem das cores é GRB, não RGB; se vermelho e verde estiverem trocados, esse é o motivo. Como 24 LEDs em branco com brilho máximo podem consumir até 1,4 A, o brilho é limitado a 20% no exemplo.
O que mudou com o Pico 2 (RP2350)?
O Raspberry Pi Pico 2 é a nova geração, com o mesmo tamanho e a mesma pinagem, mas com um chip RP2350 dentro. Ele continua com dois núcleos, mas desta vez você pode escolher na inicialização entre dois núcleos Arm Cortex-M33 ou dois núcleos Hazard3 RISC-V. Todo o código deste artigo funciona sem alterações no Pico 2: _thread é igual no MicroPython e, no core Arduino-Pico, setup1()/loop1() e rp2040.fifo mantêm os mesmos nomes. No PIO, foi adicionado um terceiro bloco, totalizando 12 máquinas de estados (0–11 no MicroPython), além de algumas novas opções de instruções.
| Característica | Pico (RP2040) | Pico 2 (RP2350) |
|---|---|---|
| Núcleos | 2 x Cortex-M0+ | 2 x Cortex-M33 ou 2 x Hazard3 RISC-V |
| Frequência de clock | 133 MHz | 150 MHz |
| RAM | 264 KB | 520 KB |
| Memória flash integrada | 2 MB | 4 MB |
| PIO | 2 blocos, 8 máquinas de estados | 3 blocos, 12 máquinas de estados |
| Ponto flutuante | Em software (rotinas rápidas na ROM) | FPU de hardware (precisão simples) + coprocessador de precisão dupla |
| Segurança | Nenhuma | TrustZone, inicialização segura, 8 KB de OTP |
| Arquivo do MicroPython | RPI_PICO (.uf2) | RPI_PICO2 (.uf2) |
Na prática, a diferença mais perceptível do Pico 2 é a velocidade: graças à FPU de hardware, tarefas com muitos cálculos em ponto flutuante (filtros, fusão de sensores, processamento de áudio) executam várias vezes mais rápido, e o dobro de RAM deixa espaço para grandes buffers de display. O cuidado principal é gravar o arquivo UF2 correto para a placa; o arquivo do Pico não funciona no Pico 2. As primeiras versões do RP2350 tinham um problema conhecido de hardware (E9) nas entradas com pull-down interno, corrigido na revisão A4; usar um resistor externo ao conectar botões é a opção segura em qualquer caso.
Quando você precisa de dois núcleos e quando precisa de PIO?
| O que você precisa | Melhor opção | Por quê? |
|---|---|---|
| Brilho de LED, servo, tom simples | PWM de hardware | Bloco pronto, uma linha de código |
| Alguns sensores + display + botão | Um núcleo, millis() ou asyncio | Sem necessidade de complexidade extra |
| Animação fluida durante cálculos demorados | Dois núcleos | O cálculo no núcleo 1 não trava o display |
| Medição contínua junto com Wi-Fi | Dois núcleos | Os atrasos da rede não interferem no intervalo de amostragem |
| WS2812B, UART extra, transmissor IR, encoder | PIO | Precisão de nanossegundos, CPU livre |
| Vídeo VGA/DVI, áudio I2S, sinais muito rápidos | PIO + DMA | Taxas de dados que a CPU não conseguiria acompanhar |
Resumindo: pense no segundo núcleo quando as tarefas entram em conflito no software, e no PIO quando os pinos precisam de precisão inferior a um microssegundo. A maioria dos projetos de hobby não precisa de nenhum dos dois; mas, se um dia sua animação WS2812B começar a engasgar durante uma requisição Wi-Fi, ou faltarem UARTs na placa, a solução já está dentro do Pico.
Ideias de projetos com PIO e dois núcleos no Pico
- Anel de LEDs que reage à música: o núcleo 1 processa amostras do microfone, o PIO controla o anel WS2812B e o núcleo 0 monitora os botões.
- Gerador de pulsos de oito canais: cada máquina de estados gera uma onda quadrada em uma frequência diferente para alimentar drivers de motores de passo ou bancadas de teste.
- Datalogger sem lacunas: o núcleo 1 lê o ADC a cada 10 ms enquanto o núcleo 0 envia os dados por Wi-Fi; uma rede lenta nunca faz você perder uma amostra.
- Portas seriais extras: abra uma terceira e uma quarta UART com PIO e conecte um GPS e um módulo Bluetooth ao mesmo tempo.
- Contador de encoder rotativo: o PIO conta os pulsos do encoder sem perder nenhum; o processador apenas lê o resultado.
- Luz noturna com efeito de respiração: deixe as transições suaves de PWM com o núcleo 1 e o sensor de luz com o núcleo 0.
Erros comuns e como corrigi-los
| Sintoma | Causa | Solução |
|---|---|---|
| A placa não responde após interromper o programa | O laço no núcleo 1 continua executando | Use uma flag de parada; desconecte e reconecte o USB se necessário |
| start_new_thread falha na segunda vez | O Pico permite apenas uma thread extra | Não inicie uma nova antes de a anterior terminar |
| As variáveis às vezes recebem valores sem sentido | Os dois núcleos escrevem nos dados compartilhados sem uma trava | Use allocate_lock() ou a FIFO |
| StateMachine gera ValueError | freq está abaixo de clock do sistema / 65536 | Aumente a frequência e reduza a velocidade com atrasos |
| PIOASMError: delay too large (mensagem de erro: atraso grande demais) | Os bits de side-set reduziram o campo de atraso | Divida o atraso ou adicione um nop() |
| Vermelho e verde trocados no WS2812B | A ordem das cores é GRB | Use o formato (g << 16) | (r << 8) | b |
| setup1() nunca executa | O pacote Arduino Mbed RP2040 está selecionado | Instale o pacote Raspberry Pi Pico/RP2040 de Earle Philhower |
Dois núcleos e PIO transformam o Pico de um simples pisca-pisca de LED em um sistema embarcado robusto, mas tudo parte da mesma base: conhecer bem os pinos, a temporização e os LEDs. No app BlueGrays, você encontra projetos com Raspberry Pi Pico, como LED piscante, sequencial de LEDs, efeito Super Máquina (Knight Rider), máquina de estados controlada por botão e efeito de respiração com PWM, cada um com esquema do circuito e código MicroPython, passo a passo, prontos para você adicionar as técnicas deste artigo.
Perguntas frequentes
O que é PIO no Raspberry Pi Pico?
PIO (entrada/saída programável) é um conjunto de pequenas máquinas de estados nos chips RP2040 e RP2350 que funcionam independentemente do processador. Cada uma executa um programa escrito em uma linguagem simples de nove instruções, com temporização precisa a cada ciclo. Ele cuida de tarefas que exigem temporização precisa, como LEDs WS2812B, UARTs extras, transmissão IR ou leitura de encoder, sem manter a CPU ocupada.
Quantos núcleos o Raspberry Pi Pico tem?
O chip RP2040 do Pico e do Pico W tem dois núcleos Cortex-M0+. O RP2350 do Pico 2 também tem dois núcleos, e você pode escolher na inicialização entre núcleos Cortex-M33 e Hazard3 RISC-V. Quando seu programa inicia, apenas o núcleo 0 funciona; você inicia o núcleo 1 por conta própria.
Quantas máquinas de estados PIO o Pico tem?
O RP2040 tem dois blocos PIO com 4 máquinas de estados cada, totalizando 8 máquinas de estados. A memória de programa de 32 instruções de cada bloco é compartilhada pelas máquinas desse bloco. O RP2350 do Pico 2 tem três blocos PIO, ou seja, 12 máquinas de estados.
O MicroPython pode usar os dois núcleos do Pico?
Sim. No Pico, uma função iniciada com _thread.start_new_thread() executa no segundo núcleo. Apenas uma thread extra pode ficar aberta por vez, e os dados compartilhados devem ser protegidos por uma trava criada com _thread.allocate_lock(). O suporte a múltiplos núcleos ainda é experimental no MicroPython, então é melhor evitar tarefas pesadas de memória na thread extra.
Como usar o segundo núcleo do Pico na Arduino IDE?
Depois de instalar o pacote Raspberry Pi Pico/RP2040/RP2350 de Earle Philhower, basta adicionar as funções setup1() e loop1() ao sketch; o núcleo 1 as executa automaticamente. Valores de 32 bits são transferidos entre os núcleos com rp2040.fifo.push() e rp2040.fifo.pop(). O pacote RP2040 do Arduino baseado em Mbed não tem esse recurso.
Preciso usar PIO para LEDs WS2812B?
Não. Tanto o módulo neopixel integrado ao MicroPython quanto a biblioteca Adafruit NeoPixel no Arduino funcionam bem no Pico. A vantagem de escrever sua própria versão com PIO é que o processador fica livre durante a transmissão e você pode aplicar a mesma técnica a outros protocolos que exigem temporização precisa.
Projetos para montar depois desta leitura
Ver todos os projetos
Piscar o LED integrado do Raspberry Pi Pico (Pico e Pico W)
O primeiro projeto da série Raspberry Pi Pico! Fazemos o LED verde integrado piscar para verificar se a placa funciona — um primeiro experimento no estilo clássico "Hello World". SEM componentes externos, apenas o Pico e um cabo USB. O código foi escrito em MicroPython (a linguagem com suporte oficial da Raspberry Pi Foundation). Aprenda a usar a classe machine.Pin, o modo Pin.OUT, os métodos led.on()/off() e time.sleep() no Thonny IDE.

Raspberry Pi Pico: controle de LED externo (protoboard)
O próximo passo após o LED integrado do Pico: conectar um LED externo à protoboard e controlá-lo pelo pino GP14. Neste projeto, você aprende a usar qualquer pino GPIO de uso geral do Pico como saída, a polaridade do LED (terminal longo = ânodo/+, terminal curto = cátodo/–) e por que um resistor limitador de corrente (220Ω) é necessário. Sem o resistor, uma corrente excessiva passa pelo LED e pode queimá-lo. O circuito é muito simples: Pico GP14 → resistor de 220Ω → LE

Raspberry Pi Pico: semáforo (3 LEDs em sequência)
Simulamos um semáforo real com LEDs vermelho, amarelo e verde — o primeiro projeto com 3 LEDs da série Pico! Verde por 4 segundos: "siga"; amarelo por 1,5 segundo: "prepare-se"; vermelho por 3 segundos: "pare"; e vermelho+amarelo por 1 segundo: "saída" (padrão de semáforo europeu). Aprenda definição de funções (def all_off()), lógica de máquina de estados (sequência) e sincronização de vários GPIOs.

Raspberry Pi Pico: LEDs sequenciais (6 LEDs)
A clássica animação de LEDs sequenciais com o Pico — versão com 6 LEDs! Os 6 LEDs acendem em sequência da esquerda para a direita, como se a luz percorresse a fileira. Aprenda listas em Python, compreensão de listas ([Pin(p, Pin.OUT) for p in LED_PINS]), controle de pinos com laço for e enumerate(). São 6 LEDs nos pinos GP9-GP14, cada um com um resistor limitador de corrente de 220Ω.

Raspberry Pi Pico: efeito Knight Rider com LEDs (6 LEDs em vaivém)
Efeito clássico de LEDs do "Knight Rider" com o Pico! 6 LEDs acendem da esquerda para a direita e depois no sentido contrário, sem parar. Como a grade dianteira do carro KITT da famosa série dos anos 80. Este projeto é uma evolução do projeto LEDs em sequência: o mesmo circuito com 6 LEDs (GP9-GP14), com outro padrão de código. Aprenda a inverter listas com reversed(), usar dois laços for separados para o vaivém e criar várias animações no mesmo circuito.

Raspberry Pi Pico: semáforo com 4 modos selecionados por botão (máquina de estados)
4 modos de semáforo com apenas 1 botão! O modo muda a cada acionamento: Ciclo normal (vermelho → amarelo → verde em sequência), Só vermelho (sinal de parada), Amarelo piscante (atenção/modo noturno), Desligado (manutenção). Conceitos: máquina de estados (a variável mode determina qual comportamento executar), alternância cíclica de modos com módulo ((mode + 1) % 4 → ciclo infinito 0→1→2→3→0), temporização sem bloqueio (as fases dos LEDs são temporizadas…

Raspberry Pi Pico: debounce de botão com IRQ ou consulta por software
Você pressiona o botão uma vez e o código conta 3-4? Isso é oscilação dos contatos — os contatos metálicos oscilam por microssegundos! Compare 2 métodos de contagem lado a lado no Monitor Serial: consulta sem filtro (detecta as oscilações e conta a mais) e IRQ + debounce por software (contagem correta). Aprenda a física da oscilação dos contatos, debounce por software (ticks_diff() > 50ms), registro de interrupção com Pin.irq(), disparo IRQ_FALLING, rotinas ISR, global e…

Raspberry Pi Pico: variação de brilho do LED com PWM (efeito de respiração)
O LED não só pisca — ele respira! Com o PWM (modulação por largura de pulso) do Raspberry Pi Pico, o brilho do LED aumenta e diminui lentamente, como a luz de um MacBook em repouso. Aprenda a usar a classe machine.PWM, duty_u16() (brilho de 16 bits, de 0–65535), frequência PWM (freq(1000) — 1.000 ciclos de ligar/desligar por segundo, sem cintilação visível), laços com passos usando range() (crescentes e decrescentes) e saída semelhante à analógica em um pino digital.
Mais artigos
App BlueGrays
Monte este circuito passo a passo pelo celular
Esquema do circuito, código e lista de componentes em uma só tela. Mais de 200 projetos com Arduino, ESP32 e Pico prontos para montar.
Escaneie com seu celular
Aponte a câmera para o código para abrir a loja de aplicativos do seu celular.
ou abrir a loja

