NEW: Learning electronics? Ask your questions on the new Electronics Questions & Answers site hosted by CircuitLab.
Microcontroller Programming » confusing bitwise arithmetic example
December 01, 2012 by keith712 |
i picked up a copy of Joe Pardue. C programming for microcontrollers. to learn more about AVR-C. in chapter four Joe gives the following example: register TCCR0A has some value xxxxxxxx. TCCR0A's bits are: 0 cs00, 1 cs01, 2 cs02, 3 wgm01, 4 com0a0, 5 com0a1, 6 wgm00, 7 foc0a the problem is how to put the value x1xx1100 into register TCCR0A? Joe says to do the following: TCCR0A |= (1<<wgm00) | (1<<wgm01) | (4<<cs00) which Joe says sets TCCR0A to x1xx1100. but i think the above would give TCCR0A = x1xx11xx because xxxxxxxx (= some intermediate value of TCCR0A) | 00000100 (= 4<<cs00) = xxxxx1xx does the left shift function 4<<cs00 somehow set the values of cs02=1, cs01=0 and cs00=0? |
---|---|
December 01, 2012 by Noter |
The best thing to do is code it up and run a test to see who is correct, you or Joe. For what it's worth, my money is not on Joe this time. |
December 02, 2012 by Rick_S |
For what it's worth, most likely Joe is talking about initializing that register. By default at boot, all values in that register are zero. Thus Or'ing the way Joe did would give the desired result. However, Keith, you are correct that Joe's way does not guarantee the value of the remaining register values if they had been changed prior. A simple way to guarantee Joe's method would work would be to simply place the statement:
Before the OR statement. This would set all the bits zero first. Rick |
December 02, 2012 by keith712 |
thanks for the input Noter and Rick. i'm new to all this and don't have any self-confidence yet. i checked to see if Joe initialized TCCR0A = 0 but he didn't. to guarantee that TCCR0A is changed from xxxxxxxx to x1xx1100 without disturbing the foc0a com0a1 and com0a0 bits and maintaining the self-documentation of the code would look something like: TCCR0A |= (1<<wgm01) | (1<<wgm00); // set waveform generation bits to 11 = fast PWM mode TCCR0A &= ~(7<<cs00); // clear clock select bits cs02 cs01 cs00 to 000 = no clock source TCCR0A |= (4<<cs00); // set clock select bits to 100 = clkio/256 mode what do you all think? |
December 02, 2012 by Noter |
Yep, I think you've got it figured out. |
December 02, 2012 by Noter |
I like to use the _BV() macro because I think it makes the code a little easier to read. Instead of coding (1<<WGM01), use _BV(WGM01). Here's a sample -
|
December 02, 2012 by keith712 |
Noter, where can i find documentation on macros like _BV()? are macros in the standard C library or do you write your own and #include them in your programs? am i asking the right questions? |
December 02, 2012 by Noter |
_BV() is part of the standard AVR lib-c. Don't remember where I ran across the _BV() macro initially but it is in this document on lib-c - http://www.nongnu.org/avr-libc/user-manual/FAQ.html#faq_use_bv |
December 02, 2012 by sask55 |
If you prefer to always think of the location of a bit as a shift left from bit 0 then, Then in order to deal with the bit value in position x we should shift 1 (00000001) some amount x to the left. In this method I would always use (1 << x) to point to a specific bit location. For example if wgm00 is defined as 6 therefore (1<<wgm00) is (1<<6). Shifting 00000001 to the left 6 time will give 01000000. By always shifting the value 1 and using the predefined names cs00,cs01 etc. you can refer to a desired bit location without even knowing what that location is. When always shifting the value of 1 you are dealing with one bit at a time. You will be required to use a separate (1<<x) for each bit you want to clear or set. Using |= will set the bit value in the location using &= ~ will clear the bit value in that location. TCCR0A= x1xx1100 could be done as. Set bit 6,3 and 2 TCCR0A |= (1<<wgm00) | (1<<wgm01) | (1<<cs02); Which isTCCR0A |= (1<<6) | (1<<3) | (1<<2); Clear bits 1 and 0 TCCR0A &= ~(1<<cs01); TCCR0A &= ~(1<<cs00); Which is TCCR0A &= ~(1<<1); TCCR0A &= ~(1<<0); If you prefer to think of TCCROA as one byte you don’t really need use to shift at all. Thinking binary TCCR0A |= 01001100 will set the bit values in locations 6,3,2 Decimal equivalent would be 64 + 8 + 4 = 76 TCCR0A |= 76; TCCR0A &= ~(00000011) will clear the bit 0 and 1 Decimal equivalent would be 2 +1 =3 TCCR0A &= ~(3); that is just the way I think of clearing or setting bits. |
December 02, 2012 by Ralphxyz |
As Noter said "_BV() is part of the standard AVR lib-c." But you can also write your own macros. Ralph |
December 02, 2012 by keith712 |
thanks Darryl, i understand exactly what you're doing which would not have been true yesterday... there are several ways to skin this cat... i think that using separate lines of code to clear or set each bit or group of bits may be easier to read or debug then your second method of eliminating the left shift by manipulating the whole byte... using macros like _BV() looks like a good way to keep the source code readable, too... Noter and Ralph, i just read a section of the book where Joe shows how to use the #define statement to write macros instead of making and calling functions... i'm going to download the avr lib-c document... this hobby this could turn into a full time job!!! |
December 02, 2012 by BobaMosfet |
Think of an OR as an ADD. Just no carry.
MSB on left, LSB on right People get confused by what statements like 'TCCR0A |= (1<<wgm00) | (1<<wgm01) | (4<<cs00)' mean, because they think they are shifting the register. The are not. They are shifting a 1 into a new position and adding that to the register. Note that there is a '4' being shifted zero places. In other words if:
then
becomes
Enjoy. BM |
December 03, 2012 by keith712 |
thanks BM... there are more ways to skin this cat then i ever would have guessed... this discussion has been very helpful... i think i've learned more in the last day and a half then i could have in a weeks worth of studying on my own... thanks to everyone... i can't wait to run into another problem... just kidding... k |
December 16, 2012 by cadiz1 |
Question on bit shifting: Q1. If I bit shift 0000 0000(start value) (1<<3) is it 0000 1000 or 0000 0100. My confusion is, do we start with bit 0 and count 0,1,2,3 ? which makes it 0000 1000. Q2. If the start byte is 0010 0010. (1<<3) is bit 1 and 5 shifted forward ? |
December 16, 2012 by pcbolt |
cadiz1 - When you write (1<<3), you are always starting with 0000 0001 and ending up with 0000 1000. The expression (1<<0) will give you 0000 0001, (1<<1) will be 0000 0010, (1<<2) will be 0000 0100 and so on. If the start byte is 0010 0010, this is the value 34 (in decimal). So you would have to write (34<<3) to get 0001 0001 0000. |
Please log in to post a reply.
Did you know that you can connect a computer keyboard to your microcontroller? Learn more...
|