Nerdegutta's logo

nerdegutta.no

PIC16F690 - Day 6: Precision Timing with Timer1

26.11.25

Embedded

Goal:

Use Timer1, a 16-bit timer, for more precise and longer timing than Timer0. We’ll toggle an LED every 1 second using:

Hardware:

LED on RB0

Concepts:

Timer1: 16-bit timer (counts 0–65535), can use internal or external clock. So:
Code 1: Polling Timer1 for 1s LED Blink
#define _XTAL_FREQ 4000000
#include < xc.h >
#include < stdint.h >

// 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 timer1_init(void) {
    T1CON = 0b00110001;  // Timer1 ON, 1:8 prescale
    TMR1 = 0;            // Clear timer
}

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

    timer1_init();

    uint8_t overflow_count = 0;

    while (1) {
        if (PIR1bits.TMR1IF) {  // Timer1 overflow flag
            PIR1bits.TMR1IF = 0;
            overflow_count++;

            if (overflow_count >= 2) {  // ~1 sec
                RB0 = !RB0;
                overflow_count = 0;
            }
        }
    }
}
Code 2: Using Timer1 with Interrupt
#define _XTAL_FREQ 4000000
#include < xc.h >
#include < stdint.h >

// 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 t1_overflows = 0;

void __interrupt() isr(void) {
    if (PIR1bits.TMR1IF) {
        PIR1bits.TMR1IF = 0;
        t1_overflows++;

        if (t1_overflows >= 2) {
            RB0 = !RB0;
            t1_overflows = 0;
        }
    }
}

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

    // Timer1 setup
    T1CON = 0b00110001;     // TMR1 ON, 1:8 prescaler
    TMR1 = 0;
    TMR1IE = 1;             // Enable Timer1 interrupt
    PEIE = 1;               // Peripheral interrupt
    GIE = 1;                // Global interrupt

    while (1) {
        // Main loop idle – ISR handles timing
    }
}