产品简介
这款PM2.5空气质量传感器基于博世研发的全球最小颗粒物传感器 BMV080 设计。它采用激光测量原理与无风扇设计,具备±10μg/m³高精度、0-1000μg/m³宽量程、24×20mm超小体积、6μA低功耗以及10年寿命低故障率等核心特点。
传统PM2.5传感器通常依赖风扇引导空气,存在体积大、噪音大、易积灰且寿命短(约1-2年)等问题,严重影响设备集成与用户体验。本产品通过创新的光学计数原理,直接测量自由扩散的颗粒物,无需风扇或风道,从根本上避免了上述问题,显著提升了可靠性。
得益于BMV080的微小尺寸——比市场上同类设备小450倍以上,本产品以此为基础进行Breakout紧凑型设计。板载引出全部引脚,支持I2C和SPI通讯,完整保留了传感器原生功能。此外,我们提供Arduino示例库,便于客户直接进行性能验证与快速集成。
产品集高精度、微型化、超低功耗与完全静音于一身,是构建下一代紧凑、高效空气质量监测方案的理想选择。它非常适合集成到便携式检测仪、设计优雅的桌面空气伴侣、静音空气净化器、现代新风系统以及其他空间受限的环境监测应用中。
产品特性
- 多参数测量:同步测量PM1/PM2.5/PM10质量浓度
- 多协议通讯:支持I2C和SPI通信,集成灵活
- 专业级精度:±10μg/m³高精度,数据准确可靠
- 宽广量程:0-1000μg/m³,覆盖日常至重度污染
- 激光原理:基于激光散射技术,测量稳定可靠
- 超低功耗:工作电流低至6μA,极省电
- 静音免维护:无风扇设计,终身静音,故障率低
- 紧凑微型尺寸:24×20×4.24mm,易于集成
应用场景
- 桌面空气伴侣
- 空气质量监测器
- 空气通风系统
- 智能空气净化器
- PM2.5探测器
尺寸图
单位:mm
产品参数
基本参数
- 工作电压:DC 3.3V
- 工作电流:70mA@3.3V,连续测量模式
- 休眠电流:6μA@3.3V
- 通讯接口:I2C/SPI
- 接口类型:2.54-7P排针孔
- I2C地址:0x57(默认)/0x54/0x55/0x56
BMV080参数
- PM2.5测量范围:0~1000μg/m³
- PM2.5输出分辨率:1μg/m³
- 测量精度:±10μg/m³(0~100μg/m³),±10%(101~1000μg/m³)
- 最小可检测颗粒物尺寸:0.5μm
- 测量模式:连续测量和周期性测量
- 启动时间:1.2s
- 稳定时间:10s
- 冷凝:在激光二极管上不允许凝结
- 激光等级:Class 1,符合IEC 60825-1标准
物理尺寸
- PCB尺寸:24mm20mm4.24mm
- 安装孔间距:19mm
- 安装孔直径:2mm
功能示意图

接口引脚说明
| 引脚丝印 | 功能描述 |
|---|---|
| 3V3 | 电源正极(供电输入3.3V) |
| GND | 电源负极(接地) |
| SCL/SCK | 复用引脚:I2C 模式为时钟线(SCL),SPI 模式为时钟线(SCK) |
| SDA/MOSI | 复用引脚:I2C 模式为数据线(SDA),SPI 模式为数据输入线(MOSI) |
| MISO | 仅 SPI 模式生效,为数据输出线 |
| CSB | 仅 SPI 模式生效,为片选引脚 |
| INT | 中断输出引脚(通用) |
工作模式切换(I2C/SPI)
- 默认状态:出厂配置为 I2C 模式,无需额外操作。
- SPI 模式切换步骤:
- 取下板上 “I2C” 处的 0Ω 电阻,如下图所指,重新焊接到 “SPI” 侧焊盘;
- 在右侧的 “CSB、MISO” 对应的 “H” 丝印下方焊盘,各焊接 1 颗 0Ω 电阻(确保 SPI 信号正常)。

I2C 地址配置(仅 I2C 模式生效)
通过 CSB、MISO 引脚的电平状态(焊盘配置)确定 I2C 地址,具体对应关系如下:
| I2C 地址 | CSB 电平 | MISO 电平 |
|---|---|---|
| 0x57 | H | H |
| 0x56 | H | L |
| 0x55 | L | H |
| 0x54 | L | L |
使用注意事项
启动时序要求
BMV080 上电后需完成硬件初始化、激光器预热、光学系统自检、风扇稳定转速等流程(通常需几秒)。为避免数据读取异常,需在主控程序中添加 “初始化延时 + 就绪状态判断” 逻辑,确保传感器完全启动后再读取数据。
安装与测量要求
- 测量距离:针对 “BMV080 的垂直于激光发射方向的白色反射表面要求”,传感器与被测表面的距离需≥350mm;
- 遮挡处理:临时遮挡会导致数据中断,移除遮挡后可恢复正常输出;
- 排针焊接:若使用排针,需焊接在传感器背面(排针朝下),避免遮挡激光镜头。
维护要点
BMV080 保护透明盖若附着灰尘,会遮挡透光、影响测量精度,甚至触发 “遮挡报警”,需定期检测并清洁镜头(建议用无尘布轻擦)。
Arduino IDE 使用教程
- 硬件准备
- SEN0663 Fermion: BMV080 PM2.5传感器 ×1
- DFR0654 FireBeetle 2 ESP32-E ×1
- 若干杜邦线
- 软件准备
例程1:I2C 模式下连续读取传感器数值
目标
通过 ESP32-E 的 I2C 接口与 BMV080 通信,连续读取 PM2.5 测量数值。
步骤 1:接线配置

按图示连接 BMV080 传感器与 ESP32-E,核心对应关系:
- 传感器引脚 “3V3” → ESP32-E 3.3V
- 传感器引脚 “GND” → ESP32-E GND
- 传感器 I2C 引脚 “SCL” → ESP32-E SCL(默认 GPIO22)
- 传感器 I2C 引脚 “SDA” → ESP32-E SDA(默认 GPIO21)
- 传感器焊盘配置:
- 在传感器的「I2C/SPI 切换焊盘」中,I2C 侧焊接 1 颗 0Ω 电阻(默认模式,无需改动出厂配置)
- 在 CSB、MISO 引脚对应的「H」丝印下方焊盘,各焊接 1 颗 0Ω 电阻(此时 I2C 地址为 0x57)
步骤 2:代码上传
打开 Arduino IDE,复制以下代码并上传至 ESP32-E:
#include "DFRobot_BMV080.h"
// 设置循环任务的栈大小为60KB
SET_LOOP_TASK_STACK_SIZE(60 * 1024);
// I2C地址选择表:
/*
* --------------------------------------
* | CSB引脚 | MISO引脚 | 地址 |
* --------------------------------------
* | 0 | 0 | 0x54 |
* --------------------------------------
* | 0 | 1 | 0x55 |
* --------------------------------------
* | 1 | 0 | 0x56 |
* --------------------------------------
* | 1 | 1 | 0x57 |
* --------------------------------------
*/
// 创建I2C传感器实例,地址为0x57(可根据实际接线修改)
DFRobot_BMV080_I2C sensor(&Wire, 0x57);
float pm1, pm2_5, pm10;
void setup() {
char id[13]; // 用于存储BMV080传感器的芯片ID
Serial.begin(115200);
while (!Serial)
delay(100);
Serial.println("连续读取模式启动");
while (sensor.begin() != 0) {
Serial.println("传感器初始化失败!请检查传感器连接是否正确");
delay(1000);
}
Serial.println("传感器初始化成功");
while (sensor.openBmv080()) {
Serial.println("传感器打开失败");
delay(1000);
}
Serial.println("传感器打开成功");
// 获取并打印芯片ID
sensor.getBmv080ID(id);
Serial.println("芯片ID:" + String(id));
// 启用遮挡检测(有遮挡时会提示数据可能无效)
sensor.setObstructionDetection(true);
// 设置测量模式为连续模式
if (0 == sensor.setBmv080Mode(CONTINUOUS_MODE)) {
Serial.println("测量模式设置成功(连续模式)");
} else {
Serial.println("测量模式设置失败");
}
}
void loop() {
if (sensor.getBmv080Data(&pm1, &pm2_5, &pm10)) {
// 打印PM1、PM2.5、PM10数值
Serial.print("PM1:" + String(pm1) + " ug/m³ ");
Serial.print("PM2.5:" + String(pm2_5) + " ug/m³ ");
Serial.print("PM10:" + String(pm10) + " ug/m³");
// 检测是否有遮挡
if (sensor.ifObstructed()) {
Serial.print(" 注意:传感器被遮挡,数据可能无效");
}
Serial.println();
}
delay(100);
}
输出结果

