Hi3061M——VL53L0X激光测距(IIC)(同样适用于其他MCU)

news2024/10/18 9:11:43

这里写目录标题

    • 前言
    • VL53L0X的简介
    • VL53L0X的初始化和效准过程的相关API
    • VL53L0X开始测量和获取测量值
    • VL53L0X移植配置
    • 结语

前言

手头正好有一个空闲的激光测距模块VL53L0X,想在Hi3061M上跑一下测距,以前并没有用过VL53L0X,想着以为还是向以前一样IIC读写寄存器就可以后面发现这个芯片是提供API的,调用API的方式来使用,在网上搜了搜资料,看着感觉好像很麻烦有好多的文件要导入,好像还要移植什么什么的,长长的API英文文档还要看,当时就想放弃了,后面认真弄了下,找了些资料其实也没那么难的。
本文主要言简意赅的介绍和实现VL53L0X的使用。

VL53L0X的简介

激光测距模块,支持电压1.6-3.5V,IIC通讯,最大速率400KHz,测量范围3cm~200cm,最快测量一次时间为20ms(准确度会受影响),33ms默认时间,测量时间加倍标准误差越小。
主要IO介绍

引脚功能
SCLIIC时钟线
SDAIIC数据线
XSHUTshutdown,高电平工作,低电平摆烂
GPIO1中断线,测量完毕触发中断,可读取测量结果

工作过程: 940nm(频段的激光为不可见光,且不危害人眼)无红光闪烁激光器,发射出激光,反射回程的IR光通过高灵敏的领先**SPAD(单光子雪崩二极管)**阵列进行测量。

VL53L0X 传感器还配有内置物理红外滤光片,可增大测量距离、较少环境光的干扰,以及对提高玻璃罩光学串扰的抗扰度。当然具体的工作实现我是不知道的啦,这个正常情况我们使用也无需知道。

此外测量模式有三种:

  • Single ranging(单次测量)
  • Continuous ranging(连续测量)
  • Continuous Timed ranging(连续定时测量)
    连续定时测量的意思就是测量后延迟固定时间在进行重复测量。

四种测量精度:

测量耗时最远测量距离典型应用
默认模式30ms1.2m(白色目标)标准
高精度200ms1.2m(白色目标)精准测量
远距离33ms2m(白色目标)黑暗条件下的远距离测量
高速度20ms1.2m(白色目标)优先速度,准确率有所下降

不同工作模式会有多加几行代码实现,通过调用相应的API实现,对应代码可以查阅API手册,在第7.2节有具体的代码实现。
一般工作在默认模式下即可,本文选择在默认模式下,此外可以通过设置单次测量时间来提高准确率。

VL53L0X的初始化和效准过程的相关API

API文档中主要讲的就是效准的过程。
总体可以分为6个部分。
API中第二章和第四章都提到了这6个部分,第二章似乎是制造生产的效准过程,而第四章是系统初始化过程。详见文档。
简单介绍一下6个部分,感觉不是高精度高要求的使用,不需要多了解。
1、设备初始化

VL53L0X_DataInit(VL53L0X_DEV dev);

2、数据初始化
允许加载特定用途的设备配置

VL53L0X_StaticInit(VL53L0X_DEV dev);

3、SPADs(单光子雪崩二极管阵列)校准
VL53L0X可能覆盖玻璃,所以需要用户自行效准,效准一次即可,数据可以进行存储。

VL53L0X_Error VL53L0X_PerformRefSpadManagement(VL53L0X_DEV Dev, uint32_t *refSpadCount,
uint8_t *isApertureSpads)

这个效准不需要特定的环境,这个API最后会输出的数字和类型会设置到设备中,可以对两个值进行存储,下次就不用在效准。
**注意:**如果设备覆盖了高反射性的物体,可能会出错,错误码为-50,这个时候需要移除物体重新效准。
4、温度效准
这个没什么好说的,校准与温度的敏感度有关的两个参数VHV 和phase cal,具体是什么我没研究。

VL53L0X_Error VL53L0X_PerformRefCalibration(VL53L0X_DEV Dev, uint8_t *pVhvSettings, uint8_t *pPhaseCal)

5、偏移校准
这个生产时校准过存在device NVM中,但是还是产品可能覆盖玻璃,导致这个值不准,需要重新效准。
这个需要自己手动校准的,但是这个意思就是误差校准,比如测量时和实际的结果存在多少mm的误差,±这个误差,大概就是这么回事,如果真想可以自己通过程序校准也一样的。

VL53L0X_Error VL53L0X_PerformOffsetCalibration(VL53L0X_DEV Dev, FixPoint1616_t CalDistanceMilliMeter, int32_t *pOffsetMicroMeter)

6、串扰校准
这个受到的影响也是,设备覆盖了玻璃,会影响测量性能,具体影响程度取决于玻璃。
这个效准似乎还分两种情况近距离和远距离,近距离有一个线性区,远距离有个曲线区域。具体大家可以查看API有相关介绍。

VL53L0X_Error VL53L0X_PerformXTalkCalibration(VL53L0X_DEV Dev,FixPoint1616_t XTalkCalDistance,
FixPoint1616_t *pXTalkCompensationRateMegaCps)

值得一提的是,这个第5、6步可以忽略,可能生产出来的时候就效准过的吧,也可能我这个模块没有覆盖玻璃,总之没有执行这两步骤可以正常初始化并使用,毕竟只是校准过程而已。

此外还有两个参数需要配置:测量模式和测量时间。
这个前面提到了这里不多介绍,相关API如下

    /**设置工作模式
     * 有三种工作模式
     * 单次测量         0
     * 连续测量         1
     * 连续延时测量     3
    */
    VL53L0X_SetDeviceMode(dev, DEMO_DEVICE_MODE);
    
    /**设置测量时间
     * 默认时间是33ms,最小的时间是20ms,注意这里参数是us,即设置20ms,需设置20*1000
     * 这个会涉及到准确率,太快,准确率会有所下降
     * 增加测量时间会提高准确率
     * 测量时间增加到2倍,测量的标准差减少到根号2
    */
    VL53L0X_SetMeasurementTimingBudgetMicroSeconds(dev, DEMO_BUDGET_TIME);

VL53L0X开始测量和获取测量值

不再过多介绍,就是调用API

// 开始测量
void vl53l0x_start(void){
    /*开始测量*/
    VL53L0X_StartMeasurement(&demo_dev);
    DBG_PRINTF("VL53L0X start ranging!\r\n");
}
// 停止测量---连续测量模式下
void vl53l0x_stop(void){
    /*开始测量*/
    VL53L0X_StopMeasurement(&demo_dev);
    DBG_PRINTF("VL53L0X stop ranging!\r\n");
}
// 获取测量结果 单位mm
unsigned short get_distance(void){

    uint8_t ret;
    VL53L0X_RangingMeasurementData_t data;
    /*检查是否完成一次测量*/
    do {
        VL53L0X_GetMeasurementDataReady(&demo_dev, &ret);
    } while (ret != 1);
    /*获取测量结果*/
    VL53L0X_GetRangingMeasurementData(&demo_dev, &data);
    return data.RangeMilliMeter;
} 

VL53L0X移植配置

VL53L0X的移植配置主要就是讲API文档中的文件放入工程中,用到的保留下,不用的删除,此外需要讲IIC的接口函数进行置换即可,换位MCU所使用的IIC。

具体需要包含的文件结构:
在这里插入图片描述
其中core是没有动过的,platform删掉了一些文件,主要需要修改的文件就**“vl53l0x_i2c_platform.c”**,可以直接复制进去,需要修改就这文件中对应的函数。
mine中是自己根据mcu实现的IIC相关代码,引脚初始化和通讯过程什么的。


#include "clock.h"
#include "debug.h"

#include <stdio.h>    // sprintf(), vsnprintf(), printf()

#ifdef _MSC_VER
#define snprintf _snprintf
#endif

#include "vl53l0x_i2c_platform.h"
#include "vl53l0x_def.h"
#include "vl53l0x_platform_log.h"

#ifdef VL53L0X_LOG_ENABLE
#define trace_print(level, ...) trace_print_module_function(TRACE_MODULE_PLATFORM, level, TRACE_FUNCTION_NONE, ##__VA_ARGS__)
#define trace_i2c(...) trace_print_module_function(TRACE_MODULE_NONE, TRACE_LEVEL_NONE, TRACE_FUNCTION_I2C, ##__VA_ARGS__)
#endif



char  debug_string[VL53L0X_MAX_STRING_LENGTH_PLT];


#define MIN_COMMS_VERSION_MAJOR     1
#define MIN_COMMS_VERSION_MINOR     8
#define MIN_COMMS_VERSION_BUILD     1
#define MIN_COMMS_VERSION_REVISION  0

#define STATUS_OK              0x00
#define STATUS_FAIL            0x01


