NerdKits - electronics education for a digital generation

You are not logged in. [log in]

NEW: Learning electronics? Ask your questions on the new Electronics Questions & Answers site hosted by CircuitLab.

Microcontroller Programming » Digital Write Question

June 21, 2009
by Ethanal
Ethanal's Avatar

I noticed in the Nerdkits guide you guys use a different method of writing to digital pins than what I am accustomed to. For example, if i wanted to turn on an led a PB1, I would use this code:

DDRB = 0x2;

PORTB = 0x2;

It appears you would use this code:

DDRB |= (1<<PB1);

PORTB |= (1<<PB1);

What is the difference? Any help is appreciated.

June 21, 2009
by mcai8sh4
mcai8sh4's Avatar

Aha, I had some confusion with this initially, there's a post in here (maybe by wayward) explaining this very nicely.

But for a quick answer....

0x2 (hex) = 00000010 (binary) = 2 (decimal)

We can use any method really, but it depends on what we are trying to achieve. Your latter example says set the the register to 1, but bit shift it by PB1 (1). If you used PB3 it would move the bit across (left) three places, ie. 00001000

The '|=' is an OR

A nice thing about this method, is that it leaves all the other bits as they where.

So if your register is set to : 001010

You can set just the third bit by using PORTB |= (1<<PB2) to give you 001110 - you can see that all the other bits are left as they where.

Check out THIS it explains it very well.

If you're still confused, shout out, I'll try to explain better (when sober)

July 01, 2009
by Ethanal
Ethanal's Avatar

O.K.-- I understand how to set a pin to high now, but how do I turn it off without affecting the other bits?

July 01, 2009
by Ethanal
Ethanal's Avatar

Never mind the last question. I figured that out, but I have a new question. How do you turn more than one pin to high or low at the same time?

July 01, 2009
by jbremnant
jbremnant's Avatar

to turn on multiple without affecting the currently "on" pins: PORTB |= (1<<PB1) | (1<<PB2) | (1<<PB3) ... you get the idea.

to turn off multiple without affecting the other pins:

PORTB &= ~((1<<PB1) | (1<<PB2) | (1<<PB3))

Additionally, I have some nifty macros you can use in C code:

#define pinOn(X,Y) PORT ## X |= (1<<P ## X ## Y) #define pinOff(X,Y) PORT ## X &= ~(1<<P ## X ## Y)

Put those lines on the top of your .c file and then use it like: pinOn(B,1); pinOff(C,0);

The first argument corresponds to port, and the second arg is the number of the pin

July 01, 2009
by jbremnant
jbremnant's Avatar

Sorry, I botched up the format of the previous post... here you go.

to turn on multiple without affecting the currently "on" pins:

PORTB |= (1<<PB1) | (1<<PB2) | (1<<PB3) ... you get the idea.

to turn off multiple without affecting the other pins:

PORTB &= ~((1<<PB1) | (1<<PB2) | (1<<PB3))

Additionally, I have some nifty macros you can use in C code:

#define pinOn(X,Y) PORT ## X |= (1<<P ## X ## Y)
#define pinOff(X,Y) PORT ## X &= ~(1<<P ## X ## Y)

Put those lines on the top of your .c file and then use it like:

pinOn(B,1);
pinOff(C,0);

The first argument corresponds to port, and the second arg is the number of the pin

July 01, 2009
by mcai8sh4
mcai8sh4's Avatar

I like the macro idea. Could you explain the '##' bits. I don't really get how it works.

Thanks

July 01, 2009
by jbremnant
jbremnant's Avatar

The "##" syntax is C macro concatenation operator. Basically, when you feed in two variables, it just joins them together.

So, doing

A ## 1

would get preprocessed and become

A1

in your C code before it gets compiled. For more info, try:

macro concatenation

July 01, 2009
by mcai8sh4
mcai8sh4's Avatar

Ah, got you. All makes sense, quite nifty that - I'll give it a go.

Stuff like that could really obfuscate things if you wanted to - I like it.

July 01, 2009
by Ethanal
Ethanal's Avatar

Thanks guys: that helped a lot. I found my mistake. I was "NOT"ing each one then "OR"ing them instead of "OR"ing them then "NOT"ing that (if that makes sense). I love how helpful the Nerdkits Community is.

P.S. Cool macro

July 05, 2009
by BobaMosfet
BobaMosfet's Avatar

I think it is important to understand what this really is. This is called MASKING. You clear and set bits and use "masks" to achieve this. C and C++ have many ways you can do this, including left and right shifting in order to create the 'mask'.

When you say "1 Left Shift PBn", what you're really saying is: create a temporary variable on the stack to hold a byte value. Put a 1 there and then left shift it by PBn bits. Whatever that value ends up being is your 'mask' during the operation.

PBn is a defined constant that represents a 1, 2, 3....n value (number of bits to shift). PORTB is a register (another byte-length variable location at a hardwired location in the process (MCU)). When you '|=' it you are adding or combining the masked value to whatever already exists in that register. And then the 'mask' variable that was kept on the stack will be discarded.

#define  BIT3 = 2
#define  BIT4 = 3

PORTB = 0;                         /* Clear the register */
PORTB |= (1<<BIT4) | (1<<BIT3);    /* Same as:  PORTB |= 0x0C; *** 0x0C = 00001100 */

PORTB &= 0xFB;                     /* Clear BIT3 *** 0xFB = 11111011 */

Using the above, here are the bytes in binary:

00000000                           ;PORTB cleared to Zero
00001100                           ;MASK FOR BIT4 AND BIT 3
--------
00001100                           ;Result of the OR Operation

00001100                           ;PORTB Existing State
11111011                           ;MASK used to clear bit 3
--------
00001000                           ;Result of the AND Operation

Hope this helps. Get real familiar with working between hex, decimal, and binary. If you learn to think in terms of nybbles (4 bits, 0000 through 1111 or 0x0 through 0xF) using hex, it makes the binary work much easier to think about.

July 05, 2009
by mcai8sh4
mcai8sh4's Avatar

BobaMosfet - great explaination, I must admit I struggled with this concept at the beginning and you're right - getting a good understanding of what you're doing (in 1's and 0's) really helps.

July 05, 2009
by jbremnant
jbremnant's Avatar

Great explanation on bit operations. To add to it, the statement for turning off 3 pins while retaining the state of others:

PORTB &= ~((1<<PB1) | (1<<PB2) | (1<<PB3))

00000001     // 1<<PB1
 OR  
00000010     // 1<<PB2
--------
00000011     // (1<<PB1) | (1<<PB2)
 OR
00000100     // (1<<PB3)
--------
00000111     // (1<<PB1) | (1<<PB2) | (1<<PB3)
 NOT
11111000     // ~((1<<PB1) | (1<<PB2) | (1<<PB3))
 AND
00001111     // PORTB which previously had all 4 pins turned on
--------
00001000     // notice the state of 4th bit(pin) is retained while
             // the 3 pins are off

And btw, I think the define statements above in BobaMosfet's post should be:

#define  BIT3 2
#define  BIT4 3
July 07, 2009
by Ethanal
Ethanal's Avatar

Thanks to everyone. You guys are a real help. Wonderful explanations. I think I understand it now.

jbremnant: I think BobaMosfet is correct. Remember PB0 is bit 1, PB1 is bit 2, etc.

Post a Reply

Please log in to post a reply.

Did you know that talking to the microcontroller over the USB/Serial link is easy under Windows, Linux, and OS X? Learn more...