What does it mean when

I understand that this code sets the port to input, but I have not seen the syntax before. Can someone explain the use of the tilde? I assume the << is bit shifting but i don’t understand how that works here so I am probably wrong.

DDRC &= ~(1 << PC5);

Yeah, this sort of thing was the MOST confusing part of getting into microcontroller programming, so lets break it down (sorry in advance that I’m probably re-explaining some stuff you already know).

DDRC stands for Data Direction Register C, it’s basically an eight bit number that controls the state of the pins of PortC. Technically PortC only has six pins on the ATMega168, PC0-PC5 (PC6 is the reset pin), but it’s an eight-bit microcontroller, so registers really can’t help but have eight bits.

By default, the data direction register bits are all set to zero, (in binary 0b00000000) making all the pins inputs. Lets say I want to set pin PC5 to be an output. I should the fifth bit of DDRC to 1 (keeping in mind that the rightmost bit is the zero’th bit). I could do something like:

DDRC=0b00100000;

But first off, that’s a little cumbersome to write out. You’re right about the << being a left bit-shifting operator, so I could write:

DDRC=(1<<5);

Where 1 in binary is 0b00000001, and shifted five bit-places to the left is 0b00100000, the number I want.

To help you keep your sanity, and make code more portable from device to device, the <avr/io.h> library contains a big list of register bit definitions that let you use the individual bit names. It’s really helpful for registers that don’t have logically numbered bits like the DDR ones. Basically PC5=5, so (1<<PC5) will be evaluated the same way as (1<<5). It’s not really different, but it’s a good bookkeeping practice.

Now, what if I want to set PC5 as an output, but I don’t know the state of, or want to mess with the other bits of DDRC (like they’re set by another part of the program). Unfortunately, the command DDRC=(1<<PC5) sets every other bit of DDRC to zero:

DDRC: ???
DDRC=(1<<PC5);
DDRC: 00100000

Whatever those other ? bits were, I’ve set them to zero now. The general way to deal with this is to use the bitwise or operator ‘|’ for example: 0b11100000|0b11000011=0b11100011. If either bit of the two numbers is 1, the resulting bit is set to one. Conveniently:

DDRC: ???
DDRC|=(1<<PC5);
DDRC: ??1???

By those question marks, I mean that whatever the state of the other bits of DDRC were, they remain unchanged, and whatever the state of PC5 was, it is now set to 1. You can also use the | operator to set multiple bits to 1 at once:

DDRC: ???
DDRC|=(1<<PC5)|(1<<PC3);
DDRC: ??1?1???

Pretty neat! But that’s only good for setting bits to 1, what if I want to take an output pin and change it back to an input pin, again without affecting the other bits of the DDR. The trick is to use the bitwise and operator ‘&’, and the bitwise not operator ‘~’.

The & operator outputs a 1 when both of two corresponding input bits is 1, for example: 0b11000000&0b10111111=0b10000000.

The ~ operator flips the bits of a number, so ~0b11110000=0b00001111. This should not be confused with the logical not operator ‘!’, which sets all nonzero numbers to 0, and zero to 1.

SO, what happens when you run DDRC&=~(1<<PC5)? Well:

(1<<PC5)=0b00100000
~(1<<PC5)=0b11011111
DDRC: ???

DDRC&=~(1<<PC5);
DDRC: ??0???

So, whether PC5 was an output or an input, you’ve now set it to be an input for sure, without affecting the input/output state of the other pins in Port C! ROCK ON!

-Adam

Adam,

Thanks, that is the best explanation I could have asked for and explains everything. I am used to doing it a little differently and I have never used the “~” as a not operator.

Nice explanation!

That code had me scratching my head for a bit, too!

Hello,
Assuming you are programming in C one thing you can do is define another set of macros that simplify things. eg:
#define PINFOO_HI = (1<<PINFOO)
Macros are just textual subsitition before compilation so there is no efficiency hit for this and it might help make your code a little easier to read.

Another thing I’ve enjoyed doing in the past when bit twiddling in C is to create a structure with bit fields.
eg:

typedef struct
{
u_int opcode:11;		
u_int ipreg     :5;			
u_int iqreg     :5;			
u_int best      :4;			
u_int plop      :7;			
}DLIB_FOO_REGISTER;

I find this much easier to debug than looking at hex and trying to figure out which bits are set.
It also makes setting bits at run time in the debugger easier.
Not sure how applicable that is to your environment but it can save quite a lot of headaches.
Cheers
Dave

Adam,
Awesome explanation. Thanks for your time to write out that clear presentation.

Dave,
I’m interested in your second comment. Can you show a small example of how you use that struct and how it makes coding convenient, especially with the debugger?

Thanks,
Marc