Reading 5 Serial port hex values and sending the hex read values to Serial1.

Hello,

I am pretty new to the Arduino Mega 2560 R3, but I figured why not try it out.

Here is what I am trying to write a program to do:

  1. I am wanting to read the 5 hex values from Serial1 (example 0c, ff, 1a, 0f, 3b) and send them back out Serial2 port as hex. I have some code that i found on the web that does the conversion from HEX to ASCII, but I am not sure how to get the code to read Serial1 and use the RX string. Then to output TX the converted ASCII back out Serial2 continuously with two hex bytes added?

[I have searched and noticed that ASCII output (from ASCII Tables) on the Arduino sends out the corresponding byte HEX values.]

Here is the code I have found so far:

byte WaitAndRead()
{
    while (Serial1.available() == 0) {
        // do nothing
    }
    return (byte) Serial.read();
}

int SerialReadHexDigit()
{
    byte c = WaitAndRead();
    if (c >= '0' && c <= '9') {
        return c - '0';
    } else if (c >= 'a' && c <= 'f') {
        return c - 'a' + 10;
    } else if (c >= 'A' && c <= 'F') {
        return c - 'A' + 10;
    } else {
        return -1;   // getting here is bad: it means the character was invalid
    }
}

int SerialReadHexByte()
{
    byte a = SerialReadHexDigit();
    byte b = SerialReadHexDigit();
    if (a<0 || b<0) {
        return -1;  // an invalid hex character was encountered
    } else {
        return (a*16) + b;
    }
}

void setup()

{
   Serial.begin(9600);  //for programminig Arduino
   Serial1.begin(9600); //for reading serial hex bytes
   Serial2.begin(9600); //for writing the ASCII/HEX Byte received on Serial1
}

void loop()
{
   if(Serial1.available());
   {
     Serial2.write(0xff); //first constant HEX output for each Serial1 HEX string, HEADER
     Serial2.write(0x2a); //second constant HEX output on each Serial1 string , HEADER
     
     // **Want Serial1 hex string to output on Serial2, not sure what to put here**
   }
}

Any guidance and help would be greatly appreciated. :slight_smile:

I know I need void setup() and void loop(), I just cannot figure out how to implement the above code into a program using the Serial1 port to read (RX) and the Serial2 port to write (TX)?

I have some code that i found on the web that does the conversion from HEX to ASCII,

Hex in; hex out. Why would you convert to some other representation in between? Especially since you'd have to undo that conversion to send the output.

Then to output TX the converted ASCII back out Serial2 continuously with two hex bytes added?

What two bytes?

If all you want to do is send data out Serial2 that comes in Serial1:

void loop()
{
   while(Serial1.available() > 0)
   {
      Serial2.write(Serial1.read());
   }
}

No need to wait for anything to become available. No need to convert the data from one format to another.

If that is not the case, please explain what is sending the data, in what format, and what you need to send the data to, in what format.

Thanks for the reply.

Yes that works for 1 hex byte(0c), but I really need to store all five ( 0c, ff, 1a, 0f, 3b ) Serial1 HEX bytes in a string or array. That way I can write all five of my hex bytes at once.

As far as the first two hex bytes I am sending (Theses bytes are always sent before each Serial2 output string/array).

EXAMPLE: So I need to output Serial2: ff 2a 0c ff 1a 0f 3b , [ ff 2a ] are constant on every message sent with [ 0c ff 1a 0f 3b ] coming from Serial1 input stream.

I hope that makes sense. I probably would also need to make sure I have 5 hex bytes or do not send any messages out Serial2.

hurley:
I probably would also need to make sure I have 5 hex bytes or do not send any messages out Serial2.

So only read the data when there are least 5 bytes in the Serial buffer:

if (Serial1.available() >= 5)
{
  for (int i=0; i<5; i++)
  {
    // read the bytes in and do something with them
  }
}

A little hint to help you. You don't need to do the conversion yourself from the hex value to the ASCII hex representation. Serial.print() will do this for you by adding an additional argument. To expand PaulS's example with this feature and to do 5 (and only five because we are hardcoding it for this example) hex values I get:

