O Raspberry Pi Pico desde o lançamento vem sendo muito desejado por muitos projetistas, mas será que realmente vale a pena aprender? Neste post você vai aprender tudo sobre ele.
1 Surgimento do Raspberry Pi Pico
Quem acompanha a empresa Raspberry Pi, sabe que todos seus lançamentos tem um preço base para um determinado produto e o propósito disso é democratizar ao máximo o acesso aos produtos da empresa.
Até então, o produto mais barato da empresa era o Raspberry Pi Zero que custava em torno dos $15, com um hardware bem primário não servia para utilizar como um computador desktop, porém era o mais próximo de um computador e um microcontrolador.

Porém pagar mais de $15 em um Raspberry para usar apenas as GPIO’s é completamente inviável, ainda mais com os preços atuais.

Então em 2021 a Rasp lançou o seu produto mais barato, o Pico, com apenas $4 teria o mais próximo das GPIO’s dos minicomputadores porém em um microcontrolador Cortex M0+.
2 O que é Cortex M0+?
Em algum momento em sua vida você já deve ter escutado sobre a tecnologia ARM, seja em celulares, computadores como o novo Macbook que utiliza um processador com arquitetura ARM ou em microcontroladores.

ARM na verdade é uma empresa holding que foi fundada em 1990 como uma join-venture (empresa conjunta por outras empresas) entre a Acorn Computers, Apple Computer e VLSI Technology (como Advanced RISC Machines).
A tecnologia ARM criou um ecossistema em que mais de 52 empresas utilizam essa arquitetura em seus produtos, por exemplo a Broadcorn que fabrica microprocessador que é utilizado no Raspberry Pi e que tem tecnologia ARM.
2.3 Classificação ARM
Segundo uma publicação do site Newnton C Braga existem três classificações para os microcontroladores ARM, sendo eles:
- Cortex-M (microcontroller) – Podem ser usados em aplicações típicas de microcontroladores como geladeiras, lavadoras, controles remotos, etc.
- Cortex-R (Real Time) – Podem ser usados em reprodutores MP3, controles de motores, robóticas, etc;
- Cortex-A (Application) – Podem ser usados em equipamentos que exigem sistemas operacionais como celulares, tablets, computadores, etc.
2.4 Gerações do ARM Cortex M
Assim como a AMD e Intel, os ARM também são divididos por gerações e no caso do Cortex M0+ significa que pertence à primeira geração, esta imagem a seguir que é presente nos datasheets da ARM ajuda a entender as diferenças.
De cara já dá para perceber que o Pico utiliza na verdade uma tecnologia “antiga”, mas se pegar documentação da Raspberry, estudar e praticar você terá maiores facilidades para entender outros microcontroladores como o STM32 por exemplo.
STM são os microcontroladores mais usados em produtos, se você pegar um hoverboard vai ter um STM32, eletrônica automotiva é certo ter também, mas aprender STM32 logo de cara pode ser uma tarefa desanimadora se você gosta de ter logo o resultado.
A comunidade da STM não é a mesma de um Arduino ou a do Raspberry Pi Pico e além disso, as documentações são bem mais técnicas e não muito amigáveis. Por isso, iniciar com o Pico vai te possibilitar a ter uma curva de aprendizado mais rápida com a arquitetura ARM.
3 Raspberry Pi Pico: Especificações
O microcontrolador RP2040 é dual-core Arm Cotex-M0+ e tem uma RAM interna de 264kB com suporte até 16MB de memória flash externa, porém na placa Rasp Pico, já conta com uma memória flash de 2MB.

Além de tudo isso, o clock o Pico pode chegar até 133MHz, isso é 8.31 vezes mais poderoso que um Arduino UNO com cristal de 16MHz, mas nem tudo trabalha com essa frequência.
3.1 Clock
O RP2040 tem que ter uma entrada de clock de 6 a 12MHz, na placa Pico já vem com um cristal de quartzo de 12MHz.

Por mais que o clock de entrada seja de 6 a 12MHz, o clock de processamento pode chegar até 133MHz graças a uma técnica conhecida como PLL.

Porém o 133MHz na verdade é válido apenas para processamento, os demais apresentam limites de clock diferentes, veja só.

3.2 Pinout
Além disso, o RP2040 possui duas 2x UART, 2x I2C, 2x SPI e 30x GPIO’s sendo 3x ADC e todos com suporte a PWM. Isso fica nítido ao visualizar o pinout.

Perceba que mais de um GPIO possui o mesmo suporte a um mesmo barramento de comunicação, isso significa que você pode optar pelo GPIO que você pretende usar para determinada função da comunicação.
Isso é muito bom, pois flexibiliza o desenvolvimento dos circuitos, diferentemente de microcontroladores como o ESP32 e o Atmega328p que tem barramento fixo.
Uma coisa muito importante que você deve se atentar é em relação a tensão, pois no RP2040 a tensão é de 1v8 a 3v3, porém é fixa em 3v3 no Pico.