int32_t VL53L0X_write_multi(uint8_t address, uint8_t index, uint8_t *pdata, int32_t count)
{
    int32_t status = STATUS_OK;

    int32_t i;
    
    vl53l0x_iic_start();
    vl53l0x_iic_send_byte((address << 1) | 0);
    if (vl53l0x_iic_wait_ack() == 1)
    {
        vl53l0x_iic_stop();
        return STATUS_FAIL;
    }
    vl53l0x_iic_send_byte(index);
    if (vl53l0x_iic_wait_ack() == 1)
    {
        vl53l0x_iic_stop();
        return STATUS_FAIL;
    }
    for (i=0; i<count; i++)
    {
        vl53l0x_iic_send_byte(pdata[i]);
        if (vl53l0x_iic_wait_ack() == 1)
        {
            vl53l0x_iic_stop();
            return STATUS_FAIL;
        }
    }
    vl53l0x_iic_stop();

    return status;
}

int32_t VL53L0X_read_multi(uint8_t address, uint8_t index, uint8_t *pdata, int32_t count)
{
    int32_t status = STATUS_OK;

    vl53l0x_iic_start();
    vl53l0x_iic_send_byte((address << 1) | 0);
    if (vl53l0x_iic_wait_ack() == 1)
    {
        vl53l0x_iic_stop();
        return STATUS_FAIL;
    }
    vl53l0x_iic_send_byte(index);
    if (vl53l0x_iic_wait_ack() == 1)
    {
        vl53l0x_iic_stop();
        return STATUS_FAIL;
    }
    vl53l0x_iic_stop();
    vl53l0x_iic_start();
    vl53l0x_iic_send_byte((address << 1) | 1);
    if (vl53l0x_iic_wait_ack() == 1)
    {
        vl53l0x_iic_stop();
        return STATUS_FAIL;
    }
    while (count)
    {
        *pdata = vl53l0x_iic_read_byte((count > 1) ? 1 : 0);
        count--;
        pdata++;
    }
    vl53l0x_iic_stop();


    return status;
}


int32_t VL53L0X_write_byte(uint8_t address, uint8_t index, uint8_t data)
{
    int32_t status = STATUS_OK;
    const int32_t cbyte_count = 1;

    status = VL53L0X_write_multi(address, index, &data, cbyte_count);

    return status;

}


int32_t VL53L0X_write_word(uint8_t address, uint8_t index, uint16_t data)
{
    int32_t status = STATUS_OK;

    uint8_t  buffer[BYTES_PER_WORD];

    // Split 16-bit word into MS and LS uint8_t
    buffer[0] = (uint8_t)(data >> 8);
    buffer[1] = (uint8_t)(data &  0x00FF);

    status = VL53L0X_write_multi(address, index, buffer, BYTES_PER_WORD);

    return status;

}


int32_t VL53L0X_write_dword(uint8_t address, uint8_t index, uint32_t data)
{
    int32_t status = STATUS_OK;
    uint8_t  buffer[BYTES_PER_DWORD];

    // Split 32-bit word into MS ... LS bytes
    buffer[0] = (uint8_t) (data >> 24);
    buffer[1] = (uint8_t)((data &  0x00FF0000) >> 16);
    buffer[2] = (uint8_t)((data &  0x0000FF00) >> 8);
    buffer[3] = (uint8_t) (data &  0x000000FF);

    status = VL53L0X_write_multi(address, index, buffer, BYTES_PER_DWORD);

    return status;

}


int32_t VL53L0X_read_byte(uint8_t address, uint8_t index, uint8_t *pdata)
{
    int32_t status = STATUS_OK;
    int32_t cbyte_count = 1;

    status = VL53L0X_read_multi(address, index, pdata, cbyte_count);

    return status;

}


int32_t VL53L0X_read_word(uint8_t address, uint8_t index, uint16_t *pdata)
{
    int32_t  status = STATUS_OK;
	uint8_t  buffer[BYTES_PER_WORD] = {0};

    status = VL53L0X_read_multi(address, index, buffer, BYTES_PER_WORD);
    // DBG_PRINTF("status: %d\r\n",status);
	*pdata = ((uint16_t)buffer[0]<<8) + (uint16_t)buffer[1];

    return status;

}

int32_t VL53L0X_read_dword(uint8_t address, uint8_t index, uint32_t *pdata)
{
    int32_t status = STATUS_OK;
	uint8_t  buffer[BYTES_PER_DWORD];

    status = VL53L0X_read_multi(address, index, buffer, BYTES_PER_DWORD);
    *pdata = ((uint32_t)buffer[0]<<24) + ((uint32_t)buffer[1]<<16) + ((uint32_t)buffer[2]<<8) + (uint32_t)buffer[3];

    return status;

}

