PDA

View Full Version : mS Timer



whmeade10
- 19th July 2006, 19:03
I need to time an incoming pulse that can be anywhere from 35 to 1000 mS long. I am not sure weather to use the external interrupt B0 or the CCP1. I am using a 18F242 pic chip. Is it possible to set up T1 to overflow every 1mS and load the number of times it overflows between the Low to High pulse into a word variable. Will this work

Set CCP1 to interrupt on low to high
Set CCP2 to interrupt on high to low

When CCP1 interrupts start T1
When CCP2 interrupts place the number of times (every 1mS) that T1 overflows into a word variable then reset variable to 0 after use.

Any sugestions....

mister_e
- 20th July 2006, 02:04
it's up to you to decide... but my vote will go to the ccp method.

Download the DS41214a app note from microchip. you'll find some good stuff in it.
http://ww1.microchip.com/downloads/en/DeviceDoc/41214a.pdf

Bruce
- 20th July 2006, 05:45
Grab that app note Steve linked to. It's got some pretty cool stuff in it.

This will save you a little time deciphering it;



' Measuring signal pulse widths with capture module

' Procedure for high-going pulse:
' 1. Configure CCP to capture on rising edge
' 2. Setup Timer1 so it will not overflow during max pulse width time
' 3. Enable ccp capture
' 4. Once capture flag bit is set, save captured value as T1
' 5. Reconfigure CCP to capture on falling edge
' 6. On 2nd capture, save 2nd value as PW
' 7. Subtract T1 from PW for the pulse width value

' Test signal:
' 12.04kHz pulse with 41uS high / 42uS low
' Input signal connected to RC2/CCP1 pin

' PIC18F242 @20MHz
DEFINE OSC 20
DEFINE DEBUG_REG PORTC
DEFINE DEBUG_BIT 6
DEFINE DEBUG_BAUD 115200
DEFINE DEBUG_MODE 0 ' 1 = inverted, 0 = true

Symbol Capture = PIR1.2 ' CCP1 capture flag
T1 VAR WORD ' 1st capture value
PW VAR WORD ' 2nd capture value & ultimately final pulse width

TRISC.2 = 1 ' CCP1 input pin (Capture input)
INTCON = 0 ' Interrupts off

ReLoad:
CCP1CON = %00000101 ' Capture mode, capture on rising edge
T1CON = 0 ' TMR1 prescale=1, clock=Fosc/4, TMR1=off (200nS per count @20MHz)
TMR1H = 0 ' Clear high byte of TMR1 counter
TMR1L = 0 ' Clear low byte
T1CON.0 = 1 ' Turn TMR1 on here

Capture = 0 ' Clear capture int flag bit
While !Capture ' Wait here until capture on rising edge
Wend

' Rising edge detected / stuff Timer1 value in T1
T1.HighByte = CCPR1H
T1.LowByte = CCPR1L

CCP1CON.0 = 0 ' Configure capture for falling edge now
Capture = 0 ' Clear capture interrupt flag bit

While !Capture ' While here until capture on falling edge
Wend

' Falling edge detected / stuff Timer1 value in PW
PW.HighByte = CCPR1H
PW.LowByte = CCPR1L

PW = PW-T1 ' High pulse width = PW-T1
' Convert to uS for 20MHz osc with 200nS Timer1 ticks
PW = (PW * 2)/10

DEBUG dec PW,"uS High",13,10 ' Output to RS232 display
GOTO ReLoad

END
I ran it with a 2nd PIC delivering a 12.04kHz signal: HPWM 1,127,12000 to the
18F242 CCP1 pin. 41uS high, 42uS low.

It's spot-on. Returns 41uS High on MCS serial terminal. Fluke ScopeMeter 123
shows precisely the same timing.

Much nicer than pulsin, count, etc..

Darrel Taylors' instant interupts works perfect for this.


