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.
2 Answers 2
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 saidcmd[8]=0;
Cmd would be{SvAdd,FuCode,AddHi,AddLo,DatHi,DatLo,CrcHi,CrcLo,0}
Is that not the case?ATE-ENGE– ATE-ENGE2017年05月17日 18:44:24 +00:00Commented May 17, 2017 at 18:44 -
To clarify, I also removed the
cmd[8]=0
line as well (sorry for the confusion)ATE-ENGE– ATE-ENGE2017年05月17日 18:50:22 +00:00Commented May 17, 2017 at 18:50 -
Perhaps you meant
[uninitialized]
where you wrote[unallocated]
. But no matter, both are wrong.cmd[9]={SvAdd,FuCode,AddHi,AddLo,DatHi,DatLo,CrcHi,CrcLo}
initializescmd
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– James Waldby - jwpat72017年05月17日 20:56:58 +00:00Commented May 17, 2017 at 20:56
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
}
Explore related questions
See similar questions with these tags.