void loop()
{
  byte byteCounter = 0;  // 255 possible counts
  while(byteCounter < 5)
  {
    while(Serial1.available() > 0)
    {
      Serial2.print(Serial1.read(),HEX);  // Note use of Serial.print instead of Serial.write
      byteCounter++;
    }
  }
}

We have to use the while counter here instead of a for loop because it may loop multiple times if Serial1.available() is zero.

Also note that because this method sends out two bytes for every one read, there exists the possibility of Serial1's input buffer overrunning if Serial2's baud rate isn't at least double Serial1's baud rate.

Arch: thanks that works for making sure there are 5 bytes in Serial1 buffer, but still only allows one hex byte sent.

I really need to send a string or array of some sort in this hex format on Serial2 after entering this data on Serial1 RX .
(Example: 2 digit hex byte, 2 digit hex byte, 2 digit hex byte, 2 digit hex byte, 2 digit hex byte).

Sembazuru: that gave me 2 ascii numbers for each digit entered. For example I entered 01 [for 0x01], it returned 30 31.

I need a hex byte 01 in one 8-bit byte or to look at it this way (00000001 in binary = 01 HEX).

Err, going back up to your original example and using ideas already discussed, try this:

void setup()
{
  // Serial.begin(9600);  //for programminig Arduino, not necessary to initialize it if we aren't using it within our code.
  Serial1.begin(9600); //for reading serial hex bytes
  // Because ASCII representation of HEX is twice as large as the byte value, double the output baud rate to avoid buffer overruns
  Serial2.begin(19200); //for writing the ASCII/HEX Byte received on Serial1
}

void loop()
{
  if(Serial1.available());  // Once something shows up on Serial1, output on Serial2 with the special formatting. Hopefully the something on Serial1 is what we want to be working on
  {
    Serial2.print(0xff,HEX); //first constant HEX output for each Serial1 HEX string, HEADER
    Serial2.print(0x2a,HEX); //second constant HEX output on each Serial1 string , HEADER

    // **try this
    for (int i = 0; i<5; i++)
    {
      while (Serial1.available() == 0)
      {
        // do nothing
      }
      Serial2.print(Serial1.read(),HEX);
    }
  }
}

A limitation of the above is you aren't saving the data anywhere to do anything with it (like possibly output to serial 0 for troublshooting). You would need a buffer to hold the value. I'd probably use a byte array to hold the hex values and define it thusly:

// I think this will work to create a 7 element array and assign the header to the first two array elements...
// No Arduino here to test, but it does compile without complaining.
byte sensorData[7] = { 0xff, 0x2a };

void setup()
{
  // Serial.begin(9600);  //for programminig Arduino, not necessary to initialize it if we aren't using it within our code.
  Serial1.begin(9600); //for reading serial hex bytes
  // Because ASCII representation of HEX is twice as large as the byte value, double the output baud rate to avoid buffer overruns
  Serial2.begin(19200); //for writing the ASCII/HEX Byte received on Serial1
}

void loop()
{
  if(Serial1.available());  // Once something shows up on Serial1, output on Serial2 with the special formatting. Hopefully the something on Serial1 is what we want to be working on
  {
    for (int i=2; i<7; i++)  // array locations 0 and 1 are the header, so the 5 bytes of data go into 2 through 6, inclusive
    {
      while (Serial1.available() == 0)  // this will pause your sketch until another byte is available in Serial1's input buffer
      {
        // do nothing
      }
      sensorData[i] = Serial1.read();
    }
  }
  for (int i=0; i<7; i++)
  {
    Serial2.print(sensorData[i],HEX);
  }
}

Hope you can see the progression of ideas here.

hurley:
Arch: thanks that works for making sure there are 5 bytes in Serial1 buffer, but still only allows one hex byte sent.

I really need to send a string or array of some sort in this hex format on Serial2 after entering this data on Serial1 RX .
(Example: 2 digit hex byte, 2 digit hex byte, 2 digit hex byte, 2 digit hex byte, 2 digit hex byte).

Sembazuru: that gave me 2 ascii numbers for each digit entered. For example I entered 01 [for 0x01], it returned 30 31.

I need a hex byte 01 in one 8-bit byte or to look at it this way (00000001 in binary = 01 HEX).

Ok, your terminology is confusing me. Let me try to restate your question with my terminology to see if we can arrive on the same page.

I will use the following terminology:
byte == in all usages it refers only to 8 bits of binary data.
hex value == a byte of information that is being thought of conceptually as hexadecimal.
ASCII hex representation == two bytes of data referring to the ASCII codes for the characters of a written out hex value.

Originally I was thinking you were receiving a hex value on Serial1 and wanting to output the ASCII hex representation on Serial2. Now I'm thinking that I was backwards and you want to receive an ASCII hex representation of a value on Serial1 and then output the hex values on Serial2. Am I now correct in what you are asking for? If so, I suggest that when giving examples of hex values use hex notation (e.g. 0x2c or 0x2C, I'm not going to carp on capitalization, but c++ might...) and when giving examples of ASCII hex representation enclose the value in quotation marks (e.g. "2c" or "2c").

Let me try to explain it better.

I see on Realterm that I have 5 HEX bytes coming into Serial1 RX from my controller's UART : (0x01,0xff,0x1a,0x2c,0x0f).

I want to output 7 HEX bytes on Serial2 TX to another controller's UART : (0xff, 0x2a,0x01,0xff,0x1a,0x2c,0x0f) <---- // Added 0xff and 0x2a on the front.

Sorry for the confusion. I will try to do better on explanations.

hurley:
Let me try to explain it better.

I see on Realterm that I have 5 HEX bytes coming into Serial1 RX from my controller's UART : (0x01,0xff,0x1a,0x2c,0x0f).

I want to output 7 HEX bytes on Serial2 TX to another controller's UART : (0xff, 0x2a,0x01,0xff,0x1a,0x2c,0x0f) <---- // Added 0xff and 0x2a on the front.

Sorry for the confusion. I will try to do better on explanations.

Ok. Now I think I understand. If you take my latest example and change all the Serial2.print(<something>,HEX); lines to Serial2.write(<something>); you should be approaching what you want (I hope).

Say you receive the 5 bytes:

0x01,0xff,0x1a,0x2c,0x0f

Are you trying to send those 5 bytes out in the same way, or are you trying to send out the ASCII coded version of it, which would result in 10 bytes being sent? Example:

'0', '1', 'f', 'f', '1', '1', '2', 'c', 0', 'f'

Arrch,

Trying to send out Serial2 exactly what comes in Serial1 (0x01,0xff,0x1a,0x2c,0x0f).

Hex String in and Hex String OUT.

Sembazuru,

Let me try the change. I will get back to you in a few minutes after I try it.

hurley:
Arrch,

Trying to send out Serial2 exactly what comes in Serial1 (0x01,0xff,0x1a,0x2c,0x0f).

In that case...

Arch: thanks that works for making sure there are 5 bytes in Serial1 buffer, but still only allows one hex byte sent

Incorrect, the for loop ensures that 5 bytes are sent.

How do you know when each block of five bytes starts and ends within the byte stream coming in over the serial port? If you assume that every five bytes received constitutes a whole message then any error on the serial interface would leave the sender and receiver out of sync forever after.

PeterH:
How do you know when each block of five bytes starts and ends within the byte stream coming in over the serial port? If you assume that every five bytes received constitutes a whole message then any error on the serial interface would leave the sender and receiver out of sync forever after.

Yeah, I hadn't quite gotten to that step with him yet. (I did allude to it in one of the comments in one of of the example sketches...) I think he was starting to think about this too with his comment "I probably would also need to make sure I have 5 hex bytes or do not send any messages out Serial2." back on reply #2.

Handshaking and data integrity is step two after just getting the 5 in 7 out that he wants... A timeout might work if he doesn't expect to get 5byte frames coming in too quickly. Even a timeout as short as a 10th of a second before giving up and presuming the data is incomplete on the current frame. Now if he is expecting the UART feeding the data to send a continuous stream of 5byte frames as fast as the serial port can handle, start and/or stop bytes will be needed for each frame. Again, this is getting ahead of ourselves. Lets crack this nut of formatting first.

Sembazuru,

