Back to the trough (Google has failed me)

Stuck with a problem in your code? Seek help here.

Back to the trough (Google has failed me)

Postby TravisCucore » February 13th, 2015, 8:54 pm

I've asked a couple of programming questions in the past and always received intelligent (and very helpful) responses. This time I've hit a wall while attempting to use an if statement to evaluate the N bit of a given string of 16 bits. I'm using an attny85 to send this information to a max7219 led driver. So, I need to evaluate the i bit without changing what is stored in SerialBuffer. I'm completely open to reevaluating the way I've gone about this. I've put this togther based on limited knowlege of C and lots of google searching. What I have now looks like this...

Code: Select all
int SendPacket()
{
   for (unsigned int i = 15; i > 0; i--)
   {
      if (SerialBuffer &= 1<<i == 1)  //I hope you can gather what I'm trying to accomplish here.  I need to evaluate the value of the ith bit.
      {
         Serial_High
         Clock_High
      }
      else
      {
         Serial_Low
         Clock_High
      }
      Clock_Low
   }
   Latch_High
   Latch_Low
   return 0;
}

My mind is open and ready to accept that I am a complete novice.  Any advise you could offer would be great. 

Thanks,
Travis Cucore
TravisCucore
 
Posts: 46
Joined: May 14th, 2013, 1:02 am

Re: Back to the trough (Google has failed me)

Postby bandersnatch » February 14th, 2015, 2:20 am

Hi.
Your question is a bit like "how long is a piece of string"
The answer is "that depends on ..."

There are lots of different ways of doing bitwise checking and the cracks here will
no doubt have lots of clever answers, with each competing for the shortest code (!)
Possible approaches are:
- Use bit shifting
- Use normal integer arithmetic
- Use bitmasks

I do not want to start an argument as to whether bit shifting is faster than array lookups
but here is a simple example using a bitmask array:
(apologies to the C purists! I can also write this on a single line but this is not a "C Obfuscation" contest ;^)))
See www.ioccc.org if you wanna see some really sick C programming...

int main(int argc, char* argv[])
{
// Bitmask array
// Assumes that you only want to check the bottom 16 bits of an integer
// And YES, there are more compact ways of initializing this array. This is purely to make the idea more obvious
// Each array entry has only ONE bit set to "1"
// E.g. we create a "bitmask" array = 000000000000 0001, 000000000000 0010, 000000000000 0100, 000000000000 1000, etc...
int iArryMask[16] = {1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384, 32768};

int SerialBuffer = 0x01; // Test value, change this for testing

for (unsigned int i = 0; i <16; i++)
{
// Perform a bitwise AND. This will ONLY be true when the corresponding bit in SerialBuffer is set to "1"
if (SerialBuffer & iArryMask[i])
{
printf("Bit %i is set\n",i);
}
else
{
printf("Bit %i is NOT set\n",i);

}

}

return 0;
}

As already mentioned, this is only one method.
I will leave it up to the cracks to illustrate the other ways of doing this.
I hope this helps.
Just post questions if you are still confused
bandersnatch
 
Posts: 150
Joined: September 17th, 2014, 12:06 pm

Re: Back to the trough (Google has failed me)

Postby TravisCucore » February 14th, 2015, 4:46 am

Thanks for the reply. I think I may have been to vague. I'm not attempting to compare a value within an array. I'm attempting to evaluate a single bit of a 16 bit value. so if I need to know if the 5th bit of a 16 bit value is a 1 or a 0, I'm looking for 0000000000010000. My initilized variable looks like this

Code: Select all
unsigned int SerialBuffer [0] = 0x0


It's one dimensional with only one unsigned int value of 16 bits, so I need to know how to evaluate the Nth bit of SerialBuffer[0].

Thanks again :)
TravisCucore
 
Posts: 46
Joined: May 14th, 2013, 1:02 am

Re: Back to the trough (Google has failed me)

Postby bandersnatch » February 14th, 2015, 4:53 am

The array is only used for isolating each bit to be tested.

Each entry in the array is bitwise "AND"ed with the SerialBuffer variable
The result of this "AND" operation will only be TRUE (>0) when the corresponding
bit in SerialBuffer is set....

Try compiling the code and running a few tests with different values for
SerialBuffer

i.e.
int SerialBuffer = 0x01;
int SerialBuffer = 0xFF;
int SerialBuffer = 0x32;
etc.

You will see that the program identifies each bit that is set.
bandersnatch
 
Posts: 150
Joined: September 17th, 2014, 12:06 pm

