VL53L0x TOF激光测距的 stm32 HAL库驱动代码

VL53L0x 是ST公司生成的 TOF激光测距传感器,得益于非常小巧的尺寸,很容易放入手机、无人机中,提供更加精准、稳定的测距方式。

 

本文代码,使用 STM32F4xx的 HAL库。

 

VL53L0x.c

#include "VL53L0x.h"
#include <math.h>
#include "PersonalMath.h"

struct VL53L0xData  VL53L0x_Bottom;		//底部连接在IIC2的VL53L0x的数据


void VL53L0x_init(I2C_HandleTypeDef *hi2c)
{	
	uint8_t VL53L0x_SendData[2] = {0x01};
	uint8_t VL53L0x_RecData[5] ;
	
/*	//Revision ID:
	HAL_I2C_Mem_Read(hi2c, VL53L0x_add, VL53L0X_REG_IDENTIFICATION_REVISION_ID, I2C_MEMADD_SIZE_8BIT, VL53L0x_RecData, 1, 10);
	//Device ID:
	HAL_I2C_Mem_Read(hi2c, VL53L0x_add, VL53L0X_REG_IDENTIFICATION_MODEL_ID, I2C_MEMADD_SIZE_8BIT, VL53L0x_RecData+1, 1, 10);
	//PRE_RANGE_CONFIG_VCSEL_PERIOD =
	HAL_I2C_Mem_Read(hi2c, VL53L0x_add, VL53L0X_REG_PRE_RANGE_CONFIG_VCSEL_PERIOD, I2C_MEMADD_SIZE_8BIT, VL53L0x_RecData+2, 1, 10);
	//FINAL_RANGE_CONFIG_VCSEL_PERIOD=
	HAL_I2C_Mem_Read(hi2c, VL53L0x_add, VL53L0X_REG_FINAL_RANGE_CONFIG_VCSEL_PERIOD, I2C_MEMADD_SIZE_8BIT, VL53L0x_RecData+3, 1, 10);
	*/
	HAL_I2C_Mem_Write(hi2c, VL53L0x_add, VL53L0X_REG_SYSRANGE_START, I2C_MEMADD_SIZE_8BIT, VL53L0x_SendData, 1, 1);
	//HAL_Delay(500);
	
	VL53L0x_SendData[1] = 100;
	while(VL53L0x_SendData[1]--)
	{
		HAL_Delay(1);
		HAL_I2C_Mem_Read(hi2c, VL53L0x_add, VL53L0X_REG_RESULT_RANGE_STATUS, I2C_MEMADD_SIZE_8BIT, VL53L0x_RecData+4, 1, 1);
			if (VL53L0x_RecData[4] & 0x01) break;
	}
}

//检查VL53L0x是否正常
//检查成功返回0
//检查失败返回1
uint8_t VL53L0x_Check(I2C_HandleTypeDef *hi2c)
{	
	uint8_t VL53L0x_SendData[2] = {0x01};
	uint8_t VL53L0x_RecData[5] ;
	
	//Revision ID:
	HAL_I2C_Mem_Read(hi2c, VL53L0x_add, VL53L0X_REG_IDENTIFICATION_REVISION_ID, I2C_MEMADD_SIZE_8BIT, VL53L0x_RecData, 1, 1);
	//Device ID:
	HAL_I2C_Mem_Read(hi2c, VL53L0x_add, VL53L0X_REG_IDENTIFICATION_MODEL_ID, I2C_MEMADD_SIZE_8BIT, VL53L0x_RecData+1, 1, 1);
	//PRE_RANGE_CONFIG_VCSEL_PERIOD =
	HAL_I2C_Mem_Read(hi2c, VL53L0x_add, VL53L0X_REG_PRE_RANGE_CONFIG_VCSEL_PERIOD, I2C_MEMADD_SIZE_8BIT, VL53L0x_RecData+2, 1, 1);
	//FINAL_RANGE_CONFIG_VCSEL_PERIOD=
	HAL_I2C_Mem_Read(hi2c, VL53L0x_add, VL53L0X_REG_FINAL_RANGE_CONFIG_VCSEL_PERIOD, I2C_MEMADD_SIZE_8BIT, VL53L0x_RecData+3, 1, 1);
	
	HAL_I2C_Mem_Write(hi2c, VL53L0x_add, VL53L0X_REG_SYSRANGE_START, I2C_MEMADD_SIZE_8BIT, VL53L0x_SendData, 1, 1);
	HAL_Delay(500);
	
	VL53L0x_SendData[1] = 100;
	while(VL53L0x_SendData[1]--)
	{
		HAL_Delay(10);
		HAL_I2C_Mem_Read(hi2c, VL53L0x_add, VL53L0X_REG_RESULT_RANGE_STATUS, I2C_MEMADD_SIZE_8BIT, VL53L0x_RecData+4, 1, 1);
			if (VL53L0x_RecData[4] & 0x01) break;
	}
	
	if (VL53L0x_RecData[4] & 0x01) 
	return 0;				//检查成功返回0
	else return 1;	//检查失败返回1
}

