Serial Communication

For a senior project, I am trying to get an Arduino Duemilanove to talk to a Microstrain InertiaLink unit (a 3 axis accelerometer and 3 axis gyroscopes). I have a MAX 232 chip installed to insure the two units talk in TTL language. How can I send a command "0xC2" which is the initiating command to prompt the Microstrain unit to output acceleration and angular rates?

Thank you

I'm not sure I'm answering the right question, but

char c = 0xc2;
Serial.print(c);

should do what you want.

(Are you using the standard hardware serial line, because when I used a serial connection to a MAX 232 as well as the USB serial port, I had to disconnect the MAX 232 connections to serial pins 0 and 1 to allow the bootloader to work. Duemilanove board.)

well thanks. here is what i have but dont see a response.

#include <SoftwareSerial.h>

#include <NewSoftSerial.h>

int Tx = 1; // Set Tx to 1
int Rx = 0;
int incomingByte = 0; // for incoming serial data

void setup()
{
pinMode(Tx, OUTPUT); // sets the digital pin as output
pinMode(Rx, INPUT);
char c = (0xC2); //44 equal Hex 2C
Serial.print(c);
delay(1000);

Serial.begin(115200); // opens serial port, sets data rate to 9600 bps
}

void loop() {

// send data only when you receive data:
if (Serial.available() >= 0) {
// read the incoming byte:
incomingByte = Serial.read();

// say what you got:
Serial.print("I received: ");
Serial.println(incomingByte, DEC);
}
}

I'm confused about your hardware connections. Can you post a schematic please.

I think you are NOT using SoftwareSerial, the Serial.xxx calls are to the hardware serial port, which is the build in UART, on pins 0 and 1.

You need to connect your Inertial Link to some other pins, then use SoftwareSerial to define a software serial port on those pins.

Have a good look at the softwareserial manual page.

  • What pins are allowable?
  • What pins are not good ones to use?
  • Can you find the example?
  • In the example, how is the port declared and started?
  • In the example, how is a call to a softwareserial port made?

I don't understand the comment in the code either - what speed are you trying to talk to the Inertial Link?

What speed are you trying to talk to the host computer?

(I'm happy to answer more questions, but will not be around for the next 4 days or so now. I have been working an implementation of
a software serial, driven by interrupts, for slower serial speeds and have been using a MAX232 chip - but for general purpose stuff you are right to use software serial or new software serial).

well thank you. this was not my latest progress but the coding is generically the same. The software serial was not used and forgot to comment it out on this one. Dont worry about the comments but the content of the code for I want 115200 baud rate to communicate with the Inertia Link. The code works enough to send a command signal "0xC2" out to the Inertia Link. The protocal manual says it needs to be a command byte of 0xC2. So instead of char c = 0xC2, should it be byte c = 0xC2?

does the output of a square O, y with two dots over it, and a A with a carot over it mean anything?

A byte and character are both 8 bits long; it won't make any difference for your serial output. The print statement should print out the single character value if given a char type. It should print out the number representing the value if given a byte. So I think that char is the right one to use.

The funny characters could be that you are receiving at the wrong speed.

I still don't understand how you are talking to the Inertial device and the COM port on your computer using the same port.
Your code is going to - send 0x2c on the serial port (to the Interial Device?)
Next its going to send on the serial port (to the Intertial Device?)

Your code is wrong too:

  • you need to start the serial port BEFORE sending out data.
  • don't think you need to set the TX and RX pin directions, that's already done for you.

start the serial port?

if it is wrong, I would still get the light to flash on on the Inertia Link signifying a data byte received?

Blackdragon,
I'm just pointing out that you are starting the serial port after using it. That is not how you are supposed to use it, so your results in terms of speed or output may be peculiar. It might output at some default speed if used before starting it, and the Inertial receive light might flash but receiving garbage.

You seem to be ignoring my questions about your hardware configuration. I think that might be key to your system working and would be happy to give advice if you provide some type of schematic or diagram of how your connections are done.

I still cannot understand how you are talking to both the Inertial device and your host computer using one serial port. If you can address that, it might help.

I've got to go now, back on Thursday or Friday. Good luck.

P.S. Have a look at Serial.begin on Arduino - Home and then have a look at Serial.print(b, BYTE).

Try this:

int incomingByte = 0;     // for incoming serial data
char c;