0n sending Serial1 RX (0x01, 0x01,0x01,0x01,0x01,0x01,0x01), I get out on Serial2 port output in ASCII like this: 00 01 20 00 01 20 00 01 20 00 01 20 00 01 20 00 01 20 00 01 20
then it returns to 00 00 00 00 00 <------with no input. This was after changing the code to Serial2.write .

Arrch,

void loop()
{
   if (Serial1.available() >= 5)
   {
      for (int i=0; i<5; i++)
      { 
         Serial2.write(Serial1.read());
      }
   }
}

I manually sent through Realterm on Serial1 RX (HEX): 01 01 01 01 01

gives me on Serial2 output: 30 31 20 30 31 20 30 31 20 30 31 20 30 31 20

hurley:
Sembazuru,

0n sending Serial1 RX (0x01, 0x01,0x01,0x01,0x01,0x01,0x01), I get out on Serial2 port output in ASCII like this: 00 01 20 00 01 20 00 01 20 00 01 20 00 01 20 00 01 20 00 01 20
then it returns to 00 00 00 00 00 <------with no input. This was after changing the code to Serial2.write .

Arrch,

void loop()

{
  if (Serial1.available() >= 5)
  {
     for (int i=0; i<5; i++)
     {
        Serial2.write(Serial1.read());
     }
  }
}




I manually sent through Realterm on Serial1 RX (HEX): 01 01 01 01 01

gives me on Serial2 output: 30 31 20 30 31 20 30 31 20 30 31 20 30 31 20

The problem is you're not sending

0x01 0x01 0x01 0x01 0x01

You're sending

'0', '1', ' ', '0', '1', ' ', '0', '1', ' ', '0', '1', ' ', '0', '1', ' '

So I think what you actually need, is a way to convert ASCII encoded HEX into binary/hex/decimal. You could write an algorithm, or stuff everything in a string (null-terminated char array) and use a function like sscanf().

hurley:
Sembazuru,

0n sending Serial1 RX (0x01, 0x01,0x01,0x01,0x01,0x01,0x01), I get out on Serial2 port output in ASCII like this: 00 01 20 00 01 20 00 01 20 00 01 20 00 01 20 00 01 20 00 01 20
then it returns to 00 00 00 00 00 <------with no input. This was after changing the code to Serial2.write .

Did you also get rid if the ,HEX argument? It looks like it is still converting to ASCII hex representation (Arrch actually used a better term "ASCII coded"). If there is still a conversion going on, 0x20 is the hex value for ASCII space... Are spaces being sent between hex values?

Arrch,

void loop()

{
  if (Serial1.available() >= 5)
  {
     for (int i=0; i<5; i++)
     {
        Serial2.write(Serial1.read());
     }
  }
}




I manually sent through Realterm on Serial1 RX (HEX): 01 01 01 01 01

gives me on Serial2 output: 30 31 20 30 31 20 30 31 20 30

When you sent that on RealTerm, did you click on "Send Numbers" or "Send ASCII"? It looks like you clicked "Send ASCII". Also, what is the "Display As" setting in RealTerm (it looks like "Hex[space]"). 0x30 is the hex value ASCII '1', 0x31 is the hex value for ASCII '2', and (again) 0x20 is the hex value for ASCII space. Arrch's code doesn't (or shouldn't) do any conversions at all so what comes in is what goes out...

The reason why Arrch's code didn't finish is because it was waiting for the third frame of 5 characters to accumulate in the input buffer. (Count, and you see that the Serial2 output is a multiple of 5, and the total number of characters (from the first zero to the last one) of what you are saying is the input is 14 characters long.

Arrch and Sembazuru,

You both are exactly right. I was sending the 01 01 01 01 01 from the Arduino Serial Monitor.

Once I sent it from Realterm, walla " real hex values ". If i can just make sure I am only getting the 5 correct hex bytes all the time from my controllers UART , I will have this problem figured out.

By the way if it helps my real controller first hex byte is either (0x20) or (0x21) . The other 4 hex bytes always change.

if that would help in how to figure if the bytes are being sent correctly.

I have learned so much on this forum today. This is a great community forum!!!