PDA

View Full Version : 16F876A CCP1 Capture/Interrupt Question



TDonBass
- 15th January 2008, 01:23
Hi,
I am experimenting with using the 16F876A to measure the turn off time of a phototransistor. I have tried two ways, just to see how much difference there would be in the time. The first way is using the RB0 input to generate an interrupt, and the 2nd is using the capture feature on pin RC2/CCP1.
1st method:
1. Turn off the LED that points at the phototransistor
2. Reset the timer1 high and low bytes to zero
3. When program jumps to ISR, read value of Timer 1. Result is 204uS

2nd method:
1. Turn off the LED that points at the phototransistor
2. Reset the timer1 high and low bytes to zero
3. Poll the CCP1IF flag in a loop until it goes high, and then read the value of the CCP1 high and low byte registers. Result is 188uS, which is almost exactly the same as I measure on an oscilloscope.

With 2nd method, I had expected to do it the same way as the first... I thought program would jump to ISR when pin RC2 went high, but it did not work. So my question is, why doesn't the program jump to the Interrupt handler when the CCP1IF flag gets set? If it did then I would not need to poll the pin in a loop. Would I be doing something wrong or is that how it is supposed to work? Thanks for any answers.

paul borgmeier
- 15th January 2008, 04:52
TDon,

You leave us guessing about how you are doing everything. Show us your code or provide a crystal ball. You will get better answers with either option.

TDonBass
- 16th January 2008, 00:54
Sorry about that.
The code directly below works...that is it displays a T_off2 reading. The program waits for the CCP1 flag to set and then it jumps to the Display2 subroutine. What I wanted to have happen though, was for the program to jump to the Interrupt Handler routine and display the T_off reading. The code just below this code shows how I tried to do that, but nothing happens. In that code the instruction to jump to the Display2 subrouting is commented out. So I'm guessing that a CCP interrupt isn't supposed to make the program jump to the interrupt routine the same way that an RB0/Interrupt does... you have to do it like the first example below.
That is my question.
Thanks,
TDon

' PIC16F876A hardware connections
' PIC External
' ---- ---------
' RB1 LED Cathode
' RC2 Phototransistor Comparator Output to RC2/CCP1 pin
' ----[ Includes / Defines ]-------------------------------------------

@ DEVICE WDT_OFF
define OSC 4
include "modedefs.bas" 'include serout defines

' -----[ Variables ]-------------------------------------------------------
T_Off var Word ' Time in uS
T_off = 0 'Initialize to zero
' -----[ Initialization ]--------------------------------------------------
Init:
TRISB = %00000000 'PortB -all outputs
PORTB = %00000000 'Initialize PortB outputs low
TRISC.2 = 1 '(Pin 13) is input for CCP1 capture mode
CCP1CON = $05 'Capture mode, every rising edge
' -----[ Main Code ]-------------------------------------------------------

' Disable interrupts and clear interrupt flags
INTCON = $00 'Disable unmasked global interrupts (bit 7)
'Peripheral interrupts disabled (bit 6)
'TMR0 Interrupt disabled (bit 5)
'Disable RB0 interrupt (bit 4)
'Disable RB Port change interrupt (bit 3)
'TMR0 overflow flag cleared (bit 2)
'RB0 interrupt flag cleared (bit 1)
'RB port change flag cleared (bit 0)
PIR1 = $00 'Clear Interrupt flags (bit 0 only used by TMR1)
PIE1 = $00 'Peripheral Interrupt Enable Register ($00 is default)
'All individual bits are disabled
'including bit 0 TMR1 overflow interrupt

' Enable unmasked global interrupts and peripheral interrupts
INTCON = $C0

On interrupt goto IntHand
'Reset Timer 1 and turn it on
TMR1H = $00 'Reset timer to zero right after turning on
TMR1L = $00
T1CON = %00000001 'TMR1 on, prescaler=1, clock = (Fosc/4)

High PortB.1 'Turn on LED
Loop:
If PIR1.2 = 1 then Display2 'wait for the CCP1 flag to set, at RC2
goto Loop

