Arduino Nano 33 BLE Sense¶
Aviso
Esta placa não é mais suportada. A última versão do firmware OpenMV para a Arduino Nano 33 BLE Sense é a 4.7.0. Nenhuma atualização de firmware, correção de bugs ou novo recurso será lançado para este alvo. As informações abaixo são preservadas para usuários que executam a 4.7.0 ou versões anteriores.
A Arduino Nano 33 BLE Sense é uma placa de 45 × 18 mm no formato Arduino-Nano construída em torno do Nordic Semiconductor nRF52840 — um único ARM Cortex-M4 com FPU rodando a 64 MHz, com 256 KB de SRAM interna e 1 MB de flash interna. O BLE vem do rádio integrado ao chip, e a placa traz uma IMU de 9 eixos, um barômetro LPS22HB, um sensor de temperatura / umidade HTS221 / HS3003, um sensor de luz ambiente / cor / proximidade / gesto APDS9960 e um microfone PDM MP34DT05. O firmware OpenMV controla todos esses dispositivos a partir do MicroPython.
Para a folha de dados completa, fotos e dimensões, consulte a página do produto Arduino Nano 33 BLE Rev2.
Destaques¶
Nordic nRF52840 Cortex-M4 com FPU a 64 MHz com 256 KB de SRAM interna e 1 MB de flash interna.
Bluetooth LE 5.0 via rádio integrado ao chip e Nordic SoftDevice s140.
IMU de 9 eixos —
LSM9DS1na Rev 1,BMI270+BMM150na Rev 2. O driver congeladoimusonda ambos na inicialização.Barômetro
LPS22HB, sensor de temperatura e umidadeHTS221/HS3003, sensor de luz ambiente / cor / proximidade / gestoAPDS9960e microfone PDM MP34DT05.Conector Micro USB para alimentação, programação e um REPL CDC.
22 pinos de I/O de usuário nos headers padrão do Nano —
TX/RX,D2–D13(digital),A0–A7(analógico).
Pinagem¶
Referência de pinos¶
Nome do pino |
Referência |
Função |
|---|---|---|
TX |
3.3 V |
UART1 TX |
RX |
3.3 V |
UART1 RX |
D2 |
3.3 V |
PWM |
D3 |
3.3 V |
PWM |
D4 |
3.3 V |
PWM |
D5 |
3.3 V |
PWM |
D6 |
3.3 V |
PWM |
D7 |
3.3 V |
PWM |
D8 |
3.3 V |
PWM |
D9 |
3.3 V |
PWM |
D10 |
3.3 V |
PWM |
D11 |
3.3 V |
PWM / SPI0 MOSI |
D12 |
3.3 V |
PWM / SPI0 MISO |
D13 |
3.3 V |
PWM / SPI0 SCK |
A0 |
3.3 V |
ADC / PWM |
A1 |
3.3 V |
ADC / PWM |
A2 |
3.3 V |
ADC / PWM |
A3 |
3.3 V |
ADC / PWM |
A4 / I2C_SDA |
3.3 V |
ADC / PWM / I2C0 SDA |
A5 / I2C_SCL |
3.3 V |
ADC / PWM / I2C0 SCL |
A6 |
3.3 V |
ADC / PWM |
A7 |
3.3 V |
ADC / PWM |
RESET |
3.3 V |
pressione o botão RESET integrado à placa ou puxe para GND para reiniciar |
LED_BUILTIN |
— |
LED de usuário laranja em |
LED_RED |
— |
Canal vermelho do LED RGB (ativo em nível baixo) |
LED_GREEN |
— |
Canal verde do LED RGB (ativo em nível baixo) |
LED_BLUE |
— |
Canal azul do LED RGB (ativo em nível baixo) |
Aviso
Os pinos de I/O da Nano 33 BLE Sense são somente 3.3 V — eles não toleram 5 V. Aplicar 5 V neles danificará o nRF52840.
Pinos de alimentação¶
VIN — entrada de 4.5 – 21 V. Alimenta a placa através do regulador integrado. Também é alimentado, através de um diodo, a partir do trilho de 5 V do USB, de modo que o USB e o
VINpodem estar presentes ao mesmo tempo sem retroalimentar um ao outro.+5V — desconectado por padrão.
+3V3 — saída do regulador de 3.3 V.
AREF — pino de referência analógica. Não é conectado ao nRF52840 nesta placa — o ADC é sempre referenciado a 3.3 V.
GND — terra comum.
A Nano 33 BLE Sense pode ser alimentada por qualquer um dos caminhos:
Micro USB — fornece 5 V ao regulador integrado.
Pino VIN — aplique uma fonte regulada de 4.5 – 21 V.
Nota
Um jumper de solda na parte inferior da placa rotulado VUSB faz a ponte entre +5V e o trilho de 5 V do USB. Feche-o para que o pino de header +5V realmente conduza 5 V.
Nota
Um jumper de solda normalmente fechado na saída do regulador chaveado de 4.5–21 V integrado à placa pode ser cortado para desabilitar o regulador, de modo que a placa possa ser alimentada diretamente por uma fonte externa de 3.3 V em +3V3.
Pinos de recuperação e depuração¶
RESET — tanto um pad exposto quanto um botão RESET momentâneo na parte superior da placa, ligado à linha de reset do nRF52840. Puxe para GND ou pressione o botão para reiniciar.
A Nano 33 BLE Sense usa o toque duplo de reset (double-tap) padrão do Arduino para entrar no bootloader do Arduino. Pressione rapidamente o botão RESET duas vezes — a placa entra no modo bootloader e o OpenMV IDE pode gravar uma nova imagem de firmware.
Os sinais SWD do nRF52840 estão expostos em pads metalizados na parte de trás da placa. Todos os sinais de depuração são referenciados a 3.3 V.
Periféricos integrados à placa¶
LEDs¶
A Nano 33 BLE Sense tem um LED RGB de usuário — controlado através dos canais serigrafados LED_RED, LED_GREEN e LED_BLUE — além de um LED laranja LED_BUILTIN separado em D13. Todos os quatro são controláveis por software através de machine.LED
from machine import LED
LED("LED_RED").on()
LED("LED_GREEN").on()
LED("LED_BLUE").on()
LED("LED_BUILTIN").on()
Um LED verde de alimentação separado na placa acende sempre que o trilho de +3.3 V está ativo e não é controlável pelo usuário.
Sensor de câmera¶
O firmware OpenMV na Nano 33 BLE Sense suporta o sensor CMOS paralelo OmniVision OV7670. A placa não possui sensor de imagem integrado — conecte um módulo OV7670 aos pinos de header serigrafados listados abaixo e controle-o através do módulo csi — sensores de câmera
import csi
cam = csi.CSI()
cam.reset()
cam.pixformat(csi.RGB565)
cam.framesize(csi.QVGA)
cam.snapshot(time=2000) # let auto‑exposure settle
while True:
img = cam.snapshot()
Nota
O OV7670 ocupa 14 pinos. O firmware os conecta da seguinte forma:
Sinal do sensor |
Pino da Nano 33 BLE Sense |
|---|---|
D0 |
|
D1 |
|
D2 |
|
D3 |
|
D4 |
|
D5 |
|
D6 |
|
D7 |
|
HSYNC |
|
VSYNC |
|
PXCLK |
|
MXCLK |
|
POWER |
|
RESET |
|
SCL |
|
SDA |
|
O barramento de controle I²C do OV7670 é o mesmo I²C 0 externo exposto em A5/A4. O sensor fica no endereço de 7 bits 0x21 — os dispositivos de usuário nesse barramento devem evitar esse endereço quando a câmera estiver conectada.
IMU¶
A IMU de 9 eixos é exposta através do módulo congelado imu, que detecta automaticamente se a placa tem o LSM9DS1 (Rev 1) ou o BMI270 + BMM150 (Rev 2) e apresenta uma classe imu.IMU unificada. Os sensores ficam no barramento interno I²C 1 (P14 / P15):
import time
from machine import I2C, Pin
from imu import IMU
bus = I2C(1, scl=Pin("P15"), sda=Pin("P14"))
sensor = IMU(bus)
while True:
print(sensor.accel()) # (x, y, z) in g
print(sensor.gyro()) # (x, y, z) in deg/s
print(sensor.magnet()) # (x, y, z) magnetometer
time.sleep_ms(100)
Para acesso direto a recursos como detecção de toque ou ao FIFO, importe o driver congelado correspondente (lsm9ds1, bmi270 ou bmm150) e instancie-o no mesmo barramento.
Sensores ambientais¶
O barômetro (LPS22HB) e o sensor de temperatura / umidade (HTS221 na Rev 1, HS3003 na Rev 2) compartilham o mesmo barramento interno I²C 1 com a IMU:
import time
from machine import I2C, Pin
from lps22h import LPS22H
from hts221 import HTS221
bus = I2C(1, scl=Pin("P15"), sda=Pin("P14"))
lps = LPS22H(bus)
try:
hts = HTS221(bus)
except OSError:
from hs3003 import HS3003
hts = HS3003(bus)
while True:
print("pressure: %.2f hPa" % lps.pressure())
print("temperature: %.2f C" % lps.temperature())
print("humidity: %.2f %%" % hts.humidity())
time.sleep_ms(500)
Luz / cor / proximidade / gesto¶
O Broadcom APDS9960 fica no mesmo barramento interno I²C 1 e fornece detecção de luz ambiente, cor RGB, proximidade e gestos:
import time
from machine import I2C, Pin
from apds9960 import uAPDS9960 as APDS9960
bus = I2C(1, scl=Pin("P15"), sda=Pin("P14"))
apds = APDS9960(bus)
apds.enableLightSensor()
while True:
print("ambient light:", apds.readAmbientLight())
time.sleep_ms(250)
Microfone¶
O microfone PDM MP34DT05 integrado à placa é capturado através de audio — Módulo de Áudio. Cada buffer chega como um bytearray PCM de 16 bits com sinal, pronto para ser alimentado em ulab/numpy para DSP:
import audio
from ulab import numpy as np
def loudness(pcmbuf):
samples = np.array(np.frombuffer(pcmbuf, dtype=np.int16), dtype=np.float)
rms = np.sqrt(np.mean(samples ** 2))
if rms > 10000:
print("Loud!", int(rms))
audio.init(channels=1, frequency=16000, gain_db=24)
audio.start_streaming(loudness)
while True:
pass
Bluetooth¶
O rádio Bluetooth LE 5.0 do nRF52840 roda sobre o Nordic SoftDevice s140 e é exposto através do módulo legado ubluepy — as APIs modernas bluetooth / aioble — BLE Assíncrono não estão habilitadas nesta build. Tanto o papel de peripheral (servidor GATT, anunciar) quanto o de central (observador / scanner GAP + conectar) estão disponíveis.
Anuncie como peripheral com um único serviço Environmental Sensing e uma característica de temperatura notificável — o callback event_handler é disparado na conexão, desconexão e em escritas de CCCD:
from ubluepy import Service, Characteristic, UUID, Peripheral, constants
from machine import LED
def event_handler(event_id, handle, data):
if event_id == constants.EVT_GAP_CONNECTED:
LED("LED_GREEN").on()
elif event_id == constants.EVT_GAP_DISCONNECTED:
LED("LED_GREEN").off()
periph.advertise(device_name="Nano 33", services=[svc])
svc = Service(UUID("181A")) # Environmental Sensing
char = Characteristic(UUID("2A6E"), # Temperature
props=Characteristic.PROP_NOTIFY | Characteristic.PROP_READ,
attrs=Characteristic.ATTR_CCCD)
svc.addCharacteristic(char)
periph = Peripheral()
periph.addService(svc)
periph.setConnectionHandler(event_handler)
periph.advertise(device_name="Nano 33", services=[svc])
Faça a varredura de dispositivos próximos que estão anunciando, no papel de central:
from ubluepy import Scanner
for entry in Scanner().scan(1_000): # 1 second window
print(entry.addr(), entry.rssi(), "dBm")
Consulte a referência de ubluepy para a API completa — UUID, Service, Characteristic, Peripheral, Scanner, ScanEntry e o namespace constants.
Referência de barramentos¶
GPIO¶
Use machine.Pin para ler ou acionar qualquer um dos pinos serigrafados. As saídas são CMOS de 3.3 V — 15 mA por pino, 25 mA no total para todas as GPIOs.
from machine import Pin
out = Pin("D2", Pin.OUT)
out.on()
out.off()
out.value(1)
inp = Pin("D3", Pin.IN, Pin.PULL_UP)
print(inp.value())
Qualquer pino de entrada também pode disparar uma interrupção em transições de borda:
def handler(pin):
print("triggered:", pin)
Pin("D3", Pin.IN, Pin.PULL_UP).irq(
handler, Pin.IRQ_FALLING | Pin.IRQ_RISING,
)
UART¶
Barramento |
TX |
RX |
|---|---|---|
UART1 |
TX |
RX |
Use os nomes de serigrafia TX/RX com machine.UART
from machine import UART
uart = UART(1, baudrate=115200)
uart.write("hello")
uart.read(5)
I²C¶
Barramento |
SDA |
SCL |
|---|---|---|
I2C0 |
|
|
I2C1 |
|
|
Ambos os barramentos precisam ter seus pinos passados explicitamente para machine.I2C
from machine import I2C, Pin
bus0 = I2C(0, scl=Pin("I2C_SCL"), sda=Pin("I2C_SDA"), freq=400_000)
bus0.scan()
bus1 = I2C(1, scl=Pin("P15"), sda=Pin("P14"), freq=400_000)
bus1.scan()
Nota
O barramento 1 é o barramento interno de sensores em P14/P15 (não está nos headers de usuário) — ele atende a IMU, o barômetro, o sensor ambiental e o APDS9960. Os drivers de sensor congelados o utilizam diretamente; o código de usuário também pode varrê-lo, mas os endereços já estão ocupados pelos sensores integrados à placa.
SPI¶
Barramento |
MOSI |
MISO |
SCK |
CS |
|---|---|---|---|---|
SPI0 |
D11 |
D12 |
D13 |
D10 |
A linha CS não é acionada pelo periférico SPI — configure D10 como saída e alterne-a manualmente em torno da transferência:
from machine import SPI, Pin
spi = SPI(0, baudrate=10_000_000)
cs = Pin("D10", Pin.OUT, value=1) # CS is not driven by the SPI peripheral
cs.value(0)
spi.write(b"hello")
cs.value(1)
Nota
D13 funciona também como o LED laranja LED_BUILTIN — acionar SPI nesse barramento fará o LED piscar em sincronia com o clock do barramento.
ADC¶
O nRF52840 tem oito canais ADC de 12 bits (SAADC) expostos em A0–A7, todos referenciados a 3.3 V — read_u16 retorna 0–65535 ao longo de 0–3.3 V no pino. O pino AREF da placa não é conectado, portanto a referência é sempre 3.3 V:
from machine import ADC
import time
adc = ADC("A0")
while True:
voltage = adc.read_u16() * 3.3 / 65535
print(voltage)
time.sleep_ms(100)
PWM¶
O nRF52840 expõe quatro periféricos PWM (PWM0–PWM3), cada um acionando quatro canais, totalizando 16 slots de PWM por hardware. Diferentemente de portas de função fixa, os periféricos roteiam através da matriz GPIOTE — qualquer GPIO pode ser uma saída PWM, portanto não há um mapeamento fixo de pino para slice. O custo dessa flexibilidade são duas restrições incorporadas no silício:
Todos os quatro canais dentro de um módulo compartilham um único período/frequência.
Cada canal tem seu próprio ciclo de trabalho (duty cycle) e polaridade.
Conceitualmente, os 16 slots se parecem com isto:
Módulo |
Ch 0 |
Ch 1 |
Ch 2 |
Ch 3 |
|---|---|---|---|---|
PWM0 |
duty |
duty |
duty |
duty |
PWM1 |
duty |
duty |
duty |
duty |
PWM2 |
duty |
duty |
duty |
duty |
PWM3 |
duty |
duty |
duty |
duty |
Cada linha roda em uma frequência; as quatro células de uma linha acionam, cada uma, um pino escolhido independentemente com seu próprio ciclo de trabalho. Linhas diferentes podem rodar em frequências completamente diferentes.
Acione qualquer pino serigrafado (ou os LEDs integrados à placa) via machine.PWM
from machine import Pin, PWM
pwm = PWM(Pin("D3"), freq=1_000, duty_u16=32768)
Aviso
A alocação automática consome um módulo inteiro por chamada. Quando você cria um PWM sem os kwargs device=/channel=, o driver pega o primeiro módulo livre e vincula seu pino apenas ao canal 0 dele. Os três canais restantes desse módulo ficam ociosos e só podem ser alcançados através de device=/channel= explícitos. Isso limita as chamadas PWM(Pin(...)) sem auxílio a quatro antes de o driver levantar ValueError: all PWM devices in use — mesmo que doze slots ainda estejam tecnicamente livres.
Para usar mais de quatro PWMs, ou para compartilhar deliberadamente uma frequência entre pinos, passe device (0–3) e channel (0–3):
# Two PWMs on the same module → forced to share frequency,
# but each gets its own duty cycle.
pwm_a = PWM(Pin("D3"), device=0, channel=0,
freq=1_000, duty_u16=32768)
pwm_b = PWM(Pin("D5"), device=0, channel=1,
freq=1_000, duty_u16=16384)
# A third PWM on a separate module, free to pick any frequency.
pwm_c = PWM(Pin("D6"), device=1, channel=0,
freq=20_000, duty_u16=49152)
O ciclo de trabalho aceita duty (0–100%), duty_u16 (0–65535) ou duty_ns. Adicione invert=1 para inverter a polaridade da saída (útil para o LED RGB ativo em nível baixo).
Nota
Como a frequência é uma propriedade por módulo, chamar pwm.freq(new_freq) em qualquer canal de um módulo executa novamente nrfx_pwm_init para o módulo inteiro e altera a frequência vista por todos os outros canais que o compartilham.
Nota
As frequências permitidas abrangem aproximadamente 4 Hz a 5.3 MHz, derivadas do clock base de 16 MHz com prescalers 1/2/4/8/16/32/64/128 e um contador de período de 15 bits. O driver escolhe automaticamente o divisor mais próximo — freq() reporta o valor solicitado, não o valor exato alcançável.
Barramentos por software (bit-banged)¶
machine.SoftI2C e machine.SoftSPI funcionam em qualquer GPIO caso você precise de um barramento adicional.
Sensor térmico (externo à placa)¶
O firmware inclui o driver fir — driver de sensor térmico (fir == far infrared) para câmeras térmicas conectadas externamente:
MLX90621 — matriz IR de 16 × 4
MLX90640 — matriz IR de 32 × 24
MLX90641 — matriz IR de 16 × 12
AMG8833 — matriz IR de 8 × 8
Conecte o módulo ao barramento I²C da placa e leia os quadros com fir.init() + fir.snapshot()
import time
import image
import fir
fir.init() # auto‑detects the sensor
clock = time.clock()
while True:
clock.tick()
try:
img = fir.snapshot(x_scale=5, y_scale=5,
color_palette=image.PALETTE_IRONBOW,
hint=image.BICUBIC,
copy_to_fb=True)
except OSError:
continue
print(clock.fps())
O driver fir só se comunica com o sensor através do I²C 0 — conecte o módulo aos pads I2C_SCL / I2C_SDA (A5 / A4).
Temporização¶
time¶
O módulo time cobre delays bloqueantes, ticks monotônicos e medição de tempo decorrido:
import time
time.sleep(1) # seconds
time.sleep_ms(500)
time.sleep_us(10)
start = time.ticks_ms()
# ...do work...
elapsed = time.ticks_diff(time.ticks_ms(), start)
Timers virtuais¶
machine.Timer agenda callbacks periódicos ou de disparo único sem consumir um slot de timer por hardware. Passe -1 como id para usar um timer virtual (por software):
from machine import Timer
one_shot = Timer(-1)
one_shot.init(period=5_000, mode=Timer.ONE_SHOT,
callback=lambda t: print("once"))
periodic = Timer(-1)
periodic.init(period=2_000, mode=Timer.PERIODIC,
callback=lambda t: print("tick"))
Os valores de período são em milissegundos. Chame deinit() para parar e liberar o slot.
Relógio de tempo real¶
machine.RTC mantém o horário do relógio de parede entre reinicializações. O RTC do nRF52840 é ligado ao oscilador interno do chip e não sobrevive a uma perda total de energia — ajuste o horário em cada inicialização a frio se isso for importante para sua aplicação:
from machine import RTC
rtc = RTC()
rtc.datetime((2026, 4, 30, 4, 12, 0, 0, 0)) # Y, M, D, weekday, h, m, s, subsec
print(rtc.datetime())
Watchdog¶
machine.WDT reinicia a placa se a aplicação travar. Uma vez iniciado, não pode ser parado ou reconfigurado — alimente-o periodicamente dentro do seu laço principal:
from machine import WDT
wdt = WDT(timeout=5_000) # 5 second window
while True:
# ...do work...
wdt.feed()
Informações de boot e tempo de execução¶
Atualização de firmware¶
A Nano 33 BLE Sense usa o toque duplo de reset (double-tap) padrão do Arduino para entrar no bootloader do Arduino. Pressione rapidamente o botão RESET duas vezes — a placa entra no modo bootloader e o OpenMV IDE pode gravar uma nova imagem de firmware.
Um script em execução pode reentrar no bootloader sob demanda chamando machine.bootloader()
import machine
machine.bootloader()
Sistema de arquivos e ordem de boot¶
O firmware da Nano 33 BLE Sense monta um único sistema de arquivos na inicialização:
Flash interna — sempre montada em
/flashe usada como diretório de trabalho. Contémmain.pyeREADME.txtpor padrão; criada na primeira inicialização.
Após a montagem, o interpretador então executa scripts a partir de /flash:
boot.pyé executado a cada soft reset.main.pyé executado somente na inicialização a frio, imediatamente apósboot.py.
O main.py padrão fornecido em uma placa recém-gravada apenas pisca o canal azul do LED RGB de usuário como um heartbeat (dois pulsos curtos, intervalo curto), para que você possa saber que o firmware inicializou corretamente sem nenhum host conectado.
/flash não é exposto como uma unidade de armazenamento em massa USB nesta placa.
Tamanhos de armazenamento¶
A Nano 33 BLE Sense vem com:
/flash— sistema de arquivos FAT de 64 KB, leitura/escrita.
A build da Nano 33 BLE Sense não inclui um ROMFS; entregue os módulos Python diretamente em /flash.
Bibliotecas de software¶
Consulte o índice da biblioteca para a lista completa de módulos — incluindo quais são exclusivos da build da Nano 33 BLE Sense.