//VL53L0x转换一次
void VL53L0x_StartConversion(I2C_HandleTypeDef *hi2c)
{
	uint8_t VL53L0x_SendData[1] = {0x01};
	HAL_I2C_Mem_Write(hi2c, VL53L0x_add, VL53L0X_REG_SYSRANGE_START, I2C_MEMADD_SIZE_8BIT, VL53L0x_SendData, 1, 1);
}

uint16_t makeuint16(int lsb, int msb) 
{
    return ((msb & 0xFF) << 8) | (lsb & 0xFF);
}


//VL53L0x读取距离等数据反馈信息
void VL53L0x_ReadDistance(I2C_HandleTypeDef *hi2c, struct VL53L0xData *VL_temp)
{
	//记录历史有效值
	VL_temp->dist_last = VL_temp->distValid;
	
	HAL_I2C_Mem_Read(hi2c, VL53L0x_add, VL53L0X_REG_RESULT_RANGE_STATUS, I2C_MEMADD_SIZE_8BIT, VL_temp->vtemp, 12, 1);
	
	VL_temp->acnt = makeuint16(VL_temp->vtemp[7], VL_temp->vtemp[6]);
	VL_temp->scnt = makeuint16(VL_temp->vtemp[9], VL_temp->vtemp[8]);
	VL_temp->dist = makeuint16(VL_temp->vtemp[11], VL_temp->vtemp[10]);
	VL_temp->DeviceRangeStatusInternal = ((VL_temp->vtemp[0] & 0x78) >> 3);

	
	//提取有效值
	if(VL_temp->dist <= 0x0014)		//距离数据无效
		VL_temp->distValid = VL_temp->dist_last;
	else 	//有效
		VL_temp->distValid = VL_temp->dist;
	
/*	下面的代码具体干嘛的时间长忘记了,功能是根据对地倾角求得飞机的高度,大家可以直接删掉 */
	
	uint8_t i,j;
	
	for(i = 14;i>0;i--)
	{
		VL_temp->dist_buff[i] = VL_temp->dist_buff[i-1];
	}
	VL_temp->dist_buff[0] = VL_temp->distValid;
	
	i =0;
	j=0;
	for(i=0;i<6;i++)
	{
		if(VL_temp->dist_buff[i] >=2000)
			j++;
	}
	
	if(j >= 2)		// 1/3的溢出率
		VL_temp->distValidFinal = 2000;
	else		//从数组里筛选出最近的有效值
	{
		i=0;
		for(i=0;i<15;i++)
		{
			if(VL_temp->dist_buff[i] <2000)
				break;
		}
		VL_temp->distValidFinal = VL_temp->dist_buff[i];
	}
	
	VL_temp->GroundDis_last = VL_temp->GroundDis;
	VL_temp->GroundDis = (float)VL_temp->distValidFinal /1000;
	VL_temp->GroundDis = VL_temp->GroundDis *cos(ABS((PostureAngle.Pitch /180 *3.14159))) *cos(ABS((PostureAngle.Roll /180 *3.14159)));
}

 

VL53L0x.h

#ifndef __VL53L0X_H
#define __VL53L0X_H			    
#include "stm32f4xx_hal.h"
#include "i2c.h"

#include "Structure.h"
#include "Algorithm_filter.h"


#define VL_CS1_Enable 		HAL_GPIO_WritePin(GPIOB,GPIO_PIN_2,(GPIO_PinState)1);	//左侧VL53L0X的PB2拉高使能
#define VL_CS1_Disable 		HAL_GPIO_WritePin(GPIOB,GPIO_PIN_2,(GPIO_PinState)0);	//左侧VL53L0X的PB2拉低失能

#define VL_CS2_Enable 		HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,(GPIO_PinState)1);	//右侧VL53L0X的PB1拉高使能
#define VL_CS2_Disable 		HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,(GPIO_PinState)0);	//右侧VL53L0X的PB1拉低失能


//寄存器操作函数	 
#define VL53L0x_add 		0x52			//VL53L0x的IIC器件地址

