This is identical to example D, except that instead of using internal definitions of pin change interrupt vectors, it depends on another library to define them for it.
To use this example, you must remove the comment braces around #define SDI12_EXTERNAL_PCINT
in the library and re-compile it.
PlatformIO Configuration
1; PlatformIO Project Configuration File
4description = SDI-12 Library Example J: Using an External Interrupt Library
5src_dir = .piolibdeps/Arduino-SDI-12_ID1486/examples/j_external_pcint_library
15 -DSDI12_EXTERNAL_PCINT
The Complete Example
2 * @example{lineno} j_external_pcint_library.ino
3 * @copyright Stroud Water Research Center
4 * @license This example is published under the BSD-3 license.
5 * @author Kevin M.Smith <SDI12@ethosengineering.org>
7 * @brief Example J: Using External Interrupts
9 * This is identical to example B, except that it uses the library
10 * [EnableInterrupt](https://github.com/GreyGnome/EnableInterrupt) to assign the pin
11 * change interrupt vector. This allows it to play nicely with any other libraries that
12 * try to assign functionality to the pin change interrupt vectors.
14 * For this to work, you must remove the comment braces around
15 * `#define SDI12_EXTERNAL_PCINT` in the library and re-compile it.
18#include <EnableInterrupt.h>
21/* connection information */
22uint32_t serialBaud = 115200; /*!< The baud rate for the output serial port */
23int8_t dataPin = 7; /*!< The pin of the SDI-12 data bus */
24int8_t powerPin = 22; /*!< The sensor power pin (or -1 if not switching power) */
25int8_t firstAddress = 0; /* The first address in the address space to check (0='0') */
26int8_t lastAddress = 62; /* The last address in the address space to check (62='z') */
28/** Define the SDI-12 bus */
29SDI12 mySDI12(dataPin);
31// keeps track of active addresses
36uint8_t numSensors = 0;
39 * @brief converts allowable address characters ('0'-'9', 'a'-'z', 'A'-'Z') to a
40 * decimal number between 0 and 61 (inclusive) to cover the 62 possible
43byte charToDec(char i) {
44 if ((i >= '0') && (i <= '9')) return i - '0';
45 if ((i >= 'a') && (i <= 'z')) return i - 'a' + 10;
46 if ((i >= 'A') && (i <= 'Z'))
53 * @brief maps a decimal number between 0 and 61 (inclusive) to allowable
54 * address characters '0'-'9', 'a'-'z', 'A'-'Z',
56 * THIS METHOD IS UNUSED IN THIS EXAMPLE, BUT IT MAY BE HELPFUL.
58char decToChar(byte i) {
59 if (i < 10) return i + '0';
60 if ((i >= 10) && (i < 36)) return i + 'a' - 10;
61 if ((i >= 36) && (i <= 62))
68 * @brief gets identification information from a sensor, and prints it to the serial
71 * @param i a character between '0'-'9', 'a'-'z', or 'A'-'Z'.
73void printInfo(char i) {
77 mySDI12.sendCommand(command);
80 String sdiResponse = mySDI12.readStringUntil('\n');
82 // allccccccccmmmmmmvvvxxx...xx<CR><LF>
83 Serial.print(sdiResponse.substring(0, 1)); // address
85 Serial.print(sdiResponse.substring(1, 3).toFloat() / 10); // SDI-12 version number
87 Serial.print(sdiResponse.substring(3, 11)); // vendor id
89 Serial.print(sdiResponse.substring(11, 17)); // sensor model
91 Serial.print(sdiResponse.substring(17, 20)); // sensor version
93 Serial.print(sdiResponse.substring(20)); // sensor id
97bool getResults(char i, int resultsExpected) {
98 uint8_t resultsReceived = 0;
99 uint8_t cmd_number = 0;
100 while (resultsReceived < resultsExpected && cmd_number <= 9) {
102 // in this example we will only take the 'DO' measurement
106 command += cmd_number;
107 command += "!"; // SDI-12 command to get data [address][D][dataOption][!]
108 mySDI12.sendCommand(command);
110 uint32_t start = millis();
111 while (mySDI12.available() < 3 && (millis() - start) < 1500) {}
112 mySDI12.read(); // ignore the repeated SDI12 address
113 char c = mySDI12.peek(); // check if there's a '+' and toss if so
114 if (c == '+') { mySDI12.read(); }
116 while (mySDI12.available()) {
117 char c = mySDI12.peek();
118 if (c == '-' || (c >= '0' && c <= '9') || c == '.') {
119 float result = mySDI12.parseFloat(SKIP_NONE);
120 Serial.print(String(result, 10));
121 if (result != -9999) { resultsReceived++; }
122 } else if (c == '+') {
128 delay(10); // 1 character ~ 7.5ms
130 if (resultsReceived < resultsExpected) { Serial.print(", "); }
133 mySDI12.clearBuffer();
135 return resultsReceived == resultsExpected;
138bool takeMeasurement(char i, String meas_type = "") {
139 mySDI12.clearBuffer();
143 command += meas_type;
144 command += "!"; // SDI-12 measurement command format [address]['M'][!]
145 mySDI12.sendCommand(command);
148 // wait for acknowlegement with format [address][ttt (3 char, seconds)][number of
149 // measurments available, 0-9]
150 String sdiResponse = mySDI12.readStringUntil('\n');
153 String addr = sdiResponse.substring(0, 1);
157 // find out how long we have to wait (in seconds).
158 uint8_t wait = sdiResponse.substring(1, 4).toInt();
162 // Set up the number of results to expect
163 int numResults = sdiResponse.substring(4).toInt();
164 Serial.print(numResults);
167 unsigned long timerStart = millis();
168 while ((millis() - timerStart) < (1000 * (wait + 1))) {
169 if (mySDI12.available()) // sensor can interrupt us to let us know it is done early
171 Serial.print(millis() - timerStart);
173 mySDI12.clearBuffer();
177 // Wait for anything else and clear it out
179 mySDI12.clearBuffer();
181 if (numResults > 0) { return getResults(i, numResults); }
186// this checks for activity at a particular address
187// expects a char, '0'-'9', 'a'-'z', or 'A'-'Z'
188boolean checkActive(char i) {
189 String myCommand = "";
191 myCommand += (char)i; // sends basic 'acknowledge' command [address][!]
194 for (int j = 0; j < 3; j++) { // goes through three rapid contact attempts
195 mySDI12.sendCommand(myCommand);
197 if (mySDI12.available()) { // If we here anything, assume we have an active sensor
198 mySDI12.clearBuffer();
202 mySDI12.clearBuffer();
207 Serial.begin(serialBaud);
211 Serial.println("Opening SDI-12 bus...");
213 delay(500); // allow things to settle
215 Serial.println("Timeout value: ");
216 Serial.println(mySDI12.TIMEOUT);
218 // Power the sensors;
220 Serial.println("Powering up sensors...");
221 pinMode(powerPin, OUTPUT);
222 digitalWrite(powerPin, HIGH);
226 // Enable interrupts for the recieve pin
227 pinMode(dataPin, INPUT_PULLUP);
228 enableInterrupt(dataPin, SDI12::handleInterrupt, CHANGE);
230 // Quickly Scan the Address Space
231 Serial.println("Scanning all addresses, please wait...");
232 Serial.println("Protocol Version, Sensor Address, Sensor Vendor, Sensor Model, "
233 "Sensor Version, Sensor ID");
235 for (byte i = firstAddress; i < lastAddress; i++) {
236 char addr = decToChar(i);
237 if (checkActive(addr)) {
244 Serial.print("Total number of sensors found: ");
245 Serial.println(numSensors);
247 if (numSensors == 0) {
249 "No sensors found, please check connections and restart the Arduino.");
250 while (true) { delay(10); } // do nothing forever
254 Serial.println("Time Elapsed (s), Est Measurement Time (s), Number Measurements, "
255 "Real Measurement Time (ms), Measurement 1, Measurement 2, ... etc.");
257 "-------------------------------------------------------------------------------");
261 // measure one at a time
262 for (byte i = firstAddress; i < lastAddress; i++) {
263 char addr = decToChar(i);
265 Serial.print(millis() / 1000);
267 takeMeasurement(addr);
272 delay(10000); // wait ten seconds between measurement attempts.