两个VL53L0X激光测距传感器的使用

序言
最近在项目中需要用到VL53L0X激光传感器进行测距,于是大概的研究了一下。开始使用的是正点原子的例程,但是项目中要使用到两个,于是乎对其进行了部分更改移植,目前来说在自己画的板子上(STM32F103RCT6)能够正常运行,但是中间也是弄了好几天,目前来看,问题都是出在很多小问题上,因此在这里做个总结。

首先将我使用到的相关参考资料在这里贴出来,有需要的伙伴可以去看一下,这里我就不重复他们资料里面的问题了,只是将我使用过程中所遇到的问题指出来说一下

参考资料
1、一个VL53L0X激光测距:正点原子的Vl53L0X激光测距传感器的例程, 可以自己移步到这里下载:正点原子激光测距传感器
2、四个VL53L0X激光测距:四路Vl53L0X激光测距

问题1:
问题描述
由于我是结合了这两份资料来进行移植修改的,因此,程序代码多少和这两份代码都有一些差异。首先是我只使用一个VL53L0X来进行测距,发现串口总是打印接口错误

问题原因
确实就如返回的错误状态所说,接口错误,也就是说,自己画的板子,接口和程序里面的不匹配,导致初始化总是失败,这里的接口错误可能有好几个地方:一是AT24C02的模拟IIC引脚初始化和位带操作这里没有匹配;二是VL53L0X的模拟IIC和片选引脚XSH没有配置对,这里一定要多仔细一点,只要是报接口错误,多半都是要么没有初始化,要么宏定义(位带操作)没有修改,或者是没有开启相应的时钟等

问题2:
问题描述
在修改了所有的引脚定义以后,初始化成功。但是发现又有一个新的问题,那就是测量数据总是异常,一会儿是7、8,一会儿又跳变到65530等较大的数字;有时候确是120mm以内正常,超过以后就数值异常。

问题原因
这个问题可能有两个原因,第一个就是没有校准,所以导致测量数据异常,重新进行校准即可;这里还有第二个原因,也是困扰我两天的问题,这里贴出来。前面说过,我是结合了两份代码进行修改的,因此很多地方就是两份代码都用到过,例如这里:
原子的测量函数:

//VL53L0X 单次距离测量函数
//dev:设备I2C参数结构体
//pdata:保存测量数据结构体
VL53L0X_Error vl53l0x_start_single_test(VL53L0X_Dev_t *dev,VL53L0X_RangingMeasurementData_t *pdata,char *buf)
{VL53L0X_Error status = VL53L0X_ERROR_NONE;uint8_t RangeStatus;    status = VL53L0X_PerformSingleRangingMeasurement(dev, pdata);//执行单次测距并获取测距测量数据if(status !=VL53L0X_ERROR_NONE) return status;RangeStatus = pdata->RangeStatus;//获取当前测量状态memset(buf,0x00,VL53L0X_MAX_STRING_LENGTH);VL53L0X_GetRangeStatusString(RangeStatus,buf);//根据测量状态读取状态字符串Distance_data = pdata->RangeMilliMeter;//保存最近一次测距测量数据return status;
}

另一份代码的测量函数:

//执行单次测量
uint16_t vl53l0x_start_single_test(VL53L0X_Dev_t *pdev,VL53L0X_RangingMeasurementData_t *pdata)
{int i = 0, j = 0, sum = 0;VL53L0X_Error status = VL53L0X_ERROR_NONE;if(vl53l0x_status != VL53L0X_ERROR_NONE)return vl53l0x_status;status = VL53L0X_PerformSingleRangingMeasurement(pdev, pdata);   //VL53L0X执行单一测量范围if(status != VL53L0X_ERROR_NONE) {printf("error:Call of VL53L0X_PerformSingleRangingMeasurement\n");return status;}for(i = 0; i < 5; i++)   //这里的代码估计是想要滤波之类的,但是好像没用,可以直接删除sum += pdata->RangeMilliMeter;    pdata->RangeMilliMeter = sum / 5;   return pdata->RangeMilliMeter;
}

这里暂时不讨论函数的内容,只看返回值,大家可以发现原子的返回值是状态,而该代码的返回值直接就是测得的距离值。而我的问题正好出在这里,我在原子的代码基础上进行更改,但是返回值改成了测量数据,从而导致我的测量距离只有120mm,大于120mm以后,数据就变成了65530等较大的数字。原因就在返回值这里,原子哥的函数返回值类型是u8类型,而实际的测量数据则是u16的类型,从而导致返回的数据在大于某个数值以后,就将低位给省略了,因此导致错误。所以大家一定要注意函数返回值和实际返回值的数据类型是否匹配。