#define VL53L0X_REG_IDENTIFICATION_MODEL_ID         0xc0
#define VL53L0X_REG_IDENTIFICATION_REVISION_ID      0xc2
#define VL53L0X_REG_PRE_RANGE_CONFIG_VCSEL_PERIOD   0x50
#define VL53L0X_REG_FINAL_RANGE_CONFIG_VCSEL_PERIOD 0x70
#define VL53L0X_REG_SYSRANGE_START                  0x00
#define VL53L0X_REG_RESULT_INTERRUPT_STATUS         0x13
#define VL53L0X_REG_RESULT_RANGE_STATUS             0x14


struct VL53L0xData {
	uint8_t vtemp[12];
	uint16_t acnt;		//环境统计,激光光强
	uint16_t scnt;		//信号数
	uint16_t dist;		//距离,单位mm	最原始数据
	uint8_t DeviceRangeStatusInternal;
	
	uint16_t dist_last;		//历史有效值,用来判断
	
	uint16_t distValid;		//原始距离值提取后的有效值
	uint16_t dist_buff[15];		//测距的滑窗缓存
	uint16_t distValidFinal;
	
	float GroundDis;
	float GroundDis_last;
	
	float Speed;
	float Speed_last;
	
	uint16_t distFilted;	//卡尔曼滤波后的距离值
	uint16_t distFilted_1;//卡尔曼后 + 一阶低通滤波
	
	uint8_t Flag_OverRange;	//超出量程标志位

/*	uint16_t dist_Original;	//原始距离值
	uint16_t dist_OriginalValid;	//原始距离值提取后的有效值
	uint16_t dist_OriginalValid_lsat;*/
};

extern struct VL53L0xData  VL53L0x_Bottom;		//底部连接在IIC2的VL53L0x的数据



void VL53L0x_init(I2C_HandleTypeDef *hi2c);

//检查VL53L0x是否正常
uint8_t VL53L0x_Check(I2C_HandleTypeDef *hi2c);

//VL53L0x转换一次
void VL53L0x_StartConversion(I2C_HandleTypeDef *hi2c);

//VL53L0x读取距离等数据反馈信息
void VL53L0x_ReadDistance(I2C_HandleTypeDef *hi2c, struct VL53L0xData *VL_temp);

void VL53L0x_DataFitting(void);

#endif

 

I2C2 在 STM32CubeMX 的配置:

 

感慨一小下

压了三年的箱底,可算翻出来了。

当时这款传感器比较新,ST提供的驱动是linux的,CubeMX和HAL库也刚步入正轨,所以借鉴了好多。Arduino的,博客的。

以前懒得码字,可现在学东西多路总容易忘记以前的东西,拿博客当云笔记用,发表出来兴许还能帮到别人,岂不美哉。

更好的 VL53L1x 早已上市,十分好这条产品线。等测距速度提上去,再与MEMS振镜结合,这不就Mini固态激光雷达嘛。

 

  • 20
    点赞
  • 120
    收藏
    觉得还不错? 一键收藏
  • 42
    评论
