TOF 测距传感器 VL6180 传感器修改测量范围 ...... by 矜辰所致
前言
之前写过一篇关于ToF 测距传感器 VL6180 使用的文章:
ToF 测距传感器 VL6180 使用踩坑记(软件 I2C)
之后有粉丝问我如何修改测量距离,当时我只回答让粉丝去找一下寄存器,最近找了点时间自己来测试了一下,发现其实直接找手册好像不那么容易解决问题,于是自己还是想着得写一篇文章来说明一下,所以本文的内容就是如何修改 VL6180 的测量距离。
我是矜辰所致,全网同名,尽量用心写好每一系列文章,不浮夸,不将就,认真对待学知识的我们,矜辰所致,金石为开!
目录
- 前言
- 一、 参考资料
- 二、代码移植说明
- 结语
一、 参考资料
在官方手册中,我们可以查到, 对于 VL6180 的测量范围说明如下:
默认情况下,缩放因子为1 ,测距的范围最大是 20cm ,我们想要测量更大需要进行设置 。
但是对于如何修改,其实从官方文档中我是没有找到很直接的答案,这里我还是在网上借鉴的大佬的文章:
添加链基于STM32CUBEMX驱动TOF模块VL6180与VL6180X(2)----修改测量范围描述
根据文章的指引,我也在官方的 SDK 包中找到了官方提供的修改测量范围的函数:
在本文中,我们也只需要根据根据大佬的文章和官方的API 来移植即可。
我自己测试起来,也遇到了一些小疑问,但是后来还是成功实现修改距离的,下面我来一一说明。
二、代码移植说明
我们移植的只有一个函数,就是 int VL6180_UpscaleSetScaling(VL6180Dev_t dev, uint8_t scaling)
这个函数,在大佬的文章中,也说到了,官方的函数相对 “ 复杂 ”,在文章中大佬也给出了简化后的代码。
首先,我们我们根据文章中的指示,该定义的定于,该写的写:
uint8 scaling;
uint16 ScalerValues[] = {0, 253, 127, 84};
void VL6180x_UpscaleSetScaling(uint8 new_scaling)
{
uint8 DefaultCrosstalkValidHeight = 20; // default value of SYSRANGE__CROSSTALK_VALID_HEIGHT
// do nothing if scaling value is invalid
if (new_scaling < 1 || new_scaling > 3) return;
scaling = new_scaling;
VL6180X_WriteByte_16Bit(RANGE_SCALER,ScalerValues[scaling]);
对于博主来说,产品上只会有一个 VL6180 探头,所以在代码中的函数,并没有 add 地址这个参数,因为对我来说,地址是固定的,直接写在了代码中。如果大家测试可能 I2C 上带多个传感器,是可能出现不同地址,需要多一个参数的。
所以在我给出的示例代码中,都没有add 这个参数,大家可以从我下面的代码中也能看出来,我在写数据的函数中,写的是固定地址。
到这里有一个VL6180X_WriteByte_16Bit
,这个地方我们需要修改一下,因为在我原本的应用中并没有写 16bit 的函数,
官方的说明都是针对硬件 I2C ,我们需要使用的是软件 I2C ,所以我们自己还得写一下这个函数。 这里也很简单,直接上一下函数比较图,大家根据自己的writeByte
函数修改即可:
当然,在函数中的一些宏定义,我们可以直接从官方的 SDK 包中照样复制到自己的代码中,如下图:
然后接着往下写,有一个关键的语句:
...
VL6180X_WriteByte(add,SYSRANGE_PART_TO_PART_RANGE_OFFSET,ptp_offset / scaling);
...
这里有一个ptp_offset
,在推荐的文章中,其实也说得不是很清楚,我们无法追溯它是怎么来的,那么我们还是得去官方 API 对应的地方查看,我们找到写SYSRANGE_PART_TO_PART_RANGE_OFFSET
这个寄存器地址的地方,看一下官方是怎么处理的:
从上面我们可以看到,我们要实现的只是往SYSRANGE_PART_TO_PART_RANGE_OFFSET
这个地址写入一个值,这个值 = 某一个数值 / 我们设置的 scaling 参数。 这个值是通过 VL6180DevDataGet
得到的,那么这个 VL6180DevDataGet
是什么东西,我们直接查找,如下图:
所以这么一分析,就是这样的:
Offset = VL6180DevDataGet(dev, Part2PartOffsetNVM) / scaling;
等于
Offset = SingleVL6180DevData.Part2PartOffsetNVM / scaling;
所以我们要确定的就是 SingleVL6180DevData.Part2PartOffsetNVM
这个等于多少,我们在 vl6180_api.c
中搜索 Part2PartOffsetNVM
这个值,我们可以找到设置这个值的地方,下图中也有对应的分析:
上面代码对 Part2PartOffsetNVM
赋值的地方在 VL6180_InitData
函数中,使用了 VL6180DevDataSet
宏定义, 和 Get 一样:
VL6180DevDataSet(dev, Part2PartOffsetNVM, offset);
等于
SingleVL6180DevData.Part2PartOffsetNVM = offset;
分析到这里,我们就知道了在 官方 API 中,在初始化的时候先读取SYSRANGE_PART_TO_PART_RANGE_OFFSET
的值,保存在 Part2PartOffsetNVM
这个结构体成员中。
在我们自己的代码中,并不需要那个复杂的结构体,我直接简单的处理:
好了,解决完了这条语句,后面几条语句直接按照大佬文章来就行了。
这里直接上一下我修改的代码主要部分:
#include "vl6180.h"
uint8 u8Ack;
uint8 scaling;
uint16 ScalerValues[] = {0, 253, 127, 84};
uint8 Part2PartOffsetNVM;
uint8 VL6180X_WriteByte(uint16 reg,uint8 data1)
{
/*
防止内容太多省略
*/
}
uint8 VL6180X_WriteByte_16Bit(uint16 reg,uint16 data1)
{
/*
防止内容太多省略
*/
}
uint8 VL6180X_ReadByte(uint16 reg)
{
/*
防止内容太多省略
*/
}
void VL6180x_UpscaleSetScaling(uint8 new_scaling)
{
uint8 DefaultCrosstalkValidHeight = 20; // default value of SYSRANGE__CROSSTALK_VALID_HEIGHT
// do nothing if scaling value is invalid
if (new_scaling < 1 || new_scaling > 3) return;
scaling = new_scaling;
VL6180X_WriteByte_16Bit(RANGE_SCALER,ScalerValues[scaling]);
VL6180X_WriteByte(SYSRANGE_PART_TO_PART_RANGE_OFFSET,Part2PartOffsetNVM / scaling);
VL6180X_WriteByte(SYSRANGE_CROSSTALK_VALID_HEIGHT, DefaultCrosstalkValidHeight / scaling);
VL6180X_ReadByte(SYSRANGE_RANGE_CHECK_ENABLES);
VL6180X_WriteByte(SYSRANGE_CROSSTALK_VALID_HEIGHT, DefaultCrosstalkValidHeight / scaling);
}
uint8 VL6180X_Read_ID(void)
{
return VL6180X_ReadByte(VL6180X_REG_IDENTIFICATION_MODEL_ID);
}
uint8 VL6180X_Init(void)
{
if(VL6180X_Read_ID() == VL6180X_DEFAULT_ID)
{
/*
防止内容太多省略
*/
while(VL6180X_WriteByte(0x003e, 0x31)); //???? ALS??
// to 500ms
while(VL6180X_WriteByte(0x0014, 0x24)); // Configures interrupt on 'New Sample
// Ready threshold event'
// VL6180X_WriteByte(VL6180X_REG_SYSTEM_FRESH_OUT_OF_RESET, 0x00);
Part2PartOffsetNVM = VL6180X_ReadByte(SYSRANGE_PART_TO_PART_RANGE_OFFSET);
VL6180x_UpscaleSetScaling(3);
return 0;
}
else return 1;
}
/*
VL6180X_Read_Range 不用变,但是值得注意的是,上面VL6180x_UpscaleSetScaling(3)
得到的距离的实际值是 下面返回的 range 的值 * 3。
*/
uint8 VL6180X_Read_Range(void)
{
uint8 range = 0;
uint16 count = 0;
while(!(VL6180X_ReadByte(VL6180X_REG_RESULT_RANGE_STATUS)&0x01)); //发送 0 和 01001101 读到的是1 STM32读到的是2
while(VL6180X_WriteByte(VL6180X_REG_SYSRANGE_START,0x01)); //?????? 00011000 正常,while(0);
//???????????(New Sample Ready threshold event)
while(!(VL6180X_ReadByte(VL6180X_REG_RESULT_INTERRUPT_STATUS_GPIO)&0x04)) //01001111 读到的是0
{
count++;
if(count >= 100){
count = 0;
VL6180X_WriteByte(VL6180X_REG_SYSTEM_INTERRUPT_CLEAR,0x07);
VL6180X_WriteByte(VL6180X_REG_SYSRANGE_START,0x01);
}
}
range = VL6180X_ReadByte(VL6180X_REG_RESULT_RANGE_VAL);
while(VL6180X_WriteByte(VL6180X_REG_SYSTEM_INTERRUPT_CLEAR,0x07)); //0111b ?????????
return range;
}
至于 .h 文件,都是宏定义和 函数声明:
#ifndef _VL6180_H_
#define _VL6180_H_
#include "EO3000I_API.h"
#include "EO3000I_CFG.h"
#include <stdlib.h>
#include "i2c.h"
#define VL6180X_DEFAULT_ID 0xB4
//#define I2C_DEBUG
#define VL6180X_DEFAULT_I2C_ADDR 0x29 ///< The fixed I2C addres
/*------------------VL6180X内部寄存器------------------*/
///! Device model identification number
#define VL6180X_REG_IDENTIFICATION_MODEL_ID 0x000
///! Interrupt configuration
#define VL6180X_REG_SYSTEM_INTERRUPT_CONFIG 0x014
///! Interrupt clear bits
#define VL6180X_REG_SYSTEM_INTERRUPT_CLEAR 0x015
///! Fresh out of reset bit
#define VL6180X_REG_SYSTEM_FRESH_OUT_OF_RESET 0x016
///! Trigger Ranging
#define VL6180X_REG_SYSRANGE_START 0x018
///! Trigger Lux Reading
#define VL6180X_REG_SYSALS_START 0x038
///! Lux reading gain
#define VL6180X_REG_SYSALS_ANALOGUE_GAIN 0x03F
///! Integration period for ALS mode, high byte
#define VL6180X_REG_SYSALS_INTEGRATION_PERIOD_HI 0x040
///! Integration period for ALS mode, low byte
#define VL6180X_REG_SYSALS_INTEGRATION_PERIOD_LO 0x041
///! Specific error codes
#define VL6180X_REG_RESULT_RANGE_STATUS 0x04d
///! Interrupt status
#define VL6180X_REG_RESULT_INTERRUPT_STATUS_GPIO 0x04f
///! Light reading value
#define VL6180X_REG_RESULT_ALS_VAL 0x050
///! Ranging reading value
#define VL6180X_REG_RESULT_RANGE_VAL 0x062
#define RANGE_SCALER 0x096
#define SYSRANGE_CROSSTALK_VALID_HEIGHT 0x021
#define SYSRANGE_EARLY_CONVERGENCE_ESTIMATE 0x022
#define SYSRANGE_PART_TO_PART_RANGE_OFFSET 0x024
#define SYSRANGE_RANGE_CHECK_ENABLES 0x02D
#define VL6180X_ALS_GAIN_1 0x06 ///< 1x gain
#define VL6180X_ALS_GAIN_1_25 0x05 ///< 1.25x gain
#define VL6180X_ALS_GAIN_1_67 0x04 ///< 1.67x gain
#define VL6180X_ALS_GAIN_2_5 0x03 ///< 2.5x gain
#define VL6180X_ALS_GAIN_5 0x02 ///< 5x gain
#define VL6180X_ALS_GAIN_10 0x01 ///< 10x gain
#define VL6180X_ALS_GAIN_20 0x00 ///< 20x gain
#define VL6180X_ALS_GAIN_40 0x07 ///< 40x gain
#define VL6180X_ERROR_NONE 0 ///< Success!
#define VL6180X_ERROR_SYSERR_1 1 ///< System error
#define VL6180X_ERROR_SYSERR_5 5 ///< Sysem error
#define VL6180X_ERROR_ECEFAIL 6 ///< Early convergence estimate fail
#define VL6180X_ERROR_NOCONVERGE 7 ///< No target detected
#define VL6180X_ERROR_RANGEIGNORE 8 ///< Ignore threshold check failed
#define VL6180X_ERROR_SNR 11 ///< Ambient conditions too high
#define VL6180X_ERROR_RAWUFLOW 12 ///< Raw range algo underflow
#define VL6180X_ERROR_RAWOFLOW 13 ///< Raw range algo overflow
#define VL6180X_ERROR_RANGEUFLOW 14 ///< Raw range algo underflow
#define VL6180X_ERROR_RANGEOFLOW 15 ///< Raw range algo overflow
uint8 VL6180X_WriteByte(uint16 reg,uint8 data1);
uint8 VL6180X_Read_ID(void);
uint8 VL6180X_Init(void);
uint8 VL6180X_Read_Range(void);
uint8 VL6180X_ReadByte(uint16 reg);
#endif
在上面代码中使用过程中有一点需要说明一下, 读取函数 VL6180X_Read_Range
不用变,但是值得注意的是,因为我们设置了 VL6180x_UpscaleSetScaling(3)
,所以得到的距离实际值是 VL6180X_Read_Range
函数的返回值 * 3。
结语
到这里大家应该都知道如何修改 VL6180 传感器的测量范围,本文还是比较简单的。
好了,本文就到这里,谢谢大家!