3.3 Alimentação
Diferentemente de outras placas embarcadas o Pico não usa um regulador de tensão e sim um conversor DC-DC buck boster.
O conversor foi escolhido pela equipe da Raspberry para que viabilizasse aplicações com bateria, o conversor presente na placa é o RT6150 e o diagrama da alimentação é este:
3.3.1 Mas o que é um Buck Boster?
Basicamente um Buck Boster é como se fosse um Step up e Step down combinados, de modo que se a tensão for menor que a desejada, ele eleva e se for acima ele reduz.
Este tipo de conversor acaba sendo muito bom para aplicações que utilizam bateria, pois a tensão mínima de entrada é de 1v8 e a máxima é de 5v5, no caso do RT6150.
O bom é que este CI é bem simples de usar e você pode por em seus projetos com outros microcontroladores seguindo o mesmo esquemático abaixo:

3.3.1.1 Observações
Embora o Pico tenha sido pensado para utilizar bateria como alimentação, ele não possui nenhum sistema de proteção de carga, sobrecarga, sobretensão ou proteção contra descarga excessiva.
3.3.2 Raspberry Pi Pico com Bateria Li-ion
Por mais que o Rasp Pico utilize um conversor DC-DC para viabilizar o uso de bateria, é necessário ainda assim, implementar um circuito que resolva todos os problemas da observação acima.
Considerando que sua aplicação com bateria seja algo simples, dá para usar um TP4056 – Protect, ele tem todas as características de segurança que precisamos.
Para montar o circuito, vamos analisar novamente o circuito de alimentação, se você observar bem, vai notar que há dois pinos de VCC “Vbus” e “Vsys”.
O Vbus antecede um diodo de proteção, porém se ligarmos a bateria 18650 nele, haverá uma queda de tensão desnecessária, então temos que por em Vsys, dessa forma:

4 Primeiros passos
Para que possamos usar o Pico, é necessário prepara e configurar todo nosso ambiente de trabalho. Primeiramente vamos configurar a IDE.
4.1 Instalando e configurando Thonny IDE
A IDE que é utilizada para o Pico é a Thonny pois nesse post só será abordado a programação em Micropython, você até pode programar em C, mas tem tanto material em Micropython para esta placa que talvez nem seja vantajoso manter em C.
Para baixar a IDE, basta clicar aqui, selecionar teu sistema operacional qual e em seguida basta seguir o padrão de qualquer instalação de programa no computador.

Agora, só precisamos configurar a IDE para programar para o Pico, para isso basta por o mouse no menu “Tools” e clicar em “Options”. Em seguida clique em “Interpreter” e escolha o seguinte interpretador:

4.2 Configurar o Pico para uso.
Antes de começarmos a usar o Pico na IDE, é necessário fazer uma pequena configuração na placa. Note que há um botão na placa, você deve manter pressionado e inserir o cabo USB, da seguinte forma:

Após feito a etapa anterior, o computador vai reconhecer como se fosse um “pendrive” e irá abrir o diretório com alguns arquivos. Você deve baixar o arquivo UF2 e colar no diretório aberto do Pico.

Pronto, agora a única configuração a ser feita é configurar a IDE para identificar a porta USB em que o Pico está conectado, para isso basta ir em “Tools” -> “Options” -> “Interpreter” e selecionar a opção “Try detect port automatically” ou selecione manualmente.

4.3 Olá mundo
Após ter feito todas as configurações podemos fazer nosso primeiro “Olá mundo”, neste exemplo vamos apenas imprimir a mensagem “Olá mundo”. Ao decorrer desta postagem, você aprenderá outras funcionalidades.
Se você não desconectou o Pico após ter adicionado o arquivo .UF2, desconecte e conecte novamente para o Rasp sair do modo boot. Em seguida, digite o seguinte código.
Esse pequeno código será o suficiente para fazer o primeiro teste com o Pico. Para executar o código basta clicar no botão de “play” no canto superior esquerdo do Thonny.

Após fazer isso, pode aparecer esse pequeno pop up para selecionar onde o código vai ficar salvo, você pode escolher qualquer uma das opções. Prefira salvar no rasp e faça uma cópia no computador.
Caso você queira que um determinado código fique executando mesmo com o Pico desconectado, basta renomear o código para “main.py”.

Salvar o arquivo não é algo que você precisa fazer em qualquer teste de código, é possível rodar o programa sem salvar.
4.3.1 Código do “Olá Mundo!”
Como o objetivo é apenas demonstrar o funcionamento, o código neste exemplo é apenas uma linha de código e extremamente simples.
print("Olá Mundo!")
4.3.2 Teste prático do Olá mundo
Quando utiliza o comando “print”, os valores são impressos no canto inferior da tela do Thonny IDE, veja só:

5 Como instalar bibliotecas no Thonny IDE
Quem já usa o Arduino IDE sabe o quão fácil é instalar bibliotecas e no Thonny também é bem fácil, talvez até um pouco mais fácil.
Neste tópico você vai aprender como instalar qualquer biblioteca através de dois métodos. Para exemplificar, vamos instalar a biblioteca do display OLED e também do módulo RFID, ambas as bibliotecas serão usadas respectivamente nos exemplos de comunicação I2C e SPI.
5.1 Primeiro método
No primeiro método, toda instalação é feita pela própria IDE, neste caso vamos instalar a biblioteca SSD1306 para o display OLED 0.92”.
Para começar a instalação, clique no botão “tools” na área de menu no canto superior esquerdo, em seguida clique em “Manager Packages”.
Ah, para fazer isso o pico não pode estar executando nenhum código durante o processo, caso contrário ocorrerá um erro.
Após ter feito a tarefa anterior, será exibido uma janela de instalação de bibliotecas, pesquise por SSD1306 e clique em “Search on PyPI”.
A biblioteca em questão é a “Micropython-ssd1306”, clique em instalar, após a instalação a biblioteca vai aparecer na lista da esquerda aonde tem “<INSTALL>”.

Quando toda instalação terminar, perceba que será criado uma pasta “lib” no Pico contendo os arquivos em Python que são as bibliotecas.

Fiz um pequeno teste com esse “lib” e notei que o código da biblioteca pode ficar fora dessa pasta que vai funcionar, porém dentro fica mais organizado, concorda?
5.2 Segundo método
Ao fazer a instalação da biblioteca pelo método acima, é possível entender como podemos fazer a instalação de forma manual.
Neste segundo método, vamos instalar a biblioteca do MFRC522 de forma manual. Talvez você possa estar se perguntando sobre a necessidade de aprender esse outro método e a resposta é bem simples, nem tudo está disponível pelo o outro método, esse do MFRC522 não está.
Para começarmos, vamos primeiramente abrir um novo arquivo, para isso basta clicar no papel do canto superior esquerdo.

