Nerdegutta's logo

nerdegutta.no

PIC16F690 - Day 4: Introduction to Timers(Timer0)

09.08.25

Embedded

Goal:Learn to generate accurate delays using Timer0, comparing it with software delays.
Timer0 is an 8-bit timer with optional prescaler and interrupt support.
We'll blink an LED every ~500 ms using:
Software loop delay (baseline)
Timer0 overflow + interrupt
Hardware: LED on RB0
Concepts:
Timer0 = 8-bit counter (0–255), overflow triggers interrupt
Prescaler divides clock to slow counting
With 4 MHz clock: 1 instruction = 1 μs (since Fosc/4 = 1 MHz)

Code 1: Software Delay for LED Blink (baseline)

#define _XTAL_FREQ 4000000
#include < xc.h > // Remove extra space

// CONFIG
#pragma config FOSC = INTRCIO
#pragma config WDTE = OFF
#pragma config PWRTE = OFF
#pragma config MCLRE = OFF
#pragma config BOREN = OFF
#pragma config CP = OFF
#pragma config CPD = OFF

void main(void) {
    TRISB0 = 0;  // RB0 as output
    ANSEL = 0;
    ANSELH = 0;

    while (1) {
        RB0 = 1;
        __delay_ms(500);
        RB0 = 0;
        __delay_ms(500);
    }
}
Code 2: Blink using Timer0 Overflow Interrupt
We’ll configure Timer0 with 1:256 prescaler.
At 4 MHz, 1 tick = 1 μs → overflow every 256 × 256 = 65.536 ms.
We'll count 8 overflows ≈ 500 ms.

#define _XTAL_FREQ 4000000
#include < xc.h > // remove extra spaces
#include < stdint.h > // remove extra spaces

// CONFIG
#pragma config FOSC = INTRCIO
#pragma config WDTE = OFF
#pragma config PWRTE = OFF
#pragma config MCLRE = OFF
#pragma config BOREN = OFF
#pragma config CP = OFF
#pragma config CPD = OFF

volatile uint8_t overflow_count = 0;

void __interrupt() isr(void) {
    if (T0IF) {
        T0IF = 0;  // Clear interrupt flag
        overflow_count++;

        if (overflow_count >= 8) {
            RB0 = !RB0;  // Toggle LED
            overflow_count = 0;
        }
    }
}

void main(void) {
    TRISB0 = 0;
    ANSEL = 0;
    ANSELH = 0;
    PORTB = 0;

    OPTION_REGbits.T0CS = 0;  // Timer0 uses internal clock
    OPTION_REGbits.PSA = 0;   // Prescaler assigned to Timer0
    OPTION_REGbits.PS = 0b111; // 1:256 prescaler

    TMR0 = 0;
    T0IE = 1;  // Enable Timer0 interrupt
    GIE = 1;   // Enable global interrupts

    while (1) {
        // Main loop idle; Timer0 handles LED blinking
    }
}