nerdegutta.no
PIC16F690 - Day 5: Combined Interrupts – Timer0 + Button Input
10.08.25
Embedded
Goal:Learn to combine multiple interrupts:
Use Timer0 to blink an LED (every 500 ms)
Use RB4 input to toggle whether the blinking is enabled
Hardware:LED on RB0
Button on RB4 (with pull-down resistor)
Concepts:Enabling multiple interrupts (Timer0 + PORTB Change)
Distinguishing interrupt sources inside the ISR
Debounce logic
Using a global flag to control behavior
Code 1: Timer0 LED Blink + Button Control via RB4 Interrupt
#define _XTAL_FREQ 4000000 #include < xc.h > // Remove extra spaces #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 overflow_count = 0; volatile uint8_t blinking_enabled = 1; void __interrupt() isr(void) { // Timer0 interrupt (every ~65.5ms with 1:256 prescaler) if (T0IF) { T0IF = 0; if (blinking_enabled) { overflow_count++; if (overflow_count >= 8) { // 8 * 65ms = ~520ms RB0 = !RB0; // Toggle LED overflow_count = 0; } } } // PORTB Change interrupt (RB4-RB7) if (RBIF) { __delay_ms(20); // Simple debounce if (RB4 == 1) { blinking_enabled ^= 1; // Toggle blink enable flag } RBIF = 0; // Clear interrupt-on-change flag } } void main(void) { TRISB0 = 0; // RB0 output (LED) TRISB4 = 1; // RB4 input (button) ANSEL = 0; ANSELH = 0; PORTB = 0; // Setup Timer0 OPTION_REGbits.T0CS = 0; // Internal clock OPTION_REGbits.PSA = 0; // Prescaler to Timer0 OPTION_REGbits.PS = 0b111; // 1:256 prescaler // Enable Timer0 interrupt TMR0 = 0; T0IE = 1; // Enable RB change interrupt for RB4 IOCB4 = 1; RBIF = 0; RBIE = 1; // Global Interrupt Enable PEIE = 1; GIE = 1; while (1) { // Nothing to do in main; logic handled in ISR } }Code 2: Same functionality without using ISR (polling + timer flag)
#define _XTAL_FREQ 4000000 #include < xc.h > // Remove extra spaces #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 uint8_t blinking_enabled = 1; void main(void) { TRISB0 = 0; // LED output TRISB4 = 1; // Button input ANSEL = 0; ANSELH = 0; PORTB = 0; // Timer0 setup OPTION_REGbits.T0CS = 0; OPTION_REGbits.PSA = 0; OPTION_REGbits.PS = 0b111; // 1:256 TMR0 = 0; uint8_t prev_btn = 0; uint8_t overflow_count = 0; uint8_t last_timer = 0; while (1) { // Polling button if (RB4 && !prev_btn) { __delay_ms(20); // debounce if (RB4) { blinking_enabled ^= 1; // Toggle flag } } prev_btn = RB4; // Poll Timer0 if (TMR0 < last_timer) { // Overflow occurred overflow_count++; if (blinking_enabled && overflow_count >= 8) { RB0 = !RB0; overflow_count = 0; } } last_timer = TMR0; } }