// PULSIN.C (CCS Info - PIC16F84) // // Implements equivalent of BASIC Stamp PULSIN command. // // Illustrates use of TMR0 and external interrupt. // // In function pulse_0, the external interrupt on RB.0 is configured for // interrrupt on negative edge, TMR0 is set to zero and T0 interrupt is // enabled. If 256 roll overs of TMR0 occur (65536 * 2 usec) with no // external interrupt, the overflow flag is set and 0x0ffff is returned. // The interpretation is that no negative edge going signal was present // over the nominal 130 ms. // // If, however, an external interrupt occurs prior to "overflow", a "fall // detected" flag is set, the external interrupt is reconfigured for // interrupt on postive edge, and the timing process begins again. If // the timer overflows, the value 0xffff is returned. The interpretation // is that no postive edge occurred. // // If, however, an external interrupt occurs (int_ocurred & fall_detected), // the number of number of roll overs of TMR0 and the current value of TMR0 // is returned. This multiplied by 2 usecs is the width of the negative // pulse. // // Function pulse_1, is similar in concept except the external interrupt is // first configured for rising and then falling. I opted to use a separate // flag "rise_detected" for clarity. // // copyright, Peter H. Anderson, Scotland Co, NC, Mar, '99. // NOT VERIFIED #case #include <16f84.h> #include <defs_f84.h> #include <string.h> long pulse_0(void); long pulse_1(void); // delay routines void delay_ms(long t); void delay_10us(int t); // LCD routines 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); #define TxData 0 // RA.0 - interface to serial LCD // global declarations short int overflow, ext_int_occurred, fall_detected, rise_detected; int count_hi, count_lo; void main(void) { long t; char s[5]; lcd_init(); t = pulse_0(); // measure width of a zero pulse on RB.0 strcpy(s, "t_0="); // and display via serial LCD on RA.0 out_RAM_str(s); lcd_hex_byte((int)((t>>8)&0xff)); lcd_hex_byte((int)t&0xff); lcd_new_line(); t = pulse_1(); // measure width of a one pulse on RB.0 strcpy(s, "t_1="); // and display out_RAM_str(s); lcd_hex_byte((int)((t>>8)&0xff)); lcd_hex_byte((int)t&0xff); lcd_new_line(); while(1) // endless loop { #asm CLRWDT #endasm } } long pulse_0(void) { overflow=FALSE; ext_int_occurred=FALSE; fall_detected=FALSE; t0cs=0; // clock psa=0; // prescale assignment ps2=0; ps1=0; ps0=0; // prescale 1:2 count_hi=0; trisb0=1; // make RB0 an input intedg=0; // ext int on falling edge t0if = 0; intf=0; TMR0 = 0; // fire up the timer inte = 1; t0ie = 1; while(1) { #asm CLRWDT #endasm if (overflow || ext_int_occurred) // for the moment turn off ints { while(gie) { gie=0; } } if (overflow) // if overflow, return 0xffff { inte=0; t0ie = 0; // housekeeping return(0xffff); } if (ext_int_occurred && !fall_detected) // fall was detected { TMR0=0; count_hi=0; intedg=1; // now interrupt on rising edge intf=0; ext_int_occurred=FALSE; overflow=FALSE; // perhaps not really necessary fall_detected = TRUE; gie=1; } if (ext_int_occurred && fall_detected) // rise was detected { inte=0; t0ie=0; return((count_hi << 8) | count_lo); } } } long pulse_1(void) { overflow=FALSE; ext_int_occurred=FALSE; rise_detected=FALSE; t0cs=0; // clock psa=0; // prescale assignment ps2=0; ps1=0; ps0=0; // prescale 1:2 count_hi=0; trisb0=1; // make RB0 an input intedg=1; // ext int on rising edge t0if = 0; intf=0; TMR0 = 0; // fire up the timer inte = 1; t0ie = 1; while(1) { #asm CLRWDT #endasm if (overflow || ext_int_occurred) // for the moment turn off ints { while(gie) { gie=0; } } if (overflow) // if overflow, return 0xffff { inte=0; t0ie = 0; // housekeeping return(0xffff); } if (ext_int_occurred && !rise_detected) // rise was detected { TMR0=0; count_hi=0; intedg=0; // now interrupt on falling edge intf=0; ext_int_occurred=FALSE; overflow=FALSE; // perhaps not really necessary rise_detected = TRUE; gie=1; } if (ext_int_occurred && rise_detected) // fall was detected { inte=0; t0ie=0; return((count_hi << 8) | count_lo); } } } #int_rtcc rtcc_handler(void) { ++count_hi; if (count_hi == 0) { overflow = TRUE; } } #int_ext ext_int_handler(void) { count_lo = TMR0; // get the low byte ext_int_occurred = TRUE; } #int_default default_handler(void) { } 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); }