int32_t VL53L0X_platform_wait_us(int32_t wait_us)
{
    int32_t status = STATUS_OK;
    float wait_ms = (float)wait_us/1000.0f;

    BASE_FUNC_DELAY_US(wait_us); 

#ifdef VL53L0X_LOG_ENABLE
    trace_i2c("Wait us : %6d\n", wait_us);
#endif

    return status;

}


int32_t VL53L0X_wait_ms(int32_t wait_ms)
{
    int32_t status = STATUS_OK;

    BASE_FUNC_DELAY_MS(wait_ms);


#ifdef VL53L0X_LOG_ENABLE
    trace_i2c("Wait ms : %6d\n", wait_ms);
#endif

    return status;

}


结语

太晚了,先下班了,具体的移植和实现,相关的代码讲解啥的明天再更,下班了下班了,感谢支持。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2217664.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

浅谈针对Nor flash状态寄存器保护位修改方法

浅谈针对Nor flash状态寄存器保护位修改 ✨最近在写QSPI驱动Nor flash过程中&#xff0c;在操作芯片的状态寄存器的时候&#xff0c;遇到的一些问题和解决办法。 &#x1f52c;操作Nor flash测试芯片&#xff1a;GD25Q64&#x1f516;以QSPI测试为例&#xff0c;SPI方式修改没有…

集成电路学习:什么是WLAN无线局域网

WLAN&#xff1a;无线局域网 WLAN&#xff0c;即无线局域网&#xff08;Wireless Local Area Network&#xff09;&#xff0c;是一种通过无线技术构建的局域网络&#xff0c;它使用无线信号传输数据&#xff0c;取代了传统有线网络中的网线连接。以下是关于WLAN的详细解释&…

Lumerical学习——优化和参数扫描(Optimization and parameter sweeps)

一、概要介绍 这部分介绍优化和参数扫描项目设定的方法。在有大量数据模拟计算过程中这个特性允许用户使处理方法自动地查找期望的参数值。 ① 创建一个参数扫描任务 ② 创建一个优化任务 ③ 创建一个良率分析任务 ⑤ 打开所选择项目的编辑窗口&#xff0c;编辑其属性…

stm32 bootloader写法

bootloader写法&#xff1a; 假设app的起始地址&#xff1a;0x08020000&#xff0c;则bootloader的范围是0x0800,0000~0x0801,FFFF。 #define APP_ADDR 0x08020000 // 应用程序首地址定义 typedef void (*APP_FUNC)(void); // 函数指针类型定义 /*main函数中调用rum_app&#x…

【Unity】Unity Shader学习笔记(八)基础纹理2:高度纹理、法线纹理、模型空间下的法线纹理、切线空间下的法线纹理光照计算

文章目录 凹凸映射法线纹理设置高度纹理&#xff08;Height Map&#xff09;法线纹理&#xff08;Normal Map&#xff09;模型空间的法线纹理切线空间的法线纹理优劣对比 切线空间下的法线纹理光照计算最终效果完整代码TANGENT语义内置宏 TANGENT_SPACE_ROTATIONObjSpaceLightD…

前缀和--一维和二维模板

前缀和 【模板】前缀和 描述 给定一个长度为n的数组a1,a2,…ana1,a2,…a**n. 接下来有q次查询, 每次查询有两个参数l, r. 对于每个询问, 请输出alal1…ara**la**l1…a**r 输入描述&#xff1a; 第一行包含两个整数n和q. 第二行包含n个整数, 表示a1,a2,…ana1,a2,…a**n.…

JavaWeb——Maven(4/8):Maven坐标,idea集成-导入maven项目(两种方式)

目录 Maven坐标 导入Maven项目 第一种方式 第二种方式 Maven坐标 Maven 坐标 是 Maven 当中资源的唯一标识。通过这个坐标&#xff0c;我们就能够唯一定位资源的位置。 Maven 坐标主要用在两个地方。第一个地方&#xff1a;我们可以使用坐标来定义项目。第二个地方&#…

CLANet:基于明场图像的跨批次细胞系识别综合框架|文献速递-基于深度学习的医学影像分类,分割与多模态应用

Title 题目 CLANet: A comprehensive framework for cross-batch cell line identificationusing brightfield images CLANet&#xff1a;基于明场图像的跨批次细胞系识别综合框架 01 文献速递介绍 细胞系鉴定&#xff08;Cell Line Authentication&#xff0c;CLA&#x…

英飞达医学影像存档与通信系统 WebUserLogin.asmx 信息泄露漏洞复现

