The following sketch (extracted from a much larger project) illustrates a problem I've run into. Perhaps someone here more versed in C/C++ can explain what's happening. NOTE: compiled with Arduino 1.0.3 and run on a Nano 3.0 clone.
void setup (){
Serial.begin (115200);
}
void loop (){
SEND_JOYSTICK_MESSAGE ();
Serial.println ("");
delay (1000);
}
void SEND_JOYSTICK_MESSAGE (){
byte Category = B01; // Roboteq SetCommand
byte Name = 0; // _G, but will contain data for both channels
byte Target = B001; // Roboteq target ID
byte ID[4];
byte * IDaddress;
IDaddress = CREATE_ID (Category, Name, Target);
ID[0] = *IDaddress;
ID[1] = *(IDaddress+1);
ID[2] = *(IDaddress+2);
ID[3] = *(IDaddress+3);
Serial.println ("returned ID bytes:");
Serial.print (ID[0]); // should be 64
Serial.print (" ");
Serial.print (ID[1]); // should be 32
Serial.print (" ");
Serial.print (ID[2]); // should be 0
Serial.print (" ");
Serial.println (ID[3]); // should be 0
}
byte * CREATE_ID (byte Category, byte Name, byte Target) {
unsigned int ID;
Serial.print ("Category = ");
Serial.print (Category);
Serial.print (" Name = ");
Serial.print (Name);
Serial.print (" Target = ");
Serial.println (Target);
ID = (uint16_t) ((Category << 6 | Name ) << 3 | Target) << 5;
Serial.print ("ID as uint16_t = ");
Serial.println (ID);
byte IDbytes[4];
byte * IDaddress;
IDbytes[0] = (ID>>8); // 64
IDbytes[1] = ID; // 32
IDbytes[2] = 0x00;
IDbytes[3] = 0x00;
IDaddress = IDbytes;
delay (1);
return IDaddress;
}
This functions exactly as it should. All of the calculation takes place in the CREATE_ID function. Three bytes (that happen to have the values 1, 0 and 1) are combined to make a uint16_t (in this case 16416 decimal) the upper 11 bits of which are a standard CAN identifier. That 16 bit number is then divided into 2 bytes (having the values of 64 and 32) which become the first two bytes of a 4-byte array. The remaining two bytes are set to 0. CREATE_ID then returns a pointer to that array, and the calling procedure just Serial.prints the results. Here's a sample of the output.
Category = 1 Name = 0 Target = 1
ID as uint16_t = 16416
returned ID bytes:
64 32 0 0
Category = 1 Name = 0 Target = 1
ID as uint16_t = 16416
returned ID bytes:
64 32 0 0
Category = 1 Name = 0 Target = 1
ID as uint16_t = 16416
returned ID bytes:
64 32 0 0
Category = 1 Name = 0 Target = 1
ID as uint16_t = 16416
returned ID bytes:
64 32 0 0
That's all OK, so what's the problem? The problem arises if the next to the last linedelay (1);
is commented out. The output is then like this:
Category = 1 Name = 0 Target = 1
ID as uint16_t = 16416
returned ID bytes:
0 107 0 106
Category = 1 Name = 0 Target = 1
ID as uint16_t = 16416
returned ID bytes:
0 107 0 106
Category = 1 Name = 0 Target = 1
ID as uint16_t = 16416
returned ID bytes:
0 107 0 106
Category = 1 Name = 0 Target = 1
ID as uint16_t = 16416
returned ID bytes:
0 107 0 106
Why is that delay needed before returning the pointer?
Indeed, in the longer program from which I took this snippet, no delay gave consistent garbage results, delay(1) gave the correct results most of the time, but gave nonsense perhaps 1 time in 20, while delay(2) makes things behave as they should.
Can someone enlighten me?
Ciao,
Lenny