Pronto, basta você copiar todo o código a seguir e colar dentro desse novo arquivo que acabamos de criar.
from machine import Pin, SPI
from os import uname
class MFRC522:
DEBUG = False
OK = 0
NOTAGERR = 1
ERR = 2
REQIDL = 0x26
REQALL = 0x52
AUTHENT1A = 0x60
AUTHENT1B = 0x61
PICC_ANTICOLL1 = 0x93
PICC_ANTICOLL2 = 0x95
PICC_ANTICOLL3 = 0x97
def __init__(self, sck, mosi, miso, rst, cs,baudrate=1000000,spi_id=0):
self.sck = Pin(sck, Pin.OUT)
self.mosi = Pin(mosi, Pin.OUT)
self.miso = Pin(miso)
self.rst = Pin(rst, Pin.OUT)
self.cs = Pin(cs, Pin.OUT)
self.rst.value(0)
self.cs.value(1)
board = uname()[0]
if board == 'WiPy' or board == 'LoPy' or board == 'FiPy':
self.spi = SPI(0)
self.spi.init(SPI.MASTER, baudrate=1000000, pins=(self.sck, self.mosi, self.miso))
elif (board == 'esp8266') or (board == 'esp32'):
self.spi = SPI(baudrate=100000, polarity=0, phase=0, sck=self.sck, mosi=self.mosi, miso=self.miso)
self.spi.init()
elif board == 'rp2':
self.spi = SPI(spi_id,baudrate=baudrate,sck=self.sck, mosi= self.mosi, miso= self.miso)
else:
raise RuntimeError("Unsupported platform")
self.rst.value(1)
self.init()
def _wreg(self, reg, val):
self.cs.value(0)
self.spi.write(b'%c' % int(0xff & ((reg << 1) & 0x7e)))
self.spi.write(b'%c' % int(0xff & val))
self.cs.value(1)
def _rreg(self, reg):
self.cs.value(0)
self.spi.write(b'%c' % int(0xff & (((reg << 1) & 0x7e) | 0x80)))
val = self.spi.read(1)
self.cs.value(1)
return val[0]
def _sflags(self, reg, mask):
self._wreg(reg, self._rreg(reg) | mask)
def _cflags(self, reg, mask):
self._wreg(reg, self._rreg(reg) & (~mask))
def _tocard(self, cmd, send):
recv = []
bits = irq_en = wait_irq = n = 0
stat = self.ERR
if cmd == 0x0E:
irq_en = 0x12
wait_irq = 0x10
elif cmd == 0x0C:
irq_en = 0x77
wait_irq = 0x30
self._wreg(0x02, irq_en | 0x80)
self._cflags(0x04, 0x80)
self._sflags(0x0A, 0x80)
self._wreg(0x01, 0x00)
for c in send:
self._wreg(0x09, c)
self._wreg(0x01, cmd)
if cmd == 0x0C:
self._sflags(0x0D, 0x80)
i = 2000
while True:
n = self._rreg(0x04)
i -= 1
if ~((i != 0) and ~(n & 0x01) and ~(n & wait_irq)):
break
self._cflags(0x0D, 0x80)
if i:
if (self._rreg(0x06) & 0x1B) == 0x00:
stat = self.OK
if n & irq_en & 0x01:
stat = self.NOTAGERR
elif cmd == 0x0C:
n = self._rreg(0x0A)
lbits = self._rreg(0x0C) & 0x07
if lbits != 0:
bits = (n - 1) * 8 + lbits
else:
bits = n * 8
if n == 0:
n = 1
elif n > 16:
n = 16
for _ in range(n):
recv.append(self._rreg(0x09))
else:
stat = self.ERR
return stat, recv, bits
def _crc(self, data):
self._cflags(0x05, 0x04)
self._sflags(0x0A, 0x80)
for c in data:
self._wreg(0x09, c)
self._wreg(0x01, 0x03)
i = 0xFF
while True:
n = self._rreg(0x05)
i -= 1
if not ((i != 0) and not (n & 0x04)):
break
return [self._rreg(0x22), self._rreg(0x21)]
def init(self):
self.reset()
self._wreg(0x2A, 0x8D)
self._wreg(0x2B, 0x3E)
self._wreg(0x2D, 30)
self._wreg(0x2C, 0)
self._wreg(0x15, 0x40)
self._wreg(0x11, 0x3D)
self.antenna_on()
def reset(self):
self._wreg(0x01, 0x0F)
def antenna_on(self, on=True):
if on and ~(self._rreg(0x14) & 0x03):
self._sflags(0x14, 0x03)
else:
self._cflags(0x14, 0x03)
def request(self, mode):
self._wreg(0x0D, 0x07)
(stat, recv, bits) = self._tocard(0x0C, [mode])
if (stat != self.OK) | (bits != 0x10):
stat = self.ERR
return stat, bits
def anticoll(self,anticolN):
ser_chk = 0
ser = [anticolN, 0x20]
self._wreg(0x0D, 0x00)
(stat, recv, bits) = self._tocard(0x0C, ser)
if stat == self.OK:
if len(recv) == 5:
for i in range(4):
ser_chk = ser_chk ^ recv[i]
if ser_chk != recv[4]:
stat = self.ERR
else:
stat = self.ERR
return stat, recv
def PcdSelect(self, serNum,anticolN):
backData = []
buf = []
buf.append(anticolN)
buf.append(0x70)
#i = 0
###xorsum=0;
for i in serNum:
buf.append(i)
#while i<5:
# buf.append(serNum[i])
# i = i + 1
pOut = self._crc(buf)
buf.append(pOut[0])
buf.append(pOut[1])
(status, backData, backLen) = self._tocard( 0x0C, buf)
if (status == self.OK) and (backLen == 0x18):
return 1
else:
return 0
def SelectTag(self, uid):
byte5 = 0
#(status,puid)= self.anticoll(self.PICC_ANTICOLL1)
#print("uid",uid,"puid",puid)
for i in uid:
byte5 = byte5 ^ i
puid = uid + [byte5]
if self.PcdSelect(puid,self.PICC_ANTICOLL1) == 0:
return (self.ERR,[])
return (self.OK , uid)
def tohexstring(self,v):
s="["
for i in v:
if i != v[0]:
s = s+ ", "
s=s+ "0x{:02X}".format(i)
s= s+ "]"
return s
def SelectTagSN(self):
valid_uid=[]
(status,uid)= self.anticoll(self.PICC_ANTICOLL1)
#print("Select Tag 1:",self.tohexstring(uid))
if status != self.OK:
return (self.ERR,[])
if self.DEBUG: print("anticol(1) {}".format(uid))
if self.PcdSelect(uid,self.PICC_ANTICOLL1) == 0:
return (self.ERR,[])
if self.DEBUG: print("pcdSelect(1) {}".format(uid))
#check if first byte is 0x88
if uid[0] == 0x88 :
#ok we have another type of card
valid_uid.extend(uid[1:4])
(status,uid)=self.anticoll(self.PICC_ANTICOLL2)
#print("Select Tag 2:",self.tohexstring(uid))
if status != self.OK:
return (self.ERR,[])
if self.DEBUG: print("Anticol(2) {}".format(uid))
rtn = self.PcdSelect(uid,self.PICC_ANTICOLL2)
if self.DEBUG: print("pcdSelect(2) return={} uid={}".format(rtn,uid))
if rtn == 0:
return (self.ERR,[])
if self.DEBUG: print("PcdSelect2() {}".format(uid))
#now check again if uid[0] is 0x88
if uid[0] == 0x88 :
valid_uid.extend(uid[1:4])
(status , uid) = self.anticoll(self.PICC_ANTICOLL3)
#print("Select Tag 3:",self.tohexstring(uid))
if status != self.OK:
return (self.ERR,[])
if self.DEBUG: print("Anticol(3) {}".format(uid))
if self.MFRC522_PcdSelect(uid,self.PICC_ANTICOLL3) == 0:
return (self.ERR,[])
if self.DEBUG: print("PcdSelect(3) {}".format(uid))
valid_uid.extend(uid[0:5])
# if we are here than the uid is ok
# let's remove the last BYTE whic is the XOR sum
return (self.OK , valid_uid[:len(valid_uid)-1])
#return (self.OK , valid_uid)
def auth(self, mode, addr, sect, ser):
return self._tocard(0x0E, [mode, addr] + sect + ser[:4])[0]
def authKeys(self,uid,addr,keyA=None, keyB=None):
status = self.ERR
if keyA is not None:
status = self.auth(self.AUTHENT1A, addr, keyA, uid)
elif keyB is not None:
status = self.auth(self.AUTHENT1B, addr, keyB, uid)
return status
def stop_crypto1(self):
self._cflags(0x08, 0x08)
def read(self, addr):
data = [0x30, addr]
data += self._crc(data)
(stat, recv, _) = self._tocard(0x0C, data)
return stat, recv
def write(self, addr, data):
buf = [0xA0, addr]
buf += self._crc(buf)
(stat, recv, bits) = self._tocard(0x0C, buf)
if not (stat == self.OK) or not (bits == 4) or not ((recv[0] & 0x0F) == 0x0A):
stat = self.ERR
else:
buf = []
for i in range(16):
buf.append(data[i])
buf += self._crc(buf)
(stat, recv, bits) = self._tocard(0x0C, buf)
if not (stat == self.OK) or not (bits == 4) or not ((recv[0] & 0x0F) == 0x0A):
stat = self.ERR
return stat
def writeSectorBlock(self,uid, sector, block, data, keyA=None, keyB = None):
absoluteBlock = sector * 4 + (block % 4)
if absoluteBlock > 63 :
return self.ERR
if len(data) != 16:
return self.ERR
if self.authKeys(uid,absoluteBlock,keyA,keyB) != self.ERR :
return self.write(absoluteBlock, data)
return self.ERR
def readSectorBlock(self,uid ,sector, block, keyA=None, keyB = None):
absoluteBlock = sector * 4 + (block % 4)
if absoluteBlock > 63 :
return self.ERR, None
if self.authKeys(uid,absoluteBlock,keyA,keyB) != self.ERR :
return self.read(absoluteBlock)
return self.ERR, None
def MFRC522_DumpClassic1K(self,uid, Start=0, End=64, keyA=None, keyB=None):
for absoluteBlock in range(Start,End):
status = self.authKeys(uid,absoluteBlock,keyA,keyB)
# Check if authenticated
print("{:02d} S{:02d} B{:1d}: ".format(absoluteBlock, absoluteBlock//4 , absoluteBlock % 4),end="")
if status == self.OK:
status, block = self.read(absoluteBlock)
if status == self.ERR:
break
else:
for value in block:
print("{:02X} ".format(value),end="")
print(" ",end="")
for value in block:
if (value > 0x20) and (value < 0x7f):
print(chr(value),end="")
else:
print('.',end="")
print("")
else:
break
if status == self.ERR:
print("Authentication error")
return self.ERR
return self.OK
Para instalar a biblioteca, basta clicar em salvar e escolher a seguinte opção abaixo. Caso você queira criar uma cópia, recomendo salvar no computador também, mas se não tiver no pico, não funciona.

Como já foi dito anteriormente, não importa se o arquivo está dentro de “lib” ou largado no diretório principal, mas neste exemplo optei por em “/lib” para organizar melhor o código.

Pronto, agora a instalação está concluída. A vantagem da biblioteca está no Pico é que não precisa ficar instalando em toda IDE, basta conectar e usar.
Porém, isso acaba consumindo ainda mais a memória e 2MB talvez fique pouco se você costuma usar muitas bibliotecas, se esse for seu caso, sugiro buscar uma memória de 16MB para evitar sufocos de falta de memória.
6 Raspberry Pi Pico exemplos
O RP2040 tem 30 GPIO’s disponíveis para uso, porém no pino há apenas 27 disponíveis nos pin’s header, sendo que a GPIO25 está dedicada a um LED na placa.
Neste tópico você vai aprender todo o básico necessário pra você conseguir ter uma base de como usar o Raspberry Pi Pico em cada aplicação.
Em todas as aplicações a seguir, você deve ficar de olho na tensão que entra no microcontrolador, não podendo ultrapassar os 3.3v.
6.1 Leitura e escrita de sinais digital e leitura analógica
Acionamento de uma porta digital geralmente é o “hello word” do hardware, mas como o objetivo desse post é te mostrar se o Pico vale a pena e como usa-lo.
6.1.1 Raspberry Pi Pico Saída Digital: Ligando LED a cada 1s
Primeiramente, o mais básico de todos é o acionamento de um LED com a porta digital, neste caso, vamos aproveitar o LED on-board que está conectado na GPIO25.
A alternância de ligar ou desligar será temporizada a cada um segundo, para que não seja necessário o uso de um botão.
6.1.1.1 Código Blink Temporizado
O interessante do Micropython é que já existe uma função que faz a troca do estado lógico de uma GPIO, o comando ‘toggle()’ substitui o comando ‘digitalWrite(LED, !digitalRead(LED))’ comumente usado no Arduino IDE.
Uma coisa que você deve notar neste e nos demais exemplos que envolvem LED, é que há uma redundância, pois todos os códigos terá acionamento também do LED da GPIO25.
from machine import Pin
import utime
led_onboard = Pin(25, Pin.OUT)
led_offboard = Pin(15, Pin.OUT)
led_onboard.low()
led_offboard.low()
while True:
led_onboard.toggle()
led_offboard.toggle()
utime.sleep(1)
6.1.1.2 Circuito exemplo do Acionamento de LED
Assim como os demais diagramas a seguir, os LED não serão necessário no circuito, você adiciona se quiser, pois já há um on-board na GPIO25.

6.1.1.3 Teste prático pisca LED
Por questões de praticidade não usei o segundo LED externo por questão de já ter um LED on-board, mas se você por, vai funcionar.
6.1.2 Raspberry Pi Pico Entrada Digital: Acionando LED ao clicar no botão
Aqui já vamos fazer uma adição de um botão no circuito para que possamos ler o sinal do botão e acionar o mesmo LED do tópico acima.
6.1.2.1 Código para ler estado do botão e inverter o estado do LED
No circuito não vamos por resistor no botão, pois vamos aproveitar o resistor presente internamente na GPIO. Por isso, vamos definir um resistor de pull down.
from machine import Pin
import utime
led_onboard = Pin(25, Pin.OUT)
led_offboard = Pin(15, Pin.OUT)
button = Pin(5, Pin.IN, Pin.PULL_DOWN)
led_onboard.low()
led_offboard.low()
while True:
if button.value() == True:
led_onboard.toggle()
led_offboard.toggle()
utime.sleep(1)
6.1.2.2 Circuito exemplo de entrada digital
Note que não houve praticamente alteração nenhuma no circuito, apenas foi adicionado um botão, caso você não tenha, poderá usar fios para simular um botão.

6.1.2.3 Teste prático de entrada digital
6.1.3 Raspberry Pi Pico ADC: Leitura ADC com conversão para volts
O RP2040 tem apenas três entradas ADC, então ficamos limitados a usar apenas essas 3, claro que há formas de contornar isso, como a multiplexação das portas ADC.
6.1.3.1 Calculo para converter Raw ADC em tensão
Para esse teste vamos apenas fazer um jumper entre o VCC a GPIO28 para que possamos medir a tensão da alimentação. Como o ADC do pico é de 12 bits, então basta a gente fazer a seguinte equação para achar a tensão.

Neste caso vamos considerar o Vref como 3.3v e o RawADC representa o valor AD lido pelo microcontrolador.
Se considerarmos que Vref vai ser uma constante, podemos simplesmente já calcular antecipadamente essa divisão e deixar apenas o processo de multiplicação do RawADC para obter a tensão.
No código eu já coloquei esse valor calculado, você pode por toda equação porém como são valores constantes, o resultado também será, então realizar essa operação por completa em toda leitura é um desperdício de processamento, por mais que isso seja irrisório.
6.1.3.2 Código de conversão ADC para volts
Como preferi não por a formula acima para cada leitura e já calculei, o resultado deu 5.0354772259098191805905241474022e-5.
Quando a tensão for maior ou igual a 3.3v, os LED’s se acenderão, caso contrário irá se apagar. Como não há filtros de entrada, o ADC tende a oscilar e consequentemente a tensão.
Por isso, quando você for testar, possa ser que em algum momento o LED pique por um curto período de tempo.
from machine import Pin
import utime
led_onboard = Pin(25, Pin.OUT)
led_offboard = Pin(15, Pin.OUT)
adc = machine.ADC(28)
led_onboard.low()
led_offboard.low()
while True:
v = adc.read_u16() * 5.0354772259098191805905241474022e-5
print(v)
if v >= 3.3:
led_onboard.value(1)
led_offboard.value(1)
else:
led_onboard.value(0)
led_offboard.value(0)
utime.sleep(0.5)
6.1.3.3 Circuito exemplo de entrada ADC
Note que no circuito abaixo optei por por um jumper entre o pino de 3v3 e a GPIO28 para simplificar ao máximo sua montagem, mas você pode por o que quiser.

6.1.3.4 Teste prático de leitura ADC
Note que após desconectar o jumper do barramento do VCC o LED se apaga e ao conectar novamente, o LED se acende.
6.1.4 Raspberry Pi Pico PWM: Exemplo com LED
O RP2040 não tem DAC (Digital Analog Converter) porém em compensação, todas as 30 GPIO’s tem suporte a PWM, o que possibilita criar um “falso DAC”. O Pico tem um PWM de 16 bits que dá um range de 0 a 65535.

6.1.4.1 Não caia nesse erro do PWM
No site oficial da Raspberry Pi o exemplo de PWM está com o valor 65025 como se fosse o máximo do PWM, mas isso na verdade é um erro de publicação, o que é completamente compreensível, mas o correto é 65535.

Se você é uma pessoa que já tem certo conhecimento, deve ter notado isso, mas caso você seja iniciante basta elevar 2^16 e subtrair por um, esse será o verdadeiro 100% do ADC.
Isso pode ser comprovado com um pequeno teste com o osciloscópio, veja que o valor 65025 representa na verdade, 99,2% do PWM e não 100%. Na imagem abaixo fica bem claro isso.

Porém se trocarmos 65025 para 65535 e mantermos a mesma configuração do teste anterior, vamos ver que a onda ficará contínua, isso significa que o duty foi para 100%, mas como o nível não cai o app registra o duty como indefinido.

6.1.4.2 Exemplo de PWM no Raspberry Pi Pico
Como é possível escolher qualquer pino para o PWM, vamos usar novamente a GPIO25 para mais um exemplo.
Neste caso não vamos usar nada mais além disso, vamos apenas fazer com que a luminosidade aumente e diminua de forma progressiva.
6.1.4.2.1 Código em Micropython para PWM
Veja como é intuitivo o código em Micropython, só de ler já é possível entender mesmo que não tenha domínio em Python.
from machine import Pin, PWM
from time import sleep
led_onboard = PWM(Pin(25))
led_offboard = PWM(Pin(15))
led_onboard.freq(1000)
led_offboard.freq(1000)
while True:
for duty in range(65535):
led_onboard.duty_u16(duty)
led_offboard.duty_u16(duty)
sleep(0.0001)
for duty in range(65535, 0, -1):
led_onboard.duty_u16(duty)
led_offboard.duty_u16(duty)
sleep(0.00001)
6.1.4.2.2 Circuito básico para PWM
O PWM está presente em muitas aplicações em nosso dia dia e o LED é a forma mais básica, mas você pode substituir um LED por um MOSFET e controlar um motor por exemplo.

6.1.4.2.3 Teste prático do PWM
Se você já usou o PWM no Arduino ou em outros microcontroladores que tenha uma resolução de 8 bits, é possível perceber que no Pico é bem mais suave, isso é por conta da resolução de 16 bits.
6.2 Raspberry Pi Pico: Interfaces de comunicação UART, SPI e I2C
O Raspberry Pico tem outras interfaces de comunicação como a I2S, VGA e DPI, porém como é algo que está pouco presente no datasheet, não terá exemplos neste post.
Apenas o que de fato está bem documentado no datasheet o RP2040, neste caso, as interfaces de comunicação UART, SPI e I2C.
O interessante que no RP2040 nós temos mais de uma opção para escolher pinos para uma mesma interface de comunicação, isso ajuda muito na montagem do circuito, porém para alguns isso pode atrapalhar, mas vou te mostrar que é bem tranquilo.
6.2.1 Raspberry Pi Pico UART: Exemplo com leitura e escrita da UART0 e UART1
O RP2040 tem duas interfaces de comunicação UART, a UART0 tem três pares de opções para escolha de pinos e a UART1 tem apenas dois pares.
6.2.1.1 Código escrevendo com UART0 e lendo com UART1
Anteriormente comentei sobre a possibilidade de escolha dos pinos, mas como faz isso? É bem simples, basta chamar “Pin(<número da GPIO>)”.
No caso do uso de bibliotecas, talvez isso não seja necessário, apenas basta por o número da GPIO sem chamar “Pin()“, no exemplo da SPI vamos ver isso.
from machine import Pin
import utime
uart0 = machine.UART(0, baudrate = 9600, parity = 0, stop = 1, bits = 8, rx = Pin(13), tx = Pin(12))
uart1 = machine.UART(1, baudrate = 9600, parity = 0, stop = 1, bits = 8, rx = Pin(9), tx = Pin(8))
while True:
uart0.write("elcereza.com")
print("UART1: ", uart1.readline())
utime.sleep(1)
6.2.1.2 Circuito Exemplo da comunicação UART
Perceba que neste circuito não há nada demais, apaenas conectei o Tx0 em Rx1 e Rx0 em Tx1 da mesma forma que foi feito no post da UART do Maix bit.

6.2.1.3 Teste prático da comunicação UART
6.2.2 Raspberry Pi Pico SPI: Exemplo com módulo RFID MFRC522
Neste exemplo e no exemplo da comunicação I2C é necessário que você tenha instalado as bibliotecas do tópico “Como instalar bibliotecas no Thonny IDE”.
Para este exemplo vamos usar um módulo de RFID, é algo bem simples e interessante que utiliza a interface SPI.
Este tópico foi estruturado com base no post do site microcontrollerslab, porém conta com algumas modificações.
6.2.2.1 Código de leitura de ID do cartão
Como foi dito no tópico da comunicação UART, neste exemplo não é necessário usar o comando “Pin()” para definir o pino, só informar o número, pois a biblioteca já faz essa definição para a gente.
from mfrc522 import MFRC522
import utime
reader = MFRC522(sck = 14, mosi = 15, miso = 12, rst = 9, cs = 13,baudrate=1000000,spi_id=1)
print("Bring TAG closer...")
print("")
while True:
reader.init()
(stat, tag_type) = reader.request(reader.REQIDL)
if stat == reader.OK:
(stat, uid) = reader.SelectTagSN()
if stat == reader.OK:
card = int.from_bytes(bytes(uid),"little",False)
print("CARD ID: "+str(card))
utime.sleep_ms(1000)
6.2.2.2 Circuito exemplo Pico e módulo RFID
Se você olhar no pinout do pico, vai perceber que não tem SPI MISO e nem SPI MOSI, mas suas equivalências são respectivamente SPI Rx e SPI Tx.

6.2.2.3 Teste prático da comunicação SPI
6.2.3 Raspberry Pi Pico I2C: Exemplo com display OLED
Por fim, a última interface de comunicação nesta serie de exemplos de comunicações. Neste exemplo vamos usar o display OLED 0,96″.
Esta interface é a mais fácil de encontrar bibliotecas prontas que possível instalar pelo primeiro método de instalação de bibliotecas no Thonny IDE.
Isso ocorre pelo simples motivo de que muitos sensores digitais usam esta interface para enviar dados, pois é uma interface que pode ter vários dispositivos simultâneos mas é mais fraca em termos de clock em relação a SPI.
6.2.3.1 Código para imprimir o link “elcereza.com”
Neste exemplo vamos usar a interface I2C 1 e como esta biblioteca não possui uma definição de pinos de forma automática, temos que declarar manualmente usando a função “Pin()”.
from machine import Pin, I2C
from ssd1306 import SSD1306_I2C
i2c = I2C(1,sda=Pin(14), scl=Pin(15), freq=400000)
oled = SSD1306_I2C(128, 64, i2c)
oled.text("elcereza.com", 0, 0)
oled.show()
6.2.3.2 Circuito do display OLED I2C e RP2040
Aqui é o padrão de sempre, quem já nos acompanha, já cansou de ver circuitos com I2C e com OLED também.

6.2.3.3 Teste prático da comunicação I2C
7 Raspberry Pi Pico vai acabar com Arduino ou ESP?
Muitas pessoas ficam comentando que o ESP32 vai acabar com o Arduino e após o lançamento do Pico, a mesma situação se repetiu. É fato que a Rasp acabou de certa forma virando um concorrente.
Porém o Arduino especificamente, é gigantesco e tem inúmeras placas para diferentes tipos de aplicações, mas no caso do ESP32 o novo Pico W se tornará de fato um concorrente direto para aplicações com WiFi.
7.1 Opinião pessoal
E por mais que o ESP32 tenha um “concorrente forte”, a Rasp é nova no mercado de microcontroladores e o ESP já está presente em inúmeros produtos de outras empresas, além disso é bem mais forte em termos técnicos.
O pico é vendido como uma placa, sendo que poderia ser vendido como uma plaquinha com o mínimo de hardware necessário igual o ESP32 Wroom.

Particularmente acredito que isso é uma grande desvantagem do Pico, pois boa parte das aplicações vai exigir mais hardware externo.
Seria necessário comprar o RP2040, cristal, capacitores, resistores e memória flash tudo de forma individual. No caso do ESP32, só é necessário o uso de um regulador de tensão e olhe lá… Só por isso o pico jamais acabaria com o ESP.
Outra coisa, essas empresas se demonstram parceiras uma da outra, o ESP usa a IDE do Arduino e o próprio Arduino tem uma placa que usa o microcontrolador RP2040.

Então não tem como uma acabar com a outra, é claro que uma placa ou outra pode ser melhor que da outra empresa, como o ESP32 é melhor que o Pico/Pico w, mas aplicação é uma aplicação e tem mercado para todos.
8 Raspberry Pi Pico W vs ESP32
O Pico e o ESP32 têm aplicações completamente diferentes um do outro, mas para que possamos ser no mínimo mais justos com a comparação, temos que levar em consideração o Pico W, e mesmo assim a diferença é absurda.

Esse comparativo mostra que o ESP32 é ainda mais poderoso, mas isso não quer dizer que é melhor ter o ESP32 do que o Pico, pois cada um vai se destacar melhor para determinadas aplicações.
Particularmente prefiro o ESP para aplicações sem fio no geral, porém se fosse um projeto para criar um osciloscópio ou gerador de funções, usaria o Pico, igual o João do Circuitaria que estar montando um.
9 Afinal, vale a pena aprender a usar o Raspberry Pi Pico?
A resposta é sim! O Rap pico é uma ótima porta de entrada para a arquitetura ARM e nada melhor que a estrutura do Raspberry.
Várias outras empresas ao redor do mundo usam essa tecnologia e por mais que haja variações entre elas a base vai permanecer, então sua adaptação vai ser maior e mais rápida do que aprender tudo do zero.