Arduino Nano 33 BLE Sense¶
警告
本開發板已不再受支援。 Arduino Nano 33 BLE Sense 的最後一個 OpenMV 韌體版本為 4.7.0。此目標將不會再發布任何後續的韌體更新、錯誤修正或新功能。以下資訊是為仍在執行 4.7.0 或更早版本的使用者所保留。
Arduino Nano 33 BLE Sense 是一塊 45 × 18 mm 的 Arduino-Nano 外形規格開發板,以 Nordic Semiconductor 的 nRF52840 為核心——這是一顆單核心 ARM Cortex-M4,內建 FPU,執行時脈為 64 MHz,具有 256 KB 內部 SRAM 與 1 MB 內部快閃記憶體。BLE 來自晶片內建的無線電,而開發板上搭載了 9 軸 IMU、一顆 LPS22HB 氣壓計、一顆 HTS221 / HS3003 溫濕度感測器、一顆 APDS9960 環境光/色彩/接近/手勢感測器,以及一顆 MP34DT05 PDM 麥克風。OpenMV 韌體可從 MicroPython 驅動上述所有元件。
完整的資料手冊、照片與尺寸請參閱 Arduino Nano 33 BLE Rev2 產品頁面。
重點特色¶
Nordic nRF52840 Cortex-M4,內建 FPU,時脈 64 MHz,具有 256 KB 內部 SRAM 與 1 MB 內部快閃記憶體。
Bluetooth LE 5.0,透過晶片內建無線電與 Nordic SoftDevice s140 提供。
9 軸 IMU——Rev 1 為
LSM9DS1,Rev 2 為BMI270+BMM150。凍結的imu驅動程式會在開機時偵測這兩種配置。LPS22HB氣壓計、HTS221/HS3003溫濕度感測器、APDS9960環境光/色彩/接近/手勢感測器,以及 MP34DT05 PDM 麥克風。Micro USB 連接器,用於供電、燒錄程式與 CDC REPL。
標準 Nano 排針上的 22 支使用者 I/O 接腳——
TX/RX、D2–D13(數位)、A0–A7(類比)。
接腳圖¶
接腳參考¶
接腳名稱 |
參考 |
功能 |
|---|---|---|
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 |
按下板上的 RESET 按鈕或拉至 GND 以重置 |
LED_BUILTIN |
— |
位於 |
LED_RED |
— |
RGB LED 紅色通道(低電位有效) |
LED_GREEN |
— |
RGB LED 綠色通道(低電位有效) |
LED_BLUE |
— |
RGB LED 藍色通道(低電位有效) |
警告
Nano 33 BLE Sense 的 I/O 接腳僅支援 3.3 V——它們不耐受 5 V。將 5 V 灌入這些接腳會損壞 nRF52840。
電源接腳¶
VIN——4.5 – 21 V 輸入。透過板上的穩壓器為開發板供電。同時也經由二極體從 USB 5 V 電源軌饋入,因此 USB 與
VIN可以同時存在而不會互相反向灌電。+5V——預設未連接。
+3V3——3.3 V 穩壓器輸出。
AREF——類比參考接腳。在此開發板上並未連接到 nRF52840——ADC 永遠以 3.3 V 為參考。
GND——共同接地。
Nano 33 BLE Sense 可透過以下任一路徑供電:
Micro USB——提供 5 V 給板上的穩壓器。
VIN 接腳——輸入經穩壓的 4.5 – 21 V 電源。
備註
開發板底部標示為 VUSB 的焊接跳線會將 +5V 橋接至 USB 5 V 電源軌。將其短接後,+5V 排針接腳才會實際輸出 5 V。
備註
板上 4.5–21 V 切換式穩壓器輸出端有一個常閉的焊接跳線,可將其切斷以停用穩壓器,如此開發板便能直接由 +3V3 上的外部 3.3 V 電源供電。
復原與除錯接腳¶
RESET——板子頂部同時有一個外露焊盤與一個瞬時 RESET 按鈕,兩者皆連到 nRF52840 的重置線。拉至 GND 或按下按鈕即可重置。
Nano 33 BLE Sense 使用 Arduino 標準的連按兩下重置來進入 Arduino 的開機載入程式。快速按兩下 RESET 按鈕——開發板便會進入開機載入程式模式,OpenMV IDE 即可燒錄新的韌體映像。
nRF52840 的 SWD 訊號外露於開發板背面的鍍層焊盤上。所有除錯訊號皆以 3.3 V 為參考。
板載周邊裝置¶
LED¶
Nano 33 BLE Sense 具有一顆使用者 RGB LED——透過絲印的 LED_RED、LED_GREEN 與 LED_BLUE 通道驅動——外加位於 D13 上一顆獨立的橘色 LED_BUILTIN。這四者皆可透過 machine.LED 以軟體控制:
from machine import LED
LED("LED_RED").on()
LED("LED_GREEN").on()
LED("LED_BLUE").on()
LED("LED_BUILTIN").on()
開發板上另有一顆獨立的綠色電源 LED,只要 +3.3 V 電源軌有電就會亮起,且無法由使用者控制。
相機感測器¶
Nano 33 BLE Sense 上的 OpenMV 韌體支援 OmniVision OV7670 並列式 CMOS 感測器。開發板本身沒有板載影像感測器——請將 OV7670 模組接到下列絲印的排針接腳上,並透過 csi --- 相機感測器 模組驅動它:
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()
備註
OV7670 需要 14 支接腳。韌體按下列方式進行接線:
感測器訊號 |
Nano 33 BLE Sense 接腳 |
|---|---|
D0 |
|
D1 |
|
D2 |
|
D3 |
|
D4 |
|
D5 |
|
D6 |
|
D7 |
|
HSYNC |
|
VSYNC |
|
PXCLK |
|
MXCLK |
|
POWER |
|
RESET |
|
SCL |
|
SDA |
|
OV7670 的 I²C 控制匯流排與 A5/A4 上外露的外部 I²C 0 為同一條。該感測器位於 7 位元位址 0x21——當相機接線完成後,該匯流排上的使用者裝置必須避開此位址。
IMU¶
9 軸 IMU 透過凍結的 imu 模組對外提供,該模組會自動偵測開發板搭載的是 LSM9DS1(Rev 1)還是 BMI270 + BMM150(Rev 2),並提供統一的 imu.IMU 類別。這些感測器位於內部 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)
若要直接存取諸如敲擊偵測或 FIFO 等功能,請匯入對應的凍結驅動程式(lsm9ds1、bmi270 或 bmm150),並在同一條匯流排上將其實體化。
環境感測器¶
氣壓計(LPS22HB)與溫濕度感測器(Rev 1 為 HTS221,Rev 2 為 HS3003)與 IMU 共用同一條內部 I²C 1 匯流排:
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)
光/色彩/接近/手勢¶
Broadcom 的 APDS9960 位於同一條內部 I²C 1 匯流排上,提供環境光、RGB 色彩、接近與手勢感測功能:
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)
麥克風¶
板上的 MP34DT05 PDM 麥克風透過 audio --- 音訊模組 擷取。每個緩衝區皆以帶符號 16 位元 PCM bytearray 形式抵達,可直接饋入 ulab/numpy 進行 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 的 Bluetooth LE 5.0 無線電執行於 Nordic SoftDevice s140 之上,並透過舊版的 ubluepy 模組對外提供——此版本並未啟用較新的 bluetooth / aioble --- 非同步 BLE API。周邊裝置(GATT 伺服器、廣播)與中央裝置(GAP 觀察者/掃描器 + 連線)角色皆可使用。
以周邊裝置角色廣播,提供單一的 Environmental Sensing 服務與一個可通知的溫度特徵值——event_handler 回呼函式會在連線、斷線與 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])
以中央裝置角色掃描附近正在廣播的裝置:
from ubluepy import Scanner
for entry in Scanner().scan(1_000): # 1 second window
print(entry.addr(), entry.rssi(), "dBm")
完整的 API 請參閱 ubluepy 參考文件——UUID、Service、Characteristic、Peripheral、Scanner、ScanEntry,以及 constants 命名空間。
匯流排參考¶
GPIO¶
使用 machine.Pin 來讀取或驅動任何絲印的接腳。輸出為 3.3 V CMOS——每支接腳 15 mA,所有 GPIO 合計 25 mA。
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())
任何輸入接腳也可在邊緣轉態時觸發中斷:
def handler(pin):
print("triggered:", pin)
Pin("D3", Pin.IN, Pin.PULL_UP).irq(
handler, Pin.IRQ_FALLING | Pin.IRQ_RISING,
)
UART¶
匯流排 |
TX |
RX |
|---|---|---|
UART1 |
TX |
RX |
搭配 machine.UART 使用絲印名稱 TX/RX:
from machine import UART
uart = UART(1, baudrate=115200)
uart.write("hello")
uart.read(5)
I²C¶
匯流排 |
SDA |
SCL |
|---|---|---|
I2C0 |
|
|
I2C1 |
|
|
這兩條匯流排都需要將其接腳明確傳遞給 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()
備註
匯流排 1 是位於 P14/P15 上的內部感測器匯流排(不在使用者排針上)——它服務於 IMU、氣壓計、環境感測器與 APDS9960。凍結的感測器驅動程式會直接使用它;使用者程式碼也可以掃描它,但這些位址已被板載感測器佔用。
SPI¶
匯流排 |
MOSI |
MISO |
SCK |
CS |
|---|---|---|---|---|
SPI0 |
D11 |
D12 |
D13 |
D10 |
CS 線並非由 SPI 周邊裝置驅動——請將 D10 設定為輸出,並在傳輸前後手動切換它:
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)
備註
D13 同時兼作橘色的 LED_BUILTIN——在此匯流排上驅動 SPI 會使該 LED 隨著匯流排時脈閃爍。
ADC¶
nRF52840 具有八個 12 位元 ADC 通道(SAADC),外露於 A0–A7 上,全部皆以 3.3 V 為參考——read_u16 會在接腳的 0–3.3 V 範圍內回傳 0–65535。開發板的 AREF 接腳未接線,因此參考永遠是 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 外露了四個 PWM 周邊裝置(PWM0–PWM3),每個驅動四個通道,總共構成 16 個硬體 PWM 槽位。與固定功能的連接埠不同,這些周邊裝置是透過 GPIOTE 矩陣繞送的——任何 GPIO 都可以是 PWM 輸出,因此不存在接腳對切片的固定對應。這份彈性的代價是矽晶片中內建的兩項限制:
同一模組內的所有四個通道共用單一的週期/頻率。
每個通道都有各自的工作週期與極性。
在概念上,這 16 個槽位看起來像這樣:
模組 |
Ch 0 |
Ch 1 |
Ch 2 |
Ch 3 |
|---|---|---|---|---|
PWM0 |
工作週期 |
工作週期 |
工作週期 |
工作週期 |
PWM1 |
工作週期 |
工作週期 |
工作週期 |
工作週期 |
PWM2 |
工作週期 |
工作週期 |
工作週期 |
工作週期 |
PWM3 |
工作週期 |
工作週期 |
工作週期 |
工作週期 |
每一列以同一個頻率執行;一列中的四格各自驅動一支獨立選定的接腳,並擁有自己的工作週期。不同的列可以以完全不同的頻率執行。
透過 machine.PWM 驅動任何絲印的接腳(或板載 LED):
from machine import Pin, PWM
pwm = PWM(Pin("D3"), freq=1_000, duty_u16=32768)
警告
每次呼叫進行自動配置時都會消耗一整個模組。 當你在不帶 device=/channel= 關鍵字引數的情況下建立 PWM 時,驅動程式會抓取第一個空閒的模組,並僅將你的接腳繫結到其通道 0。該模組剩下的三個通道會閒置,且只能透過明確的 device=/channel= 才能存取。這使得未經輔助的 PWM(Pin(...)) 呼叫在驅動程式拋出 ValueError: all PWM devices in use 之前,最多只能進行 四 次——即便技術上仍有十二個槽位是空閒的。
若要使用超過四個 PWM,或刻意讓多支接腳共用同一頻率,請傳入 device(0–3)與 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)
工作週期接受 duty(0–100%)、duty_u16(0–65535)或 duty_ns。加上 invert=1 可翻轉輸出極性(對低電位有效的 RGB LED 很方便)。
備註
由於頻率是每個模組的屬性,在某個模組的任一通道上呼叫 pwm.freq(new_freq) 都會為整個模組重新執行 nrfx_pwm_init,並改變共用該模組的其他每個通道所看到的頻率。
備註
允許的頻率範圍大約為 4 Hz 到 5.3 MHz,由 16 MHz 基礎時脈搭配 1/2/4/8/16/32/64/128 的預除頻器與一個 15 位元的週期計數器衍生而來。驅動程式會自動挑選最接近的除數——freq() 回報的是請求的值,而非實際能達到的精確值。
軟體位元模擬匯流排¶
如果你需要額外的匯流排,machine.SoftI2C 與 machine.SoftSPI 可在任何 GPIO 上運作。
熱感測器(外接)¶
韌體包含 fir --- 熱感測器驅動程式 (fir == far infrared,遠紅外線) 驅動程式,可用於外接接線的熱成像儀:
MLX90621——16 × 4 紅外線陣列
MLX90640——32 × 24 紅外線陣列
MLX90641——16 × 12 紅外線陣列
AMG8833——8 × 8 紅外線陣列
將模組接到開發板的 I²C 匯流排,並以 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 驅動程式僅透過 I²C 0 與感測器通訊——請將模組接到 I2C_SCL / I2C_SDA 焊盤(A5 / A4)。
計時¶
time¶
time 模組涵蓋阻塞式延遲、單調遞增的計時刻度,以及經過時間的量測:
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)
虛擬計時器¶
machine.Timer 可在不佔用硬體計時器槽位的情況下排程週期性或單次的回呼函式。將 -1 作為 id 傳入即可使用虛擬(軟體)計時器:
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"))
週期值的單位為毫秒。呼叫 deinit() 可停止並釋放槽位。
即時時鐘¶
machine.RTC 可在多次重置之間維持實際時間。nRF52840 的 RTC 連接到晶片內建振盪器,無法在完全斷電後保留——如果這對你的應用很重要,請在每次冷開機時都設定一次時間:
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())
看門狗¶
如果應用程式當機,machine.WDT 會重置開發板。一旦啟動,它就無法停止或重新設定——請在主迴圈中定期餵食它:
from machine import WDT
wdt = WDT(timeout=5_000) # 5 second window
while True:
# ...do work...
wdt.feed()
開機與執行階段資訊¶
韌體更新¶
Nano 33 BLE Sense 使用 Arduino 標準的連按兩下重置來進入 Arduino 的開機載入程式。快速按兩下 RESET 按鈕——開發板便會進入開機載入程式模式,OpenMV IDE 即可燒錄新的韌體映像。
執行中的指令碼可透過呼叫 machine.bootloader() 隨時重新進入開機載入程式:
import machine
machine.bootloader()
檔案系統與開機順序¶
Nano 33 BLE Sense 韌體在開機時會掛載單一個檔案系統:
內部快閃記憶體——永遠掛載於
/flash,並作為工作目錄使用。預設存放main.py與README.txt;於最初次開機時建立。
掛載完成後,直譯器接著會從 /flash 執行指令碼:
boot.py會在每一次軟重置時執行。main.py僅在冷開機時執行,緊接在boot.py之後。
全新燒錄的開發板上隨附的預設 main.py 只會將使用者 RGB LED 的藍色通道作為心跳閃爍(兩次短脈衝、短暫間隔),讓你在不連接任何主機的情況下就能判斷韌體是否乾淨地開機。
在此開發板上,/flash 不會以 USB 大容量儲存裝置的形式對外提供。
儲存空間大小¶
Nano 33 BLE Sense 出廠時隨附:
/flash——64 KB FAT 檔案系統,可讀寫。
Nano 33 BLE Sense 的版本不包含 ROMFS;請直接將 Python 模組放在 /flash 上。
軟體程式庫¶
完整的模組清單請參閱 程式庫索引——包括哪些模組是 Nano 33 BLE Sense 版本所獨有的。