Register Manipulation for Dummy

I didn’t find yet the explanation, so I’m post (maybe already exists)
I cut this from a sketch that I found on the internet, but, I’m trying to understand

TCCR1B |= (1 << CS10); //selecting prescaler 0b001 (Tclk/1)
TCCR1B &= ~((1<<CS11) | (1<<CS12)); // turn off CS12 and CS11 bits

TCCR1B |= (1 << CS10), I understood (not sure if correct) that this is changing the current bits on the TCCR1B doing an OR with (1 << CS10), but:
Is it manipulating all bits or only the CS10 bit.

TCCR1B &= ~((1<<CS11) | (1<<CS12)), I understood that this is also manipulating the TCCR1B, but only the bits CS11 and CS12?

So, I appreciate if somebody can explain me … I understood that << to a shift of 2, but I don’t here is the case because if we are manipulating individuals bits, we don’t need to shift

Thanks

Yes, the << is a bit shift, |= is OR assignment - zero bits in constant does not change appropriate bits in the register, 1 bits set appropriate bits to 1 in register. TCCR1B |= (1 << CS10) means that CS10 bit will be set and other bits will be without the change. TCCR1B &= ~((1<<CS11) | (1<<CS12)) clears CS11 and CS12 since &= is AND assignement, as 0 in constant will clear appropriate bit and 1 will let it without the change.
See C/C++ documentation.

But let consider that TCCR1B has initially b00000011 what is prescaler 64, and that the bits for TCCR1B is
MSB … not important at this moment
bit 7 … to bit 5 not important at this moment
b3 = CS12
b2 = CS11
LSB = CS10

if I’m manipulating CS10 it’s already defined that I want change the position LSB, so if I have b00000011, and a do a OR with b000000001 shifted << I will manipulate the position b3 (position 1 “LSB”, shifted 2x to left) and will change the initial b00000011 to b00000111

From iom328p.h:

#define CS10 0

?
#define CS10 0

1<<CS10

is 1.

Can you elaborate why 1<<CS10 is 1?

can I change the code from

TCCR1B |= (1 << CS10)

to

TCCR1B |= 1

?

Seems that not because in this case I will change the 8 bits as 00000001 and I just want to the change the LSB which is the CS10

EduAQA:
Can you elaborate why 1<<CS10 is 1?

x << y;

Means shift ‘x’ to the left ‘y’ places. So:

1 << 0;

is 1.

CS10 is 0, So:

1 << CS10;

is 1.

can I change the code from

TCCR1B |= (1 << CS10)

to

TCCR1B |= 1

?

Yes.

but when on the .h we define that CS10 0 are not we talking about the position 0 on the byte? steady of the decimal 0?
Because the others position on the same byte are:
#define TCCR1B _SFR_MEM8(0x81)
#define CS10 0
#define CS11 1
#define CS12 2
#define WGM12 3
#define WGM13 4
#define ICES1 6
#define ICNC1 7

and we cannot say that ICNC1 for example is 7, because the binary values needs to be 0 or 1, it cannot be 7
so ICNC1 7 is the position of the bit on the byte not the value of the bit.

1 << ICNC1;

is: 0b10000000
Note how the ‘1’ aligns with the register’s ICNC1 bit.

EDIT:
So yes, ICNC1 (aka 7) is the position of the “ICNC1 bit” inside the register.

I think I’m starting understand, so if I say

TCCR1B |= (1 << ICNC1),

I’m saying

take the current value of TCCR1B and do a
OR
with the binary value of the decimal 1 what is b00000001, but, used the b10000000 because it needs to be shifted ICNC1 (which means shift 7 positions).
so after the transformation of the (1 << ICNC1) we will have

TCCR1B |= b10000000

So it will change the bit on the position 7 (because is a OR math) without altering the others.

Very good. Now that seems that I understood the constants (.h definitions) and shifting I will try to understand the second line that use &= (AND) and ~(NOT)

TCCR1B &= ~((1<<CS11) | (1<<CS12)); // turn off CS12 and CS11 bits

Just break it apart:

CS11 is 1
1 << CS11 is 0b00000010