问题3:
问题描述
在将上面两个问题都解决以后,将两个VL53L0X都接入板子,发现总是只有最后一个才能正常工作。

问题原因
这个问题原子哥其实说过。正点原子的VL53L0用户手册上也写明了再次使能时设备地址会恢复为0x52,这是一个坑,一定要注意
但是由于他的历程只有一个传感器,因此就不存在这个问题,所以大家如果使用多个VL53L0X时,在初始化的时候不能按照原子哥的初始化步骤来,一定要先将IIC和所有的VL53L0X片选引脚XSH拉低,然后逐个开启(拉高)片选引脚XSH,在使能了片选引脚以后,就不能再次将该引脚拉低,否则就只有最后一个才能工作(最后一个是正常初始化,相当于只有一个)

这里贴出主要代码,没有贴出来的部分几乎都是原子的例程代码,如校准和模式设定等函数。想要工程文件的朋友可以直接移步到文末下载
代码:
主函数:

int main(void)
{   delay_init();            //延时函数初始化    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);    //设置NVIC中断分组2:2位抢占优先级,2位响应优先级Uart1_init(115200);         //串口1LED_Init();                   //LED端口初始化  OLED_Init();VL53L0X_Init();         //vl53l0x初始化    OLED_ShowString(0,0,"Dis[0]:",16);OLED_ShowString(0,16,"Dis[1]:",16);OLED_Refresh_Gram();   //死循环while(1){          VL53L0x_GetDistance();      //获取距离值OLED_ShowNum(80,0,Distancebuff[0],5,16);//显示ASCII字符的码值 OLED_ShowNum(80,16,Distancebuff[1],5,16);//显示ASCII字符的码值   OLED_Refresh_Gram();        //更新显示到OLED                                 }
}

初始化函数:

void VL53L0X_Init(void)
{       AT24CXX_Init();             //EEPROM的IIC引脚SCL、SDA初始化    while(AT24CXX_Check()){OLED_ShowString(0,0,"NO 24C02",16);        OLED_Refresh_Gram();LED1 =!LED1;delay_ms(500);}VL53L0X_GPIO_init();            //这里一定注意!在引脚初始化时要先将所有的片选失能,然后在初始化时再逐一使能开启!否则其地址就变成了默认值vl53l0x_init(&vl53l0x_dev0,0);   //初始化引脚,地址,设备,EEPROMvl53l0x_init(&vl53l0x_dev1,1); //初始化引脚,地址,设备,EEPROM
}
//VL53L0X引脚初始化
void VL53L0X_GPIO_init(void)
{GPIO_InitTypeDef   GPIO_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);    //使能AFIO时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE); //使能GPIOC时钟//IIC引脚GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7|GPIO_Pin_8;  //端口配置GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ;       //推挽输出GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;       //50Mhz速度GPIO_Init(GPIOC, &GPIO_InitStructure);GPIO_SetBits(GPIOC,GPIO_Pin_7|GPIO_Pin_8);// 输出高  //片选//XSH1----PB4GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;            //端口配置GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;       //推挽输出GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;      //IO口速度为50MHzGPIO_Init(GPIOB, &GPIO_InitStructure);                 //根据设定参数初始化GPIOBGPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);      //禁止JTAG,从而PB4可以当做普通IO口//XSH2----PC9GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;             //端口配置GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;       //推挽输出GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;      //IO口速度为50MHzGPIO_Init(GPIOC, &GPIO_InitStructure);                  //失能片选信号VL53L0X_Xshut1=0;  //失能VL53L0XVL53L0X_Xshut2=0;delay_ms(20);
}
//初始化vl53l0x
//dev:设备I2C参数结构体
VL53L0X_Error vl53l0x_init(VL53L0X_Dev_t *dev,uint8_t VL53L0X_x_id)
{VL53L0X_Error    Status     = VL53L0X_ERROR_NONE; //状态定义为0,没有错误VL53L0X_Dev_t     *pMyDevice = dev;                    //这里注意是指针,是地址的传递//对传感器的寄存器内容进行初始化---------------------------------------------pMyDevice->I2cDevAddr       = VL53L0X_Addr;//I2C地址(上电默认0x52)pMyDevice->comms_type       = 1;           //I2C通信模式pMyDevice->comms_speed_khz  = 400;    //I2C通信速率//根据传入的ID不同,对不同的传感器进行初始化操作switch(VL53L0X_x_id){case 0:VL53L0X_Xshut1=1; //使能片选delay_ms(20);vl53l0x_Addr_set(pMyDevice,0x54);    //重新设定地址    AT24CXX_Read(50,(u8*)&Vl53l0x_data_1,sizeof(_vl53l0x_adjust));//读取24c02保存的校准数据,若已校准 Vl53l0x_data_1.adjustok==0xAA if(Vl53l0x_data_1.adjustok==0xAA)//已校准AjustOK_1=1;   else //没校准  AjustOK_1=0;break;     case 1:VL53L0X_Xshut2=1;//这里之所以在初始化第二个传感器的时候没有失能第一个,是因为第一个的地址已经变化了,但是第二个的地址仍然是默认地址delay_ms(20);vl53l0x_Addr_set(pMyDevice,0x56); AT24CXX_Read(100,(u8*)&Vl53l0x_data_2,sizeof(_vl53l0x_adjust));if(Vl53l0x_data_2.adjustok==0xAA)//已校准AjustOK_2=1;    else //没校准  AjustOK_2=0;       break;}//设置传感器地址、设备初始化、获取设备信息、读取EEPORM数据//设备上电初始化Status = VL53L0X_DataInit(pMyDevice);     if(Status!=VL53L0X_ERROR_NONE) goto error;delay_ms(2);//获取设备ID信息Status = VL53L0X_GetDeviceInfo(pMyDevice,&vl53l0x_dev_info);  if(Status!=VL53L0X_ERROR_NONE) goto error;//校准--在第一次校准以后手动屏蔽
//  vl53l0x_adjust(pMyDevice,VL53L0X_x_id); //模式设定vl53l0x_set_mode(pMyDevice,0,VL53L0X_x_id);   error:if(Status!=VL53L0X_ERROR_NONE) {print_pal_error(Status);//打印错误信息return Status;}  return Status;
}

