python_xhb 2023-10-03 14:25 采纳率: 100%
浏览 12
已结题

VL53L0X激光测距器能否使用51单片机

VL53L0X激光测距器能否使用51单片机接受

有没有它的库文件,和51单片机的

keil开发

  • 写回答

1条回答 默认 最新

  • CSDN-Ada助手 CSDN-AI 官方账号 2023-10-03 16:03
    关注

    【相关推荐】



    • 这篇博客: 两路VL53L0X激光测距传感器的使用中的 两个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);	 	 //串口1
      
       	LED_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);	//初始化引脚,地址,设备,EEPROM
      	vl53l0x_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----PB4
      	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;	           //端口配置
          GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;       //推挽输出
          GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;      //IO口速度为50MHz
          GPIO_Init(GPIOB, &GPIO_InitStructure);				   //根据设定参数初始化GPIOB
      	GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);		//禁止JTAG,从而PB4可以当做普通IO口
      	//XSH2----PC9
      	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;	           //端口配置
          GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;       //推挽输出
          GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;      //IO口速度为50MHz
          GPIO_Init(GPIOC, &GPIO_InitStructure);				   	
      	//失能片选信号
      	VL53L0X_Xshut1=0;	//失能VL53L0X
      	VL53L0X_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引脚,因此这里需要进行引脚重映射;


    如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

问题事件

  • 系统已结题 2月5日
  • 已采纳回答 1月28日
  • 创建了问题 10月3日

悬赏问题

  • ¥15 BP神经网络控制倒立摆
  • ¥20 要这个数学建模编程的代码 并且能完整允许出来结果 完整的过程和数据的结果
  • ¥15 html5+css和javascript有人可以帮吗?图片要怎么插入代码里面啊
  • ¥30 Unity接入微信SDK 无法开启摄像头
  • ¥20 有偿 写代码 要用特定的软件anaconda 里的jvpyter 用python3写
  • ¥20 cad图纸,chx-3六轴码垛机器人
  • ¥15 移动摄像头专网需要解vlan
  • ¥20 access多表提取相同字段数据并合并
  • ¥20 基于MSP430f5529的MPU6050驱动,求出欧拉角
  • ¥20 Java-Oj-桌布的计算