void setup()
{
Serial.begin(115200);
c = 194;              //194 equal 0xC2
Serial.print(c);
delay(1000);
}

void loop() {

           // send data only when you receive data:
           if (Serial.available() >= 0) {
                       // read the incoming byte:
                       incomingByte = Serial.read();

                       // say what you got:
                       Serial.print("I received: ");
                       Serial.println(incomingByte, DEC);
           }
}

Based on your posts I can't tell if the code should actually be 0x2C or 0xC2, the posts say C2 but your code comments looked like 2C, if it's wrong change the c initialize statement to c = 44;

Are you connecting the device to the TX/RX pins of the Arduino and expecting the Serial.print() statements to debug to the screen via USB? If so you may need/want the software serial after all.

If you have a character LCD lying around try debugging using that instead of the serial line. Program the Arduino, disconnect the USB, and hit reset and see if messages start showing up on the LCD.

Update: i got the unit to run in continuous mode now so i know i have a lot of data coming at me. i am now using the following: i cleared up the comments so it is clear. I am now getting 32 1s do to the binary output. any suggestions to get more readable data? should i make a pure transmit pin (not pin 1) and the receive pin as 0 to ensure there is no interference when i write "i receive" ?

#include <NewSoftSerial.h>

//===========================================================================
// SetContinuousMode
//---------------------------------------------------------------------------
// Start continuous mode
//===========================================================================

NewSoftSerial SerialIn(0, 1);

int incomingByte = 0; // for incoming serial data

void setup(){
//pinMode(Tx, OUTPUT);
// pinMode(Rx, INPUT);
SerialIn.begin(115200); // opens serial port, sets data rate
//delay(100);

byte a = B11000100; //binary for 0xC4
SerialIn.print(a);
byte b = B11000001; //binary for 0xC1
SerialIn.print(b);
byte c = B00101001; //binary for 0x29
SerialIn.print(c);
byte d = B11000010; //binary for 0xC2
SerialIn.print(d);

if (SerialIn.available() >= 0) {

}
}
//delay (100);

void loop() {

// send data only when you receive data:

// read the incoming byte:
incomingByte = SerialIn.read();

// say what you got:
SerialIn.print("I received: ");
SerialIn.println(incomingByte, BIN);

}

Thanks

well THANK YOU so much mdowning I cannot believe it was so simple. You dont know how many hours went into this. So now I just need to pull off the data into readable numbers for acceleration and angular rate? I am still abit unsure how to seperate this out, but this definitely puts me forward to the next step.

Do you have a link to the microstrain datasheet or do you know how it spits the data back over the serial line? That should offer some clues.

I'm guessing here, but if it sends data as multiple bytes that will always come in the same order (X acc, Y acc, Z acc, for instance) you can change your if statement from waiting for any data to be received to when a certain amount of data is received.

if (SerialIn.available() > 0) changes to

if (SerialIn.available() >=3) meaning there are at least 3 bytes in the buffer.

Then in the loop you can assign each of the three bytes to a different variable, or read it into an array in a way that makes sense.

I actually haven't used NewSoftSerial so I don't know how big the buffer is. Just make sure it doesn't overflow because if bytes are lost the group of three bytes may not be synced anymore and you'll get bogus data.

yes it does command in certain number of ordered bytes. the link is the following:

http://www.microstrain.com/pdf/dcp/Inertia-Link-3DM-GX2-data-communications-protocol.pdf

My concern is that if I put the final print value as BYTE, then I get a y with a double dots over it.

Thanks

Boy, that sensor has some tricky communications...

OK, if I'm reading this right you're going to need to structure your input routing carefully because there's probably some data you want and some you don't (confirmations, checksums and such).

Just out of curiosity, why are you using continuous output mode instead of polled mode? Seems like it would be easier to structure the communications if you asked for say accelerometer data, read it in, then asked for something else. Instead in continuous output you have to parse huge amounts of data not knowing exactly what it is?

Also keep in mind - I don't know how large the NewSoftSerial buffer is but the regular serial buffer is only 64 bytes. Most of the data packets on here look to be 30+ bytes in length so if you are parsing data while two packets are received, the next one may be lost.

Good luck!

The continuation mode was set to assure that reasonable data was being received. Thanks to your coding, all works well and numbers look reasonable. I just need to convert a ASCII DEC printout to normal decimals (1.00 g) for example. I was trying to find this last night. I will convert to polled mode--for this is what we will use for our application. For proper organization, dont i need a BYTE output other than a y with a double dot on top?

