Shop OBEX P1 Docs P2 Docs Learn Events
RTCC with SX/B help request on magneto/throttle project — Parallax Forums

RTCC with SX/B help request on magneto/throttle project

Ken GraceyKen Gracey Posts: 7,389
edited 2006-10-17 15:01 in General Discussion
Hey SXers:

This is my first time attempting to use the SX's RTCC ISR. This portion of the·project consists of a Honda engine magneto connected to an SX, with a servo for throttle control. The goal is to control the throttle using a known RPM. The bigger project is that I've got an alternator connected to the engine for a high-powered robot power plant for over-the-snow travel. But·this is where I'm stuck.·The signals I'm dealing with look like this (servo on top, magneto on bottom):

attachment.php?attachmentid=43493

Every 20-50 ms I generate·the servo pulse, and meanwhile I'd like to be counting magneto pulses for 1 second. The scope capture above shows the engine in an idle state, so the pulse frequency increases with RPM. I'm able to control the servo and count pulses accurately, but putting these two tasks together is where I need some help. You can ignore the R/C circuit with the potentiometer - the purpose of that was to manually set the throttle so I could test the pieces of this project before I tried to put it all together.

This is my schematic:

attachment.php?attachmentid=43494

I created some psuedo-code which compiles, though·the use of PULSOUT in the interrupt routine·will wreck the timing. How can I incorporate the adjustment of a servo timing pulse·within the ISR?·It seems like I'd use the tix counter to adjust servo pulses.·Do I need to·make a relationship between ServoVal and tix variables, so that I use tix and HIGH/LOW Servo·in the ISR to control the servo? I·would benefit from a couple more hints.·Preliminary·psuedo-code is below, so you·can understand the·approach I'm trying to take.

'
' Throttle Feedback Control.SXB
' Magneto counting for Honda Engine / alternator coupling
' to set an RPM between two values
'


DEVICE········· SX28, OSCXT2, TURBO, STACKX, OPTIONX
FREQ··········· 4_000_000

'
' I/O Pins
'


Servo·········· PIN·RA.1· OUTPUT
Magneto········ PIN·RB.4· INPUT CMOS
RCCircuit······ PIN·RC.3· INPUT· ' not used in this code·

'
' Constants
'


HighThrottle··· CON·130
LowThrottle···· CON·190

'
' Variables
'


ServoVal······· VAR·Word
analog········· VAR·Word
RPM············ VAR·Word
MagnetoPulses·· VAR·Byte
tix············ VAR·Byte

'
· INTERRUPT 200
'


ISR_Start:
· INC tix······································ ' update tix counter
· IF tix = 10 THEN····························· ' every 50 ms
··· tix = 0
··· PULSOUT Servo, ServoVal
· ENDIF
ISR_Exit:
· RETURNINT·

' =========================================================================
· PROGRAM Start
' =========================================================================

Start:
· ServoVal = LowThrottle

CountRPMs:
· COUNT Magneto, 1000, MagnetoPulses
· RPM = MagnetoPulses * 60
· IF RPM <· 3000 THEN
··· ServoVal = ServoVal - 5 ················· ' increase throttle
··· IF RPM > 4000 THEN
··· ServoVal = ServoVal······················ ' hold throttle
····· IF RPM > 5000 THEN
····· ServoVal = ServoVal + 5················ ' decrease throttle
····· ENDIF
··· ENDIF
· ENDIF
GOTO CountRPMs

Thanks for any help ahead of time.·

Ken Gracey
Parallax, Inc. ·

Post Edited (Ken Gracey (Parallax)) : 10/6/2006 6:09:22 PM GMT

