Help with understanding setting flag bits in registers?

Go To Last Post
11 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

1) TCCR1B = (1<<ICNC1) | (1<<ICES1) | (1<<CS12) | (1<<CS11);

 

2) edge = TCCR1B;

    TCCR1B = edge ^ (1<<ICES1);

 

3) TCCR1B ^= (1<<ICES1);

                              

/* Timer/Counter 1 Control and Status Register B - TCCR1B */
#define    ICNC1        7
#define    ICES1        6
#define    WGM13        4
#define    WGM12        3
#define    CS12         2
#define    CS11         1
#define    CS10         0

 

I am definitely messing up my understanding of flag bit setting and clearing

 

Can anyone explain me the above code lines? Does 1<<ICES1 mean that the flag bit is set or the flag bit is left shifted as a result of which ICNC1 is set?

 

                      7           6          5          4           3           2           1          0    

TCCR1B      ICNC1    ICES1        -       WGM13  WGM12   CS12     CS11     CS10

 

 

 

Thanks

This topic has a solution.

Amateur programmer.
Believe when I tell you that my struggle on here is real.

Last Edited: Fri. Nov 10, 2017 - 07:44 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Search the tutorial forum here for "bit manipulation 101"

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

As advised I did go through it, But I am not clear with bit flipping. Can you explain bit flipping by taking the codelines 2 and 3 from above as examples? 

Amateur programmer.
Believe when I tell you that my struggle on here is real.

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

From:

TCCR1B = (1<<ICNC1) | (1<<ICES1) | (1<<CS12) | (1<<CS11);

and

/* Timer/Counter 1 Control and Status Register B - TCCR1B */
#define    ICNC1        7
#define    ICES1        6
#define    WGM13        4
#define    WGM12        3
#define    CS12         2
#define    CS11         1
#define    CS10         0

You know the first line is the same as:

TCCR1B = (1<<7) | (1<<6) | (1<<2) | (1<<1);

Simple maths tells you that:

(1<<7) = 0b10000000 (1 moved left 7 times) = 0x80 = 128
(1<<6) = 0b01000000 (1 moved left 6 times) = 0x40 = 64 
(1<<2) = 0b00000100 (1 moved left 2 times) = 0x04 = 4
(1<<1) = 0b00000010 (1 moved left 1 times) = 0x02 = 2

So ORing (|) them all together means:

TCCR1B = (1<<7) | (1<<6) | (1<<2) | (1<<1);

is the same as either

TCCR1B = 0b10000000 | 0b01000000 | 0b00000100 | 0b00000010;
TCCR1B = 0x80 | 0x40 | 0x04 | 0x02;
TCCR1B = 128 | 64 | 4 | 2;

Now different folks "see" binary numbers better in different ways. Personally I couldn't possibly visualise what

128 | 64 | 4 | 2;

except to say that because each represents just one but you can treat | (OR) like + (ADD) so:

TCCR1B = 128 + 64 + 4 + 2;

which means:

TCCR1B = 198;

But it's still very difficult to visualise which bits are set in the decimal value 198.

 

Hex may be easier:

TCCR1B = 0x80 | 0x40 | 0x04 | 0x02;

The 0x80 and 0x40 combine to make 0xC0 in the upper nibble and the 0x04 and 0x02 combine to make 0x06 in the lower nibble so the complete value is:

TCCR1B = 0xC6;

(of course 0xC6 is just 198 - that's just two different ways to represent the same thing) but I think to really "see" what is going on the binary values are easiest to picture, especially if you write:

TCCR1B = 0b10000000 | 0b01000000 | 0b00000100 | 0b00000010;

as this:

TCCR1B = 0b10000000 | 
         0b01000000 | 
         0b00000100 | 
         0b00000010;

in which case it's just a case of putting all 8 columns together:

TCCR1B = 0b10000000 | 
         0b01000000 | 
         0b00000100 | 
         0b00000010;

is the same as:

TCCR1B = 0b11000110;

then go back to this picture:
 

              7       6        5       4     3       2        1        0    
TCCR1B      ICNC1    ICES1     -     WGM13  WGM12   CS12     CS11     CS10

and you can see exactly where those 1's and 0's are going. Just as the original line says you are putting the 1's in the bit positions 7,6,2,1 that is in positions ICNC1, ICES1, CS12 and CS11 which is what the line of C actually "said" in the first place:

TCCR1B = (1<<ICNC1) | (1<<ICES1) | (1<<CS12) | (1<<CS11);

Please NEVER, EVER, EVER consider writing this as:

TCCR1B = 198;

No one reading that (and that includes you in 3 months time!) will ever have any real idea what bits are being set using the decimal value 198.

 

On the other hand anyone who read:

TCCR1B = (1<<ICNC1) | (1<<ICES1) | (1<<CS12) | (1<<CS11);

will instantly see that you are setting the ICNC1, ICES1, CS12 and CS11 bits. For many bits in many registers a lot of the AVR users reading here will actually know what these bits are and what they do so we can all read that line of C without ever digging out a datasheet to look it all up. If you used 198 we wouldn't have had a clue!!!

 

Oh and the same technique applies for (2) and (3). All you need to know there (I assume you do?) is that '^' is the Exclusive-OR operation in C. It has the interesting property that it turns 0 bits to 1 and 1 bits to 0 in the given position. In other words it is a "toggle". So to switch the state of bit 3 in something you might use val ^= (1 <<3) for example and if bit 3 was 1 it is now 0 and if bit 3 was 0 it is now 1. Very useful for flashing LEDs on and off!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I guess Cliff's again excellent and comprehensive answer is what qualifies as spoon feeding? Another beginner saved from the hassle of retrieving necessary info themselves (this being called "learning")?

 

This is not to say that i don't enjoy reading Cliff's responses, as I'd never could be patient long enough to spend my time for such an exhaustive explanation just to save another guy's time... Not that this issue hasn't been discussed a thousand times in hundreds of similar forums/tutorials/guides.

Einstein was right: "Two things are unlimited: the universe and the human stupidity. But i'm not quite sure about the former..."

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The title of the thread is, "Help with understanding setting flag bits in registers"

 

Just a quick note to say that none of this has anything specifically to do with registers or even microcontrollers - it is all bog-standard, textbook 'C'.

 

See: http://www.avrfreaks.net/comment...

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

DO1THL wrote:
qualifies as spoon feeding?
We all had to learn this stuff at some point. I just wish I'd had someone around to explain it to me! cheeky

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Read up what binary operators in C does & | ^ (and or xor). (and perhaps how they works on left side of =)

 

and when people say toggle a bit with ^ it's just because a bit  xor'ed with a bit set (=1) will toggle the bit.    

Last Edited: Thu. Nov 9, 2017 - 11:31 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

sparrow2 wrote:
Read up what binary (sic) operators in C does

You mean Bitwise operators.

 

It does also require an understanding of the underlying Boolean Algebra

 

https://en.wikipedia.org/wiki/Boolean_algebra

 

https://en.wikipedia.org/wiki/Truth_table

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

@clawson - thanks a lot. Thanks @sparrow2, awneil, ki0bk

Amateur programmer.
Believe when I tell you that my struggle on here is real.