1

I have this code written and functioning that will write out the chars in cmd to a serial port for an input of ASCII text representing byte values.

void SendCTRL (String &input) 
{
  //Adjust Data
  const char *hin = input.c_str();    // Get character array
  int clen = input.length()/2;
  unsigned char cmd[clen+1]; // Leave a byte for null terminator
  for (int i=0; i < 2*clen; i+=2)
  {
    cmd[i/2] = dehex(hin[i])<<4 | dehex(hin[i+1]);
  }

  //Send Data
  cmd[clen] = 0;                     // Null-byte terminator
  digitalWrite(SSerialTxControl, RS485Transmit);  // Enable RS485 Transmit   
  for (int i=0; i< clen; i++)
  {
    RS485Serial.write(cmd[i]);   // Send string someplace
  }
  digitalWrite(SSerialTxControl, RS485Receive);  // Disable RS485 Transmit    
}

As the majority of the byte values fed are constant, I'm trying to create similar output for the following code when I feed the function below only the byte values that change frequently:

void Create_Message(int Address, int Data)
{
  //Adjust Data
  Address--;
  byte SvAdd = 1;
  byte FuCode = 6;
  byte AddHi = Address>>8;
  byte AddLo = Address;
  byte DatHi = Data>>8;
  byte DatLo = Data;
  byte AdDa[] = {SvAdd,FuCode,AddHi,AddLo,DatHi,DatLo};
  unsigned int crc=CRC(AdDa,sizeof(AdDa)/sizeof(AdDa[0]));
  byte CrcHi = crc & 0xFF;
  byte CrcLo = crc >> 8;
  /*U8 Slave Address, U8, Function Code, U16 Address, U16 Data, U16 CRC
  * to
  *[U8 Address Split High, U8 Address Split Low, U8 Data Split High, U8 Data Split Low, U8 Function Code]
  */


  //Send Data
  unsigned char cmd[9]={SvAdd,FuCode,AddHi,AddLo,DatHi,DatLo,CrcHi,CrcLo};
  cmd[8]=0; //Null-byte terminator
  digitalWrite(SSerialTxControl, RS485Transmit);  // Enable RS485 Transmit
  lcd.setCursor(0, 1);   
  for (int i=0; i< sizeof(cmd)/sizeof(cmd[0]); i++)
  {
    RS485Serial.write(cmd[i]);   // Send string someplace
  }
  digitalWrite(SSerialTxControl, RS485Receive);  // Disable RS485 Transmit    
}

I'm reading the Values written by RS485.write() and, in both cases, the data is good. However, for the 2nd section of code, the Arduino seems to write out the null-byte while it does not write the byte out in the 1st block. If I remove the allocation for the null-byte in the second code, it does not get a response from my device.

I'm guessing that the issue is that I am not setting my null-byte terminator correctly or otherwise missing something (I'm pretty new here XD )

Update: it seems like using sizeof(cmd)/sizeof(cmd[0]) to determine the send length interfered with data transmission when I set this to a constant the code works just fine.

1

In the second code example, the value of sizeof(cmd)/sizeof(cmd[0]) is 9, due to the declaration unsigned char cmd[9] ...

Thus, the for loop will write out 9 bytes, with indices 0, 1, ... 8. Due to cmd[8]=0; earlier in the code, the last byte will be zero. To prevent that, one might instead use the expression sizeof(cmd)/sizeof(cmd[0])-1 in the for loop:

for (int i=0; i< sizeof(cmd)/sizeof(cmd[0])-1; i++)
   RS485Serial.write(cmd[i]);

Note, this doesn't explain why it should be so that “If I remove the allocation for the null-byte in the second code, it does not get a response from my device”, although practically anything can happen if you say cmd[8]=0; after allocating only 8 bytes of storage.

  • I was under the impression that cmd[9]={SvAdd,FuCode,AddHi,AddLo,DatHi,DatLo,CrcHi,CrcLo} would make the cmd array equal to {SvAdd,FuCode,AddHi,AddLo,DatHi,DatLo,CrcHi,CrcLo,[unallocated]} so that when I said cmd[8]=0; Cmd would be {SvAdd,FuCode,AddHi,AddLo,DatHi,DatLo,CrcHi,CrcLo,0} Is that not the case? – ATE-ENGE May 17 '17 at 18:44
  • To clarify, I also removed the cmd[8]=0 line as well (sorry for the confusion) – ATE-ENGE May 17 '17 at 18:50
  • Perhaps you meant [uninitializ​ed] where you wrote [unallocat‌​ed]. But no matter, both are wrong. cmd[9]={SvAdd,FuCode,AddHi,AddLo,DatHi,DatLo,CrcHi,CrcLo} initializes cmd to {SvAdd,FuCode,AddHi,AddLo,DatHi,DatLo,CrcHi,CrcLo,0} because it uses the default initializer for unspecified elements, and the default initializer is 0. See eg an answer to Is there a better way to initialize an array? and also see C++ array initialization, – James Waldby - jwpat7 May 17 '17 at 20:56
0

In addition to James's answer, to print (or send) a null terminated string you do not have to know the length of the string. Just print the characters till you find the null. So this code works better.

for (int i=0; cmd[i] != 0; i++)
{
    RS485Serial.write(cmd[i]);   // Send string someplace
}

//or

int i=0;
while(cmd[i] != 0)
{
    RS485Serial.write(cmd[i++]);   // Send string someplace
}
  • Ok, I'll do that – ATE-ENGE May 17 '17 at 18:39
  • @ATE-ENGE you should have not edited your question. New readers are going to get confused :) – Macit May 17 '17 at 18:43
  • Ok, I'll undo that XD – ATE-ENGE May 17 '17 at 18:46

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.