Measuring duty cycle of short duration pulses with long period


Closed Thread
Results 1 to 13 of 13

Hybrid View

  1. #1
    Join Date
    Jun 2005
    Location
    West Australia
    Posts
    116


    Did you find this post helpful? Yes | No

    Default Re: Measuring duty cycle of short duration pulses with long period

    Hi All,

    I've done some research and have found modern diesels have multiple fuel injection events such is the speed of the piezo injectors with extremes of fuel pressure to pass. Events typically number up to 5 but some documents suggest up to 8.

    So my goal has changed slightly whereby I now want to capture each of these events and sum their duration for maximum fuel injected and also record the longest pulse (if 5 events this is most likely the middle one). I can use tmr1 for capturing each pulse's duration but I want to limit recording of valid events to a 4ms window (triggered by first pulse edge) and am not doing too well manipulating tmr0 using Darrel's Instant Interrupts. I really need to embrace these and use more often...

    The full code (work in progress!) shows what I am trying to do but without success. As written Led2 pulses about 1hz and I only see a 4ms flash if the asm parts are commented out - but then pulse values are wild and erratic.

    How does one start and stop DT's Ints or is there a better way to control a 4ms window. All advice is greatly appreciated.

    Cheers,
    Bill

    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

  2. #2
    Join Date
    May 2013
    Location
    australia
    Posts
    2,653


    Did you find this post helpful? Yes | No

    Default Re: Measuring duty cycle of short duration pulses with long period

    an alternative approach could be to use a chip with timer1 gate control.
    if the timer gate was connected to the injector signal and the timer read and reset at a metered rate
    the count would be directly proportional to the injector ontime [effectively a digital integrator].
    it should not be too difficult to find a suitable timer clock rate and integration period to suit.
    Warning I'm not a teacher

Similar Threads

  1. Count Pulses and duration
    By ruijc in forum mel PIC BASIC Pro
    Replies: 6
    Last Post: - 13th February 2014, 22:04
  2. Measuring Period of a pulse
    By c_moore in forum mel PIC BASIC Pro
    Replies: 4
    Last Post: - 17th February 2012, 05:15
  3. Measuring duty cycle when it can be 0 to 100.
    By Tobias in forum mel PIC BASIC Pro
    Replies: 3
    Last Post: - 3rd December 2011, 18:24
  4. Pin max current - short duration?
    By kevj in forum mel PIC BASIC Pro
    Replies: 6
    Last Post: - 2nd January 2008, 12:53
  5. Measuring Period & Hz
    By MaurI in forum mel PIC BASIC Pro
    Replies: 10
    Last Post: - 29th July 2005, 04:03

Members who have read this thread : 0

You do not have permission to view the list of names.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts