Pages: [1] 2   Go Down
Author Topic: SDI-12 compatibility  (Read 4782 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Newbie
*
Karma: 0
Posts: 48
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I have some sensors that only have SDI-12 output.  Is there an easy way to interface them with an Arduino?
Logged

Phoenix, Arizona USA
Offline Offline
Faraday Member
**
Karma: 39
Posts: 5557
Where's the beer?
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I assume you mean this:

http://www.sdi-12.org/

You should be able to communicate with such devices easily using the Arduino, as the serial data stream is just HIGH/LOW pulses of (approximately) 0 and 5 VDC, where a LOW logic level (0V) is equivalent to a binary state of "1" and a HIGH logic level (5V) is equivalent to a binary state of "0"; in other words, inverse logic.

I don't know of a library or anything that makes it simple to communicate using an Arduino, but you should be able to adapt one of the "2-wire" serial libraries with only a few changes (mainly inverting the logic if needed, and adjusting for 1200 baud).

I'm sure there are other methods (ie, using a level or protocol converter IC or similar), but in theory, based on my (admittedly) limited quick reading of the spec of the protocol, it should be something you can directly interface to with the Arduino using a single digital pin, and appropriate driver/interface software...

 smiley
Logged

I will not respond to Arduino help PM's from random forum users; if you have such a question, start a new topic thread.

0
Offline Offline
Newbie
*
Karma: 0
Posts: 48
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Yep, that's the protocol.  It's rather common in the environmental sensor world.  It looks like the Arduino could handle it, I just dont' have the experience or time to brute force my way through designing an interface, so I'm hoping someone else has done it, or has something that could be easily adapted to work with Arduino.
Logged

Nova Scotia, CA
Offline Offline
Jr. Member
**
Karma: 0
Posts: 64
A world that runs on bits and bytes!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I guess I am curious why you would want to interface an SDI-12 sensor to an Arduino. 

SDI-12 sensors have their own MCU, most pre-process measurements already (e.g. smp, avg, min, max, etc.) which can be called using the SDI protocol based on how the manufacturer has it configured and typically support other output types e.g. RS232/485.  SDI-12 is great for low powered applications and supports daisy chaining of sensors as the protocol supports sensor addressing.  It's a slick protocol developed by Eric Campbell of Campbell Scientific, worked for the company, and have used it frequently (sensor & data-logger development).

If your an intermediate programmer I would suggest polling the sensor via RS232.  Check the sensor because some support TTL, if thats the case, use the SoftSerial library and two IO ports.

Logged

Common sense is not so common...

Adelaide AUST
Offline Offline
Newbie
*
Karma: 0
Posts: 1
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Just wondering whether anyone had made progress with this topic: SDI-12 on Arduino?
There are plenty of SDI-12 compatible data loggers in the market place and on the other hand, plenty of good, simple sensor ideas around for Arduino.
What would be good would be to bring them together: that is using Arduino as a simple front end for some SDI-12 smart sensors.
Logged

Vancouver, Canada
Offline Offline
Newbie
*
Karma: 0
Posts: 12
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi all,

I don't suppose anybody has found a sdi12.h library? I have a very nice anemometer that uses SDI-12 communication.

Thx
Logged

Vancouver, Canada
Offline Offline
Newbie
*
Karma: 0
Posts: 12
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Here is a newbie thought. Please tell me if this is a dumb one:

If I tie a couple of Rx and Tx pins together, and wrap all Tx serial commands in toggling the interrupt register OFF then ON.

For example for pins 14 & 15:

PCICR |= (0<<PCIE2);                 // disables  interrupts on pins 8-15
serial.print("0");
serial.print(13, BYTE);
serial.print(10, BYTE);
PCICR |= (1<<PCIE2);                 // enables  interrupts on pins 8-15

Would this allow me to communicate over the same SDI-12 line using standard serial commands? If yes; here comes the next question:

How can I apply this to say pin 30 and 31 using the NewSoftSerial.h library. I can't even figure out what the pin-change-register is for pins 30 and 31. Besides that, it would be even better to figure out how to modify the NewSoftSerial library to pull this trick.

Cheers,
Terke
Logged

Kansas City, MO
Offline Offline
Jr. Member
**
Karma: 0
Posts: 71
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I've just received one of these devices. I've yet to hook it up and try it yet, but I thought I would provide the link. I work for the National Weather Service and we use quite a bit of SDI-12. I wanted to see if I could interface with our SDI-12 sensors effectively.

http://www.vegetronix.com/Products/SDI-12.phtml
Logged

Vancouver, Canada
Offline Offline
Newbie
*
Karma: 0
Posts: 12
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks,

Had a look at that board. Nice, but the mega should simply be able to talk SDI-12. It is just a matter of finding the trick.

Cheers,
terke
Logged

Knoxville Tn
Offline Offline
Newbie
*
Karma: 0
Posts: 1
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I modified the software serial code to work for some sdi-12 sensor I was working with. The documentation for sdi-12 isn't the best but it wasn't to hard. Just invert the digitalRead part of the code and reduce it for a 7 bit string. Let me know and I'll post the modified softwareSerial.
Logged

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 212
Posts: 13531
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset


started some work on a SDI-12 lib (anemometer) a few weeks ago, never finished it  smiley-red  no sensor => could not test

It contains several shortcuts, but it could get someone started
Code:
//
//    FILE: SDI-12.001.pde
//  AUTHOR: Rob Tillaart
//    DATE: 2012-mar-18
//
// PUPROSE: talk to SDI-12 anemometer
//

void setup()
{
  // communication with PC
  Serial.begin(115200);
  Serial.println("\nSDI-12 0.01");

  // hardware serial1 for the sensor  [MEGA, optional replace with softSerial]
  Serial1.begin(1200);
}

void loop()
{
  char *answer;
 
  answer = addressQuery(); // char, no string
  Serial.print("\n addressQuery: ");
  Serial.println(answer);

  AcknowledgeActive('0'); // char, no string
  Serial.print("\n Address: ");
  Serial.println(answer);

  addressChange('0', 'Z');
  Serial.println(answer);
  addressChange('Z', '0');
  Serial.println(answer);

  sendIdentification('0'); // char, no string
  Serial.print("\n id: ");
  Serial.println(answer);

  int t = 0;
  int n = 0;

  startMeasurement('0', &t, &n);
  Serial.print("\n startMeasurement: ");
  Serial.println(answer); 
  Serial.println(t, DEC); 
  Serial.println(n, DEC);

  delay(t*1000UL); // wait for the measurement to be ready

  sendData('0');
  Serial.print("\n sendData: ");
  Serial.println(answer);

  delay(20000UL);
}

/////////////////////////////////////////////////////////
//
// Proto  SDI-12 commands
//
// names of functions, Table 5, page 8, SDI-12 1.3 specification
//


/////////////////////////////////////////////////////////
//
// Private members
//
char response[80];    // at least 35/75 according to 1.3 spec

/////////////////////////////////////////////////////////
//
// Public part I (admin commands)
//
char* AcknowledgeActive(char address)
{
  char command[] = "a!";
  command[0] = address;
  request(2, command, response);
  return response;
}

char* addressQuery()
{
  char command[] = "?!";
  request(2, command, response);
  return response;
}

char* addressChange(char oldAddress, char newAddress)
{
  char command[] = "aAb!";
  command[0] = oldAddress;
  command[2] = newAddress;
  request(4, command, response);
  return response;
}

char* sendIdentification(char address)
{
  char command[] = "aI!";
  command[0] = address;
  request(3, command, response);
  return response;
}

void printIdentification(char *idStr)
{
  // TODO
}

/////////////////////////////////////////////////////////
//
// Public part II (measurements)
//
char* startMeasurement(char address, int *t, int *n)
{
  char command[] = "aI!";
  command[0] = address;
  request(3, command, response);

  int len = strlen(response);
  *n = (int) (response[len-1] - '\0');
  *t = atoi(&response[1]) / 10;

  return response;
}

char* sendData(char address)
{
  char command[] = "aD0!";
  command[0] = address;
  request(4, command, response);
  return response;
}


/////////////////////////////////////////////////////////
//
// Private part I
//
void request(uint8_t length, char *command, char *response)
{
  // send command
  for (int idx=0; idx<length; idx++)
  {
    Serial.write(command[idx]);
  }

  // blocking until answer comes in
  char c = ' ';
  int idx = 0;
  while (c != 10)  // answer ends with LineFeed = char 10
  {
    if (Serial.available() > 0)
    {
      c = Serial.read();
      response[idx] = c & 0x7F;  // strip bit 8
      idx++;
      if (idx > 75) break; // prevent overflow answer;
    }
  }
  response[idx-2] = 0; // remove the CRLF and end string correctly
}

// --- END OF FILE ---
Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Offline Offline
Newbie
*
Karma: 0
Posts: 1
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

@4A_5E_33 Would you mind posting that modified library for some of us to take a look at?  I've been trying to get a good interface method for SDI-12 sensors for a while and would be very interested in seeing your method.
Logged

Vancouver, Canada
Offline Offline
Newbie
*
Karma: 0
Posts: 12
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hello All;

I'm making a little progress in talking with my SDI-12 sensor. I'm using Rob Tillaart's code as a starting point with a few changes:
First off I switched to SoftwareSerial.h and then set the UART to inverted logic. Before I had tried with Rob's code but that kept the Tx (pin 10) port high all the time which won't work with SDI-12. I added a 13ms HIGH pulse, followed by 9ms of LOW on the Tx pin before sending the command. You can see the SDI-12 answer but at slightly lower voltage. The voltage is lower for the reply because the Tx (pin 10) and Rx (pin 11) pins are tied together. At first they were simply tied together, but then the reply voltage was only about 1.8V because of the open Tx pin. Now the Tx pin talks through a 2.2kOhm resistor and far more signal is available for the Rx pin. If I could figure out how to pull the internal resistor on the Tx pin high I would give that a try.

I have attached two pics. One of the scope showing the 13ms High pulse, 9ms Low, the request from the Arduino, and finally the reply from the sensor.

The second pic is a screen grab of the terminal output. I send the configuration commands to the sensor, and then try to ask for the sensor to send back what it has for configuration. For some reason, the I can only read a small part of the settings back when requested. I can't figure out why.

And here is the code:
Code:
//
//    FILE: SDI-12.001.pde
//  AUTHOR: Rob Tillaart
//    DATE: 2012-mar-18
//
// PUPROSE: talk to SDI-12 anemometer
//

#include <SoftwareSerial.h>

#define txPin 10
#define rxPin 11
#define INVERTED true          //SDI-12 uses inverted logic

SoftwareSerial sdiAnem(rxPin, txPin, INVERTED);

void setup()
{
 // communication with PC
 Serial.begin(115200);
 Serial.println("\nSDI-12 0.01");

 // software serial for the sensor
 sdiAnem.begin(1200);
 
 delay(9);
 digitalWrite(txPin, HIGH);
 delay(13);
 digitalWrite(txPin, LOW);
 delay(9);
sdiAnem.write("0XXU,A=0,M=R,C=1,B=1200,D=7,P=E,S=1!");
Serial.println("0XXU,A=0,M=R,C=1,B=1200,D7,P=E,S=1!");

 delay(9);
 digitalWrite(txPin, HIGH);
 delay(13);
 digitalWrite(txPin, LOW);
 delay(9);
sdiAnem.write("0XWU,R=01001100&01001100,I=10,A=60,G=3,U=N,D=0,N=W,F=4!");
Serial.println("0XWU,R=01001100&01001100,I=10,A=60,G=3,U=N,D=0,N=W,F=4!");

char incomingAnswer[80];
char a;
int idy = 0;
 delay(9);
 digitalWrite(txPin, HIGH);
 delay(13);
 digitalWrite(txPin, LOW);
 delay(9);
sdiAnem.write("0SU!");
   if (sdiAnem.available() > 0)
   {
     a = sdiAnem.read();
     incomingAnswer[idy] = a & 0x7F;  // strip bit 8
     idy++;
   }
Serial.print("Reported settings are: ");  
Serial.println(incomingAnswer);
  

}

void loop()
{
 char *answer;

 answer = addressQuery(); // char, no string
 Serial.print("\n addressQuery: ");
 Serial.println(answer);

 AcknowledgeActive('0'); // char, no string
 Serial.print("\n Address: ");
 Serial.println(answer);

 sendIdentification('0'); // char, no string
 Serial.print("\n id: ");
 Serial.println(answer);

 int t = 0;
 int n = 0;

/* startMeasurement('0', &t, &n);
 Serial.print("\n startMeasurement: ");
 Serial.println(answer);
 Serial.println(t, DEC);
 Serial.println(n, DEC);

 delay(t*1000UL); // wait for the measurement to be ready
*/
 sendData('0');
 Serial.print("\n sendData: ");
 Serial.println(answer);

 delay(20000UL);
}

/////////////////////////////////////////////////////////
//
// Proto  SDI-12 commands
//
// names of functions, Table 5, page 8, SDI-12 1.3 specification
//


/////////////////////////////////////////////////////////
//
// Private members
//
char response[80];    // at least 35/75 according to 1.3 spec

/////////////////////////////////////////////////////////
//
// Public part I (admin commands)
//
char* AcknowledgeActive(char address)
{
 char command[] = "a!";
 command[0] = address;
 request(2, command, response);
 return response;
}

char* addressQuery()
{
 char command[] = "?!";
 request(2, command, response);
 return response;
}

char* addressChange(char oldAddress, char newAddress)
{
 char command[] = "aAb!";
 command[0] = oldAddress;
 command[2] = newAddress;
 request(4, command, response);
 return response;
}

char* sendIdentification(char address)
{
 char command[] = "aI!";
 command[0] = address;
 request(3, command, response);
 return response;
}

void printIdentification(char *idStr)
{
 // TODO
}

/////////////////////////////////////////////////////////
//
// Public part II (measurements)
//
char* startMeasurement(char address, int *t, int *n)
{
 char command[] = "aI!";
 command[0] = address;
 request(3, command, response);

 int len = strlen(response);
 *n = (int) (response[len-1] - '\0');
 *t = atoi(&response[1]) / 10;

 return response;
}

char* sendData(char address)
{
 char command[] = "0R1!";
 request(4, command, response);
 return response;
}


/////////////////////////////////////////////////////////
//
// Private part I
//
void request(uint8_t length, char *command, char *response)
{
 // send command
 delay(9);
 digitalWrite(txPin, HIGH);
 delay(13);
 digitalWrite(txPin, LOW);
 delay(9);
 for (int idx=0; idx<length; idx++)
 {
   sdiAnem.write(command[idx]);
 }

 // blocking until answer comes in
 char c = ' ';
 int idx = 0;
 while (c != 10)  // answer ends with LineFeed = char 10
 {
   if (sdiAnem.available() > 0)
   {
     c = sdiAnem.read();
     response[idx] = c & 0x7F;  // strip bit 8
     idx++;
   }
 }
 response[idx-2] = 0; // remove the CRLF and end string correctly
}

// --- END OF FILE ---

noderator added code tags


* photo.jpeg (339.23 KB, 1280x957 - viewed 55 times.)

* Screen Shot 2012-06-19 at 10.49.28 PM.png (19.93 KB, 399x359 - viewed 56 times.)
« Last Edit: March 02, 2014, 02:23:15 am by robtillaart » Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 7
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi, just letting you know I'm also interested in your work here. Thanks for taking the time to post your code, and I'd love to know if you've made more progress.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 4
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I have just created this exact library smiley

https://github.com/joranbeasley/SDISerial
Logged

Pages: [1] 2   Go Up
Jump to: