Need help with sending/receiving and making use of hex data over serial.

Hi all, I have a project where I'm trying to interface with a laser rangefinder module using arduino, however I'm having a little bit of difficulty.

Essentially I need to send a command in hex, receive the hex reply, convert the sixth and seventh bytes to decimal at which point I can use that however I need.

Right now I'm trying to use software serial to connect to the module so the arduino can output to the computer.

#include <SoftwareSerial.h>

SoftwareSerial mySerial(2, 3); // RX, TX

byte singleshot[8]={0x55,0xAA,0x88,0xFF,0xFF,0xFF,0xFF,0x84};

void setup()
{
  // Open serial communications and wait for port to open:
  Serial.begin(115200);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for Native USB only
  }


  Serial.println("Goodnight moon!");

  // set the data rate for the SoftwareSerial port
  mySerial.begin(115200);
}

void loop() // run over and over
{

  Serial.write(singleshot, sizeof(singleshot));
  delay(5000);
  mySerial.write(singleshot, sizeof(singleshot));
  Serial.println(mySerial.read());
  delay(1000);
}

The problem I'm having at least right now, just trying to send, is that a whole bunch of extra stuff is getting put in front of my message.

55 AA 88 FF FF FF FF 84 is what I need to send to the module however when I use a serial monitor that can handle hex, I instead see

47 6F 6F 64 6E 69 67 68 74 20 6D 6F 6F 6E 21 OD 0A 55 AA 88 FF FF FF FF 84

I have a feeling this same extra stuff at the start is being sent to my module hence getting a garbage response, but I'm not sure why it's adding all that extra stuff in.

When I use a different serial program I don't specify 0x55, 0xAA etc and maybe that's part of it? The thing is if I remove the 0x section then I get errors when I try to compile, saying that things such as "AA" weren't defined in the scope.

The only other part of this I think will be tricky is receiving the serial response from the module also in hex, and filtering out specific bytes to use, the third byte of the response would be 01 or 00 for success or failure, and ignoring failures would be good, and then I just need to isolate the sixth and seventh bytes to use with strtol as far as I can tell.

The second part doesn't matter much if I can't get the stuff being sent to the module to make sense though.

Software serial will not work at 115200 baud. The fastest that I have seen software serial run, reliably, is 38400 baud.

groundFungus:
Software serial will not work at 115200 baud. The fastest that I have seen software serial run, reliably, is 38400 baud.

I should be able to change down to 9600, 115200 is just the default on the module, however the extra garbage I am getting back in front of what I actually wanted to send is through the hardware serial connection, that wasn't going through the software serial port at all. I wanted to make sure the arduino was sending it properly and turns out it wasn't.

I also don't need two serial ports for this so in the end I probably will be using hardware serial, and I can hook up a little oled or something for testing too, but I need to have the code for sending and receiving hex without that gibberish in there right.

I also tried like this and I'm still getting all that extra crap in front of what I actually need. I don't get where "47 6F 6F 64 6E 69 67 68 74 20 6D 6F 6F 6E 21 OD 0A" is coming from when I send the hex directly do the serial port connected to the computer.

Serial.write(0x55);
Serial.write(0xAA);
Serial.write(0x88);
Serial.write(0xFF);
Serial.write(0xFF);
Serial.write(0xFF);
Serial.write(0xFF);
Serial.write(0x84);

It must be something simple.

What laser range finder module are you using? I'd be interested to try that out.

If you have an Uno, Mega, that kind of processor, you don't need these lines
while (!Serial) {
; // wait for serial port to connect. Needed for Native USB only
}

Also looks like Goodnight moon is going out
www.asciitable.com

CrossRoads:
What laser range finder module are you using? I'd be interested to try that out.

If you have an Uno, Mega, that kind of processor, you don't need these lines
while (!Serial) {
; // wait for serial port to connect. Needed for Native USB only
}

Also looks like Goodnight moon is going out
www.asciitable.com

Yeah, the regular text is going out over serial just fine, but if I monitor using Docklight under the HEX section, that's where I'm getting all that extra garbage info infront of what I need. That good night moon thing is just leftover from the software serial sketch I modified.

Maybe the ascii table would help although the last 8 groups I read in docklight are correct, so it's not like it's being completely lost, there's just all this... crap in front and I don't get it.

No matter what I try I can't get the single shot hex to send properly and man this is frustrating me. I can't find anyone having similar issues googling either.

All I need is to be able to send "55 AA 88 FF FF FF FF 84" as hex over the serial connection, like docklight or other terminal programs can and I'm sure I could make progress on the code to receive the hex return from the module pretty quickly.

I've seen a couple posts where people want to get specific bytes from hex and I'm sure I could find something useful but nobody seems to be having issues sending like I am. Uhg,

Here is an example of using the program docklight and a TTL adapter directly connected to the module, I send that hex information and it sends a reply, with bytes 6 and 7 being the distance. Works great using this.

What are you getting besides Goodnight moon? (which I looked up letter by letter, so it didn't seem to be just random stuff).

I don't know why software serial would be sending anything else out.

I've never sent an array out like this:
mySerial.write(singleshot, sizeof(singleshot));

I've only done it in a for loop, like

for (x=0; x<8; x=x+1){
mySerial.write (singleshot[x]);
}

Your 8 Serial.write()s would do the same tho.

47 6F 6F 64 6E 69 67 68 74 20 6D 6F 6F 6E 21 OD 0A = Goodnight moon! CR LF

What else are you seeing?

So after every command:
55 AA 88 FF FF FF FF 84

You get a reply with 55 AA 88 and then 5 more bytes.
Read those into an array as they come in, and parse for the data you want.

if (mySerial.available() > 7){
   for (x = 0; x <8; x=x+1){
   incomingStream[x] = mySerial.read();
   }
}

and go from there.

distance = some manipulation of incomingStream[3] thru [7];

Add a check that bytes [ 0 ] thru [ 2 ] are == 55 AA 88 so you can tell you're in sync.

Oh my F*king god, "goodnight moon" is the extra crap I was getting before 55 AA 88 FF FF FF FF 84.

Docklight wasn't just filtering out hex data but it was showing the ascii stuff in that tab too, and because there was no delay between the two both were showing up.

internal screaming

I can't believe it took me this long to see it.

Also for clarification, 55 AA 88 FF FF FF FF 84 is the command to get a reading, and the reply will be similar to

55 AA 88 01 FF 01 39 C1

01 is the status, 01 if it did read, 00 if it didn't, 01 39 are the high and low parts of the measurement and c1 is the check bit.

CrossRoads:

Ok, wanted to post updated code, this helped me confirm that the arduino is taking in a HEX input and spitting it out properly, also tried displaying on an oled but of course it's hex so it doesn't make sense. This at least helped me confirm that the sending and receiving is somewhat working on a basic level.

I also removed software serial as I won't be using the software serial connection when this thing is done, and I can use the OLED for debugging now that they arrived yesterday.

Now I just have to get hex input into an array as you mentioned, I'm not sure if it's better to read it as a string like I did here or not, but we'll see.

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 32 // OLED display height, in pixels

#define OLED_RESET 4
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

byte singleshot[]={0x55,0xAA,0x88,0xFF,0xFF,0xFF,0xFF,0x84};

String readString;

void setup()
{
  // Open serial communications and wait for port to open:
  Serial.begin(115200);
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C); //or 0x3C
  display.clearDisplay(); //for Clearing the display
  display.display();
  display.setTextSize(2);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(0,0);
  display.println("READY");
  display.display();
  delay(5000);
}

void loop() // run over and over
{


   while (Serial.available()) {
   delay(10);  //small delay to allow input buffer to fill

   char c = Serial.read();  //gets one byte from serial buffer
   if (c == ',') {
     break;
   }  //breaks out of capture loop to print readstring
   readString += c;
 } //makes the string readString  

 if (readString.length() >0) {
   display.clearDisplay();
   display.display();
   display.setTextSize(2);
   display.setTextColor(SSD1306_WHITE);
   display.setCursor(0,0);
   display.println(readString);
   display.display();
   Serial.print(readString);
   
   readString=""; //clears variable for new input
 }

  delay(5000);
}

With this as the loop it's printing the reply as ASCII, and I can see it flash rapidly on the oled but just show the last byte in the end, not sure if this is a better method to start with or if I want to keep it as non ascii. Hmm

void loop() // run over and over
{
     for (int i=0; i<23; i++) {
      while(!Serial.available()); // wait for a character
    int incomingByte = Serial.read();
    Serial.print(incomingByte,HEX);
    Serial.print(' ');
    display.clearDisplay(); //for Clearing the display
    display.display();
    display.setTextSize(2);
    display.setTextColor(SSD1306_WHITE);
    display.setCursor(0,0);
    display.print(incomingByte, HEX);
    display.display();
    }
    Serial.println();

  delay(5000);
}

I've tweaked the code from here from 2 to 3 and it's properly grouping all of the bytes and spitting them out converted to decimal individually which seems promising, I need the sixth and seventh to be together, and I also want to be able to read the fourth on it's own but this seems like a good start.

I do need to join the 6th and seventh, so that 1A 20 would be 1A20 for it to convert to decimal properly though, hmm.

void setup() {
  Serial.begin(115200);
}

void loop() {
  char input[3];
  int charsRead;
  int val;
 
  if (Serial.available() > 0) {
    charsRead = Serial.readBytesUntil('\n', input, 3);  // fetch the two characters
    input[charsRead] = '\0';                            // Make it a string

    val = StrToHex(input);                              // Convert it

    Serial.print("Hex input was: ");                    // Show it...
    Serial.print(input);
    Serial.print("   decimal = ");
    Serial.println(val);
  }
}

int StrToHex(char str[])
{
  return (int) strtol(str, 0, 16);
}

CrossRoads:
So after every command:
55 AA 88 FF FF FF FF 84

You get a reply with 55 AA 88 and then 5 more bytes.
Read those into an array as they come in, and parse for the data you want.

if (mySerial.available() > 7){

for (x = 0; x <8; x=x+1){
  incomingStream[x] = mySerial.read();
  }
}



and go from there.


distance = some manipulation of incomingStream[3] thru [7];



Add a check that bytes [ 0 ] thru [ 2 ] are == 55 AA 88 so you can tell you're in sync.

Ok, I think I wandered in the wrong direction so I've started trying out your example again, but it's returning all zeroes on the serial monitor, so there's something I need to tweak to get it to read the input properly.

I haven't messed with strings much but your code is making a little more sense in that I guess it groups the bytes together and assigns them a number of 0 through 8

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 32 // OLED display height, in pixels

#define OLED_RESET 4
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

byte singleshot[]={0x55,0xAA,0x88,0xFF,0xFF,0xFF,0xFF,0x84};

String incomingStream;
int x = 0;

void setup()
{
  // Open serial communications and wait for port to open:
  Serial.begin(115200);
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C); //or 0x3C
  display.clearDisplay(); //for Clearing the display
  display.display();
  display.setTextSize(2);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(0,0);
  display.println("READY");
  display.display();
  delay(2000);
}

void loop() // run over and over
{
      if(Serial.available() >7){
        for (x = 0; x <8; x=x+1){
        incomingStream[x] = Serial.read();
        Serial.print(incomingStream[x]);
      }
     }

  delay(1000);
}

Ah shoot instead of string I probably need to use

byte incomingStream[8];

instead, though with that I'm getting a quite long somewhat garbled output of all numbers on serial instead of the actual hex byte.

edit: with this change I now get "30" as a response. Doesn't make sense converting the second bytes to their decimal equivalent but maybe I'm closer.

void loop() // run over and over
{
      if(Serial.available() >7){
        for (x = 0; x <8; x=x+1){
        incomingStream[8] = Serial.read();
        Serial.print(incomingStream[3]);
      }
     }

  delay(1000);
}

Ahh ok here we go, so with this

void loop() // run over and over
{
      if(Serial.available() >7){
        for (x = 0; x <8; x=x+1){
        incomingStream[8] = Serial.read();
        Serial.print(incomingStream[8], HEX);
      }
     }

  delay(1000);
}

