ATmega8A Register-3 LED Blink with Button

ATmega8A Complete Programming Guide: Direct Port Register, LED Blink & Button Input

Complete ATmega8A Microcontroller Programming Guide

Key Takeaway: The ATmega8A is an 8-bit AVR microcontroller perfect for learning direct port register programming. This guide covers everything from programming setup with Arduino Uno as ISP through 3 progressively complex LED blink examples, giving you bare-metal control over the hardware.

1. Programming the ATmega8A with an Arduino Uno

The ATmega8A microcontroller can be programmed using an Arduino Uno board as an In-System Programmer (ISP). This is the most cost-effective way to get started because you do not need a dedicated programmer — if you already have an Arduino Uno, you have everything you need.

Step 1: Set Up Arduino as ISP

Open the Arduino IDE. Navigate to File > Examples > ArduinoISP and upload the ArduinoISP sketch to your Uno board. This turns the Uno into a programmer that can burn bootloaders and upload code to other AVR chips.

Step 2: Wiring Connections

Connect the Arduino Uno to the ATmega8A as follows: Arduino D10 (SS) to ATmega8A PB2 (Reset), D11 (MOSI) to PB3, D12 (MISO) to PB4, D13 (SCK) to PB5, 5V to VCC, and GND to GND. Add a 10k pull-up resistor from Reset to VCC.

Step 3: Configure Arduino IDE

Go to Tools > Board > Boards Manager and install the ATmega8 core. Select Tools > Board > ATmega8A, choose the correct clock speed (8 MHz internal or 16 MHz external), and select Tools > Programmer > Arduino as ISP.

Unlike Arduino’s digitalWrite(), direct register access gives you precise control with minimal overhead. On the ATmega8A, Port B controls pins PB0-PB5. The three key registers are:

  • DDRB: Data Direction Register — sets pins as input (0) or output (1)
  • PORTB: Data Register — sets output HIGH (1) or LOW (0)
  • PINB: Input Pins — reads the current state
#include <avr/io.h>
#include <util/delay.h>

int main(void) {
    DDRB |= (1 << PB0);  // Set PB0 as output
    while (1) {
        PORTB |= (1 << PB0);   // PB0 HIGH
        _delay_ms(500);
        PORTB &= ~(1 << PB0);  // PB0 LOW
        _delay_ms(500);
    }
}

3. Multiple LEDs with Direct Port Access

Direct port manipulation really shines when controlling multiple pins. A single register write can set or clear several outputs at once.

#include <avr/io.h>
#include <util/delay.h>

int main(void) {
    DDRB = 0b00111111;  // PB0-PB5 as outputs
    while (1) {
        PORTB = 0b00111111;  // All ON
        _delay_ms(300);
        PORTB = 0b00000000;  // All OFF
        _delay_ms(300);
        for (int i = 0; i < 6; i++) {
            PORTB = (1 << i);  // Running LED
            _delay_ms(150);
        }
    }
}

4. Button-Controlled LED

Reading inputs with direct register access uses PINB. Enable the internal pull-up resistor by setting the PORTB bit for the input pin.

#include <avr/io.h>
#include <util/delay.h>

int main(void) {
    DDRB |= (1 << PB0);      // PB0 output (LED)
    DDRB &= ~(1 << PB1);     // PB1 input (button)
    PORTB |= (1 << PB1);     // Pull-up on PB1
    uint8_t last = 1;
    while (1) {
        uint8_t cur = PINB & (1 << PB1);
        if (last && !cur) { PORTB ^= (1 << PB0); _delay_ms(50); }
        last = cur;
    }
}

Advantages of Direct Port Register Programming

  • Speed: Register ops execute in 1-2 clock cycles vs dozens for digitalWrite()
  • Atomic: Change multiple pins simultaneously in one write
  • Code size: Much smaller — critical for limited flash memory
  • Precision: Deterministic timing essential for bit-banging protocols

Frequently Asked Questions

What is the difference between DDRB, PORTB, and PINB?

DDRB sets pin direction (input/output). PORTB sets output value or enables pull-ups. PINB reads the current logic state of input pins.

Can I use Arduino functions after ISP programming?

Only if you burn the Arduino bootloader first. Programming as ISP target requires bare-metal AVR C/C++ — no Arduino functions available.

What external components does the ATmega8A need?

A 10k pull-up on Reset, 100nF decoupling capacitor near VCC, and either a 16 MHz crystal with 22pF caps or use the internal 8 MHz oscillator. Add 220-470 ohm resistors in series with LEDs.

How do I set ATmega8A fuses for clock speed?

Use avrdude or Arduino IDE Burn Bootloader. For 8 MHz internal: Low Fuse 0xE4. For 16 MHz external crystal: Low Fuse 0xFF. Incorrect fuses can lock you out of the chip.

Is the ATmega8A good for real-time control?

Yes. At 16 MHz it executes up to 16 MIPS, making it suitable for motor control, sensor reading, and simple closed-loop systems. Direct register access ensures deterministic timing.

External Resources

Sources: Microchip ATmega8A Datasheet, Arduino ISP Documentation, AVR Libc Reference

ATmega8A Register-3 LED Blink with Button

Leave a Reply