thanks

Well I have made huge progress and have 1 more step. I have all incoming bytes organized by the accelerations and angular rates. The final code I am using is the following. It simply organizes the incoming bytes to their corresponding desired outputs. I want to get the 4 inputs organized into 1. My understanding is the followin: You have 4 bytes (8 bit words) for Acceleration X for example, correct. If the first 2 bits are say (10000001) and (00011000), then add 8 zeros to the first word resulting in (1000000100000000) and add to second bit resulting in 1000000100011000 ( a 16 bit word). This value precedes the decimal point. You repeat the procedure for the last two bits resulting in a value after the decimal point. The combination of Result1.Result2 produces the final 32 bit word resulting in the single result of Acceleration X when read in DEC.

If my procedure is correct, can you use the shift command to tack on the following zeros?

float incomingByte = 0; // for incoming serial data
int i;
char a;
char b;
char c;
char d;
char e;
void setup()
{
Serial.begin(115200);
//e = 250; // DEC for 0xFA stop continuous mode
//Serial.print(e);
//a = 196; // DEC for 0xC4 start continuous
//Serial.print(a);
//b = 193; // DEC for 0xC1 dont change
//Serial.print(b);
//c = 41; // DEC for 0x29 dont change
Serial.print(c);
d = 194; // DEC for 0xC4 change for desired output (see Microstrain Protocal)
Serial.print(d);
delay(1000);
if (Serial.available() >= 0) {
for (i=0; i<1; i++) {// read the incoming byte:
incomingByte = (float)Serial.read()/10.0;
Serial.print("\n\nHeader: ");
Serial.println(incomingByte*10);
}
Serial.print("\n");

for (i=1; i<5; i++) {
incomingByte = (float)Serial.read()/2560.0;
Serial.print("Acceleration in X: ");
Serial.println(incomingByte*10);
}
Serial.print("\n");

for (i=5; i<9; i++) {
incomingByte = (float)Serial.read()/2560.0;
Serial.print("Acceleration in Y: ");
Serial.println(incomingByte*10);
}
Serial.print("\n");

for (i=9; i<13; i++) {
incomingByte = (float)Serial.read()/2560.0;
Serial.print("Acceleration in Z: ");
Serial.println(incomingByte*10);
}
Serial.print("\n");

for (i=13; i<17; i++) {
incomingByte = (float)Serial.read()/2560.0;
Serial.print("Angular Rate in X: ");
Serial.println(incomingByte*10);
}
Serial.print("\n");

for (i=17; i<21; i++) {
incomingByte = (float)Serial.read()/2560.0;
Serial.print("Angular Rate in Y: ");
Serial.println(incomingByte*10);
}
Serial.print("\n");

for (i=21; i<25; i++) {
incomingByte = (float)Serial.read()/2560.0;
Serial.print("Angular Rate in Z: ");
Serial.println(incomingByte*10);
}
Serial.print("\n");

for (i=25; i<29; i++) {
incomingByte = (float)Serial.read()/2560.0;
Serial.print("Check Sum: ");
Serial.println(incomingByte*10);
}
Serial.print("\n");

for (i=29; i<31; i++) {
incomingByte = (float)Serial.read()/2560.0;
Serial.print("Timer: ");
Serial.println(incomingByte*10);
}
}
}
void loop() {}

Thank you. This is my last step

I have some suggestions, which I hope you will take in good part.

1 Your code as posted is all in setup, so it is going to run once and stop. Is that what you wanted? Perhaps it should be inside loop.

2 You are assuming that as soon as 1 serial byte is ready for reading (the available() call), all the rest will follow slightly slower than you can process them - that is dangerous. Serial.read() will return -1 if no data is present. You could start analysing as soon as
available() > 31, then you know you can safely read 32 bytes.

3 I would do the data manipulation like this, otherwise you will overflow the byte. The spec for the output seems to be a 4 byte value, in a floating point format, and I think you are intending to use command 0xC1. I haven't got one to try! Also, print does not work on float.

long incomingvalue; //should by 4 bytes long
float z;
int int_part_of_float;
int frac_part_of_float;

