SDI-12 communications


CamEra

Recommended Posts

Hi,

I would like to connect an instrument that use SDI-12 commands to DaqFactory. I have not seen any mention of this in the documentation or this forum.

SDI-12 instruments operate similar to RS-485 with all being piggy backed together and each having a unique address. The system (DaqFactory) needs to send a command which is addressed to just one SDI-12 instrument. That instrument responds advising the delay (warmup period) before data is sent and the number of values which will be sent. The values are then sent once the delay has expired. There are a lot of other commands as well but this is the simplest form of the command to get data. This all occurs at 1200 baud.

This type of communication is used extensively with data loggers.

Can you help.

George

Link to comment
Share on other sites

We don't have a driver written up, but I don't see any reason you couldn't do it yourself pretty easily just using some basic script. Start by creating a new serial device at 1200 baud. Then using device.mydevice. functions (where mydevice is the name of the device you created) such as read() and write(), combined with delay(), you should be able to achieve the protocol.

Link to comment
Share on other sites

Turns out his is not as simple as I thought.

SDI-12 uses three wire connection, ground, +12 volts and one communications line. So, it cannot just be connected to a serial port.

The option is to use a USB to SDI-12 convertor which will allow comunication to/from the SDI-12 instrument and the PC.

I am not sure if this device then appears as a COM port in the PC so not sure if I can just use a seial device in DaqFactory. Can I set up a user USB device in DaqFactory?

George

Link to comment
Share on other sites

I thought that was the case.

No, you cannot create a user USB device, at least not the same way as you can with other serial devices. Read the section on USB in the DAQFactory Serial/ethernet communications guide.

However, if the USB device comes with a DLL library, you can likely call that library from DAQFactory using extern().

Link to comment
Share on other sites

Hi,

I now have lots more info and hopefully you can help out.

I have got hold of a SDI-12 to USB convertor. This device is actually an SDI-12 to USB to serial convertor. SDI-12 is a multi drop interface and only needs two connections, Grounfd and SDI-12. Multiple SDI instruments can be connected to the same port. Each SDI instrument must have a different address, addresses go from 0 to 9, the default is 0. For my testing I have one instrument connected with an address of 0.

In the attached word document are some screen shots and explanation. The SDI-12 to USB interface comes with a program which allows the user to query the SDI instrument(s). I have incldued this applications Communications window to show the results of using it. It works fine. Commands to the SDI instrument begin with the address (0 in my case) and then a command (e.g. "I" which requests the SDI instrument to send its Identification) and terminated by an "!". Responses vary but all begin with the address of the instrument (0 in my case) and for the "I" command a string similar to that in the word document is returned.

SDI-12 port requirements are 1200 baud, 1 start bit, 7 data bits(least significant first -not sure if this is normal), 1 parity bit (even parity), 1 stop bit. In the attached document is how I set up DaqFactory RS232 device and the responses in the monitor window when used. Unfortunately it didn't work. Perhaps you can shed some light on to this.

If you want more information on SDI-12 go to http://www.sdi-12.org/ and look at the protocol specification.

Thanks

George

Link to comment
Share on other sites

Hi,

Hopefully my previous attempt to load my attachment worked although I haven't seen the messsage appear yet.

But, I now understand why I cann send and receive information to the SDI instrument. To achieve this I need to set a break on the PC Transmit line for at least 12 msec before each command is sent. This basically wakes up all the SDI instruments letting them know a command is coming and they need to check whether it is for them.

Not sure how to achieve this.

Thanks

George

Link to comment
Share on other sites

Hi,

Tried to add this file again yesterday but I see no new post so trying again today.

I have just discovered that to get the SDI instruments attention there needs to be a break "continuous spacing for at least 12 milliseconds". This needs to be done before all commands are sent to the SDI-12 instrument.

Any idea how to achieve that?

Thanks

George

SDI_12_questions.zip

Link to comment
Share on other sites

You can get a 12 millisecond delay just by doing delay(0.012) in your script at the appropriate spot.

In your monitor I see it echoing back what you type. Does it echo everything? Try typing some garbage and see if it sends back the same thing.

Also, do you need a carriage return at the end? A lot of programs, like Hyperterminal, and maybe your tool, don't show carriage returns or line fields in their monitor. You can generate one by doing 13 in the monitor (or 10 for a line feed)

Link to comment
Share on other sites

Hi,

The break is not just a delay it is a break in actual communication line. From another source

A typical section of code (VB6) would be

Set the Break condition.

MSComm1.Break = True

' Set duration to 1/10 second.

Duration! = Timer + .1

' Wait for the duration to pass.

Do Until Timer > Duration!

DoEvents

Loop

' Clear the Break condition.

MSComm1.Break = False

Or the section of code in the SDI Explorer software (C#)

this.port.BreakState = true;

Thread.Sleep(sdiBreakLength);

this.port.BreakState = false;

So these are commands to the hardware port to create this break condition not just a time delay so unless there is an equivalnet command in DaqFactory I don't think it will work.

It will always echo back what I type and no CR and LF's are not needed. The device will send dat back terminated with a CR LF sequence.

Thanks for the help

Link to comment
Share on other sites

I thought maybe so. The current release of DAQFactory does not support this. However, since you asked nicely, we have added it to the next release, which should be mid next week. Before that, however, I'd like you to try it, so if you could email us directly through our web form, I will email you back a link with a patch so you can try it and make sure it works the way you want before we release it. The functions will be:

device.mydevice.SetCommBreak()

and

device.mydevice.ClearCommBreak()

Link to comment
Share on other sites

Hi,

With a great deal of help from the folks at Azeotech we have managed to get DaqFactory to talk happily with SDI-12 instruments. So here is how it was achieved.

SDI-12 is a communications protocol that allows mulitple instruments to talk over a simple two wire interface, just Ground and SDI-12. This has been designed to allow sensors with SDI-12 to talk to dataloggers but I wanted them to be able to talk to the PC - DaqFactory actually. To achieve this you need to have a convertor that interfaces between the SDI instruments and the PC. I use a UNIDATA one (see http://www.unidata.com.au/pubs/brochures/usb_interface.pdf). This device is actually an SDI-12 to USB to serial convertor so once installed it is just another serial port on the PC. The software that comes with it is great to test that it works with your instrument.

The protocol to talk to the SDI instrument requires that a break on the serial port line is created for 20 milliseconds. This was the first problem that Azeotech fixed by adding two more commands to DaqFactory (see previous posts). Once that was sorted it was a matter of making it work. With the impressive technical support this was achieved with one telphone call and allowing Azeotech support to take control of my PC - what a great service!!

Another factor is that once the break on the communications line has finished you must wait for a minimum of 8.5 ms before sending a command.

Firstly a new serial port device was created with the communication parameters set as above. Because the communications is via only two wires (input and output goes over the same line) then any output command to the device is echoed with the response and that multiple commands may be needed to get the data it was easier to use a sequence than the standard Poll routine.

To get data from an SDI-12 device you must first command it to take a measurement of its sensors using the command nM! where the n is the address of the SDI instrument and is in the range (0-9), so mine was 0M!. This command responds with the SDI-12 address (0-9), 3 digits for the time delay in seconds before the data will be ready (035 in my case) and how many data values will be returned (5 in my case). You then need to wait for that time period and then send the command to get the dat, split it up and save it to your channels.

The Poll code is

function Poll(string out, until)
//This is just DaqFactory Poll routine placed in a sequence because the process
//is quite different for SDI-12. Because it is in a sequence we need to address
//the commands to the actual device as in "device.sdi.write(out)"   
//sdi is out serial device set up via menu Quick/Device Configuration, where we
//set all the port parameters, for SDI-12 these are
// baud=1200, 1 start bit, 7 data bits,1 parity bit (even parity), 1 stop bit.
//for the protocol use the NULL protocol.

// this function will poll the port with given string and read
// the response until the given character.  Returns NULL (empty)
// if there is an error

if (argc < 2)
   throw("Invalid number of parameters")
endif
private string in
try
   // lock the port
   if (!Device.sdi.LockPort())
	  throw("Unable to lock port")
   endif
   // clear anything pending
   Device.sdi.Purge()
   //begin break on serial port. SDI-12 requires a break on the port for a minimum
   //of 12 millseconds to awaken all SDI-12 instruments to let them know a command is coming
   Device.sdi.SetCommBreak()
   //keep break for 20 ms, added a little extra to be sure
   delay(0.02)
   //clear the break on the serial port
   Device.sdi.ClearCommBreak()
   //once break is complete we need to have a delay og 8 ms before a command is sent
   //delayed here for 10 ms
   delay(0.01)
   //clear anythin on port
   Device.sdi.Purge()
   // output our string
   Device.sdi.Write(out)
   // and read until the eol:
   in = Device.sdi.ReadUntil(until) 
   // release the port
   Device.sdi.UnlockPort()
   // and return the response
   return(in)
catch()
   // error occured
   Device.sdi.UnlockPort()
   throw()
endcatch
// return NULL to indicate error.  This should never happen
// because of the throw() statement above
return(NULL)

The code to use Poll sequence is

// Routine to poll SDI instrument for data
// Output command is "0M!", SDI instrument responds with
// Instrument address(1 character,0-9), Time before data sent (3 characters, in my case 035 which
// is 35 seconds), number of data values )in my case it has 5 sensors0\)

private string datain  // string for input
private string data	// string for cleaned data 
private delayamount  // delay in seconds
// poll our port by sending command and wait for CR
datain = poll("0M!",13)
//extract out the delay, return is like 0M!00351310
//because SDI-12 sends input and output over same line the command is echoed back as well as the data
//therefore need ignore first 4 characters and next 3 are the delay in seconds
//NOTE - this sequence assumes you only have one SDI instrument attached with address 0
//if there are more then the address will need to be extracted to enable the data to be sent to the correct channel
delayamount = strtodouble(mid(datain,3,4))
//check if delay is very short and make sure we wait for  short period
if (delayamount < 5)
   delayamount = 5
endif
//delay for set time (added 1 second more to be sure)
delay(delayamount + 1)
//send data command to get the latest data
datain = poll("0D0!",13)
//remove command from beginning of line ready to pass data and pass it using the plus sign as data separator
// data line looks like "0D0!0+23.19+99.5+3.14+4.9+10.871310" 
//"0D0!" is command echoed, next "0" is SDI address, remainder is data
data = parse(mid(datain,6,1000),-1,"+")
//go add to channels
for (private x = 0, x < numrows(data), x++)
   execute("ch" + doubletostr(x) + ".addvalue(strtodouble(data[x]))")
endfor

It is now easy to set these up to run at the time intervals required.

Thanks once again to the marvellous help at Azeotech without whose efforts this would have a major hassle to achieve and would have taken many hours more.

George

Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.