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 打造——这是一颗主频 64 MHz、带 FPU 的单核 ARM Cortex-M4,内置 256 KB 片内 SRAM 和 1 MB 片内闪存。BLE 由片上无线电提供,开发板还搭载了 9 轴 IMU、LPS22HB 气压计、HTS221 / HS3003 温湿度传感器、APDS9960 环境光 / 颜色 / 接近 / 手势传感器以及 MP34DT05 PDM 麦克风。OpenMV 固件通过 MicroPython 驱动以上全部器件。
完整的数据手册、照片和尺寸请参阅 Arduino Nano 33 BLE Rev2 产品页面。
亮点¶
Nordic nRF52840 主频 64 MHz、带 FPU 的 Cortex-M4,内置 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 个槽位如下所示:
模块 |
通道 0 |
通道 1 |
通道 2 |
通道 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 == 远红外) 驱动,用于外接连线的热成像仪:
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 构建所独有的。