获取距离值:

//VL53L0X获取距离程序
void VL53L0x_GetDistance(void)
{       Distancebuff[0] = vl53l0x_start_single_test(&vl53l0x_dev0,&vl53l0x_data);Distancebuff[1] = vl53l0x_start_single_test(&vl53l0x_dev1,&vl53l0x_data);
}
VL53L0X_Error vl53l0x_start_single_test(VL53L0X_Dev_t *dev, VL53L0X_RangingMeasurementData_t *pdata)
{VL53L0X_Error status = VL53L0X_ERROR_NONE;uint8_t RangeStatus;status = VL53L0X_PerformSingleRangingMeasurement(dev, pdata);//执行单次测距并获取测距测量数据if(status != VL53L0X_ERROR_NONE) return status;
//    RangeStatus = pdata->RangeStatus;//获取当前测量状态
//    memset(buf, 0x00, VL53L0X_MAX_STRING_LENGTH);
//    VL53L0X_GetRangeStatusString(RangeStatus, buf); //根据测量状态读取状态字符串
//    printf("State;%i \r\n",RangeStatus);//打印测量状态return pdata->RangeMilliMeter;
}

工程文件
最后将我的工程代码放出来,大家有积分的可以到这里去下载:
VL53L0X激光测距
没有积分的可以留言发邮箱。主要代码都在画圈这几个文件中。另外,我也是新手,水平有限,欢迎各位朋友留言讨论,大佬轻喷。

注意事项:
1、在实际使用的时候一般不需要原子哥里面的复位函数,可以将其屏蔽;
2、该工程只使用了普通测量模式,需要中断模式的大家自行添加;
3、因为我这里使用的AT24C04,因此在检查有无EEPROM的函数里面大家自己根据自己的板子改一下地址;
4、另外其中一个VL53L0X使用到了PB4引脚,因此这里需要进行引脚重映射;

