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
SDI-12 Sensor with Feather M0 and Adalogger
Moderators: adafruit_support_bill, adafruit
Please be positive and constructive with your questions and comments.
- asaeed01
- Posts: 2
- Joined: Thu Jan 16, 2025 1:00 pm
Re: SDI-12 Sensor with Feather M0 and Adalogger
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;
}
- adafruit_support_mike
- Posts: 68386
- Joined: Thu Feb 11, 2010 2:51 pm
Re: SDI-12 Sensor with Feather M0 and Adalogger
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.
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.
Please be positive and constructive with your questions and comments.