Basado en el módulo TOF de conducción STM32CUBEMX VL53l0x(1)----La mejor práctica de adquisición de distancia de un solo módulo

Descripción general

VL53L0X es una nueva generación de módulo de alcance láser de tiempo de vuelo (ToF) (diferente de la tecnología tradicional). Adopta el paquete más pequeño actualmente en el mercado y puede proporcionar una medición de distancia precisa independientemente de la reflectividad del objetivo. Puede medir distancias absolutas de hasta 2 m, estableciendo un nuevo punto de referencia para los niveles de rendimiento y abriendo la puerta a una variedad de nuevas aplicaciones.
Actualmente estoy realizando cursos de ST, si necesitas muestras puedes unirte al grupo y postular: 615061293.
Insertar descripción de la imagen aquí

El VL53L0X integra una matriz SPAD (diodo de avalancha de fotón único) líder e incorpora la tecnología patentada FlightSense™ de segunda generación de ST.
El emisor VCSEL (láser emisor de superficie de cavidad vertical) de 940 nm del VL53L0X es completamente invisible para el ojo humano. Junto con el filtro infrarrojo físico incorporado, tiene una distancia de alcance más larga, una mayor inmunidad a la luz ambiental y es resistente a las hojas de cobertura. La diafonía óptica tiene mejor estabilidad.

Actualmente estoy realizando cursos de ST, si necesitas muestras puedes unirte al grupo y postular: 615061293.

Vídeo de enseñanza

https://www.bilibili.com/video/BV1dH4y1D7Px/

Basado en el módulo TOF de conducción STM32CUBEMX VL53l0x(1)----La mejor práctica de adquisición de distancia de un solo módulo

aplicación de muestra

https://www.wjx.top/vm/OhcKxJk.aspx#

Descarga del código fuente

https://download.csdn.net/download/qq_24312945/88332771

Todas las características

● Módulo miniaturizado totalmente integrado
○ Láser VCSEL de 940 nm
○ Controlador VCSEL
○ Sensor de rango con microcontrolador avanzado integrado
○ 4,4 x 2,4 x 1,0 mm
● Rango rápido y preciso
○ Distancia absoluta medida hasta 2 m
○ Distancia informada Independiente de la reflectividad del objetivo
○ Óptica integrada avanzada la compensación de diafonía simplifica la selección del cubreobjetos
● Seguro para la vista
○ Dispositivo láser Clase 1, compatible con el último estándar IEC 60825-1:2014 (3.ª edición)
● Fácil integración
○ Reflujo único Componentes soldables
○ Sin componentes ópticos adicionales
○ Fuente de alimentación única
○ I2C interfaz para control de dispositivos y transferencia de datos
○ Xshutdown (reinicio) e interrupción GPIO
○ Dirección I2C programable
Insertar descripción de la imagen aquí

especificaciones

El requisito de fuente de alimentación de este módulo es de 2,8 V, lo que es adecuado para escenarios de aplicaciones de bajo voltaje. Realiza control de host y comunicación de datos a través de la interfaz I2C para facilitar la integración con otros dispositivos. Admite velocidad máxima en modo rápido, alcanzando 400k, lo que garantiza una transmisión de datos eficiente.
Finalmente, el módulo VL53L0X tiene una dirección de dispositivo con una dirección predeterminada de 0x29, lo que facilita la administración y diferenciación entre diferentes módulos cuando varios dispositivos I2C comparten el mismo bus.

Rango de medición

Insertar descripción de la imagen aquí

interfaz

El diagrama esquemático de la interfaz del módulo VL53L0X se muestra a continuación.
Insertar descripción de la imagen aquí

Descripción de la interfaz

Insertar descripción de la imagen aquí

diagrama mínimo del sistema

Insertar descripción de la imagen aquí

configuración de la CII

En esta aplicación, el módulo VL53L0X se comunica con el controlador maestro a través de la interfaz I2C (IIC). Específicamente, los pines I2C del módulo VL53L0X están conectados a los dos puertos IO PB6 (pin B6) y PB7 (pin B7) del controlador principal.
Este método de conexión garantiza una transmisión de datos y comunicación confiables entre el módulo y el controlador principal. PB6 sirve como línea de datos en serie (SDA) del bus I2C y es responsable de la transmisión y recepción de datos. PB7 actúa como la línea de reloj serie (SCL) del bus I2C y se utiliza para sincronizar el tiempo de transmisión de datos.

Insertar descripción de la imagen aquí

Configure IIC en modo rápido con una velocidad de 400k.
Insertar descripción de la imagen aquí

Redirección de puerto serie

