exs_vl53l1x 扩展库
作者:江访 | 最后修改:2026-07-21
一、概述
exs_vl53l1x 是基于 ST(意法半导体) 出品的 VL53L1X ToF 激光测距传感器开发的 LuatOS 扩展库。VL53L1X 采用940nm不可见的1类激光发射器(对人眼安全),通过测量光子飞行时间实现绝对距离测量。
1.1 主要特性
- 测距范围:最远 4m(暗室,long 模式),最近 4cm
- 供电:2.8V 单电源(AVDD 和 AVDDVCSEL)
- 输出单位:毫米(mm)
- 接口:I2C,7 位固定地址 0x29
- 支持三种测距模式:short(约 1.36m,抗强光)、standard(约 2.9m,默认)、long(约 3.6m)
- 软件 I2C / 硬件 I2C 均可
- 内置 I2C 总线卡死自动检测与恢复
- 支持软件待机睡眠与唤醒
- 支持串扰校准(用于带保护玻璃的模组)
- 支持 GPIO1 中断(数据就绪通知,响应更快)
1.2 注意事项
- 推荐使用软件 I2C 模式:VL53L1X 在异常通信后可能锁死 SDA 总线,软件 I2C 可通过 GPIO 脉冲 SCL 恢复
- 初始化后自动启动测距,无需额外调用 start 方法
- 每次读取测距数据时自动跳过无效帧(如刚启动、刚唤醒时的第一帧)
- 最低工作距离 4cm,低于此值距离值不准
- SCL/SDA 需外接 4.7kΩ~10kΩ 上拉电阻(模块通常已集成)
1.3 测距模式说明
| 模式 | 暗室最远 | 强光下最远 | 特点 |
|---|---|---|---|
| short | 约 1.36m | 约 1.35m | 抗环境光干扰最强 |
| standard(默认) | 约 2.9m | 约 0.76m | 一般场景均衡模式 |
| long | 约 3.6m | 约 0.73m | 远距离,暗光环境 |
1.4 GPIO1 中断说明
GPIO1 是 VL53L1X 的中断输出引脚,每次测距完成时自动输出一个低电平脉冲(约 10μs),通知主机有新数据就绪。
中断触发方式:
- GPIO1 默认配置为下降沿触发(ACTIVE_LOW),测距完成后引脚被拉低
- 每次调用 get_data() 后,库会自动清除中断(写寄存器 0x0086=0x01),释放 GPIO1
- 未使用 GPIO1 时,库通过 I2C 轮询内部寄存器判断数据是否就绪,速度稍慢但不影响功能
中断频率: - 每次测距完成触发一次中断,频率取决于测距模式的测量周期 - Standard Ranging 模式下连续测距,每次完成一帧立即触发下一次,约每秒 30~50 帧 - 中断频率 = 1 /(实际测量时间)
使用方式:
- 通过 setup({int1 = {int_gpio = 引脚号}}) 注册中断引脚
- 有 cb 回调时:每帧测距完成自动调用回调函数(适合低频场景,如 1~10 帧/秒)
- 无 cb 回调时:通过 get_int_flag() 轮询中断标志(适合高频场景,如 30+ 帧/秒,比回调更可靠)
- 注册中断后 get_data() 内部改读 GPIO 电平代替 I2C 轮询,响应更快且省 I2C 总线
1.5 功耗参考
| 模式 | 功耗 | 说明 |
|---|---|---|
| 软件待机(sleep) | 约 6μA | 调用 sleep() 后进入 |
| 连续测距 | 约 20mW | 正常测距时(按33ms 10Hz 计算) |
| 激光发射峰值 | 40mA | VCSEL 点亮的瞬间 |
1.6 接线方式