Re: Back to the trough (Google has failed me)

Postby bandersnatch » February 14th, 2015, 5:03 am

You might like to brush up on your boolean arithmetic

A couple of quick examples

0x0000 & 0x0001 = 0000 (false)
0x0001 & 0x0001 = 0001 (true) bit 1 is set
0x0010 & 0x0001 = 0000 (false)
0x0011 & 0x0001 = 0000 (true) bit 1 is set

0x0000 & 0x0010 = 0000 (false)
0x0001 & 0x0010 = 0000 (false)
0x0010 & 0x0010 = 0010 (true) (> 0) bit 2 is set
0x0011 & 0x0010 = 0010 (true) (> 0) bit 2 is set

Get the idea? The bitmask array is used to isolate each bit of the word being tested
The "&" operation will only yield a value > 0 when the corresponding bit in the word being tested is also set to 1
bandersnatch
 
Posts: 150
Joined: September 17th, 2014, 12:06 pm

Re: Back to the trough (Google has failed me)

Postby bandersnatch » February 14th, 2015, 5:05 am

Ooops, I mistyped one line

bandersnatch wrote:0x0000 & 0x0001 = 0000 (false)
0x0001 & 0x0001 = 0001 (true) bit 1 is set
0x0010 & 0x0001 = 0000 (false)
0x0011 & 0x0001 = 0000 (true) bit 1 is set


Should read:
0x0001 & 0x0001 = 0001 (true) bit 1 is set
0x0010 & 0x0001 = 0000 (false)
0x0011 & 0x0001 = 0001 (true) bit 1 is set

DOH!!!
bandersnatch
 
Posts: 150
Joined: September 17th, 2014, 12:06 pm

Re: Back to the trough (Google has failed me)

Postby bandersnatch » February 14th, 2015, 5:20 am

Perhaps the following example will make things a bit clearer:

// This function returns TRUE if bit number "iBitToBeTested" (0-15) in "iValueToBeTested" is set
// and returns FALSE if not.
bool IsBitSet( int iValueToBeTested, int iBitToBeTested) {
int iArryMask[16] = {1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384, 32768};
if (iValueToBeTested & iArryMask[iBitToBeTested])
{
return true;
} else {
return false;
}

}

int main(int argc, char* argv[])
{

int SerialBuffer = 0x32; // Test value

for (unsigned int i = 0; i <16; i++)
{
if (IsBitSet(SerialBuffer, i) )
{
printf("Bit %i is set\n",i);

}
else
{
printf("Bit %i is NOT set\n",i);

}

}

return 0;
}
bandersnatch
 
Posts: 150
Joined: September 17th, 2014, 12:06 pm

Re: Back to the trough (Google has failed me)

Postby bandersnatch » February 14th, 2015, 6:22 am

Just for the purposes of illustration,
here is an example of the same function implemented using bitmasks and bit shifting:
(C cracks: YES, it can be shorter ;^))))

bool IsBitSet( int iValueToBeTested, int iBitToBeTested) {
int iArryMask[16] = {1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384, 32768};
if (iValueToBeTested & iArryMask[iBitToBeTested])
{
return true;
} else {
return false;
}

}
bool IsBitSetUsingBitShift( int iValueToBeTested, int iBitToBeTested) {

int iShiftedValue=iValueToBeTested;

// Shift right by the bitnumber to be tested if we are not testing bit0
if (iBitToBeTested>0) iShiftedValue = iValueToBeTested>>iBitToBeTested;

if (iShiftedValue & 0x1) //Now check the value of the bit we have shifted
{
return true;
} else {
return false;
}

}

int main(int argc, char* argv[])
{

int SerialBuffer = 0x32; // Test value

for (unsigned int i = 0; i <16; i++)
{
if (IsBitSet(SerialBuffer, i) ) printf("BitmaskTest: Bit %i is set\n",i); else printf("BitmaskTest: Bit %i is NOT set\n",i);
if (IsBitSetUsingBitShift(SerialBuffer, i) ) printf("Bitshiftest: Bit %i is set\n",i); else printf("Bitshiftest: Bit %i is NOT set\n",i);

printf("\n");
}

return 0;
}
bandersnatch
 
Posts: 150
Joined: September 17th, 2014, 12:06 pm

Re: Back to the trough (Google has failed me)

Postby TravisCucore » February 15th, 2015, 6:49 pm