例程2:SPI 模式下连续读取传感器数值
目标
通过 ESP32-E 的 SPI 接口与 BMV080 通信,连续读取 PM2.5 测量数值。
步骤 1:接线配置

按图示连接 BMV080 传感器与 ESP32-E,核心对应关系:
- 传感器引脚 “3V3” → ESP32-E 3.3V
- 传感器引脚 “GND” → ESP32-E GND
- 传感器 SPI 引脚 “SCK” → ESP32-E SCK(默认 GPIO18)
- 传感器 SPI 引脚 “MOSI” → ESP32-E MOSI(默认 GPIO23)
- 传感器 SPI 引脚 “MISO” → ESP32-E MISO(默认 GPIO19)
- 传感器 SPI 引脚 “CSB” → ESP32-E GPIO13
- 焊盘配置:
- 在传感器的「I2C/SPI 切换焊盘」中,SPI 侧焊接 1 颗 0Ω 电阻
- 在 CSB、MISO 引脚对应的「H」丝印下方焊盘,各焊接 1 颗 0Ω 电阻
步骤 2:代码上传
打开 Arduino IDE,复制以下代码并上传至 ESP32-E:
#include "DFRobot_BMV080.h"
// 设置循环任务栈大小(ESP32运行传感器需足够内存,避免崩溃)
SET_LOOP_TASK_STACK_SIZE(60 * 1024);
// SPI关键配置:定义片选(CS)引脚,需根据ESP32-E实际接线修改(示例为13引脚)
#define SPI_CS_PIN 13
DFRobot_BMV080_SPI sensor(&SPI, SPI_CS_PIN);
float pm1, pm2_5, pm10;
void setup() {
char id[13];
Serial.begin(115200);
while (!Serial) delay(100);
Serial.println("启动SPI模式读取PM值");
while (sensor.begin() != 0) {
Serial.println("传感器初始化失败,请检查接线!");
delay(1000);
}
Serial.println("传感器初始化成功");
while (sensor.openBmv080()) {
Serial.println("传感器打开失败");
delay(1000);
}
Serial.println("传感器打开成功");
// 读取并打印芯片ID(用于确认硬件识别正常)
sensor.getBmv080ID(id);
Serial.print("芯片ID:");
Serial.println(id);
// 设为连续测量模式(读取PM值的基础模式)
if (0 == sensor.setBmv080Mode(CONTINUOUS_MODE)) {
Serial.println("已开启连续测量模式");
} else {
Serial.println("模式设置失败");
}
}
void loop() {
if (sensor.getBmv080Data(&pm1, &pm2_5, &pm10)) {
Serial.print("PM1:" + String(pm1) + " ug/m³ ");
Serial.print("PM2.5:" + String(pm2_5) + " ug/m³ ");
Serial.print("PM10:" + String(pm10) + " ug/m³");
// 检测是否有遮挡
if (sensor.ifObstructed()) {
Serial.print(" 注意:传感器被遮挡,数据可能无效");
}
Serial.println();
}
delay(100);
}
输出结果

API函数
/**
* @fn begin
* @brief 检测是否传感器已连接
* @return 0 已连接
* @return 1 未连接
*/
int begin(void);
/**
* @fn openBmv080
* @brief 初始化BMV080传感器
* @pre 必须先调用此函数,以便为其他函数创建所需的“句柄”
* @post 该“句柄”必须通过“bmv080_close”函数来销毁
* @note 它必须在与传感器进行交互的任何其他功能执行之前被调用
* @return 如果操作成功则返回值为 0,否则则返回一个错误代码
*/
uint8_t openBmv080(void);
/**
* @fn closeBmv080
* @brief 关闭传感器。此时传感器将停止工作。如果您需要再次使用它,需要调用 openBmv080 函数。
* @pre 必须最后调用此函数,以便销毁由“bmv080_open"函数创建的"句柄"
* @return 1 成功
* @return 0 失败,句柄为空,或者在这之前没有调用“openBmv080 stopBmv080”函数
*/
bool closeBmv080(void);
/**
* @fn resetBmv080
* @brief 重置一个传感器单元,该单元包括硬件和软件部分
* @pre 必须使用由“bmv080_open”函数生成的有效“句柄”
* @post 通过“bmv080_set_parameter”更改的任何参数都会恢复到其默认值
* @return 1 成功
* @return 0 失败,在这之前没有调用“openBmv080 stopBmv080”函数
*/
bool resetBmv080(void);
/**
* @fn getBmv080DV
* @brief 获取 BMV080 传感器的驱动程序版本
* @param major: 主要版本号
* @param minor: 次要版本号
* @param patch: 补丁版本号
* @return 1 成功
* @return 0 失败
*/
bool getBmv080DV(uint16_t &major, uint16_t &minor, uint16_t &patch);
/**
* @fn getBmv080ID
* @brief 获取此传感器的ID号。
* @param id: 存放ID的数组
* @return 1 成功
* @return 0 失败
*/
bool getBmv080ID(char *id);
/**
* @fn getBmv080Data
* @brief 获取 BMV080 传感器的数据
* @param PM1: PM1.0 浓度 (ug/m3)
* @param PM2_5: PM2.5 浓度 (ug/m3)
* @param PM10: PM10 浓度 (ug/m3)
* @param allData: 所有数据,这是一个结构体,包含所有数据,包含一下成员
* float runtime_in_sec:运行时间
* float pm2_5_mass_concentration: PM2.5 浓度(ug/m3)
* float pm1_mass_concentration: PM1.0 浓度(ug/m3)
* float pm10_mass_concentration: PM10 浓度(ug/m3)
* float pm2_5_number_concentration: PM2.5 浓度(particles/m3)
* float pm1_number_concentration: PM1.0 浓度(particles/m3)
* float pm10_number_concentration: PM10 浓度(particles/m3)
* bool is_obstructed: 判断传感器是否被遮挡,从而判断数据是否有效。1 表示传感器被遮挡,0 表示传感器未被遮挡
* bool is_outside_measurement_range:判断传感器是否在测量范围外(0..1000 ug/m3)1 表示传感器在范围外,0 表示传感器在范围内
* @note 此功能每秒至少应被调用一次。
* @return 1 成功, BMV080 传感器数据有效
* @return 0 失败, BMV080 传感器数据无效
*/
bool getBmv080Data(float *PM1, float *PM2_5, float *PM10, bmv080_output_t *allData=NULL);
/**
* @fn setBmv080Mode
* @brief 设置 BMV080 传感器的模式
* @param mode: 设置的模式可为:CONTINUOUS_MODE 或 DUTY_CYCLE_MODE
* CONTINUOUS_MODE: 传感器持续进行测量
* DUTY_CYCLE_MODE: 传感器会按照指定的时间间隔进行测量
* @return 0 成功
* @return -1 参数错误
* @return -2 调用顺序有误,或者在这之前没有调用“openBmv080 或者 stopBmv080”函数。
* @return other 其他错误,请参考bmv080_defs.h中的bmv080_status_code_t相关错误码。
*/
int setBmv080Mode(uint8_t mode);
/**
* @fn stopBmv080
* @brief 停止测量。如果需要继续进行测量,则需要调用“setBmv080Mode”函数。
* @pre 必须在数据采集周期结束时调用以确保传感器单元准备好下一个测量周期。
* @return 1 成功
* @return 0 错误
*/
bool stopBmv080(void);
/**
* @fn setIntegrationTime
* @brief 设置测量窗口时间。
* @note 在占空循环模式下,该测量窗口也是传感器开启时间。
* @param integration_time 测量积分时间,单位为毫秒(ms)。
* @return 0 成功
* @return -1 integration_time不在有效范围内,必须大于等于1s
* @return -2 integration_time 必须小于 duty_cycling_period 至少2s
* @return -3 在这之前没有调用“openBmv080 或者 stopBmv080”函数。
* @return other 其他错误,请参考bmv080_defs.h中的bmv080_status_code_t相关错误码。
*/
int setIntegrationTime(float integration_time);
/**
* @fn getIntegrationTime
* @brief 获取当前积分时间。
* @return 当前积分时间,单位为毫秒(ms)。
* @return 0 错误,在这之前没有调用“openBmv080 或者 stopBmv080”函数。
*/
float getIntegrationTime(void);
/**
* @fn setDutyCyclingPeriod
* @brief 设置占空循环周期。
* @n 占空循环周期(积分时间和传感器关闭/休眠时间之和)。
* @note 此值必须比积分时间至少大2秒。
* @param duty_cycling_period 占空循环周期,单位为毫秒(ms)。
* @return 0 成功
* @return -1 duty_cycling_period 不在有效范围内,必须大于等于12s
* @return -2 duty_cycling_period 必须大于 integration_time 至少2s.
* @return -3 传感器还在持续运行种,在这之前没有调用“openBmv080 或者 stopBmv080”函数。
* @return other 其他错误,请参考bmv080_defs.h中的bmv080_status_code_t相关错误码。
*/
int setDutyCyclingPeriod(uint16_t duty_cycling_period);
/**
* @fn getDutyCyclingPeriod
* @brief 获取当前占空循环周期。
* @param duty_cycling_period 当前占空循环周期,单位为毫秒(ms)。
* @return 1 成功
* @return 0 错误,在这之前没有调用“openBmv080 或者 stopBmv080”函数。
*/
bool getDutyCyclingPeriod(uint16_t *duty_cycling_period);
/**
* @fn setObstructionDetection
* @brief 设置是否启用阻塞检测功能。
* @param obstructed 1 启用阻塞检测,0 禁用。
* @return 1 成功
* @return 0 错误,在这之前没有调用“openBmv080 或者 stopBmv080”函数。
*/
bool setObstructionDetection(bool obstructed);
/**
* @fn getObstructionDetection
* @brief 获取阻塞检测功能是否启用状态。
* @return 1 阻塞检测启用。
* @return 0 阻塞检测禁用。
* @return -1 获取失败,在这之前没有调用“openBmv080 或者 stopBmv080”函数。
*/
int getObstructionDetection(void);
/**
* @fn setDoVibrationFiltering
* @brief 启用或禁用振动过滤功能。
* @param do_vibration_filtering 1 启用,0 禁用。
* @return 1 成功
* @return 0 错误,在这之前没有调用“openBmv080 或者 stopBmv080”函数。
*/
bool setDoVibrationFiltering(bool do_vibration_filtering);
/**
* @fn getDoVibrationFiltering
* @brief 获取振动过滤功能的状态。
* @return 1 振动过滤启用。
* @return 0 振动过滤禁用。
* @return -1 获取失败,在这之前没有调用“openBmv080 或者 stopBmv080”函数。
*/
int getDoVibrationFiltering(void);
/**
* @fn setMeasurementAlgorithm
* @brief 设置测量算法。
* @param measurement_algorithm 使用的测量算法。
* FAST_RESPONSE:响应迅速模式,适用于需要快速响应的场景
* BALANCED:平衡模式,适用于需要在精度与快速响应之间取得平衡的场景
* HIGH_PRECISION:高精度模式,适用于对精度有高要求的场景
* @return 1 成功
* @return 0 错误
* @return -1 measurement_algorithm 不在有效范围内
* @return -2 传感器还在持续运行种,在这之前没有调用“openBmv080 或者 stopBmv080”函数。
*/
int setMeasurementAlgorithm(uint8_t measurement_algorithm);
/**
* @fn getMeasurementAlgorithm
* @brief 获取当前使用的测量算法。
* @return 当前使用的测量算法。
* FAST_RESPONSE:响应迅速模式,适用于需要快速响应的场景
* BALANCED:平衡模式,适用于需要在精度与快速响应之间取得平衡的场景
* HIGH_PRECISION:高精度模式,适用于对精度有高要求的场景
* @return 0 获取失败,在这之前没有调用“openBmv080 或者 stopBmv080”函数。
*/
uint8_t getMeasurementAlgorithm(void);
/**
* @fn ifObstructed
* @brief 检测传感器是否被遮挡。
* @return 1 被遮挡。
* @return 0 未被遮挡。
*/
bool ifObstructed(void);