Shop OBEX P1 Docs P2 Docs Learn Events
Repetative Timing consistancy — Parallax Forums

Repetative Timing consistancy

tek_mantek_man Posts: 9
edited 2006-12-24 04:48 in General Discussion
I have recently aquired a basic stamp kit to create some simulators for automotive fuel and ignition systems (I teach vehicle repair and diagnostic tool usage)

A little background to let you know my experience level:

3 years University in EE and ME (years ago...)
15 years diagnosing and repairing vehicles (Primarily electrical / computer / emmisions systems)
I have Fortran and Pascal programming experience, and I currently use VB.net (intermediate skill level)

I understand electronic and circuits from a diagnostic point of view...Show me a diagram and I can diagnose and find the problem (and understand the cicuit in question)
What I do not have is practical electronic experience DESIGNING circuits (except for years ago in college), or programming said circuits to be functional.

I have gone completely through the "Whats a Micro Controller?" book and I have completed all of the practice examples (and modified most of them playing around)

The reason for the simulator is that it is much easier to hook up a scope to a known circuit in a classroom environment rather than everybody crowded around a vehicle.

For my first project, I am in process of making a fuel system simulator that would sequentially pulse 6 or 8 injectors. I would like to have a variable frequency (RPM) and pulsewidth (PW) for the injectors. I have designed a circuit using multiple LED's that I have used to get the programming right before I construct the actual circuit and training boards.

I have successfully created 2 totally different programs that accomplish ALMOST the same thing, but they each have a couple of issues that I would like some insight into..


The first (and simpler) program is this:
pulsewidth VAR Byte         ' variable to store PW of each pulse
off_time   VAR word         ' variable to store offtime between pulses
Current_inj VAR Byte        ' current injector being pulsed
 
CUrrent_inj = 10            ' I used pins 10 - 15 for "injector" drivers, this is #1
 
DO
 
  If Current_inj > 15 THEN Current_inj = 10
 
  GOSUB ck_timer
 
  PULSOUT Current_inj, pulsewidth
  PAUSE off_time
 
  Current_inj = CUrrent_inj + 1
 
LOOP
 
ck_timer:
  HIGH 0         ' I used 2 variable pots with RCTIME to adjust PW and OFFTIME on the fly
  HIGH 2
  PAUSE 25
 
  RCTIME 0,1, off_time
  RCTIME 1,1, pulsewidth
 
'CALCULATIONS TO SCALE PW AND OFFTIME GO HERE
 
RETURN

This program works very well with one minor issue... One a vehicle one of the characteristics of the fuel injectors when the vehicle is under load is that the individual pulses "overlap", in other words injector #2 fires before injector #1 turns off. Depending on the load this can cascade into having 3 or 4 injectors on at the same time. Obvously this first program does not address this issue. Other than that the program works flawlessly.