Disable
IntHand:
T_Off.HighByte = TMR1H
T_off.Lowbyte = TMR1L
serout 2, T2400, ["T_Off = ", #T_Off, 13,10]
PIR1 = $00 'Clear Peripheral Interrupt Flag Register
INTCON.1=0
RESUME
ENABLE

Display2:
T_Off.HighByte = CCPR1H
T_Off.LowByte = CCPR1L
serout 2, T2400, ["T_Off2 = ", #T_Off, 13,10]
PIR1.2 = 0
INTCON.1=0
Return

END

----------------------------------------------------------------------------------
' PIC16F876A hardware connections
' PIC External
' ---- ---------
' RB1 LED Cathode
' RC2 Phototransistor Comparator Output to RC2/CCP1 pin
' ----[ Includes / Defines ]-------------------------------------------

@ DEVICE WDT_OFF
define OSC 4
include "modedefs.bas" 'include serout defines

' -----[ Variables ]-------------------------------------------------------
T_Off var Word ' Time in uS
T_off = 0 'Initialize to zero
' -----[ Initialization ]--------------------------------------------------
Init:
TRISB = %00000000 'All port b are outputs
PORTB = %00000000 'Initialize PortB outputs low
TRISC.2 = 1 '(Pin 13) is input for CCP1 capture mode
CCP1CON = $05 'Capture mode, every rising edge
' -----[ Main Code ]-------------------------------------------------------

' Disable interrupts and clear interrupt flags
INTCON = $00 'Disable unmasked global interrupts (bit 7)
'Peripheral interrupts disabled (bit 6)
'TMR0 Interrupt disabled (bit 5)
'Disable RB0 interrupt (bit 4)
'Disable RB Port change interrupt (bit 3)
'TMR0 overflow flag cleared (bit 2)
'RB0 interrupt flag cleared (bit 1)
'RB port change flag cleared (bit 0)
PIR1 = $00 'Clear Interrupt flags (bit 0 only used by TMR1)
PIE1 = $00 'Peripheral Interrupt Enable Register ($00 is default)
'All individual bits are disabled
'including bit 0 TMR1 overflow interrupt

' Enable unmasked global interrupts and Peripheral Interrupts
INTCON = $C0

On interrupt goto IntHand
'Reset Timer 1 and turn it on
TMR1H = $00 'Reset timer to zero right after turning on
TMR1L = $00
T1CON = %00000001 'TMR1 on, prescaler=1, clock = (Fosc/4)

High PortB.1 'Turn on LED
Loop:
'If PIR1.2 = 1 then Display2 'wait for the external interrupt on RC2
goto Loop

Disable
IntHand:
T_Off.HighByte = CCPR1H
T_off.Lowbyte = CCPR1L
serout 2, T2400, ["T_Off = ", #T_Off, 13,10]
PIR1 = $00 'Clear Peripheral Interrupt Flag Register
INTCON.1=0
RESUME
ENABLE

Display2:
T_Off.HighByte = CCPR1H
T_Off.LowByte = CCPR1L
serout 2, T2400, ["T_Off2 = ", #T_Off, 13,10]
PIR1.2 = 0
Return

Archangel
- 16th January 2008, 04:18
Hi TDon,
without reading and understanding your code, which I didn't and don't, I will still toss out this comment: PBP interrupts are like a teenager, you ask them to do something and they will, in their own time. Have you tried Darrel's instant interrupt routines ? They offer assembly interrupts in a bolt on fashion, without the brain damage associated with using assembly.

http://darreltaylor.com/DT_INTS-18/home.html
http://www.picbasic.co.uk/forum/showthread.php?t=3251

BrianT
- 16th January 2008, 08:16
If an event is slow, say many milliseconds, then software measurements such as you are trying can give reasonable results. However I would expect the turnon or turnoff time of a phototransistor with say a 4k7 load resistor to be only a few tens of microseconds. This is way too fast to easily measure in software IMHO. Unless you get deep into the assembly code produced by PBP and your assembler (PM or MPASM) you will not know how many machine code instructions lie between the event and the display of that event. That makes such a measurement in code a rather hit or miss affair.

There are no published timings for PBP commands because many of them are variable. For example the instruction "If A > B then" takes different times for a byte compare vs a word compare.

If at all possible, use an independent hardware device, an oscilloscope or logic analyser, to get believable and repeatable measurements.

HTH
BrianT

Bruce
- 16th January 2008, 14:40
Capture will generate the interrupt, but only if you have it enabled. PIE1 = $04 should do
the trick. With PIE1 = 0 you have the interrupt disabled.

Do a search here for examples using capture & code execution timing with timers for several
good examples.

Edit: Here's an example http://www.picbasic.co.uk/forum/showthread.php?p=23401

TDonBass
- 17th January 2008, 03:25
Joe and Brian,
Thanks for the comments.. I had already downloaded Darrel's instant interrupts but I haven't tried those yet... later in my learning process I will do that. The phototransistor turn off time I'm measuring with a 10K load is on the order of 100 to 200uS, and I seem to be getting very accurate measurements using the CCP1 pin (they agree with my oscilloscope), but not that accurate with the RB0/INT pin because of the things you mentioned.

Bruce,
You nailed it. Thanks for taking the time to read through my code and figure it out for me...I should have been able to figure that out myself, but I kept missing it. I knew it couldn't have been a bad PIC - I bought it from you!