Electrical Engineering Stack Exchange is a question and answer site for electronics and electrical engineering professionals, students, and enthusiasts. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

In AVR Tutorials I often see:

DDRA |= (1 << PA0);
PORTA |= (1 << PA0);

used instead of:

DDRA |= PA0;
PORTA |= PA0;

What is the purpose of this?

share|improve this question
14  
I don't know much about AVR, but (1 << 2) is not the same as 2. – Armandas Mar 18 at 12:14
    
Because they are programming in C. In assembler you'd use a bit setting instruction directly, in Ada you have several options, for one you can simply assign True or False to one member of a packed array of booleans : PortA(PAO) := True; – Brian Drummond Mar 18 at 12:14
    
If PA0 specifies a bit number (such as 0 through 31), then (1 << PA0) represents a bit mask or bit field in which that bit is set. – kkrambo Mar 18 at 13:53
    
It seems that you don't understand bitwise operators. Here is one I used: Bit Manipulation It starts from the basics and goes as far are required. – StudentOlife Mar 18 at 15:20
1  
As an aside, in AVR C you can typically also use the _BV() macro to get the "bit value" (e.g. PORTA |= _BV(PA0);. I personally think it makes the code more readable, but opinions differ quite a bit in the community. – Mels Mar 18 at 15:27
up vote 16 down vote accepted

PA0 will be defined as 0 so the following line:

DDRA |= (1 << PA0);

Equates to shifting 1 left by zero bits, leaving an OR with the value 1 to set the first bit. Whereas the following line:

 DDRA |= PA0;

Is doing an OR with zero so won't change the registers at all.

share|improve this answer
    
That makes me wonder why they wouldn't just use DDRA |= 1. Do they expect PA0 to change across different environments? – corsiKa Mar 18 at 15:36
7  
@corsiKa: which is easier to read and understand: DDRA |= 72; or DDRA |= (1<<PA6) | (1<<PA3);? – David Mar 18 at 16:03
1  
Ah, there are other bits in the pattern. Gotchya. Nope, I like it. – corsiKa Mar 18 at 16:07
    
@corsiKa even when you set only 1 bit, does |= 128 make more sense than |= (1 << 7). How do you know that it'll set the 7th bit when looking at values like 128? – Lưu Vĩnh Phúc Mar 19 at 11:12
    
@LưuVĩnhPhúc Of course not. But to someone who doesn't use that framework, it's not clear that they care about "setting a bit" at first glance, hence why I asked. Suffice it say, PA0 isn't very descriptive of what it's actually doing. – corsiKa Mar 20 at 21:13

Why do they do this? Likely because everyone else they ask for help or learned from did it that way. And because the standard defines are weirdly done.

Shifting by a number, typically a decimal number, will move that value over by that many binary positions. 1 << PA0 will shift 1 by PA0 to the left. Since PA0 is 0, there is no shift. But given 1 << 6 1 will become 0b1000000. Given13 << 6, it will shift 13, in binary which is 0b1101, over by 6 to become 0b1101000000 or 832.

Now, we need to see what PA0 - PA7 are defined as. These are typically defined in the specific header for your specific microcontroller, included via io.h or portpins.h

#define     PA7   7
#define     PA6   6
~
#define     PA1   1
#define     PA0   0

They are defined as their numerical position, in decimal!

They cannot be directly assigned, as bits, because they are not single bits.

If you were to do PORTA |= PA7; assuming PORTA is 0b00000000 (all off), you will get:

PORTA = PORTA | PA7; or PORTA = 0 | 7; or PORTA = 0 | 0b111

See the problem? You just turned on PA0, PA1, PA2, instead of PA7.

But PORTA |= (1 << PA7); works as you expect.

PORTA = PORTA | (1 << PA7); or PORTA = 0 | (1 << 7); or PORTA = 0 | 0b10000000;


The Smarter way

The other, better microcontroller, the MSP430, has a standard define of bits as:

#define BIT0                (0x0001)
#define BIT1                (0x0002)
~
#define BIT6                (0x0040)
#define BIT7                (0x0080)

These are define as their binary position, in hex. BIT0 is 0b0001, not like PA0, which is 0. BIT7 is 0b10000000, not like PA7, which is 0b111.

So direct assignments like P1OUT |= BIT7; will work the same as P1OUT |= (1 << 7); would.

share|improve this answer

Your question has already been answered, but I want to present an alternative that was a bit much for a comment. One of the first things I do when I start an embedded project is define my bit set and clear macros.

#define bitset(var,bitno) ((var) |= 1 << (bitno))
#define bitclr(var,bitno) ((var) &= ~(1 << (bitno)))

Using the macros, your code becomes:

bitset(DDRA,0);
bitset(PORTA,0);

The end result is a bit set instruction in assembly.

share|improve this answer
3  
You made a typo, the second line should be e.g. "bitclear". – jms Mar 18 at 13:37
    
Your 2nd #define, not your 2nd example. – brhans Mar 18 at 13:53

Have a look here: http://nongnu.org/avr-libc/user-manual/FAQ.html#faq_use_bv

Those macros are used when setting particular bits in a register. For example: if PORTA is 8-bits wide, then PA0 is the lowest bit, PA7 is the highest. To set PA0 to 1 you have to write ("or-write") 0x01 to the register. If you want to set PA2, then you need a value that in binary will have a one in the right place, for PA2 that will be 0x04.

People don't want to remember which bit has a particular position (as other registers may have different bit names eg. CS12, CS10, ADSC etc.) so they use more abstract names. Instead of typing: PORTA = 0x04 you type PORTA = _BV(PA2) and you instantly know that it will turn pin PA2 high.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.