Code:
'****************************************************************************************************
'* Name : Pulses Timer.pbp *
'* Date : 25-02-17 *
'* Device : 16F648A (4k code space). *
'* Version : 1.0 *
'* Notes 1 : words with (PBP 3.0.6.4) with thanks to Darrel Taylor for his ISR. *
'* : *
'* : Uses DT's Instant Interrupts with Tmr0 for a 4ms window and Tmr1 for pulse duration. *
'* : *
'* : The code records multiple injection events within a 4ms window and combines all for *
'* : total fuel time, also takes longest pulse and self adjusts reference duration if it *
'* : exceeds current set DutyCycle value. A low value first read from EEPROM allows early *
'* : updates to the LCD. Updated value can be saved to EEPROM by pushbutton control. *
'* : *
'* : A switch sets expected polarity of the incoming pulses - normally high pulsing low as *
'* : measured at injector [usual] or normally low pulsing high at ecu output [possible]. *
'* : *
'* : *
'****************************************************************************************************
'
' LCD PIC(F648A) OTHER
'
' DB0-3 No connection
' DB4 PortA.0 (pin 17)
' DB5 PortA.1 (pin 18)
' DB6 PortA.2 (pin 1)
' DB7 PortA.3 (pin 2)
' RS PortA.4 (pin 3) 10K pullup to 5v due Open Drain.
' MCLR (pin 4) 10k pullup to 5v.
' RW Ground (pin 5)
' Vdd 5 volts (pin 14)
' Vss Ground (pin 5)
' Vo 20K LCD contrast potentiometer wiper (or ground).
' PortB.0 (pin6) Set button (10k pullup to 5v).
' PortB.1 (pin7) + button (10k pullup to 5v).
' PortB.2 (pin 8) - button (10k pullup to 5v). Hardware serial port Rx.
' (CCP1) PortB.3 (pin 9) Input for Pulses/Duty Cycle via 1k.
' PortB.4 (pin 10) Polarity of pulse switch - Pulled up.
' PortB.5 (pin 11)
' PortB.6 (pin 12)
' PortB.7 (pin 13) Debug in via 22k.
' Xtal PortA.6 (pin 15) Debug out via 1k.
' E Xtal PortA.7 (pin 16)
'=========================================================================================================
' CONFIGURE DEVICE
'=========================================================================================================
' The config can set RB0 or RB3 for CCP1 capture use. Confirm by viewing the fuses code box via the programmer.
#CONFIG
__config _INTRC_OSC_NOCLKOUT & _WDT_ON & _PWRTE_OFF & _MCLRE_ON & _LVP_OFF & _CP_OFF
#ENDCONFIG
wsave VAR BYTE $70 SYSTEM ' Save location for W
' -----[ Initialization ]------------------------------------------------------------------------------------------------
CMCON = 7 ' Disable analog comparators.
T1CON = 0 ' TIMER1: Clock Internal, Pre-scaler 1:1
Define OSC 4 ' Set Xtal Frequency
' Define LCD connections Change these to match your LCD
DEFINE LCD_DREG PORTA ' LCD Data Port
DEFINE LCD_DBIT 0 ' Starting Data Bit
DEFINE LCD_RSREG PORTA ' Register Select Port
DEFINE LCD_RSBIT 4 ' Register Select Bit
DEFINE LCD_EREG PORTA ' Enable Port
DEFINE LCD_EBIT 7 ' Enable Bit
DEFINE LCD_BITS 4 ' Data Bus Size
DEFINE LCD_LINES 2 ' Number of Lines on LCD
DEFINE DEBUG_REG PORTA ' Port_A outgoing serial communication.
DEFINE DEBUG_BIT 6
DEFINE DEBUG_BAUD 9600
DEFINE DEBUG_MODE 1 ' Debug mode: 0 = True, 1 = Inverted
'Includes
Include "Modedefs.bas" ' Mode definitions for Debug, Serin/out, Shiftin/out, Xin/out.
INCLUDE "DT_INTS-14.bas" ' Base Interrupt System
INCLUDE "ReEnterPBP.bas" ' Include if using PBP interrupts
ASM
INT_LIST macro ; IntSource, Label, Type, ResetFlag?
INT_Handler TMR0_INT, _ToggleLED2, PBP, yes
endm
INT_CREATE ; Creates the interrupt processor
; INT_ENABLE TMR0_INT ; enable Timer 0 interrupts. [WJS] normally enabled here but not for this app. as it
ENDASM ; is only enabled when required for the timing windows.
' OPTION_REG = %10010011 ; Prescale of 16 will give 4ms interrupt (8ms period).
OPTION_REG = %10010010 ; Prescale of 8 will give 2ms interrupt (4ms period).
Data "Pulses Timer",word 400 ' Next locn is 14.
'=========================================================================================================
' PIN ASSIGNMENTS, SYSTEM CONSTANTS, TEMPORARY VARIABLES
'=========================================================================================================
' Alias pins
Set var PORTB.0 ' Set button.
Plus var PORTB.1 ' + button.
Minus var PortB.2 ' - button.
SignalInput var PORTB.3 ' Input pulses pin.
Polar var PORTB.4 ' Polarity switch for output pin - normal high going low or normal low going high.
LED2 var PORTB.7 ' LED for Tmr0 testing.
' Variables
PulseHigh1 var word ' Width of 1st +ve going pulse, idling low.
PulseLow1 var word ' Width of 1st -ve going pulse, idling high.
PulseHigh2 var word ' Width of 2nd +ve going pulse, idling low.
PulseLow2 var word ' Width of 2nd -ve going pulse, idling high.
PulseHigh3 var word ' etc...
PulseLow3 var word '
PulseHigh4 var word '
PulseLow4 var word '
PulseHigh5 var word '
PulseLow5 var word '
SumPulseHigh var word ' Sum of Widths of +ve going pulses, idling low.
SumPulseLow var word ' Sum of Widths of -ve going pulses, idling high.
DC100 var word ' Value of 100% Duty Cycle for math calcs despite frequency.
Dummy var Word ' For Div32 math.
DutyCycle var word ' Percentage of pulse ratio wrt DC100.
MaxPulse var word ' Max pulse measured - should always be the Main injection pulse.
x var word ' Loop counter.
Events var byte ' Number of inj pulses per cycle.
Sign var byte ' + or - sign for serial indication of polarity.
Window var bit ' Event window - limits time when pulses are valid. 1 = open, 0 = closed.
' Alias Definition
T1ON var T1CON.0
' Software/Hardware initialisation
CLEAR
TRISA = %00001111 ' PORTA I/O.
TRISB = %10011111 ' RB3 as input for pulses, RB4 is polarity select switch.
PortA.6 = 0 ' Set low for serial debug idle state.
read 12,word DC100 ' Read initial value of stored DutyCycle (start with 400).
MaxPulse = 0 ' Reset count - can only get bigger from here.
Events = 0 ' Reset count.
GOSUB ClearTimer
First: ' Operation when system first powered up.
' Load custom characters to LCD CGRam memory.
LCDOUT $FE,64 ' Set CGRam mode.
LCDOUT $FE,$40,15,9,9,9,9,9,9,25 ' Cust Char #0 +ve pulse symbol.
LCDOUT $FE,$48,25,9,9,9,9,9,9,15 ' Cust Char #1 -ve pulse symbol.
LCDOUT $FE,1,$FE,2 ' Exit CGRam mode, Clear screen and home cursor.
goto Start ' Jump subs.
'=========================================================================================================
' Subroutines here in the first page...
'=========================================================================================================
ClearTimer:
TMR1L=0
TMR1H=0
RETURN
AdjustDC100:
for x = 0 to 99 ' 100 cycles.
LCDOUT $FE,2,"DC 100% = ",dec4 DC100,"us"
LCDOUT $FE,$C0," Set + - "
if plus = 0 then ' + pushed.
DC100=DC100+10 ' increment in 10us lumps.
pause 50
else
if Minus = 0 then ' - pushed.
DC100=DC100-10 ' decrement in 10us lumps.
pause 50
endif
endif
pause 100 ' .1*100 = 10 second loop.
If Set = 0 then ' Set is pushed.
While Set = 0 ' If still pressed then wait -
PAUSE 5 ' - until released.
Wend
write 12,DC100.lowbyte ' Store new value in EEPROM.
write 13,DC100.Highbyte ' Store new value in EEPROM.
LCDOUT $FE,$C0," Stored okay... "
pause 2000 ' Time to read it.
return ' Jump out once done.
endif
next
return
'=========================================================================================================
' Program area...
'=========================================================================================================
Start:
' Check if buttons pushed.
If plus = 0 then ' Plus button pushed.
While plus = 0 ' If still pressed then wait -
PAUSE 5 ' - until released.
Wend
gosub AdjustDC100
endif
If Minus = 0 then ' Minus button pushed.
While Minus = 0 ' If still pressed then wait -
PAUSE 5 ' - until released.
Wend
MaxPulse = 0 ' Reset Max.
endif
' Check Polarity switch state.
if polar = 1 then ' Switch open - this pin sits high due pullup, expects high pulse.
sign = "+" ' expecting high pulse.
LCDOUT $FE,2,1 ' Cust Char #1 +ve pulse Line 1 posn 1.
goto GetHighs ' Jump to routine.
endif
if polar = 0 then ' Switch closed - this pin sits low, expects low pulse.
sign = "-" ' expecting low pulse.
LCDOUT $FE,2,0 ' Cust Char #0 -ve pulse Line 1 posn 1.
goto GetLows ' Jump to routine.
endif
GetHighs: ' Measure high pulses
WHILE SIGNALINPUT = 0 ' Waiting for rising edge.
WEND
' Start timers - a rising edge has been detected to get here.
@ INT_ENABLE TMR0_INT ; Enable Tmr0 interrupts for 4ms window.
Window = 1 ' Open the pulse count window.
while Window = 1 '
T1ON = 1 ' Start Pulse Timer tmr1.
WHILE SIGNALINPUT = 1 ' Wait for next falling edge.
WEND
T1ON = 0 ' Stop timer.
Events = 1 '
PULSEhigh1.HIGHBYTE=TMR1H ' Store results.
PULSEhigh1.LOWBYTE=TMR1L '
if PULSEhigh1 > MaxPulse then
MaxPulse = PULSEhigh1 ' Capture longest pulse.
endif
gosub Cleartimer ' Reset Timer1 register (TMR1L, TMR1H).
' Capture additional high pulses
WHILE SIGNALINPUT = 0 ' Waiting for rising edge.
WEND
T1ON=1 ' Start Pulse Timer tmr1.
WHILE SIGNALINPUT = 1 ' Wait for next falling edge.
WEND
T1ON = 0 ' Stop timer.
Events = 2 '
PULSEhigh2.HIGHBYTE=TMR1H ' Store results.
PULSEhigh2.LOWBYTE=TMR1L '
if PULSEhigh2 > MaxPulse then
MaxPulse = PULSEhigh2 ' Capture longest pulse.
endif
gosub Cleartimer ' Reset Timer1 register (TMR1L, TMR1H).
WHILE SIGNALINPUT = 0 ' Waiting for rising edge.
WEND
T1ON=1 ' Start Pulse Timer tmr1.
WHILE SIGNALINPUT = 1 ' Wait for next falling edge.
WEND
T1ON = 0 ' Stop timer.
Events = 3 '
PULSEhigh3.HIGHBYTE=TMR1H ' Store results.
PULSEhigh3.LOWBYTE=TMR1L '
if PULSEhigh3 > MaxPulse then
MaxPulse = PULSEhigh3 ' Capture longest pulse.
endif
gosub Cleartimer ' Reset Timer1 register (TMR1L, TMR1H).
WHILE SIGNALINPUT = 0 ' Waiting for rising edge.
WEND
T1ON=1 ' Start Pulse Timer tmr1.
WHILE SIGNALINPUT = 1 ' Wait for next falling edge.
WEND
T1ON = 0 ' Stop timer.
Events = 4 '
PULSEhigh4.HIGHBYTE=TMR1H ' Store results.
PULSEhigh4.LOWBYTE=TMR1L '
if PULSEhigh4 > MaxPulse then
MaxPulse = PULSEhigh4 ' Capture longest pulse.
endif
gosub Cleartimer ' Reset Timer1 register (TMR1L, TMR1H).
WHILE SIGNALINPUT = 0 ' Waiting for rising edge.
WEND
T1ON=1 ' Start Pulse Timer tmr1.
WHILE SIGNALINPUT = 1 ' Wait for next falling edge.
WEND
T1ON = 0 ' Stop timer.
Events = 5 '
PULSEhigh5.HIGHBYTE=TMR1H ' Store results.
PULSEhigh5.LOWBYTE=TMR1L '
if PULSEhigh5 > MaxPulse then
MaxPulse = PULSEhigh5 ' Capture longest pulse.
endif
gosub Cleartimer ' Reset Timer1 register (TMR1L, TMR1H).
wend
sumpulsehigh = pulsehigh1 + pulsehigh2 + pulsehigh3 + pulsehigh4 + pulsehigh5
dummy = MaxPulse*100 ' Perform the multiply ready for Div32.
DutyCycle = div32 DC100 ' Calculate wrt stored value.
' ### NB debug affected by interrupts!
'debug "Pol ",sign,", MaxPulse ",dec4 MaxPulse,"us, Events ",#Events,13
LCDOUT $FE,2,0," Inj ",dec4 maxpulse,"us Max" ' Write LCD line 1.
goto ShowMore ' Jump GetLows.
'===============================================================================================================
GetLows: ' Measure low pulses
while Signalinput = 1 ' Waiting for falling edge.
Wend
' Start timers - a falling edge has been detected to get here.
@ INT_ENABLE TMR0_INT ; Enable Tmr0 interrupts for 5ms window.
Window = 1 ' Open the pulse count window.
while Window = 1 ' ### is the first line needed?
T1ON = 1 ' Start timer1.
WHILE SIGNALINPUT = 0 ' Wait for next rising edge.
WEND
T1ON = 0 ' Stop Timer.
Events = 1 '
PULSElow1.HIGHBYTE = TMR1H ' Store result.
PULSElow1.LOWBYTE = TMR1L '
if PULSElow1 > MaxPulse then
MaxPulse = PULSElow1 ' Capture longest pulse.
endif
gosub Cleartimer ' Reset Timer1 register (TMR1L, TMR1H).
' Capture additional low pulses
while Signalinput = 1 ' Waiting for falling edge.
WEND
T1ON = 1 ' Start timer1.
WHILE SIGNALINPUT = 0 ' Wait for next rising edge.
WEND
T1ON = 0 ' Stop Timer.
Events = 2 '
PULSElow2.HIGHBYTE = TMR1H ' Store result.
PULSElow2.LOWBYTE = TMR1L '
if PULSElow2 > MaxPulse then
MaxPulse = PULSElow2 ' Capture longest pulse.
endif
gosub Cleartimer ' Reset Timer1 register (TMR1L, TMR1H).
while Signalinput = 1 ' Waiting for falling edge.
WEND
T1ON = 1 ' Start timer1.
WHILE SIGNALINPUT = 0 ' Wait for next rising edge.
WEND
T1ON = 0 ' Stop Timer.
Events = 3 '
PULSElow3.HIGHBYTE = TMR1H ' Store result.
PULSElow3.LOWBYTE = TMR1L '
if PULSElow3 > MaxPulse then
MaxPulse = PULSElow3 ' Capture longest pulse.
endif
gosub Cleartimer ' Reset Timer1 register (TMR1L, TMR1H).
while Signalinput = 1 ' Waiting for falling edge.
WEND
T1ON = 1 ' Start timer1.
WHILE SIGNALINPUT = 0 ' Wait for next rising edge.
WEND
T1ON = 0 ' Stop Timer.
Events = 4 '
PULSElow4.HIGHBYTE = TMR1H ' Store result.
PULSElow4.LOWBYTE = TMR1L '
if PULSElow4 > MaxPulse then
MaxPulse = PULSElow4 ' Capture longest pulse.
endif
gosub Cleartimer ' Reset Timer1 register (TMR1L, TMR1H).
while Signalinput = 1 ' Waiting for falling edge.
WEND
T1ON = 1 ' Start timer1.
WHILE SIGNALINPUT = 0 ' Wait for next rising edge.
WEND
T1ON = 0 ' Stop Timer.
Events = 5 '
PULSElow5.HIGHBYTE = TMR1H ' Store result.
PULSElow5.LOWBYTE = TMR1L '
if PULSElow5 > MaxPulse then
MaxPulse = PULSElow5 ' Capture longest pulse.
endif
gosub Cleartimer ' Reset Timer1 register (TMR1L, TMR1H).
' Window = 0 ' Close the pulse count window. #### Testing - Int should do this.
wend
sumpulselow = pulselow1 + pulselow2 + pulselow3 + pulselow4 + pulselow5
dummy = maxpulse*100 ' Perform the multiply ready for Div32.
DutyCycle = div32 DC100 ' Calculate wrt stored value.
' ### NB affected by interrupts!
'debug "Pol ",sign,", MaxPulse ",dec4 MaxPulse,"us, ",#Events," Events, SumPulseLow = ",#sumpulselow,13
LCDOUT $FE,2,0," Inj ",dec4 PULSElow3,"us Max" ' Write LCD line 1.
ShowMore:
LCDOUT $FE,$C0,"DC",DEC2 DutyCycle,"% ",dec4 DC100," ",dec5 MaxPulse ' Write LCD line 2.
pause 500 ' Time to read.
goto start
'---[TMR0 - interrupt handler]-------------
ToggleLED2:
Window = 0 ' Close the window for pulse counting.
TOGGLE LED2 ' LED2 flashes, timed by TMR0.
@ INT_DISABLE TMR0_INT ; Disable Tmr0 interrupts ready for next window.
@ INT_RETURN ; Return to point where interrupt took place.
end
Bookmarks