Abra la varita mágica y verifique MicroLIB

Insertar descripción de la imagen aquí
En main.c, agregue el archivo de encabezado. Si no lo agrega, aparecerá un error de identificador "ARCHIVO" no definido.

/* USER CODE BEGIN Includes */
#include "stdio.h"
/* USER CODE END Includes */

Declaración de función y redirección del puerto serie:

/* USER CODE BEGIN PFP */
int fputc(int ch, FILE *f){
    
    
	HAL_UART_Transmit(&huart1 , (uint8_t *)&ch, 1, 0xFFFF);
	return ch;
}
/* USER CODE END PFP */

Selección de chip del módulo

De acuerdo con la información de la tabla proporcionada, podemos saber que el pin XSHUT del módulo VL53L0X se utiliza como pin de selección de chip (Chip Enable). Este es el pin Xshutdown. Es una entrada digital. Cuando está en un estado de nivel bajo. (Activo BAJO), se puede utilizar para apagar (es decir, "apagar") el sensor. Esto generalmente se usa para restablecer el sensor o apagarlo para ahorrar energía cuando no se necesitan mediciones del sensor.
Insertar descripción de la imagen aquí

Mirando el manual, podemos ver que las IO correspondientes son PB2 y PB4.

Insertar descripción de la imagen aquí

La configuración en STM32CUBEMX es la siguiente.
Insertar descripción de la imagen aquí

dirección del módulo

La dirección de dispositivo predeterminada del módulo VL53L0X es 0x29. La dirección de un dispositivo es un identificador que se utiliza para identificar y comunicarse con un dispositivo específico. Al configurar la dirección del dispositivo del módulo VL53L0X en 0x29, puede garantizar una comunicación y control normales con el módulo.
Si se agregan bits de lectura y escritura, la dirección de escritura es 0x52 y la dirección de lectura es 0x53.
Insertar descripción de la imagen aquí

Para el módulo VL53L0X, la dirección predeterminada de 7 bits es 0x29 (010 1001 en binario), que es 0x52 (0101 0010 en binario) después de agregar el bit de escritura y 0x53 (0101 0011 en binario) después de agregar el bit de lectura.
Esto significa que cuando el maestro se comunica con el módulo VL53L0X, envía 0x52 bytes de dirección para una operación de escritura o 0x53 bytes de dirección para una operación de lectura.

extern I2C_HandleTypeDef hi2c1;

void VL53L0X_WriteByte(uint8_t add,uint8_t reg,uint8_t data)
{
    
    
	HAL_I2C_Mem_Write(&hi2c1 ,(add<<1)|0,reg,I2C_MEMADD_SIZE_8BIT,&data,1,0xffff);
	
}
void VL53L0X_WriteByte_16Bit(uint8_t add,uint8_t reg,uint16_t data)
{
    
    
	uint8_t data2[2]={
    
    0,0};
	data2[0]=data>>8;
	data2[1]=data;
	HAL_I2C_Mem_Write(&hi2c1 ,(add<<1)|0,reg,I2C_MEMADD_SIZE_8BIT,data2,2,0xffff);
	
}

void VL53L0X_WriteByte_32Bit(uint8_t add,uint8_t reg,uint32_t data)
{
    
    
	uint8_t data2[4]={
    
    0,0,0,0};
	data2[0]=data>>24;
	data2[1]=data>>16;
	data2[2]=data>>8;
	data2[3]=data;
	HAL_I2C_Mem_Write(&hi2c1 ,(add<<1)|0,reg,I2C_MEMADD_SIZE_8BIT,data2,4,0xffff);
	
}

uint8_t VL53L0X_ReadByte(uint8_t add,uint8_t reg)
{
    
    
	uint8_t data=0;
	HAL_I2C_Mem_Read(&hi2c1 ,(add<<1)|1,reg,I2C_MEMADD_SIZE_8BIT,&data,1,0xffff);
	return data;
}




uint16_t VL53L0X_ReadBytee_16Bit(uint8_t add,uint16_t reg)
{
    
    
	uint16_t data=0;
	uint8_t data2[2];
	HAL_I2C_Mem_Read(&hi2c1 ,(add<<1)|1,reg,I2C_MEMADD_SIZE_8BIT,data2,2,0xffff);
	data=data2[0];
	data=data<<8;
	data+=data2[1];
	
	return data;

}

Documentación de referencia

El documento al que se hace referencia aquí pregunta sobre el código del controlador de Arduino.
https://github.com/pololu/vl53l0x-arduino/tree/master

inicialización

La inicialización proporcionada en el programa de referencia se muestra a continuación.
Insertar descripción de la imagen aquí

Entre ellos, sensor.init() es la configuración inicial del módulo de VL53L0X.

// Initialize sensor using sequence based on VL53L0X_DataInit(),
// VL53L0X_StaticInit(), and VL53L0X_PerformRefCalibration().
// This function does not perform reference SPAD calibration
// (VL53L0X_PerformRefSpadManagement()), since the API user manual says that it
// is performed by ST on the bare modules; it seems like that should work well
// enough unless a cover glass is added.
// If io_2v8 (optional) is true or not given, the sensor is configured for 2V8
// mode.
bool VL53L0X::init(bool io_2v8)
{
    
    
  // check model ID register (value specified in datasheet)
  if (readReg(IDENTIFICATION_MODEL_ID) != 0xEE) {
    
     return false; }

  // VL53L0X_DataInit() begin

  // sensor uses 1V8 mode for I/O by default; switch to 2V8 mode if necessary
  if (io_2v8)
  {
    
    
    writeReg(VHV_CONFIG_PAD_SCL_SDA__EXTSUP_HV,
      readReg(VHV_CONFIG_PAD_SCL_SDA__EXTSUP_HV) | 0x01); // set bit 0
  }

  // "Set I2C standard mode"
  writeReg(0x88, 0x00);

  writeReg(0x80, 0x01);
  writeReg(0xFF, 0x01);
  writeReg(0x00, 0x00);
  stop_variable = readReg(0x91);
  writeReg(0x00, 0x01);
  writeReg(0xFF, 0x00);
  writeReg(0x80, 0x00);

  // disable SIGNAL_RATE_MSRC (bit 1) and SIGNAL_RATE_PRE_RANGE (bit 4) limit checks
  writeReg(MSRC_CONFIG_CONTROL, readReg(MSRC_CONFIG_CONTROL) | 0x12);

  // set final range signal rate limit to 0.25 MCPS (million counts per second)
  setSignalRateLimit(0.25);

  writeReg(SYSTEM_SEQUENCE_CONFIG, 0xFF);

  // VL53L0X_DataInit() end

  // VL53L0X_StaticInit() begin

  uint8_t spad_count;
  bool spad_type_is_aperture;
  if (!getSpadInfo(&spad_count, &spad_type_is_aperture)) {
    
     return false; }

  // The SPAD map (RefGoodSpadMap) is read by VL53L0X_get_info_from_device() in
  // the API, but the same data seems to be more easily readable from
  // GLOBAL_CONFIG_SPAD_ENABLES_REF_0 through _6, so read it from there
  uint8_t ref_spad_map[6];
  readMulti(GLOBAL_CONFIG_SPAD_ENABLES_REF_0, ref_spad_map, 6);

  // -- VL53L0X_set_reference_spads() begin (assume NVM values are valid)

  writeReg(0xFF, 0x01);
  writeReg(DYNAMIC_SPAD_REF_EN_START_OFFSET, 0x00);
  writeReg(DYNAMIC_SPAD_NUM_REQUESTED_REF_SPAD, 0x2C);
  writeReg(0xFF, 0x00);
  writeReg(GLOBAL_CONFIG_REF_EN_START_SELECT, 0xB4);

  uint8_t first_spad_to_enable = spad_type_is_aperture ? 12 : 0; // 12 is the first aperture spad
  uint8_t spads_enabled = 0;

  for (uint8_t i = 0; i < 48; i++)
  {
    
    
    if (i < first_spad_to_enable || spads_enabled == spad_count)
    {
    
    
      // This bit is lower than the first one that should be enabled, or
      // (reference_spad_count) bits have already been enabled, so zero this bit
      ref_spad_map[i / 8] &= ~(1 << (i % 8));
    }
    else if ((ref_spad_map[i / 8] >> (i % 8)) & 0x1)
    {
    
    
      spads_enabled++;
    }
  }

  writeMulti(GLOBAL_CONFIG_SPAD_ENABLES_REF_0, ref_spad_map, 6);

  // -- VL53L0X_set_reference_spads() end

  // -- VL53L0X_load_tuning_settings() begin
  // DefaultTuningSettings from vl53l0x_tuning.h

  writeReg(0xFF, 0x01);
  writeReg(0x00, 0x00);

  writeReg(0xFF, 0x00);
  writeReg(0x09, 0x00);
  writeReg(0x10, 0x00);
  writeReg(0x11, 0x00);

  writeReg(0x24, 0x01);
  writeReg(0x25, 0xFF);
  writeReg(0x75, 0x00);

  writeReg(0xFF, 0x01);
  writeReg(0x4E, 0x2C);
  writeReg(0x48, 0x00);
  writeReg(0x30, 0x20);

  writeReg(0xFF, 0x00);
  writeReg(0x30, 0x09);
  writeReg(0x54, 0x00);
  writeReg(0x31, 0x04);
  writeReg(0x32, 0x03);
  writeReg(0x40, 0x83);
  writeReg(0x46, 0x25);
  writeReg(0x60, 0x00);
  writeReg(0x27, 0x00);
  writeReg(0x50, 0x06);
  writeReg(0x51, 0x00);
  writeReg(0x52, 0x96);
  writeReg(0x56, 0x08);
  writeReg(0x57, 0x30);
  writeReg(0x61, 0x00);
  writeReg(0x62, 0x00);
  writeReg(0x64, 0x00);
  writeReg(0x65, 0x00);
  writeReg(0x66, 0xA0);

  writeReg(0xFF, 0x01);
  writeReg(0x22, 0x32);
  writeReg(0x47, 0x14);
  writeReg(0x49, 0xFF);
  writeReg(0x4A, 0x00);

  writeReg(0xFF, 0x00);
  writeReg(0x7A, 0x0A);
  writeReg(0x7B, 0x00);
  writeReg(0x78, 0x21);

  writeReg(0xFF, 0x01);
  writeReg(0x23, 0x34);
  writeReg(0x42, 0x00);
  writeReg(0x44, 0xFF);
  writeReg(0x45, 0x26);
  writeReg(0x46, 0x05);
  writeReg(0x40, 0x40);
  writeReg(0x0E, 0x06);
  writeReg(0x20, 0x1A);
  writeReg(0x43, 0x40);

  writeReg(0xFF, 0x00);
  writeReg(0x34, 0x03);
  writeReg(0x35, 0x44);

  writeReg(0xFF, 0x01);
  writeReg(0x31, 0x04);
  writeReg(0x4B, 0x09);
  writeReg(0x4C, 0x05);
  writeReg(0x4D, 0x04);

  writeReg(0xFF, 0x00);
  writeReg(0x44, 0x00);
  writeReg(0x45, 0x20);
  writeReg(0x47, 0x08);
  writeReg(0x48, 0x28);
  writeReg(0x67, 0x00);
  writeReg(0x70, 0x04);
  writeReg(0x71, 0x01);
  writeReg(0x72, 0xFE);
  writeReg(0x76, 0x00);
  writeReg(0x77, 0x00);

  writeReg(0xFF, 0x01);
  writeReg(0x0D, 0x01);

  writeReg(0xFF, 0x00);
  writeReg(0x80, 0x01);
  writeReg(0x01, 0xF8);

  writeReg(0xFF, 0x01);
  writeReg(0x8E, 0x01);
  writeReg(0x00, 0x01);
  writeReg(0xFF, 0x00);
  writeReg(0x80, 0x00);

  // -- VL53L0X_load_tuning_settings() end

  // "Set interrupt config to new sample ready"
  // -- VL53L0X_SetGpioConfig() begin

  writeReg(SYSTEM_INTERRUPT_CONFIG_GPIO, 0x04);
  writeReg(GPIO_HV_MUX_ACTIVE_HIGH, readReg(GPIO_HV_MUX_ACTIVE_HIGH) & ~0x10); // active low
  writeReg(SYSTEM_INTERRUPT_CLEAR, 0x01);

  // -- VL53L0X_SetGpioConfig() end

  measurement_timing_budget_us = getMeasurementTimingBudget();

  // "Disable MSRC and TCC by default"
  // MSRC = Minimum Signal Rate Check
  // TCC = Target CentreCheck
  // -- VL53L0X_SetSequenceStepEnable() begin

  writeReg(SYSTEM_SEQUENCE_CONFIG, 0xE8);

  // -- VL53L0X_SetSequenceStepEnable() end

  // "Recalculate timing budget"
  setMeasurementTimingBudget(measurement_timing_budget_us);

  // VL53L0X_StaticInit() end

  // VL53L0X_PerformRefCalibration() begin (VL53L0X_perform_ref_calibration())

  // -- VL53L0X_perform_vhv_calibration() begin

  writeReg(SYSTEM_SEQUENCE_CONFIG, 0x01);
  if (!performSingleRefCalibration(0x40)) {
    
     return false; }

  // -- VL53L0X_perform_vhv_calibration() end

  // -- VL53L0X_perform_phase_calibration() begin

  writeReg(SYSTEM_SEQUENCE_CONFIG, 0x02);
  if (!performSingleRefCalibration(0x00)) {
    
     return false; }

  // -- VL53L0X_perform_phase_calibration() end

  // "restore the previous Sequence Config"
  writeReg(SYSTEM_SEQUENCE_CONFIG, 0xE8);

  // VL53L0X_PerformRefCalibration() end

  return true;
}

