Tasmota 中的 VL53L0X 飞行时间测距传感器库:Arduino 集成、API 详解与多传感器配置实战
【免费下载链接】TasmotaAlternative firmware for ESP8266 and ESP32 based devices with easy configuration using webUI, OTA updates, automation using timers or rules, expandability and entirely local control over MQTT, HTTP, Serial or KNX. Full documentation at项目地址: https://gitcode.com/GitHub_Trending/ta/Tasmota
本文以仓库内 vl53l0x-arduino-1.02 库及其配套文档为主体,系统讲解 Pololu VL53L0X Arduino 库的硬件接线、安装方式、完整 API 参考与底层实现原理,并结合 Tasmota 的 VL53L0X 驱动 说明如何在 ESP8266/ESP32 固件中以 I²C 方式接入一颗或多颗 VL53L0X 激光测距传感器。读完本文,你将掌握从单次测距到连续测距、从信号率限制到时序预算调优的完整能力,并能在 Tasmota 上通过多 XSHUT 引脚实现多传感器独立寻址与数据采集。
库概览:定位与版本
VL53L0X 是 ST 推出的飞行时间(Time-of-Flight, ToF)激光测距传感器,通过测量激光脉冲从发射到反射返回的时间来计算目标距离。Pololu 编写的这套 Arduino 库封装了该传感器绝大部分配置与读取逻辑,开发者只需通过标准 I²C(Wire库)即可完成初始化和距离读取。
本仓库内对应的库版本信息如下(见 library.properties):
- 名称:VL53L0X
- 版本:1.0.2
- 作者/维护者:Pololu
- 类别:Sensors
- 支持的架构:
*(全平台)
版本历史(记录于 README.md):
| 版本 | 日期 | 变更 |
|---|---|---|
| 1.0.2 | 2017-06-27 | 修复getSpadInfo()中一处寄存器修改的拼写错误 |
| 1.0.1 | 2016-12-08 | 修复readReg32Bit()中的类型错误 |
| 1.0.0 | 2016-08-12 | 首次发布 |
该库的大部分功能基于 ST 官方提供的 VL53L0X API(STSW-IMG005)改写,部分解释性注释直接引用或转述自 API 源码、API 用户手册(UM2039)与 VL53L0X 数据手册。
支持的平台
README 明确说明该库面向 Arduino IDE 1.6.x 及以上版本设计(更早版本未经测试),并支持任何 Arduino 兼容开发板,包括 Pololu A-Star 32U4 控制器系列。在本仓库的 library.properties 中architectures=*也印证了全平台支持的设计意图。由于 Tasmota 生态以 ESP8266/ESP32 为主,该库正是被 Tasmota 的 I²C 传感器框架直接引用的(详见下文“在 Tasmota 中的集成”)。
硬件接线
VL53L0X 载板与 Arduino 之间只需要 4 根线:电源、地、SDA、SCL。README 按开发板 I/O 电平给出了两种接线方案。
5V 开发板
适用于 Arduino Uno、Leonardo、Mega 以及 Pololu A-Star 32U4:
Arduino VL53L0X board ------- ------------- 5V - VIN GND - GND SDA - SDA SCL - SCL3.3V 开发板
适用于 Arduino Due 等 3.3V 平台:
Arduino VL53L0X board ------- ------------- 3V3 - VIN GND - GND SDA - SDA SCL - SCL注意事项(结合源码与 Tasmota 驱动的补充说明):
- 传感器默认 I²C 从机地址为 7 位
0x29。这一点在 VL53L0X.cpp 中由宏ADDRESS_DEFAULT 0b0101001定义,与 Tasmota 驱动 中VL53L0X_ADDRESS 0x29完全一致。 - 若需在总线上挂接多颗 VL53L0X,必须额外连接每颗传感器的 XSHUT 引脚,由主控通过软件依次拉低/释放 XSHUT 来逐个枚举并改写地址。传感器不保存其地址,因此该改址过程在每次重启后都必须重新执行(详见 Tasmota 集成章节)。
- 传感器支持 1V8 与 2V8 两种 I/O 模式,库默认在
init()时切换为 2V8 模式,接线时需保证主控 I/O 电平兼容(必要时使用电平转换)。
软件安装
方式一:Arduino IDE 库管理器
使用 Arduino IDE 1.6.2 或更高版本时:
- 打开 IDE,进入“项目”菜单 → “加载库” → “管理库…”。
- 搜索
VL53L0X。 - 在结果列表中选择 VL53L0X 条目。
- 点击“安装”按钮。
方式二:手动安装
- 从库的发布页面下载最新 release 压缩包并解压。
- 将解压得到的文件夹重命名为
VL53L0X。 - 将
VL53L0X文件夹移动到 Arduino 草稿本目录(sketchbook)下的libraries目录中;可通过 IDE“文件 → 首选项”查看草稿本位置,若不存在libraries目录则自行创建。 - 安装完成后重启 Arduino IDE。
在本仓库中,该库以 1.0.2 版本存放于 lib/lib_i2c/vl53l0x-arduino-1.02,由 Tasmota 的 PlatformIO 构建系统按lib_i2c目录约定自动纳入编译(需在编译选项中启用USE_VL53L0X)。
示例程序
仓库内自带两个官方示例,可通过 IDE“文件 → 示例 → VL53L0X”访问(若找不到说明安装有误,需重试上述安装步骤):
- examples/Single/Single.ino:单次(single-shot)测距模式。
setup()中完成Wire.begin()、sensor.init()与sensor.setTimeout(500),loop()中调用readRangeSingleMillimeters()输出毫米级距离,并用timeoutOccurred()判断是否发生读取超时。 - examples/Continuous/Continuous.ino:连续测距模式。
setup()中调用无参的sensor.startContinuous()进入 back-to-back 模式(传感器尽可能快地连续测量);如需定时模式则传入毫秒间隔,例如sensor.startContinuous(100)。
两个示例都演示了三种可选的测距调优宏(在setup()中按需取消注释):
LONG_RANGE:长距离模式。将信号率限制降到 0.1 MCPS,并把 VCSEL 脉冲周期提高到 Pre=18、Final=14 PCLKs,以增加传感器灵敏度与潜在量程,但会增加来自非目标物体反射导致误读的概率,且在黑暗环境下表现最佳。HIGH_SPEED:高速模式。将测量时序预算降至 20 ms(默认约 33 ms),以速度换取精度。HIGH_ACCURACY:高精度模式。将测量时序预算提升到 200 ms,以时间换取精度。
与 ST 官方 API 的关系
库的注释与实现大量参考 ST 官方 VL53L0X API(STSW-IMG005)与用户手册 UM2039,但其定位与官方 API 有明显差异:
- 更易上手:相比为 Arduino 定制编译 ST 官方 API,本库接口更精简,存储与内存占用更小。
- 功能裁剪:未实现官方 API 中部分高级功能(例如针对覆盖玻璃场景的校准),且错误检查不如官方 API 健壮。
- 适用建议:对于高级应用,尤其是在存储与内存不那么紧张的场景,README 建议直接使用 ST 官方 VL53L0X API;对于大多数常规测距需求,本库足够。
库参考:完整 API 详解
以下为 README.md 中 "Library reference" 章节的完整方法清单,并结合 VL53L0X.h 与 VL53L0X.cpp 给出实现层面的补充说明。
公共成员
uint8_t last_status最近一次 I²C 写传输的状态码,取值含义见Wire.endTransmission()返回值说明(0 表示成功)。VL53L0X(void)构造函数。源码实现将address初始化为默认地址0x29,io_timeout初始化为 0(禁用超时),did_timeout初始化为 false。void setAddress(uint8_t new_addr)将传感器的 I²C 从机地址改为给定 7 位地址。实现上通过写寄存器I2C_SLAVE_DEVICE_ADDRESS(0x8A)完成,并同步更新内部address变量。uint8_t getAddress(void)返回当前 I²C 地址(VL53L0X.h中以内联函数实现,直接返回address成员)。bool init(bool io_2v8 = true)初始化并配置传感器。可选参数io_2v8默认为 true,表示配置为 2V8(2.8V I/O)模式;传 false 则保持 1V8 模式。返回布尔值表示初始化是否成功。源码中init()完整复刻了官方 API 的VL53L0X_DataInit()、VL53L0X_StaticInit()与VL53L0X_PerformRefCalibration()三段流程(见下文源码解析)。void writeReg(uint8_t reg, uint8_t value)/void writeReg16Bit(uint8_t reg, uint16_t value)/void writeReg32Bit(uint8_t reg, uint32_t value)分别向传感器寄存器写入 8/16/32 位数据。多字节写入时高位在前(大端)。寄存器地址常量由VL53L0X.h中的regAddr枚举定义,例如sensor.writeReg(VL53L0X::SYSRANGE_START, 0x01);。uint8_t readReg(uint8_t reg)/uint16_t readReg16Bit(uint8_t reg)/uint32_t readReg32Bit(uint8_t reg)分别从传感器寄存器读取 8/16/32 位数据,高位在前。void writeMulti(uint8_t reg, uint8_t const * src, uint8_t count)从给定寄存器起始,将数组中的任意字节数连续写入传感器。void readMulti(uint8_t reg, uint8_t * dst, uint8_t count)从给定寄存器起始,连续读取任意字节数到目标数组。init()中读取 SPAD 使能映射表(GLOBAL_CONFIG_SPAD_ENABLES_REF_0起 6 字节)即使用该函数。bool setSignalRateLimit(float limit_Mcps)设置回波信号率限制,单位为 MCPS(每秒百万计数)。该值是传感器判定有效读数所需的最小回波信号幅度:设得更低可增大潜在量程,但也会因非目标物体反射而增加误读概率。默认初始化为 0.25 MCPS。参数非法(小于 0 或大于 511.99)时返回 false。实现上以 Q9.7 定点格式写入FINAL_RANGE_CONFIG_MIN_COUNT_RATE_RTN_LIMIT寄存器(VL53L0X.cpp)。float getSignalRateLimit(void)返回当前回波信号率限制(MCPS),实现为将寄存器值按 Q9.7 定点格式除以 128 还原。bool setMeasurementTimingBudget(uint32_t budget_us)设置单次测距的时序预算,单位为微秒。预算越长,测量越精确;增大 N 倍预算可使测距标准差降低约 √N 倍。默认预算约 33000 µs(33 ms),最小 20000 µs(20 ms);小于最小值返回 false。实现会按测距序列各子步骤(TCC/MSRC/DSS/Pre-range/Final-range)的固定开销拆分预算,最终将余量分配给 final range 步骤(VL53L0X.cpp)。uint32_t getMeasurementTimingBudget(void)返回当前测量时序预算(µs)。实现根据各步骤使能状态与超时值反向累加出总预算,其中 StartOverhead 取 1910(与 set 侧的 1320 不同,为官方 API 的既有差异)。bool setVcselPulsePeriod(vcselPeriodType type, uint8_t period_pclks)设置指定类型的 VCSEL(垂直腔面发射激光器)脉冲周期,单位为 PCLK。周期越长,传感器潜在量程越大。合法取值(仅限偶数):类型 合法范围 默认值 Pre-range( VcselPeriodPreRange)12 ~ 18 14 Final-range( VcselPeriodFinalRange)8 ~ 14 10 参数非法时返回 false。实现上会同步调整 valid phase 限值、VCSEL 宽度、相位校准超时等配套寄存器,重算并回写各步骤超时,最后重新应用时序预算并执行相位校准(VL53L0X.cpp)。
uint8_t getVcselPulsePeriod(vcselPeriodType type)返回指定类型的当前 VCSEL 脉冲周期(PCLKs)。void startContinuous(uint32_t period_ms = 0)启动连续测距。period_ms为 0(默认)时进入连续 back-to-back 模式,传感器以尽可能高的频率连续测量;非 0 时进入连续定时模式,按指定的毫秒间隔执行测量。实现上通过写SYSRANGE_START寄存器 0x02(back-to-back)或 0x04(timed)触发,定时模式下还需依据OSC_CALIBRATE_VAL校准写入SYSTEM_INTERMEASUREMENT_PERIOD(VL53L0X.cpp)。void stopContinuous(void)停止连续测距模式。uint16_t readRangeContinuousMillimeters(void)在连续模式下读取一次距离值,单位毫米。实现上先轮询RESULT_INTERRUPT_STATUS寄存器低 3 位等待新数据就绪,然后读取RESULT_RANGE_STATUS + 10处的 16 位距离值,并写SYSTEM_INTERRUPT_CLEAR清除中断(VL53L0X.cpp)。uint16_t readRangeSingleMillimeters(void)执行一次单次测距并返回毫米读数。实现先写SYSRANGE_START0x01 启动单次测量,等待 start 位被清除后再复用readRangeContinuousMillimeters()取数。void setTimeout(uint16_t timeout)设置读取操作的超时时间(毫秒)。若传感器在超时时间内未就绪,读操作将中止;传 0 可禁用超时。uint16_t getTimeout(void)返回当前超时设置。bool timeoutOccurred(void)指示自上次调用timeoutOccurred()以来是否发生过读取超时。注意:读函数超时返回时,距离值会返回 65535,且内部did_timeout标志被置位,随后由本方法查询并清除。
私有方法与内部结构(源码级)
VL53L0X.h还声明了若干私有辅助方法与结构体,体现了与官方 API 的对应关系:
SequenceStepEnables/SequenceStepTimeouts:描述测距序列各步骤(TCC、MSRC、DSS、Pre-range、Final-range)的使能状态与超时值,setMeasurementTimingBudget()与setVcselPulsePeriod()依赖它们完成预算拆分与超时换算。getSpadInfo():获取参考 SPAD(单光子雪崩二极管)数量与类型,对应官方VL53L0X_get_info_from_device()的简化实现。1.0.2 版本修复的正是该方法中的寄存器修改拼写错误。performSingleRefCalibration():执行单次参考校准(VHV 校准与相位校准),对应官方VL53L0X_perform_single_ref_calibration()。decodeTimeout()/encodeTimeout()/timeoutMclksToMicroseconds()/timeoutMicrosecondsToMclks():超时值在寄存器编码(LSByte * 2^MSByte + 1)与 MCLK/µs 之间的换算工具,内部基于calcMacroPeriod(PLL 周期 1655 ps、macro 周期 2304 VCLK)计算。
初始化流程的源码级拆解
init()是使用本库的第一步,其内部按官方 API 的三段流程逐步配置传感器(VL53L0X.cpp):
- DataInit 阶段:若启用 2V8 模式,置位
VHV_CONFIG_PAD_SCL_SDA__EXTSUP_HV的 bit 0;设置 I²C 标准模式;读取stop_variable(0x91)供后续启动测量时回写;禁用 MSRC 与 Pre-range 的信号率检查(MSRC_CONFIG_CONTROL |= 0x12);调用setSignalRateLimit(0.25)设置默认信号率限制。 - StaticInit 阶段:读取参考 SPAD 信息(数量与 aperture 类型)及 6 字节 SPAD 使能映射表,按规则重新编排并写回;随后加载一整段
DefaultTuningSettings调优参数(源自官方vl53l0x_tuning.h,对应 0xFF 页切换与各寄存器写入序列);配置 GPIO 中断为“新样本就绪、低电平有效”;计算当前时序预算并重新应用;最后将测距序列配置为 0xE8(禁用 MSRC 与 TCC 步骤)。 - RefCalibration 阶段:依次执行 VHV 校准(
performSingleRefCalibration(0x40))与相位校准(performSingleRefCalibration(0x00)),完成后恢复序列配置 0xE8。
值得强调的是:init()不执行参考 SPAD 校准(官方VL53L0X_PerformRefSpadManagement()),因为官方 API 用户手册说明裸模块在出厂时已由 ST 完成该校准;只有在添加覆盖玻璃等场景下才可能需要额外校准——这正是该库相对官方 API 裁剪掉的高级功能之一。
在 Tasmota 中的集成:多传感器配置实战
该库在 Tasmota 固件中由 xsns_45_vl53l0x.ino 驱动接入,作为编号 45 的传感器模块(XSNS_45)。启用前提是编译时同时定义USE_I2C与USE_VL53L0X,并在配置中启用 I²C 功能 31(XI2C_31,详见 I2CDEVICES.md)。
单传感器接入
单传感器场景最简单:无需配置 XSHUT 引脚,驱动在检测阶段直接探测默认地址0x29,init()成功后调用setTimeout(500)并启动连续 back-to-back 测距(startContinuous())。数据采集由FUNC_EVERY_250_MSECOND定时回调驱动,每 250 ms 读取一次readRangeContinuousMillimeters(),距离 0 或超过 2200 mm 的读数被归一化为 9999(表示无效/超量程)。
多传感器接入与 XSHUT 寻址
当需要挂接多颗 VL53L0X 时,必须将每颗传感器的 XSHUT 引脚接入主控(Tasmota 模板中的GPIO_VL53LXX_XSHUT1引脚组,最多 8 路)。驱动在Vl53l0Detect()中的枚举策略是(xsns_45_vl53l0x.ino):
- 先将所有 XSHUT 引脚配置为输出并置低(第 0 路置高),使除首颗外的传感器全部处于关断状态。
- 逐路释放(置为输入/上拉)对应 XSHUT 引脚,唤醒一颗传感器,探测其地址(未配置过的为
0x29)。 - 对该传感器执行
init(),成功后调用setAddress()将其地址改写为VL53L0X_XSHUT_ADDRESS + i,即从0x78(120)开始的递增地址,最多占用0x78~0x7F。 - 所有传感器均获得唯一地址后,每 250 ms 轮询读取各自的距离。
由于传感器不保存地址,这个改址流程在每次重启后都会自动重跑。注意地址冲突:0x78~0x7F区间在 I²C 标准中同时被 PCA9685 等器件占用,Tasmota 驱动注释明确提示二者不能共用总线。
测距模式与数据输出
Tasmota 驱动完整移植了库示例中的三种调优模式,以编译宏形式提供(xsns_45_vl53l0x.ino):
VL53L0X_LONG_RANGE:setSignalRateLimit(0.1)+ Pre-range 18 / Final-range 14 PCLKs,对应库示例的LONG_RANGE。VL53L0X_HIGH_SPEED:setMeasurementTimingBudget(20000)。VL53L0X_HIGH_ACCURACY:setMeasurementTimingBudget(200000)。
此外驱动默认启用 5 点中值滤波(USE_VL_MEDIAN/USE_VL_MEDIAN_SIZE 5),对原始距离序列做排序取中值,抑制偶发跳变。最终读数通过FUNC_JSON_APPEND以 JSON 形式上报(单位 cm,原始 mm 读数除以 10),例如:
"VL53L0X1":{"Distance":12.3}多传感器场景下,各传感器以VL53L0X1、VL53L0X2等索引区分;无效读数(9999)在输出时转换为NAN。该值也会呈现在 Web 控制台的传感器页面上,并可在USE_DOMOTICZ编译选项下上报 Domoticz(仅在距离变化超过 8 mm 时上报以减少流量)。配合USE_DEEPSLEEP时,驱动会在进入深睡眠前重新执行init()使传感器进入稳定待机状态,以避免连续模式下的高静态电流。
小结
VL53L0X 库以极简的接口封装了 ST 官方 API 的核心能力,从单次测距、连续测距到信号率限制、时序预算、VCSEL 脉冲周期等关键调优参数一应俱全,且在本仓库中由 Tasmota 驱动 完整落地:单传感器即插即用,多传感器通过 XSHUT 引脚实现软件寻址,并结合中值滤波、JSON/Web 上报与深睡眠待机,构成了 ESP8266/ESP32 平台上成熟可靠的激光测距方案。无论是独立 Arduino 项目还是 Tasmota 固件开发,本文覆盖的接线、安装、API 与源码级原理都足以支撑直接上手。
【免费下载链接】TasmotaAlternative firmware for ESP8266 and ESP32 based devices with easy configuration using webUI, OTA updates, automation using timers or rules, expandability and entirely local control over MQTT, HTTP, Serial or KNX. Full documentation at项目地址: https://gitcode.com/GitHub_Trending/ta/Tasmota
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考