Arduino Nano 33 BLE Sense

Aviso

Esta placa já não tem suporte. A última versão de firmware OpenMV para o Arduino Nano 33 BLE Sense é a 4.7.0. Não serão emitidas mais atualizações de firmware, correções de erros ou novas funcionalidades para este alvo. As informações abaixo são preservadas para utilizadores que executem a versão 4.7.0 ou anterior.

O Arduino Nano 33 BLE Sense é uma placa com fator de forma Arduino‑Nano de 45 × 18 mm, construída em torno do Nordic Semiconductor nRF52840 — um único ARM Cortex‑M4 com FPU a 64 MHz, com 256 KB de SRAM interna e 1 MB de flash interna. O BLE provém do rádio integrado no chip, e a placa inclui um IMU de 9 eixos, um barómetro LPS22HB, um sensor de temperatura/humidade HTS221 / HS3003, um sensor de luz ambiente/cor/proximidade/gesto APDS9960, e um microfone PDM MP34DT05. O firmware OpenMV controla todos estes componentes a partir do MicroPython.

Arduino Nano 33 BLE Sense

Para a ficha de dados completa, fotografias 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 através do rádio integrado no chip e do Nordic SoftDevice s140.

  • IMU de 9 eixosLSM9DS1 na Rev 1, BMI270 + BMM150 na Rev 2. O controlador frozen imu deteta ambos durante o arranque.

  • LPS22HB barómetro, HTS221 / HS3003 sensor de temperatura e humidade, APDS9960 sensor de luz ambiente / cor / proximidade / gesto, e microfone PDM MP34DT05.

  • Conector Micro USB para alimentação, programação e um REPL CDC.

  • 22 pinos de I/O de utilizador nos headers Nano padrão — TX/RX, D2D13 (digital), A0A7 (analógico).

Disposição dos pinos

Arduino Nano 33 BLE Sense Pinout

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

prima o botão RESET na placa ou ligue a GND para reiniciar

LED_BUILTIN

LED de utilizador laranja em D13

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 do Nano 33 BLE Sense são apenas 3,3 Vnão são tolerantes a 5 V. Aplicar 5 V nos mesmos 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 via díodo a partir do barramento USB de 5 V, pelo que USB e VIN podem estar presentes em simultâneo sem retroalimentação.

  • +5V — não ligado por defeito.

  • +3V3 — saída do regulador de 3,3 V.

  • AREF — pino de referência analógica. Não ligado ao nRF52840 nesta placa — o ADC é sempre referenciado a 3,3 V.

  • GND — terra comum.

O Nano 33 BLE Sense pode ser alimentado através de qualquer um dos seguintes 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 face inferior da placa designado VUSB liga +5V ao barramento USB de 5 V. Feche-o para que o pino de header +5V transporte efetivamente 5 V.

Nota

Um jumper de solda normalmente fechado na saída do regulador de comutação integrado de 4,5–21 V pode ser cortado para desativar o regulador, permitindo alimentar a placa diretamente de uma fonte externa de 3,3 V em +3V3.

Pinos de recuperação e depuração

  • RESET — tanto um pad exposto como um botão RESET momentâneo na face superior da placa, ligado à linha de reset do nRF52840. Ligue a GND ou prima o botão para reiniciar.

O Nano 33 BLE Sense utiliza o duplo toque de reset padrão da Arduino para entrar no bootloader da Arduino. Prima rapidamente o botão RESET duas vezes — a placa entra em modo bootloader e o OpenMV IDE pode flashar uma nova imagem de firmware.

Os sinais SWD do nRF52840 estão expostos em pads metalizados na parte traseira da placa. Todos os sinais de depuração são referenciados a 3,3 V.

Periféricos integrados

LEDs

O Nano 33 BLE Sense possui um LED RGB de utilizador — controlado através dos canais LED_RED, LED_GREEN e LED_BLUE marcados na serigrafía — mais um LED_BUILTIN laranja 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 barramento +3,3 V está ativo e não é controlável pelo utilizador.

Sensor de câmara

O firmware OpenMV no Nano 33 BLE Sense suporta o sensor CMOS paralelo OmniVision OV7670. A placa não possui sensor de imagem integrado — ligue um módulo OV7670 aos pinos de header indicados na serigrafía abaixo e controle-o através do módulo csi — sensores de câmara

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 necessita de 14 pinos. O firmware liga-os da seguinte forma:

Sinal do sensor

Pino do Nano 33 BLE Sense

D0

D10

D1

TX

D2

RX

D3

D2

D4

D3

D5

D5

D6

D6

D7

D4

HSYNC

A1

VSYNC

D8

PXCLK

A0

MXCLK

D9

POWER

A3

RESET

A2

SCL

A5 (I²C 0)

SDA

A4 (I²C 0)

O barramento de controlo I²C do OV7670 é o mesmo I²C 0 externo exposto em A5/A4. O sensor está no endereço de 7 bits 0x21 — os dispositivos de utilizador nesse barramento devem evitar este endereço quando a câmara estiver ligada.

IMU

O IMU de 9 eixos é exposto através do módulo frozen imu, que deteta automaticamente se a placa tem o LSM9DS1 (Rev 1) ou o BMI270 + BMM150 (Rev 2) e apresenta uma classe imu.IMU unificada. Os sensores estão no barramento I²C 1 interno (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 funcionalidades como deteção de toque ou a FIFO, importe o controlador frozen correspondente (lsm9ds1, bmi270, ou bmm150) e instancie-o no mesmo barramento.

Sensores ambientais

O barómetro (LPS22HB) e o sensor de temperatura/humidade (HTS221 na Rev 1, HS3003 na Rev 2) partilham o mesmo barramento I²C 1 interno que o 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 APDS9960 da Broadcom está no mesmo barramento I²C 1 interno e fornece deteção de luz ambiente, cor RGB, proximidade e gesto:

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 é capturado através de audio — Módulo de Áudio. Cada buffer chega como PCM de 16 bits com sinal em bytearray, pronto para alimentar ulab/numpy para processamento 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 funciona com o Nordic SoftDevice s140 e é exposto através do módulo legacy ubluepy — as APIs modernas bluetooth / aioble — BLE Assíncrono não estão ativadas nesta compilação. Estão disponíveis os papéis de periférico (servidor GATT, advertise) e central (observador/scanner GAP + ligar).

Anuncie como periférico com um único serviço de Monitorização Ambiental e uma característica de temperatura com notificação — o callback event_handler é acionado em ligação, desligação e escritas no 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])

Pesquise dispositivos de anúncio próximos no papel 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 ubluepy para a API completa — UUID, Service, Characteristic, Peripheral, Scanner, ScanEntry, e o espaço de nomes constants.

Referência de barramentos

GPIO

Use machine.Pin para ler ou controlar qualquer um dos pinos marcados na serigrafía. As saídas são CMOS a 3,3 V — 15 mA por pino, 25 mA no total em todos os GPIO.

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 pode também disparar uma interrupção em transições de flanco:

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 da serigrafía 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

I2C_SDA / A4

I2C_SCL / A5

I2C1

P14

P15

Ambos os barramentos requerem que os seus pinos sejam 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 nos headers de utilizador) — serve o IMU, barómetro, sensor ambiental e APDS9960. Os controladores frozen de sensores utilizam-no diretamente; o código de utilizador também pode analisá-lo, mas os endereços já estão ocupados pelos sensores integrados.

SPI

Barramento

MOSI

MISO

SCK

CS

SPI0

D11

D12

D13

D10

A linha CS não é controlada 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 também funciona como o LED_BUILTIN laranja — operar SPI neste barramento fará piscar o LED em sincronia com o relógio do barramento.

ADC

O nRF52840 tem oito canais ADC de 12 bits (SAADC) expostos em A0–A7, todos referenciados a 3,3 Vread_u16 devolve 0–65535 para 0–3,3 V no pino. O pino AREF da placa não está ligado, pelo que 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 (PWM0PWM3), cada um a controlar quatro canais, para um total de 16 slots de hardware PWM. Ao contrário das portas de função fixa, os periféricos são encaminhados através da matriz GPIOTE — qualquer GPIO pode ser uma saída PWM, pelo que não existe mapeamento pino-para-fatia. O custo dessa flexibilidade são duas restrições incorporadas no silício:

  • Todos os quatro canais dentro de um módulo partilham um único período/frequência.

  • Cada canal tem o seu próprio ciclo de trabalho e polaridade.