Dado que algunas definiciones de macros están comentadas, no es necesario ejecutar las instrucciones en el cuadro rojo a continuación.
Insertar descripción de la imagen aquí

Longitud de distancia de lectura única

En el programa principal, la ejecución principal es obtener datos en una sola vez.

Insertar descripción de la imagen aquí

El código fuente correspondiente es el siguiente.

// Returns a range reading in millimeters when continuous mode is active
// (readRangeSingleMillimeters() also calls this function after starting a
// single-shot range measurement)
uint16_t VL53L0X::readRangeContinuousMillimeters()
{
    
    
  startTimeout();
  while ((readReg(RESULT_INTERRUPT_STATUS) & 0x07) == 0)
  {
    
    
    if (checkTimeoutExpired())
    {
    
    
      did_timeout = true;
      return 65535;
    }
  }

  // assumptions: Linearity Corrective Gain is 1000 (default);
  // fractional ranging is not enabled
  uint16_t range = readReg16Bit(RESULT_RANGE_STATUS + 10);

  writeReg(SYSTEM_INTERRUPT_CLEAR, 0x01);

  return range;
}

// Performs a single-shot range measurement and returns the reading in
// millimeters
// based on VL53L0X_PerformSingleRangingMeasurement()
uint16_t VL53L0X::readRangeSingleMillimeters()
{
    
    
  writeReg(0x80, 0x01);
  writeReg(0xFF, 0x01);
  writeReg(0x00, 0x00);
  writeReg(0x91, stop_variable);
  writeReg(0x00, 0x01);
  writeReg(0xFF, 0x00);
  writeReg(0x80, 0x00);

  writeReg(SYSRANGE_START, 0x01);

  // "Wait until start bit has been cleared"
  startTimeout();
  while (readReg(SYSRANGE_START) & 0x01)
  {
    
    
    if (checkTimeoutExpired())
    {
    
    
      did_timeout = true;
      return 65535;
    }
  }

  return readRangeContinuousMillimeters();
}