I get an ASCII output of the input, but in HEX format, if I monitor the serial interface looking for ASCII output.

With this

void loop() // run over and over
{
      if(Serial.available() >7){
        for (x = 0; x <8; x=x+1){
        incomingStream[8] = Serial.read();
        Serial.print(incomingStream[8]);
      }
     }

  delay(1000);
}

it's spitting out the converted version of hex, but in ASCII, not in decimal which is why it didn't look right in the decimal tab.

The problem is that if I try to just print incomingStream[2] or any other of the 8 positions, I just get 0 in ascii or 30 in hex which doesn't add up. Hmm

I've been able to trim down the first half of the output by changing this line

for (x = 0; x <7; x=x+1){

if I swap out 7 for another number I can display the first half, or however many numbers of positions, so

for (x = 0; x <2; x=x+1){

will only read out 55AA however I can't figure out how to instead make it do the last half of the hex input, or chop out a specific positon. Hmm

Serial.print always writes ASCII equivalents of the underlying binary data, converted into decimal or hex format.
If you want to write the raw binary data instead, use Serial.write.

pcbbc:
Serial.print always writes ASCII equivalents of the underlying binary data, converted into decimal or hex format.
If you want to write the raw binary data instead, use Serial.write.

Ahh, interesting, I knew that sending my command with serial.print wasn't working, but it did with serial.write, I didn't know that it converted it when using print.

Good to know in future for something that is reporting back to a computer. At this point I'm just stuck on figuring out how to either grab specific parts of that incoming stream, or convert the whole thing so that I can parse it.

Unfortunately a lot of the examples I find for parsing rely on specific characters to indicate a separation between bits of data but there are no such things in the hex reply I'll be getting.

The raw HEX does contain spaces so maybe that will factor in somehow.

I feel like I'm close but just can't put my finger on the solution. Hmm.

edit: delimiter is the word i was looking for, I think.

edit 2:

Just so that it's on this page and maybe a little more clear, I'll be receiving hex like this:

55 AA 88 01 FF 1A 20 C1

I'll need the "01" to plug into an if statement, and "1A" and "20" to combine to "1A20" to convert to decimal.

Of course 1A and 20 will change often, and the fourth positon, 01 is going to be that or 00.

I just can't get that incoming stream code to pick out spot 4 only, or spots 6 and 7 together.

Oh yeah and the rangefinder module is one off aliexbaba, it was called a j52 rangefinder or something similar to that, though similar modules are used in cheap rangefinders for golf and measuring tapes, cheaper than the modules alone sometimes which is odd.

Ok, shoot so I had changed incomingStream[x] to incomingStream[8] at some point and that didn't help me out.

Now with the code like this

  if(Serial.available() >7){
        for (x = 0; x <8; x=x+1){
        incomingStream[x] = Serial.read();
        Serial.write(incomingStream[5]);
        
      }

I get an output of 00 00 00 00 00 00 00 C1

and if I change the number from 5 to 6 it instead spits out 20, although for some reason it's formatted as
00 00 00 00 00 00 20 20

Not quite sure why but think I'm a step closer now.

edit:

interesting, if I add this if statement in the whole output in serial reads as 01 but each of the 8 sections takes about three seconds to come in. The if statement is working though which is nice.

void loop() // run over and over
{
      if(Serial.available() >7){
        for (x = 0; x <8; x=x+1){
        incomingStream[x] = Serial.read();
        Serial.write(incomingStream[3]);
        if (incomingStream[3] = 01) {
          digitalWrite(13, HIGH);
          delay(2000);
        }
        
      }
     }

  delay(1000);
  digitalWrite(13, LOW);
}

So, interestingly even with a 200ms delay total it takes a good second and a half for serial output to complete and the light definitely stays on for more than 200ms. Strange.

void loop() // run over and over
{
      if(Serial.available() >7){
        for (x = 0; x <8; x=x+1){
        incomingStream[x] = Serial.read();
        Serial.write(incomingStream[3]);
        if (incomingStream[3] == 01) {
          digitalWrite(13, HIGH);
          delay(200);
        }
       
      }
     }

  digitalWrite(13, LOW);
}