目录
- 前言
- 资源下载
- 移植
- 基本使用
- IO配置
- 调用测量
- 总结
前言
昨晚太晚了,草草结束了上一篇,今天更新下半部分。
昨天已经讲了VL53L0X的使用流程,无非就是进行6步的效准初始化,然后配置下模式和时间,开始采样,获取数据这四个部分,都是通过调用API来实现,那么这些API哪来呢,源码呢?
这就是今天补充的内容了。
资源下载
首先要说明的是,ST提供源码包和相关资料的下载,有一丢丢麻烦,但是也还好。ST官方链接
里面包含源码和一些其他的资料。
另外你还需要一个API手册,API使用手册。
第一个ST官方链接打开会出现上面界面,点击get software即可跳转到下载源码的位置,可以登录下载也可以通过邮箱,发一封邮件给你提供的邮箱,然后在邮箱中点开下载链接,注意这里邮箱打开的浏览器要和你原来打开官方页面的浏览器一样,不然无法下载。
另外还要下载这个API使用手册,可以直接点API使用手册链接进行下载保存。这个链接是2022.10.25的2.0目前最新版本,后面如果有更新建议下载最新的。
此外觉得麻烦的也可以直接下载我提供的源码包。源码
里面包含2024-10-18 10:37:21下载的最新官方源码和API使用文档,以及我的移植相关代码my_vl53l0x和Hi3061M的一个使用案例。其中my_vl53l0x实现了代码的移植,基本上你只需要将这个文件添加到你的工程目录,然后修改一下vl53l0x_iic.h中的IO口配置和初始化即可,拿stm32移植举例,你需要将这个文件下的源码导入工程,当然还要配置.h,然后你需要将IIC通讯和x_shutIO口配置好初始化,和电平变化操作进行转换为stm32上的形式即可。
移植
移植主要就是放入源码, 该API适配的过程,要删删减减一些东西,不要的东西可以丢掉什么的,具体过程其实我自己也没记,反正就是删删改改,参考了正点原子的代码。
此外想要自己移植可以网上找资料看文档, 也可以看这篇文章https://blog.csdn.net/qlexcel/article/details/106154743
写的东西比较详细吧,但是感觉有点杂乱,又很长,我当时就不是很想看了,后面简单浏览了一遍,确实比我还是详细很多的,不过我这个主打一个简单高效的使用吧。
基本使用
首先下载了我提供的源码,放到gitee上了,和上面一样的。
IO配置
这个里面的就是相关包,放入你的工程文件,每个目录下包含inc和src,stm32需要包含头文件的分别包含进入即可。
导入文件后,需要修改vl53l0x_iic.h中的IO口配置和初始化
上图红框部分了,就是IIC通讯时的引脚电平设置,拿STM32举例就是改为:
//库函数
GPIO_SetBits(GPIOB,GPIO_Pin_10);//PB10 输出高
GPIO_ResetBits(GPIOB,GPIO_Pin_10);//PB10 输出低
//hal库
HAL_GPIO_WritePin(ATK_MS53L0_XSH_GPIO_PORT, ATK_MS53L0_XSH_GPIO_PIN, GPIO_PIN_SET) :
HAL_GPIO_WritePin(ATK_MS53L0_XSH_GPIO_PORT, ATK_MS53L0_XSH_GPIO_PIN, GPIO_PIN_RESET);
其他的MCU也是同样的原理,配置好这个就好。IO口的引脚电平设置,还有一个就是IO口的方向,和读取IO口的数据,这部分在IIC读和ACK读的时候是需要用到的。
另外IO口的初始化IIC两个引脚和VL53L0X_XSH复位引脚,这个IO初始化就需要自己在开始前进行初始化,上面IO口时钟和模式什么的,根据自己MCU配置。
还有IO口有关的头文件记得包含进去。
另外还有两个要修改
一个是串口打印函数,一个延时函数,us级别的
// 这里需要改为自己MCU相关的延时函数
#define vl53l0x_iic_delay(t) BASE_FUNC_DELAY_US(t)
// 这里需要改为自己MCU相关的延时函数
#define print_log DBG_PRINTF
调用测量
上面配置好后,我封装了一下连续测量的一个使用函数,在vl53l0x.c中,你只需要在main.c中包含vl53l0x.h,然后调用其中的函数就可以实现vl53l0x的测量了。vl53l0x.h中主要包含这四个函数:
// 初始化,包含硬件复位,芯片初次IIC通讯和设备验证,6步初始化校验,配置模式和时间。
void vl53l0x_init(void);
// 开始测量
void vl53l0x_start(void);
// 停止测量
void vl53l0x_stop(void);
// 获取测量距离,单位mm
unsigned short get_distance(void);
main函数中调用这四个函数即可实现功能,注意 配置vl53l0x初始化vl53l0x_init ,在初始化之前最好不要开中断(上面定时器中断什么的),可能会扰乱IIC通讯
因为这个初始化过程包含了IIC通讯过程,另外如果初始化成功了后面基本没问题(会有对应的输出),如果失败了那么会卡在这里,因为里面有个死循环。其他的配置可以进去vl53l0x.c在相应的函数实现中直接修改,代码有详细注释。
初始化后,调用vl53l0x_start开始测量,相当于启动按钮,这默认的模式是连续测量,一次时间66ms,vl53l0x.c中可以修改,这时候设备就会不断测量并将结果保存,你需要读取结果时调用get_distance即可得到测量结果,单位为mm。注意这里要开启了测量,因为里面有检查设备是否完成测量的循环,如果没有完成测量就会卡在循环那里,所以确保调用get_distance前,调用了vl53l0x_start。如果你想停止测量,因为是连续测量模式,可以调用vl53l0x_stop。
main.c使用样例:
#include "vl53l0x.h"
//其他相关头文件
unsigned short s_distance;
void main(){
// 注意需要先进行三个IO口的初始化
// io_config_init();
// 当然如果你用中断的方式,就是四个,还有一个外部中断IO口 vl53l0x_init();
// time_start() ;定时器中断什么的最好在之后开启。vl53l0x_start() ;
// 这里就可以开启测量了,毕竟测量是芯片在做并不消耗mcu资源,
// 当然如果从功率的角度就另说 ,自行在地方调用 while(1){
// 主循环s_distance = get_distance() ;//这是轮询的方式获取测量结果
// printf("ranging result s_distance = %d\r\n",s_distance) ;//当然如果是中断的方式就是另外的实现了,但是要记得清除芯片中断标识 //vl53l0x.c的注释中有提到 }
}
总结
最后总结下流程:
1.下载 源码
2.将my_vl53l0x文件夹导入工程
3.修改vl53l0x_iic.h文件中的函数
4.main.c导入vl53l0x.h,参照样例调用函数,实现测量。
如何,还是很简单,很方便的吧,如果觉得还不错,点赞关注支持一下吧,哈哈~
另外附上vl53l0x.c文件源码
#include "vl53l0x.h"
#include "vl53l0x_iic.h"
#include "vl53l0x_api.h"#define CUSTOM_DEV_IIC_ADDDR (VL53L0X_IIC_ADDR) /*自定义IICַ地址*/
#define DEMO_DEVICE_MODE VL53L0X_DEVICEMODE_CONTINUOUS_RANGING /* 连续测量模式 */
#define DEMO_BUDGET_TIME (66*1000) /* 测量时间 *//* VL53L0X设备结构体 */
static VL53L0X_Dev_t demo_dev = {.I2cDevAddr = VL53L0X_IIC_ADDR, /* 上电默认IIC通讯地址ַ*/
};static void device_detect(VL53L0X_DEV dev, uint8_t iic_addr)
{uint16_t module_id = 0;VL53L0X_Error status;/*** 获取设备ID,身份鉴别* 另外可以相当于一次通讯验证,IIC是否可以正常通讯* */status = VL53L0X_RdWord(dev, VL53L0X_REG_IDENTIFICATION_MODEL_ID, &module_id);// DBG_PRINTF("ATK-MS53L0 ID: %d,status: %d\r\n",module_id,status);if (module_id != VL53L0X_MODULE_ID){print_log("ATK-MS53L0 Detect Failed!\r\n");while (1){// 如果通讯失败,就会卡在这个死循环中。}} /*** 改变IIC设备地址* 如果你想改变IIC设备地址,有多个设备使用时,可用此API* 上电默认的地址是0x29,可以自己设置IIC地址 */if (iic_addr != dev->I2cDevAddr){VL53L0X_SetDeviceAddress(dev, iic_addr << 1);dev->I2cDevAddr = iic_addr;print_log("Change IIC address success! IIC Address: 0x%x\r\n",iic_addr);}else{print_log("Default IIC Address: 0x%x\r\n",iic_addr);}
}/*** 设备配置:效准和初始化* 根据手册在测量前有一系列初始化和效准过程,保证测量精度*/
static void device_init(VL53L0X_DEV dev)
{uint8_t vhvsettings;uint8_t phasecal;uint32_t refspadcount;uint8_t isaperturespads;// 设备初始化 VL53L0X_DataInit(dev);// 加载特殊配置VL53L0X_StaticInit(dev);// Spad(单光子雪崩二极管)效准,用来对返射会的IR光进行测量的VL53L0X_PerformRefSpadManagement(dev, &refspadcount, &isaperturespads);/*温度效准*/// VL53L0X_PerformRefCalibration(dev, &vhvsettings, &phasecal); /*偏移效准*/// VL53L0X_PerformOffsetCalibration();/*串扰效准*/// VL53L0X_PerformXTalkCalibration();/**设置工作模式* 有三种工作模式* 单次测量 0* 连续测量 1* 连续延时测量 3*/VL53L0X_SetDeviceMode(dev, DEMO_DEVICE_MODE);/**设置测量时间* 默认时间是33ms,最小的时间是20ms* 这个会涉及到准确率,太快,准确率会有所下降* 增加测量时间会提高准确率* 测量时间增加到2倍,测量的标准差减少到根号2*/VL53L0X_SetMeasurementTimingBudgetMicroSeconds(dev, DEMO_BUDGET_TIME);
}/***/
void vl53l0x_init(void)
{uint8_t ret;VL53L0X_RangingMeasurementData_t data;vl53l0x_hw_reset(); //使能,设置 XSHUT引脚为高电平(低电平表示关闭)device_detect(&demo_dev, CUSTOM_DEV_IIC_ADDDR); /*首次通讯验证和设备验证*/device_init(&demo_dev); /*设备初始化-会设置测试时间(精确相关)和设备工作模式*/print_log("VL53L0X init Succedded!\r\n");// /*开始测量*/// VL53L0X_StartMeasurement(&demo_dev);// while (1)// {// /*检查是否完成一次测量*/// do {// VL53L0X_GetMeasurementDataReady(&demo_dev, &ret);// } while (ret != 1); // /**清除中断// * 如果使用中断的方式,通过连接中断引脚进行判断,进入中断后需要清除中断// * 这里使用的是轮询的方式,所以可以不需要// */// // VL53L0X_ClearInterruptMask(&demo_dev, 0);// /*获取测量结果*/// VL53L0X_GetRangingMeasurementData(&demo_dev, &data);// /*输出测量结果(单位mm)*/// DBG_PRINTF("Distance: %dmm\r\n", data.RangeMilliMeter);// }
}
// 开始测量
void vl53l0x_start(void){/*开始测量*/VL53L0X_StartMeasurement(&demo_dev);print_log("VL53L0X start ranging!\r\n");
}
// 停止测量---连续测量模式下
void vl53l0x_stop(void){/*开始测量*/VL53L0X_StopMeasurement(&demo_dev);print_log("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;
}