Merge two sketches and use softwareserials

Hello all,

I sit now for 2 days and can not find a solution.
Searched forums, looked at similar sketches and tried to understand the structure and functions. countless tests...I give up.
I hope you can help me.

Probably quite simple for you guys:
I have 2 sketches for my ESP8266 that I need to put together.
Both separately work.

  1. sketch - laser distance meter with a TF mini and forwarding the measured values with mqtt - Taken from: https://www.fambach.net/ftmini-laser/

  2. sketch is reading air pressure and temperature from a BMP180 - Taken from: ESP8266 Wetterstation + Datenaufzeichnung und Visualisierung

For the BMP180, however, I lack the use of softwareserial, because the laser distance meter is already connected to the gpio 5.4. already with softwareserial alone only with the BMP180 I fail grandiosely.
how the data from the BMP180 then still transferred to mqtt is a whole other topic.

Maybe you can assemble me the two sketch and add the missing components.

because i am new in the forum, i can't upload any attachments.
For sketch 1 there are 5 files.

greetings and thanks
tom

TF_mini_mqtt_iobroker_Tom.ino

/* This example shows how to use the TFMini module.
The nodeMCU have an build in Watchdog and therefore it is necessary,
that you delete/disable all <<Serial.print>> commands from the TFMini.cpp.
Otherwise you will run into an restart loop, because the Watchdog become
activated...

Wiring:
TFMini  -> nodeMCU
SDA     -> D2 -> 4 -> Tx
SCL     -> D1 -> 5 -> Rx
VCC     -> 5V
GND     -> GND
*/
#include <Arduino.h>
#include <SoftwareSerial.h>
#include "TFMini.h"
#include <ESP8266WiFi.h>
#include "config.h"
#include <ArduinoOTA.h>
#include <PubSubClient.h>
#include "Adafruit_BMP085.h"
//#include "helper.h"


Adafruit_BMP085 bmp;
float tempBMP180;
float pressure;

// Setup software serial port
SoftwareSerial mySerial(3, 1);    // connection to TFMini
TFMini         tfmini;              // tfmini access
unsigned long  previousMillis = 0;  // access time
const long     interval = 100;    // interval at which to measure (milliseconds)

WiFiClient wiFiClient;
PubSubClient client(wiFiClient);

byte clientStatus, prevClientStatus = 99;

/*
-----------------S E T U P-----------------
*/
void setup() {

  // Step 1: Initialize hardware serial port (serial debug port)
  Serial.begin(115200);
  // wait for serial port to connect. Needed for native USB port only
  while (!Serial);

  // Step 2: Initialize the data rate for the SoftwareSerial port
  mySerial.begin(TFMINI_BAUDRATE);  // default boudrate is 115200
  delay(10);

  // Step 3: Initialize the TF Mini sensor
  tfmini.begin(&mySerial);
  Serial.println ("Initializing Serial and mySerial finished");

  /* Explicitly set the ESP8266 to be a WiFi-client, otherwise, it by default,
     would try to act as both a client and an access-point and could cause
     network-issues with your other WiFi-devices on your WiFi-network. */
  
  // Set WIFI module to STA mode
  WiFi.mode(WIFI_STA);
  WiFi.begin(WIFI_SSID, WIFI_PASS);
 
  // Wait
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
    
  }

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());

setupOTA();

  // MQTT
    client.setServer(MQTT_SERVER_IP, MQTT_SERVER_PORT);
    digitalWrite(TRIGGER_PIN, LOW);
    delay(2);
}

void ensureMQTTConnection (){
  if (!client.connected()) {
    Serial.println("Attempting MQTT connection...");
    // Attempt to connect

    if (MQTT_SERVER_USER_ID != "" && MQTT_SERVER_PASS != ""){
      client.connect(MQTT_CLIENT_NAME, MQTT_SERVER_USER_ID, MQTT_SERVER_PASS);
      }
    else (client.connect(MQTT_CLIENT_NAME));
    
    if(client.connected()){
      Serial.println("connected");
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}

void setupOTA(){
    ArduinoOTA.onStart([]() {
    String type;
    if (ArduinoOTA.getCommand() == U_FLASH) {
      type = "sketch";
    } else { // U_SPIFFS
      type = "filesystem";
    }

    // NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end()
    Serial.println("Start updating " + type);
    });
    ArduinoOTA.onEnd([]() {
    Serial.println("\nEnd");
    });
    ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
    Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
    });
    ArduinoOTA.onError([](ota_error_t error) {
    Serial.printf("Error[%u]: ", error);
    if (error == OTA_AUTH_ERROR) {
      Serial.println("Auth Failed");
    } else if (error == OTA_BEGIN_ERROR) {
      Serial.println("Begin Failed");
    } else if (error == OTA_CONNECT_ERROR) {
      Serial.println("Connect Failed");
    } else if (error == OTA_RECEIVE_ERROR) {
      Serial.println("Receive Failed");
    } else if (error == OTA_END_ERROR) {
      Serial.println("End Failed");
    }
  });
  ArduinoOTA.begin();
}

/*
-----------------L O O P-----------------
*/
void loop() {
  // we will not use an delay...
  // but we wait some short time before taking the next measurement
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= interval) {
    
  // save the last measure time
  previousMillis = currentMillis;
    
  // Take one TF Mini distance measurement
  uint16_t dist = tfmini.getDistance();
  uint16_t strength = tfmini.getRecentSignalStrength();
    
  // Display the measurement
  Serial.print(dist);
  Serial.print(" cm   Signal: ");
  Serial.println(strength);

  //MQWW Connectionint 
  ensureMQTTConnection();
    static unsigned long last = millis();
    if (millis() - last >= IDLE_TIME *1000) {
        last = millis();
        int waterlevel = tfmini.getDistance();
        char cdist[16];
        itoa(waterlevel ,cdist, 10);
        client.publish(MQTT_TOPIC_NAME_LEVEL_CM, cdist);
  }
 
 }
}

TFMini.cpp

/*
Arduino driver for Benewake TFMini time-of-flight distance sensor.
by Peter Jansen (December 11/2017)
This code is open source software in the public domain.

THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

The names of the contributors may not be used to endorse or promote products
derived from this software without specific prior written permission.
*/

#include "TFMini.h"

// Constructor
TFMini::TFMini() {
  // Empty constructor
}


boolean TFMini::begin(Stream* _streamPtr) {
  // Store reference to stream/serial object
  streamPtr = _streamPtr;

  // Clear state
  distance = -1;
  strength = -1;
  state = READY;

  // Set standard output mode
  setStandardOutputMode();

  return true;
}


// Public: The main function to measure distance.
uint16_t TFMini::getDistance() {
  int numMeasurementAttempts = 0;
  while (takeMeasurement() != 0) {
    numMeasurementAttempts += 1;
    if (numMeasurementAttempts > TFMINI_MAX_MEASUREMENT_ATTEMPTS) {
//      Serial.println ("TF Mini error: too many measurement attempts");
//      Serial.println ("Last error:");
      if (state == ERROR_SERIAL_NOHEADER)     //Serial.println("ERROR_SERIAL_NOHEADER");
      if (state == ERROR_SERIAL_BADCHECKSUM)  //Serial.println("ERROR_SERIAL_BADCHECKSUM");
      if (state == ERROR_SERIAL_TOOMANYTRIES) //Serial.println("ERROR_SERIAL_TOOMANYTRIES");

      state = ERROR_SERIAL_TOOMANYTRIES;
      distance = -1;
      strength = -1;
      return -1;
    }
  }

  if (state == MEASUREMENT_OK) {
    return distance;
  } else {
    return -1;
  }
}


// Public: Return the most recent signal strength measuremenet from the TF Mini
uint16_t TFMini::getRecentSignalStrength() {
  return strength;
}


// Private: Set the TF Mini into the correct measurement mode
void TFMini::setStandardOutputMode() {
  // Set to "standard" output mode (this is found in the debug documents)
  streamPtr->write((uint8_t)0x42);
  streamPtr->write((uint8_t)0x57);
  streamPtr->write((uint8_t)0x02);
  streamPtr->write((uint8_t)0x00);
  streamPtr->write((uint8_t)0x00);
  streamPtr->write((uint8_t)0x00);
  streamPtr->write((uint8_t)0x01);
  streamPtr->write((uint8_t)0x06);

  delay(100);
}


// Private: Handles the low-level bits of communicating with the TFMini, and detecting some communication errors.
int TFMini::takeMeasurement() {
  int numCharsRead = 0;
  uint8_t lastChar = 0x00;

  // Step 1: Read the serial stream until we see the beginning of the TF Mini header, or we timeout reading too many characters.
  while (1) {

    if (streamPtr->available()) {
      uint8_t curChar = streamPtr->read();

      if ((lastChar == 0x59) && (curChar == 0x59)) {
        // Break to begin frame
        break;

      } else {
        // We have not seen two 0x59's in a row -- store the current character and continue reading.
        lastChar = curChar;
        numCharsRead += 1;
      }
    }

    // Error detection:  If we read more than X characters without finding a frame header, then it's likely there is an issue with
    // the Serial connection, and we should timeout and throw an error.
    if (numCharsRead > TFMINI_MAXBYTESBEFOREHEADER) {
      state = ERROR_SERIAL_NOHEADER;
      distance = -1;
      strength = -1;
      if (TFMINI_DEBUGMODE == 1)// Serial.println("ERROR: no header");
      return -1;
    }

  }

  // Step 2: Read one frame from the TFMini
  uint8_t frame[TFMINI_FRAME_SIZE];

  uint8_t checksum = 0x59 + 0x59;
  for (int i=0; i<TFMINI_FRAME_SIZE; i++) {
    // Read one character
    while (!streamPtr->available()) {
      // wait for a character to become available
    }
    frame[i] = streamPtr->read();

    // Store running checksum
    if (i < TFMINI_FRAME_SIZE-2) {
      checksum += frame[i];
    }
  }

  // Step 2A: Compare checksum
  // Last byte in the frame is an 8-bit checksum
  uint8_t checksumByte = frame[TFMINI_FRAME_SIZE-1];
  if (checksum != checksumByte) {
    state = ERROR_SERIAL_BADCHECKSUM;
    distance = -1;
    strength = -1;
    if (TFMINI_DEBUGMODE == 1)// Serial.println("ERROR: bad checksum");
    return -1;
  }


  // Step 3: Interpret frame
  uint16_t dist = (frame[1] << 8) + frame[0];
  uint16_t st = (frame[3] << 8) + frame[2];
  uint8_t reserved = frame[4];
  uint8_t originalSignalQuality = frame[5];


  // Step 4: Store values
  distance = dist;
  strength = st;
  state = MEASUREMENT_OK;

  // Return success
  return 0;
}

TFMini.h

/*
Arduino driver for Benewake TFMini time-of-flight distance sensor. 
by Peter Jansen (December 11/2017)
This code is open source software in the public domain.

THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  

The names of the contributors may not be used to endorse or promote products
derived from this software without specific prior written permission. 
*/

#if (ARDUINO >= 100)
 #include "Arduino.h"
#else
 #include "WProgram.h"
#endif


// Defines
#define TFMINI_BAUDRATE   115200
#define TFMINI_DEBUGMODE  0

// The frame size is nominally 9 characters, but we don't include the first two 0x59's marking the start of the frame
#define TFMINI_FRAME_SIZE                 7

// Timeouts
#define TFMINI_MAXBYTESBEFOREHEADER       30
#define TFMINI_MAX_MEASUREMENT_ATTEMPTS   10

// States
#define READY                             0
#define ERROR_SERIAL_NOHEADER             1
#define ERROR_SERIAL_BADCHECKSUM          2
#define ERROR_SERIAL_TOOMANYTRIES         3
#define MEASUREMENT_OK                    10


//
// Driver Class Definition
//
class TFMini {
  public: 
    TFMini(void);

    // Configuration
    boolean begin(Stream* _streamPtr);

    // Data collection
    uint16_t getDistance();
    uint16_t getRecentSignalStrength();

  private:
    Stream* streamPtr;
    int state;
    uint16_t distance;
    uint16_t strength;
    
    // Low-level communication
    void setStandardOutputMode();
    int takeMeasurement();
    
    
};

config.h

#define WIFI_SSID "Yacht"       //enter SSID and pass without <>
#define WIFI_PASS "Tommyland78"

#define MQTT_SERVER_IP "192.168.1.2"
#define MQTT_SERVER_PORT 1883

#define MQTT_CLIENT_NAME "Yacht_Laser_Höhenmesser"
#define MQTT_SERVER_USER_ID "Administrator"      // leave quotes empty, if no authentication is required
#define MQTT_SERVER_PASS "Tommyland78"

#define MQTT_TOPIC_NAME_LEVEL_CM "Schiff/Höhenmesser/Laser"

#define TRIGGER_PIN 12 //5 //~D1
#define ECHO_PIN 14 //4    //~D2

#define SENSOR_DISTANCE_TO_MAX_VOLUME 0         // in cm - minimum is 21
#define SENSOR_OFFSET 0                         // use ruler and the mqtt topic cistern/level/cm to calibrate this value


#define IDLE_TIME 1                    // in seconds

#define TIME_PERIOD_BETWEEN_READINGS 10   // in seconds
#define SAMPLE_SIZE 10



/** ===============ADVANCED SETTINGS==================== **/

#define TRIGGER_PULSE_WIDTH 15      // in microseconds - adjust this setting if your sensor doesn't send the pulse

#define READING_TIMEOUT 60      // in milliseconds - max is 60ms - post-pulse time period after which the MCU gives up waiting for a return signal

Files from sketch with the laser

BMP180

#include "Adafruit_BMP085.h"

Adafruit_BMP085 bmp;
float tempBMP180;
float pressure;

void setup() {
  Serial.begin(115200);

  if (!bmp.begin()) {
    Serial.println("Sensor BMP180 nicht gefunden!");
    while (1) {}
  }
}

void loop() {

  tempBMP180 = bmp.readTemperature();
  pressure = bmp.readPressure();

  Serial.print("Temperatur BMP180: ");
  Serial.print(tempBMP180);
  Serial.println("*C");

  Serial.print("Luftdruck BMP180: ");
  Serial.print(pressure/100);
  Serial.println("hPa");

  Serial.println();
  delay(2000);
}

Welcome to the forum.

The TFMini uses Serial/UART, it does not have a I2C bus. Can you try not to mix the Serial/UART and the I2C bus (SDA, SCL) ?

The BMP180 uses the I2C bus.
The I2C bus used default pin D2 (GPIO4) = SDA and pin D1 (GPIO5) = SCL.

Can you put the SoftwareSerial for the TFmini on other pins ?
They don't have to be on pin 3 and 1, change these numbers:

SoftwareSerial mySerial(3, 1);

Please post links to the specs of your esp8266 board and the sensors you are using. When you say "ESP8266" that could mean any of 20+ different boards. There are multiple BMP180 board designs also.

On all ESP8266, i2c is always software i2c, so this also can be moved to different pins than the default SDA/SCL pins, if that helps to solve the problem.

Yes, many forum members could do that. But most will not. It's the "teach a man to fish" versus "give a man a fish" principle. You will get unlimited free help if you demonstrate that you are willing to learn.

yes sure I can move the ports for the TF Mini.
I had already tried that. So the TF Mini on 3 and 1 for example was also my attempts. Then additionally the BMP180 with on 4 and 5. but that did not work.

I guess I have had errors in the code.

BR
Tom

Hello Paul,

the board is a:
AZDelivery NodeMCU Amica Module V2 ESP8266 ESP

the laser distance meter is a:
Benewake TFmini Plus I2C UART

the BMP180 is a:
AZDelivery GY-68 BMP180

BR
Tom

I see, it can be set to UART or I2C mode over the same wires.

If you use the default D1 and D2 for the I2C bus, then you can not use pin D1 for the SoftwareSerial at the same time.

I don't know why the I2C bus on 4 and 5 and the TFmini at 3 and 1 does not work.

Hi Tom,

@dertom78 That's a good feature. I would definitely look into that. If you can set the lidar sensor to i2c, that should make things easier and save pins.

And you may need to save pins because while it looks like the NodeMCU has lots of pins, a lot of them are not useful. The Wemos Mini has as many useful/useable pins as the NodeMCU but without the extra bulk.

Hello all,

I first had to try to understand that sensors communicate differently.
If I understand correctly, the I2C is a type of communication that uses specific addresses.
So the sensors can be kept apart.
The TF-mini is now switched to I2C. The address is 0x10.
The BMP actually a BMP 085 has the address 0x77.

Now I have found 2 sketch that work individually for themselves.

Do I understand this correctly? Both sensors can now use the same TX/RX pin on the ESP8266?
If so, how do I bring this together now?
This is way too complex for me. I don't even understand 30% of the sketch.

#include <Adafruit_BMP085.h>

/*************************************************** 
  This is an example for the BMP085 Barometric Pressure & Temp Sensor

  Designed specifically to work with the Adafruit BMP085 Breakout 
  ----> https://www.adafruit.com/products/391

  These pressure and temperature sensors use I2C to communicate, 2 pins
  are required to interface
  Adafruit invests time and resources providing this open source code, 
  please support Adafruit and open-source hardware by purchasing 
  products from Adafruit!

  Written by Limor Fried/Ladyada for Adafruit Industries.  
  BSD license, all text above must be included in any redistribution
 ****************************************************/

// Connect VCC of the BMP085 sensor to 3.3V (NOT 5.0V!)
// Connect GND to Ground
// Connect SCL to i2c clock - on '168/'328 Arduino Uno/Duemilanove/etc thats Analog 5
// Connect SDA to i2c data - on '168/'328 Arduino Uno/Duemilanove/etc thats Analog 4
// EOC is not used, it signifies an end of conversion
// XCLR is a reset pin, also not used here

Adafruit_BMP085 bmp;
  
void setup() {
  Serial.begin(115200);
  if (!bmp.begin()) {
	Serial.println("Could not find a valid BMP085 sensor, check wiring!");
	while (1) {}
  }
}
  
void loop() {
    Serial.print("Temperature = ");
    Serial.print(bmp.readTemperature());
    Serial.println(" *C");
    
    Serial.print("Pressure = ");
    Serial.print(bmp.readPressure());
    Serial.println(" Pa");
    
    // Calculate altitude assuming 'standard' barometric
    // pressure of 1013.25 millibar = 101325 Pascal
    Serial.print("Altitude = ");
    Serial.print(bmp.readAltitude());
    Serial.println(" meters");

    Serial.print("Pressure at sealevel (calculated) = ");
    Serial.print(bmp.readSealevelPressure());
    Serial.println(" Pa");

  // you can get a more precise measurement of altitude
  // if you know the current sea level pressure which will
  // vary with weather and such. If it is 1015 millibars
  // that is equal to 101500 Pascals.
    Serial.print("Real altitude = ");
    Serial.print(bmp.readAltitude(101500));
    Serial.println(" meters");
    
    Serial.println();
    delay(500);
}
/*This is a reference code about Arduino UNO receive TFmini-Plus I²C Data from I²C bus
 * Arduino is Master, TFminiPlus-I²C is slave. Master send command to TFmini Plus
 * TFminiPlus needs hardware verson equal or above 1.3.5 and firmware 1.9.0.
 * Before test IIC,you should config TFminiPlus from TTL default to IIC mode.
 * Author:zhaomingxin@Benewake
 * Update date:2019.6.26
 * This is for free.
 */
#include <Wire.h>

void setup() {
  Wire.begin();        // join i2c bus (address optional for master)
  Serial.begin(115200);  // start serial for output print
  GetLidarVersionFromIIC(0x10);//Get #0x10 Lidar's firmware version.
  delay(100);
  SetLidarFrequenceFromIIC(0x10 , 100);//Set #0x10 Lidar's output frame rate to 100Hz. //If you don't need to set the frame rate, please comment this line.
  delay(100);
  SaveLidarSetFromIIC(0x10);//Save #10 Lidar`s set.
  delay(100);
  
}

void loop() {
  Get_LidarDatafromIIC(0x10);//Get #10 Lidar measurment result from IIC;
    delay(250);
}

void Get_LidarDatafromIIC(unsigned char address){
  char i = 0; 
  unsigned char rx_buf[9] = {0}; 
  unsigned char check_sum = 0;
  Wire.beginTransmission(address); // Begin a transmission to the I2C Slave device with the given address. 
  Wire.write(0x5A); // see product mannual table 11:Obtain Data Frame
  Wire.write(0x05); // 
  Wire.write(0x00); // 
  Wire.write(0x01); // 
  Wire.write(0x60); // 
  Wire.endTransmission(1);  // Send a STOP Sign
  Wire.endTransmission(0);  // Send a START Sign
  Wire.requestFrom(address, 9 , 1); // request 9 bytes from slave device address

  //Read IIC data and save to rx_buf[]
   while ( Wire.available()) 
  { 
    rx_buf[i] = Wire.read(); // received one byte 

    i++; 
  }
  //Judge and print result via serial
    for(i=0;i<8;i++)
      check_sum += rx_buf[i];
   if(rx_buf[0] == 0x59 && rx_buf[1] == 0x59 &&  rx_buf[8] == check_sum)
   {
         Serial.print("Distance=");
      Serial.print(rx_buf[3]*256+rx_buf[2]);
      Serial.print(";");
      Serial.print("Strength=");
      Serial.print(rx_buf[5]*256+rx_buf[4]);
   }
   else
   {
      Serial.print("Maybe something wrong to Get Lidar`s data.");   
   }
  Serial.print("\r\n"); 
}

void GetLidarVersionFromIIC(unsigned char address)
{
  char i = 0; 
  unsigned char rx_buf[7] = {0}; 
  unsigned char check_sum = 0;
  Wire.beginTransmission(address); // Begin a transmission to the I2C Slave device with the given address. 
   Wire.endTransmission(1);  // Send a STOP Sign 
  delay(100);
  Wire.endTransmission(0);  // Send a START Sign 
  Wire.requestFrom(address, 7 , 1); // request 9 bytes from slave device address
  //Read IIC data and save to rx_buf[]
   while ( Wire.available()) 
  { 
    rx_buf[i] = Wire.read(); // received one byte 
    Serial.print("0x");
    Serial.print(rx_buf[i],HEX);
    Serial.print(";");
    i++;
   }
   //Judge and print result via serial
   for(i=0;i<6;i++)
      check_sum += rx_buf[i];
   if(rx_buf[0] == 0x5A && rx_buf[1] == 0x07 && rx_buf[2] == 0x01 && rx_buf[6] == check_sum)
   {
      Serial.print("    The Lidar firmware version is v");
      Serial.print(rx_buf[5],HEX);
      Serial.print(".");
      Serial.print(rx_buf[4],HEX);
      Serial.print(".");
      Serial.print(rx_buf[3],HEX);    
   }
   else
   {
      Serial.print("Check version error!");
   }

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

void SetLidarFrequenceFromIIC(unsigned char address,byte frequence)
{
  char i = 0; 
  unsigned char rx_buf[6] = {0}; 
  unsigned char check_sum = 0;
  unsigned char fre_L , fre_H;
  fre_L = frequence;
  fre_H = frequence>>8;
  Wire.beginTransmission(address); // Begin a transmission to the I2C Slave device with the given address. 
  Wire.write(0x5A); // see product mannual table 11:Obtain Data Frame
  Wire.write(0x06); // 
  Wire.write(0x03); // 
  Wire.write(fre_L); // 
  Wire.write(fre_H); // 
  Wire.write(0x5A+0x06+0x03+fre_L+fre_H); // 
  Wire.endTransmission(1);  // Send a STOP Sign 
  delay(100);
  Wire.endTransmission(0);  // Send a START Sign 
  Wire.requestFrom(address, 6 , 1); // request 9 bytes from slave device address
  //Read IIC data and save to rx_buf[]
   while ( Wire.available()) 
  { 
    rx_buf[i] = Wire.read(); // received one byte 
    //Print the rx_buf data via serial
    Serial.print("0x");
    Serial.print(rx_buf[i],HEX);
    Serial.print(";");
    i++; 
   }
   //Judge and print result via serial
   for(i=0;i<5;i++)
    check_sum += rx_buf[i];
   if(rx_buf[0] == 0x5A && rx_buf[1] == 0x06 && rx_buf[2] == 0x03 && rx_buf[5] == check_sum)
   {
      Serial.print("    Lidar's frame rate has been set to ");
      Serial.print(rx_buf[3] + rx_buf[4]*256,DEC);
      Serial.print("Hz");
   }
   else
   {
      Serial.print("Set frame rate error!");
   }

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

}

void SaveLidarSetFromIIC(unsigned char address)
{
  char i = 0; 
  unsigned char rx_buf[5] = {0}; 
  Wire.beginTransmission(address); // Begin a transmission to the I2C Slave device with the given address. 
  Wire.write(0x5A); // see product mannual table 11:Obtain Data Frame
  Wire.write(0x04); // 
  Wire.write(0x11); // 
  Wire.write(0x6f); // 
  Wire.endTransmission(1);  // Send a STOP Sign 
  delay(100);
  Wire.endTransmission(0);  // Send a START Sign 
  Wire.requestFrom(address, 5 , 1); // request 9 bytes from slave device address
  //Read IIC data and save to rx_buf[]
   while ( Wire.available()) 
  { 
    rx_buf[i] = Wire.read(); // received one byte 
    Serial.print("0x");
    Serial.print(rx_buf[i],HEX);
    Serial.print(";");
    i++; 
   }
   //Judge and print result via serial
   if(rx_buf[0] == 0x5A && rx_buf[1] == 0x05 && rx_buf[2] == 0x11 && rx_buf[3] == 0x00 && rx_buf[4] == 0x70)
   {
       Serial.print("    Lidar's set has been saved");
   }
   else
   {
      Serial.print("Save error!");
   }

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

Multiple communications devices and protocols - a layman's analogy.

Serial - uses a hardware 'device'* UART. Assigned to hypothetical pins A, B which communicate using a particular pattern of ones and zeros at a fixed clock rate

I2C - uses a hardware 'device'*. Assigned to hypothetical pins C, D, and which communicate using a second unique pattern of ones and zeros at a different fixed clock rate

SPI - uses a hardware 'device'*. Assigned to hypothetical pins E, F, G and which communicate using a third unique pattern of ones and zeros at yet again, a different fixed clock rate

All are different devices using different signaling features, and must utilize different, specific pins of your Arduino.
'* -device, in this context, is a specific subregion of the semiconductor 'chip' inside your Arduino. Think of these as unique neighbourhoods within your city, interconnected by streets.

Thanks for the summary.
Still one question - to be sure - with I2C all devices are connected to the same PINs?
From your example, all devices to C, D?

The I2C bus has SDA and SCL, they are digital signals that can go in both directions.
Each I2C device has its own I2C address, and the Master puts that first on the I2C bus so only that device will respond.

All the SDA pins of all devices are connected to the SDA of the Master.
The same for the SCL pin, all those SCL pins are connected to the SCL of the Master.

However, if there are two I2C devices that have the same I2C address, then they can not be on the same I2C bus.

There are I2C multiplexers out there that will allow this, but the implementation cost is high because the user must then manage the multiplexer, as the standard I2C libraries don't cover that detail:

(Link chosen because Adafruit gives coherent descriptions of the technical context of the device, in comparison with Amazon/Aliexpress; Adafruit are therefore worthy of support from the community.)

Still, if I were to want to use something that only had one address, and I wanted more than that, it might be worth the complexity ultimately.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.