Pulse width Measurement, Square Wave Generation, and External

advertisement
Pulse width Measurement, Square Wave Generation, and External
Interrupts (on RB0)
Dr. Abdel-Rahman Jaradat
In this lab session we will address three topics:
1. We want to measure the ON time in a square wave (or the positive pulse duration). The following CCS program
will do the required as follows: read RA0 and wait while it is zero ’OFF’, when it is one (ON) start TMR0,
and while it is one (ON) wait till it becomes zero (OFF) and read TMR0. Number of ’ticks’ multiplied by the
prescaler times MC (machine cycle) will give the ON time of the signal.
In the lab we want to measure the ON time for a 1 KHz square wave (be careful to adjust the square wave to
be between 0 and 5 Volts by using the oscilloscope) and connect it to RA0. We took the prescaler value P = 16
and hence every tick will take 8 times MC=16 µs. For an ON time of approximately half a milli-second (500
µs) TMR0 will count 500
16 = 31.25 ticks (≈ 31) ticks.
/*
PW_TMR0.c
Use TMR0 to measure pulse duration. Input pulse applied to RA0.
From Start when LOW-to-HIGH (0->1) and Stop when HIGH-to-LOW (1->0)
Ref. Smith pg189
*/
#include "16f84a.h"
#use delay (clock=4000000) // 4MHz crystal
#fuses XT, NOWDT, NOPUT, NOPROTECT
void main()
{
int x;
set_tris_A(0x1); // pin RA0 as input
set_tris_B(0x0); // pins RB7:RB0 output
setup_timer_0(RTCC_DIV_16|RTCC_INTERNAL); // presacaler=16, Use internal clock
while(1)
{
while (!input(PIN_A0)); // wait for A0 to go high
set_timer0(0);
// init timer0 to 0
while (input(PIN_A0)); // wait for A0 to go low
x=get_timer0();
output_B(x);
// display PW in micro seconds times prescaler (=16)
// if prescaler = 256, then every tick approximately = 0.25 millisecond
}
}
When using Oshon simulator, inject a square wave on RA0 (signal generator assigned to pin RA0) and put the
period to be 1000 µs (for 1 KHz the period=1ms=1000 µs) which corresponds to 4MHz
1000 = 4000 (crystal) clock
cycles and enter the duty cycle as 50.
1
2. Configure portB as o/p and connect it to 8-leds. We want to display the binary representations of the numbers
0, 1, 2, · · ·, 255 on portB with separated in 1 second time interval. Use 16F84A and 4 MHz xtal.
fosc = 4M Hz → Tosc = 14 µsec → machine cycle (MC) = 4* Tosc = 1µs. For a prescaler of 1, P = 1, the
Time-Out (TO) occurs after 256 × M C = 256µs.
6
µs
1s
To number of Time-Outs that we need to reach 1 s = 256µs
= 10
256µs = 3906. This number is much more than
255 which is the limit that can fit in 8-bit register.
The only way to go around this is to use a prescaler value bigger than 1. Try to use P=256 (which the largest
106
= 15.259 which can easily fit in an
possible value for prescaler), then the number of Time-Outs TOs= 256×256
8-bit register.
The following CCS program will ’tick’ every (Tick Time) T T = M C × 256 = 256µs and a TO every T T × 256 =
65536µs and hence we need 106 /65536 = 15.259 to reach one second.
/*
tick_per_second.c
fosc=4MHz, RTCC_DIV_256 (max. value),
TMR0 increments at a rate=(4000000/4)/256=3906.25 increments per second
10**6/256=3906.25 ==> 256 us per increment.
TMR0 will interrupt every 2**8=256 counts (0,1,2,...,255)
In 1 second, there will be 3906.25/256=15.25 interrupts. Approx. set this to 15.
*/
#include "16f84a.h"
#use delay (clock=4000000) // 4MHz crystal
#fuses XT, NOWDT, NOPUT, NOPROTECT
int ctr=0;
int sec=0;
// interrupt from RTCC (=TMR0)
#int_rtcc
void timer_rtcc ()
{
ctr++;
if (ctr == 15)
// every 15 interrupts occur in 1 sec
{ sec++; ctr=0; output_b(sec); }
}
void main()
{
set_tris_B(0x0); // pins RB7:RB0 output
setup_counters(RTCC_DIV_256,RTCC_INTERNAL); // presacaler=256, Use internal clock
enable_interrupts(INT_RTCC);
enable_interrupts(GLOBAL);
while(1);
// repeat always
}
3. Write a program to generate 1kHz square wave on RA0. Display the output on the scope.
// generate 1kHz square wave
#include "16f84a.h"
#use delay (clock=4000000) // 4MHz crystal
main(){
set_tris_a(0x00); // pins 0 to 4 of port A are outputs
while(TRUE){
output_high(PIN_A0);
delay_us(500);
output_low(PIN_A0);
2
delay_us(500);
}
}
Modify the above program to use interrupts.
4. Use example in class for interrupt. int ext: Interrupt on RB0 when occurs write 31=b’11111’ show output on
simulator scope then on physical.
Modify your program to count number of one-to-zero changes on RB0 and display the output on RA4:RA1.
// C-Programming - Bates, page 106
// External interrupt test program
#include "16F877a.h"
#use delay (clock=4000000) // 4MHz crystal
#int_ext
void isrext() {output_D(255); delay_ms(1000);}
main(){
int x=0;
enable_interrupts(int_ext);
enable_interrupt(global);
ext_int_edge(H_TO_L);
while(1) {
output_D(x);
x++;
delay_ms(100);
}
}
5. Simulate the following Assembly language program that uses interrupts from RB0 (connect RB0 to a switch)
; xint-delay-tmr0.asm: delay using tmr0 via interrupt
#include "p16f84a.inc"
COUNT EQU 0X0C
TEMP EQU COUNT+1
LIST P=16F84 ; we are using the 16F84.
ORG 0x0
GOTO START
;**********************************************************************
; Configuration Bits
__CONFIG _CP_OFF & _WDT_OFF & _PWRTE_ON & _XT_OSC ;H’3FF1’
;*********************************************************
;RB0 Interrupt Initialization
;In order to initialize the RB0 interrupt, the following operations must take place:
;1. Port-B, line 0, must be initialized for input.
;2. The interrupt source must be set to take place either on the falling or the rising edge of the
; signal by set or reset of INTEDG=OPTION_REG bit 6.
;3. The external interrupt flag (INTF in the INTCON Register) must be initially cleared.
;4. Global interrupts must be enabled by setting the GIE bit in the INTCON Register.
;5. The External Interrupt on RB0 must be enabled by setting the INTE bit in the INTCON Register.
;The following code fragment, from the program RB0Int in Sanchez and Canton, performs these operation
;=============================
; interrupt handler STARTS FROM LOCATION 0X04
;=============================
org 0x04
goto IntServ
;=============================
; main program
3
;=============================
START
; SETUP INTERRUPT REGISTER: INTCON IS IN BOTH BANKS 0 AND 1
BSF INTCON,GIE
BSF INTCON,INTE ; ENABLE INT/EXT FROM RB0
BCF INTCON,INTF ; CLR FLAG BIT ... JUST IN CASE
;SETUP PORTA AND PORTB DIRECTIONS
BSF STATUS,RP0 ; TO BANK 1
MOVLW 0X01
MOVWF TRISB ; RB0 AS INPUT
MOVLW 0X10
MOVWF TRISA ; RA3,RA2,RA1,RA0 AS INPUT
; Set up interrupt on rising edge by setting OPTION register bit INTEDG (BIT 6)
BSF OPTION_REG,INTEDG
BCF STATUS,RP0 ; BANK 0
LOOP
MOVF COUNT,W ; W <- COUNT
MOVWF PORTA ; PORTA <- COUNT
GOTO LOOP ; REPEAT FOREVER
SLEEP
;RB0 Interrupt Service Routine
;The Service Routine for the RB0 interrupt depends on the specific application. Nevertheless,
;the following processing steps should be considered:
;1. Determine if the source of interrupt is an RB0 interrupt.
;2. Clear the RB0 interrupt flag (INTF bit) in the INTCON Register.
;3. Save the context. Which registers and variables need to be saved depends on the specific applicat
;4. Perform the interrupt action.
;5. Restore the context.
;6. Return from the interrupt with the retfie instruction.
;=======================================================
; Interrupt Service Routine
;=======================================================
; Service routine receives control whenever RB0 change state
IntServ
MOVWF TEMP ;SAVE W TILL WE RETURN FROM INTERRUPT
INCF COUNT,F ; COUNT <- COUNT+1
MOVLW 0X0A ; W <- 10
SUBWF COUNT,W ; W <- COUNT-W
BTFSS STATUS,C; CHECK CARRY BIT
GOTO CARRY_ON ; COUNT < 10
GOTO CLEAR ; COUNT > 9 ... CLEAR IT
CARRY_ON
BCF INTCON,INTF ; ENABLE MORE INTERRUPTS
MOVF TEMP,W ;RESTORE W BEFORE INTERRUPT
retfie ; RETURN FROM INTERRUPT
;
CLEAR
CLRF COUNT ; COUNT <- 0
BCF INTCON,INTF
RETFIE ; RETURN FRON INTERRUPT
END
Modify the pulse width measurement to use external interrupt on RB0 and measure the period of a square wave
4
Download