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.
Observera
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.
Observera
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()
Observera
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()
Observera
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)
Observera
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).
Observera
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.
Observera
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.