RS-232 with force gauge: two-way communication?

Hello all,

Situation
I'm having trouble with something that should be simple...
I'm trying to use Arduino to measure forces out from a basic force gauge that uses RS-232 data output.
The Force gauge is from a Japanese company called Imada, and reading its not-so-complete manual (penultimate page of http://www.checkline.com/products/126020/zp-manual-usb-3.pdf), I see its RS-232 uses these parameters:
19200 bps; 8 data bits; 1 stop bit; no parity bits

What I did
First, from the 9-pin plug from the Force gauge, I hooked up appropriate RX, TX, and GND wires to Arduino via MAX232.

Then, I wrote very simple code (see below) using NewSoftSerial on pins 2 and 3, and proceeded to print out what I saw on computer serial monitor.

Note that, as the manual says, since this device's communication is bi-directional, I need to send out a command first in the form of an Ascii character.
In my case, since I just want to read out measurements, I sent out:
--the ASCII character 'D' (which corresponds to command of reading out display data from the gauge)
--a carriage return
--start and stop bits handled by NewSoftSerial

PROBLEM
Everything is happening as it should from my side but I'm getting nothing in the output from the gauge!

I checked the scope at various points to see what was going in:

  1. Transmit: I saw: 5 Volt pulses from the Arduino's TX before the MAX232 chip
  2. Transmit: I saw: MINUS 8 Volt pulses to PLUS 8 Volt pulses (approx.) on the TX line from Arduino AFTER MAX232 chip
  3. Receive: I saw: Nothing from the gauge's RS-232

Question: What am I doing wrong in terms of sending my request for data, and why is the gauge not answering?!
I'm afraid I'm missing something very basic about RS-232, because based on what I've read, it's supposed to be simple.

The very straightforward code...

#include <NewSoftSerial.h>
NewSoftSerial mySerial(2, 3);
char c;

void setup() {
  mySerial.begin(19200);
  Serial.begin(19200);
  pinMode(3,OUTPUT);
}

void loop() {
  // First, send out an ascii-character command to request data
  mySerial.println("D"); // ASCII character 'D' followed by carriage return

  // Then, just read in the received data, if any
  if (mySerial.available()) {
     c = (char)mySerial.read();
     Serial.print(c);
  }
  else delay(500);
}

I think you might have a misconception as far as start and stop bits used in serial communications. Those bits are imbedded and sent and received automatically by either the serial hardare on chip or the NewSoftSerial serial library. There is no need for you to directly manuipulate the serial output pin using digitalWrite statements.

Lefty

Lefty, after learning that NewSoftSerial handles that, I changed it; still no luck...

I'm wondering if the problem is with the range of +8 V to -8 V that I'm seeing in the pulses I see when reading the Arduino's TX signal after MAX232.
Perhaps that range is not acceptable for RS-232 (does it need to be a strict, specific amplitude)?

I'm wondering if the problem is with the range of +8 V to -8 V that I'm seeing in the pulses I see when reading the Arduino's TX signal after MAX232.
Perhaps that range is not acceptable for RS-232 (does it need to be a strict, specific amplitude)?

Those voltages seem good to me. RS-232 allows something like +/- 3-15vdc as the logic levels. On the Arduino side you should only see 0vdc and +5vdc logic levels.

Lefty

Ok, problem half-solved.
Still have just ONE PROBLEM though!

Good news is, I realized that the pins I plugged into on the DB-9 plug were mirrored from what they should be (I was using a google-found reference). Four hours spent due to such a trivial thing!

Now, I can send it commands perfectly; for example, I'm able to zero the gauge, change units on its display etc., through the RS-232 (will be doing a tutorial soon, if anyone's interested; this is very cool - I can remotely command a force gauge now!).

But bad news is:
For the opposite direction, it doesn't work! For example, when I want to read data from the display, I send it the appropriate command (which I can accurately assume the gauge is getting, because it's getting the other commands). But after that command is received, I don't think it's sending back any data.

Or I'm not reading it properly? Anyone see something that COULD go wrong with the code or the basic approach for reading OUT data from the gauge?

Unless I'm missing something about how you set things up, or how the NewSoftSerial library works, I don't think you can just wire a TTL serial device (like the Arduino) to an RS-232 serial device. See here: RS-232 vs. TTL Serial Communication - SparkFun Electronics