Conceptualmente, os 16 slots têm o seguinte aspeto:

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 funciona a uma frequência; as quatro células numa linha controlam cada uma um pino escolhido independentemente com o seu próprio ciclo de trabalho. Linhas diferentes podem funcionar a frequências completamente diferentes.

Controle qualquer pino marcado na serigrafía (ou os LEDs integrados) através de 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 cria um PWM sem os kwargs device=/channel=, o controlador ocupa o primeiro módulo livre e liga o seu pino apenas ao seu canal 0. Os três canais restantes desse módulo ficam inativos e só são acessíveis através de device=/channel= explícitos. Isso limita as chamadas PWM(Pin(...)) sem assistência a quatro antes de o controlador lançar ValueError: all PWM devices in use — mesmo que doze slots estejam tecnicamente ainda livres.

Para usar mais de quatro PWMs, ou para deliberadamente partilhar 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 de 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 volta a executar nrfx_pwm_init para o módulo inteiro e altera a frequência vista por todos os outros canais que o partilham.

Nota

As frequências permitidas abrangem aproximadamente 4 Hz a 5,3 MHz, derivadas do relógio base de 16 MHz com prescalers 1/2/4/8/16/32/64/128 e um contador de período de 15 bits. O controlador escolhe automaticamente o divisor mais próximo — freq() reporta o valor pedido, não o valor exato alcançável.

Barramentos implementados por software

machine.SoftI2C e machine.SoftSPI funcionam em qualquer GPIO se precisar de um barramento extra.

Sensor térmico (externo)

O firmware inclui o controlador fir — driver de sensor térmico (fir == infravermelho longínquo) para imagers térmicos ligados 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

Ligue o módulo ao barramento I²C da placa e leia fotogramas 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 controlador fir comunica com o sensor apenas através de I²C 0 — ligue o módulo aos pads I2C_SCL / I2C_SDA (A5 / A4).

Temporização

time

O módulo time cobre atrasos 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)

Temporizadores virtuais

machine.Timer agenda callbacks periódicos ou de disparo único sem consumir um slot de temporizador de hardware. Passe -1 como id para usar um temporizador 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 estão em milissegundos. Chame deinit() para parar e libertar o slot.

Relógio em tempo real

machine.RTC mantém a hora do relógio de parede entre reinicializações. O RTC do nRF52840 está ligado ao oscilador interno e não sobrevive a perda total de alimentação — defina a hora em cada arranque a frio se for importante para a 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 ficar suspensa. Uma vez iniciado, não pode ser parado nem reconfigurado — alimente-o periodicamente dentro do seu ciclo principal:

from machine import WDT

wdt = WDT(timeout=5_000)   # 5 second window
while True:
    # ...do work...
    wdt.feed()

Informação de arranque e tempo de execução

Atualização de firmware

O Nano 33 BLE Sense utiliza o duplo toque de reset padrão da Arduino para entrar no bootloader da Arduino. Prima rapidamente o botão RESET duas vezes — a placa entra em modo bootloader e o OpenMV IDE pode flashar uma nova imagem de firmware.

Um script em execução pode voltar a entrar no bootloader a pedido chamando machine.bootloader()

import machine

machine.bootloader()

Sistema de ficheiros e ordem de arranque

O firmware do Nano 33 BLE Sense monta um único sistema de ficheiros no arranque:

  • Flash interna — sempre montada em /flash e usada como diretório de trabalho. Contém main.py e README.txt por defeito; criada no primeiro arranque.

Após a montagem, o interpretador executa scripts de /flash:

  • boot.py é executado em cada reset suave.

  • main.py é executado apenas no arranque a frio, imediatamente após boot.py.

O main.py padrão fornecido numa placa recém-flashada apenas faz piscar o canal azul do LED RGB de utilizador como sinal de vida (dois pulsos curtos, pausa curta), para que possa confirmar que o firmware arrancou corretamente sem qualquer dispositivo anfitrião ligado.

/flash não está exposta como unidade de armazenamento em massa USB nesta placa.

Tamanhos de armazenamento

O Nano 33 BLE Sense é fornecido com:

  • /flash — sistema de ficheiros FAT de 64 KB, leitura/escrita.

A compilação do Nano 33 BLE Sense não inclui uma ROMFS; distribua módulos Python diretamente em /flash.

Bibliotecas de software

Consulte o índice de bibliotecas para a lista completa de módulos — incluindo quais são exclusivos da compilação do Nano 33 BLE Sense.