Arduino serial: inverted 7E1. Possible?

3.9k views Asked by At

I'm trying to talk serial with an SDI-12 device, and it requires inverted seven data bits, even parity and one stop bit (7E1) serial at 1200 baud.

From the datasheet:

SDI-12 communication sends characters at 1200 bits per second. Each character has 1 start bit, 7 data bits (LSB first), 1 even parity bit, and 1 stop bit (Active low or inverted logic levels):

All SDI-12 commands and response must adhere to the following format on the data line. Both the command and response are preceded by an address and terminated by a carriage return line feed combination.

Is this possible with the Serial or SoftwareSerial libraries? I am trying to avoid additional hardware (beyond a levelshifter to 3.3 V), but I will do so if it is the only way.

I have seen that SoftwareSerial can do inverted, and Serial can do 7E1, but I can't find if either can do both.

I have access to a Arduino Mega (R2), and Arduino Uno (R3).

Here is the device I want to communicate with: http://www.decagon.com/products/sensors/soil-moisture-sensors/gs3-soil-moisture-temperature-and-ec/ and here, http://www.decagon.com/assets/Uploads/GS3-Integrators-Guide.pdf is the document explaining the protocol. Page 6 talks about its implementation of SDI.

2

There are 2 answers

0
Joran Beasley On

A little late... but better late than never

I have actually just written a library for exactly that (actually exactly that including the sensors ... so it should work exactly with the included examples )

https://github.com/joranbeasley/SDISerial (Arduino Library)

#include <SDISerial.h> //https://github.com/joranbeasley/SDISerial (Arduino Library)
#include <string.h>
#define DATA_PIN 2
SDISerial connection(DATA_PIN);
char output_buffer[125]; // just for uart prints
char tmp_buffer[4];
char sensor_info[]
//initialize variables
void setup(){
      connection.begin();
      Serial.begin(9600);//so we can print to standard uart
      //small delay to let the sensor do its startup stuff
      delay(3000);//3 seconds should be more than enough
      char* sensor_info = connection.sdi_query("0I!",1000); // get sensor info for address 0
}

//main loop
void loop(){
    //print to uart
    Serial.println("Begin Command: ?M!");

    //send measurement query (M) to the first device on our bus
    char* resp = connection.service_request("0M!","0D0!");//Get Measurement from address 0


    sprintf(output_buffer,"RECV: %s",resp?resp:"No Response Recieved!!");
    Serial.println(output_buffer);
    delay(10000);//sleep for 10 seconds before the next read
}
1
A Royal On

I'm not familiar with Arduino, however the SDI-12 physical layer is inverted from the standard TTL levels - probably for two reasons:

  1. Since the idle voltage is 0V, this results in lower standby power (due to nominal pull-down resistors in a typical SDI-12 sensor.
  2. It facilitates simple bus 'sniffing' using a standard RS-232 serial port.

Short of bit-banging a 5V IO pin - yes, if using a standard microcontroller UART you will need an external inverter (or 2) and a 3-state buffer. Possibly requiring level shifting, depending on your hardware.

Thumbs down to the Wikipedia entry - SDI-12 uses entirely standard UART bit timings (very much like RS-232), just different signal levels (0 - 5V); see point #2. However, there are specific break sequences and strict timing requirements, which makes firmware development more difficult.

If you are serious about SDI-12 firmware development, you may want to invest in an SDI-12 Verifier. A thorough study of the specification is essential.