两路VL53L0X激光测距传感器的使用相关推荐

  1. shineblink VL53L0X激光测距传感器

    VL53L0X激光测距 一.本例程实现功能 二.VL53L0X传感器介绍 三.传感器性能描述 四. 传感器工作模式配置说明 五.接线图 七.完整代码 八.代码运行结果 九.关于校准 一.本例程实现功能 ...

  2. 工赛-记录2-----四路vl53l0x激光测距

    四路vl53l0x激光测距 一开始对于激光测距还是很懵后来一直找资料发现大多都是一个知道我看到一个大佬修改的两路激光测距用的是正点原子的资料进行修改,我只能说正点牛逼!哈哈哈 ** 1.材料** 用的 ...

  3. Android九点阵手势识别,能量黑科技模块八-九:两路按键颜色手势魔块

    8. 两路按键魔块 模块一共有两路硅胶按键,可以检测按键是否按下.当按键按下时,对应按键背后的红色LED会亮,并且返回触发信号,按键按下事件为真.另外按键键帽上可安装乐高十字插销. 8.1. 详细介绍 ...

  4. c语言蓝牙接收6,终于搞定了通过两路蓝牙接收数据

    一直想做无线传感器,通过蓝牙来接收数据,无奈因为arduino接收串口数据的一些问题,一直搁到现在.因为学校里给学生开了选修课,所以手边有一些nano和mega可以使用,所以就做了用两个nano加上两 ...

  5. 【机器人】激光测距传感器的数据处理步骤

    激光测距传感器FT55-RLAM-800 注:这里针对我们所使用的激光测距传感器FT 55-RLAM-800,不同测距传感器处理方式不完全相同. 问: 怎么从激光测距传感器得到数据并对其测量数据进行处 ...

  6. 虹科技术 | 快速准确测量0.05m-500m--虹科dimetix激光测距传感器的优势

    引言 传统上,激光测距传感器测量飞行时差或相移.但是这些方法各有优缺点:飞行时差测量速度很快,但由于时间测量要求很高,通常不够准确.相移的测量明显更准确,但由于评估更复杂,不如飞行时差测量快.Dime ...

  7. 虹科案例 | 利用激光测距传感器进行锯齿定位

    PART ONE 应用描述 在这项应用中,两个激光测距传感器分别安装在一个凸出部分的末端的两侧,用以测量其两侧到锯齿的距离的差.一个微型控制器会按照预设,记录测量数据并提供一个方便快捷的前后位置校准的 ...

  8. STM32F103实现激光测距传感器测距WT-VL53L0 L1

    目录 本博客将采用标准库和HAL库实现 所用设备选择 引脚说明 与单片机的接线表 标准库实现 HAL库实现 本博客将采用标准库和HAL库实现 所用设备选择 单片机型号:STM32F103C8T6  激 ...

  9. 虹科案例 | Dimetix 激光测距传感器: 纸(布)卷直径与宽度的自动测量

    应用领域:造纸业 应用类型:尺寸测量/监测 想要对纸(布)卷的直径和宽度进行监测?想要寻找一款相较于弦式电位计.超声波传感器和手动卷尺测量读数,是可靠的.可重复使用的.经济的替代品?那快了解一下虹科D ...

  10. Ardunio开发实例-VL53L0X飞行时间传感器

    VL53L0X飞行时间传感器 VL53L0X是新一代的飞行时间(ToF)激光测距模块,采用当今市场上最小的封装,与传统技术不同,无论目标反射率如何,都可以提供精确的距离测量. 它可以测量高达2m的绝对 ...

最新文章

  1. python predict_Python model.predict方法代码示例
  2. java Serializable 详解
  3. 华为ap配置_第18期——AP安装常见问题和注意事项
  4. [Cocoa]深入浅出Cocoa系列
  5. mysql sys exec_mysql提权lib_mysqludf_sys执行sys_exec出现32256的问题解决办法
  6. SAP Commerce Cloud JavaScript Storefront
  7. python中导入模块队列_【每日学习】Python中模块的导入
  8. es6 filter函数的用法_Python 函数式编程指北,不只是面向对象哦!超级详细!
  9. HTML/CSS进阶
  10. php任务奖励体系,phpwind7.5完备的积分体系
  11. XSS-Game level 6
  12. 无人机倾斜摄影测量土方计算
  13. vue炫酷好看的登陆界面
  14. win10打开计算机出现马赛克,图片有马赛克怎么去除?win10给图片去除马赛克的方法...
  15. 我上传的CSDN资源无法使用的处理方法
  16. 利用 MySQLi 将PHP连接到mysql数据库,并采用MySQLi以面向对象的方式对mysql进行增删查改(CRUD)
  17. Linux磁盘管理和文件系统
  18. 和 loading 界面说 ByeBye
  19. Subsonic中使用事务
  20. POP3与SMTP协议

热门文章

  1. leaflet 把图片放到地图上L.imageTransform或者L.imageOverlay.rotated,把视频放到地图上L.videooverlay,把geoJson放到地图上,
  2. Lorenzo Von Matterhorn(暴力)(树)
  3. 手游后劲不足,“体验”会是端游发展的一张王牌吗?
  4. A Comprehensive Measurement Study of Domain Generating Malware 原文翻译
  5. 贴吧防删图应该怎么学?【万能的小胡】
  6. nyoj 题目172 小柯的图表
  7. 基于ROS的机器人设计
  8. 计算机打开远程桌面服务,如何开启Windows远程桌面服务 | 远程操作自己的电脑...
  9. iOS辅助功能Accessibility浅析
  10. 深入理解示波器探头各种作用及工作原理