Hi!
I am trying to use the SDI-12 library (GitHub - EnviroDIY/Arduino-SDI-12: An Arduino library for SDI-12 communication with a wide variety of environmental sensors. This library provides a general software solution, without requiring any additional hardware.) with MKR 1010 wifi as a dataloggin system for Atmos 22 anemometer (http://publications.metergroup.com/Integrator%20Guide/18195%20ATMOS%2022%20Integrator%20Guide.pdf).
Everything works fine with Arduino Uno. I'm using continuous measurement command aR4! . The problem with MKR is that it frequently skips every 4. ,5. or 6. measurement.
I noticed that every time the measurement is skipped, there is only 0 or 1 byte in the buffer to read. With oscilloscope I noticed that the signal is then really short compared to normal measurements.
I'm also using a bidirectional level shifter 3.3V <->5.0V made from two resistors and a mosfet. It seems to work fine.
Is there a fundamental issue with MKR:s compatibility with the SDI-12 library, or is there a fix for this problem? I would like to use MKR because I need wifi connection, RTC clock and SD-card compatibility and MKR has first two of them.
EDIT:
Here is the code. It is a bit messy, because I it's a heavily modified version of the libraries examples for test purposes.
At the beginning of the code there are some notes about the Atmos 22 anemometer.
* =================REMARKS ABOUT ATMOS 22 ============
* - Sensor measurenmet sequence:
* -Internal clock from 0-59, increases by 1 every second and resets to 0 after 59
* -In poer up timer is set to 55
* -Averanging command resets timer to 55
* - Orientation is measured every 60s
* -MEAUREMENTS:
* -Atmos takes wind and air temperature measurements every 10s at internal timer intervals of 0, 10, 20, 30, 40,50.
* -Averanging commands( aM!, aR0!, aR3!,..) compute the averages , accumulations or maximums of these measurements and
* reset the internal counters and accumulators
*
* - aR4! mode:
* -Instantaneous measurements
* - Command triggers a sensor measurenment and returns the data automatically
*
* -response:
* a<TAB><NorthWindSpeed> <EastWindSpeed> <gustWindSpeed> <airTemperature> <xOrientation>
<yOrientation> <nullValue><CR><sensortype><Checksum><CRC>
-NOTE THAT VALUES ARE SPACE DELIMITED!!!
- Must be used at intervals of 10s or greater!! (as aR3!)
- Power Up time for continious mode is 10s, after that communication is possible
- 3.6 V <Supply voltage< 15.0 V
- digital logig level must be greater than 3.9 V. Note that many Arduinoboards use 3.3 V logil leves,
so level shifter is needed
- ERROR codes
-9999 general error
-9990 meaurement error
*/
// CODE:
#include <SDI12.h>
#define SERIAL_BAUD 115200 /*!< The baud rate for the output serial port */
#define DATA_PIN 6 /*!< The pin of the SDI-12 data bus */
#define POWER_PIN -1 /*!< The sensor power pin (or -1 if not switching power) */
// === SENSOR ADDRESS ===
const uint8_t ADDRESS = 1;
/** Define the SDI-12 bus */
SDI12 mySDI12(DATA_PIN);
uint8_t numSensors = 0;
String sdiResponse = "";
/**
* @brief converts allowable address characters ('0'-'9', 'a'-'z', 'A'-'Z') to a
* decimal number between 0 and 61 (inclusive) to cover the 62 possible
* addresses.
*/
byte charToDec(char i) {
if ((i >= '0') && (i <= '9')) return i - '0';
if ((i >= 'a') && (i <= 'z')) return i - 'a' + 10;
if ((i >= 'A') && (i <= 'Z'))
return i - 'A' + 36;
else
return i;
}
/**
* @brief maps a decimal number between 0 and 61 (inclusive) to allowable
* address characters '0'-'9', 'a'-'z', 'A'-'Z',
*
* THIS METHOD IS UNUSED IN THIS EXAMPLE, BUT IT MAY BE HELPFUL.
*/
char decToChar(byte i) {
if (i < 10) return i + '0';
if ((i >= 10) && (i < 36)) return i + 'a' - 10;
if ((i >= 36) && (i <= 62))
return i + 'A' - 36;
else
return i;
}
/**
* @brief gets identification information from a sensor, and prints it to the serial
* port
*
* @param i a character between '0'-'9', 'a'-'z', or 'A'-'Z'.
*/
void printInfo(char i) {
String command = "";
command += (char)i;
command += "I!";
mySDI12.sendCommand(command);
delay(100);
String sdiResponse = mySDI12.readStringUntil('\n');
sdiResponse.trim();
// allccccccccmmmmmmvvvxxx...xx<CR><LF>
Serial.print(sdiResponse.substring(0, 1)); // address
Serial.print(", ");
Serial.print(sdiResponse.substring(1, 3).toFloat() / 10); // SDI-12 version number
Serial.print(", ");
Serial.print(sdiResponse.substring(3, 11)); // vendor id
Serial.print(", ");
Serial.print(sdiResponse.substring(11, 17)); // sensor model
Serial.print(", ");
Serial.print(sdiResponse.substring(17, 20)); // sensor version
Serial.print(", ");
Serial.print(sdiResponse.substring(20)); // sensor id
Serial.print(", ");
}
// ============ MEASUREMENT METHOD ==================
void getContinuousResults(char i) {
// uint8_t resultsReceived = 0;
uint8_t cmd_number = 4; // aR4! command
String command = "";
// aR4! command
command = "";
command += i;
command += "R";
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) < 1000) {}
// Checking the bytes in the buffer
Serial.print("Test " + String(mySDI12.available()) + ' ');
while (mySDI12.available()) { // build string from response
char c = mySDI12.read();
sdiResponse += c;
delay(10); // 1 character ~ 7.5ms
}
Serial.println(sdiResponse); // write the response to the screen
sdiResponse = ""; // clear the response string
mySDI12.clearBuffer();
}
// this checks for activity at a particular address
// expects a char, '0'-'9', 'a'-'z', or 'A'-'Z'
boolean checkActive(char i) {
String myCommand = "";
myCommand = "";
myCommand += (char)i; // sends basic 'acknowledge' command [address][!]
myCommand += "!";
for (int j = 0; j < 3; j++) { // goes through three rapid contact attempts
mySDI12.sendCommand(myCommand);
delay(100);
if (mySDI12.available()) { // If we here anything, assume we have an active sensor
mySDI12.clearBuffer();
return true;
}
}
mySDI12.clearBuffer();
return false;
}
// ======================= SETUP ===========================
void setup() {
Serial.begin(SERIAL_BAUD);
while (!Serial);
Serial.println("Opening SDI-12 bus...");
mySDI12.begin();
delay(10000); // allow things to settle for 10s,POWER up time for c-mode
mySDI12.setTimeoutValue(-8888); // chagne timeout, -9999 is a general error code in Atmos22
Serial.println("Timeout value: ");
Serial.println(mySDI12.TIMEOUT);
// Check that the Atmos 22 is active and the address is correct
char addr = decToChar(1);
if (checkActive(addr)) {
numSensors++;
//isActive[i] = 1;
printInfo(addr);
Serial.println();
}
if (numSensors == 0) {
Serial.println(
"No sensors found, please check connections and restart the Arduino.");
while (true) { delay(10); } // do nothing forever
}
Serial.println();
Serial.println(
"Time Elapsed (s), NWS, EWS, GWS, T, xOr, yOr, nullValue,... ");
Serial.println(
"-------------------------------------------------------------------------------");
}
// ==================== LOOP ========================
void loop() {
char addr = decToChar(ADDRESS); // Addres from int to char
Serial.print(millis()); // Print elapsed time
Serial.print(", ");
getContinuousResults(addr); // Get continious resoults from sensor
delay(10000); // wait 10s between measurement attempts.
}`