megaAVR® Oscillator Example Project

Last modified by Microchip on 2023/11/10 11:09


This page provides a simple project demonstrating dynamic adjustment of the System Clock Frequency via modification of the System Clock Prescaler Register (CLKPR) on megaAVR® devices. The code example runs on the ATmega328PB MCU.

The System Clock Source is set via configuration fuse bits to be the external 16MHz clock provided by the mEDBG chip (see connection diagram below).

The project configures the Timer/Counter1 module to operate in Clear-Timer-On-Compare (CTC) mode, and, on a period match, generates a tick interrupt every 100 mS. The timer clock source is configured to be SYS_CLK/64.

The Timer/Counter1 ISR toggles LED0, and increments a Counter. The main program loop monitors the Counter value and updates CLKPR value every 10 seconds to dynamically change the SYS_CLK frequency.

CLKPR is toggled between div/1 and div/4 setting, thereby changing the toggle (interrupt) interval from 100 ms to 400 mS respectively. This can be seen as the LED0 blink rate changes every 10 seconds.

Review the project's main.c file for further detailed comments and a description of the operation.

Back to top

Reference Material

ATmega328PB Xplained Mini

Back to top

Connection Diagram

The mEDBG chip controls the programming/debug interface, as well as supplying a 16 MHz clock when the Xplained board is connected via USB cable to a PC.

Connection Diagram

Back to top


Attach the ATmega328PB Xplained Mini board

Using a USB-A-male-to-Micro-B-male cable, attached the Xplained Mini to your computer. Start MPLAB X IDE®. If the board has been successfully enumerated, you should see the board image come up in Studio as shown in the accompanying image.


Create a New Project

In MPLAB X IDE, select File > New Project.

Choose Project

Select Microchip Embedded and then Standalone Project and then select Next.

Standalone Project selection


Select Device

Use the pulldown or type into the boxes to indicate the Family,  ATmega328PB, and Tool. Then Select Next.

Device Selection Dialog


Select Compiler

Select the XC8 Compiler and then Next.

Compiler Selection Dialog


Name the Project

Choose a name for the project, browse to a location to save it, and select Finish.

Project Name Dialog Box


Create a New main.c file

Right-click on Source Files in the file explorer window and select New > avr-main.c and rename the File Name to main.  Then select Finish.

New mail.c dialog box


Add the Code

Delete the contents of the newly created main.c file. Copy and Paste the following code into it.

 * File:  main.c
 * Project:  8avr-mega-oscillator-example
 * Description: Timer/Counter1 ISR used to toggle LED0, and increment a Counter.
 *    Main loop monitors the Counter. CLKPR is updated Every 10 sec
 *    to dynamically change the SYS_CLK frequency.
 *    CLKPR is toggled between div/1 and div/4 setting, which changes
 *    the toggle from 100ms to 400mS respectively.
 * Date:  22-Aug-2017
 * Revision:
 * Author:
 * Hardware: ATmega328PB Xplained Mini PCB Rev 3
 *    Clock:  16MHz (External - from EDBG IC)
 *    LED0:  PB5
 *    SW0:  PB7
 * Fuses:  (Programmed in Atmel Studio)
 *    NOTE: Target ATmega328PB CKSEL fuse bits are unchangeable on the
 *    Xplained Mini board within Atmel Studio.
 *    Ext:  0xFC
 *    High:  0xDF
 *    Low:  0xC0 (EXT CLK, Fast VDD rise, CLKDIV = 1)

#include <stdint.h>    // Std integral type definitions
#include <avr/io.h>    // SFR definitions
#include <avr/interrupt.h>  // ISR macros

#define LONG_TOGGLE_DURATION 25 // 10 second delay @ 400mS tick
#define SHORT_TOGGLE_DURATION 100 // 10 second delay @ 100mS tick

#define CLKPR_DIV_1  0x00 // CLKPR values
#define CLKPR_DIV_2  0x01
#define CLKPR_DIV_4  0x02
#define CLKPR_DIV_8  0x03
#define CLKPR_DIV_16 0x04
#define CLKPR_DIV_32 0x05
#define CLKPR_DIV_64 0x06
#define CLKPR_DIV_128 0x07
#define CLKPR_DIV_256 0x08

// variables used by main loop to track when to switch CLKPR value
enum {SHORT, LONG} toggleDurationState = SHORT;
volatile uint8_t toggleCounter = 0;
uint8_t toggleDurationTripThreshold = SHORT_TOGGLE_DURATION;

// CLKPR update function signature
void clkPrescaleSet(uint8_t divisionFactor);

// Define An Interrupt Handler for TIMER1_COMPA Interrupt (Nesting Disabled)
PORTB ^= (1<<PORTB5);  // Toggle LED0 (PB5)
toggleCounter++;   // Increment counter

int main(void)
   // Set up Timer/Counter1
   TCCR1B |= (1 << WGM12);   // Configure timer 1 for CTC mode
   OCR1A = 25000;     // Set CTC compare value to 10Hz (100mS) at
        // 16MHz AVR clock , with a prescaler of 64
   TIMSK1 |= (1 << OCIE1A);  // Enable CTC interrupt
   TCCR1B |= ((1 << CS10) | (1 << CS11)); // Start Timer/Counter1 at F_CPU/64

   // Set LED as output
   DDRB |= (1<<PORTB5);   // Configure PB5 as digital output
   PORTB &= ~(1<<PORTB5);   // Set initial level for PB5
// enable interrupts

while (1)
  case SHORT:
  if(toggleCounter >= toggleDurationTripThreshold){
   toggleCounter = 0;
   toggleDurationTripThreshold = LONG_TOGGLE_DURATION;
   toggleDurationState = LONG;
  case LONG:
  if(toggleCounter >= toggleDurationTripThreshold){
   toggleCounter = 0;
   toggleDurationTripThreshold = SHORT_TOGGLE_DURATION;
   toggleDurationState = SHORT;

void clkPrescaleSet(uint8_t divisionFactor){
cli();      // disable interrupts
CLKPR = (1<<CLKPCE);  // enable change of the CLKPSx bits
CLKPR = divisionFactor;  // update the CLKPSx bits
sei();      // re-enable interrupts
Program the Device

At the top of the MPLAB X IDE, select the Make and Program device button.

Programl the Device

Observe the Results

LED0 will light at a fixed frequency which will change every 10 seconds.

Xplained Mini Oscillator Example Resulats


This project has provided an example of how to dynamically adjust the system clock frequency on the megaAVR® MCU.

Back to top

Learn More

Back to top