Arduino Nano 33 BLE Sense¶
Varning
Detta kort stöds inte längre. Den sista OpenMV-firmware-utgåvan för Arduino Nano 33 BLE Sense är 4.7.0. Inga ytterligare firmware-uppdateringar, buggfixar eller nya funktioner kommer att släppas för detta mål. Informationen nedan bevaras för användare som kör 4.7.0 eller tidigare.
Arduino Nano 33 BLE Sense är ett 45 × 18 mm kort i Arduino-Nano-formfaktor byggt kring Nordic Semiconductors nRF52840 — en enkel ARM Cortex‑M4 med FPU som kör på 64 MHz med 256 KB internt SRAM och 1 MB internt flashminne. BLE kommer från radion på chipet, och kortet bär en 9‑axlig IMU, en LPS22HB barometer, en HTS221 / HS3003 temperatur‑ / fuktsensor, en APDS9960 sensor för omgivningsljus / färg / närhet / gester och en MP34DT05 PDM-mikrofon. OpenMV-firmware driver alla dessa från MicroPython.
För fullständigt datablad, foton och dimensioner, se produktsidan för Arduino Nano 33 BLE Rev2.
Höjdpunkter¶
Nordic nRF52840 Cortex‑M4 med FPU på 64 MHz med 256 KB internt SRAM och 1 MB internt flashminne.
Bluetooth LE 5.0 via radion på chipet och Nordic SoftDevice s140.
9‑axlig IMU —
LSM9DS1på Rev 1,BMI270+BMM150på Rev 2. Den infrystaimu-drivrutinen avsöker båda vid uppstart.LPS22HBbarometer,HTS221/HS3003temperatur‑ och fuktsensor,APDS9960sensor för omgivningsljus / färg / närhet / gester och MP34DT05 PDM-mikrofon.Micro USB-kontakt för ström, programmering och en CDC-REPL.
22 användar-I/O-stift på standard-Nano-anslutningarna —
TX/RX,D2–D13(digitala),A0–A7(analoga).
Stiftkonfiguration¶
Stiftreferens¶
Stiftnamn |
Referens |
Funktion |
|---|---|---|
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 |
tryck på RESET-knappen på kortet eller dra till GND för att återställa |
LED_BUILTIN |
— |
Orange användar-LED på |
LED_RED |
— |
Röd kanal på RGB-LED (aktiv låg) |
LED_GREEN |
— |
Grön kanal på RGB-LED (aktiv låg) |
LED_BLUE |
— |
Blå kanal på RGB-LED (aktiv låg) |
Varning
I/O-stiften på Nano 33 BLE Sense är endast 3,3 V — de är inte 5 V-toleranta. Att driva 5 V in i dem skadar nRF52840.
Strömstift¶
VIN — 4,5 – 21 V ingång. Driver kortet genom regulatorn på kortet. Matas även via en diod från USB:s 5 V-skena, så USB och
VINkan vara närvarande samtidigt utan att backmata varandra.+5V — inte ansluten som standard.
+3V3 — utgång från 3,3 V-regulatorn.
AREF — analog referensstift. Inte kopplad till nRF52840 på detta kort — ADC:n refereras alltid till 3,3 V.
GND — gemensam jord.
Nano 33 BLE Sense kan drivas via endera vägen:
Micro USB — levererar 5 V till regulatorn på kortet.
VIN-stift — driv en reglerad matning på 4,5 – 21 V.
Anteckning
En lödbygel på kortets undersida märkt VUSB bryggar +5V till USB:s 5 V-skena. Stäng den för att få +5V-anslutningsstiftet att faktiskt bära 5 V.
Anteckning
En normalt sluten lödbygel på utgången från kortets switchade 4,5–21 V-regulator kan klippas för att inaktivera regulatorn, så att kortet kan drivas direkt från en extern 3,3 V-matning på +3V3.
Stift för återställning och felsökning¶
RESET — både en exponerad kontaktyta och en momentan RESET-knapp på kortets ovansida, kopplade till nRF52840:s återställningslinje. Dra till GND eller tryck på knappen för att återställa.
Nano 33 BLE Sense använder Arduinos standardmetod dubbeltryck-återställning för att gå in i Arduinos startladdare. Tryck snabbt på RESET-knappen två gånger — kortet går in i startladdarläge och OpenMV IDE kan flasha en ny firmware-image.
nRF52840:s SWD-signaler är exponerade på pläterade kontaktytor på kortets baksida. Alla felsökningssignaler är 3,3 V-refererade.
Kringutrustning på kortet¶
LED-lampor¶
Nano 33 BLE Sense har en användar-RGB-LED — driven via de silktryckta kanalerna LED_RED, LED_GREEN och LED_BLUE — plus en separat orange LED_BUILTIN på D13. Alla fyra är programstyrbara via machine.LED
from machine import LED
LED("LED_RED").on()
LED("LED_GREEN").on()
LED("LED_BLUE").on()
LED("LED_BUILTIN").on()
En separat grön ström-LED på kortet lyser närhelst +3,3 V-skenan är uppe och är inte användarstyrbar.
Kamerasensor¶
OpenMV-firmware på Nano 33 BLE Sense stöder den parallella CMOS-sensorn OmniVision OV7670. Kortet har ingen bildsensor på kortet — koppla en OV7670-modul till de silktryckta anslutningsstiften som listas nedan och driv den via modulen csi — kamerasensorer
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()
Anteckning
OV7670 tar 14 stift. Firmware kopplar dem enligt följande:
Sensorsignal |
Nano 33 BLE Sense-stift |
|---|---|
D0 |
|
D1 |
|
D2 |
|
D3 |
|
D4 |
|
D5 |
|
D6 |
|
D7 |
|
HSYNC |
|
VSYNC |
|
PXCLK |
|
MXCLK |
|
POWER |
|
RESET |
|
SCL |
|
SDA |
|
OV7670:s I²C-styrbuss är samma externa I²C 0 som exponeras på A5/A4. Sensorn sitter på 7‑bitarsadressen 0x21 — användarenheter på den bussen måste undvika denna adress när kameran är inkopplad.
IMU¶
Den 9‑axliga IMU:n exponeras via den infrysta imu-modulen, som automatiskt detekterar om kortet har LSM9DS1 (Rev 1) eller BMI270 + BMM150 (Rev 2) och presenterar en enhetlig imu.IMU-klass. Sensorerna sitter på den interna I²C 1-bussen (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)
För direkt åtkomst till funktioner som tryckdetektering eller FIFO:n, importera den matchande infrysta drivrutinen (lsm9ds1, bmi270 eller bmm150) och instansiera den på samma buss.
Miljösensorer¶
Barometern (LPS22HB) och temperatur‑ / fuktsensorn (HTS221 på Rev 1, HS3003 på Rev 2) delar samma interna I²C 1-buss som IMU:n:
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)
Ljus / färg / närhet / gester¶
Broadcoms APDS9960 sitter på samma interna I²C 1-buss och tillhandahåller avkänning av omgivningsljus, RGB-färg, närhet och gester:
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)
Mikrofon¶
MP34DT05 PDM-mikrofonen på kortet fångas via audio — Ljudmodul. Varje buffert anländer som signerad 16‑bitars PCM bytearray, redo att matas in i ulab/numpy för 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¶
nRF52840:s Bluetooth LE 5.0-radio körs på Nordic SoftDevice s140 och exponeras via den äldre ubluepy-modulen — de moderna API:erna bluetooth / aioble — Asynkron BLE är inte aktiverade i denna build. Både peripheral-rollen (GATT-server, annonsering) och central-rollen (GAP-observatör / scanner + anslut) är tillgängliga.
Annonsera som en peripheral med en enda Environmental Sensing-tjänst och en notifierbar temperaturkarakteristik — återanropet event_handler aktiveras vid anslutning, frånkoppling och CCCD-skrivningar:
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])
Skanna efter närliggande annonserande enheter i central-rollen:
from ubluepy import Scanner
for entry in Scanner().scan(1_000): # 1 second window
print(entry.addr(), entry.rssi(), "dBm")
Se ubluepy-referensen för det fullständiga API:et — UUID, Service, Characteristic, Peripheral, Scanner, ScanEntry och namnrymden constants.
Bussreferens¶
GPIO¶
Använd machine.Pin för att läsa eller driva något av de silktryckta stiften. Utgångar är 3,3 V CMOS — 15 mA per stift, 25 mA totalt över alla GPIO:er.
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())
Vilket ingångsstift som helst kan även utlösa ett avbrott vid kantövergångar:
def handler(pin):
print("triggered:", pin)
Pin("D3", Pin.IN, Pin.PULL_UP).irq(
handler, Pin.IRQ_FALLING | Pin.IRQ_RISING,
)
UART¶
Buss |
TX |
RX |
|---|---|---|
UART1 |
TX |
RX |
Använd silktrycksnamnen TX/RX med machine.UART
from machine import UART
uart = UART(1, baudrate=115200)
uart.write("hello")
uart.read(5)
I²C¶
Buss |
SDA |
SCL |
|---|---|---|
I2C0 |
|
|
I2C1 |
|
|
Båda bussarna behöver få sina stift uttryckligen angivna till 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()
Anteckning
Buss 1 är den interna sensorbussen på P14/P15 (inte på användaranslutningarna) — den betjänar IMU:n, barometern, miljösensorn och APDS9960. De infrysta sensordrivrutinerna använder den direkt; användarkod kan också skanna den men adresserna är redan upptagna av sensorerna på kortet.
SPI¶
Buss |
MOSI |
MISO |
SCK |
CS |
|---|---|---|---|---|
SPI0 |
D11 |
D12 |
D13 |
D10 |
CS-linjen drivs inte av SPI-kringutrustningen — konfigurera D10 som en utgång och växla den manuellt runt överföringen:
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)
Anteckning
D13 fungerar också som den orange LED_BUILTIN — att driva SPI på denna buss får LED:en att blinka i takt med bussklockan.
ADC¶
nRF52840 har åtta 12‑bitars ADC-kanaler (SAADC) exponerade på A0–A7, alla 3,3 V-refererade — read_u16 returnerar 0–65535 över 0–3,3 V vid stiftet. Kortets AREF-stift är inte kopplat, så referensen är alltid 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¶
nRF52840 exponerar fyra PWM-kringutrustningar (PWM0–PWM3), som var och en driver fyra kanaler, för totalt 16 hårdvaru-PWM-platser. Till skillnad från portar med fast funktion routas kringutrustningarna genom GPIOTE-matrisen — vilken GPIO som helst kan vara en PWM-utgång, så det finns ingen mappning från stift till skiva. Priset för den flexibiliteten är två begränsningar inbakade i kislet:
Alla fyra kanaler inuti en modul delar en enda period/frekvens.
Varje kanal har sin egen pulskvot och polaritet.
Konceptuellt ser de 16 platserna ut så här:
Modul |
Ka 0 |
Ka 1 |
Ka 2 |
Ka 3 |
|---|---|---|---|---|
PWM0 |
pulskvot |
pulskvot |
pulskvot |
pulskvot |
PWM1 |
pulskvot |
pulskvot |
pulskvot |
pulskvot |
PWM2 |
pulskvot |
pulskvot |
pulskvot |
pulskvot |
PWM3 |
pulskvot |
pulskvot |
pulskvot |
pulskvot |
Varje rad körs på en frekvens; de fyra cellerna i en rad driver var och en ett oberoende valt stift med sin egen pulskvot. Olika rader kan köras på helt olika frekvenser.
Driv vilket silktryckt stift som helst (eller LED:erna på kortet) via machine.PWM
from machine import Pin, PWM
pwm = PWM(Pin("D3"), freq=1_000, duty_u16=32768)
Varning
Automatisk allokering förbrukar en hel modul per anrop. När du skapar en PWM utan nyckelorden device=/channel= tar drivrutinen den första lediga modulen och binder ditt stift enbart till dess kanal 0. De återstående tre kanalerna i den modulen ligger oanvända och är endast nåbara via uttryckliga device=/channel=. Detta begränsar oassisterade PWM(Pin(...))-anrop till fyra innan drivrutinen kastar ValueError: all PWM devices in use — även om tolv platser tekniskt sett fortfarande är lediga.
För att använda fler än fyra PWM:er, eller för att avsiktligt dela en frekvens över stift, ange device (0–3) och 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)
Pulskvot accepterar duty (0–100 %), duty_u16 (0–65535) eller duty_ns. Lägg till invert=1 för att vända utgångens polaritet (praktiskt för den aktiv-låga RGB-LED:en).
Anteckning
Eftersom frekvens är en egenskap per modul kommer anrop av pwm.freq(new_freq) på vilken kanal som helst i en modul att köra om nrfx_pwm_init för hela modulen och ändra frekvensen som ses av varje annan kanal som delar den.
Anteckning
Tillåtna frekvenser sträcker sig grovt från 4 Hz till 5,3 MHz, härledda från basklockan på 16 MHz med förskalare 1/2/4/8/16/32/64/128 och en 15‑bitars periodräknare. Drivrutinen väljer automatiskt närmaste delare — freq() rapporterar det begärda värdet, inte det exakt uppnåeliga.
Programvarustyrda bit-bangade bussar¶
machine.SoftI2C och machine.SoftSPI fungerar på vilken GPIO som helst om du behöver en extra buss.
Värmesensor (utanför kortet)¶
Firmware inkluderar drivrutinen fir — drivrutin för värmesensor (fir == far infrared) för externt kopplade värmekameror:
MLX90621 — 16 × 4 IR-matris
MLX90640 — 32 × 24 IR-matris
MLX90641 — 16 × 12 IR-matris
AMG8833 — 8 × 8 IR-matris
Koppla modulen till kortets I²C-buss och läs bildrutor med 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())
fir-drivrutinen kommunicerar endast med sensorn över I²C 0 — koppla modulen till kontaktytorna I2C_SCL / I2C_SDA (A5 / A4).
Tidtagning¶
time¶
time-modulen täcker blockerande fördröjningar, monotona tick och mätning av förfluten tid:
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)
Virtuella timers¶
machine.Timer schemalägger periodiska eller engångsåteranrop utan att förbruka en hårdvarutimerplats. Ange -1 som id för att använda en virtuell (programvaru-) timer:
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"))
Periodvärden anges i millisekunder. Anropa deinit() för att stoppa och frigöra platsen.
Realtidsklocka¶
machine.RTC håller väggklockstid över återställningar. nRF52840:s RTC är knuten till oscillatorn på chipet och överlever inte fullständig strömförlust — ställ in tiden vid varje kallstart om det är viktigt för din applikation:
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())
Vakthund¶
machine.WDT återställer kortet om applikationen hänger sig. När den väl startats kan den inte stoppas eller konfigureras om — mata den periodiskt inuti din huvudloop:
from machine import WDT
wdt = WDT(timeout=5_000) # 5 second window
while True:
# ...do work...
wdt.feed()
Uppstarts- och körtidsinformation¶
Firmware-uppdatering¶
Nano 33 BLE Sense använder Arduinos standardmetod dubbeltryck-återställning för att gå in i Arduinos startladdare. Tryck snabbt på RESET-knappen två gånger — kortet går in i startladdarläge och OpenMV IDE kan flasha en ny firmware-image.
Ett körande skript kan återgå till startladdaren på begäran genom att anropa machine.bootloader()
import machine
machine.bootloader()
Filsystem och uppstartsordning¶
Nano 33 BLE Sense-firmware monterar ett enda filsystem vid uppstart:
Internt flashminne — alltid monterat på
/flashoch används som arbetskatalog. Innehållermain.pyochREADME.txtsom standard; skapas vid allra första uppstarten.
Efter montering kör tolken sedan skript från /flash:
boot.pykörs vid varje mjuk återställning.main.pykörs endast vid kallstart, omedelbart efterboot.py.
Standard-main.py som levereras på ett nyflashat kort blinkar bara den blå kanalen på användar-RGB-LED:en som ett hjärtslag (två korta pulser, kort paus), så att du kan se att firmware startade rent utan någon ansluten värd.
/flash exponeras inte som en USB-masslagringsenhet på detta kort.
Lagringsstorlekar¶
Nano 33 BLE Sense levereras med:
/flash— 64 KB FAT-filsystem, läs/skriv.
Builden för Nano 33 BLE Sense inkluderar inte något ROMFS; leverera Python-moduler direkt på /flash.
Programvarubibliotek¶
Se biblioteksindexet för den fullständiga listan över moduler — inklusive vilka som är unika för Nano 33 BLE Sense-builden.