I realized that the pins I plugged into on the DB-9 plug were mirrored from what they should be (I was using a google-found reference). Four hours spent due to such a trivial thing!

You can never trust the RX/TX labels, they may be relative to the gadget or the thing they expect to be plugged in.

If you can send other commands successfully then the read command should work as well, but the other commands didn't require two-way comms I guess. Can you verify that the gauge is transmitting by looking at the input to it's line driver chip, then the output etc.


Rob

void loop() {

// First, send out an ascii-character command to request data
  mySerial.println("D"); // ASCII character 'D' followed by carriage return

// Then, just read in the received data, if any
  if (mySerial.available()) {
    c = (char)mySerial.read();
    Serial.print(c);
  }
  else delay(500);
}

I wouldn't do it like that. What's the delay for? If it doesn't respond within a microsecond or so you wait 500 ms and then try again. Maybe more like:

void loop() {
  // First, send out an ascii-character command to request data
  mySerial.println("D"); // ASCII character 'D' followed by carriage return

  // wait for response
  while (!mySerial.available()) {}

  // Then, just read in all the received data
  while (mySerial.available()) {
     c = (char)mySerial.read();
     Serial.print(c);
  }

  delay (500);

}

Even that isn't great, because if there is no response it just hangs. But it should be enough for testing.

thank you guys... after incorporating a couple of your suggestions (see below) and messing around with the loose wires, it worked! 99% there.

One very small but tricky problem remains:
When I use regular serial (i.e., inbuilt RX-TX functionality on pins 0 and 1) for both sending and receiving data, then both RECEIVE and TRANSMIT work perfectly fine, and I see data from the force gauge on serial monitor of computer.
BUT when I use NewSoftSerial (on pins 2 and 3), I'm unable to see any RECEIVED data (transmit works fine)... even though I wrote the code so that serial monitor of the computer prints out any received data on NewSoftSerial's RX.
Why could this be??...
(placed current updated code, i.e., the version with problem below...)

@jgalak: yes, as I mentioned, I used MAX232 for inversion and level shifting.

@Graynomad: yes, I guess it's always better to use the multimeter to check which one is which, unless datasheet of product tells you.
I didn't change anything much in the circuit, but just decided to try your suggestion, and used scope again to check directly from gauge (as opposed to checking with scope directly at arduino RX earlier), and voila, it showed pulses!
then I pushed the wires into the breadboard harder, and haha, pulses at arduino too.

@Nick:
as you see in my updated code with your addition, I added a generous timer condition to prevent the hanging problem.

Code

#include <NewSoftSerial.h>

NewSoftSerial mySerial(2, 3);
char c; unsigned long start;

void setup() {
  mySerial.begin(19200); Serial.begin(19200);
}

void loop () {
    mySerial.print('D'); mySerial.print(13,BYTE); }
  
    start = millis();
    while (!mySerial.available() && (millis()-start) < 500) {}
  
    start = millis();
    while (mySerial.available() && (millis()-start) < 500) {
           c = (char)mySerial.read();
           Serial.print(c);
    }
  
  delay(500);
}

giantsfan3:
@jgalak: yes, as I mentioned, I used MAX232 for inversion and level shifting.

My bad, I missed that part of the op.

I don't know if it will fix it, but you don't need the timeout code here:

start = millis();
    while (mySerial.available() && (millis()-start) < 500) {
           c = (char)mySerial.read();
           Serial.print(c);
    }

mySerial.available() will end the loop as soon as data is not available, which will happen eventually. It is more useful in the earlier loop which loops until data is available (which might be never).

Hey Nick we have a photo, nice to put a face to the posts.

I'd do the same but there's probably youngsters browsing the forum, I don't want to scare them.


Rob

(offtopic, I know - apologies to the OP).

Rob, your CV reads a bit like mine. Nice photos, too BTW. I still have my old 6800 programming manual - I couldn't afford an assembler in those days so I had to just write in hex machine code. That is, until I finished my first major project: an assembler. That made things a bit easier.

I couldn't afford an assembler in those days so I had to just write in hex machine code. That is, until I finished my first major project: an assembler.

Bootstrapping at it's best.

Nice photos, too BTW.

Thanks, it keeps me off the streets :slight_smile:


Rob