' PIC18F242 @20MHz
DEFINE OSC 20
DEFINE DEBUG_REG PORTC
DEFINE DEBUG_BIT 6
DEFINE DEBUG_BAUD 115200
DEFINE DEBUG_MODE 0 ' 1 = inverted, 0 = true

OverFlows VAR BYTE ' Timer1 overflow total
Remainder VAR WORD ' Remaining Timer1 ticks after falling edge capture

INCLUDE "DT_INTS-18.bas" ; Base Interrupt System
INCLUDE "ReEnterPBP-18.bas" ; Include if using PBP interrupts

;----[High Priority Interrupts]----------------------------------------
ASM
INT_LIST macro ; IntSource, Label, Type, ResetFlag?
INT_Handler CCP1_INT, _Capture, PBP, yes
INT_Handler TMR1_INT, _Timer1, PBP, yes
endm
INT_CREATE ; Creates the High Priority interrupt processor
ENDASM

CCP1CON = %00000101 ' Capture mode, capture on rising edge
T1CON = 0 ' TMR1 prescale=1, clock=Fosc/4, TMR1=off (200nS per count @20MHz)
@ INT_ENABLE CCP1_INT ; enable Capture interrupts

Main:
IF T1CON.0 = 0 THEN ' If done, show result
DEBUG "Timer Overflows = ",DEC OverFlows
DEBUG " Remaining ticks = ",dec Remainder,13,10
ENDIF
PAUSE 2000
@ INT_ENABLE CCP1_INT ; Start new capture
GOTO Main

'---[CCP1 - interrupt handler]------------------------------------------
Capture:
IF CCP1CON = %00000101 THEN ' If rising edge capture then
TMR1L = 0 ' Clear Timer1 counts
TMR1H = 0
T1CON.0 = 1 ' Turn Timer1 on at rising edge capture
OverFlows = 0 ' Clear over flow counts
Remainder = 0 ' Clear remainder
CCP1CON = %00000100 ; Switch to falling edge capture
PIR1.0 = 0 ; Clear Timer1 overflow flag before enable
@ INT_ENABLE TMR1_INT ; Enable Timer 1 Interrupts
GOTO OVER_CCP ; Done, exit
ENDIF

IF CCP1CON = %00000100 THEN ; If falling edge capture then
T1CON.0 = 0 ; Stop Timer1
CCP1CON = %00000101 ; Switch back to rising edge capture
@ INT_DISABLE TMR1_INT ; Disable Timer 1 Interrupts
@ INT_DISABLE CCP1_INT ; Disable CCP1 Interrupts
Remainder.LowByte = TMR1L ; Get remaining Timer1 counts on falling edge
Remainder.HighByte = TMR1H
ENDIF
OVER_CCP:
@ INT_RETURN

'---[TMR1 - interrupt handler]---------------------------------------------
Timer1:
OverFlows = OverFlows + 1
@ INT_RETURN

END
Input for testing was a 2nd PIC providing a 30mS pulse followed by a 1000mS
pulse with a 5 second delay between each.

For the 30mS pulse it displays: Timer Overflows = 2 Remaining ticks = 19048

The total pulse width: (2 * 65536 * 200nS) + (19048 * 200nS) = 30.0242mS

For the 1000mS pulse: Timer Overflows = 76 Remaining ticks = 19480
So: (76 * 65536 * 200nS) + (19480 * 200nS) = 1.0000432 S

Darrels interrupt routines are pretty handy.

Bruce
- 20th July 2006, 18:06
And then there's the old fashioned way..;o}


' PIC18F242 @20MHz
DEFINE OSC 20
DEFINE INTHAND Capture ' Context saving for High Priority Ints
DEFINE DEBUG_REG PORTC
DEFINE DEBUG_BIT 6
DEFINE DEBUG_BAUD 115200
DEFINE DEBUG_MODE 0 ' 1 = inverted, 0 = true

OverFlows VAR BYTE BANKA SYSTEM ' Timer1 overflow total
Remainder VAR WORD BANKA SYSTEM ' Remaining Timer1 ticks after falling edge capture
Ready VAR BYTE BANKA SYSTEM ' Indicates pulse width measurement is complete when 1
Ready = 0

ReStart:
CCP1CON = %00000101 ' Capture mode, capture on rising edge
T1CON = 0 ' TMR1 prescale=1, clock=Fosc/4, TMR1=off (200nS per count @20MHz)
RCON.7 = 1 ' Enable priority interrupts
PIE1.0 = 0 ' Disable Timer1 over flow interrupt
PIE1.2 = 1 ' Enable CCP1 interrupt
PIR1 = 0 ' Clear any pending interrupt flags
PIR2 = 0 ' before enabling global
INTCON.7 = 1 ' Enable all unmasked interrupts

Main:
WHILE !Ready ' While not ready, wait
' Do other stuff here if needed
WEND

' Result is ready
DEBUG "Timer Overflows = ",DEC OverFlows
DEBUG "Remaining ticks = ",DEC Remainder,13,10
Ready = 0

PAUSE 2000
GOTO ReStart

'---[CCP1 & Timer1 - interrupt handler]------------------------------------------
ASM
Capture
btfsc PIR1,TMR1IF ; Timer1 interrupt?
bra T1_Int ; Yes. Goto T1_Int
bcf PIR1,CCP1IF ; No it's a capture int so clear capture int flag
btfss CCP1CON,0 ; Rising edge capture?
bra FallingEdge ; No. Skip to falling edge capture
clrf TMR1H ; Yes. Clear high count
clrf TMR1L ; Clear low count
bsf T1CON,0 ; Turn Timer1 on at rising edge capture
clrf OverFlows ; Clear over flow count
clrf Remainder ; Clear remainder count
bcf PIE1,CCP1IE ; Disable capture interrupt before switching
bcf CCP1CON,0 ; Switch to falling edge capture
bcf PIR1,0 ; Clear Timer1 overflow flag before enable
bsf PIE1,TMR1IE ; Enable Timer1 Interrupt
bsf PIE1,CCP1IE ; Re-enable capture interrupt
bra OVER_CCP ; Done, exit

T1_Int
bcf PIR1,TMR1IF ; Clear Timer1 overflow flag
incf OverFlows,f ; Increment over flow count
bra OVER_CCP ; Done, exit

FallingEdge
bcf T1CON,0 ; Stop Timer1
bcf PIE1,CCP1IE ; Disable CCP1 interrupt
bcf PIE1,TMR1IE ; Disable Timer1 interrupt
bsf CCP1CON,0 ; Switch back to rising edge capture
movff TMR1L, Remainder ; Get low byte on falling edge
movff TMR1H, Remainder+1 ; Get high byte
bsf Ready,0 ; Indicate process is complete

OVER_CCP
retfie fast ; Done, return
ENDASM

END

boroko
- 8th September 2020, 10:49
Hi All,

Working through a similar issue trying to time a couple of events and looking for some clarification.
In this explanation, and in the tips and tricks there is this line:

"2. Setup Timer1 so it will not overflow during max pulse width time".

Yet the amount of overflows is how you're measuring the pulse. What am I overlooking here, and why mention that?

I'm on a 12F683 and have been trying to use GPC_INT (Interupt on change) to do this, while keeping within one cycle of TMR1 and it has limitations. Using the overflow count and remainder looks like a much better idea. I'm going to crank through it that way and see if it solves my problem, I am just confused about that line.

Thanks
bo

richard
- 8th September 2020, 11:25
that post has two separate methods , one measures the pulse width with timer counts the other by timer overflows

boroko
- 8th September 2020, 12:12
Thank you Richard, I have few arenas that bring out self doubt as quickly as trying to muscle one of these little buggers.
I almost have it rewritten using this scheme. I hope to test it when I get back to the shop.
bo