对于VL53L1x TOF激光测距模块,可以使用STM32的I2C总线进行控制和通信。下面是基于HAL库的VL53L1x驱动代码: ```c #include "vl53l1x.h" // 初始化VL53L1x模块 VL53L1_Error VL53L1x_Init(VL53L1_Dev_t *dev) { VL53L1_Error status = VL53L1_ERROR_NONE; uint8_t sensor_state = 0; uint32_t refSpadCount; uint8_t isApertureSpads; uint8_t VhvSettings; uint8_t PhaseCal; uint32_t sequence_config_timeout_us; // 打开I2C总线 HAL_I2C_MspInit(dev->I2cHandle); // 软复位 status = VL53L1_software_reset(dev); if (status != VL53L1_ERROR_NONE) { return status; } // 等待传感器初始化完成 while (sensor_state == 0) { status = VL53L1_RdByte(dev, 0x010F, &sensor_state); if (status != VL53L1_ERROR_NONE) { return status; } } // 设备版本号 uint8_t version[3]; status = VL53L1_GetVersion(dev, version); if (status != VL53L1_ERROR_NONE) { return status; } // 设备参数配置 status = VL53L1_DataInit(dev); if (status != VL53L1_ERROR_NONE) { return status; } status = VL53L1_StaticInit(dev); if (status != VL53L1_ERROR_NONE) { return status; } // 设备校准 status = VL53L1_PerformRefSpadManagement(dev, &refSpadCount, &isApertureSpads); if (status != VL53L1_ERROR_NONE) { return status; } status = VL53L1_PerformRefCalibration(dev, &VhvSettings, &PhaseCal); if (status != VL53L1_ERROR_NONE) { return status; } // 设备配置 status = VL53L1_SetXTalkCompensationEnable(dev, 0); if (status != VL53L1_ERROR_NONE) { return status; } status = VL53L1_SetOffsetCalibrationDataMicroMeter(dev, 0); if (status != VL53L1_ERROR_NONE) { return status; } // 设备开始测距 status = VL53L1_SetDistanceMode(dev, VL53L1_DISTANCEMODE_LONG); if (status != VL53L1_ERROR_NONE) { return status; } status = VL53L1_SetMeasurementTimingBudgetMicroSeconds(dev, 50000); if (status != VL53L1_ERROR_NONE) { return status; } sequence_config_timeout_us = (uint32_t)VL53L1_calc_timeout_us(dev, 2000); status = VL53L1_SetSequenceStepTimeout(dev, VL53L1_SEQUENCESTEP_TCC, sequence_config_timeout_us); if (status != VL53L1_ERROR_NONE) { return status; } status = VL53L1_SetSequenceStepTimeout(dev, VL53L1_SEQUENCESTEP_DSS, sequence_config_timeout_us); if (status != VL53L1_ERROR_NONE) { return status; } status = VL53L1_SetSequenceStepTimeout(dev, VL53L1_SEQUENCESTEP_MSRC, sequence_config_timeout_us); if (status != VL53L1_ERROR_NONE) { return status; } status = VL53L1_SetSequenceStepTimeout(dev, VL53L1_SEQUENCESTEP_PRE_RANGE, sequence_config_timeout_us); if (status != VL53L1_ERROR_NONE) { return status; } status = VL53L1_SetSequenceStepTimeout(dev, VL53L1_SEQUENCESTEP_FINAL_RANGE, sequence_config_timeout_us); if (status != VL53L1_ERROR_NONE) { return status; } status = VL53L1_SetInterMeasurementPeriodMilliSeconds(dev, 100); if (status != VL53L1_ERROR_NONE) { return status; } status = VL53L1_SetGPIOConfig(dev, 0, VL53L1_GPIOFUNCTIONALITY_NEW_MEASURE_READY, VL53L1_INTERRUPTPOLARITY_LOW); if (status != VL53L1_ERROR_NONE) { return status; } return status; } // 触发一次测量 VL53L1_Error VL53L1x_StartMeasurement(VL53L1_Dev_t *dev) { VL53L1_Error status = VL53L1_ERROR_NONE; uint8_t measurement_mode; uint8_t system_health; uint8_t measurement_device_ready; // 获取测量模式 status = VL53L1_GetMeasurementMode(dev, &measurement_mode); if (status != VL53L1_ERROR_NONE) { return status; } // 如果设备未准备好,则等待 if (measurement_mode == VL53L1_DEVICEREADY_WAIT_FOR_MEASURE_VALID) { status = VL53L1_WaitDeviceBooted(dev); if (status != VL53L1_ERROR_NONE) { return status; } } // 触发测量 status = VL53L1_StartMeasurement(dev); if (status != VL53L1_ERROR_NONE) { return status; } // 等待测量完成 do { status = VL53L1_GetMeasurementDataReady(dev, &measurement_device_ready); if (status != VL53L1_ERROR_NONE) { return status; } status = VL53L1_GetSystemHealth(dev, &system_health); if (status != VL53L1_ERROR_NONE) { return status; } } while ((measurement_device_ready == 0) && (system_health == 0)); return VL53L1_ERROR_NONE; } // 读取测量距离 VL53L1_Error VL53L1x_ReadMeasurement(VL53L1_Dev_t *dev, uint16_t *distance) { VL53L1_Error status = VL53L1_ERROR_NONE; VL53L1_RangingMeasurementData_t ranging_data; // 读取测量数据 status = VL53L1_GetRangingMeasurementData(dev, &ranging_data); if (status != VL53L1_ERROR_NONE) { return status; } // 检查数据是否有效 if (ranging_data.RangeStatus != 0) { return VL53L1_ERROR_RANGE_ERROR; } // 保存测量距离 *distance = ranging_data.RangeMilliMeter; return VL53L1_ERROR_NONE; } ``` 使用时,可以调用VL53L1x_Init()函数初始化设备,然后使用VL53L1x_StartMeasurement()函数触发一次测量,最后使用VL53L1x_ReadMeasurement()函数读取测量距离。需要注意的是,VL53L1x模块的I2C地址为0x29,可以在VL53L1x_Init()函数中进行配置。
评论 42
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值