Hi,
I am trying to interface an Arduino with a depth gauge sensor on my boat. The depth sensor is no longer supported and there are no specs or support for it (if you're curious, it's a Standard Horizon DS50). However, it has a 5-pin interface and using a multimeter I was able to identify the GND, VCC (12v) and TX pins, and by hooking up an FTDI board to my MacBook and using a terminal program, I was able to verify the device is transmitting data at 1200 baud 8N1. The device is transmitting well-formed 8-byte sentences that start with 0x38 and end with 0x00.
I wrote a python program to read the data:
port = serial.Serial(portName, baudrate=1200, bytesize=8, parity='N', stopbits=1, timeout=0)
print(port.name, file=sys.stderr)
word = ''
while True:
data = port.read(1)
if len(data) > 0:
for c in data:
if len(word) == 0 and c == 0x38:
word = b'\x38'
elif len(word) == 7 and c == 0:
ts = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
print("%-12s %4X %4X %4X %4X %4X %4X %4X" % (ts, word[0], word[1], word[2], word[3], word[4], word[5], word[6]))
word = b''
elif len(word) > 0:
word = word + bytes([c])
Which produces output like this when connected as described with either a 5V or 3.3V FTDI adapter:
/dev/cu.usbserial-A603AXO7
2023-09-03 13:52:21 38 83 B9 28 3B 2B 32
2023-09-03 13:52:23 38 87 B9 28 3B 2B 35
2023-09-03 13:52:25 38 3B B9 A9 83 2B 2A
2023-09-03 13:52:26 38 83 B9 A8 3B 2B 35
2023-09-03 13:52:26 38 3B B9 A8 3B 2B 2A
And another python program to write simulated data:
port = serial.Serial(portDev, baudrate=1200, bytesize=8, parity='N', stopbits=1, timeout=0)
random.seed()
template = [56, 59, 185, 0, 0, 43, 42, 0]
while True:
# change bytes 3 & 4 to random numbers
template[3] = random.randint(1, 200)
template[4] = random.randint(1, 200)
print(' '.join(['{:02X}'.format(c) for c in template]), file=sys.stdout)
port.write(template)
time.sleep(0.75)
And of course, an Arduino program that essentially does the same thing as the first python program; I'm connecting the RX pin on the Arduino to the TX pin on the DS50 and GND to GND.
#include <LiquidCrystal.h>
const int rs = 9, en = 8, d4 = 5, d5 = 4, d6 = 3, d7 = 2;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
void setup() {
Serial.begin(1200, SERIAL_8N1);
// initialize the display
lcd.begin(16, 2);
lcd.clear();
}
unsigned char ds50Buf[16];
int ds50BufSize = 0;
void loop() {
while( Serial.available() > 0 ) {
process();
}
}
void process() {
int readByte;
char buf[4];
status("PROCESS");
readByte = Serial.read();
status_byte("RX", readByte);
if( ds50BufSize + 1 >= sizeof(ds50Buf) ) {
status("RESET");
ds50BufSize = 0;
}
if( ds50BufSize == 0 && readByte == ds50Byte0 ) {
status("BEGIN");
ds50Buf[ds50BufSize++] = readByte;
}
else if( ds50BufSize == 7 ) {
status("END");
if( readByte == 0 ) {
// legitimate ds50 sentence
ds50Buf[ds50BufSize++] = readByte;
logData();
}
ds50BufSize = 0;
}
else if( ds50BufSize > 0 ) {
ds50Buf[ds50BufSize++] = readByte;
}
}
void status(const char *s) {
status(s, 3);
}
void status(const char *s, int pos) {
int i, x, y;
y = pos/2;
x = (pos%2) * 8;
lcd.setCursor(x, y);
lcd.print(s);
i = strlen(s);
while( i++ < 8 )
lcd.print(' ');
}
void status_byte(const char *s, int b) {
char buf[12];
strcpy(buf, s);
sprintf(buf + strlen(buf), "%02x", b);
status(buf, 0);
}
void logData() {
unsigned long t = millis();
char lcdBuf[20], logBuf[32], buf[4];
int i;
status("LOGGING");
// sanity check
if( ds50BufSize > 8 ) ds50BufSize = 8;
sprintf(logBuf, "%06ld", (long) (t/1000));
lcdBuf[0] = 0;
for(i=0;i<ds50BufSize;i++) {
sprintf(buf, "%02X", (int) ds50Buf[i]);
// don't print the terminating 00 to screen
if( i < 7 ) strcat(lcdBuf, buf);
if( i == 2 || i == 4 ) {
strcat(lcdBuf, " ");
}
strcat(logBuf, " ");
strcat(logBuf, buf);
}
lcd.setCursor(0, 0);
lcd.print(lcdBuf);
lcd.setCursor(0, 1);
lcd.print(millis()/1000);
}
I'm testing with both an Arduino Uno R3 (5V 16Mhz) and an Arduino Pro Mini (3.3v 8Mhz).
Results:
- I can connect my Macbook to the DS50 and run the 1st program (data receiver) and it produces the expected 8-byte sentences
- I can connect my Macbook running the 2nd program (data simulator) to an Arduino running the program shown and the Arduino parses and prints the same 8-byte sentences
- However, connecting the Arduino to the DS50 produces a string of unrecognized bytes, mostly 0x2B, 0x2E and 0x00.
- I've tried inserting a logic shifter on all of the scenarios described above with no effect; i.e., the Macbook can communicate with either the DS50 or the Arduino (suggesting the logic shifter is correctly connected) but the Arduino still doesn't read data correctly from the DS50. For the Uno I'm connecting VCC on the logic shifter to 5V on the Uno, and for the Pro/Mini I'm connecting to VCC (3.3v)
- The Macbook can read the DS50 with either a 3.3V or 5V FTDI adapter, with or without the logic converter.
Bottom line: all 3 devices are sending or receiving at 1200 baud, 8N1. The Macbook can read either Arduino or the DS50 just fine. Either Arduino can read the Macbook (sending simulated data) fine. But neither Arduino can read the DS50; instead it gets seemingly random data bytes. Logic shifters seem to have no effect.
Any ideas what could account for this? Perhaps a default in the serial setup that is different in the Arduino and Macbook/python environments?