TOF モジュール VL53l0x(1) を駆動する STM32CUBEMX に基づいています---単一モジュール距離取得のベスト プラクティス

概要

VL53L0X は、従来の技術とは異なる新世代の飛行時間型 (ToF) レーザー測距モジュールで、現在市販されている最小のパッケージを採用しており、ターゲットの反射率に関係なく正確な距離測定が可能です。最大 2m までの絶対距離を測定できるため、さまざまなパフォーマンス レベルの新しいベンチマークを設定し、さまざまな新しいアプリケーションへの扉を開きます。
現在 ST コースを受講中です。サンプルが必要な場合は、グループに参加して申請してください: 615061293。
ここに画像の説明を挿入します

VL53L0X は、最先端の SPAD アレイ (単一光子アバランシェ ダイオード) を統合し、ST の第 2 世代 FlightSense™ 特許技術を組み込んでいます。
VL53L0X の 940nm VCSEL エミッター (垂直共振器面発光レーザー) は人間の目には完全に見えず、内蔵の物理赤外線フィルターと組み合わせることで、より長い測距距離、周囲光に対する強い耐性、およびカバー シートに対する耐性を備えています。光クロストークの安定性が向上しました。

現在 ST コースを受講中です。サンプルが必要な場合は、グループに参加して申請してください: 615061293。

ビデオ教育

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

TOF モジュール VL53l0x(1) を駆動する STM32CUBEMX に基づいています---単一モジュール距離取得のベスト プラクティス

サンプルアプリケーション

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

ソースコードのダウンロード

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

すべての機能

● 完全に統合された小型モジュール
○ 940 nm レーザー VCSEL
○ VCSEL ドライバー
○ 高度なマイクロコントローラーが組み込まれた測距センサー
○ 4.4 x 2.4 x 1.0 mm
● 高速で正確な測距
○ 最大 2m までの絶対距離を測定
○ 報告される距離 ターゲットの反射率に依存しない
○ 高度な組み込み光学式クロストーク補償により、カバー ガラスの選択が簡素化されます
● アイセーフ
○ 最新規格 IEC 60825-1:2014 (第 3 版) に準拠したクラス 1 レーザー デバイス
● 簡単な統合
○ 1 回のリフローはんだ付け可能なコンポーネント ○
追加の光学コンポーネントなし ○
単一電源
○ I2Cデバイス制御およびデータ転送用インターフェイス
○ Xshutdown (リセット) および GPIO 割り込み
○ プログラム可能な I2C アドレス
ここに画像の説明を挿入します

仕様

このモジュールの電源要件は 2.8V であり、低電圧アプリケーション シナリオに適しています。I2C インターフェイスを介してホスト制御とデータ通信を実行し、他のデバイスとの統合を容易にします。400k に達する最大高速モード レートをサポートし、効率的なデータ転送を保証します。
最後に、VL53L0X モジュールには、デフォルト アドレス 0x29 のデバイス アドレスがあり、複数の I2C デバイスが同じバスを共有する場合に、異なるモジュールの管理と区別が容易になります。

測定範囲

ここに画像の説明を挿入します

インターフェース

VL53L0X モジュール インターフェースの概略図を以下に示します。
ここに画像の説明を挿入します

インターフェースの説明

ここに画像の説明を挿入します

最小限のシステム図

ここに画像の説明を挿入します

IIC構成

このアプリケーションでは、VL53L0X モジュールは I2C (IIC) インターフェイスを介してマスター コントローラーと通信します。具体的には、VL53L0X モジュールの I2C ピンは、メイン コントローラの 2 つの IO ポート PB6 (ピン B6) と PB7 (ピン B7) に接続されます。
この接続方法により、モジュールとメインコントローラー間の確実なデータ送信と通信が保証されます。PB6 は I2C バスのシリアル データ ライン (SDA) として機能し、データの送受信を担当します。PB7 は I2C バスのシリアル クロック ライン (SCL) として機能し、データ送信のタイミングを同期するために使用されます。

ここに画像の説明を挿入します

速度 400k の高速モードで IIC を設定します。
ここに画像の説明を挿入します

シリアルポートのリダイレクト

魔法の杖を開いてMicroLIBを確認してください

ここに画像の説明を挿入します
main.cにヘッダファイルを追加しますが、追加しないと識別子「FILE」が未定義ですエラーが表示されます。

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

関数宣言とシリアルポートリダイレクト:

/* 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 */

モジュールチップセレクト

提供されたテーブル情報によると、VL53L0X モジュールの XSHUT ピンがチップ セレクト ピン (チップ イネーブル) として使用されていることがわかります。これは Xshutdown ピンです。デジタル入力です。ロー レベル状態の場合です。 (アクティブ LOW)、センサーをオフにする (つまり「シャットダウン」) ために使用できます。これは通常、センサーをリセットするか、センサーの測定が必要ないときに電力を節約するためにセンサーをオフにするために使用されます。
ここに画像の説明を挿入します

マニュアルを見ると、対応するIOはPB2とPB4であることがわかります。

ここに画像の説明を挿入します

STM32CUBEMXの構成は以下の通りです。
ここに画像の説明を挿入します

モジュールアドレス

VL53L0X モジュールのデフォルトのデバイス アドレスは 0x29 です。デバイスアドレスは、特定のデバイスを識別し、通信するために使用される識別子です。VL53L0X モジュールのデバイスアドレスを 0x29 に設定すると、モジュールとの正常な通信と制御が保証されます。
読み取りビットと書き込みビットを追加すると、書き込みアドレスは 0x52、読み取りアドレスは 0x53 になります。
ここに画像の説明を挿入します

VL53L0X モジュールの場合、デフォルトの 7 ビット アドレスは 0x29 (バイナリで 010 1001) で、書き込みビットを追加すると 0x52 (バイナリで 0101 0010)、読み取りビットを追加すると 0x53 (バイナリで 0101 0011) になります。
これは、マスターが VL53L0X モジュールと通信するときに、書き込み操作の場合は 0x52 アドレス バイトを送信し、読み取り操作の場合は 0x53 アドレス バイトを送信することを意味します。

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;

}

参考資料

ここで参照しているドキュメントはArduinoのドライバーコードについて尋ねています。
https://github.com/pololu/vl53l0x-arduino/tree/master

初期化

参考プログラムで与えられる初期化を以下に示します。
ここに画像の説明を挿入します

このうち、sensor.init()は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;
}

一部のマクロ定義はコメントアウトされているため、以下の赤枠内の命令を実行する必要はありません。
ここに画像の説明を挿入します

単一読み取り距離の長さ

メインプログラムでは、一度にデータを取得することが主な実行となります。

ここに画像の説明を挿入します

対応するソースコードは以下の通りです。

// 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();
}

修正版は以下の通りです。

// 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);
}

試験結果

試験結果を以下に示します。
ここに画像の説明を挿入します

おすすめ

転載: blog.csdn.net/qq_24312945/article/details/132843722