Thank you so much for lending me your wisdom. I spent 3 days worth of free time searching the internet and using trial and error attempting to solve this problem. While my solution looks a bit different from what you have shown me here, it is derived from what you have shown me. It appears all I really needed was to understand bitmasks better. Here is what my code looks like now. If anyone sees room for improvement, my ears are always open.

Code: Select all

unsigned int SerialBuffer;
Unsigned int SerialMask;
int SendPacket()
{
   for (int i = 15; i >= 0; i--)
   {
      SerialMask |= (1<<i);
      if ((SerialMask & SerialBuffer) == SerialMask)
      {
         Serial_High
         Clock_High
      }
      else
      {
         Serial_Low
         Clock_High
      }
      Clock_Low
      SerialMask &= ~(1<<i);
   }
   Latch_High
   Latch_Low
   return 0;
}


Thanks again,
Travis Cucore
TravisCucore
 
Posts: 46
Joined: May 14th, 2013, 1:02 am

Re: Back to the trough: Footnote

Postby bandersnatch » February 16th, 2015, 5:54 pm

Yippee!!! Problem solved.... ;^)
Just a quick footnote with words of praise & a few final suggestions:

Praise 1: Congratulations on getting your code working! In the end, this is what really matters

Praise 2: I commend your commitment to solving the problem by yourself in your own way.
Despite being given "ready made" code, your final solution proves that you have made
a real effort to understand the problem. Your solution proves my comment in an earlier
mail that there are lots of different ways of solving this problem.
I have seen quite a lot of C code over the years and your solution is truly original, if somewhat unorthodox.

Programming style is always a hotly debated topic and I dont want to start a "good" or "bad" code argument
but since your ".... ears are always open..", here are a few general comments/suggestions.

These are naturally all only IMHO and not intended as statments of universal truth (!)

Static vs dynamic data
----------------------
Your code implements a 16 bit "shift register" for outputting the contents of a 16 bit word as
a clocked (synchronous) serial data stream.

When processing within loops it is alwaysa good idea to think about
the data that MUST change within the loop and the data
that is always the same and can be defined once outside the loop.

In this code you dynamically calculate the SerialMask each time the loop is
executed. This is not wrong, but if you think about it, the SerialMask variable only
has 16 possible values and these 16 values are always the same each time SendPacket() is called.

This is why one of my suggested solutions used a bitmask[] array of pre-defined SerialMask values.
All the SerialMask values are calculated once and then each appropriate pre-calculated value is
used within the loop.
This eliminates 2 lines of code and the repetition of unnecessary calculations.
This may seem trivial to you, and it makes very little difference in this application, but
understanding the basic principle of identifying static and dynamic data is an important
programming concept.
It also improves the readability of your code. A pre-defined table of constants is much easier
to read and understand. Especially for someone else or when you have to look at the code again
6 months later and have forgotten how the damn thing works (!).
Regardless of the application you should always try to identify static data and explicitly define
it.

The mysteries of C conditional testing
--------------------------------------
The code testing the bit of the serial buffer is a good example for delving into the deeper nature
of C expressions.
...
if ((SerialMask & SerialBuffer) == SerialMask)
...
The code works but the test "== SerialMask" is unnecessary.... But why?
An integer in C can be used a numeric value but can ALSO be used as a BOOLEAN value (TRUE or FALSE)
A value of 0 is FALSE and ANY non-zero value, e.g 1,2,4,8,99,32767 etc is always TRUE
The same is also true for an integer mathematical expression.
e.g. 0+1=TRUE, 1-1=False, 0 & 0 = FALSE, 0 & 1= FALSE , 1 & 1=TRUE

This means that you only need to test
if (SerialMask & SerialBuffer)
I.e. the "SerialMask" variable containing only ONE bit set
is "bitwise ANDed" with the SerialBuffer variable that we are checking.
The result of this "bitwise AND" will only be >0 when the single bit
in SerialMask and the same bit in SerialBuffer both have a value of 1
The numeric actual value is irrelevant, all that matters is the BOOLEAN
value of TRUE (>0) or FALSE (=0)
This may also seem trivial but treating the results of expressions and function
calls as boolean values for conditional testing is used very often in C and you
gotta understand how this works.

Thats all for now. C is fundamentally simple in principle (basically just a "souped up assembler")
but is also very unforgiving of mistakes and can sometimes be remarkably subtle & difficult to comprehend.
Good luck with your project....
bandersnatch
 
Posts: 150
Joined: September 17th, 2014, 12:06 pm

Next

Return to Help Me! Software

Who is online

Users browsing this forum: No registered users and 3 guests