Nerdegutta's logo

nerdegutta.no

PIC16F690 - Day 2: Input Handling (Button Input)

29.07.25

Embedded

Day 2: Input Handling (Button Input)



Goal: Read a button input connected to RA3. Toggle an LED on RB0 when the button is pressed.

Hardware: Button with 10k pull-down resistor on RA3 (active HIGH when pressed). LED with resistor on RB0

Concepts: Input configuration with TRISx

Digital input logic
Debouncing (basic)
Two methods:
Polling the input in the main loop.
Using PORTB Change Interrupt (RB4–RB7 only, so we simulate interrupt on a supported pin) 🔹 Code 1: Polling Method (RA3 button → RB0 LED)
#define _XTAL_FREQ 4000000

#include < xc.h > // Remove extra spaces

// CONFIG
#pragma config FOSC = INTRCIO   // Internal oscillator
#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) {
    TRISA3 = 1;   // RA3 as input
    TRISB0 = 0;   // RB0 as output

    ANSEL = 0;    // Disable analog on PORTA
    ANSELH = 0;
    PORTB = 0;

    while(1) {
        if (RA3 == 1) {      // Button pressed (active high)
            RB0 = 1;         // Turn on LED
        } else {
            RB0 = 0;         // Turn off LED
        }
        __delay_ms(20);      // Simple debounce
    }
}
Code 2: Interrupt-on-Change (IOC) on RB4 (simulate same logic)
Since PORTA doesn't support interrupts, we use RB4 instead.

Button on RB4, LED on RB0. Button press toggles LED (state remembered).
#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 led_state = 0;

void __interrupt() isr(void) {
    if (RBIF) {
        // Simple debounce wait
        __delay_ms(20);

        if (RB4 == 1) {
            led_state ^= 1;       // Toggle state
            RB0 = led_state;      // Apply to LED
        }

        // Clear interrupt flag
        RBIF = 0;
    }
}

void main(void) {
    TRISB4 = 1;   // RB4 input (button)
    TRISB0 = 0;   // RB0 output (LED)
    
    ANSEL = 0;
    ANSELH = 0;
    PORTB = 0;

    // Enable IOC on PORTB
    IOCB4 = 1;    // Enable interrupt on change for RB4

    // Enable interrupts
    INTCONbits.GIE  = 1;
    INTCONbits.PEIE = 1;
    INTCONbits.RBIE = 1;
    INTCONbits.RBIF = 0;

    while(1) {
        // Main loop does nothing; ISR handles the toggle
    }
}