Infineon Team
Published © MIT

Underwater Data Collection with XMC1400, CAN, and DPS368

Dive into lake water monitoring with the help of CAN communication.

AdvancedFull instructions providedOver 2 days944
Underwater Data Collection with XMC1400, CAN, and DPS368

Things used in this project

Hardware components

Infineon XMC1400 2GO KIT
Infineon XMC1400 2GO KIT
×2
S2GO PRESSURE DPS368
Infineon S2GO PRESSURE DPS368
×1
DC-SHIELD BTN9970LV
Infineon DC-SHIELD BTN9970LV
×1
TLS4120 5V CORE-BOARD
Infineon TLS4120 5V CORE-BOARD
×1
TDS meter
×1
TinyScreen-OLED TinyShield
TinyCircuits TinyScreen-OLED TinyShield
×1
DC Motor, 12 V
DC Motor, 12 V
×1
Pushbutton switch 12mm
SparkFun Pushbutton switch 12mm
×1
9V battery (generic)
9V battery (generic)
×1
cable (10m*4)
×1
Solderless Breadboard Half Size
Solderless Breadboard Half Size
×1

Software apps and online services

Arduino IDE
Arduino IDE

Hand tools and fabrication machines

Soldering iron (generic)
Soldering iron (generic)
Premium Female/Male Extension Jumper Wires, 40 x 6" (150mm)
Premium Female/Male Extension Jumper Wires, 40 x 6" (150mm)
3D Printer (generic)
3D Printer (generic)

Story

Read more

Custom parts and enclosures

motor-holder

buoy-cover

spool_cover

buoy

caps11

Sketchfab still processing.

caps22

Sketchfab still processing.

caps12

Sketchfab still processing.

caps21

Sketchfab still processing.

spool

Sketchfab still processing.

Schematics

submerged-device

all-project

Code

Under_water_node

Arduino
#include <Dps3xx.h>
#include <CAN.h>

// TDS Sensor Configuration
#define TdsSensorPin A0
#define VREF 5.0              // Analog reference voltage (Volts)
#define SCOUNT  30            // Number of sample points

int analogBuffer[SCOUNT];     // Store analog values from the ADC
int analogBufferTemp[SCOUNT];
int analogBufferIndex = 0;

// TDS Calculation Variables
float averageVoltage = 0;
float tdsValue = 0;

// DPS3xx Sensor Object
Dps3xx Dps3xxPressureSensor;

// Temperature and Pressure Variables
float temperature = 25.0;     // Default temperature (will be updated by sensor)
float pressure;
uint8_t oversampling = 7;
int16_t ret;

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

  // Initialize the DPS3xx Pressure Sensor
  Dps3xxPressureSensor.begin(Wire);
  // If the library provides a method to check the status, use it here
  // For example:
  // if (!Dps3xxPressureSensor.isInitialized()) {
  //   Serial.println("Failed to initialize DPS3xx sensor!");
  //   while (1);
  // }
  Serial.println("DPS3xx Sensor Initialized.");

  // Initialize the CAN bus at 500 kbps
  if (!CAN.begin(500E3)) {
    Serial.println("Starting CAN failed!");
    while (1);
  }
  Serial.println("CAN Bus Initialized.");

  pinMode(TdsSensorPin, INPUT);
}

