资讯详情

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

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

最近需要在项目中使用VL53L0X激光传感器测距,大致研究。正点原子的例程开始使用,但项目中使用了两个例程,因此部分更改移植。目前,它们在自己画的板上(STM32F103RCT6)可以正常运行,但中间也做了几天几天了。目前问题很多,这里总结一下。

首先,在这里发布我使用的相关参考资料。有需要的合作伙伴可以去看看。在这里,我不会重复他们数据中的问题,只是指出我在使用过程中遇到的问题

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

: 由于我结合这两个数据进行移植和修改,程序代码与这两个代码有所不同。首先,我只用了一个VL53L0X来进行测距,发现串口总是打印接口错误

: 正如返回的错误状态所说,,也就是说,自己画的板,接口和程序不匹配,导致初始化总是失败,这里可能有几个接口错误:AT24C02的模拟IIC这里不匹配引脚初始化和位带操作;VL53L0X的模拟IIC和片选引脚XSH没有正确的配置。我们在这里必须更加小心。只要报告界面错误,大部分要么没有初始化,要么没有修改宏定义(位带操作),要么没有打开相应的时钟

: 修改所有引脚定义后,初始化成功。然而,还有一个新一个新的问题是,测量数据总是异常的,一段时间是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的类型,从而导致返回的数据在大于某个数值以后,就将低位给省略了,因此导致错误。

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

: 这个问题原子哥其实说过。。 但是由于他的历程只有一个传感器,因此就不存在这个问题,所以大家如果,一定要先(拉高)片选引脚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引脚,因此这里需要进行引脚重映射;

标签: 激光波传感器

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台