SDI-12 Sensor with Feather M0 and Adalogger

General project help for Adafruit customers

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
Post Reply
User avatar
asaeed01
 
Posts: 2
Joined: Thu Jan 16, 2025 1:00 pm

SDI-12 Sensor with Feather M0 and Adalogger

Post by asaeed01 »

Hello,
I was having extreme problems with a project I'm continuing from somebody else which is supposed to be a datalogger for SDI-12 sensors. I was able to ensure everything was functioning correctly but still have not been able to receive any input from the sensors. I am not sure what the problem since I am a beginner but I believe it is the code which is not correctly calling upon the correct pins. I can attach whatever is required for help and I've attached a photo of the project thus far.

Thanks
boximage.jpg
boximage.jpg (829.09 KiB) Viewed 17 times

User avatar
asaeed01
 
Posts: 2
Joined: Thu Jan 16, 2025 1:00 pm

Re: SDI-12 Sensor with Feather M0 and Adalogger

Post by asaeed01 »

I've also attached the code here

Code: Select all

#include <SDI12.h>
#include <SPI.h>
#include <SD.h>
#include <LoRa.h>
#include "RTClib.h"
#include "ArduinoLowPower.h"

RTC_PCF8523 rtc;
 
#define DATAPIN 15         // change to the proper pin for sdi-12 data pin, I prefer D7
#define VBATPIN 9

SDI12 mySDI12(DATAPIN); 

// Timing       
int interval = 5;         // set the interval in minutes
// Strings
//String dString = "";              // Variable to assign data too
char fname[] = "Logger.csv";    // Variable storing the filename 

// variables for the SDI reader
String command = "";

// LoRa network
byte msgCount = 0;            // count of outgoing messages
byte localAddress = 0x3;      // address of this device
byte destination = 0xFF;      // destination to send to

void setup () 
{  String dString = "";
   Serial.begin(57600);
   delay(1500);

   // starting RTC clock
   //rtc.start();
   if (!rtc.begin()) {
    Serial.println("Couldn't find RTC");
    Serial.flush();
    while (1) delay(10);
  }


  if (!rtc.initialized() || rtc.lostPower()) {
    Serial.println("RTC is NOT initialized, let's set the time!");
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
  }

  rtc.start();


   // initialzing LoRa
   LoRa.setPins(8,4,3);
   if (!LoRa.begin(915E6)) {
     Serial.println("Starting LoRa failed!");
   }
   LoRa.setTxPower(20);
   LoRa.setSpreadingFactor(12);
//   LoRa.setSignalBandwidth(62500);
//   LoRa.setCodingRate4(5);
   Serial.println("Lora and RTC Success");

   // initializing SD card -- That's important!
//   pinMode(10, OUTPUT);  
//   digitalWrite(8, HIGH);
//   digitalWrite(10, LOW);
   delay(1);

   // see if the card is present and can be initialized:
   if (!SD.begin(10)) {
      Serial.println("Card failed, or not present");
      // don't do anything more:
      while (1);
   }

   // create File to log data if it doesn't exist
   if (! SD.exists(fname)) {
     // only open a new file if it doesn't exist
     File dfile = SD.open(fname, FILE_WRITE); 
     dString += "#Time,P1-EC,P1-VWC,P1-Temp,P2-EC,P2-VWC,P2-Temp,P3-EC,P3-VWC,P3-Temp,P4-Pot,P4-Temp,P5-WDT,P5-T,P5-EC,Bat";
     dfile.println(dString);
     dfile.close();
   }
   // setting up LED   
   pinMode(13, OUTPUT);
   digitalWrite(13, LOW);
 
   Serial.print("Opening SDI port...");
   mySDI12.begin(); 
}
 
void loop () 
{   int ID;
    String dString = "";
    DateTime start_t = rtc.now();
    dString  = "";

    dString += String(start_t.year()) + "/" + String(start_t.month()) + "/" + String(start_t.day()) + " ";
    dString += String(start_t.hour()) + ":" + String(start_t.minute()) + ":" + String(start_t.second());

    // get SDI response from attached sensors
    // sensors 1-3 = 5TE
    // sensor  4   = MPS6
    // sensor  5   = CDT
    delay(100);
    
    for (char j = '1'; j <= '5'; j++)  {         
      if (j == '1' or j == '2' or j == '3'){                
          dString += tm2Measurement(j);
        }   
      if (j == '4'){
          dString += mpsMeasurement(j);
        }
      if (j == '5'){
          dString += cdtMeasurement(j);
        }
      delay(200);     
    }
    delay(100);

    //Measure battery voltage and add to data string

    float measuredvbat = analogRead(VBATPIN);
    measuredvbat *= 2;    // we divided by 2, so multiply back
    measuredvbat *= 3.3;  // Multiply by 3.3V, our reference voltage
    measuredvbat /= 1024; // convert to voltage
    
    dString += ",";
    dString += measuredvbat;

    //Write output file
    File dFile = SD.open(fname, FILE_WRITE);
     
    if (dFile){
       dFile.println(dString);
       dFile.close();
    }
    //if the file isn't open, pop up an error:
    else {
       Serial.println("error opening data file");
    }

    delay(200);
    Serial.println(dString);
    // Send LoRa message
     
    interval = sendPackage(dString);
    ID +=1;

    // set Adafruit to sleep 
    DateTime end_t = rtc.now();
    while(abs(((start_t.hour()*60)+start_t.minute()) - ((end_t.hour()*60)+end_t.minute())) < interval) {
         // This will disconnect the USB connection - yet the code is running
         LowPower.deepSleep(60000);
         end_t = rtc.now();
    } 
    
} 

 
String tm2Measurement(char i){        //Meter 5TE sensor
  int resultsExpected = 3;
  float S1 = 0.0;
  float S2 = 0.0;
  float VWC = 0.0;
  float S3 = 0.0;
  
  String dString = "";

  digitalWrite(13, HIGH);

  uint8_t resultsReceived = 0;
  uint8_t cmd_number      = 0;
  String command = "";
  
  // initiate a measurement
  command = "";
  command += i;
  command += "M!"; // SDI-12 measurement command format  [address]['M'][!]
  mySDI12.sendCommand(command); 
  delay(30); 
  mySDI12.clearBuffer();
  delay(1000);
  
  while (resultsReceived < resultsExpected && cmd_number <= 0) {    
    command = "";
    command += i;
    command += "D";
    command += cmd_number;
    command += "!";  // SDI-12 command to get data [address][D][dataOption][!]
    mySDI12.sendCommand(command);

    uint32_t start = millis();
    while (mySDI12.available() < 3 && (millis() - start) < 1500) {}
    mySDI12.read();           // ignore the repeated SDI12 address
    char c = mySDI12.peek();  // check if there's a '+' and toss if so
    if (c == '+') { mySDI12.read(); }

    while (mySDI12.available()) {
      char c = mySDI12.peek();
      if (c == '+') {
        mySDI12.read();
        float result = mySDI12.parseFloat(SKIP_NONE);
        if (result != -9999) { 
          resultsReceived++; 
          if (resultsReceived==1){
            S1 = result;
          }
          else if (resultsReceived==2){
            S2 = result;
          }
          else if (resultsReceived==3){
            S3 = result;
          }
        }
      } 
      else if (c =='-') {
        mySDI12.read();
        float result = mySDI12.parseFloat(SKIP_NONE);
        if (result != -9999) { 
          resultsReceived++; 
          if (resultsReceived==1){
            S1 = -1*result;
          }
          else if (resultsReceived==2){
            S2 = -1*result;
          }
          else if (resultsReceived==3){
            S3 = -1*result;
          }
        }
      }
      else {
        mySDI12.read();
      }
      delay(10);  // 1 character ~ 7.5ms
    }
    if (resultsReceived < resultsExpected) { dString=",-999.9,-999.9,-999.9"; }
    else if (resultsReceived >= resultsExpected){
      VWC = 100*((4.3e-6*(S1*S1*S1)) - (5.5e-4*(S1*S1)) + (2.92e-2 * S1) - 5.3e-2) ;     //the TOPP equation used to calculate VWC
      
      dString += ",";
      dString += String(S2);
      dString += ",";
      dString += String(S1);
      dString += ",";
      dString += String(S3);
      }
    cmd_number++;
  }
  mySDI12.clearBuffer();
  digitalWrite(13, LOW);

  return dString;
}

String mpsMeasurement(char i){        //Meter MPS6 sensor
  int resultsExpected = 2;
  float S1 = 0.0;
  float S2 = 0.0;
  
  String dString = "";

  digitalWrite(13, HIGH);

  uint8_t resultsReceived = 0;
  uint8_t cmd_number      = 0;
  String command = "";
  
  // initiate a measurement
  command = "";
  command += i;
  command += "M!"; // SDI-12 measurement command format  [address]['M'][!]
  mySDI12.sendCommand(command); 
  delay(30); 
  mySDI12.clearBuffer();
  delay(1000);

  
  while (resultsReceived < resultsExpected && cmd_number <= 0) {    
    command = "";
    command += i;
    command += "D";
    command += cmd_number;
    command += "!";  // SDI-12 command to get data [address][D][dataOption][!]
    mySDI12.sendCommand(command);

    uint32_t start = millis();
    while (mySDI12.available() < 3 && (millis() - start) < 1500) {}
    mySDI12.read();           // ignore the repeated SDI12 address
    char c = mySDI12.peek();  // check if there's a '+' and toss if so
    if (c == '+') { mySDI12.read(); }

    while (mySDI12.available()) {
      char c = mySDI12.peek();
      if (c == '+') {
        mySDI12.read();
        float result = mySDI12.parseFloat(SKIP_NONE);
        if (result != -9999) { 
          resultsReceived++; 
          if (resultsReceived==1){
            S1 = result;
          }
          else if (resultsReceived==2){
            S2 = result;
          }
        }
      }
      else if (c =='-') {
        mySDI12.read();
        float result = mySDI12.parseFloat(SKIP_NONE);
        if (result != -9999) { 
          resultsReceived++; 
          if (resultsReceived==1){
            S1 = -1*result;
          }
          else if (resultsReceived==2){
            S2 = -1*result;
          }
        }
      }
      else {
        mySDI12.read();
      }
      delay(10);  // 1 character ~ 7.5ms
    }
    if (resultsReceived < resultsExpected) { dString=",-999.9,-999.9"; }
    else if (resultsReceived >= resultsExpected){
      dString += ",";
      dString += String(S1);
      dString += ",";
      dString += String(S2);
      }
    cmd_number++;
  }
  mySDI12.clearBuffer();
  digitalWrite(13, LOW);

  return dString;
}


String cdtMeasurement(char i){        //Meter CDT sensor
  int resultsExpected = 3;
  float S1 = 0.0;
  float S2 = 0.0;
  float VWC = 0.0;
  float S3 = 0.0;
  
  String dString = "";

  digitalWrite(13, HIGH);

  uint8_t resultsReceived = 0;
  uint8_t cmd_number      = 0;
  String command = "";
  
  // initiate a measurement
  command = "";
  command += i;
  command += "M!"; // SDI-12 measurement command format  [address]['M'][!]
  mySDI12.sendCommand(command); 
  delay(30); 
  mySDI12.clearBuffer();
  delay(1000);
  
  while (resultsReceived < resultsExpected && cmd_number <= 0) {    
    command = "";
    command += i;
    command += "D";
    command += cmd_number;
    command += "!";  // SDI-12 command to get data [address][D][dataOption][!]
    mySDI12.sendCommand(command);

    uint32_t start = millis();
    while (mySDI12.available() < 3 && (millis() - start) < 1500) {}
    mySDI12.read();           // ignore the repeated SDI12 address
    char c = mySDI12.peek();  // check if there's a '+' and toss if so
    if (c == '+') { mySDI12.read(); }

    while (mySDI12.available()) {
      char c = mySDI12.peek();
      if (c == '+') {
        mySDI12.read();
        float result = mySDI12.parseFloat(SKIP_NONE);
        if (result != -9999) { 
          resultsReceived++; 
          if (resultsReceived==1){
            S1 = result;
          }
          else if (resultsReceived==2){
            S2 = result;
          }
          else if (resultsReceived==3){
            S3 = result;
          }
        }
      } 
      else if (c =='-') {
        mySDI12.read();
        float result = mySDI12.parseFloat(SKIP_NONE);
        if (result != -9999) { 
          resultsReceived++; 
          if (resultsReceived==1){
            S1 = -1*result;
          }
          else if (resultsReceived==2){
            S2 = -1*result;
          }
          else if (resultsReceived==3){
            S3 = -1*result;
          }
        }
      }
      else {
        mySDI12.read();
      }
      delay(10);  // 1 character ~ 7.5ms
    }
    if (resultsReceived < resultsExpected) { dString=",-999.9,-999.9,-999.9"; }
    else if (resultsReceived >= resultsExpected){

      dString += ",";
      dString += String(S1);
      dString += ",";
      dString += String(S2);
      dString += ",";
      dString += String(S3);
      }
    cmd_number++;
  }
  mySDI12.clearBuffer();
  digitalWrite(13, LOW);

  return dString;
}


String terosMeasurement(char i){        //Meter 5TE sensor
  int resultsExpected = 3;
  float S1 = 0.0;
  float S2 = 0.0;
  float VWC = 0.0;
  float S3 = 0.0;

  
  String dString = "";

  digitalWrite(13, HIGH);

  uint8_t resultsReceived = 0;
  uint8_t cmd_number      = 0;
  String command = "";
  
  // initiate a measurement
  command = "";
  command += i;
  command += "M!"; // SDI-12 measurement command format  [address]['M'][!]
  mySDI12.sendCommand(command); 
  delay(30); 
  mySDI12.clearBuffer();
  delay(1000);
  
  while (resultsReceived < resultsExpected && cmd_number <= 0) {    
    command = "";
    command += i;
    command += "D";
    command += cmd_number;
    command += "!";  // SDI-12 command to get data [address][D][dataOption][!]
    mySDI12.sendCommand(command);

    uint32_t start = millis();
    while (mySDI12.available() < 3 && (millis() - start) < 1500) {}
    mySDI12.read();           // ignore the repeated SDI12 address
    char c = mySDI12.peek();  // check if there's a '+' and toss if so
    if (c == '+') { mySDI12.read(); }

    while (mySDI12.available()) {
      char c = mySDI12.peek();
      if (c == '+') {
        mySDI12.read();
        float result = mySDI12.parseFloat(SKIP_NONE);
        if (result != -9999) { 
          resultsReceived++; 
          if (resultsReceived==1){
            S1 = result;
          }
          else if (resultsReceived==2){
            S2 = result;
          }
          else if (resultsReceived==3){
            S3 = result;
          }
        }
      } 
      else if (c =='-') {
        mySDI12.read();
        float result = mySDI12.parseFloat(SKIP_NONE);
        if (result != -9999) { 
          resultsReceived++; 
          if (resultsReceived==1){
            S1 = -1*result;
          }
          else if (resultsReceived==2){
            S2 = -1*result;
          }
          else if (resultsReceived==3){
            S3 = -1*result;
          }
        }
      }
      else {
        mySDI12.read();
      }
      delay(10);  // 1 character ~ 7.5ms
    }
    if (resultsReceived < resultsExpected) { dString=",-999.9,-999.9,-999.9"; }
    else if (resultsReceived >= resultsExpected){
      VWC = 100*((3.879e-4 *S1)-0.6956) ;     //the TOPP equation used to calculate VWC
      
      dString += ",";
      dString += String(S3/100);
      dString += ",";
      dString += String(VWC);
      dString += ",";
      dString += String(S2);
      }
    cmd_number++;
  }
  mySDI12.clearBuffer();
  digitalWrite(13, LOW);

  return dString;
}

int sendPackage(String message){
    digitalWrite(13, HIGH);
    Serial.println("Sending package");
    // sending data to LoRa receiver
    LoRa.beginPacket();                   // start packet
    LoRa.write(destination);              // add destination address
    LoRa.write(localAddress);             // add sender address
    LoRa.write(msgCount);                 // add message ID
    LoRa.write(byte(message.length()));        // add payload length
    LoRa.print(message);                 // add payload
    LoRa.endPacket();                     // finish packet and send it
    msgCount++;                           // increment message ID

    delay(30);
    LoRa.receive();
    uint32_t start = millis(); 
    while ((millis() - start) < 5000) {
      int packetSize = LoRa.parsePacket();
      if (packetSize) {
        int recipient = LoRa.read();          // recipient address
        byte sender = LoRa.read();            // sender address
        byte incomingMsgId = LoRa.read();     // incoming msg ID
        byte incomingLength = LoRa.read();    // incoming msg length
      
        String incoming = "";
      
        while (LoRa.available()) {
          incoming += (char)LoRa.read();
        }
            
        // if the recipient isn't this device or broadcast,
        if (recipient != localAddress) {
          Serial.println("This message is not for me.");
          digitalWrite(13, LOW);
          LoRa.idle();
          return interval;                             // skip rest of function
        }
      
        // if message is for this device, or broadcast, print details:
        Serial.println("Received from: 0x" + String(sender, HEX));
        Serial.println("Sent to: 0x" + String(recipient, HEX));
        Serial.println("Message: " + incoming);
        digitalWrite(13, LOW);
        LoRa.idle();
        return incoming.toInt();
        }       
    }
    digitalWrite(13, LOW);
    return interval;
}

User avatar
adafruit_support_mike
 
Posts: 68386
Joined: Thu Feb 11, 2010 2:51 pm

Re: SDI-12 Sensor with Feather M0 and Adalogger

Post by adafruit_support_mike »

We don't use SDI-12 sensors, so I'm afraid we don't have any known-working code I can suggest for the sake of testing.

That's where you want to start though. Drop back to the simplest example code you can find for a sensor and try to get that working. Talk to whoever makes the sensor or any adapter that connects to the microcontroller and get a "this should work" baseline.

The process of getting a system to work at all is called 'first light', and can be one of the hardest parts of a project. Once you have a working system that does anything, getting it to do something else tends to be easier. Gradually tweaking a system to do something specific follows from there.

Post Reply
Please be positive and constructive with your questions and comments.

Return to “General Project help”