PIC C, Use of TMR0 Interrupt


Overview

These routines illustrate various uses of the TMR0 and External interrupts.

Program TMR0_1.C uses TMR0 to provide 1 ms timing so as to generate a 500 Hz tone and also flash an LED on and off with a period of 8 seconds.

Program TMR0_2.C expands this to also toggle another LED in response to an interrupt on RB.0.

Program TMR0_3.C counts the number of events appearing on RB.0 over a one second period and displays the result on a serial LCD.


// Program TMR0_1.C (CCS PCM, PIC16F84)
//
// Configuration.  LED on RB.3. Speaker through capacitor on RB.2
//
// Illustrates use of TMR0 to time for 1 ms.  Generates 500 Hz tone on
// speaker on RB.2 and continually flashes LED on RB.3 on for 4 secs
// and off for 4 seconds.
//
// Note that TMR0 is configured for CLOCK, assigned to OSC, prescale
// by 4.  Thus, 1.00 MHz / 4 = 250 KHz.  Period = 4 usecs.  Thus, TMRO
// is loaded with the twos comp of 250 to achieve interrupt timing of 1 ms.
//
// Copyright, Peter H. Anderson, Georgetown, Co, SC, Mar, '99

#case
#include <16f84.h>
#include <defs_f84.h>

#define LED_FL_PIN rb3 	// RB3
#define SPKR_PIN rb2

#define LED_FL_DIR trisb3
#define SPKR_DIR trisb2

#define T_TICK (~250) + 1	// see program description

long time_count = 4000;

void main(void)
{
// turn on RBPU resistors, make SPKR_PIN and LED_FL_PIN outputs
   not_rbpu = 0;
   SPKR_DIR = 0;  // make SPKR and LED_FL outputs
   LED_FL_DIR = 0;

   LED_FL_PIN = 0;
   SPKR_PIN = 0;

// configure TMR0, CLK as source, prescale assigned to TMR0, prescale = 4
   t0cs = 0;
   psa = 0;
   ps2=0;  ps1=0;  ps0=1;

// configure interrupts, T0IE=1, GIE=1
   t0if=0;
   t0ie=1;
   gie=1;

   while(1)
   {
#asm
      CLRWDT
#endasm
   }
}

#int_rtcc rtcc_handler()
{
   TMR0 = T_TICK;		// load TMR0
   SPKR_PIN = !SPKR_PIN;

   if (--time_count==0)
   {
      LED_FL_PIN = !LED_FL_PIN;
                 // reverse LED every 4000 ms
      time_count=4000;
   }
   // note that compiler takes care of clearing interrupt flag
}

#int_default default_handler(void)
{
}


// Program TMR0_2.C (CCS PCM, PIC16F84) // // Configuration. LEDs on RB.3 and RB.1. Speaker through capacitor on // RB.2. Switch on RB.0 to force external interrupt. // // Illustrates use of TMR0 to time for 1 ms. Generates 500 Hz tone on // speaker on RB.2 and continually flashes LED on RB.3 on for 4 secs // and off for 4 seconds. // // Also reverses state of LED on RB1 when external interrupt on RB.0. // // Note that TMR0 is configured for CLOCK, assigned to OSC, prescale // by 4. Thus, 1.00 MHz / 4 = 250 KHz. Period = 4 usecs. Thus, TMRO // is loaded with the twos comp of 250 to achieve interrupt timing of 1 ms // // Copyright, Peter H. Anderson, Georgetown Co, SC, Mar, '99 #case #include <16f84.h> #include <defs_f84.h> #define LED_FL_PIN rb3 #define SPKR_PIN rb2 #define LED_EV_PIN rb1 #define EXT_INT_PIN rb0 #define LED_FL_DIR trisb3 #define SPKR_DIR trisb2 #define LED_EV_DIR trisb1 #define EXT_INT_DIR trisb0 #define IN 1 #define OUT 0 #define T_TICK (~250) + 1 // see program description long time_count = 4000; void main(void) { // turn on RBPU resistors, make SPKR, LED_FL and LED_EV outputs. // make EXT_INT an input not_rbpu = 0; SPKR_DIR = OUT; LED_FL_DIR = OUT; LED_EV_DIR = OUT; EXT_INT_DIR = IN; SPKR_PIN =0; LED_FL_PIN=0; LED_EV_PIN =0; // configure TMR0, CLK as source, prescale assigned to TMR0, prescale = 4 t0cs = 0; psa = 0; ps2=0; ps1=0; ps0=1; t0if = 0; t0ie = 1; // configure interrupts, T0IE=1 // configure for external interrupt intedg = 0; intf = 0; inte = 1; // enable interrupts and loop gie=1; while(1) { #asm CLRWDT #endasm } } #int_rtcc rtcc_handler(void) { TMR0 = T_TICK; // load TMR0 SPKR_PIN = !SPKR_PIN; if (--time_count==0) { LED_FL_PIN = !LED_FL_PIN; // reverse LED every 4000 ms time_count=4000; } // note that compiler takes care of clearing interrupt flag } #int_ext ext_int_handler(void) { // toggle LED_EV LED_EV_PIN = !LED_EV_PIN; } #int_default default_handler(void) { }


