Supachai Vorapojpisut
Published © CC BY

Experiencing VL53L8 multizone ToF sensor

I got X-NUCLEO-53L8A1 to test multizone Time-of-Flight technology, so let's share my experience with B-L475E-IOT01A to report data via MQTT.

BeginnerProtip1 hour73
Experiencing VL53L8 multizone ToF sensor

Things used in this project

Hardware components

STMicroelectronics B-L475E-IOT01A
×1
STMicroelectronics X-NUCLEO-53L8A1
×1

Software apps and online services

PlatformIO IDE
PlatformIO IDE
STMicroelectronics STM32CubeMX

Story

Read more

Code

Main code

C/C++
main.cpp that add MQTT/JSON code with VL53L8 example code
#include <Arduino.h>
#include <Wire.h>
#include <vl53l8cx_class.h>
#include <WiFiST.h>
#include <SPI.h>
#include <PubSubClient.h>
#include <ArduinoJson.h>

#define LPN_PIN     10
#define I2C_RST_PIN -1
#define PWREN_PIN   11

#define DEV_I2C Wire

char ssid[] = "WIFI_SSID";
const char* password = "WIFI_PASSWD";
const char* MQTT_BROKER = "broker.mqtt-dashboard.com";
const int MQTT_PORT = 1883;
const char* MQTT_CLIENT_ID = "my_demo_vl53l8cx";
const char* MQTT_DATA_TOPIC = "your_data_topic";
const char* MQTT_CMD_TOPIC = "your_cmd_topic";

SPIClass SPI_3(PC12, PC11, PC10);
WiFiClass WiFi(&SPI_3, PE0, PE1, PE8, PB13);
WiFiClient STClient;
int status = WL_IDLE_STATUS;     // the Wifi radio's status

PubSubClient mqttClient(STClient);
long lastMsg = 0;
char msg[50];
long value = 0;
ArduinoJson::JsonDocument json_doc;

void print_result(VL53L8CX_ResultsData *Result);
void clear_screen(void);
void handle_cmd(uint8_t cmd);
void display_commands_banner(void);
void mqtt_callback(char* topic, byte* payload, unsigned int length);

// Components.
VL53L8CX sensor_vl53l8cx_top(&DEV_I2C, LPN_PIN, I2C_RST_PIN);

bool EnableAmbient = false;
bool EnableSignal = false;
uint8_t res = VL53L8CX_RESOLUTION_4X4;
char report[256];

/* Setup ---------------------------------------------------------------------*/
void setup()
{
  // Initialize serial for output.
  Serial.begin(460800);

  // Connect to WiFi network
  while (status != WL_CONNECTED) {
    Serial.print(".");
    // Connect to WPA2 network:
    status = WiFi.begin(ssid, password);
    // wait 10 seconds for connection:
    delay(1000);
  }
  Serial.println();
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());

  mqttClient.setServer(MQTT_BROKER, MQTT_PORT);
  mqttClient.setCallback(mqtt_callback);
  mqttClient.connect(MQTT_CLIENT_ID);
  mqttClient.subscribe(MQTT_CMD_TOPIC);

  // Enable PWREN pin if present
  if (PWREN_PIN >= 0) {
    pinMode(PWREN_PIN, OUTPUT);
    digitalWrite(PWREN_PIN, HIGH);
    delay(10);
  }

  // Initialize I2C bus.
  DEV_I2C.begin();
  
  // Configure VL53L8CX component.
  sensor_vl53l8cx_top.begin();
  sensor_vl53l8cx_top.init_sensor();
  
  // Start Measurements
  sensor_vl53l8cx_top.vl53l8cx_start_ranging();
}

void loop()
{
  VL53L8CX_ResultsData Results;
  uint8_t NewDataReady = 0;
  uint8_t status;

  do {
    status = sensor_vl53l8cx_top.vl53l8cx_check_data_ready(&NewDataReady);
  } while (!NewDataReady);

  if ((!status) && (NewDataReady != 0)) {
    status = sensor_vl53l8cx_top.vl53l8cx_get_ranging_data(&Results);
    print_result(&Results);
    json_doc.clear();
    int number_of_zones = res;
    int zones_per_line = (number_of_zones == 16) ? 4 : 8;
    json_doc["number_of_zones"] = res;
    for (int i = 0; i < number_of_zones; i++) {
      json_doc["distance"][i] = 0;
    }
    for (int j = 0; j < number_of_zones; j += zones_per_line) {
      for (int k = 0; k < zones_per_line; k++) {
        json_doc["distance"][j + k] = Results.distance_mm[j+k];
      }
    }
    char buffer[256];
    serializeJson(json_doc, buffer);
    mqttClient.publish(MQTT_DATA_TOPIC, buffer);
  }

  if (Serial.available()>0)
  {
    handle_cmd(Serial.read());
  }
  delay(100);
  mqttClient.loop();
}

/* Private functions ---------------------------------------------------------*/
void mqtt_callback(char* topic, byte* payload, unsigned int length) {
}

void print_result(VL53L8CX_ResultsData *Result)
{
  int8_t i, j, k, l;
  uint8_t zones_per_line;
  uint8_t number_of_zones = res;

  zones_per_line = (number_of_zones == 16) ? 4 : 8;

  display_commands_banner();

  Serial.print("Cell Format :\n\n");
  
  for (l = 0; l < VL53L8CX_NB_TARGET_PER_ZONE; l++)
  {
    snprintf(report, sizeof(report)," \033[38;5;10m%20s\033[0m : %20s\n", "Distance [mm]", "Status");
    Serial.print(report);

    if(EnableAmbient || EnableSignal)
    {
      snprintf(report, sizeof(report)," %20s : %20s\n", "Signal [kcps/spad]", "Ambient [kcps/spad]");
      Serial.print(report);
    }
  }

  Serial.print("\n\n");

  for (j = 0; j < number_of_zones; j += zones_per_line)
  {
    for (i = 0; i < zones_per_line; i++) 
      Serial.print(" -----------------");
    Serial.print("\n");
    
    for (i = 0; i < zones_per_line; i++)
      Serial.print("|                 ");
    Serial.print("|\n");
  
    for (l = 0; l < VL53L8CX_NB_TARGET_PER_ZONE; l++)
    {
      // Print distance and status 
      for (k = (zones_per_line - 1); k >= 0; k--)
      {
        if (Result->nb_target_detected[j+k]>0)
        {
          snprintf(report, sizeof(report),"| \033[38;5;10m%5ld\033[0m  :  %5ld ",
              (long)Result->distance_mm[(VL53L8CX_NB_TARGET_PER_ZONE * (j+k)) + l],
              (long)Result->target_status[(VL53L8CX_NB_TARGET_PER_ZONE * (j+k)) + l]);
              Serial.print(report);
        }
        else
        {
          snprintf(report, sizeof(report),"| %5s  :  %5s ", "X", "X");
          Serial.print(report);
        }
      }
      Serial.print("|\n");

      if (EnableAmbient || EnableSignal )
      {
        // Print Signal and Ambient 
        for (k = (zones_per_line - 1); k >= 0; k--)
        {
          if (Result->nb_target_detected[j+k]>0)
          {
            if (EnableSignal)
            {
              snprintf(report, sizeof(report),"| %5ld  :  ", (long)Result->signal_per_spad[(VL53L8CX_NB_TARGET_PER_ZONE * (j+k)) + l]);
              Serial.print(report);
            }
            else
            {
              snprintf(report, sizeof(report),"| %5s  :  ", "X");
              Serial.print(report);
            }
            if (EnableAmbient)
            {
              snprintf(report, sizeof(report),"%5ld ", (long)Result->ambient_per_spad[j+k]);
              Serial.print(report);
            }
            else
            {
              snprintf(report, sizeof(report),"%5s ", "X");
              Serial.print(report);
            }
          }
          else
          {
            snprintf(report, sizeof(report),"| %5s  :  %5s ", "X", "X");
            Serial.print(report);
          }
        }
        Serial.print("|\n");
      }
    }
  }
  for (i = 0; i < zones_per_line; i++)
   Serial.print(" -----------------");
  Serial.print("\n");
}

void toggle_resolution(void)
{
  sensor_vl53l8cx_top.vl53l8cx_stop_ranging();

  switch (res)
  {
    case VL53L8CX_RESOLUTION_4X4:
      res = VL53L8CX_RESOLUTION_8X8;
      break;

    case VL53L8CX_RESOLUTION_8X8:
      res = VL53L8CX_RESOLUTION_4X4;
      break;

    default:
      break;
  }
  sensor_vl53l8cx_top.vl53l8cx_set_resolution(res);
  sensor_vl53l8cx_top.vl53l8cx_start_ranging();
}

void toggle_signal_and_ambient(void)
{
  EnableAmbient = (EnableAmbient) ? false : true;
  EnableSignal = (EnableSignal) ? false : true;
}

void clear_screen(void)
{
  snprintf(report, sizeof(report),"%c[2J", 27); /* 27 is ESC command */
  Serial.print(report);
}

void display_commands_banner(void)
{
  snprintf(report, sizeof(report),"%c[2H", 27); /* 27 is ESC command */
  Serial.print(report);

  Serial.print("53L7A1 Simple Ranging demo application\n");
  Serial.print("--------------------------------------\n\n");

  Serial.print("Use the following keys to control application\n");
  Serial.print(" 'r' : change resolution\n");
  Serial.print(" 's' : enable signal and ambient\n");
  Serial.print(" 'c' : clear screen\n");
  Serial.print("\n");
}

void handle_cmd(uint8_t cmd)
{
  switch (cmd)
  {
    case 'r':
      toggle_resolution();
      clear_screen();
      break;

    case 's':
      toggle_signal_and_ambient();
      clear_screen();
      break;

    case 'c':
      clear_screen();
      break;

    default:
      break;
  }
}

platformio.ini

INI
Platform.io setting for B-L475E-IOT01A with required libraries
; PlatformIO Project Configuration File
;
;   Build options: build flags, source filter
;   Upload options: custom upload port, speed and extra flags
;   Library options: dependencies, extra library storages
;   Advanced options: extra scripting
;
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html

[env:disco_l475vg_iot01a]
platform = ststm32
board = disco_l475vg_iot01a
framework = arduino
monitor_speed = 460800
lib_deps = 
	knolleary/PubSubClient@^2.8
	bblanchon/ArduinoJson@^7.0.4
	https://github.com/stm32duino/VL53L8CX.git
	stm32duino/STM32duino ISM43362-M3G-L44@^1.1.1
lib_ignore =
	WiFi

Credits

Supachai Vorapojpisut

Supachai Vorapojpisut

2 projects • 1 follower
Background in Electrical Engineering with past experience in firmware development for several processor platforms.

Comments