5

I have an Arduino that I've put between a computer and an RS485 device. The job of the Arduino now is just to transmit data but will eventually do data logging and have a small user interface as time goes by.

So far, this serial read code has worked for me to communicate to the Arduino from the computer:

 void serialEvent() 
 {
  while(Serial.available())
  {
    // get new byte
    char inChar = (char)Serial.read();
    if (inChar == '\n') 
    {
      stringComplete = true;
    }
    else
    {
      inputstring += inChar;
    }
  }
 }

The downside here is that I cannot send the '\n' char to my RS485 unit. Is there a way I can refine the code so I can send an arbitrary string of chars while still having a termination [thing] to turn on the stringComplete flag?

EDIT To clarify this the process by how my message string is being created:

Input: U16 Address, U16 Data, U8 Function Code
U16 Address -> U8 Address Split High, U8 Address Split Low
U16 Data -> U8 Data Split High, U8 Data Split Low

U8 Array of [U8 Address Split High, U8 Address Split Low, U8 Data Split High, U8 Data Split Low, U8 Function Code]

U8 Array -> Message String

Output: Write Message String
  • Is it just strings of ASCII characters (codes 32 to 127 + \n) that you want to send? – Majenko May 5 '17 at 14:08
  • No, I'm sending n number of u8 ints (words?) that are represented as \code characters put together to form a string. – ATE-ENGE May 5 '17 at 15:36
  • But the actual string content that is sent over the wire only consists of printable characters? You're sending such things as \024\075\216\030\777\000\123 etc? – Majenko May 5 '17 at 15:46
  • Or are you sending the actual 8 bit values that you have put into the string using '\whatever`? – Majenko May 5 '17 at 15:51
  • Right now, I'm sending and receiving the actual 8bit values the entire process is as follows: Computer Input: U16 Address, U16 Data, U8 Function Code U16 Address -> U8 Address Split High, U8 Address Split Low U16 Data -> U8 Data Split High, U8 Data Split Low U8 Array of [U8 Address Split High, U8 Address Split Low, U8 Data Split High, U8 Data Split Low, U8 Function Code] U8 Array -> Message String Output: Message String – ATE-ENGE May 5 '17 at 17:15
4

Since you are using all 8 bits of the serial data for your data there is nothing "in band" that you can use for a delimiter.

Instead you will have to think outside the box somewhat and create some form of "out of band" data that can signal the end of a packte.

One option (probably the simplest) would be to include the concept of time into your protocol. If you go more than X milliseconds (X is to be determined by you) without receiving a byte then you are at the end of your packet. This has the disadvantage that it slows down your maximum packet rate, since each packet has to have a suitable delay between them.

Another option may be to use a serial break character between packets. This is a special event where the UART output is held low for at least 10 symbol lengths, which results in an framing error (the STOP bit is wrong) and a flag being set. It would mean though that you have to implement all the UART code yourself since the Arduino's UART code doesn't support breaks.

A third option, which also would require you to write your own UART code, or alter the Arduino UART code, would be to operate the UART in 9-bit mode. You then have 0-511 instead of 0-255, so you can send your 8-bit data as per normal (with the 9th bit set to 0) and any control and protocol characters with the 9th bit set, so between 256 and 511.

Finally, you could halve your overall transmission speed by sending the data as ASCII-encoded HEX digits. That would be two characters (0-9,A-F) for each byte sent, leaving all the other characters (including \n) available for you to use as you wish.

2

Normally strings end with a '/0' item ... than /n is part of the string and can be handled as normally.

So you have to change the check to

if (inchar == '\0')

Also consider not adding a character every time to the string, since it will cause the string to be replaced/copied every time, which is not good for both performance and memory gaps resulting.

Instead make a predefined buffer if possible (if you know the maximum string length, don't forget to add +1 for the ending '0' character). In that case you can add the '\0' yourself or even better:

char inputString[101];
uint8_t inputStringLength = 0;

while(Serial.available())
{
    // get new byte
    char inChar = (char) Serial.read();
    inputString[inputStringLength++] = inChar;

    stringComplete = (inChar == '\0')
}
1

Serial.avilable() returns the number of bytes available in the buffer. One solution could be to try reading that many bytes at a time. This assumes that the buffer contains only entire strings.

Note: If your RS485 device sends multiple, non-delimited strings between buffer reads then this may not work as desired.

void serialEvent() 
{
  int bytes = Serial.available();

  if ( bytes == 0 ) // empty buffer, bail
    return;

  for (; bytes > 0; bytes-- )
  {
    // get new byte
    char inChar = (char)Serial.read();
    inputstring += inChar;  
  }
  stringComplete = true;
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.