PDA

View Full Version : Interrupt RPM and Taylors Elapsed time on 18F4620



Tobias
- 27th January 2010, 16:40
I see the 18F4620 has a couple 16 bit timers. I have RPM going into C2/CCP1. So if I have the code set up right I should be getting RPM. I am not though. I did have this code working just fine on a 16F877A.

I needed to modify Taylors ET code to use Timer3. This code works just fine using Timer1 but then when I change the code around for Timer3 its not working.
Any ideas? I am hoping I just have a couple lines of code setting up flags incorrectly and I will be able to use the ET and RPM at the same time.


RPM Code

DEFINE OSC 20
Prefix con $FE ' needed before each command
LcdCls CON $51 ' clear LCD (use PAUSE 5 after)
CursorPS con $45 'Cursor Position
Capture VAR PIR2.0 ' CCP1 capture flag
Overflow VAR PIR2.1 ' Timer1 overflow flag
RPM var word
period var Word
TotalTime var word 'Holds seconds and tics

LCD VAR PortC.6 'LCD output
Gate1 Var PortC.1
Gate2 var PortD.1
Gate3 var PortD.2
Gate4 var PortD.3
Gate5 var PortD.6
Gate6 var PortD.7
Gate7 var PortD.5
Gate8 var PortD.4
WOT var PortB.0

ADCON0 =0
ADCON1.3=1
ADCON1.2=1
ADCON1.1=1
ADCON1.0=1
TRISE.0=1
TRISE.1=1

T1CON.7=1 'enable timer 16 bit `
T1CON.6=1 'Timer1 OSC
T1CON.5=1 '1:4 prescaler
T1CON.4=0 '1:4 prescaler
T1CON.3=1 'Timer1 OSC enabled
T1CON.2=0 'sychro clock
T1CON.1=1 'external clock
T1CON.0=0 'stop timer

pause 100
SEROUT2 LCD,84, [Prefix, LcdCls]

Include "modedefs.bas" ' Mode definitions for Serout

Loop:
TMR1H = 0
TMR1L = 0
capture = 0

Start:
If Capture = 0 then
Goto Start
endif
'code doesn't make it this far..assuming waiting for Cpature =1
T1CON.0=1
Capture = 0

CaptureLoop:
If Capture = 0 then
Goto CaptureLoop
endif

period.LowByte=CCPR1L
period.HighByte=CCPR1H

RPM = 10000
RPM = RPM * RPM ' 100,000,000
RPM = DIV32 period ' 100,000,000 / RevCount
RPM = RPM * 60 ' Per minute
RPM = DIV32 398 '400
RPM = (RPM*5)
pause 10
SEROUT2 LCD,84, [Prefix,CursorPS,0,"RPM ",dec5 RPM, " ", #Period]
T1Con.0=0

Gosub ClearTimer1

Goto Loop

ClearTimer1:
If Capture = 0 then
goto ClearTimer1
endif

TMR1H = 00
TMR1L = 0
Capture = 0
Overflow = 0
return




Taylors ET Code
'************************************************* ***************
'* Name : ELAPSED.PBP *
'* Author : Darrel Taylor *
'* Notice : Copyright (c) 2003 *
'* Date : 12/16/2003 *
'* Notes : *
'************************************************* ***************
disable debug

Define INTHAND _ClockCount ' Tell PBP Where the code starts on an interrupt
Include "ASM_INTS-18.bas" ' ASM Interrupt Stubs

Ticks var Word ' 1/1000th of a second
Seconds var byte
Minutes var byte
Hours var byte
Days var word
R0save var word
R1save var word
R4save var word

SecondsChanged var bit
MinutesChanged var bit
HoursChanged var bit
DaysChanged var bit
SecondsChanged = 1
MinutesChanged = 1

Goto OverElapsed

' ------------------------------------------------------------------------------
Asm
IF OSC == 4 ; Constants for 100hz interrupt from Timer1
TimerConst = 0D8F7h ; Executed at compile time only
EndIF
If OSC == 8
TimerConst = 0B1E7h
EndIF
If OSC == 10
TimerConst = 09E5Fh
EndIF
If OSC == 20
TimerConst = 0EC80h
EndIF
If OSC == 40
TimerConst = 03CB7h
EndIF

; ----------------- ADD TimerConst to TMR1H:TMR1L
ADD2_TIMER macro
CHK?RP T3CON
BCF T3CON,TMR3ON ; Turn off timer
MOVLW LOW(TimerConst) ; 1
ADDWF TMR3L,F ; 1 ; reload timer with correct value
BTFSC STATUS,C ; 1/2
INCF TMR3H,F ; 1
MOVLW HIGH(TimerConst) ; 1
ADDWF TMR3H,F ; 1
endm

; ----------------- ADD TimerConst to TMR1H:TMR1L and restart TIMER1
RELOAD_TIMER macro
ADD2_TIMER
BSF T3CON,TMR3ON ; 1 ; Turn TIMER1 back on
CHK?RP PIR2
bcf PIR2, TMR3IF ; Clear Timer1 Interrupt Flag
endm

; ----------------- Load TimerConst into TMR1H:TMR1L
LOAD_TIMER macro
EndAsm
T3CON.0 = 0 ; Turn OFF Timer1
TMR3L = 0
TMR3H = 0
Asm
ADD2_TIMER
endm
EndAsm

' ------[ This is the Interrupt Handler ]---------------------------------------
ClockCount: ' Note: this is being handled as an ASM interrupt
@ INT_START
@ RELOAD_TIMER ; Reload TIMER1
R0save = R0 ; Save 2 PBP system vars that are used during
R1save = R1 ; the interrupt
R4save = R4
Ticks = Ticks + 1
if Ticks = 1000 then
Ticks = Ticks-1000
Seconds = Seconds + 1
SecondsChanged = 1
if Seconds = 60 then
Minutes = Minutes + 1
MinutesChanged = 1
Seconds = 0
endif
if Minutes = 60 then
Hours = Hours + 1
HoursChanged = 1
Minutes = 0
endif
if Hours = 24 then
Days = Days + 1
DaysChanged = 1
Hours = 0
endif
endif
R4 = R4save ; Restore the PBP system vars
R1 = R1save
R0 = R0save
@ INT_RETURN ; Restore context and return from interrupt

'-----====[ END OF TMR1 Interrupt Handler ]====---------------------------------

StartTimer:
T3CON.1 = 0 ; (TMR1CS) Select FOSC/4 Clock Source
T3CON.3 = 0 ; (T1OSCEN) Disable External Oscillator
PIR2.0 = 0 ; (TMR1IF) Clear Timer1 Interrupt Flag
PIE2.0 = 1 ; (TMR1IE) Enable TMR1 overflow interrupt
INTCON.6 = 1 ; (PEIE) Enable peripheral interrupts
INTCON.7 = 1 ; (GIE) Enable global interrupts
T3CON.0 = 1 ; (TMR1ON) Start TIMER1
@ if OSC == 40
T3CON.5 = 0 ; Prescaler = 1:2
T3CON.4 = 1
@ endif
return

; -----------------
StopTimer:
T3CON.0 = 0 ; Turn OFF Timer1
return

; -----------------
ResetTime:
R0save = T3CON.0 ; Save TMR1ON bit
T3CON.0 = 0 ; Turn OFF Timer1
TMR3L = 0
TMR3H = 0
@ LOAD_TIMER ; Load TimerConst
T3CON.0 = R0save ; Restore TMR1ON bit
Ticks = 0
Seconds = 0
Minutes = 0
Hours = 0
Days = 0
SecondsChanged = 1
return

OverElapsed:
enable debug

Bruce
- 27th January 2010, 19:38
Looks like you forgot to write to CCP1CON to turn on capture.

Tobias
- 27th January 2010, 21:44
Thanks for your help and also Taylors email. I inserted CCP1CON flags and also had a couple others wrong. I am learning alot about how to read the datasheets changing chips.

I am using an external 20 MHZ OSC

The code below works except it isn't as close as when I was using the 877A chip. I have an rpm frequency generator with a digital readout that I am using to check the rpm with the 4620 chip. Following is data

RPM with generator/RPM with 4620
4000/3975
5000/4965
6000/5960
7000/6955
8000/7950
9000/8945
10000/9935

All chip numbers are 99.35% appr from RPM generator. When I used the 877A all numbers matched up dead on.

Any ideas?



DEFINE OSC 20
Prefix con $FE ' needed before each command
LcdCls CON $51 ' clear LCD (use PAUSE 5 after)
CursorPS con $45 'Cursor Position
Capture VAR PIR1.2 ' CCP1 capture flag CCP1IF
Overflow VAR PIR1.0 ' Timer1 overflow flag TMR1IF:
RPM var word
period var Word
TotalTime var word 'Holds seconds and tics

LCD VAR PortC.6 'LCD output
Gate1 Var PortC.1
Gate2 var PortD.1
Gate3 var PortD.2
Gate4 var PortD.3
Gate5 var PortD.6
Gate6 var PortD.7
Gate7 var PortD.5
Gate8 var PortD.4
WOT var PortB.0

ADCON0 =0 'A/D Off
ADCON1.3=1 'All AN channels digital
ADCON1.2=1 '''
ADCON1.1=1 '''
ADCON1.0=1 '''
TRISE.0=1 'EO input
TRISE.1=1 'E1 input
CCP1CON = %00000110 ; Capture mode, every 4th rising edge 0110
T1CON.7=1 'enable timer 16 bit `
T1CON.6=1 'Timer1 OSC
T1CON.5=1 '1:4 prescaler
T1CON.4=0 '1:4 prescaler
T1CON.3=0 'Timer1 OSC off
T1CON.2=0 'sychro clock
T1CON.1=0 'internal clock
T1CON.0=0 'stop timer

pause 10
SEROUT2 LCD,84, [Prefix, LcdCls]

Include "modedefs.bas" ' Mode definitions for Serout
SEROUT2 LCD,84, [Prefix,CursorPS,0,"RPM test"]
pause 500

Loop:
TMR1H = 0 'Clear 8-bit register
TMR1L = 0 'Clear 8-bit register
capture = 0 'Clear Timer
'SEROUT2 LCD,84, [Prefix,CursorPS,0,"Capture ", dec Capture," ",DEC Period]
Start:
If Capture = 0 then
Goto Start
endif

T1CON.0=1
Capture = 0

CaptureLoop:
If Capture = 0 then
'SEROUT2 LCD,84, [Prefix,CursorPS,0,"Dont Capture ", dec Capture," ",DEC Period]
Goto CaptureLoop
endif
T1Con.0=0
period.LowByte=CCPR1L
period.HighByte=CCPR1H

RPM = 10000
RPM = RPM * RPM ' 100,000,000
RPM = DIV32 period ' 100,000,000 / RevCount
RPM = RPM * 60 ' Per minute
RPM = DIV32 400
RPM = (RPM*5)

SEROUT2 LCD,84, [Prefix,CursorPS,20,"RPM ",dec5 RPM, " ", DEC Period]

Gosub ClearTimer1

Goto Loop

ClearTimer1:
If Capture = 0 then
'SEROUT2 LCD,84, [Prefix,CursorPS,40,"Don't Clear Timer ", DEC Period]
goto ClearTimer1
endif
''SEROUT2 LCD,84, [Prefix,CursorPS,40,"Clear Timer ", DEC Period]
TMR1H = 00
TMR1L = 0
Capture = 0
Overflow = 0
return

Bruce
- 28th January 2010, 00:22
If you're using exactly the same setting for capture, timer1, etc, and it works 100%
on the 877A, but not on the 4620, then I would suspect a bug in the 4620, or something
has been changed somewhere between the 2 versions.

What values do you get if sending the raw value from period to your display immediately
after this?

period.LowByte=CCPR1L
period.HighByte=CCPR1H

Tobias
- 28th January 2010, 03:54
Here are the numbers from an 877A and 4620 both configured to use HS 20 MHZ.

I will say I am not too sure with the T1Con flags if its set exactly as the 877A


RPM 877A 4620
5000 Low Byte 202 243
High Byte 175 58
6000 Low Byte 125 31
High Byte 146 497
7000 Low Byte 141 26
High Byte 167 421
8000 Low Byte 125 215
High Byte 146 36



'877A Code
DEFINE OSC 20
Prefix con $FE ' needed before each command
LcdCls CON $51 ' clear LCD (use PAUSE 5 after)
CursorPS con $45 'Cursor Position
Capture VAR PIR1.2 ' CCP1 capture flag
Overflow VAR PIR1.0 ' Timer1 overflow flag
RPM var word
period var Word
TotalTime var word 'Holds seconds and tics

LCD VAR PortC.6 'LCD output
Gate1 Var PortC.1
Gate2 var PortD.1
Gate3 var PortD.2
Gate4 var PortD.3
Gate5 var PortD.6
Gate6 var PortD.7
Gate7 var PortD.5
Gate8 var PortD.4
WOT var PortB.0

ADCON0 =0
ADCON1.3=1
ADCON1.2=1
ADCON1.1=1
ADCON1.0=1
TRISE.0=1
TRISE.1=1
CCP1CON = %00000110 ' Enable the CCP1 capture, every 4th rising edge

pause 100
SEROUT2 LCD,84, [Prefix, LcdCls]
low Gate1
Low Gate2
Low Gate3
Low Gate4
Low Gate5
Low Gate6
Low Gate7
Low Gate8

Include "modedefs.bas" ' Mode definitions for Serout
T1CON=%00100000

Loop:
TMR1H = 0
TMR1L = 0
capture = 0

Start:
IF capture = 0 Then
goto Start ' Wait here for the first capture
endif

T1CON.0 = 1 ' Start the Timer
capture = 0 ' Reset the capture flag

CaptureLoop:
IF capture = 0 Then
goto CaptureLoop ' Wait here until captured
endif

period.lowbyte = CCPR1L ' Store the captured value in
period.highbyte = CCPR1H ' period variable

RPM = 10000
RPM = RPM * RPM ' 100,000,000
RPM = DIV32 period ' 100,000,000 / RevCount
RPM = RPM * 60 ' Per minute
RPM = DIV32 400 '400
RPM = (RPM*5)
pause 10
SEROUT2 LCD,84, [Prefix,CursorPS,20,"RPM ",dec5 RPM, " ", DEC CCPR1L, " ", dec CCPR1H]
T1CON.0=0

gosub cleartimer1

GoTo loop ' Do it forever

ClearTimer1:
IF (capture = 0) Then
goto cleartimer1 ' Wait for beginning of next period
endif

TMR1L = 0 ' Clear Timer1 low register
TMR1H = 0 ' Clear Timer1 high register
capture = 0 ' Clear capture flag
overflow = 0 ' Clear overflow flagReturn
return



'4620
DEFINE OSC 20
Prefix con $FE ' needed before each command
LcdCls CON $51 ' clear LCD (use PAUSE 5 after)
CursorPS con $45 'Cursor Position
Capture VAR PIR1.2 ' CCP1 capture flag CCP1IF
Overflow VAR PIR1.0 ' Timer1 overflow flag TMR1IF:
RPM var word
period var Word
TotalTime var word 'Holds seconds and tics

LCD VAR PortC.6 'LCD output
Gate1 Var PortC.1
Gate2 var PortD.1
Gate3 var PortD.2
Gate4 var PortD.3
Gate5 var PortD.6
Gate6 var PortD.7
Gate7 var PortD.5
Gate8 var PortD.4
WOT var PortB.0

ADCON0 =0 'A/D Off
ADCON1.3=1 'All AN channels digital
ADCON1.2=1 '''
ADCON1.1=1 '''
ADCON1.0=1 '''
TRISE.0=1 'EO input
TRISE.1=1 'E1 input
CCP1CON = %00000110 ; Capture mode, every 4th rising edge 0110
T1CON.7=1 'enable timer 16 bit `
T1CON.6=1 'Timer1 OSC
T1CON.5=1 '1:4 prescaler
T1CON.4=0 '1:4 prescaler
T1CON.3=0 'Timer1 OSC off
T1CON.2=0 'sychro clock
T1CON.1=0 'internal clock
T1CON.0=0 'stop timer

pause 10
SEROUT2 LCD,84, [Prefix, LcdCls]

Include "modedefs.bas" ' Mode definitions for Serout
SEROUT2 LCD,84, [Prefix,CursorPS,0,"RPM test"]
pause 500

Loop:
TMR1H = 0 'Clear 8-bit register
TMR1L = 0 'Clear 8-bit register
capture = 0 'Clear Timer
Start:
If Capture = 0 then
Goto Start
endif

T1CON.0=1
Capture = 0

CaptureLoop:
If Capture = 0 then
Goto CaptureLoop
endif
T1Con.0=0
period.LowByte=CCPR1L
period.HighByte=CCPR1H

RPM = 10000
RPM = RPM * RPM ' 100,000,000
RPM = DIV32 period ' 100,000,000 / RevCount
RPM = RPM * 60 ' Per minute
RPM = DIV32 400
RPM = (RPM*5)

SEROUT2 LCD,84, [Prefix,CursorPS,20,"RPM ",dec5 RPM, " ", DEC CCPR1L, " ", dec CCPR1H]

Gosub ClearTimer1

Goto Loop

ClearTimer1:
If Capture = 0 then
goto ClearTimer1
endif

TMR1H = 00
TMR1L = 0
Capture = 0
Overflow = 0
return

Bruce
- 28th January 2010, 17:53
Are your result figures correct? It shows the exact same result on the 877A for 6000
and 8000 RPM!

What do you get with something like this on both versions?


period.lowbyte = CCPR1L ' Store the captured value in
period.highbyte = CCPR1H ' period variable

SEROUT2 LCD,84, [Prefix,CursorPS,20,dec5 period]

Tobias
- 28th January 2010, 18:35
RPM and period numbers per chip
Rpm 4620 877a
5000 15090 14999
6000 12575 12499
7000 10777 10712
8000 9430 9373
9000 8383 8331
10000 7545 7499

Bruce
- 28th January 2010, 20:21
Do you have another 18F type besides a 4620 you can test this on?

That would tell you if it's a hardware bug on the 4620. This part has
a massive list of errata & odd problems with ECCP, Timer1, Timer3,
and more.

Tobias
- 28th January 2010, 21:18
I might have a 4520 floating around. Can you suggest a part number that will work with the boards I already have made? I will order it today if you have a suggestion.

Bruce
- 28th January 2010, 21:38
A 4520 should drop right in, but this one also has a boat-load of errata for CCP, timer, and
a bunch more. I would test it if you already have one before buying another PIC.

The 18F4431 is my own personal favorite, and I also like the older 18F452. The drop-in
replacement (your 4520) for the 452 has way too many bugs.

Tobias
- 28th January 2010, 21:58
Thanks it looks like a couple different config flags need to be changed to go with the 4431. The pinout appears to be the same.?.

Bruce
- 28th January 2010, 22:05
It's the same pinout. It also has a lot of extra features.

But - I would try that 4520 if you can find it.

Where are you getting your PICs from? I have samples, and would be
more than willing to shoot you an 18F4431 if you cover postage.

Tobias
- 28th January 2010, 22:16
I usually go through Mouser but I would rather spend money with you. Do you want to Paypal the freight? My paypal acct is [email protected].

I need a 44 pin TQFP

Shipping is
xBase
506 Park St
Sterling CO 80751

Hell with your 719 area code you can't be far anyway.
Thanks
Toby

Bruce
- 28th January 2010, 22:29
I need a 44 pin TQFP
Yikes .. I only have DIP package types. Never get TQFP samples.

But - I am in the process as we speak of putting in a big order for various PIC types, so
I can grab one for you on this order, and get it out to you tomorrow. All at our exact cost
on shipping & part.

PIC18F4431-I/PT $6.60
Priority Mail $4.95

Darrel Taylor
- 28th January 2010, 22:32
RPM and period numbers per chip
Rpm 4620 877a
5000 15090 14999
6000 12575 12499
7000 10777 10712
8000 9430 9373
9000 8383 8331
10000 7545 7499

I think you need to clear the timer sooner. (Immediately after capture).

The program goes through the whole conversion to RPM with multiplications and DIV32's before clearing the timer.

The 18F's multiply faster because they have a hardware multiplier.
So it clears the timer quicker and ends up with bigger numbers.

The 4620 numbers are closer to reality, but it's still wrong.

Clear the timer immediately after a capture and both chips should read the same numbers (or really close).

hth,

Bruce
- 28th January 2010, 22:50
Hi Darrel,



Start:
If Capture = 0 then ' ignores 1st capture
Goto Start
endif

T1CON.0=1
Capture = 0

CaptureLoop:
If Capture = 0 then
Goto CaptureLoop
endif
T1Con.0=0
period.LowByte=CCPR1L
period.HighByte=CCPR1H
With both PICs running at 20MHz, CCPR1L & CCPR1H should have the same values - since
it's all done in hardware with the capture module capturing the value of timer1 after the
4 rising edges.

And the value being captured is before the multiply.

Tobias
- 28th January 2010, 22:50
Ship three please. How do you want me to pay?


Yikes .. I only have DIP package types. Never get TQFP samples.

But - I am in the process as we speak of putting in a big order for various PIC types, so
I can grab one for you on this order, and get it out to you tomorrow. All at our exact cost
on shipping & part.

PIC18F4431-I/PT $6.60
Priority Mail $4.95

Bruce
- 28th January 2010, 22:53
I've already ordered one, but let's hold-off on me shipping one until we hear back from
Darrel. He might have noticed something I'm just not picking up on...;o)

I haven't compiled both versions and looked at the timing difference from the instance
you enable TMR1. That may make a difference.

Darrel Taylor
- 28th January 2010, 23:01
With both PICs running at 20MHz, CCPR1L & CCPR1H should have the same values - since it's all done in hardware with the capture module capturing the value of timer1 after the
4 rising edges.
Yes the captured value is stored in CCPR1L:H, but the CCP module does not clear Timer1. You have to do that. And it's not being cleared until after the math.

Then it goes back up to Loop: and clears it again, without any reference to the incoming signal. (actually, it is referenced to the last capture plus math time).

If you only clear it once, immediately after the capture, then it will be ready for the next capture.

The first capture is always wrong, and must be discarded.

Loop:
TMR1H = 0 'Clear 8-bit register
TMR1L = 0 'Clear 8-bit register
capture = 0 'Clear Timer
Start:
If Capture = 0 then
Goto Start
endif

T1CON.0=1
Capture = 0

CaptureLoop:
If Capture = 0 then
Goto CaptureLoop
endif
T1Con.0=0
period.LowByte=CCPR1L
period.HighByte=CCPR1H

RPM = 10000
RPM = RPM * RPM ' 100,000,000
RPM = DIV32 period ' 100,000,000 / RevCount
RPM = RPM * 60 ' Per minute
RPM = DIV32 400
RPM = (RPM*5)

SEROUT2 LCD,84, [Prefix,CursorPS,20,"RPM ",dec5 RPM, " ", DEC CCPR1L, " ", dec CCPR1H]

Gosub ClearTimer1

Goto Loop


Added: I guess if Timer1 was Stopped in the ClearTimer1 routine (or at Loop: ), what you have would work better, but it will only capture every other 4-pulses. (8-pulses total)

Darrel Taylor
- 28th January 2010, 23:19
Oi vey,
I just saw ...

T1Con.0=0

Ignore what I just said, and I'm off to proteus to make sure before I open my mouth again.

:o

Bruce
- 28th January 2010, 23:25
Cool. If I'm wrong, he gets a free PIC & you get the eBeer....:)

Like I said before, there could indeed be a timing difference between these points;


T1CON.0=1
Capture = 0

That would for sure be the cause.

Tobias
- 28th January 2010, 23:36
Here is what I have now. I have set it up for every rising pulse and changed the math because when I incorporate this into my other code, waiting for four pulses delays alot of events.

Its still off with the output RPM numbers by the same percentage.

DEFINE OSC 20
Prefix con $FE ' needed before each command
LcdCls CON $51 ' clear LCD (use PAUSE 5 after)
CursorPS con $45 'Cursor Position
Capture VAR PIR1.2 ' CCP1 capture flag CCP1IF
Overflow VAR PIR1.0 ' Timer1 overflow flag TMR1IF:
RPM var word
period var Word
TotalTime var word 'Holds seconds and tics

LCD VAR PortC.6 'LCD output
Gate1 Var PortC.1
Gate2 var PortD.1
Gate3 var PortD.2
Gate4 var PortD.3
Gate5 var PortD.6
Gate6 var PortD.7
Gate7 var PortD.5
Gate8 var PortD.4
WOT var PortB.0

ADCON0 =0 'A/D Off
ADCON1.3=1 'All AN channels digital
ADCON1.2=1 '''
ADCON1.1=1 '''
ADCON1.0=1 '''
TRISE.0=1 'EO input
TRISE.1=1 'E1 input
CCP1CON = %00000101 ; Capture mode, every rising edge 0101
T1CON.7=1 'enable timer 16 bit `
T1CON.6=1 'Timer1 OSC
T1CON.5=1 '1:4 prescaler
T1CON.4=0 '1:4 prescaler
T1CON.3=0 'Timer1 OSC off
T1CON.2=0 'sychro clock
T1CON.1=0 'internal clock
T1CON.0=0 'stop timer

pause 10
SEROUT2 LCD,84, [Prefix, LcdCls]

Include "modedefs.bas" ' Mode definitions for Serout
SEROUT2 LCD,84, [Prefix,CursorPS,0,"RPM test"]
pause 500

TMR1H = 0 'Clear 8-bit register
TMR1L = 0 'Clear 8-bit register
capture = 0 'Clear Timer

Calc_RPM_Timer:
TMR1H = 0 'Clear 8-bit register
TMR1L = 0 'Clear 8-bit register
capture = 0 'Clear Timer

StartRPM:
If Capture = 0 then
Goto StartRPM
endif

T1CON.0=1
Capture = 0

CaptureLoop:
If Capture = 0 then
Goto CaptureLoop
endif
T1Con.0=0
period.LowByte=CCPR1L
period.HighByte=CCPR1H

TMR1H = 0
TMR1L = 0
Capture = 0
Overflow = 0

RPM = 10000
RPM = RPM * RPM ' 100,000,000
RPM = DIV32 period ' 100,000,000 / RevCount
RPM = RPM * 60 ' Per minute
RPM = DIV32 1600
RPM = (RPM*5)

SEROUT2 LCD,84, [Prefix,CursorPS,20,"RPM ",dec5 RPM]
goto Calc_RPM_Timer
return

Bruce
- 28th January 2010, 23:49
I've already ordered you the 4431. Sorry I placed the order before I knew you needed
or wanted 3. But I'm still holding the at cost offer open if you want this one even
if/when Darrel proves me wrong - which he does way too often...;o)

These really are some cool PICs'.

If you don't mind my asking - what boards are you using? Surely you're not de-soldering
and replacing TQFP package types!

Tobias
- 29th January 2010, 01:15
Yea I will take a couple of the PICS no matter the outcome here. One way or another I want to get it working right. I need to use DT's elapsed time file and also interrupt rpm at the same time. So I can't go back to the 877A unless there is another approach.

Desoldering the TQFP's is pretty easy. Not something I want to do often but when needed I have the technique down.

Thanks to both of you on helping me get this sorted out too.

Darrel Taylor
- 29th January 2010, 02:55
Proteus Rules.

Here's what I found.
After the capture was made, and the math completed, the result is displayed with a SEROUT2 to the LCD.

But at 9600 baud, by the time it gets around to displaying CCPR1L and CCPR1H, multiple captures have taken place without Timer1 being cleared.

If you use this line instead, you get the same numbers on both chips and they are the right ones.


SEROUT2 LCD,84, [Prefix,CursorPS,20,"RPM ",dec5 RPM, " ", DEC5 period]

<object id='stUkhdQ01IR19bR15YXVpZVFJV' width='425' height='344' type='application/x-shockwave-flash' data='http://www.screentoaster.com/swf/STPlayer.swf' codebase='http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,115,0'><param name='movie' value='http://www.screentoaster.com/swf/STPlayer.swf'/><param name='allowFullScreen' value='true'/><param name='allowScriptAccess' value='always'/><param name='flashvars' value='video=stUkhdQ01IR19bR15YXVpZVFJV'/></object><div style='width: 425px; text-align: right;'><a href='http://www.screentoaster.com/'>Capture your screen in seconds</a></div>

My SEROUT2 was a little different ...
SEROUT2 LCD,84, ["RPM ",dec5 RPM, " ", DEC CCPR1H<<8+CCPR1L," ",DEC period," Ovr:",BIN1 Overflow,13,10]

The small pulse I measured was the time to do the math.
The big pulse was the time for SEROUT2.
The original SEROUT2 was shorter, and around 20mS.
<br>

Bruce
- 29th January 2010, 04:08
Nope...:)

Lets say we had ten thousand captures after this;


Loop:
TMR1H = 0 'Clear 8-bit register
TMR1L = 0 'Clear 8-bit register
capture = 0 'Clear Timer
'SEROUT2 LCD,84, [Prefix,CursorPS,0,"Capture ", dec Capture," ",DEC Period]
Start:
If Capture = 0 then
Goto Start
endif

T1CON.0=1
Capture = 0

CaptureLoop:
If Capture = 0 then
'SEROUT2 LCD,84, [Prefix,CursorPS,0,"Dont Capture ", dec Capture," ",DEC Period]
Goto CaptureLoop
endif
T1Con.0=0
period.LowByte=CCPR1L
period.HighByte=CCPR1H
They would all be zero since TMR1 was disabled after the T1CON.0=0.
Once period = CCPR1L & CPR1H it's a done deal until the next capture,
and Timer1 is re-enabled.

Capture works wether or not Timer1 is enabled. It just returns 0 if it's off.

Yet - I may be missing something...;)

Darrel Taylor
- 29th January 2010, 04:34
Yup...:)

But that's a very interesting point.

In the 4620 program it does turn off the timer at that point.
But the 877A program does not.

And you can even see the difference in the simulation.
The 4620 always has the same values for CCPR1L:H and period (+1?), but the 877A doesn't.

4620
T1CON.0=1
Capture = 0

CaptureLoop:
If Capture = 0 then
Goto CaptureLoop
endif
T1Con.0=0
period.LowByte=CCPR1L
period.HighByte=CCPR1H

RPM = 10000


877A
T1CON.0 = 1 ' Start the Timer
capture = 0 ' Reset the capture flag

CaptureLoop:
IF capture = 0 Then
goto CaptureLoop ' Wait here until captured
endif
; nada
period.lowbyte = CCPR1L ' Store the captured value in
period.highbyte = CCPR1H ' period variable

RPM = 10000


And when a Timer is turned off, it retains the last value in the TMR?L:H registers.
<br>

Tobias
- 29th January 2010, 04:48
With all that in mind, what do I need to change from the last code I posted to get RPM correct?

Bruce
- 29th January 2010, 04:50
Hey Darrel,

Disabling TMR1 after the event has zero affect on the value that CCPR1l & CCPR1H record at the time of the event. The value in Timer1 is captured immediatley on event.

Can you recommend something for the OP that wiil fix it?

If you can -- he gets the free PIC, and I'll send you a six-pack of your favorite BEER...:)

FYI: Disabling the timer after the capture event has zero effect on the value captured by the hardware catpure module.

Remember ... It's done in hardware

Tobias
- 29th January 2010, 05:05
Bruce
Ship a couple of the chips tomorrow. I will pay for them. I need to get this calculating correctly soon. If you mail tomorrow I bet I have it saturday.

Darrel Taylor
- 29th January 2010, 05:13
Disabling TMR1 after the event has zero affect on the value that CCPR1l & CCPR1H record at the time of the event. The value in Timer1 is captured immediatley on event.
Absolutely true!
But the numbers given originally were from multiple captures without the timer being turned off. So they were irrelevant and confusing.


Can you recommend something for the OP that will fix it?

If you can -- he gets the free PIC, and I'll send you a six-pack of your favorite BEER...:)
I can ... soon. Just don't want to have to say Oi Vey again.

Hell, ship him the chips, and I'll pay for them if I fail.
But long before he gets them, the problem will be solved, and I will drink your beer. :)
<br>

Bruce
- 29th January 2010, 05:17
Hey Toby,

I'm real sorry I didn't order three of these things for you, but if you refer back to post
#23 -- you'll see what happened.

Bruce
- 29th January 2010, 05:26
But long before he gets them, the problem will be solved, and I will drink your beer.

Cool, but you have to prove me wrong to get that BEER...:)

What's your favorite suds?

Just want to be prepared for when you DO....:)

Tobias
- 29th January 2010, 05:34
One will be fine too, will it ship tomorrow? Not that I don't have faith in DT

Charles Linquis
- 29th January 2010, 05:43
Tobias,

Not that I think there is anything wrong with the way you are doing things, but - I earlier posted a routine that can read virtually any number of tachometers to good accuracy, and to RPMs far past 15000 (if your tach output is the standard 2 pulse/rev) type. It averages over a period, so jitter
isn't a problem.

It is interrupt-driven, and runs totally in the background.

Tobias
- 29th January 2010, 05:45
Did you ever test it on an 18F4620? I found it. I am sure I will have a few questions in the morning.

Darrel Taylor
- 29th January 2010, 06:00
I earlier posted a routine that can read virtually any number of tachometers to good accuracy, and to RPMs far past 15000 (if your tach output is the standard 2 pulse/rev) type.

BEER thief :eek:
<br>

Bruce
- 29th January 2010, 06:03
Yep. My order was shipped UPS RED, and should be here tomorrow, so I'll be shooting
your 18F4431 TQFP out by standard Priority Mail. You should be receiving it pretty fast
with you being just down-the-road.


Not that I don't have faith in DT
You should .. he's a real genius at this stuff...;)

BTW: Your total for the 18F4431 TQFP + shipping is $11.55, which is exactly our cost for
the part + shipping. Just make a Paypal payment in this amount to [email protected]

And, if you need any help using this thing - just ask. I've done a boat-load of commercial
apps with these.

Tobias
- 29th January 2010, 06:07
Thanks check your PayPal acct

Bruce
- 29th January 2010, 06:08
BEER thief
That is just so WRONG ... hit squad has been mobilized....;)

Darrel Taylor
- 29th January 2010, 06:52
If Charles hadn't done it with DT_INTS, I might have been upset (longer).

But he did (http://www.picbasic.co.uk/forum/showpost.php?p=77705&postcount=12) ...
More things to simulate.

I might have to send Charles a 6-pack too. :D
<br>

Bruce
- 29th January 2010, 07:09
You ain't getting off that easy bud .. you still have to prove me wrong, and show a solution to the problem....)

Darrel Taylor
- 29th January 2010, 07:19
Agreed, and accepted.

But just so I'm clear, what I'm proving wrong is that it's a revision or errata sheet problem with the 18F4620 itself.
And that using an 18F4431 will solve it?

In other words, I gotta do it in hardware too?
<br>

Bruce
- 29th January 2010, 07:35
You just have to prove that my recommendations throughout this thread (for this specific controller) were wrong, and show your solution to the problem - using the same controller.

My point thus far has been that this particular controller is doo-doo. Your entry point on this thread stated;

I think you need to clear the timer sooner.

boroko
- 29th January 2010, 09:20
Darrel, help me understand here...

I thought that Proteus dealt with many versions of compilers except PBP.

Are you just running the already compiled program and reverse troubleshooting in your head? I imagine that watching the registers would let you know where you are at and if you could transpose between the two, it would work.

Care to elaborate on how you use it to help you?
Bo

Darrel Taylor
- 29th January 2010, 10:23
You just have to prove that my recommendations throughout this thread (for this specific controller) were wrong, and show your solution to the problem - using the same controller.
I had missed post#22 while working with proteus, but it didn't matter ... it works too.

So, at the risk of loosing beer :eek: ... and buying chips ...
Other than the problems that were fixed earlier ... CCP1CON missing ... period instead if CCPR1L:H ...

This is the problem ....

The 4620's oscillator is running at 20.13 mhz

If it's a crystal, the caps are wrong or the crystal is off (or a radio crystal).
If it's a cheap resonator, then it's only to be expected.

That's my story ... and I'm sticking to it. :)
No way to prove it unless Toby checks it.

If I run the simulator at 20.13mhz, I get the exact same numbers across the board.
<br>

Charles Linquis
- 29th January 2010, 12:29
I rive in China. The address in my bio is just to confuse people.

Tobias
- 29th January 2010, 15:50
Theoretically I should be able to swap oscillators and the problem will be on the 877A. Give me a bit and I will try that.

Here is a link to the one I have on the boards.
http://mouser.com/ProductDetail/Kyocera-AVX/PBRC-2000HR/?qs=sGAEpiMZZMsBj6bBr9Q9aT0hc%252b7BflTbXFVfiWpjmq o%3d

Bruce
- 29th January 2010, 16:48
I think Darrel nailed it with the oscillator problem. Nice catch. I just assumed you were
testing different PICs on the same board.

Tobias
- 29th January 2010, 17:28
its the osc. I had no idea there could be that much variance. Can you suggest a better part number?

Darrel Taylor
- 29th January 2010, 18:58
Woohoo!
I can taste it already. :D

http://www.pbpgroup.com/files/180px-Guinness.jpg

Darrel Taylor
- 29th January 2010, 20:52
Can you suggest a better part number?

The datasheet for that resonator shows that they have other versions of the same thing but with tighter tolerances (down to 0.1%).
At least it will have the same footprint.

With 0.1%, at 6000 RPM it will read between 5990-6010. (according to proteus).

Darrel Taylor
- 29th January 2010, 21:13
I thought that Proteus dealt with many versions of compilers except PBP.
Currently, you can only simulate the .hex files directly in Proteus.
No single stepping through the program.

But you can use it as a debugger in MPLAB where you can single step and watch variables in PBP.
It's too slow for me that way though. It simulates in "Real-Time" when not animating.

It's like real hardware is sitting in front of you, only you can't create Smoke or Fry your chips. :)
I'm getting hooked on it.

It's just so nice not to have to build a breadboard to test things.
20 minutes, and you can draw it on the computer.

Plus, with the Logic Analyzer, O-Scope, I2C debugger etc.
It saves thousands on test equipment.

And my cats can't play with the wires. :D
<br>

Bruce
- 30th January 2010, 15:27
Darrel,

Are you using the free or full version?

Darrel Taylor
- 30th January 2010, 19:40
Using the Full version.

The free version doesn't let you draw your own circuits.
<br>

Tobias
- 30th January 2010, 22:54
Thanks for the help on getting the RPM working right.

Next question, when I want to incorporate this into other code how do I keep it from taking up as much time as just measuring the pulse width with Pulsin? I can't have it in the little CaptureLoop routine waiting for the next rpm pulse.

Looking through the spec sheet on the 4620, I see CCP1IE (PIE1.2). If I enable that bit, will I get an interrupt on each cylinder fire? I know there is a way to start and stop timer1 based on the cylinder firing and not just looping for the cylinder firing.

Here is what I am working on assuming that is the right path to take. I haven't worked with interrupts much so I am sure I need more work.
DEFINE OSC 20
Prefix con $FE ' needed before each command
LcdCls CON $51 ' clear LCD (use PAUSE 5 after)
CursorPS con $45 'Cursor Position
Capture VAR PIR1.2 ' CCP1 capture flag CCP1IF
Overflow VAR PIR1.0 ' Timer1 overflow flag TMR1IF:
RPM var word
period var Word
TotalTime var word 'Holds seconds and tics
Counter var word
Detect var bit
LCD VAR PortC.6 'LCD output


ADCON0 =0 'A/D Off
ADCON1.3=1 'All AN channels digital
ADCON1.2=1 '''
ADCON1.1=1 '''
ADCON1.0=1 '''
TRISE.0=1 'EO input
TRISE.1=1 'E1 input
CCP1CON = %00000110 ; Capture mode, every rising edge 0101 , Fourth 0110
T1CON.7=1 'enable timer 16 bit `
T1CON.6=1 'Timer1 OSC
T1CON.5=1 '1:4 prescaler
T1CON.4=0 '1:4 prescaler
T1CON.3=0 'Timer1 OSC off
T1CON.2=0 'sychro clock
T1CON.1=0 'internal clock
T1CON.0=0 'stop timer
PIE1.2=1 'Enables the CCP1 interrupt

pause 10
SEROUT2 LCD,84, [Prefix, LcdCls]

Include "modedefs.bas" ' Mode definitions for Serout
SEROUT2 LCD,84, [Prefix,CursorPS,0,"RPM test"]
pause 500

TMR1H = 0 'Clear 8-bit register
TMR1L = 0 'Clear 8-bit register
capture = 0 'Clear Timer
Detect = 0

ON Interrupt goto Measure_Time

Loop:
Counter = Counter + 1
SEROUT2 LCD,84, [Prefix,CursorPS,0,dec5 Counter]
SEROUT2 LCD,84, [Prefix,CursorPS,20,"RPM ",dec5 RPM, " ", #Detect]
goto loop

Disable
Measure_Time:
SEROUT2 LCD,84, [Prefix,CursorPS,40,"Int ",dec5 RPM]
If Detect = 0 then
T1CON.0=1
detect = 1
capture = 0
endif

If Detect = 1 then
T1CON.0=0
detect = 0
period.LowByte=CCPR1L
period.HighByte=CCPR1H
capture = 0
TMR1H = 0
TMR1L = 0

RPM = 10000
RPM = RPM * RPM ' 100,000,000
RPM = DIV32 period ' 100,000,000 / RevCount
RPM = RPM * 60 ' Per minute
RPM = DIV32 1600
RPM = (RPM*5)
endif
Enable
return

rmteo
- 30th January 2010, 22:59
See here Using hardware capture (http://www.picbasic.co.uk/forum/showthread.php?t=12562)

Tobias
- 31st January 2010, 00:12
Thanks for the link. The thing is though I don't want to go into a loop waiting for the tach pulse. I want to be able to do it by interrupt so I can be doing other things in between pulses and on the pulse go start/stop the timer.

rmteo
- 31st January 2010, 00:24
Look at post #9. This is its main loop:

Main:
' do other stuff here as required
IF CF.0 THEN ' figure out & print result only after last capture
PW = PW-T1 ' High pulse width = PW-T1
CF.0 = 0 ' clear flag bit
HSEROUT [DEC PW,"uS High",13,10]
ENDIF

GOTO Main

Tobias
- 1st February 2010, 23:16
Thanks, when I insert the RPM part of code I get an error. Except for when I comment out the DIV32.


' Measuring signal pulse widths with capture module & interrupt

' 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
Prefix con $FE ' needed before each command
LcdCls CON $51 ' clear LCD (use PAUSE 5 after)
LcdLine1 CON $00 ' move cursor to line 1
LcdLine2 con $40 ' move curson to line 2
LcdLine3 con $14 ' move curson to line 3
lcdLine4 con $54 ' move curson to line 4
LcdCol1 con $00 ' move cursor to column 1
LcdCol2 con $07 ' move cursor to column 7
Backlight con $53 ' Backlighting 1-8
CursorPS con $45 'Cursor Position
CursorOn con $47 'Cursof On
CursorOff con $48 'Cursor Off
LCD VAR PortC.6 'LCD output
DEFINE OSC 20 ' 4MHz for 1uS resolution TMR1 counts
DEFINE INTHAND CCP_INT ' declare high-pri interrupt handler

Symbol Capture = PIR1.2 ' CCP1 capture flag
SYMBOL CapIE = PIE1.2 ' CCP1 interrupt enable bit
SYMBOL CapPriEn = IPR1.2 ' priority enable bit for CCP1 interrupt
SYMBOL PriEnable = RCON.7 ' set to enable priority levels on interrupts

T1 VAR WORD BANKA SYSTEM ' 1st capture value
PW VAR WORD BANKA SYSTEM ' 2nd capture value & ultimately final pulse width
CF VAR BYTE BANKA SYSTEM ' indicates when last capture is ready
RPM var word
Period var word
CLEAR ' clear RAM on POR
TRISC.2 = 1 ' CCP1 input pin (Capture input on 18F242)
INTCON = 0 ' Interrupts off for now

GOTO Init ' jump over interrupt handler

ASM
CCP_INT
BTFSS CCP1CON,0 ; capture from rising edge?
BRA Fall ; no .. goto falling edge
MOVFF CCPR1L, T1 ; get low capture byte into T1
MOVFF CCPR1H, T1+1 ; get high capture byte into T1
BRA IntExit ; outta here
Fall
MOVFF CCPR1L, PW ; get low capture byte into PW
MOVFF CCPR1H, PW+1 ; get high capture byte into PW
BSF CF,0 ; indicate last capture
IntExit
BTG CCP1CON,0 ; toggle between rising/falling edge captures
BCF PIR1,2 ; clear capture interrupt flag bit
RETFIE FAST ; return/restore W, STATUS and BSR
ENDASM

Init: ' initialize a few things first
CCP1CON = %00000110 ' Capture mode, capture on rising edge
'T1CON = 0 ' TMR1 prescale=1, clock=Fosc/4, TMR1=off
T1CON.7=1 'enable timer 16 bit `
T1CON.6=1 'Timer1 OSC
T1CON.5=1 '1:4 prescaler
T1CON.4=0 '1:4 prescaler
T1CON.3=0 'Timer1 OSC off
T1CON.2=0 'sychro clock
T1CON.1=0 'internal clock
TMR1H = 0 ' Clear high byte of TMR1 counter
TMR1L = 0 ' Clear low byte
PriEnable = 1 ' enable priority levels on interrupts
Capture = 0 ' clear capture flag bit
CapPriEn = 1 ' set CCP1 int to high priority
CapIE = 1 ' enable the CCP1 capture interrupt
INTCON = %11000000 ' global + peripheral ints enabled
T1CON.0 = 1 ' Turn TMR1 on here

Main:
' do other stuff here as required
IF CF.0 THEN ' figure out & print result only after last capture
PW = PW-T1 ' High pulse width = PW-T1
Period = PW
CF.0 = 0 ' clear flag bit
RPM = 10000
'RPM = RPM * RPM ' 100,000,000
'RPM = DIV32 period ' 100,000,000 / RevCount
RPM = RPM * 60 ' Per minute
'RPM = DIV32 1600
RPM = (RPM*5)
SEROUT2 LCD,84, [Prefix,CursorPS,0,#PW]
ENDIF

GOTO Main

END

Bruce
- 1st February 2010, 23:36
Change T1 VAR WORD BANKA SYSTEM to something else. My example was a PBP
re-make from a Microchip app note using T1 as a variable, and didn't use DIV32.

PBP has an internal variable it uses named T1 for complex math equations. Just changing
the name of this variable should clear the problem.

aratti
- 2nd February 2010, 09:59
PBP has an internal variable it uses named T1 for complex math equations. Just changing
the name of this variable should clear the problem.

Bruce, thank you for this information (there is no trace into the PBP manual!)

There are other reserved words, we should avoid and not mentioned into the PBP manual?

Al.

HenrikOlsson
- 2nd February 2010, 10:31
Hi Al,
PBP declares several internal variables as it needs them. Names are R0 - R8, T0 - T7, FLAGS, GOP, RM1, RM2, RR1, RR2, RS1, RS2, PRODL, TBLPTRU, TBLPTRH, TBLPTRL and perhaps some I've missed. Some get's declared in every program and some only depending on what your PBP code does.

This, of course, isn't something I've figured out myself - I've simply looked at Darrels Instant Interrupt code - specifically the ReEnterPBP18 file.

/Henrik.

Dave
- 2nd February 2010, 12:01
Tobias, The RESERVED words are in the manual and are not to be used, they are on the last couple of pages or so...

Dave Purola,
N8NTA

aratti
- 2nd February 2010, 12:17
Hi Henrik, thank you for your post. "Every day is a good to learn something knew, but again, let me stess my point "NO MENTION IN THE MANUAL" (at least mine) and this is pretty bad.

What now will make me worring for a while (till I will forget it) is your statement
"... and perhaps some I've missed". Is there a way to obtain the full list?

Al.

HenrikOlsson
- 2nd February 2010, 13:04
Hi Al,
I don't see anything about the system variables in the manual either but I don't think it's that big of a problem. If you're trying to declare T2 (or whatever) in your program but the compiler also declares T2 as it needs it for its library calls you'll get an error saying Redefinition of VAR - which I guess is the error Tobias got when he was using T1. So, it shouldn't cause any real trouble.

/Henrik.

Bruce
- 2nd February 2010, 15:03
What happens is something like this;

Declaring T1 VAR WORD BANKA SYSTEM creates a user VAR T1 without the underscore. Then you can use T1 in your assembler routine without the underscore like in my example.

T1 VAR BYTE BANKA removing the SYSTEM part would create the user variable with the underscore _T1, which wouldn't clash with the PBP temp system variable T1.

I.E. the user var would be _T1. PBPs system var would be T1.

A good rule-of-thumb would be to just never declare a system variable with any PBP system variable name. Totally my fault on this one. I did this for someone that asked me to translate a Microchip Tips & Tricks example to PBP, and just didn't consider T1, like used in the Microchip example.

Maybe it wouldn't be a bad idea for the PBP manual to include a complete list of all temp system variables?

Standard PBP system variables are listed in the reserved words section, but none of the temp variables, that may or may not even be used, for heavy number crunching are.

Tobias
- 2nd February 2010, 18:13
The RPM code works great. I changed a few things around like the scaler configs to work with a V-8. I incorporated it into the other code I have that also uses the elapsed time code. When I compile I got an error centered around DEFINE INTHAND CCP_INT. So I looked in the elapsed-18-t3con.bas file and it has Define INTHAND _ClockCount I did some research on the forums and found I can used INTLHAND. Apparently I am defining two high priority interrupt handlers and that is a no-no. So I changed the line to Define INTLHAND _ClockCount . From what I have learned the LHAnd is another interrupt handler with a lower priority.

I have changed the Elapsed code to use T3 and also go to the thousandths of a second. It worked fine separately too. The code is on the next post.

When I start the timer, apparently the code goes into a loop on the elasped time code. If I don't start the timer, the code progresses to the next line of code and beyond. I have tried changing around the INTLHAND and INTHAND but same result.


Start var PortB.0
OnOff var PortB.1 'Input to start timers
Dig4 Var PortB.2
Reset var PortB.3
SOR VAR PortC.7 'Shift Over-Ride
Dig1 Var PortC.0
Dig2 var PortA.0
Dig3 var PortA.1
Up1 var PortA.3 'Up button to change seconds
Down1 var PortA.2 'Down button to change seconds.
Up001 var PortE.0 'Up button to change tenths of second.
Down001 var PortE.1 'Down button to change tenths of second.
Up01 var PortA.4 'Up button to change hundredths of a second
Down01 var PortA.5 'Down button to change hundredths of a second
Tool var PortB.4 'Button to change to diffent menu
UpStage var PortD.0 'Button to change stages
DownStage var PortC.3 'Button to change stages
LCD VAR PortC.6 'LCD output
RPMInput var PortC.2
Gate1 Var PortC.1
Gate2 var PortD.1
Gate3 var PortD.2
Gate4 var PortD.3
Gate5 var PortD.6
Gate6 var PortD.7
Gate7 var PortD.5
Gate8 var PortD.4
StageCounter var byte
OnOffType var Bit 'Toggles between On/Off part of a Stage
ETorRPM var Bit
EditStage var byte


TotalTime var word 'Holds seconds and tics

Active var bit
Prefix con $FE ' needed before each command
LcdCls CON $51 ' clear LCD (use PAUSE 5 after)
LcdLine1 CON $00 ' move cursor to line 1
LcdLine2 con $40 ' move curson to line 2
LcdLine3 con $14 ' move curson to line 3
lcdLine4 con $54 ' move curson to line 4
LcdCol1 con $00 ' move cursor to column 1
LcdCol2 con $07 ' move cursor to column 7
Backlight con $53 ' Backlighting 1-8
CursorPS con $45 'Cursor Position
CursorOn con $47 'Cursof On
CursorOff con $48 'Cursor Off

Symbol Capture = PIR1.2 ' CCP1 capture flag
SYMBOL CapIE = PIE1.2 ' CCP1 interrupt enable bit
SYMBOL CapPriEn = IPR1.2 ' priority enable bit for CCP1 interrupt
SYMBOL PriEnable = RCON.7 ' set to enable priority levels on interrupts
TS VAR WORD BANKA SYSTEM ' 1st capture value
PW VAR WORD BANKA SYSTEM ' 2nd capture value & ultimately final pulse width
CF VAR BYTE BANKA SYSTEM ' indicates when last capture is ready
RPM var word BANKA SYSTEM
Period var word BANKA SYSTEM
define CODE_SIZE 32
define osc 20
DEFINE INTHAND CCP_INT ' declare high-pri interrupt handler

Capture_Loop = 0
CLEAR ' clear RAM on POR
TRISC.2 = 1 ' CCP1 input pin (Capture input on 18F242)
INTCON = 0 ' Interrupts off for now

INTCON2.7 = 0 'Pull Ups enabled
ADCON0 =0
ADCON1.3=1
ADCON1.2=1
ADCON1.1=1
ADCON1.0=1
TRISE.0=1
TRISE.1=1

'---------Display Start-Up Info-------
Include "Elapsed-18-T3CON.bas"
Include "modedefs.bas" ' Mode definitions for Serout

Pause 200
gosub ClearScreen
pause 100
GOTO Init
ASM
CCP_INT
BTFSS CCP1CON,0 ; capture from rising edge?
BRA Fall ; no .. goto falling edge
MOVFF CCPR1L, TS ; get low capture byte into T1
MOVFF CCPR1H, TS+1 ; get high capture byte into T1
BRA IntExit ; outta here
Fall
MOVFF CCPR1L, PW ; get low capture byte into PW
MOVFF CCPR1H, PW+1 ; get high capture byte into PW
BSF CF,0 ; indicate last capture
IntExit
BTG CCP1CON,0 ; toggle between rising/falling edge captures
BCF PIR1,2 ; clear capture interrupt flag bit
RETFIE FAST ; return/restore W, STATUS and BSR
ENDASM

Init: ' initialize a few things first
CCP1CON = %00000110 ' Capture mode, capture on rising edge
T1CON.7=1 'enable timer 16 bit `
T1CON.6=1 'Timer1 OSC
T1CON.5=1 '1:4 prescaler
T1CON.4=0 '1:4 prescaler
T1CON.3=0 'Timer1 OSC off
T1CON.2=0 'sychro clock
T1CON.1=0 'internal clock
TMR1H = 0 ' Clear high byte of TMR1 counter
TMR1L = 0 ' Clear low byte
PriEnable = 1 ' enable priority levels on interrupts
Capture = 0 ' clear capture flag bit
CapPriEn = 1 ' set CCP1 int to high priority
CapIE = 1 ' enable the CCP1 capture interrupt
INTCON = %11000000 ' global + peripheral ints enabled
T1CON.0 = 1 ' Turn TMR1 on here

Gosub ResetTime

'---------Pre Run Routine------------------------------
PreRun:
Repeat
Serout2 LCD, 84, [Prefix,CursorPS,64,"Ready ", DEC5 RPM]
gosub Tach
Gosub Shift
Until Start = 0 and OnOff = 0
'-----------Run Routine--------------------------

While Start = 0 and OnOff = 0
PrvOnOffType=0
wend
Active = 1
Run: '''''''''''''''''''''''''''''''''''''''''''''''''' ''''''''''''''''''''''''''''''''''''''''

While Start=0 and OnOff = 1 '''''!!!!!!!!!!!!!!!

If Active = 1 then
Gosub StartTimer
endif
Serout2 LCD,84,[Prefix,CursorPS,71,"test "]', #Stage3TOn]
''''Code doesn't make it this far. If I comment out 'gosub startimer' it makes it to this line.
Gosub Calc_TotalTime
Wend
gosub Tach

Tobias
- 2nd February 2010, 18:14
Here is the elasped timer code I modified to use T3 and go to the thousandths. Also I have the interrupt set up as INTLHAND


'************************************************* ***************
'* Name : ELAPSED.PBP *
'* Author : Darrel Taylor *
'* Notice : Copyright (c) 2003 *
'* Date : 12/16/2003 *
'* Notes : *
'************************************************* ***************
disable debug

Define INTLHAND _ClockCount ' Tell PBP Where the code starts on an interrupt
Include "ASM_INTS-18.bas" ' ASM Interrupt Stubs

Ticks var Word ' 1/1000th of a second
Seconds var byte
Minutes var byte
Hours var byte
Days var word
R0save var word
R1save var word
R4save var word

SecondsChanged var bit
MinutesChanged var bit
HoursChanged var bit
DaysChanged var bit
SecondsChanged = 1
MinutesChanged = 1

Goto OverElapsed

' ------------------------------------------------------------------------------
Asm
IF OSC == 4 ; Constants for 100hz interrupt from Timer1
TimerConst = 0D8F7h ; Executed at compile time only
EndIF
If OSC == 8
TimerConst = 0B1E7h
EndIF
If OSC == 10
TimerConst = 09E5Fh
EndIF
If OSC == 20
TimerConst = 0EC80h
EndIF
If OSC == 40
TimerConst = 03CB7h
EndIF

; ----------------- ADD TimerConst to TMR1H:TMR1L
ADD2_TIMER macro
CHK?RP T3CON
BCF T3CON,TMR3ON ; Turn off timer
MOVLW LOW(TimerConst) ; 1
ADDWF TMR3L,F ; 1 ; reload timer with correct value
BTFSC STATUS,C ; 1/2
INCF TMR3H,F ; 1
MOVLW HIGH(TimerConst) ; 1
ADDWF TMR3H,F ; 1
endm

; ----------------- ADD TimerConst to TMR1H:TMR1L and restart TIMER1
RELOAD_TIMER macro
ADD2_TIMER
BSF T3CON,TMR3ON ; 1 ; Turn TIMER1 back on
CHK?RP PIR2
bcf PIR2, TMR3IF ; Clear Timer1 Interrupt Flag
endm

; ----------------- Load TimerConst into TMR1H:TMR1L
LOAD_TIMER macro
EndAsm
T3CON.0 = 0 ; Turn OFF Timer1
TMR3L = 0
TMR3H = 0
Asm
ADD2_TIMER
endm
EndAsm

' ------[ This is the Interrupt Handler ]---------------------------------------
ClockCount: ' Note: this is being handled as an ASM interrupt
@ INT_START
@ RELOAD_TIMER ; Reload TIMER1
R0save = R0 ; Save 2 PBP system vars that are used during
R1save = R1 ; the interrupt
R4save = R4
Ticks = Ticks + 1
if Ticks = 1000 then
Ticks = Ticks-1000
Seconds = Seconds + 1
SecondsChanged = 1
if Seconds = 60 then
Minutes = Minutes + 1
MinutesChanged = 1
Seconds = 0
endif
if Minutes = 60 then
Hours = Hours + 1
HoursChanged = 1
Minutes = 0
endif
if Hours = 24 then
Days = Days + 1
DaysChanged = 1
Hours = 0
endif
endif
R4 = R4save ; Restore the PBP system vars
R1 = R1save
R0 = R0save
@ INT_RETURN ; Restore context and return from interrupt

'-----====[ END OF TMR1 Interrupt Handler ]====---------------------------------

StartTimer:
T3CON.1 = 0 ; (TMR1CS) Select FOSC/4 Clock Source
T3CON.3 = 0 ; (T1OSCEN) Disable External Oscillator
PIR2.1 = 0 ; (TMR1IF) Clear Timer1 Interrupt Flag
PIE2.1 = 1 ; (TMR1IE) Enable TMR1 overflow interrupt
INTCON.6 = 1 ; (PEIE) Enable peripheral interrupts
INTCON.7 = 1 ; (GIE) Enable global interrupts
T3CON.0 = 1 ; (TMR1ON) Start TIMER1
@ if OSC == 40
T3CON.5 = 0 ; Prescaler = 1:2
T3CON.4 = 1
@ endif
return

; -----------------
StopTimer:
T3CON.0 = 0 ; Turn OFF Timer1
return

; -----------------
ResetTime:
R0save = T3CON.0 ; Save TMR1ON bit
T3CON.0 = 0 ; Turn OFF Timer1
TMR3L = 0
TMR3H = 0
@ LOAD_TIMER ; Load TimerConst
T3CON.0 = R0save ; Restore TMR1ON bit
Ticks = 0
Seconds = 0
Minutes = 0
Hours = 0
Days = 0
SecondsChanged = 1
return

OverElapsed:
enable debug

Tobias
- 2nd February 2010, 21:59
This appears to be working correctly. Are there any problems going this route?
Of course this isn't all the code, just the part that is relevant.


DEFINE INTHAND Direction

ASM
Direction
ENDASM
If PIR1.2 = 1 then
goto RPMASM
endif

If PIR2.1 = 1 then
goto ClockCount
endif
return

RPMASM:
ASM
CCP_INT
BTFSS CCP1CON,0 ; capture from rising edge?
BRA Fall ; no .. goto falling edge
MOVFF CCPR1L, TS ; get low capture byte into T1
MOVFF CCPR1H, TS+1 ; get high capture byte into T1
BRA IntExit ; outta here
Fall
MOVFF CCPR1L, PW ; get low capture byte into PW
MOVFF CCPR1H, PW+1 ; get high capture byte into PW
BSF CF,0 ; indicate last capture
IntExit
BTG CCP1CON,0 ; toggle between rising/falling edge captures
BCF PIR1,2 ; clear capture interrupt flag bit
RETFIE FAST ; return/restore W, STATUS and BSR
ENDASM

ClockCount: ' Note: this is being handled as an ASM interrupt
@ INT_START
@ RELOAD_TIMER ; Reload TIMER1
R0save = R0 ; Save 2 PBP system vars that are used during
R1save = R1 ; the interrupt
R4save = R4
Ticks = Ticks + 1
if Ticks = 1000 then
Ticks = Ticks-1000
Seconds = Seconds + 1
SecondsChanged = 1
if Seconds = 60 then
Minutes = Minutes + 1
MinutesChanged = 1
Seconds = 0
endif
if Minutes = 60 then
Hours = Hours + 1
HoursChanged = 1
Minutes = 0
endif
if Hours = 24 then
Days = Days + 1
DaysChanged = 1
Hours = 0
endif
endif
R4 = R4save ; Restore the PBP system vars
R1 = R1save
R0 = R0save
@ INT_RETURN ; Restore context and return from interrupt

Bruce
- 3rd February 2010, 16:12
You don't need the bit tests in Direction since you have CCP_INT (or Direction) set as a high-priority interrupt, and you have ClockCount set as a low-priority interrupt.

Direction will be jumped to automatically when the CCP interrupt fires. ClockCount will be jumped to automatically when the TMR3 interrupt fires. Note that your low-priority interrupt can be interrupted by the high-priority one.