La versión modificada es la siguiente.

// Returns a range reading in millimeters when continuous mode is active
// (readRangeSingleMillimeters() also calls this function after starting a
// single-shot range measurement)
uint16_t VL53L0X_readRangeContinuousMillimeters(uint8_t add)
{
    
    
  startTimeout();
uint16_t range;
  while ( (VL53L0X_ReadByte(add,RESULT_INTERRUPT_STATUS) & 0x07) == 0)
  {
    
    
    if (checkTimeoutExpired())
    {
    
    
      did_timeout = true;
      return 65535;
    }
  }
  // assumptions: Linearity Corrective Gain is 1000 (default);
  // fractional ranging is not enabled
   range= VL53L0X_ReadBytee_16Bit(add,RESULT_RANGE_STATUS + 10);

  VL53L0X_WriteByte(add,SYSTEM_INTERRUPT_CLEAR, 0x01);

  return range;
}


// Performs a single-shot range measurement and returns the reading in
// millimeters
// based on VL53L0X_PerformSingleRangingMeasurement()
uint16_t VL53L0X_readRangeSingleMillimeters(uint8_t add)
{
    
    
  VL53L0X_WriteByte(add,0x80, 0x01);
  VL53L0X_WriteByte(add,0xFF, 0x01);
  VL53L0X_WriteByte(add,0x00, 0x00);
  VL53L0X_WriteByte(add,0x91, stop_variable);
  VL53L0X_WriteByte(add,0x00, 0x01);
  VL53L0X_WriteByte(add,0xFF, 0x00);
  VL53L0X_WriteByte(add,0x80, 0x00);

  VL53L0X_WriteByte(add,SYSRANGE_START, 0x01);

  // "Wait until start bit has been cleared"
  startTimeout();
  while (VL53L0X_ReadByte(add,SYSRANGE_START) & 0x01)
  {
    
    
    if (checkTimeoutExpired())
    {
    
    
      did_timeout = true;
      return 65535;
    }
  }

  return VL53L0X_readRangeContinuousMillimeters(add);
}

Resultados de la prueba

Los resultados de la prueba se muestran a continuación.
Insertar descripción de la imagen aquí

Supongo que te gusta

Origin blog.csdn.net/qq_24312945/article/details/132843722
Recomendado
Clasificación