- Code: Select all
// 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);
}
- Code: Select all
; PULSIN.ASM
;
; Illustrates an implementation of the Basic Stamp's PULSIN command.
;
; Subroutine PULSE_0 measures the amount of time between the falling
; edge of a pulse on RA.2 to the next rising edge. The amount of time
; is returned to the calling program in TICK_H and TICK_L where the count
; is the number 5 usecs. Thus, times of up to 327 msecs (65534 * 5 usecs)
; may be measured.
;
; A value of FFFFH is returned if a falling edge was not found within
; 327 msecs or the zero time was greater than 327 msecs.
;
; On entry into into the PULSIN_0 routine, the program loops to ZERO
; until the input goes high. It then loops in ONE until the input goes
; to zero. At EDGE_0, the program then loops until the input again goes
; positive.
;
; The timing from EDGE_0 to EDGE_1 is accomplished by counting the
; number of passes through the loop, each pass being 5 usecs.
;
; However, after 256 passes, there is some additional time associated
; with incrementing the high byte (TICK_H).
;
; This program simply calls PULSIN_0. It does nothing with TICK_H and
; TICK_L.
;
; Note that a very similar routine could be developed for determining
; the amount of time a pulse is at a logic one. This gives the developer
; the capability of then measuring the period.
;
; copyright, H. Paul Roach, Baltimore, MD, Feb, '98
LIST p=16f84
#include <c:\mplab\p16f84.inc>
__CONFIG 11h
CONSTANT VARS=0CH
TICK_L EQU VARS+0 ; amount of time in 5 usecs counts
TICK_H EQU VARS+1
ORG 000H
BSF STATUS, RP0
BSF TRISA, 2 ; make RA2 (terminal 1) an input
BCF STATUS, RP0
MAIN:
CALL PULSIN_0
GOTO MAIN
PULSIN_0:
ZERO:
CLRF TICK_H
CLRF TICK_L
ZERO_1: ; if at logic zero loop
BTFSC PORTA, 2
GOTO ONE
INCFSZ TICK_L, F
GOTO ZERO_1
INCFSZ TICK_H, F
GOTO ZERO_1
GOTO PULSIN_0_OVR_FLOW
ONE: ; at logic one, wait for transition
CLRF TICK_H
CLRF TICK_L
ONE_1:
BTFSS PORTA, 2
GOTO EDGE_0
INCFSZ TICK_L, F
GOTO ONE_1
INCFSZ TICK_H, F
GOTO ONE_1
GOTO PULSIN_0_OVR_FLOW
EDGE_0: ; 1 to 0 transition occurred
CLRF TICK_H
CLRF TICK_L
EDGE_0_1:
BTFSC PORTA, 2 ; 2 ~ this is the 5 usec time loop
GOTO EDGE_1 ;
INCFSZ TICK_L, F ; 1~
GOTO EDGE_0_1 ; 2 ~
INCFSZ TICK_H, F
GOTO EDGE_0_1
GOTO PULSIN_0_OVR_FLOW
EDGE_1:
RETURN
PULSIN_0_OVR_FLOW: ; fill TICK_H and TICK_L with FFFFH
MOVLW 0FFH
MOVWF TICK_H
MOVWF TICK_L
RETURN
END
Link: PULSIN C code for PIC16F84A
Link: PULSIN AMS code for PIC16C84
