跳转至

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

  1. 更新时间:2026-07-21
  2. 更新内容: 支持软件I2C、硬件I2C初始化 支持标准测距、三档模式切换(standard/short/long) 支持I2C 总线卡死自动检测与恢复 支持睡眠/唤醒/关闭,支持低功耗待机

六、产品支持说明

所有支持 luatos 二次开发的模块,具体可以查看选型手册

AI问答/AI搜索