Here is another one that I wrote ( a little more complex) that addresses that issue but creates some more. This next one will overlap the pulses, but if I push the limits for PW or RPM ·it will appear to skip "Injectors" (LED's) or the timing is not consistant for each injector. (Even though this is not a time critical project, I get kind of anal about stuff like this)

' {$STAMP BS2}
' {$PBASIC 2.5}
pulse_width      VAR   Word
cycle_time       VAR   Word
Counter          VAR   Word
Current_injector VAR   Byte   ' current injector to be pulsed
Last_Injector    VAR   Byte   ' previous injector
Increment        VAR   Byte   ' step increment to loop (RPM)
Num_Injectors    CON   6
Cycle_time       =     100    ' this is the number of "counts" to cycle through all LED's
pulse_width      =     15     ' ON Time
Counter          =     0      ' keep track of where I am in the cycle
Increment        =     5      ' how fast to loop through (RPM)
 
DO
  Current_Injector = counter / ((cycle_time / Num_Injectors) + 1)      ' this is the current injector to be triggered based on cycle_time position

  GOSUB ck_injector_status

  IF counter > (cycle_time - Increment) THEN counter = 0

LOOP
 
ck_injector_status:
  IF Current_Injector = 0 THEN Last_Injector = 5 ELSE Last_Injector = Current_Injector - 1  ' figure out last injector fired
 
       '####### Check to see if the last injector needs to be turned off  (It does work)################## 
  IF counter < (cycle_time * Last_Injector) ** 10923 OR counter >= (cycle_time * Last_Injector) ** 10923 + pulse_width   THEN
    LOW Last_Injector + 10
  ENDIF
 
        ' ########### check to see if it is time to turn on the next injector (same logic as above) #################
  IF counter >= (cycle_time * Current_Injector) ** 10923 AND counter < (cycle_time * Current_injector ** 10923) + pulse_width    THEN
    HIGH Current_injector + 10
    IF current_injector = 5 THEN PAUSE 5   '######### the last injector always seemed "Short" so I added this
  ENDIF

  Counter = Counter + Increment '########### move one step in cycle

RETURN

THis is a little convoluted, but it does seem to work except when I start varying the PW and increment / cycle_time it will screw the timing up and the LEDs quit pulsing in the correct way.

Any insite would be much appreciated...I will post an explaination of my math in the second example tomorrow if needed (it is getting late and I am beat)

Thanks again for any help

Lee

Comments

  • Bruce BatesBruce Bates Posts: 3,045
    edited 2006-12-22 12:03
    Lee -

    Let's break this up into at least two posts, to avoid utter confusion. I have copied your first program below, and after we work on this, we can do the same thing with the second program. At this juncture I have made only minor modifications, just to make it a bit easier to read, and have it run a bit more efficiently. I have also added some comments and questions. Here is the ORIGINAL and unmodified Program One:

    The first (and simpler) program is this:

    [noparse][[/noparse]code]
    pulsewidth VAR Byte········ ' variable to store PW of each pulse

    off_time·· VAR word········ ' variable to store offtime between pulses

    Current_inj VAR Byte······· ' current injector being pulsed

    CUrrent_inj =·10··········· ' I used pins 10 - 15 for "injector" drivers, this is #1

    DO

    · If Current_inj > 15 THEN Current_inj = 10·'Reset inj to beginning

    · GOSUB ck_timer

    · PULSOUT Current_inj, pulsewidth

    · PAUSE off_time

    · Current_inj = CUrrent_inj + 1

    LOOP

    ck_timer:

    · HIGH 0········ ' I used 2 variable pots with RCTIME to adjust PW and OFFTIME on the fly

    · HIGH 2

    · PAUSE 25

    · RCTIME 0,1, off_time

    · RCTIME 1,1, pulsewidth

    'CALCULATIONS TO SCALE PW AND OFFTIME GO HERE

    RETURN

    This program works very well with one minor issue... One a vehicle one of the characteristics of the fuel injectors when the vehicle is under load is that the individual pulses "overlap", in other words injector #2 fires before injector #1 turns off. Depending on the load this can cascade into having 3 or 4 injectors on at the same time. Obvously this first program does not address this issue. Other than that the program works flawlessly.

    Here is your Program One slightly modified:

    <!--StartFragment -->The first (and simpler) program is this:



    [noparse][[/noparse]code]
    pulsewidth VAR Byte········ ' variable to store PW of each pulse

    off_time·· VAR word········ ' variable to store offtime between pulses

    Current_inj VAR·NIB······· ' current injector being pulsed

    'Constants

    'Now the starting and ending injectors can be changed throughout by
    'only modifying the following·two constants:

    Start_inj = 10
    End_inj·· = 15
    ' DEBUG "Starting" 'See below, presently a comment

    Main_Loop:

    ·FOR··Current_inj = Start_inj to End_inj·'Loop thru injectors 10-->15

    ·· GOSUB ck_timer·'Obtain user variables

    ·· PULSOUT Current_inj, pulsewidth ' Pulse injector "n"

    ·· PAUSE off_time·'Wait for variable off time

    ·NEXT

    · GOTO Main_Loop
    ·
    ck_timer: 'Subroutine

    · ·HIGH 0···' 2 variable pots with RCTIME to adj. PW and OFFTIME on the fly

    ·· HIGH 2

    ·· 'PAUSE 25·'No idea why this pause is here?

    ·· RCTIME 0,1, off_time

    ·· RCTIME 1,1, pulsewidth

    'CALCULATIONS TO SCALE PW AND OFFTIME GO HERE

    · RETURN
    END

    Regardless of which copy of the programs you view above:

    1.·either/both "fire" the injectors in sequence, and

    2. every PBASIC instruction MUST complete before the next instruction can take place.

    Thus, it is nearly impossible for the prgram logic to be causing what you seem to be seeing as injector overlap. So, I'd carefully check my wiring.

    It IS possible that the program is resetting (usually due to a current overload) and the injectors are not firing as you wish them to. You can make the following the first executable statement in the program to detect that condition:

    DEBUG "Starting"

    If you see "Starting" displayed more than once during any iteration of the program, you will then know the Stamp is resetting.

    Regards,

    Bruce Bates
  • Shawn LoweShawn Lowe Posts: 635
    edited 2006-12-22 15:48
    Also, you are making pins 0 and 2 go high, and taking an RCTIME on pins 0 and 1.
    Also, I believe the pause 25 is there to allow the caps to fully charge.

    FWIW

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Shawn Lowe


    My last words shall be - "NOT YET!!!"
  • tek_mantek_man Posts: 9
    edited 2006-12-22 18:53
    Thanks

    I appreciate the feedback...

    I like the modifications that you made to my original code, it does make it flow a little better. The PAUSE 25 that you questions is there to give the caps time to charge up as Shawn suggested, I just made a typo for Pin 2 (should have been pin 1)

    As far as the overlap, I understand that the controller only executes one command at a time and that this program will only turn the next injector on AFTER the previous one has been turned off. That is indeed how this works on the actual circuit.

    I was trying to create the overlap by using the second bit of code by using HIGH and LOW rather than PULSOUT. That way I could turn injector (1) on with a HIGH, and then the injector (2) on before I issued the LOW for injector (1). I see that I copied some code that was a "beta"...(It was about 2AM when I posted so I was a little brain dead. I will post the actual code later that I was using that does "overlap" the pulses by keeping track of HIGH and LOW state on multiple outputs, the problem I was having was there was apparantly too much overhead in the code and it was causing timing errors.

    I have not actually wired the injectors yet, I am currently just using 6 LED's until I get my logic straight

    Thanks again for the help

    Lee
  • bennettdanbennettdan Posts: 614
    edited 2006-12-22 23:22
    tek_man

    The effect of what you are seeing on the Oscope that two or more Injectors are on at the same time at higher RPM could it be dwell of your caps discharging of the mosfet stiffin caps and not really the MCU telling the injectors to come on?

    If you can get a print of a real Car MCU and put your scope directly to the output pin of the Processor then I think you will see a true step from the pins.

    If you want the LEDS/Injectors to ack like they over lap on your project just use a cap to cause the injector or led to fade down.

    With the right cap it should be no overlap with low RPM and then start causing it to overlap more the faster it sequences, kind of like the Red Lamps on the front of the Kight Rider Car...

    Hope this help let us know
  • tek_mantek_man Posts: 9
    edited 2006-12-23 07:10
    OK...
    Thanks for the responses so far,
    Here is a (reworked, as in brand new) program that does EXACTLY what I want it to, only it is SLOW. I would like to speed up the loop if possible. Forget about the injectors for now, this circuit/program is designed to drive 6 LEDs connected to pins 1-6 on the Stamp Controller. (and it does work, including the "overlap" of pulses)
    I thought the process through and completely changed my strategy.
    Here is the basic logic of the program:
    Run through a loop that is an even multiple of the number of LED's, for this example I used 600 to keep the math easy
    At each even interval (100,200,300,400,500,600) turn on the next LED in the sequence. I start the loop at 100 and end at 699 to avoid some div / 0 errors in the calculations.
    With each iteration through the loop, add one to a counter for every LED that is illuminated
    With each iteration of the loop, check the counter to see if it has exceeded the "pulsewidth" for the ON TIME, if it has then turn off the LED and reset the counter.
    To change the Frequency you can either make the main loop shorter (so it has less cycles to go through) or change the STEP for the loop, the loop length and STEP values need to be even multiples so that it does not skip any events
    TO change how long each LED is illuminated, adjust the pulse_width variable, longer values will case the pulses to overlap.
    I understand that there is a certain amount of time it takes to run through these iterations, and there is overhead doing it this way. Does anybody see a way to optimize the code so that it is capable of higher frequencies?

    Functional Code:
    ' {$STAMP BS2}
    ' {$PBASIC 2.5}
    pulse_width      VAR   Byte                       ' number of cycles to keep LED High
    cycle_time       VAR   Word                       ' Length of complete cycle to fire all LEDs
    Counter          VAR   Word                       ' Keeps track of position through cycle
    Current_LED      VAR   Nib                        ' The current LED to turn on
    Increment        VAR   Byte                       ' controls how fast we loop through
    Multiplier       VAR   Byte                       ' ensures that math is even for division
    LED_Ticks        VAR   Byte(7)                    ' Counts how many cycles LEDs are illuminated
    LED_Status       VAR   Bit(7)                     ' Current status (HIGH/LOW) of each LED
     
    Num_LEDs         CON   6                           ' number of LED's to sequence
     
    Multiplier       =     100                         ' Ensures that the math works out even for timing pulses
    Cycle_time       =     Multiplier  * (Num_LEDs + 1)' Total length of cycle in even increment of number of LED's and a multiplier
    pulse_width      =     5                           ' Number of "ticks" to hold Injector on
    Increment        =     10                          ' RPM/Frequency Control...needs to divide evenly into multiplier
     
    '##################################################################
    
    Main_loop:     '### loops through and turns on LED's at even increments
     
    FOR Counter = Multiplier TO Cycle_time - 1 STEP Increment  ' Start loop at first interval to avoid DIV by 0 errors in math
     
      IF Counter // Multiplier = 0 THEN       '  Turns on LED if position is an even interval
        Current_LED = Counter / Multiplier    '  Calculates which LED to Turn ON
        HIGH Current_LED                      '  Turn on Current LED
        LED_Status(Current_LED) = 1           '  Set LED Status to HIGH
      ENDIF
     
      GOSUB Poll_LEDs          ' Go check the status of all LEDs
      GOSUB End_LED_Pulses     ' Turn off LEDs if they have been on long enough
     
    NEXT
     
    GOTO Main_loop
     
    '###################################################################
    
    Poll_LEDs:    '### This Subroutine polls the current status of all LEDs and increments a counter
     
    FOR Current_LED = 1 TO Num_LEDs
     
        IF LED_Status(Current_LED) = 1 THEN
          LED_Ticks(Current_LED) = LED_Ticks(Current_LED) + 1       ' Increment LED Tick Counts
        ENDIF
     
    NEXT
     
    RETURN
     
    '####################################################################
    
    End_LED_Pulses:     '### This Subroutine compares the "Tick counter" to Pulse_width and shuts down the LEDs
     
    FOR Current_LED = 1 TO Num_LEDs
     
      IF LED_Ticks(Current_LED) >= pulse_width THEN  'Check to see if LED "Ticks" have surpassed Pulse_width
        LOW Current_LED                   ' Turn off current LED
        LED_Ticks(Current_LED) = 0        ' Reset Tick Counter
        LED_Status(Current_LED) = 0       ' Reset LED Status to LOW
      ENDIF
     
    NEXT
     
    RETURN
    



    Thanks Again, this is a great forum and I have learned a bunch just in the last few days....



    Lee
  • metron9metron9 Posts: 1,100
    edited 2006-12-24 02:20
    This should speed things up a bit. If you need to be more exact on timing you can replace the pause statements with if then statements and put in a couple of tick counters but the way it is now you can get pretty good resolution. Or use the pulsout for finer resolution. With zero pause just the program statements I got almost 3600 RPM (scope output on injector 5(red) and 6(blue) (I only have a dual scope).

    My education, I did finish high School but never did any serious studying in school but I do read quite a bit now.

    Hope this helps.


    
    ' {$STAMP BS2}
    ' {$PBASIC 2.5}
    
    plugbit          VAR   Byte
    oldplugbit       VAR   Byte
    
    DIRL=127  'Using bits 1 thru 6 Pin outputs 1 thru 6
    OUTL=0
    plugbit=2
    oldplugbit=1
    
    Main_loop:
    OUTL=(OUTL) | (plugbit)                 'Turn on injector x
    plugbit = plugbit<<1                    'Select next injector
    IF plugbit=128 THEN plugbit=2           'Check for last injector and circle back to start
    
    PAUSE 3                                 'Injector x-1 overlap time
    OUTL=OUTL ^ oldplugbit                  'Turn off injector x-1
    oldplugbit=oldplugbit<<1                'Select next injector
    IF oldplugbit=128 THEN oldplugbit=2     'Check for last injector and circle back to start
    PAUSE 1                                 'Time to next injector
    
    GOTO main_loop
    
    
    
    

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Think Inside the box first and if that doesn't work..
    Re-arrange what's inside the box then...
    Think outside the BOX!
    956 x 424 - 17K
  • metron9metron9 Posts: 1,100
    edited 2006-12-24 03:59
    Sorry, I did not read before you needed a bigger overlap than one injector so I whipped up another simulator.

    It's bloody slow so you may want to port it to something with a bigger engine [noparse]:)[/noparse]

    This code will overlap 100% of up to the next three injectors.
    You can add another load factor for on times if you like to fire them sooner but I wanted to keep it simple.


    I started with a simulated shaft that rotates 360 degrees in 252 steps. Each injector fires at 1/6 of the rotation
    Variables are set for both on and off so it is just a matter of setting the on and off times within the boundaries of the shaft rotation.

    The logic is quite simple I could port it to an ATMEL mega48 in assembler if you like, someone here could toss it on SX or something.
    If you have enough speed and memory for variables I would use 360 steps or 3600 depending on the resolution you need or want on the simulated shaft. If you want this one faster you could reduce the steps but it still won't win any races.

    I am actually doing something similar to this, a simulated rotating light with 16 LED's using PWM to fade up the next led while the previous led fades down although it's all in assembler on mega48.


    ' {$STAMP BS2}
    ' {$PBASIC 2.5}
    ' 252
    
    max_shaft_pos CON 252
    
    Load_factor  VAR   Byte 'Load Factor adjustment
    Shaft_Pos    VAR   Byte ' Shaft Position 1 through 252 (Each piston 42 ticks apart from top)
    IJ1_on       VAR   Byte 'IJ1 thru 6 shaft position to turn injector on
    IJ2_on       VAR   Byte
    IJ3_on       VAR   Byte
    IJ4_on       VAR   Byte
    IJ5_on       VAR   Byte
    IJ6_on       VAR   Byte
    
    IJ1_off      VAR   Byte 'IJ1 thru 6 shaft position to turn injector off
    IJ2_off      VAR   Byte
    IJ3_off      VAR   Byte
    IJ4_off      VAR   Byte
    IJ5_off      VAR   Byte
    IJ6_off      VAR   Byte
    
    
    Load_factor = 150       'initially set to overlap 50% to next piston
    
    'Note
    'You could also add another loadfactor to subtract ontime (turn on faster)
    'you will need To wrap IJ1 as it will go negative. Off times could also wrap
    'in the negative direction with special code for wrapping around as the case for IJ5
    'going larger than max_shaft_pos in the subroutine below.
    
    
    GOTO START
    
    'Subroutines
    
    Initial_On_off_times:
    IJ1_on  = 1           'initially set to turn on at top of piston (Don't know anything about engines:)
    IJ2_on  = 42*1
    IJ3_on  = 42*2
    IJ4_on  = 42*3
    IJ5_on  = 42*4
    IJ6_on  = 42*5
    
    
    IJ1_off = (42*1)+load_factor
    IJ2_off = (42*2)+load_factor
    IJ3_off = (42*3)+load_factor
    IJ4_off = (42*4)+load_factor
    IJ5_off = (42*5)+load_factor
    IJ6_off = load_factor
    
    
    'Special case if IJ5 goes larger than max_shaft_pos wrap it around
    IF IJ5_off > max_shaft_pos THEN IJ5_off=IJ5_off-max_shaft_pos
    
    RETURN
    
    START:
    GOSUB Initial_on_off_times
    
    Shaft_Pos = 1
    
    
     Main:
     IF IJ1_on = Shaft_pos THEN HIGH 1
     IF IJ2_on = Shaft_pos THEN HIGH 2
     IF IJ3_on = Shaft_pos THEN HIGH 3
     IF IJ4_on = Shaft_pos THEN HIGH 4
     IF IJ5_on = Shaft_pos THEN HIGH 5
     IF IJ6_on = Shaft_pos THEN HIGH 6
     IF IJ1_off = Shaft_pos THEN LOW 1
     IF IJ2_off = Shaft_pos THEN LOW 2
     IF IJ3_off = Shaft_pos THEN LOW 3
     IF IJ4_off = Shaft_pos THEN LOW 4
     IF IJ5_off = Shaft_pos THEN LOW 5
     IF IJ6_off = Shaft_pos THEN LOW 6
    
     shaft_pos=Shaft_pos+1
     IF Shaft_pos>max_shaft_pos THEN
      shaft_pos=1
    
     '============================================
      load_factor=load_factor+1   'This code simulates increasing load factor to three pistons
       IF load_factor>166 THEN Load_factor=21  'Allows 100% of next three pistons
      GOSUB Initial_on_off_times               'Resets off times with new load factor
      DEBUG DEC load_factor,CR
     '=============================================
    
     ENDIF
    
     GOTO main
    
    

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Think Inside the box first and if that doesn't work..
    Re-arrange what's inside the box then...
    Think outside the BOX!

    Post Edited (metron9) : 12/24/2006 4:04:55 AM GMT
  • tek_mantek_man Posts: 9
    edited 2006-12-24 04:48
    Thanks Metron9,

    That first program really speeds things up..
    I think that it will do what I need it to do, the timing is not that critical down to the mS level so it should work. Here is a 4 trace shot of 4 out of the 6 LED's

    That is one thing that I am not real stong on, it bitwise math and operators. I need to read up on them some more I can see powerful they can be..

    Thanks again
    637 x 481 - 13K
Sign In or Register to comment.