C - AVR - Simple PORTB, DDRB, PINB explanation C - AVR - Simple PORTB, DDRB, PINB explanation c c

C - AVR - Simple PORTB, DDRB, PINB explanation


Do you means what is if-condition PINB & (1<< PINB0))?

It checks whether PINB0 + 1 number bit( from rhs) is ON (1) in PINB or OFF (0).

For example. (a & (1 << 2)) checks whether 3rd bit is ON in a or OFF. In the expression two operators are used << bitwise left shift and & bitwise and below I have explained for one byte example:

  1. 1 is 0000 0001
  2. 1 << 2 after left shift gives 0000 0100
  3. a bitwise and with 0000 0100 gives either all zeros 0000 0000 or 0000 0100

    3a. If all zeros then if condition is false (when third bit in a is zero).
    3b. If result of bitwise and is 0000 0100 then if condition evaluates as true (when third bit in a is one).


Microprocessors use a memory map to interface their hardware functionality with the software.

Basically, there are static addresses in memory that the hardware will use to determine its functionality. These are specific to the manufacturer, the part, and sometimes even how the part is configured.

The datasheet for the part will tell you the exact memory location to control different functionality. However, this is normally very tedious. As a result, the datasheet will also (almost) always give a name to that particular location in memory that describes its functionality. Once again, these names are manufacturer and part specific.

To make this interface easier for programmers, people (the manufacturer or the community) will often create macros to these memory locations. For example, you could find

// Clock Prescalar Register for ATMega328p#define CLKPR *0x61

in a header file associated with the part (such as AVR libc).

Now, by writing OSCCAL = 0b10000000 (or whatever else I want to write that is allowable by the specifications in the datasheet) I can directly access and change the clock prescalar module for this part.

But, often we are interested in the value of a single bit, not the entire byte. As a result, we use bitwise operators (such as &, |, ~, << >>) to "mask" off bits that we are interested in manipulating.

This offers the simultaneous advantage of allowing us to only read the value from the bit of interest, while not inadvertently changing any bits that we do not mean to toggle.

Many bit positions are also given by macros as well. For instance, bit 7 in OSCCAL is named CLKPCE (again, from the datasheet).

CLKPCE is most likely defined (at least in AVR libc - the standards vary) by:

#define CLKPCE 7

because it defines the bit shift needed to get to the desired bit inside OSCCAL.

In order to talk about the bit here, I can do several things.

Set the bit

To set the bit, we want to make it a 1, without affecting any of the other bits. To do this, we use an OR mask, as follows:

OSCCAL = (OSCCAL | (1 << CLKPCE));

I'll leave it to you to review bit operators and see how this works.

Clear the bit

Here, we want to make it a 0, without affecting the other bits. It will look something like this:

OSCCAL = (OSCCAL & ~(1 << CLKPCE));

Query the bit

When querying, we want an expression that returns nonzero if the bit was set (1), and zero if the bit was cleared (0). It'll look like this:

(OSCCAL & (1 << CLKPCE));

The Takeaway

By using these different bitwise operations with predefined macros, we can directly control and query the state of the hardware by using this static memory map.

However, to make sense of all of these macros, you will need to consult (and read, and re-read, and re-re-read) the datasheet for your part. Luckily, searchable PDFs are available for free from Atmel on your part's page!


if (PINB & (1 << PINB0)){        A = true;    }

This code checks whether PIN 0 in PORTB is HIGH or LOW. If it is high then assigns A = true;Here, PINB --> Reads data from PORTB, (1<<PINB0) --> Make 0th bit as 1 and AND's both values to know whether PIN 0 in PORTB is high or not.