0x01 产品简介 英飞达医学影像存档与通信系统 Picture Archiving and Communication System,它是应用在医院影像科室的系统,主要的任务就是把日常产生的各种医学影像(包括核磁,CT,超声,各种X光机,各种红外仪、显微仪等设备产生的图像)通过各种接口(模拟,DICOM,网络…

二叉树与堆讲解

目录 1.树的概念及结构 1.树的概念 2.树的相关概念 3.树的表示 2.二叉树 1.概念 2.特殊的二叉树 1.满二叉树 2.完全二叉树 3.二叉树的性质 4.二叉树的存储结构 1.顺序结构 2.链式存储 3.堆 1.堆的概念及结构 2.堆的实现 1.堆的创建 2.堆的初始化&#xff08;H…

力扣力扣力:206. 反转链表

leetcode链接&#xff1a;206. 反转链表 题目描述&#xff1a; 给你单链表的头节点 head &#xff0c;请你反转链表&#xff0c;并返回反转后的链表。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5]输出&#xff1a;[5,4,3,2,1] 示例 2&#xff1a; 输入&#xff1…

手写Spring IOC-简易版

目录 项目结构entitydaoIUserDaoUserDaoImpl serviceIUserServiceUserServiceImpl ApplicationContext 配置文件初始化 IOC 容器RunApplication 注解初始化 IOC 容器BeanAutowired Reference 项目结构 entity User Data NoArgsConstructor AllArgsConstructor Accessors(chai…

面试八股(自用)

什么是java序列化&#xff0c;什么时候需要序列化? 序列化是指将java对象转化成字节流的过程&#xff0c;反序列化是指将字节流转化成java对象的过程。 当java对象需要在网络上传输 或者 持久化到存储文件中&#xff0c;就需要对java对象进行序列化处理。 JVM的主要组成部分…

Leetcode—1242. 多线程网页爬虫【中等】Plus(多线程)

2024每日刷题&#xff08;187&#xff09; Leetcode—1242. 多线程网页爬虫 实现代码 /*** // This is the HtmlParsers API interface.* // You should not implement it, or speculate about its implementation* class HtmlParser {* public:* vector<string>…

【Java 并发编程】阻塞队列与仿真餐厅

前言 阻塞队列 (BlockingQueue) 顾名思义是一种支持阻塞操作的队列&#xff0c;因为内部机制中添加了 wait 和 notify 方法&#xff0c;所以阻塞队列具备了线程之前相互协调的功能。阻塞队列主要运用于两个场景&#xff0c;一是生产者与消费者模型&#xff0c;二是线程池。本章…

【C语言】循环嵌套:乘法表

循环嵌套&#xff0c;外层循环执行一次&#xff0c;内层循环执行i次。分别控制 在循环的过程中加一层循环。 多层循环属于循环嵌套、嵌套循环 #include <stdio.h> #include <math.h> /* 功能&#xff1a;循环嵌套 乘法表 时间&#xff1a;2024年10月 地点&#xf…

可编辑73页PPT | 企业智慧能源管控平台建设方案

荐言分享&#xff1a;随着全球能源形势的日益紧张和智能化技术的快速发展&#xff0c;企业对于能源的高效利用和精细化管理需求愈发迫切。智慧能源管控平台作为一种集成了物联网、大数据、云计算、人工智能等先进技术的综合管理系统&#xff0c;旨在帮助企业实现能源数据的实时…

【线性回归分析】:基于实验数据的模型构建与可视化

目录 线性回归分析&#xff1a;基于实验数据的模型构建与可视化 1. 数据准备 2. 构建线性回归模型 3. 可视化 数据分析的核心 构建预测模型 应用场景 预测模型中的挑战 结论 线性回归分析&#xff1a;基于实验数据的模型构建与可视化 在数据分析领域&#xff0c;线性…

永恒之蓝漏洞

MS17-010是微软于2017年3月发布的一个安全补丁&#xff0c;旨在修复Windows操作系统中的一个严重漏洞&#xff0c;该漏洞被称为“永恒之蓝”&#xff08;EternalBlue&#xff09;。这个漏洞影响了Windows的Server Message Block&#xff08;SMB&#xff09;协议&#xff0c;允许…

JavaEE-线程安全问题

1.多线程带来的的⻛险-线程安全 1.1 观察线性不安全 // 此处定义⼀个 int 类型的变量 private static int count 0;public static void main(String[] args) throws InterruptedException {Thread t1 new Thread(() -> {// 对 count 变量进⾏⾃增 5w 次for (int i 0; i…