// for each block of data, as you coded it
incomingvalue = 0;
for (i=9; i<13; i++) {
incomingvalue <<= 8; // shift contents 8 bits = multiply by 256
incomingvalue += Serial.read(); // add byte in
}
z = float(incomingvalue);
int_part_of_float = (int)z;
frac_part_of_float = 100 * (z - (float)int_part_of_float);

Serial.print("Acceleration in Z: ");
Serial.print(int_part_of_float);
Serial.print('.');
Serial.println(frac_part_of_float);
Serial.print("\n");

4 According to the device specs, you get an 8 byte response back when you set continuous mode. At the moment your code is ignoring this, you need to eat those bytes in the setup part. Perhaps

if (Serial.available() > 7)
{
for(i = 0; i < 8; i++)
{
Serial.read();
}
}

Good luck.

well thank you very much. I am trying to perform my work in polled mode--one time display of the values. When I ran your code, I receive a number of about 12,000. One concern was whether your coding involved the 32 bit output of the Inertia Link in IEEE 754 format-sign (+/-) is first byte, exponent follows in the next byte, then rest are base value. This is how I understand it. I was concerned that the shifting is overriding this format?

You are right, I'm looking for a way to convert the 4 bytes into a float format. The cast (float)incomingvalue won't work. Try the code following. I've tested putting some bytes into the array, and it gives the same value as a float.

Edit: I've looked at page http://babbage.cs.qc.edu/IEEE-754/32bit.html I don't know which order your device will send the bytes, you may have to tinker, by reversing the order the 4 bytes are read into the array. I've posted the sketch I was using to try and convert bytes to and from floats. It gives the same value as the calculated values from the page, e.g. 100 is hex 42c80000, which is loaded as the values 0 0 200 66.

union t_long_fl { // this assign the byte array on the same memory as the float
byte b_arr[4];
float f_var;
} ;

t_long_fl t1;
int j;
 
int int_part_of_float;
int frac_part_of_float;

// for each block of data, as you coded it
  j=0;
  for (i=9; i<13; i++)
  {
    t1.b_arr[j] = Serial.read(); // add byte into array
    j += 1;
  }

  int_part_of_float = (int)t1.f_var;
  frac_part_of_float = 100 * (t1.f_var - (float)int_part_of_float);

  Serial.print("Acceleration in Z: ");
  Serial.print(int_part_of_float);
  Serial.print('.');
  Serial.println(frac_part_of_float);
  Serial.print("\n");
long readnumber()
{
  char c;
  long res= 0;
  int count = 0;
  boolean pos = true;
  while (true) {
   if (Serial.available())
   {
     c = Serial.read();
     count ++;
     if (c >= '0' && c <= '9')
     {
       res *= 10;
       res += (c - '0');
     }
     else if (c = '-' && count == 1)
     {
        pos = false;
     }
     else
     else
     {
       break;
     }
   }
  }
  return pos ? res : -res;
}

union t_long_fl {
byte  b_arr[4];
float f_var;
} t1 ;

void print_ba()
{
  for (int i = 0; i < 4; i++)
  {
     Serial.print(" ");
     Serial.print((int)t1.b_arr[i]);
  }
}

void print_float(float f)
{
  long i_i = (long)f;
  int i_f = 100 * (f - (float)i_i);
  Serial.print(i_i);
  Serial.print('.');
  Serial.print(i_f);
}


void setup()
{
  Serial.begin(9600);
  Serial.print("enter [Fii ff ] or [Imm mm mm mm ] or [P]\nii ff integer,fractional part for float\nmm values for each byte (dec)\n");
}

void loop()
{
  long int_part;
  int int_frac;
  if (Serial.available())
  {
    char c = Serial.read();
    Serial.print(c);
    switch (c)
    {
      case 'I':
        for (int i = 0; i < 4 ; i++)
        {
          t1.b_arr[i] = readnumber();
        }
        print_ba();
        Serial.println();
        break;
      case 'F':
        int_part = readnumber();
        Serial.print("int part:");
        Serial.print(int_part);
        int_frac = readnumber();
        Serial.print(" frac part:");
        Serial.println(int_frac);
        t1.f_var = int_part + float(int_frac)/100.0;
        break;
      case 'P':
        print_float(t1.f_var);
        print_ba();
        Serial.println();
        break;
      default:
        Serial.println(" bad char ");
        break;
    } // end switch
  }
} // end loop