┌──────────────┐ ┌──────────────────┐
│ 主控 │ │ VL53L1X │
│ │ │ │
│ GPIO_SCL ────┼──────┼──→ SCL │
│ GPIO_SDA ────┼──────┼──→ SDA │
│ GPIO_INT ────┼──────┼──→ GPIO1 (可选) │
│ GPIO_RST ────┼──────┼──→ XSHUT (可选) │
│ VCC 3.3V ────┼──────┼──→ VIN │
│ GND ────┼──────┼──→ GND │
└──────────────┘ └──────────────────┘
GPIO1(中断输出引脚):不接不影响测距功能。接上后可用中断通知代替 I2C 轮询,响应更快、省 I2C 总线。详见 1.4 节。
XSHUT(硬件复位引脚,低电平有效):不接时传感器上电自动启动。接上后 setup({xshut = pin}) 使用硬件复位(拉低再拉高),比软复位更彻底。如果遇到初始化不稳定、I2C 通信异常,建议接上这个引脚。
1.7 加载方式
-- 加载扩展库
local exs_vl53l1x = require "exs_vl53l1x"
二、核心示例
2.1 标准测距
展示最基础的初始化、读取数据和关闭流程。
-- 加载扩展库
local exs_vl53l1x = require "exs_vl53l1x"
-- 主任务
local function demo()
-- 初始化(软件 I2C:SCL=GPIO31, SDA=GPIO30)
local result = exs_vl53l1x.setup({scl = 31, sda = 30})
if not result then
log.error("初始化失败,请检查接线")
return
end
log.info("exs_vl53l1x", "版本:", exs_vl53l1x.version())
sys.wait(200) -- 等待第一帧稳定
for i = 1, 5 do
local data = exs_vl53l1x.get_data()
if data then
log.info(string.format("距离:%dmm 状态=%s", data.distance, data.status_str))
end
sys.wait(500) -- 每 500ms 读一次
end
exs_vl53l1x.close() -- 关闭传感器
end
sys.taskInit(demo)
2.2 测距模式切换示例
展示三种测距模式的用法。
-- 加载扩展库
local exs_vl53l1x = require "exs_vl53l1x"
local function demo()
-- short 模式(抗强光,约 1.36m)
local ok = exs_vl53l1x.setup({scl = 31, sda = 30, range_mode = "short"})
if not ok then return end
sys.wait(200)
log.info("距离:", exs_vl53l1x.get_data().distance, "mm (short)")
-- 切换 long 模式(远距离,约 3.6m)
exs_vl53l1x.close()
ok = exs_vl53l1x.setup({scl = 31, sda = 30, range_mode = "long"})
if not ok then return end
sys.wait(200)
log.info("距离:", exs_vl53l1x.get_data().distance, "mm (long)")
end
sys.taskInit(demo)
2.3 中断回调读取
适合需要及时响应测距结果的场景,省去 I2C 轮询,响应更快。
-- 加载扩展库
local exs_vl53l1x = require "exs_vl53l1x"
-- 中断回调函数,每帧测距完成后自动触发
local function data_cb(data)
log.info(string.format("距离:%dmm 状态=%s", data.distance, data.status_str))
end
local function demo()
local result = exs_vl53l1x.setup({
scl = 31, sda = 30,
int1 = {int_gpio = 10, cb = data_cb}, -- GPIO1 接 GPIO10,注册回调
})
if not result then return end
-- 回调自动处理数据,主线程可做其他事
end
sys.taskInit(demo)
也可以不传 cb,通过 get_int_flag() 轮询(适合高频场景):
-- 轮询任务
local function poll_task()
while true do
if exs_vl53l1x.get_int_flag() then -- 检查中断标志
local data = exs_vl53l1x.get_data()
if data then
log.info(string.format("距离:%dmm 状态=%s", data.distance, data.status_str))
end
end
sys.wait(1)
end
end
sys.taskInit(poll_task)
-- 注册中断(不传 cb,只设引脚)
exs_vl53l1x.setup({scl = 31, sda = 30, int1 = {int_gpio = 10}})
2.4 休眠与唤醒
适合间歇性采样的场景,不需要时休眠省电。
exs_vl53l1x.sleep() -- 休眠(约 6μA),自动停止测距
sys.wait(5000)
exs_vl53l1x.wakeup() -- 唤醒,自动恢复测距
sys.wait(200)
local data = exs_vl53l1x.get_data()
2.5 串扰校准
如果传感器装了保护玻璃或外壳,激光会在玻璃表面反射产生串扰,导致远距离测不准或信号弱。校准可以补偿这个误差。
校准前:在传感器正前方 400mm 处放一张纯白纸板。
-- 加载扩展库
local exs_vl53l1x = require "exs_vl53l1x"
local function calibration()
-- 执行串扰校准
local xtalk = exs_vl53l1x.calibrate_xtalk({
scl = 31, sda = 30,
target_distance_mm = 400, -- 目标距离
samples = 50, -- 采样帧数
})
if not xtalk then return end
log.info("校准完成,xtalk=" .. xtalk)
-- 用校准值初始化(校准值掉电丢失,需在代码中保存)
exs_vl53l1x.setup({scl = 31, sda = 30, xtalk_offset = xtalk})
end
sys.taskInit(calibration)
保存校准值:校准值掉电会丢失,需在代码中保存并在下次开机时传入。
-- 方案一:直接在代码中写死(适合量产时固定值)
local XTALK_FIXED = 45 -- calibrate_xtalk 返回的值
-- 方案二:写入可写文件系统(如 /lfs/)
io.writeFile("/lfs/xtalk.txt", tostring(xtalk))
local xtalk = tonumber(io.readFile("/lfs/xtalk.txt")) or 0
-- 使用时
exs_vl53l1x.setup({scl = 31, sda = 30, xtalk_offset = xtalk})
三、常量解释
扩展库常量,顾名思义是由合宙 LuatOS 扩展库中定义的、不可重新赋值或修改的固定值,在脚本代码中不需要声明,可直接调用,本扩展库没有常量。
四、函数详解
4.1 exs_vl53l1x.setup(config)
功能
初始化传感器并启动测距。
参数
config
参数含义:初始化配置表
数据类型:table
取值范围:
{
参数含义:SCL 时钟引脚 GPIO 编号
数据类型:number
取值范围:有效的 GPIO 编号
是否必选:可选,与 sda 一起传入
注意事项:与 sda 一起传入时创建软件 I2C(推荐)
参数示例:31
config.scl ,
参数含义:SDA 数据引脚 GPIO 编号
数据类型:number
取值范围:有效的 GPIO 编号
是否必选:可选,与 scl 一起传入
注意事项:I2C 模式下该引脚需外接 4.7kΩ~10kΩ 上拉电阻到 VCC
参数示例:30
config.sda ,
参数含义:硬件 I2C 总线 ID
数据类型:number
取值范围:有效的 I2C 总线编号
是否必选:可选
注意事项:默认 0。仅传 i2c_id 时不走总线恢复
参数示例:0
config.i2c_id ,
参数含义:XSHUT 复位引脚 GPIO 编号
数据类型:number
取值范围:有效的 GPIO 编号
是否必选:可选
注意事项:传此参数时使用 XSHUT 硬件复位(拉低再拉高),比软复位更彻底。不传时使用软件复位
参数示例:32
config.xshut ,
参数含义:测距模式
数据类型:string
取值范围:"standard"(默认,约 2.9m)、"short"(约 1.36m,抗强光)、"long"(约 3.6m,远距离)
是否必选:可选
注意事项:short 模式在强光下表现最好;long 模式在强光下最远距离约 0.73m,建议室内或弱光使用
参数示例:"short"
config.range_mode ,
参数含义:串扰校准偏移值
数据类型:number
取值范围:0~65535,由 calibrate_xtalk() 返回
是否必选:可选
注意事项:传入后自动写入串扰补偿寄存器。校准值掉电丢失,需在代码中保存
参数示例:45
config.xtalk_offset ,
参数含义:GPIO1 中断配置
数据类型:table
是否必选:可选
注意事项:格式为 {int_gpio = 引脚号, cb = 回调函数}。int_gpio 是 GPIO1 接的引脚,
cb 是每次测距完成后的回调函数。cb 在 GPIO 中断中触发,频率约 30~50 次/秒,
高频场景建议不传 cb,改用 get_int_flag() 轮询
参数示例:{int_gpio = 10, cb = data_cb}
config.int1 ,
}
是否必选:是
参数示例:
-- 软件 I2C,默认模式
exs_vl53l1x.setup({scl = 31, sda = 30})
-- 远距离模式 + 串扰校准
exs_vl53l1x.setup({scl = 31, sda = 30, range_mode = "long", xtalk_offset = 45})
-- 注册 GPIO1 中断回调
exs_vl53l1x.setup({scl = 31, sda = 30, int1 = {int_gpio = 10, cb = data_cb}})
返回值
local result = exs_vl53l1x.setup(config)
result
含义说明:初始化是否成功
数据类型:boolean
取值范围:true(成功),false(失败)
注意事项:失败时请检查接线、供电和 I2C 通信
返回示例:true
示例
-- 最简用法:软件 I2C,默认 standard 模式
local result = exs_vl53l1x.setup({scl = 31, sda = 30})
if not result then return end
-- 硬件 I2C 模式
local result = exs_vl53l1x.setup({i2c_id = 0})
if not result then return end
-- 短距离模式(抗强光)
local result = exs_vl53l1x.setup({scl = 31, sda = 30, range_mode = "short"})
if not result then return end
-- 远距离模式 + XSHUT 硬件复位
local result = exs_vl53l1x.setup({scl = 31, sda = 30, range_mode = "long", xshut = 32})
if not result then return end
-- 串扰校准值 + GPIO1 中断回调
local result = exs_vl53l1x.setup({scl = 31, sda = 30, xtalk_offset = 45, int1 = {int_gpio = 10, cb = data_cb}})
if not result then return end
4.2 exs_vl53l1x.get_data()
功能
读取一帧测距数据。等待数据就绪后读取,自动跳过无效帧(首次启动/唤醒后的第一帧),读取后自动触发下一次测量。
参数
无
返回值
local data = exs_vl53l1x.get_data()
data
含义说明:测距数据表,失败返回 nil
数据类型:table 或 nil
取值范围:返回table 包含以下值
{
参数含义:测距距离
数据类型:number
取值范围:4~4000,单位 mm
注意事项:低于 4cm 时值不准确
返回示例:235
data.distance ,
参数含义:测距状态码,0 表示数据可靠
数据类型:number
取值范围:0(测距成功)、1(Sigma 失效)、2(信号失效)、3(目标太近)、
4(相位超出范围)、5(硬件故障)、6(测距成功但未绕行检查)、
7(相位绕行)、8(处理失败)、9(串扰信号)、10(同步中断)、
11(合并脉冲)、12(信号弱)、13(最小距离失败)、14(范围无效)
注意事项:status=0 为测距成功,数据可靠
返回示例:0
data.status ,
参数含义:测距状态描述
数据类型:string
取值范围:对应 status 的中文描述
返回示例:"测距成功"
data.status_str ,
参数含义:帧计数
数据类型:number
取值范围:每次测距递增,0~255 循环
注意事项:stream=0 的帧为无效帧,会自动跳过
返回示例:15
data.stream_count ,
}
返回示例:{distance = 235, status = 0, status_str = "测距成功", stream_count = 15}
示例
-- 读取测距数据
local data = exs_vl53l1x.get_data()
if data and data.status == 0 then -- 只使用有效数据
log.info("距离:", data.distance, "mm")
end
4.3 exs_vl53l1x.get_int_flag()
功能
查询 GPIO1 中断触发标志,查询后自动清除。适合不传 cb 时轮询用。
使用 GPIO1 时,get_data() 内部改读 GPIO 引脚电平代替 I2C 轮询,响应更快。
参数
无
返回值
local flag = exs_vl53l1x.get_int_flag()
flag
含义说明:是否触发中断
数据类型:boolean
取值范围:true(有中断),false(无中断)
注意事项:查询后自动清除标志
返回示例:true
示例
-- 轮询任务
local function poll_task()
while true do
if exs_vl53l1x.get_int_flag() then -- 检查是否有新数据
local data = exs_vl53l1x.get_data()
if data then
log.info(string.format("距离:%dmm 状态=%s", data.distance, data.status_str))
end
end
sys.wait(1)
end
end
sys.taskInit(poll_task)
-- 注册中断引脚(不传 cb)
exs_vl53l1x.setup({scl = 31, sda = 30, int1 = {int_gpio = 10}})
4.4 exs_vl53l1x.sleep()
功能
进入软件待机,功耗约 6μA。调用后自动停止测距,保持现有配置。
参数
无
返回值
无
示例
-- 休眠(自动停止测距)
exs_vl53l1x.sleep()
4.5 exs_vl53l1x.wakeup()
功能
从软件待机唤醒,自动恢复测距。与 sleep() 配对使用。
参数
无
返回值
local ok = exs_vl53l1x.wakeup()
ok
含义说明:唤醒是否成功
数据类型:boolean
取值范围:true(成功),false(失败,未执行 setup 时返回 false)
返回示例:true
示例
-- 唤醒
local ok = exs_vl53l1x.wakeup()
if ok then
sys.wait(200)
local data = exs_vl53l1x.get_data()
end
4.6 exs_vl53l1x.close()
功能
关闭传感器。停止测距并清空内部状态,再次使用前需要重新 setup。
参数
无
返回值
无
示例
-- 关闭传感器
exs_vl53l1x.close()
4.7 exs_vl53l1x.calibrate_xtalk(config)
功能
执行串扰校准。当传感器加了保护玻璃或外壳时,激光在玻璃表面反射会产生串扰信号,导致远距离测距不准。校准后数据更准确。
什么时候需要做: - 传感器装在带玻璃面板的外壳内 - 更换了不同厚度的保护玻璃 - 测量距离不准确或经常报信号失效
校准前准备: - 在传感器正前方 400mm 处放一张纯白纸板,环境光不要太强。校准过程约 2~4 秒。
参数
config
参数含义:校准配置表
数据类型:table
取值范围:
{
参数含义:SCL 时钟引脚 GPIO 编号
数据类型:number
取值范围:有效的 GPIO 编号
是否必选:推荐传入(用于总线恢复)
参数示例:31
config.scl ,
参数含义:SDA 数据引脚 GPIO 编号
数据类型:number
取值范围:有效的 GPIO 编号
是否必选:推荐传入
参数示例:30
config.sda ,
参数含义:硬件 I2C 总线 ID
数据类型:number
取值范围:有效的 I2C 总线编号
是否必选:可选,不传 scl/sda 时使用
参数示例:0
config.i2c_id ,
参数含义:目标距离(传感器到校准平面的距离)
数据类型:number
取值范围:100~1000,单位 mm
是否必选:否
注意事项:默认 400,建议与官方校准距离一致
参数示例:400
config.target_distance_mm ,
参数含义:采样帧数
数据类型:number
取值范围:10~200
是否必选:否
注意事项:默认 50。帧数越大越稳定,但校准时间越长(约 2~5 秒/50 帧)
参数示例:100
config.samples ,
}
是否必选:是
参数示例:
exs_vl53l1x.calibrate_xtalk({scl = 31, sda = 30})
返回值
local xtalk = exs_vl53l1x.calibrate_xtalk(config)
xtalk
含义说明:串扰偏移值
数据类型:number 或 nil
取值范围:0~65535
注意事项:有效采样帧数不足 10 帧时返回 nil。返回值可直接传给 setup({xtalk_offset = xtalk})
返回示例:45
示例
-- 执行串扰校准
local xtalk = exs_vl53l1x.calibrate_xtalk({scl = 31, sda = 30})
if xtalk then
log.info("校准完成, xtalk=" .. xtalk)
-- 用校准值重新初始化
exs_vl53l1x.setup({scl = 31, sda = 30, xtalk_offset = xtalk})
end
4.8 exs_vl53l1x.version()
功能
获取库版本号。
参数
无
返回值
local ver = exs_vl53l1x.version()
ver
含义说明:版本号字符串
数据类型:string
取值范围:格式 "yyyymmddhhmm",表示 yyyy年mm月dd日hh时mm分发布的版本
返回示例:"202607201200"
示例
-- 获取版本号
local ver = exs_vl53l1x.version()
log.info("exs_vl53l1x", "版本:", ver)
五、版本更新说明
版本号:202607211200
- 更新时间:2026-07-21
- 更新内容: 支持软件I2C、硬件I2C初始化 支持标准测距、三档模式切换(standard/short/long) 支持I2C 总线卡死自动检测与恢复 支持睡眠/唤醒/关闭,支持低功耗待机
六、产品支持说明
所有支持 luatos 二次开发的模块,具体可以查看选型手册。