sprintf() mystery....

Hello guys,

Been coding for a while now. I would like to say that i'm becoming better at it. But one thing is keeping me awake for a while now.... I just can't find out what is wrong...

The sprintf() function is not working the way I want. I want to make one string, that is received over a CAN network to print as one long string. But the placement in the string is not correct.

My code snippet:

void loop(){

  if(!digitalRead(CAN0_INT))                         // If CAN0_INT pin is low, read receive buffer
  {
    CAN0.readMsgBuf(&rxId, &lenrx, rxBuf);      // Read data: len = data length, buf = data byte(s)

    if(rxId != 1088 and  rxId != 1352 and rxId != 1344 and rxId != 1348){       //ignore CAN messages
        for(byte i=lenrx; i<8; i++){
          rxBuf[i]=0;
        }
        sprintf(ReceString, "%.3X %.2X%.2X%.2X%.2X%.2X%.2X%.2X%.2XX", rxId,rxBuf[0],rxBuf[1],rxBuf[2],rxBuf[3],rxBuf[4],rxBuf[5],rxBuf[6],rxBuf[7]);
        ReceString[3]=lenrx+'0';
        Serial.println(ReceString);
        Serial.println(rxBuf[0]);
    }
  }
}

The output of this code is:
103100A8000000000000X
168

I expect it to be:
1031A800000000000000X
168

That's because the A8 (dec 168) is at the first %.2X in the sprintf() function. But somehow it always end up were rxBuf[1] acutally is. I just don't know why... Probably a user error of me, but I just don't see it... Tried everything.

Anyone an idea? I hope i'm clear...

Regards, Rico

little update:
Shortening to:

sprintf(ReceString, "%.3X %.2XX", rxId,rxBuf[0]);

gives:
103100X
168

Can you make a small sketch for us that we can try ?

The code you showed does not tell if the variables are integers or bytes: http://snippets-r-us.com/.
The %X on a Arduino Uno is for a two-byte unsigned integer that will be showed in hexadecimal format as capitals. The sprintf will read two bytes for every %X.

test code (did the same)
I've added one more %.2X so all 8 (or 9 :stuck_out_tongue: ) bytes are shown.

unsigned char rxBuf[8]={0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x11, 0x22};
long unsigned int rxId = 0x103;
char ReceString[32];

void setup() {
  // put your setup code here, to run once:
Serial.begin(115200);
}

void loop() {
        sprintf(ReceString, "%.3X %.2X%.2X%.2X%.2X%.2X%.2X%.2X%.2X%.2XX", rxId,rxBuf[0],rxBuf[1],rxBuf[2],rxBuf[3],rxBuf[4],rxBuf[5],rxBuf[6],rxBuf[7]);
        ReceString[3]=7+'0';
        Serial.println(ReceString);
        Serial.println(rxBuf[0]);
        delay(1000);
  
}

%.2X is the wrong way to specify the number of digits. It should be %2X and if you want the leading zero for numbers less than 0x10, then the format should be %02X.

Pete

You should study how the sprinft works, and perhaps start with a few simple examples.

When you use a 4-byte parameter, you have to specify in the format string that a 4-byte parameter is used. For example with "%03lX". The 'X' is for a 2-byte parameter, the extra 'l' makes it 4-byte.

When you specify in the format that a 2-byte parameter is used, you have to give the sprintf a 2-byte parameter, not a single byte parameter.

This works:

unsigned char rxBuf[8]= { 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x11, 0x22 };
unsigned long rxId = 0x103;
char ReceString[32];

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

void loop() 
{
  sprintf(ReceString, "%03lX %02X%02X%02X%02X%02X%02X%02X%02XX", 
    rxId,
    (unsigned int) rxBuf[0],
    (unsigned int) rxBuf[1],
    (unsigned int) rxBuf[2],
    (unsigned int) rxBuf[3],
    (unsigned int) rxBuf[4],
    (unsigned int) rxBuf[5],
    (unsigned int) rxBuf[6],
    (unsigned int) rxBuf[7]);
  ReceString[3]=7+'0';
  Serial.println(ReceString);
  Serial.println(rxBuf[0]);
  delay(1000); 
}

You could add the '7' at position 3 in the format string. There is no need to do that afterwards.

Tinkercad:

Thank you both. Works like a charm!

I did not modify the %.2X because it was in an example code. So I thought that it would be ok. Funny thing is I this half a year ago at school. So that makes it extra awkward..

I think that %.2X does the same as %02X, they are both the minimal size with added zeros. However, everyone uses %02X and no one uses %.2X for an integer.