Go Down

Topic: Serial.print(n, BIN) displaying all bits ? (Read 2148 times) previous topic - next topic

andyhunti

Is there a way to print all bits in a value not just those from the first 1?

eg. Serial.print(B00001111, BIN); gives 1111

but it'd be helpful to show those leading zeros sometimes.

I've written a function to do it but I was wondering if there was a lower level way to do it.


Code: [Select]

char* b2s(byte myByte){
 char Str[8];
 byte mask = B10000000;
 for(int i = 0; i<8; i++){
   Str[i]='0';
   if(((mask >> i) & myByte) == (mask>>i)){
     Str[i]='1';
   }
 }
 // terminate the string with the null character
 Str[8] = '\0';
 return Str;
}


Cheers,

Andy

mem

#1
Feb 26, 2009, 10:57 am Last Edit: Feb 26, 2009, 12:46 pm by mem Reason: 1
Perhaps something like this:

void printBits(byte myByte){
 for(byte mask = 0x80; mask; mask >>= 1){
   if(mask  & myByte)
       Serial.print('1');
   else
       Serial.print('0');
 }
}

edit: added angle bracket missing from the for loop

andyhunti

Cheers,
So there's no core support eg. Serial.println(n, BIN8) for instance

mem

#3
Feb 26, 2009, 12:56 pm Last Edit: Feb 26, 2009, 12:57 pm by mem Reason: 1
No, the second argument to Serial.print is the number base (BIN=2) and there is no way the current core code that prints number bases knows how many places to pad - the same routine is used for one, two or 4 byte values.

BTW, I updated the code I posted above

andyhunti

Thanks for confirmation and the tidy function.

halley

#5
Feb 26, 2009, 03:31 pm Last Edit: Feb 26, 2009, 03:35 pm by halley Reason: 1
Code: [Select]
char* b2s(byte myByte) {
 char Str[8];
  :
 return Str;
}


The technique above is dangerous, as the storage for that Str array is on the stack.  The function returns, and the stack no longer "owns" that memory.  The memory is still there, and not modified yet, so sometimes the code that calls this function will work.  But calling another function after this one will damage the stack contents (setting up for different variables in the same memory).

Code: [Select]
char* b2s(byte myByte) {
 [glow]static [/glow]char Str[8];
  :
 return Str;
}


Some will say this is an improvement.  This adjustment will cause a part of memory to be dedicated to the array at all times, not just when the function is running.  So you can call the function, and trust the results are still there and safe when the function returns.

However, there is only one such array.  The next time you call the same function, the memory gets rewritten with the new values.  So your calling code needs to be aware of this, and make sure not to call the routine twice in a row without grabbing what it wanted from the results of the first call.  That's fine for your own code that you don't expect to share as a library, but I wouldn't recommend this approach for general-purpose library code.

Code: [Select]
char* b2s(byte myByte[glow], byte Str[], int length[/glow]) {
   :
 return Str;
}


This approach puts the caller in charge of array memory.  They can arrange for stack or permanent allocation, and can pass different array addresses if they want to collect multiple values without interference.  Since it's the caller's own memory space, the function doesn't even have to return the address at all, but it's still a kind of convenience thing to do.  This is the recommended technique if you want your routine to be the safest, most general-purpose, sharable routine.  

mem

Halley, excellent advice as usual. But you left something out - the best way to prevent abusing arrays  is not to use them when they are not needed. Hence the code posted in reply #1

andyhunti

Yep, thanks for the advice and going into that amount of detail. Explaining why is very helpful. Cheers.

halley

mem, exactly-- O(1) space is better than O(n), and safer to manage too.

Go Up