void loop() {
  // Read analog value every 40 milliseconds
  static unsigned long analogSampleTimepoint = millis();
  if (millis() - analogSampleTimepoint > 40U) {
    analogSampleTimepoint = millis();
    analogBuffer[analogBufferIndex] = analogRead(TdsSensorPin);
    analogBufferIndex = (analogBufferIndex + 1) % SCOUNT;
  }

  // Process data every 800 milliseconds
  static unsigned long printTimepoint = millis();
  if (millis() - printTimepoint > 800U) {
    printTimepoint = millis();

    // Copy the analog buffer for processing
    for (int i = 0; i < SCOUNT; i++) {
      analogBufferTemp[i] = analogBuffer[i];
    }

    // Read temperature from DPS3xx sensor
    ret = Dps3xxPressureSensor.measureTempOnce(temperature, oversampling);
    if (ret != 0) {
      Serial.print("Temperature measurement failed! Error: ");
      Serial.println(ret);
    } else {
      Serial.print("Temperature: ");
      Serial.print(temperature);
      Serial.println(" °C");

      // Send the temperature over the CAN bus
      CAN.beginPacket(0x123);  // Replace with your CAN message ID
      CAN.write((uint8_t*)&temperature, sizeof(temperature));
      CAN.endPacket();
    }

    // Read pressure from DPS3xx sensor
    ret = Dps3xxPressureSensor.measurePressureOnce(pressure, oversampling);
    if (ret != 0) {
      Serial.print("Pressure measurement failed! Error: ");
      Serial.println(ret);
    } else {
      Serial.print("Pressure: ");
      Serial.print(pressure);
      Serial.println(" Pa");

      // Send the pressure over the CAN bus
      CAN.beginPacket(0x456);  // Replace with your CAN message ID
      CAN.write((uint8_t*)&pressure, sizeof(pressure));
      CAN.endPacket();
    }

    // TDS Calculation
    averageVoltage = getMedianNum(analogBufferTemp, SCOUNT) * VREF / 1024.0;

    // Temperature compensation
    float compensationCoefficient = 1.0 + 0.02 * (temperature - 25.0);
    float compensationVoltage = averageVoltage / compensationCoefficient;

    // Convert voltage to TDS value
    tdsValue = (133.42 * pow(compensationVoltage, 3)
                - 255.86 * pow(compensationVoltage, 2)
                + 857.39 * compensationVoltage) * 0.5;

    Serial.print("TDS Value: ");
    Serial.print(tdsValue, 0);
    Serial.println(" ppm");

    // Send TDS value over the CAN bus
    CAN.beginPacket(0x789);  // Replace with your CAN message ID
    CAN.write((uint8_t*)&tdsValue, sizeof(tdsValue));
    CAN.endPacket();
  }
}

// Median filtering algorithm
int getMedianNum(int bArray[], int iFilterLen) {
  int bTab[iFilterLen];
  memcpy(bTab, bArray, iFilterLen * sizeof(int));
  for (int j = 0; j < iFilterLen - 1; j++) {
    for (int i = 0; i < iFilterLen - j - 1; i++) {
      if (bTab[i] > bTab[i + 1]) {
        int temp = bTab[i];
        bTab[i] = bTab[i + 1];
        bTab[i + 1] = temp;
      }
    }
  }
  if ((iFilterLen & 1) > 0) {
    return bTab[(iFilterLen - 1) / 2];
  } else {
    return (bTab[iFilterLen / 2] + bTab[iFilterLen / 2 - 1]) / 2;
  }
}

Surface_node

Arduino
#include "btn99x0_motor_control.hpp"
#include "btn99x0_half_bridge.hpp"
#include <CAN.h>
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
// OLED display setup
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 32
#define OLED_RESET    -1
#define SCREEN_ADDRESS 0x3C
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// Variables to store sensor values
float temperature = 0.0;
float pressure = 0.0;
float tds = 0.0;
using namespace btn99x0;

// Pin definitions
#define HB1_IN     1   // PWM Pin for DC-Shield
#define HB2_IN     2   // PWM Pin for DC-Shield
#define HB1_INH    3   // Inhibit PIN for Halfbridge 1 on DC shield
#define HB2_INH    4   // Inhibit PIN for Halfbridge 2 on DC shield
#define HB1_Isense A1  // Diagnosis pin for Half-bridge 1
#define HB2_Isense A0  // Diagnosis pin for Half-bridge 2

// Motor speed setting
#define SPEED 150

// Button pin
#define BUTTON_PIN 0

// IO pins structs
io_pins_t hb1_io_pins {
  HB1_Isense,
  HB1_IN,
  HB1_INH
};

io_pins_t hb2_io_pins {
  HB2_Isense, 
  HB2_IN,
  HB2_INH
};

hw_conf_t hw_conf = {
    2000, // Resistor on the DC shield for the Diagnosis pin
    3.3,  // Maximum voltage on the ADC Pin
    1023
};

DCShield shield(hb1_io_pins, hb2_io_pins, hw_conf);
MotorControl btn_motor_control(shield);

// Direction state variable
bool direction = false; // false for positive, true for negative

void setup() {
  Serial.begin(9600);
  Serial.println("Serial initialized");

  // Initialize OLED
  if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
    while (1); // Stop execution if OLED initialization fails
  }
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(0, 0);
  display.println("Initializing...");
  display.display();
  delay(2000);

  // Initialize CAN bus at 500 kbps
  if (!CAN.begin(500E3)) {  // 500 kbps
    Serial.println("Starting CAN failed!");
    while (1);
  }
  Serial.println("CAN Bus Initialized.");

  display.clearDisplay();
  display.setCursor(0, 0);
  display.println("Receiver Ready");
  display.display();
  delay(2000);

  

  // Set the button pin mode. Adjust if you have a pull-up or pull-down:
  pinMode(BUTTON_PIN, INPUT);

  delay(5000);
  btn_motor_control.begin();
  delay(2000);

  // Set the slew rate
  btn_motor_control.set_slew_rate(SLEW_RATE_LEVEL_7);
}

void loop() {
    int packetSize = CAN.parsePacket();

  if (packetSize) {
    uint32_t canId = CAN.packetId();
    if (canId == 0x123 || canId == 0x456 || canId == 0x789) {
      if (packetSize == sizeof(float)) {
        float value;
        CAN.readBytes((char*)&value, sizeof(value));

        if (canId == 0x123) {
          Serial.print("Temperature: ");
          Serial.println(value, 1);
        } else if (canId == 0x456) {
          Serial.print("Pressure: ");
          Serial.println(value, 1);
        } else if (canId == 0x789) {
          Serial.print("TDS: ");
          Serial.println(value, 1);
        }
      }
    }
  }
  static int lastButtonState = HIGH;
  int buttonState = digitalRead(BUTTON_PIN);

  // Check for rising edge: HIGH -> LOW
  if (buttonState == LOW && lastButtonState == HIGH) {
    // Toggle direction on each new press
    direction = !direction;
  }

  // Run motor if button is pressed, else stop
  if (buttonState == LOW) {
    if (direction) {
      btn_motor_control.set_speed(SPEED);  // Turn motor in one direction
    } else {
      btn_motor_control.set_speed(-SPEED); // Turn motor in opposite direction
    }
  } else {
    // Stop the motor when button is not pressed
    btn_motor_control.set_speed(0);
  }

  // Store the button state for next loop iteration
  lastButtonState = buttonState;

  // Short delay to reduce switch bounce (can be improved with actual debouncing)
  delay(50);
}

oled-set-up-test

Arduino
#include <CAN.h>
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>


// OLED display setup
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 32
#define OLED_RESET    -1
#define SCREEN_ADDRESS 0x3C
using namespace btn99x0;

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

// Variables to store sensor values
float temperature = 0.0;
float pressure = 0.0;
float tds = 0.0;

bool newDataReceived = false;

void setup() {


  // Initialize OLED
  if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
    while (1); // Stop execution if OLED initialization fails
  }
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(0, 0);
  display.println("Initializing...");
  display.display();
  delay(2000);

  Serial.begin(9600);

  // Initialize CAN bus at 500 kbps
  if (!CAN.begin(500E3)) {  // 500 kbps
    Serial.println("Starting CAN failed!");
    while (1);
  }
  Serial.println("CAN Bus Initialized.");

  display.clearDisplay();
  display.setCursor(0, 0);
  display.println("Receiver Ready");
  display.display();
  delay(2000);
}

void loop() {

  int packetSize = CAN.parsePacket();

  if (packetSize) {
    uint32_t canId = CAN.packetId();
    if (canId == 0x123 || canId == 0x456 || canId == 0x789) {
      if (packetSize == sizeof(float)) {
        float value;
        CAN.readBytes((char*)&value, sizeof(value));

        if (canId == 0x123) {
          Serial.print("Temperature: ");
          Serial.println(value, 1);
          temperature = value;
        } else if (canId == 0x456) {
          Serial.print("Pressure: ");
          Serial.println(value, 1);
          pressure = value;
        } else if (canId == 0x789) {
          Serial.print("TDS: ");
          Serial.println(value, 1);
          tds = value;
        }
        newDataReceived = true; // Set flag to update display
      }
    }
  }

  // Update the display only when new data is received
  if (newDataReceived) {
    updateDisplay();
    newDataReceived = false; // Reset flag
  }
}

void updateDisplay() {
  display.clearDisplay();
  display.setCursor(0, 0);
  display.print("Temp: ");
  display.println(temperature, 1);
  display.print("Pressure: ");
  display.println(pressure, 1);
  display.print("TDS: ");
  display.println(tds, 1);
  display.display();
    display.print("Euler: ");
  display.println(0, 1);
  display.display();
}

motor-test

Arduino
#include "btn99x0_motor_control.hpp"
#include "btn99x0_half_bridge.hpp"

using namespace btn99x0;

// Pin definitions
#define HB1_IN     1   // PWM Pin for DC-Shield
#define HB2_IN     2   // PWM Pin for DC-Shield
#define HB1_INH    3   // Inhibit PIN for Halfbridge 1 on DC shield
#define HB2_INH    4   // Inhibit PIN for Halfbridge 2 on DC shield
#define HB1_Isense A1  // Diagnosis pin for Half-bridge 1
#define HB2_Isense A0  // Diagnosis pin for Half-bridge 2

// Motor speed setting
#define SPEED 250

// Button pin
#define BUTTON_PIN 0

// IO pins structs
io_pins_t hb1_io_pins {
  HB1_Isense,
  HB1_IN,
  HB1_INH
};

io_pins_t hb2_io_pins {
  HB2_Isense, 
  HB2_IN,
  HB2_INH
};

hw_conf_t hw_conf = {
    2000, // Resistor on the DC shield for the Diagnosis pin
    3.3,  // Maximum voltage on the ADC Pin
    1023
};

DCShield shield(hb1_io_pins, hb2_io_pins, hw_conf);
MotorControl btn_motor_control(shield);

// Direction state variable
bool direction = false; // false for positive, true for negative

void setup() {
  Serial.begin(9600);
  Serial.println("Serial initialized");

  // Set the button pin mode. Adjust if you have a pull-up or pull-down:
  pinMode(BUTTON_PIN, INPUT);

  delay(5000);
  btn_motor_control.begin();
  delay(2000);

  // Set the slew rate
  btn_motor_control.set_slew_rate(SLEW_RATE_LEVEL_7);
}

void loop() {
  static int lastButtonState = HIGH;
  int buttonState = digitalRead(BUTTON_PIN);

  // Check for rising edge: HIGH -> LOW
  if (buttonState == LOW && lastButtonState == HIGH) {
    // Toggle direction on each new press
    direction = !direction;
  }

  // Run motor if button is pressed, else stop
  if (buttonState == LOW) {
    if (direction) {
      btn_motor_control.set_speed(SPEED);  // Turn motor in one direction
    } else {
      btn_motor_control.set_speed(-SPEED); // Turn motor in opposite direction
    }
  } else {
    // Stop the motor when button is not pressed
    btn_motor_control.set_speed(0);
  }

  // Store the button state for next loop iteration
  lastButtonState = buttonState;

  // Short delay to reduce switch bounce (can be improved with actual debouncing)
  delay(50);
}

Credits

Infineon Team
100 projects • 157 followers
Contact

Comments

Please log in or sign up to comment.