// Program TMR0_3.C // // Pulse source (such as the Morgan Logic Probe) on RB.0. Ser LCD // on RA.0. // // Counts the number of events on RB.0 over one second. // // TMR0 is used to time for 1000 ms. External interrupt is used for // counting. // // Displays count in hexadecimal on serial LCD on RA.0. // // Note that TMR0 is configured for CLOCK, assigned to OSC, prescale // by 4. Thus, 1.00 MHz / 4 = 250 KHz. Period = 4 usecs. Thus, TMRO // is loaded with the twos comp of 250 to achieve interrupt timing of 1 ms // // Copyright, Peter H. Anderson, Georgetown Co, SC, Mar, '99 #case #include <16f84.h> #include <defs_f84.h> #define EXT_INT_DIR trisb0 #define EXT_INT_PIN rb0 #define OUT 0 #define IN 1 #define T_TICK (~250) + 1 // see program description #define TxData 0 // RA.0 - interface to serial LCD // lcd routines void delay_ms(long t); void delay_10us(int t); void lcd_init(void); void out_RAM_str(int *s); void lcd_hex_byte(int val); void lcd_dec_byte(int val, int digits); int num_to_char(int val); void lcd_char(int ch); void lcd_new_line(void); void count(void); long ct, timer_count; // globals void main(void) { not_rbpu = 0; // enable PORTB pullups while(1) { timer_count = 1000; // count for 1000 ms count(); lcd_init(); lcd_hex_byte((int)(ct >> 8) & 0xff); // display a long int lcd_hex_byte((int) (ct & 0xff)); delay_ms(4000); } } void count(void) { // note that timer_count and ct are globals // timer_count is the time to count // ct is the count over this time ct = 0; // configure TMR0 t0cs=0; // use CLK as source psa=0; // use OSC clock ps2=0; ps1=0; ps0=1; // prescale by 4 t0if = 0; // clear any existing interrupt t0ie = 1; // configure external interrupt EXT_INT_DIR = IN; intedg = 0; intf = 0; inte = 1; // gie = 1; while(timer_count) // wait until timer_count is decremented to zero { #asm CLRWDT #endasm } inte=0; t0ie=0; while(gie) // turn off GIE and be sure they are off { gie=0; } } #int_rtcc rtcc_handler(void) { TMR0 = T_TICK; // load TMR0 --timer_count; // decrement global timer_count t0if=0; // clear flag - not sure if necessary } #int_ext ext_int_handler(void) { ++ct; intf = 0; // not usure if necessary } #int_default default_handler(void) { } // delay routines void delay_10us(int t) { #asm BCF STATUS, RP0 DELAY_10US_1: CLRWDT NOP NOP NOP NOP NOP NOP DECFSZ t, F GOTO DELAY_10US_1 #endasm } void delay_ms(long t) // delays t millisecs { do { delay_10us(100); } while(--t); } // LCD Routines int num_to_char(int val) // converts val to hex character { int ch; if (val < 10) { ch=val+'0'; } else { val=val-10; ch=val + 'A'; } return(ch); } void lcd_char(int ch) // serial output to PIC-n-LCD, 9600 baud { int n, dly; // start bit + 8 data bits #asm BCF STATUS, RP0 MOVLW 9 MOVWF n BCF STATUS, C LCD_CHAR_1: BTFSS STATUS, C BSF PORTA, TxData BTFSC STATUS, C BCF PORTA, TxData MOVLW 32 MOVWF dly LCD_CHAR_2: DECFSZ dly, F GOTO LCD_CHAR_2 RRF ch, F DECFSZ n, F GOTO LCD_CHAR_1 BCF PORTA, TxData CLRWDT MOVLW 96 MOVWF dly LCD_CHAR_3: DECFSZ dly, F GOTO LCD_CHAR_3 CLRWDT #endasm } void lcd_init(void) // sets TxData in idle state and resets PIC-n-LCD { #asm BCF STATUS, RP0 BCF PORTA, TxData BSF STATUS, RP0 BCF TRISA, TxData BCF STATUS, RP0 #endasm lcd_char(0x0c); delay_ms(250); } void lcd_new_line(void) // outputs 0x0d, 0x0a { lcd_char(0x0d); delay_ms(10); // give the PIC-n-LCD time to perform the lcd_char(0x0a); // new line function delay_ms(10); } void out_RAM_str(int *s) { while(*s) { lcd_char(*s); ++s; } } void lcd_hex_byte(int val) // displays val in hex format { int ch; ch = num_to_char((val>>4) & 0x0f); lcd_char(ch); ch = num_to_char(val&0x0f); lcd_char(ch); } void lcd_dec_byte(int val, int digits) // displays byte in decimal as either 1, 2 or 3 digits { int d; int ch; if (digits == 3) { d=val/100; ch=num_to_char(d); lcd_char(ch); } if (digits >1) // take the two lowest digits { val=val%100; d=val/10; ch=num_to_char(d); lcd_char(ch); } if (digits == 1) // take the least significant digit { val = val%100; } d=val % 10; ch=num_to_char(d); lcd_char(ch); }