Hi3061M与VL53L0X激光测距IIC通信详解(兼容多种MCU)

目录

  • 前言
  • 资源下载
  • 移植
  • 基本使用
  • 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;
    } 
    

    作者:NS_ice

    物联沃分享整理
    物联沃-IOTWORD物联网 » Hi3061M与VL53L0X激光测距IIC通信详解(兼容多种MCU)

    发表回复