Hi everyone,
This post will cover usage of I/O ports in ATmega328P. I will start with a simple code to blink a LED.


Figure 1: Pin Diagram for 28-pin PDIP

In the previous figure, the schematic gives us information about ATmega328P pin capabilities and their special property. The following table contains brief information about pins.




Figure 2: I/O Pin Equivalent Schematic [2]

As can be seen from the Figure 1, All port pins have selectable pull-up resistors and protection diodes for Vcc and GND. What is pull-up or pull-down resistors? Here is a brief information about what they are. Suppose that, there is an input pin and you want to decide the state of pin. Is it high or low? This might be a little bit difficult because of these reasons, pull-up and pull-down resistors are highly used to ensure the pin state. For further information about pull-up and pull-down resistors please visit these sites;




Let’s look registers for I/O. There are three port pin register bits; PINx, DDRx and PINx. Each register has special purpose. I wondered that why there is not PORTA in Atmega328P and I have found a few sources. I do not know the real reason why PORTA does not exist.





Figure 3: Register Summary for I/O [3]


DDRxn (Data Direction Register) selects the direction of this pin.


For reading data from register, you can simple use PINx register.

The PORTxn register has different properties according to the pin is input or output. From figure 3, you can see how things change based on pin situation and PORTxn value.


Figure 4: Port Pin Configuration [4]

If you want to learn more information about ATmega328P, you should read datasheet (section 18.3).

For simulating this lecture, you need to build the following circuit in Proteus. Also, I will share all source and project files.


Figure 5: Circuit Schematic for Lecture-1


Printing ‘Hello World’ on a screen is probably first program that every programmer writes. In embedded world, blinking a led is the first step into embedded programming.


#include <avr/io.h>
#include <util/delay.h>
int main(void)
    DDRB |= 0xFF; // All PORT-B is configured as an output
    while (1) {
        PORTB |= 0x01; // PINB0 is configured as a high
        _delay_ms (500); // wait 500ms 
        PORTB = 0x00; // PINB0 is configured as a low
        _delay_ms (500); // wait 500ms
    return 0;

The main of the example is that blinking the led every 500ms. Because of these reason, the io and delay libraries are included. The io library is about input-output operations and the delay library is about delay.

DDRB is register that controls the port-B pins are output or input. As mentioned in the beginning of the tutorial, if ‘1’ is written to that register, the pin becomes output. Otherwise, it is configured as an input. We must define the pins as output because, we want to control the LEDs. This means that we control the voltage that goes to LEDs.


As you know, there are 8 pins in Port-B. By writing ‘0xFF’ to PORTB register, all port-B pins are configured as output. Instead of writing ‘0xFF’, we can write ‘0b11111111’ or ‘255’.

‘DDRB |= 0xFF;’, ‘DDRB |= 0b11111111;’, ‘DDRB |= 255’ are same.

In the ‘while (1)’ loop, the ATmega328P will blink the led and waits for 500ms then, turn off the led and waits for 500ms. There are 8 pins in port-B and the LED that is connected to the least significant pin (PINB0) is used. To turn on the LED, we need to write ‘1’ to the PINB0 pin and to turn off the LED, we need to write ‘1’ to the PINB0 pin. These delay function is used for delaying next operation. Thus, LED blinks every 500ms.


Figure 6: Output of the First Example


Figure 7: Oscilloscope Output for First Example

According to the oscilloscope result, the LED blinks every 500ms. The high duration is 500ms and low duration is 500ms in PINB0 pin.