Comments

  • BeanBean Posts: 8,129
    edited 2006-10-06 18:14
    Ken,
    How fast can the magneto pulses be at maximum RPM ?

    P.S. I hate to bring this up, but the SX48 could handle both of these functions using JUST the two hardware timers.

    Bean.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Cheap used 4-digit LED display with driver IC·www.hc4led.com

    Low power SD Data Logger www.sddatalogger.com
    SX-Video Display Modules www.sxvm.com

    Don't mistake experience for intelligence. And vis-vera.
    ·
  • Ken GraceyKen Gracey Posts: 7,389
    edited 2006-10-06 18:34
    Hey Bean,

    The fastest magneto pulses I'm counting are 200 per second, and best I can tell I get two pulses per rotation. 200 x 60 / 2 = 6,000 rpm. Idle is around 50 pulses per second.

    I forgot to say why I want RPM control. I've got a voltage regulator circuit which generates a known amount of current at different RPMs. I could come close to achieving what I want with an open-loop throttle, but since I've come this far. . .

    I could use the SX48 Proto Board - not a problem especially if it makes the coding more practical. Sure.

    Ken Gracey
    Parallax, Inc.

    Post Edited (Ken Gracey (Parallax)) : 10/6/2006 7:33:23 PM GMT
  • RonWRonW Posts: 39
    edited 2006-10-06 23:01
    The ISR should control the servo without a problem.

    However, the COUNT function will not be precise for two reasons:

    1) Time spent in the ISR does not count against your 1000 msecs timing interval. In your case the ISR time will vary with the width of the servo pulse. Worst case, on average around 4% of your time will be in the ISR, so this probably isn't a concern here.

    2) If a magneto pulse happens during a servo pulse, it won't get counted. The COUNT function can't register a pulse unless it (and not the ISR) is running when the pulse happens. Since the magneto pulses can be shorter than the servo pulses, this is a definite possibility. Again, you may be able to convince yourself that missing a few pulses won't be a problem for this project.

    If you decide you need to, you can solve both of these problems by coding the pulse counter yourself. You could add code to the ISR to set a bit flag once per second (every 200 executions of the ISR). WKPND_B.4 will be set every time there is a magneto pulse, independent of what code is running. You just have to clear it before the next pulse comes along. Create a loop that checks and clears WPKND_B.4, increments the count when it's set, and loops until the 1 second flag is set. When that happens, clear the 1 second flag and save the count.

    There's a trick to using the WKPND_B register. WKPND_B = ByteVar will actually swap the value of ByteVar and the value of WKPND_B. So the the pulse counting code would be:

    CountRPMS:
    MagnetoPulses = 0
    DO
    Temp = 0
    WKPND_B = Temp 'Temp gets the value of WKPND_B and WKPND_B is cleared and ready for the next pulse
    IF Temp.4 = 1 THEN
    INC MagnetoPulses
    ENDIF
    LOOP UNTIL OneSecondFlag = 1
    OneSecondFlag = 0
    'Update ServoVal here
    GOTO CountRPMS

    By the way, you'll probably want to force ServoVal to stay between LowThrottle and HighThrottle.
  • RonWRonW Posts: 39
    edited 2006-10-06 23:14
    I'm learning how to format my posts.· Here's a more readable version of the code snippet:

    CountRPMS:
    ·· MagnetoPulses = 0
    ·· DO
    ····· Temp = 0
    ····· WKPND_B = Temp 'Temp gets the value of WKPND_B and WKPND_B is cleared and ready for the next pulse
    ····· IF Temp.4 = 1 THEN
    ········ INC MagnetoPulses
    ····· ENDIF
    ·· LOOP UNTIL OneSecondFlag = 1
    ·· OneSecondFlag = 0
    ·· 'Update ServoVal here
    GOTO CountRPMS
  • BeanBean Posts: 8,129
    edited 2006-10-06 23:21
    Ken,
    · I would use RTCC to count the mag pulses. And update the servo in the program loop.
    · This will work on the SX28 or SX48. And no messy interrupts are needed.
    · Something like: [noparse][[/noparse]WARNING...UNTESTED CODE AHEAD!]

     
    OPTION = %11111111 ' Setup RTCC inc from external pin (Mag pulse)
     
    servoPos = 150 ' 1.5 milliseconds
     
    DO
      RTCC = 0
      FOR cnt=1 TO 50
        servoPin = 1
        PAUSEUS servoPos * 10
        servoPin = 0
        servoPos = 255 - servoPos
        PAUSEUS servoPos * 10
        servoPos = 255 - servoPos
        ' Delayed 2.550 milliseconds so far
        PAUSE 17.45 ' Make total delay 20mSec
      NEXT
      magCnt = RTCC
      ' Do something with magCnt
    LOOP
    


    Bean.
    ·

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Cheap used 4-digit LED display with driver IC·www.hc4led.com


    Low power SD Data Logger www.sddatalogger.com
    SX-Video Display Modules www.sxvm.com

    Don't mistake experience for intelligence. And vis-vera.
    ·
  • pjvpjv Posts: 1,903
    edited 2006-10-06 23:48
    Hi Bean;

    Now wait just a minute...... there is nothing "messy" about interrupts. It permits you to do things exactly and deterministically. In fact, I bellieve it to be the ONLY way to code time related programs...... I would never stoop to using a "pause" (OK, perhaps a few NOPs for a few cycles) to wait for anything. With interrupts, (simple) multi-tasking is a breeze, and pre-emptive multi-tasking is very achievable in an SX28.

    That said, with the exception of the PAUSE function, I do like what you have done with SX/B. You can get a lot done with only a little effort. It appears to be well respected for non time-critical applications, and has garnered quite a following. For real-time multi threading however, something more substantial is required employing those darned "ISR's", and that's the field where I like to "mess".

    Keep up the good work.

    Cheers,

    Peter (pjv)
  • BeanBean Posts: 8,129
    edited 2006-10-07 00:32
    I agree interrupts are great, but if I can do something without interrupts I will.

    Bean.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Cheap used 4-digit LED display with driver IC·www.hc4led.com

    Low power SD Data Logger www.sddatalogger.com
    SX-Video Display Modules www.sxvm.com

    Don't mistake experience for intelligence. And vis-vera.
    ·
  • pjvpjv Posts: 1,903
    edited 2006-10-07 01:20
    Hi Bean;

    Interesting, your approach.

    Where on the other hand, I never write a program without interrupts, even if it just returns..... it's a standard piece in my template. It becomes so second nature, and it really helps (me, at least) clarify the dissection of a software structure for any particular requirement.

    Cheers,

    Peter (pjv)
  • PJMontyPJMonty Posts: 983
    edited 2006-10-07 03:56
    Peter,

    I agree. Time spent learning how to handle interrupts and communication between FG and BG code is time well spent. Perhaps the single strongest feature of the SX chips is the jitter free interrupt. I can treat the SX like a piece of dedicated hardware because the lack of jitter in the interrupt system allows me to have 100% deterministic response time.

    In addition, by dividing tasks between FG and BG, I guarantee time critical code is executed. In one of my projects, I have an SX that communicates with a 68HC11. The SX polls the communications lines in the interrupt handler. Mind you, it doesn't block. It just checks the status and acts when the line has done what it is waiting for. By counting the duration of the code path in the 68HC11, I am able to set an RTCC interrupt rate in the SX that absolutely guarantees it will never miss a communication request by the 68HC11. There is no wondering if it's fast enough. I can prove that I am sampling the communication line at around 3X faster than the 68HC11 can toggle it. This allows my FG code to do whatever it needs with the data as it comes in because the interrupt will always catch the data and notify the FG when it is ready.

    This has also given me a huge advantage in writing multi-threaded code for Windows. The lessons learned on how to synchronize communication between the FG and BG is just like synchronizing communication between threads in Windows. As a result, my multi-threaded Windows apps cruise along without running afoul of issues like race conditions because I learned how to deal with those (the hard way) writing assembly language code (using interrupts) on various micro platforms.
      Thanks, PeterM
  • Mike CookMike Cook Posts: 829
    edited 2006-10-07 15:08

    OT: Sort of

    Ken,

    What type of alternator are you using with the GX-35?

    Is it a direct drive or are you using a pulley/chain arrangement?

    Is the GX-35 electric start or pull?

    Some Pics would be neat!

    I've kept my daughter's motorized car she had when she was little, now 13. Was think about making a 'explorer' bot (probably just R/C for now) out of it.

    Thanks,

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Mike
  • Guenther DaubachGuenther Daubach Posts: 1,321
    edited 2006-10-07 17:28
    Hi all,

    tacho pulses are kinda asynchronous. Using an ISR to catch them, means that the ISR must be executetd often enough in order not to miss anya tacho pulse transition, so the ISR would act as a "fast poller" on the tacho input line. As the SX is faster than many oher controllers, this may, or may be not a problem.

    Nevertheless, please don't forget another great SX feature: The "wake-up" capability of the port B inputs. What is called the "wake-up capability" is actually a endge-capture feature available on the port B inputs. You can configure each of them to capture a rising or falling input signal edge, using the WKPED_B configuration register. You may configure the individual port B inputs to issue an interrupt, or a wake-up event using the WKEN_B configuration register. But even without enabling interrupts/wakeups on port B transitions, you can always "read" the WKPND_B register to find out if the input has changed to the configured direction since the last read. Actually, you do an exchange between W and the WKPND_B registers, so the instruction sequence

    mov w, #0
    mode $09
    mov !rb, w

    copies the current status of the wakeup pending bits into w, and clears them for the next run.

    This feature is especially handy when you have to deal with very short pulses. Let's assume that the pulses look like to this:

    _______________-_______________-_____________

    and you poll the input at times shown here:

    ____|____|____|____|____|____|____|____|____|____

    So, you will miss all the low-high transitions, although you are polling the input faster than the pulse period.

    The status of a WKPND_B register bit would look like this (assuming that it is cleared whenever it is read):

    ______________
    ____________----____________

    i.e. it goes high on a rising input signal, and low again when it is read by the SX program, so you won't miss any input transition using this feature.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Greetings from Germany,

    G
  • Ken GraceyKen Gracey Posts: 7,389
    edited 2006-10-08 21:58
    Hey guys,

    Thanks a bunch for the help. I'm going to do a bit more research on RTCC to see if it can achieve my goals. I'll put the tach pulses on the RTCC pin and deal with the servo in my main program. I need to see if this pin can be set to CMOS. This seems likea fairly light-duty approach compared to the edge detection tips from Guenther and Peter's encouragement to learn ISRs inside and out, but it's a small step in the right direction from my standpoint. I'll be working on this over the next day or two and will report back my findings.

    Mike,

    This is a direct coupling arrangement. I don't want to mess around with chains or pulleys due to safety, power loss, and general "junk" that I consider it in my system. Basically, this system is producing 15-20A without problem and the battery is acting like a giant capacitor in the project. This is the·power plant "test bed" I built, which·was only assembled to prove to myself that the concept is feasible. I've connected loads over 15A at 12V·and I can deliver this power for an hour and a half with this engine. I'll post the·whole entire project in·the "Projects" section of this forum once I get the SX to count magneto pulses. I'll post mechanical drawings, too.

    Ken Gracey
    Parallax, Inc.

    attachment.php?attachmentid=43532
    attachment.php?attachmentid=43531
    400 x 357 - 11K
    400 x 300 - 61K
  • BeanBean Posts: 8,129
    edited 2006-10-08 22:30
    Ken,
    I "THINK" I remember reading somewhere that the RTCC pin is schmitt trigger levels. So you may need to run the magneto pulse through a gate to "square it up" first. I'd try it straight in first.

    Bean.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Cheap used 4-digit LED display with driver IC·www.hc4led.com

    Low power SD Data Logger www.sddatalogger.com
    SX-Video Display Modules www.sxvm.com

    Don't mistake experience for intelligence. And vis-vera.
    ·
  • pjvpjv Posts: 1,903
    edited 2006-10-09 01:27
    Hi Ken;
    ·
    Just for interest I thought I would code up in assembler (my skills at SX/B are inadequate) what I think you are trying to do.
    ·
    I believe your project is well served by a simple minded co-operative scheduler and state machines, so I thought it to be a good example to demonstrate those.
    ·
    I have not followed your port bits and numbers scaling as I was not at my internet connection at the time I coded this, so I was going by memory as to what the concepts were, and that was what I implemented.
    ·
    Essentially my example shows several concepts, and how to execute several independently timed concurrent routines "simultaneously":
    ·
    1. use interrupt to time all events
    2. read magneto pulses for one second
    3. use port B change detection as per Guenther's example above
    4. output servo pulses from 1 through 2 milliseconds duration
    5. calculate throttle raise/lower requirements
    ·
    A virtual A/D converter for a pot-adjusting RPM setpoint can be readily incorporated.
    ·
    This particular implementation is not as concise as I would normally code it, as that would obscure some of the concepts for those who are trying to learn from these examples, and this version is only one of many ways to "skin this cat".
    ·
    It's also interesting to note the difference in effort between an SX/B (your code rendering) and assembler. It took me about 3 hours to figure out what was needed, how to tackle it, write the code starting with my standard template, and another hour to debug it and run it with simulated inputs/outputs. Then it took me another two hours to edit the post so formatting was intact·for·making it·readable !

    My scope verified proper operation of the servo pulse outputs, but using the imprecise internal R/C oscillator caused a little error in the timing. During "DEBUG", while the SX key was generating the clock, timing was perfect.
    ·
    ·
    Anyhow do with it what you will, and I'd be happy to add the A/D or any other features you might desire.
    ·
    Cheers,
    ·
    Peter (pjv)
    id 'Gracey1'   ; Oct8, 2006
           Device SX28, Osc4MHz, Turbo, Optionx            ;new assembler
    ;      Device watchdog                                 ;turn the watchdog on
    ;      Device bor42                                    ;turn brown-out detect on
    ;      Device carryx                                   ;turn extended carry on
    ;      Device protect                                  ;turn program read protection on
           Freq 4_000_000                                  ;run speed
           Reset Initialize                                ;start at label on reset
           IRC_Cal IRC_Slow                                ;
    

    ;Constants for the Mode register settings
    ModeComp       equ $08                                 ;mode for port B comparator swap access
    ModeBPend      equ $09                                 ;mode for port B change detect sawp access 
    ModeBEdge      equ $0A                                 ;mode for port B change rising edge selection (0)
    ModeBEnable    equ $0B                                 ;mode for port B change detection enable (0)
    ModeSchmidt    equ $0C                                 ;mode for port  BC bit Schmidt trigger enable (0)
    ModeLevel      equ $0D                                 ;mode for port ABC bit CMOS level selection (0)
    ModePullup     equ $0E                                 ;mode for port ABC bit pullup selection (0)
    ModeTristate   equ $0F                                 ;mode for port ABC bit output direction selection (0)
    

    ;Constants for the option register
    ;                 +------------------------------------0 for RTCC at address 1
    ;                 |+-----------------------------------0 for RTCC roll over interrupt enable
    ;                 ||+----------------------------------0 for RTCC increment on instruction clock
    ;                 |||+---------------------------------0 for RTCC rising edge increment
    ;                 |||| +-------------------------------0 for RTCC prescaler assignment
    ;                 |||| |+------------------------------Prescaler 2
    ;                 |||| ||+-----------------------------Prescaler 1  
    ;                 |||| |||+----------------------------Prescaler 0 14kHz watchdog; 000 is 16 mSec
    ;                 |||| ||||
    RTCCIntDisable = %1111_1111                            ;
    RTCCIntEnable  = %1001_1111
    

    IntConst       equ -100                                ;25 usec base tick at 4 MHz
    MagnetoIn      equ rb.0                                ;input pin from magneto interface
    ServoOut       equ rc.0                                ;output pin to servo
    

                   org 8
    Flags          ds 1                                    ;
    Intflag        = Flags.0                               ;indicate an interrupt has happened
    

    Timers         org $10
    Time1          ds 1                                    ;timer to create 100 uSec
    Time2          ds 1                                    ;timer to create   1 mcec
    Time3          ds 1                                    ;timer to create  10 mSec
    Time4          ds 1                                    ;timer to create 100 mSec
    Time5          ds 1                                    ;timer to create   1  Sec
    MagnetoState   ds 1                                    ;keeps track of what magneto routine is running
    MagnetoAccumulatorLo   ds 1                            ;raw magneto counts Lo
    MagnetoAccumulatorHi   ds 1                            ;raw magneto counts Hi
    MagnetoCount   ds 1                                    ;most significant byte (scaled) of magneto pulses in one second
    ServoState     ds 1                                    ;keeps track of what servo routine is running
    ServoLoad      ds 1                                    ;value of pulse length to output for servo
    ServoDuration  ds 1                                    ;down counter for servo pulse duration... count of 10 uSec ticks
    

    watch MagnetoAccumulatorLo,16,udec                     ;
    watch MagnetoCount,8,udec                              ;
    watch ServoLoad,8,udec                                 ;
    watch ServoDuration,8,udec                             ;
    

    ;Interrupt =============================================
                   org     0                               ;
    Interrupt      setb    Intflag                         ;interrupt based tick generator
                   mov     w,#IntConst                     ;load interrupt interval value
                   retiw                                   ;
    

    Initialize ;===========================================;Program starts here on power-up and on reset.
    InitLevels     mov     m,#ModeLevel                    ;Set to 0 for CMOS levels
                   mov     !ra,#%0000                      ;
                   mov     !rb,#%0000_0000                 ;
                   mov     !rc,#%0000_0000                 ;
    InitPullup     mov     m,#ModePullup                   ;Set to 0 for pullups
                   mov     !ra,#%0000                      ;
                   mov     !rb,#%0000_0000                 ;
                   mov     !rc,#%0000_0000                 ;
    InitEdgeDetect mov     m,#ModeBPend                    ;clear out any pending bits before enabling edge detect interrupt
                   mov     !rb,#0                          ;
    InitTris       mov     m,#ModeTristate                 ;Set to 0 for output
                   clr     ra                              ;
                   mov     !ra,#%1111                      ;all inputs
                   clr     rb                              ;
                   mov     !rb,#%1111_1111                 ;all inputs
                   clr     rc                              ;  
                   mov     !rc,#%0000_0000                 ;all outputs
    ClrMem         clr     fsr                             ;beginning of ram
    ClrOne         setb    fsr.4                           ;stay in upper half
                   clr     ind                             ;clear location
                   incsz   fsr                             ;next location
                   jmp     ClrOne                          ;continue clearing
                   clr     Flags                           ;
    InitTimers     bank    Timers                          ;
                   mov     w,#4                            ;
                   mov     Time1,w                         ;100 uSec timer
                   mov     w,#10                           ;
                   mov     Time2,w                         ;  1 mSec timer
                   mov     Time3,w                         ; 10 mSec timer
                   mov     Time4,w                         ;100 mSec timer
                   mov     Time5,w                         ;  1  Sec timer
    InitMagneto    mov     MagnetoState,#MagnetoIdle       ;initial state for magneto routines
    InitServo      mov     ServoState,#ServoIdle           ;initial state for servo routines
                   mov     ServoLoad,#ServoMin             ;low setting
    InitRTCC       clr     rtcc                            ;
                   mov     !option,#RTCCIntEnable          ;enable interrupt
                   jmp     Main                            ;
    

    ;Mainline program loop ================================= 
    Main           sb      Intflag                         ;wait for occurence of an interrupt
                   jmp     Main                            ;
    uSec25         clrb    Intflag                         ;act on interrupt event
           ;put 25 uSec scheduled events here
                   call    Servo                           ;do required state of servo routines
                   bank    Timers                          ;
                   decsz   Time1                           ;
                   jmp     Main                            ;
    uSec100        mov     Time1,#4                        ;reload timer for another 100 uSec (4 ticks of 25 uSec)
           ;put 100 uSec scheduled events here
                   bank    Timers                          ;
                   decsz   Time2                           ;
                   jmp     Main                            ;
    mSec1          mov     Time2,#10                       ;reload timer for another 1 mSec
           ;put 1 mSec scheduled events here
                   call    Magneto                         ;do required state of magneto routines
                   bank    Timers                          ;
                   decsz   Time3                           ;
                   jmp     Main                            ;
    mSec10         mov     Time3,#10                       ;reload timer for another 10 mSec
           ;put 10 mSec scheduled events here
                   mov     ServoState,#ServoStart          ;trigger a servo out pulse duration sequence every 10 mSec
                   bank    Timers                          ;
                   decsz   Time4                           ;
                   jmp     Main                            ;
    mSec100        mov     Time4,#10                       ;reload timer for another 100 mSec
           ;put 100 mSec scheduled events here
                   bank    Timers                          ;
                   decsz   Time5                           ;
                   jmp     Main                            ;
    SecOne         mov     Time5,#10                       ;reload timer for another 1 Sec
           ;put 1 Sec scheduled events here
                   call    Control                         ;calculate change for servo
                   jmp     Main                            ;
    

    ;Magneto State Routines ===============================;gets called every 1 mSec... good for 1000 pulses/sec, or 60,000 pulses per minute
    Magneto        mov     pc,MagnetoState                 ;jump to the current magneto routine
    

    MagnetoIdle    retp                                    ;not counting magneto pulses just now
    

    MagnetoStart   clr     MagnetoAccumulatorLo            ;zero the magneto pulse counter
                   clr     MagnetoAccumulatorHi            ;
                   mov     MagnetoState,#MagnetoFall       ;from now on look for a falling pulse level
    MagnetoFall    mov     m,#ModeBPend                    ;switch to pending mode
                   clr     w    ;
                   mov     !rb,w                           ;read and clear any port b transition pending bits
                   test    w                               ;determine any changed bits on port b
                   snz                                     ;skip on changes
                   jmp     MagnetoExit                     ;no magneto pulses detected
    MagnetoPulse   incsz   MagnetoAccumulatorLo            ;keep track of magneto pulse count
                   skip                                    ;
                   inc     MagnetoAccumulatorHi            ;16 bit counter
    MagnetoExit    mov     m,#ModeTristate                 ;restore direction mode... not neccessarily required in this simple case
                   retp                                    ;
    

    ;Servo State Routines =================================;gets called every 25 uSec... pulse granularity of 25 uSec for max length of 255 x 25 uSec = 6.375 mSec
    Servo          mov     pc,ServoState                   ;jump to the current servo routine
    

    ServoIdle      retp                                    ;no pulse required at this time
    

    ServoStart     mov     w,ServoLoad                     ;load up the servo pulse duration value; can be 1 through 255 ticks of the 10 uSec time base
                   snz                                     ;check for non-zero
                   retp                                    ;bail out for value of zero
                   mov     ServoDuration,w                 ;set the servo duration timer
                   setb    ServoOut                        ;set servo pin high
                   mov     ServoState,#ServoPulse          ;next time count one tick of the servo pulse output
                   retp                                    ;
                  
    ServoPulse     decsz   ServoDuration                   ;count ticks until counter is depleted
                   retp                                    ;
                   clrb    ServoOut                        ;servo pulse is now finished
                   mov     ServoState,#ServoIdle           ;next go to idle state until we are triggered again
                   retp                                    ;
    

    ;Control Routines =====================================
    LowSetpoint    = 25                                    ;25 magneto pulses per second..... probably 25 * 60 * 2 = 3000 RPM
    HighSetpoint   = 30                                    ;30 magneto pulses per second..... probably 30 * 60 * 2 = 3600 RPM
    RaiseSize      = 5                                     ;step size for raising speed.. arbitrary choice
    LowerSize      = 7                                     ;step size for lowering speed.. arbitrary choice
    ServoMin       = 40                                    ;minimum servo pulse duration; 40 * 25 uSec = 1 mSec
    ServoMax       = 80                                    ;maximum servo pulse duration; 80 * 25 uSec = 2 mSec
    

    Control        mov     MagnetoState,#MagnetoIdle       ;stop magneto pulse accumulation
                   rl      MagnetoAccumulatorLo            ;only use 13 bits of 16 bit accumulator; good up to 8191 magneto pulses in one second
                   rl      MagnetoAccumulatorHi            ;
                   rl      MagnetoAccumulatorLo            ;only use 13 bits of 16 bit accumulator
                   rl      MagnetoAccumulatorHi            ;
                   rl      MagnetoAccumulatorLo            ;only use 13 bits of 16 bit accumulator
                   rl      MagnetoAccumulatorHi            ;
                   mov     MagnetoCount,MagnetoAccumulatorHi;only use most significant byte of pulse accumulation of previous one second
                   cjb     MagnetoCount,#LowSetpoint,Raise ;increase throttle if magneto is below setpoint
                   cja     MagnetoCount,#HighSetpoint,Lower;decrease throttle if magneto is above setpoint
    ControlExit    mov     MagnetoState,#MagnetoStart      ;trigger a one second magneto pulse accumulation
                   retp                                    ;
    

    Raise          add     ServoLoad,#RaiseSize            ;increase servo pulse duration
                   snc                                     ;look for roll-over
                   jmp     SetMax                          ;
                   csa     ServoLoad,#ServoMax             ;look for overflow
                   jmp     ControlExit                     ;
    SetMax         mov     ServoLoad,#ServoMax             ;limit to some maximum
                   jmp     ControlExit                     ;
    

    Lower          sub     ServoLoad,#LowerSize            ;decrease servo pulse duration
                   sc                                      ;look ror roll-under
                   jmp     SetMin                          ;
                   csb     ServoLoad,#ServoMin             ;look for underflow
                   jmp     ControlExit                     ;
    SetMin         mov     ServoLoad,#ServoMin             ;limit to some minimum
                   jmp     ControlExit                     ;
    

    ;======================================================
    

    
    
    Post Edit:··· Well, it looks like my effort to retain the formatting is for naught! This is so difficult to read..... I really wish there was another way to make things easier.·I hope the attached copy is proper !
    Post Edit: fixed missing literal indicator (#) in "MagnetoExit" line.
    Cheers,
    ·Peter (pjv)


    Post Edited (pjv) : 10/10/2006 3:39:31 PM GMT
  • James NewtonJames Newton Posts: 329
    edited 2006-10-09 20:59
    This is a really cool project Ken! I can't wait to see this work.

    You might want to take a look at:
    http://www.piclist.com/images/boards/Injector-JAW/index.htm which does injector control for a motorcycle engine. The code is for the PIC, but it can be converted.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    ---
    James Newton, Host of SXList.com
    james at sxlist,com 1-619-652-0593 fax:1-208-279-8767
    SX FAQ / Code / Tutorials / Documentation:
    http://www.sxlist.com Pick faster!



  • Ken GraceyKen Gracey Posts: 7,389
    edited 2006-10-10 03:12
    Peter,

    This is fantastic. I'm spending some time studying the code example before I reply in detail to make sure I've got a basic grasp of the concepts. I'll be at home on Tuesday evening, and should be able to run it as early as Wednesday morning. I truly appreciate the help and look forward to reporting back with results! Thanks again!

    You guys have tons of solutions for me!

    Sincerely,

    Ken Gracey
    Parallax, Inc.
  • Mike CookMike Cook Posts: 829
    edited 2006-10-10 03:23
    Ken,

    That's a pretty sweet setup! Looks like you work in aluminum like I do in MDF. Wish my home built CNC router would cut aluminum, probably will but will have to make MANY passes, need to try one day. Hope to see this in the 'Projects' section soon, you've sparked my interest!

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Mike
  • pjvpjv Posts: 1,903
    edited 2006-10-10 15:41
    Hi Ken;

    I spotted an error in my code; a missing literal indicator (#) in the "MagnetoExit" line. Eventhough it ran fine in my trial, it might have screwed up later if you added more features.

    I have "post-fixed" this.

    Cheers,

    Peter (pjv)
  • ShaneShane Posts: 2
    edited 2006-10-14 21:09
    Ken,

    Your power generator looks great! It is a work of art. I would enjoy reading a full article on the project.

    I suspect that your battery is closer to 10 Ahr rather than the 10 mAhr noted in the schematic of the LM723 voltage regulator.

    Are you planning on taking the next step and replacing the LM723 with the SX for regulation of the field current? In theory it should be rather simple.

    Just keep the voltage divider read the voltage with the SX. Replace the 2N3055 with a logic level MOSFET controlled with the SX (buffer with an ICL7667 style MOSFET driver if you want very fast edges) and PWM the field coil. A loop update rate of 100Hz to 200Hz should be plenty.

    In addition being cool and reducing the parts count, you would also get more run time. You would save the power lost due to the base current of the 2N3055 as well as the associated I*Vce losses. You might even be able to eliminate the 16 ohm resistor in series with the field coil for additional power savings.

    You might want to throw in a one-wire temperature sensor to make sure the alternator is not getting to hot at full load.

    I also wanted to throw in with Guenther. The best way to accurately count short events is to use an interrupt on level change (edge). Otherwise you are guaranteed to eventually miss events unless your time between samples is shorter than the minimum event duration.

    Congratulations again on such a well designed project. I look forward to reading more about the design and build.

    -Shane
  • ChrisPChrisP Posts: 136
    edited 2006-10-17 15:01
    Sorry about the late post, been very busy with work lately but accurately reading rpm in a real time environment is something thats been on my mind for quite a while. With the SX's speed I was thinking using the pulsin command to measure either the accumulated time of the pulse itself and the off time, or just the offtime if the pulse length was repeatable over the rpm range. In your application·I think you could ignore the pulse width from the looks of the scope signal and just measure off time. For the sake of reliability you could error proof a little by taking two pulse measurements. Sorry I havent had a chance to work on the concept yet, but its the fastest method I've come up with so far. Count over time wont work for what I intend to do with it, too much time taken counting pulses to come up with an accurate number.
Sign In or Register to comment.