CS12 is 2
1 << CS12 is 0b00000100

(1 << CS11) | (1 << CS12) is 0b00000010 | 0b00000100 = 0b00000110

~(0b00000110) is 0b11111001

TCCR1B & 0b11111001 clears bits 1 and 2 of TCCR1B and leaves the rest unchanged.

EduAQA:
I will try to understand the second line that use &= (AND) and ~(NOT)

The "&" operator only selects bits which are set in both values. The "~" operator is an inversion operator, it inverts all bits in a value. When you combine them, you will clear the defined bits.

byte a = 0b00000011;
byte b =  0b00000010;

//Select common bits with &
byte c = a & b; //c=0b00000010

//Clear bit 1 in a
byte d = ~(0b00000010); //d=0b11111101
a &= d; //a=0b00000001

The line "byte d = ~(0b00000010)" is equal to "byte d = 0b00000010 ^ 0b11111111". The "^" operator is also called "xor" or eXclusive OR which inverts the defined bits (1 xor 1 = 0 and 0 xor 1 = 1). Xor is often used to toggle a state / bool.

I'm a confirmed Luddite. I prefer to set my bits with something like TCCR1A &= 0b00100010;
(By th way, my binary is meaningless and just to show the style)

...R

I go even simpler.

a = a & 0b00001111; // clears bits 7-6-5-4, leaves 3-2-1-0 alone -> a = 0b0000xxxx

a = a | 0b10100000; // sets bits 7, 5, leaves rest alone -> a now equals 0b1010xxxx

Thanks gfvalvo, very clear way to explain, mainly for a dummy like me.
Thank you all for the reply.

Robin2:
I'm a confirmed Luddite. I prefer to set my bits with something like TCCR1A &= 0b00100010;

I don't see the advantage of not using the macro names (which were defined for this purpose) along with the standard bit shift operators. There certainly isn't a speed advantage as everything is resolved at compile time. And, using them at least gives you an idea of which function bits are being manipulated in the register.

CrossRoads:
I go even simpler.

a = a & 0b00001111; // clears bits 7-6-5-4, leaves 3-2-1-0 alone -> a = 0b0000xxxx

a = a | 0b10100000; // sets bits 7, 5, leaves rest alone -> a now equals 0b1010xxxx

Again, what is the advantage of not using the standard language operators such as |= and &= operators?

Robin2:
I'm a confirmed Luddite. I prefer to set my bits with something like TCCR1A &= 0b00100010;
(By th way, my binary is meaningless and just to show the style)

...R

I'd go further and suggest using something like  TCCR1A = 0b01010001 ;
You shouldn't be making any assumptions about the previous state of the hardware when you set it up,
so just set all the bits to precisely what you want.

Also with some hardware registers a read operation on the register has side-effects (for instance reading
the interrupt status register clears it). I think its best to make every read and write of a hardware
register explicit, rather than hidden in something like REGXYZ |= val;

Sometimes you have to only set part of a register (for instance pinMode() and digitalWrite() do this),
as other bits are not under your control, but otherwise set the whole register to ensure a known state.

An example from Uno showing setting pins 2 to 6 all HIGH:

  PORTD = (PORTD & 0x83) | 0x7C ;  // each access to PORTD register explicit

I think thats better than

  PORTD |= 0x7C ;

And it you want to set some pins high and some low its atomic too, compare:

  PORTD = (PORTD & 0x83) | 0x28 ;  // set pins 2,4,6 low, 3,5 high, preserve 0,1,7

to

  PORTD |= 0x28 ;  // 0b00101000
  PORTD &= ~0x54 ; // 0b01010100

I personally use hexadecimal mostly as I find it harder to mis-read or miscount bits, but then
I've been using hex for many decades - I know its probably confusing for a newcomer.

gfvalvo:
I don't see the advantage of not using the macro names (which were defined for this purpose) along with the standard bit shift operators.

I find the combination of macro names and shift operators very confusing. When I set out 0b01010000 I can see visually exactly how the bits will be set.

And, as @MarkT recommends in Reply #17 I do generally use TCCR1A = 0b01010001;

...R