'first try basic/assembler jet engine control unit 'all the time-critical subroutines (interrupts) are written in assembler 'the more complex functions (math etc) are in basic for comfort 'functions of first version: '-evaluates single channel (throttle) '-monitors RPM, EGT, Supply voltage '-uses acceleration ramp and predefined values for engine control '-monitors for missing/unplausible ppm signal '-incorporates basic safety functions 'define all i/o pin functions. all functions are positive logic except otherwise noted egtin var porta.0 'exhaust gas temperature input tambin var porta.1 'ambient temperature input (currently not used) vccin var porta.2 'supply voltage monitoring input rpmin var porta.4 'rpm signal counter input ignout var portb.0 'ignition output - reverse logic (currently not used) lightout var portb.1 'warning/status light output gasout var portb.2 'solenoid propane valve output (currently not used) thrtlin var portb.4 'throttle ppm input - reverse logic cntlin var portb.5 'control ppm input - reverse logic (currently not used) strtout var portc.1 'starter motor pwm output (currently not used) pumpout var portc.2 'fuel pump pwm output i2cscl var portc.3 'serial clock for i2c bus (currently not used) i2csda var portc.4 'serial data for i2c bus (currently not used) 232txd var portc.6 'rs232 transmit data line 232rxd var portc.7 'rs232 receive data line equ rbbak ; zustand von port b t-1 equ cntl1 ; kanalzähler 1 low equ cnth1 ; kanalzähler 1 high equ cntl1bk ; kanalzähler 1 low t-1 equ cnth1bk ; kanalzähler 1 high t-1 equ cntl2 ; kanalzähler 2 low equ cnth2 ; kanalzähler 2 high equ cntl2bk ; kanalzähler 2 low t-1 equ cnth2bk ; kanalzähler 2 high t-1 equ chn1 ; kanal schub equ chn1bk ; kanal schub t-1 equ chn2 ; kanal status equ chn2bk ; kanal status t-1 equ scalemul ; skalierungsmultiplikator für pulsdauer equ sclofsl ; skalierungsoffset low für pulsdauer equ sclofsh ; skalierungsoffset high für pulsdauer goto start 'skip around interrupt handler '*********start of interrupt service routine********************** define inthand isr 'define interrupt handler asm 'start assembly language isr movwf wsave ;save machine registers swapf STATUS, W ; clrf STATUS ; movwf ssave ; movf PCLATH, W ; movwf psave ; ;determine source of interrupt btfsc INTCON,T0IF ; goto emgstop ; -> severe overspeed - do emergency stop btfsc INTCON,RBIF ; goto rcpls ; -> r/c-pulse length determination btfsc PIR1,TMR1IF ; goto tick ; -> do everything that needs to be done periodically btfsc PIR1,RCIF ; goto commrx ; -> communications receive routine btfsc pir1,txif ; goto commtx ; -> communications transmit routine btfsc pir1,adif ; goto adisr ; -> a/d converter interrupt service routine ;emergency stop is executed in main program, the isr only sets the appropriate flag emgstop bsf flag,stop ; set engine stop flag goto endisr ; -> endisr ;auswertung der rc-pulslängen auf port b.4 und 5 ;rc1 (kanal schub) wird mit 16bit ausgewertet und auf 8bit skaliert. ;rc2 (kanal status) wird mit 16bit ausgewertet und auf 8bit reduziert. ;beim überlauf des zählers werden die werte verworfen, um zeit zu sparen. rcpls bcf INTCON,RBIF ; clear interrupt flag movf PORTB,0 ; load port b xorwf rbbak,1 ; xor (port b, port b[t-1]) btfsc rbbak,4 ; level of throttle channel changed? goto rc1 ; (yes) -> rc1 btfsc rbbak,5 ; level of status channel changed? goto rc2 ; (yes) -> rc2 goto endrc ; -> endrc rc1 btfss thrtlin ; throttle level = 0 ? goto rc1l ; (yes) -> rc1l bcf T1CON,TMR1ON ; stop timer 1 movf TMR1L,0 ; load timer 1,l movwf cntl1 ; store to channel counter t,l movf TMR1H,0 ; load timer 1,h movwf cnth1 ; store to channel counter t,h bsf T1CON,TMR1ON ; start timer 1 movf cntl1bk,0 ; subtract counter readings of rising and subwf cntl1,1 ; falling edge to get duration of ppm pulse. btfss STATUS,C ; if wrap-around occurred between the two incf cnth1bk,1 ; redings, the result is negative but this movf cnth1bk,0 ; doesn't matter due to the 2's complement subwf cnth1,1 ; method of subtraction. goto out1 ; (yes) -> out1 rc1l bcf T1CON,TMR1ON ; stop timer 1 movf TMR1L,0 ; load timer 1,l movwf cntl1bk ; store to channel counter t-1,l movf TMR1H,0 ; load timer 1,h movwf cnth1bk ; store to channel counter t-1,h bsf T1CON,TMR1ON ; start timer 1 goto endrc ; -> endrc rc2 btfss thrtlin ; throttle level = 0 ? goto rc2l ; (yes) -> rc1l bcf T1CON,TMR1ON ; stop timer 1 movf TMR1L,0 ; load timer 1,l movwf cntl2 ; store to channel counter t,l movf TMR1H,0 ; load timer 1,h movwf cnth2 ; store to channel counter t,h bsf T1CON,TMR1ON ; start timer 1 movf cntl2bk,0 ; load channel counter t-1,l subwf cntl2,1 ; cntl1 = cntl1 - cntl1bk btfss STATUS,C ; result negative ? incf cnth2bk,1 ; (yes) cnth1bk = cnth1bk + 1 movf cnth2bk,0 ; load channel counter t-1,h subwf cnth2,1 ; cnth1 = cnth1 - cnth1bk - \c goto out2 ; (yes) -> out2 rc2l bcf T1CON,TMR1ON ; stop timer 1 movf TMR1L,0 ; load timer 1,l movwf cntl2bk ; store to channel counter t-1,l movf TMR1H,0 ; load timer 1,h movwf cnth2bk ; store to channel counter t-1,h bsf T1CON,TMR1ON ; start timer 1 goto endrc ; -> endrc ; here the raw pulse length values are made available to the main control ; program, as well the mean "jitter" and repetition rate are evaluated to ; determine the signal quality. out1 movf cntl1,0 ; load channel counter t,l subwf rcrawl1,1 ; rcrawl1 = rcrawl1 - cntl1 btfss STATUS,C ; result negative ? incf rcrawh1,1 ; (yes) rcrawh1 = rcrawh1 + 1 movf cnth1,0 ; load channel counter t,h subwf rcrawh1,1 ; rcrawh1 = rcrawh1 - cnth1 - \c btfsc STATUS,C ; result positive? goto posdif1 ; (yes) -> posdif1 comf rcrawh1,1 ; complement rcrawh1 incf rcrawh1,1 ; rcrawh1 = rcrawh1 + 1 comf rcrawl1,1 ; complement rcrawl1 incf rcrawl1,1 ; rcrawl1 = rcrawl1 + 1 btfsc status,c ; carry set? incf rcrawh1,1 ; (yes) rcrawh1 = rcrawh1 + 1 posdif1 movf rcrawl1,0 ; load rcrawl1 addwf rcdifl1,1 ; rcdifl1 = rcdifl1 + rcrawl1 btfsc status,c ; carry set? incf rcrawh1,1 ; rcrwah1 = rcrawh1 + 1 movf rcrawh1,0 ; load rcrawh1 addwf rcdifh1,1 ; rcdifh1 = rcdifh1 + rcrawh1 + c movf cntl1,0 ; load cntl1 movwf rcrawl1 ; rcrawl1 = cntl1 (for export) movf cnth1,0 ; load cnth1 movwf rcrawh1 ; rcrawh1 = cnth1 (for export) incf ppmcnt1,1 ; ppmcnt1 = ppmcnt1 + 1 goto endrc ; -> endrc out2 movf cntl2,0 ; load channel counter t,l subwf rcrawl2,1 ; rcrawl2 = rcrawl2 - cntl2 btfss STATUS,C ; result negative ? incf rcrawh2,1 ; (yes) rcrawh2 = rcrawh2 + 1 movf cnth2,0 ; load channel counter t,h subwf rcrawh2,1 ; rcrawh2 = rcrawh2 - cnth2 - \c btfsc STATUS,C ; result positive? goto posdif2 ; (yes) -> posdif2 comf rcrawh2,1 ; complement rcrawh2 incf rcrawh2,1 ; rcrawh1 = rcrawh2 + 1 comf rcrawl2,1 ; complement rcrawl2 incf rcrawl2,1 ; rcrawl1 = rcrawl2 + 1 btfsc status,c ; carry set? incf rcrawh2,1 ; (yes) rcrawh1 = rcrawh2 + 1 posdif2 movf rcrawl2,0 ; load rcrawl2 addwf rcdifl2,1 ; rcdifl2 = rcdifl2 + rcrawl2 btfsc status,c ; carry set? incf rcrawh2,1 ; rcrwah2 = rcrawh2 + 1 movf rcrawh2,0 ; load rcrawh2 addwf rcdifh2,1 ; rcdifh2 = rcdifh2 + rcrawh2 + c movf cntl2,0 ; load cntl2 movwf rcrawl2 ; rcrawl2 = cntl2 (for export) movf cnth2,0 ; load cnth2 movwf rcrawh2 ; rcrawh2 = cnth2 (for export) incf ppmcnt2,1 ; ppmcnt2 = ppmcnt2 + 1 endrc movf PORTB,0 ; load port b movwf rbbak ; store to rbbak goto endisr ; -> endisr ; tick stores the rpm counter value into rpmcnt to make it available to the main ; program and sets the tmrof flag to notify to the main program (basic) that ; a new set of pwm values needs to be calculated tick bcf pir1,tmr1if ; clear timer 1 interrupt flag movf tmr0,w ; move timer 0 contents movwf rpmcnt ; to rpmcnt clrf tmr0 ; reset timer 0 bcf t0if ; clear timer 0 interrupt flag bsf flag,tmrof ; set timer1 overflow flag goto endisr ; -> endisr ; the communications receive routine sets the appropriate flag to enter interactive mode commrx bcf pir1,rcif ; clear rxd interrupt flag bsf flag,rxflag ; set receive flag goto endisr ; -> endisr ; the communications transmit routine should (once it's finished) circulate through the ; diagnostic parameters to be transmitted to the host or display unit. but not yet ;-) commtx bcf pir1,txif ; clear txd interrupt flag bsf flag,txflag ; set transmit flag goto endisr ; -> endisr ; adisr will cycle through the analog inputs and load the appropriate a/d results into ; variables to transfer them to the main program. adisr bcf pir1,adif ; clear a/d interrupt flag egt movf adcnt,w ; egt routine (adc channel 0) xorlw 'h0000' ; btfss status,z ; goto amb ; movf adresh,w ; movwf egth ; bsf status,rp0 ; register bank 1 movf adresl,w ; movwf egtl ; bcf status,rp0 ; register bank 0 amb movf adcnt,w ; tamb routine (adc channel 1) xorlw 'h0008' ; btfss status,z ; goto vbat ; movf adresh,w ; movwf ambh ; bsf status,rp0 ; register bank 1 movf adresl,w ; movwf ambl ; bcf status,rp0 ; register bank 0 vbat movf adcnt,w ; vbat routine (adc channel 2) xorlw 'h0010' ; btfss status,z ; goto exad ; movf adresh,w ; movwf vbath ; bsf status,rp0 ; register bank 1 movf adresl,w ; movwf vbatl ; bcf status,rp0 ; register bank 0 exad movlw 'h0008' ; addwf adcnt,f ; adcnt = adcnt + 8 movf adcnt,w ; xorlw 'h0018' ; btfsc status,z ; clrf adcnt ; if adcnt = 18h then adcnt = 0 movlw 'h00c7' ; andwf adcon0,f ; clear chs0-chs2 of adcon0 movf adcnt,w ; iorwf adcon0,f ; set chs0-chs2 of adcon0 according to adcnt bsf adcon0,go ; start new a/d conversion ; goto endisr ; -> endisr endisr movf psave,W ; restore saved registers movwf PCLATH ; swapf ssave,W ; movwf STATUS ; swapf wsave, F ; swapf wsave, W ; retfie ; Return from interrupt endasm '*********end of interrupt service routine************************ 'initialisation is written in assembler because it isn't any more complicated 'but results in much more compact code than in basic asm init movlw 'h0001' ; movwf PORTB ; ignition and transistors off movlw 'h00d8 ; movwf PORTC ; pwm transistors off bsf STATUS,RP0 ; select register bank 1 movlw 'h00ff' ; movwf TRISA ; set port a as input movlw 'h0030' ; movwf TRISB ; set port b 0-3,6,7 as output; 4,5 as input movlw 'h00d8' ; movwf TRISC ; set port c 0-2,5 as output; 3,4,6,7 as input movlw 'h003f' ; movwf OPTION ; attach presc to wdt 1:128, activate rb pull-up, timer 0 external movlw 'h0071' ; movwf PIE1 ; activate timer 1, a/d, usart rx/tx interrupts clrf PIE2 ; deactivate timer 2 interrupt movlw 'h00ff' ; movwf PR2 ; set pwm module to 10 bit resolution movlw 'h0002' ; movwf TXSTA ; ser. async., low speed, txd off movlw 'h000c' ; movwf SPBRG ; set baud-rate to 9.615 (fosc = 8Mhz) movlw 'h0082' ; movwf ADCON1 ; set ra0-ra3,ra5 as analog input, vdd as reference bcf STATUS,RP0 ; select register bank 0 clrf TMR0 ; clear timer 0 movlw 'h0068' ; movwf INTCON ; activate peripheral, timer 0, portb interrupts clrf PIR1 ; clear peripheral interrupt flags movlw 'h0011' ; movwf T1CON ; set timer 1 presc. to 1:2, clk source internally, start timer 1 movlw 'h0005' ; movwf T2CON ; set timer 2 presc. to 1:4, start timer 2 clrf CCPR1L ; clear pwm1.2-9 (fuel pump off) clrf CCPR2L ; clear pwm2.2-9 (engine starter off) movlw 'h000f' ; movwf CCP1CON ; clear pwm1.0-1, start pwm movwf CCP2CON ; clear pwm2.0-1, start pwm ; movlw 'h003b' ; ; movwf SSPCON ; iic-modus initialisieren und aktivieren movlw 'h00a0' ; movwf RCSTA ; set serial receiver to 8bit, activate serial port movlw 'h0085' ; movwf ADCON0 ; initialise a/d converter and start first conversion bsf INTCON,GIE ; activate all interrupts (and off we go...) endasm start: