Example I: SDI-12 PC Interface.
Example I: SDI-12 PC Interface
Arduino-based USB dongle translates serial comm from PC to SDI-12 (electrical and timing)
- Allows user to communicate to SDI-12 devices from a serial terminal emulator (e.g. PuTTY).
- Able to spy on an SDI-12 bus for troubleshooting comm between data logger and sensors.
- Can also be used as a hardware middleman for interfacing software to an SDI-12 sensor. For example, implementing an SDI-12 data logger in Python on a PC. Use verbatim mode with feedback off in this case.
Note: "translation" means timing and electrical interface. It does not ensure SDI-12 compliance of commands sent via it.
D. Wasielewski, 2016 Builds upon work started by: https://github.com/jrzondagh/AgriApps-SDI-12-Arduino-Sensor https://github.com/Jorge-Mendes/Agro-Shield/tree/master/SDI-12ArduinoSensor
Known issues:
- Backspace adds a "backspace character" into the serialMsgStr (which gets sent out on the SDI-12 interface) instead of removing the previous char from it
- Suceptible to noise on the SDI-12 data line; consider hardware filtering or software error-checking
2 * @example{lineno} i_SDI-12_interface.ino
3 * @copyright Stroud Water Research Center
4 * @license This example is published under the BSD-3 license.
6 * @author D. Wasielewski
8 * @brief Example I: SDI-12 PC Interface
10 * Arduino-based USB dongle translates serial comm from PC to SDI-12 (electrical and
12 * 1. Allows user to communicate to SDI-12 devices from a serial terminal emulator
14 * 2. Able to spy on an SDI-12 bus for troubleshooting comm between data logger and
16 * 3. Can also be used as a hardware middleman for interfacing software to an SDI-12
17 * sensor. For example, implementing an SDI-12 data logger in Python on a PC. Use
18 * verbatim mode with feedback off in this case.
20 * Note: "translation" means timing and electrical interface. It does not ensure
21 * SDI-12 compliance of commands sent via it.
23 * D. Wasielewski, 2016
24 * Builds upon work started by:
25 * https://github.com/jrzondagh/AgriApps-SDI-12-Arduino-Sensor
26 * https://github.com/Jorge-Mendes/Agro-Shield/tree/master/SDI-12ArduinoSensor
29 * - Backspace adds a "backspace character" into the serialMsgStr (which gets sent
30 * out on the SDI-12 interface) instead of removing the previous char from it
31 * - Suceptible to noise on the SDI-12 data line; consider hardware filtering or
32 * software error-checking
37 "help : Print this message\r\n" \
38 "mode s : SDI-12 command mode (uppercase and ! automatically corrected) " \
40 "mode v : verbatim mode (text will be sent verbatim)\r\n" \
41 "fb on : Enable feedback (characters visible while typing) [default]\r\n" \
42 "fb off : Disable feedback (characters not visible while typing; may be desired " \
43 "for developers)\r\n" \
44 "(else) : send command to SDI-12 bus"
49#define SDI12_DATA_PIN 7
51#ifndef SDI12_POWER_PIN
52#define SDI12_POWER_PIN 22
55/* connection information */
56uint32_t serialBaud = 115200; /*!< The baud rate for the output serial port */
57int8_t dataPin = SDI12_DATA_PIN; /*!< The pin of the SDI-12 data bus */
58int8_t powerPin = SDI12_POWER_PIN; /*!< The sensor power pin (or -1) */
59char sensorAddress = '1'; /*!< The address of the SDI-12 sensor */
61/** Define the SDI-12 bus */
62SDI12 mySDI12(dataPin);
65 Serial.begin(serialBaud);
66 while (!Serial && millis() < 10000L);
70 Serial.println("Powering up sensors...");
71 pinMode(powerPin, OUTPUT);
72 digitalWrite(powerPin, HIGH);
76 // Initiate serial connection to SDI-12 bus
79 mySDI12.forceListen();
81 // Print help text (may wish to comment out if used for communicating to software)
82 Serial.println(HELPTEXT);
86 static String serialMsgStr;
87 static boolean serialMsgReady = false;
89 static String sdiMsgStr;
90 static boolean sdiMsgReady = false;
92 static boolean verbatim = false;
93 static boolean feedback = true;
96 // -- READ SERIAL (PC COMMS) DATA --
97 // If serial data is available, read in a single byte and add it to
98 // a String on each iteration
99 if (Serial.available()) {
100 char inByte1 = Serial.read();
101 if (feedback) { Serial.print(inByte1); }
102 if (inByte1 == '\r' || inByte1 == '\n') {
103 serialMsgReady = true;
105 serialMsgStr += inByte1;
109 // -- READ SDI-12 DATA --
110 // If SDI-12 data is available, keep reading until full message consumed
111 // (Normally I would prefer to allow the loop() to keep executing while the string
112 // is being read in--as the serial example above--but SDI-12 depends on very precise
113 // timing, so it is probably best to let it hold up loop() until the string is
115 int avail = mySDI12.available();
117 mySDI12.clearBuffer();
118 } // Buffer is full; clear
119 else if (avail > 0) {
120 for (int a = 0; a < avail; a++) {
121 char inByte2 = mySDI12.read();
122 Serial.println(inByte2);
123 if (inByte2 == '\n') {
125 } else if (inByte2 == '!') {
129 sdiMsgStr += String(inByte2);
135 // Report completed SDI-12 messages back to serial interface
137 Serial.println(sdiMsgStr);
138 // Reset String for next SDI-12 message
143 // Send completed Serial message as SDI-12 command
144 if (serialMsgReady) {
146 // Check if the serial message is a known command to the SDI-12 interface program
147 String lowerMsgStr = serialMsgStr;
148 lowerMsgStr.toLowerCase();
149 if (lowerMsgStr == "mode v") {
151 Serial.println("Verbatim mode; exact text will be sent. Enter \"mode s\" for "
152 "SDI-12 command mode.");
153 } else if (lowerMsgStr == "mode s") {
155 Serial.println("SDI-12 command mode; uppercase and ! suffix optional. Enter "
156 "\"mode v\" for verbatim mode.");
157 } else if (lowerMsgStr == "help") {
158 Serial.println(HELPTEXT);
159 } else if (lowerMsgStr == "fb off") {
161 Serial.println("Feedback off; typed commands will not be visible. Enter \"fb "
162 "on\" to enable feedback.");
163 } else if (lowerMsgStr == "fb on") {
165 Serial.println("Feedback on; typed commands will be visible. Enter \"fb off\" "
166 "to disable feedback.");
168 // If not a known command to the SDI-12 interface program, send out on SDI-12 data
172 mySDI12.sendCommand(serialMsgStr);
174 serialMsgStr.toUpperCase();
175 String fullCommand = serialMsgStr + "!";
176 mySDI12.sendCommand(fullCommand);
179 // Reset String for next serial message
180 serialMsgReady = false;