//-------------------------- #pragma config OSC=INTIO67, FCMEN=OFF, IESO=OFF, MCLRE=OFF, PBADEN=OFF, WDT=OFF//, WDTPS=16 #pragma config CCP2MX=PORTBE, LPT1OSC=OFF, LVP=OFF, DEBUG=OFF, XINST=OFF, PWRT=ON #pragma config BOREN=OFF, STVREN=ON //*********************************************** #include // some constants #define ReqFuelInitx8 87 //8x11.4ms*8=91 should be, but... #define INJ_OPEN_TIMEx16 8 //0.5ms*16 #define defInjPedalOffx16 19 //1.3ms*16 when pedal off ? #define ISCVcranking 250 #define ISCVstarting 230 #define ISCVwarming 175 #define ISCVnormal 140 //ISCV 255=100%, 127=50% #define STARTING_TRIGGER 250 #define TEMPHOT 5 //#define WOT_def 200 //#define WOTenrich 32 #define MS120_CRANKING 40 //up to 500 rpm we say cranking! // TABLE RANGES #define TblRange 8 #define TblLast 7 //TblRange-1 #define SqTblRange 64 //TblRange*TblRange #define ByteToTblRange 5 //8bits>>5 for 0-7 //********** PINS //***PORTA,A/D //PORTA 0-5 AD without 4 //<-- //AD channel 0(RA0) TPS //AD channel 1(RA1) LAMBDA //AD channel 2(RA2) ENG TEMP //AD channel 3(RA3) AIR TEMP //AD channel 4(RA5) on MAP //RA5 - T0CK <-POS signal #define MAIN_RELLAY PORTAbits.RA6 #define FUEL_PUMP PORTAbits.RA7 //***PORTB // PORTB 0,1 - INT0, INT1 <-REF signal //<-- //#define IGN_ON PORTBbits.RB2 //<-- mpx with INT2 when sleep //#define ISCV PORTBbits.RB3 //<-- #define TACHO PORTBbits.RB6 //--> //#define LAMBDA_CORRECTION PORTBbits.RB4 //--> //--> //#define LPG_RELLAY PORTBbits.RB7 //--> //***PORTC #define INJECTORS PORTC //-->> 0-5, PORTCbits.RC7 is inhibit bit for the Ind Coils!!! When = 1 no sparks! #define INJ_135 0b00010000 //PORTCbits.RC6 #define INJ_246 0b00100000 //PORTCbits.RC7 #define ALLINJECTORS 0b00110000 #define COILS PORTC #define ZEROcoil 0b11110000 #define ZEROinj 0b00001111 //-->> 0-5 //***PORTD #define ADSORBER PORTDbits.RD0 #define FUEL_OFF PORTDbits.RD1 #define BTN_PLUS PORTDbits.RD2 #define BTN_MINUS PORTDbits.RD3 //<-- //***PORTE //#define PORTEbits.RE0 //--> //#define PORTEbits.RE1 //--> //#define PORTEbits.RE2 //--> #define T0CONinit 0b11111111 //Timer0:on,8 bit,ext counter on falling edge,no prescale #define T1CONinit 0b10110001 //32MHz, 1000 ticks = 1ms #define T2CONinit 0b01111110 //32MHz TMR2=0, PR2=32 <=> 1024microsec #define T3CONinit 0b10110001 //32MHz 1000 ticks = 1ms //Timer3:16bit read/write, not source for ccp,1:8,not synch,int clock, timer on #define ADCON2initR 0b10100010 //32MHz right just #define ADCON2initL 0b00100010 //32MHz left just //****************************************************************** /* ot MegaSquirt, stock H20A VE Table RPM Range [ 8] # expressed in RPM/100 [ 0] = 7 [ 1] = 12 [ 2] = 21 [ 3] = 30 [ 4] = 39 [ 5] = 47 [ 6] = 56 [ 7] = 65 VE Table Load Range (MAP) [ 8] [ 0] = 20 [ 1] = 30 [ 2] = 45 [ 3] = 55 [ 4] = 65 [ 5] = 80 [ 6] = 90 [ 7] = 100 VE Table [ 8][ 8] [ 0] [ 1] [ 2] [ 3] [ 4] [ 5] [ 6] [ 7] [ 0] = 43 47 52 55 57 56 53 50 [ 1] = 46 50 56 59 61 60 57 54 [ 2] = 51 55 61 64 66 65 63 60 [ 3] = 54 59 65 69 71 70 67 64 [ 4] = 57 62 69 73 75 74 71 68 [ 5] = 62 66 74 78 79 78 75 72 [ 6] = 65 70 78 83 84 83 80 76 [ 7] = 68 73 82 87 88 88 84 80 */ #pragma idata ram unsigned char //CYL TDC, working tact 2 1 6 5 4 3 //INT0 10gr ATDC, POS pulses 4 24 20 16 12 8 //110gr to the next TDC BATCH[7]={0,INJ_135,INJ_246,INJ_135,INJ_246,INJ_135,INJ_246}, // SEQ[7]={0,0b00001100,0b00001101,0b00001110,0b00001001,0b00001010,0b00001011}, //1->4,2->5,3->6,4->1,5->2,6->3 ACCELx16[TblRange] = {0,0,18,25,27,30,33,35}, COILCHRG[TblRange]={55,55,45,40,35,30,25,20},//degrees coil charge CRNK_PLSx8[TblRange]={105,93,75,57,35,30,25,20},//ms*8 // General Motors uses stoichiometric mixtures for both idle and // cranking pulse widths at full coolant temperature, and a 1.5:1 cranking AFR at -30°F(-34C) or so. //50F(10C) range is nearly 8.7:1 commanded AFR WARMUPFACTOR[TblRange] = {220,200,160,140,135,130,125,120}, ISCV[TblRange] = {240,200,155,125,110,100,95,90}, STARTING_FACTOR[TblRange]= {170,160,155,150,145,145,140,130}, //afterstart enrichment percentage typically around 25%, up to 45% AIRTCORR[TblRange] = {140,137,135,127,125,120,120,120}, VE_MAP[SqTblRange] = //[MAP][RPM] %VE //700rpm<=>MS120=28(28.57ms/120graduses 6500rpm<=>MS120=3(3.07ms/120graduses) { 43, 47 , 52 , 55 , 57 , 56 , 53 , 50, //20KPa 46 , 52 , 56 , 59 , 62 , 61 , 57 , 54, 51 , 56 , 60 , 64 , 67 , 66 , 63 , 60, 56 , 60 , 65 , 69 , 71 ,70 , 67 , 64, 60 , 64 , 70 , 74 , 76 , 74, 71 , 67, 64 , 68 , 75 , 79 , 81 , 79 , 78 , 73, 67 , 72 , 79 , 83 , 85 , 84 , 81 , 77, 70 ,76 , 83 , 87 , 89 , 88, 84 , 82 //100KPa },//RPMs are contrary to milliseconds!!! //used in low priority routines, not to use in high-priority int routines!!! REQ_FUEL=ReqFuelInitx8, InjPedalOff = defInjPedalOffx16, PULSES=0,CountdownLoaded=255, WATERTEMP=0, AIRTEMP=0, MAPNORM=7,MAP=127, TPSmin=127,DeltaTPS=0, PEDAL_OFF=1, CRANKING=1,STARTINGindx=0 , RCyc=0; ram volatile unsigned char DEG_CNT_IGN=85, MS120=45, MS120NORM=7, TPS=127,TPSprev=127, Rollover=1, TactsLow=1,TactsHigh=0, batch=0, MSINJH=0,MSINJL=0 ; #pragma udata ram unsigned char h,AD_8,j,VE_MAPindex, //only in INT routines used !!! CYL, free,//used as help var, but value not used hh,//help var in high priority interrupt routines! not to use in low-priority routiness! CoilInj, SPARKING ; ram unsigned int i ,H//used in low priority routines! not to use in high priority routines!!! ,HH// used in high priority routines!!! ; #pragma code void init(void) { //*****************hardware init **************** OSCCON = 0b01110000;//FOSC3:FOSC0 = 1000, so INTOSC is primary! , 8MHz OSCTUNE = 0b01000000; //INTs RCONbits.IPEN=0;//disable INT priority INTCONbits.GIE = 1; // Enable interrupts INTCONbits.PEIE = 1; // Enable periferal interrupts INTCONbits.RBIE=0;//PORTB change -> INT enabled NO! INTCON2bits.RBPU=0;//PORTB pull-ups disabled INTCON3bits.INT1IP=1; //INT1 priority high INTCON3bits.INT1IE=1; //enable INT1 INTCONbits.INT0IE=1; //enable INT0 INTCON2bits.INTEDG0 = 1; //external INT0 on RISING edge INTCON2bits.INTEDG1 = 0; //external INT1 on FALLING edge INTCON3bits.INT2IE=0; //disable INT2 //timers T0CON=0; INTCONbits.TMR0IE=0; T1CON=0; PIE1bits.TMR1IE=0; T2CON=0; PIE1bits.TMR2IE=0; T3CON=0; PIE2bits.TMR3IE=0; // A/D PIE1bits.ADIE=0;//disable AD INT ADCON0 = 0;//A/D disabled //Comparators CMCON = 0b00000111; // comparators off PIE2bits.CMIE=0; //CCPs CCP1CON=0; PIE1bits.CCP1IE=0; // PWM SETINGS PR2 = 0b11111111 ; CCP2CON = 0b00111100 ; PIE2bits.CCP2IE=0; CCPR2L = 250;//100% - duty cycle ; //PORTs TRISA= 0b00111111; PORTA = 0; //TRISB = 0b000011xx TRISBbits.TRISB2 =1; TRISBbits.TRISB3=0; //CCP2 multiplexed TRISBbits.TRISB4=1; TRISBbits.TRISB5=0; TRISBbits.TRISB6=0; TRISBbits.TRISB7=0; TRISC=0b00000000; PORTC=0b00000000; TRISD=0b00001110; PORTD=0b00000000; //POR RCONbits.POR=1; //***************** soft init //align VE table, x/100 -> x/127 j=0;while(j>7)*MAP)>>7)+ACCELx16[DeltaTPS];// 1/16 ms } H = (((H*WARMUPFACTOR[WATERTEMP])>>7)*AIRTCORR[AIRTEMP])>>7;//WARMUP/127 H=((H*STARTING_FACTOR[STARTINGindx])>>8)+INJ_OPEN_TIMEx16; MSINJH = (unsigned char)(H/4); MSINJL = (unsigned char)((H%4)*64); }//calc_inj_ms void calc_inj_ms(void) { if(PEDAL_OFF)H = InjPedalOff;// 1/16 ms else { VE_MAPindex = (TblRange*MAPNORM)+TblLast-MS120NORM; H = VE_MAP[VE_MAPindex]; H = ((((H*REQ_FUEL)>>7)*MAP)>>7)+ACCELx16[DeltaTPS];// 1/16 ms } H = ((((H*WARMUPFACTOR[WATERTEMP])>>7)*AIRTCORR[AIRTEMP])>>7)+INJ_OPEN_TIMEx16; MSINJH = (unsigned char)(H/4); MSINJL = (unsigned char)((H%4)*64); }//calc_inj_ms /////////////////////////////////// void wait(void) { i=1; while(i) { i++; _asm CLRWDT _endasm } } void wait_sec(void){wait();wait();wait();} //*********************INT handlers***************************** void InterruptHandlerHigh(void); // High priority interrupt vector #pragma code InterruptVectorHigh = 0x08 void InterruptVectorHigh (void) { _asm goto InterruptHandlerHigh _endasm } // High priority interrupt routine #pragma interrupt InterruptHandlerHigh //save=PROD void InterruptHandlerHigh (void) { if (INTCONbits.INT0IF) //INT0 start of REF { _asm CLRWDT _endasm INTCONbits.INT0IF = 0; free = TMR3L; if(Rollover){ MS120=45;Rollover=0;}else MS120 = TMR3H>>2;//TMR3H>>2 = ms TMR3H=0;TMR3L=3; T3CON=T3CONinit;//start timer to calc MS120 PIE2bits.TMR3IE=1;// to stop if rollover CYL=(PULSES+2)>>2; //if(CYL){if(CYL==1)CYL=6;else CYL--;} if(MS120>27)MS120NORM = 7; else MS120NORM = MS120>>2;// normalised miliseconds(0-7) if(CYL%2) { TactsLow++; if(!TactsLow)TactsHigh++; TPSprev = TPS; } // *** Load countdoun for the IC charge CountdownLoaded = 255-(DEG_CNT_IGN>>1)+1; //timer to countdown for the spark, 2 degrees per pulse! TMR0L = CountdownLoaded; T0CON = T0CONinit;//start INTCONbits.TMR0IE = 1; //Enable timer0 interrupt SPARKING=0; //START INJECTION. It seems, the best point to start injection if (MSINJH) { if(batch) CoilInj = BATCH[CYL]; else CoilInj = ALLINJECTORS; TMR1H = 255-MSINJH; TMR1L = 255-MSINJL; T1CON = T1CONinit;//start PIE1bits.TMR1IE=1;//enbl TIMER1 int } else CoilInj=0; INJECTORS = CoilInj; }else if (INTCON3bits.INT1IF)//INT1 end of REF { INTCON3bits.INT1IF = 0; PULSES = TMR0L-CountdownLoaded; }if (INTCONbits.TMR0IF)// timer0 { INTCONbits.TMR0IF = 0; if(SPARKING) //time to spark, IC off! { T0CON = 0;// no need to count more TACHO = 0; CoilInj=CoilInj&ZEROcoil; COILS = CoilInj;// all cyl ign pins --> off & SPARK!!! }else { T0CON = T0CONinit;//start INTCONbits.TMR0IE = 1; //Enable timer0 interrupt hh = ((COILCHRG[MS120NORM])>>1)-1; TMR0L = 255-hh; CountdownLoaded = CountdownLoaded-hh; CoilInj = CYL|CoilInj; COILS = CoilInj; TACHO=1; SPARKING=1; } } else if (PIR1bits.TMR1IF)// timer1 INT - inject end { PIR1bits.TMR1IF = 0; T1CON = 0; CoilInj=CoilInj&ZEROinj; INJECTORS = CoilInj; } else if (PIR2bits.TMR3IF)//timer3 rollover { PIR2bits.TMR3IF=0; Rollover++; T3CON=0; } else if(!RCONbits.TO)// WatchDogTimer RESET { FUEL_PUMP=0; //LPG_RELLAY=0; wdt_loop: MAIN_RELLAY = 0;wait_sec();MAIN_RELLAY = 1;wait_sec(); MAIN_RELLAY = 0;wait_sec();wait_sec();wait_sec(); goto wdt_loop; } else if(STKPTRbits.STKFUL)//StackFull RESET { FUEL_PUMP=0; //LPG_RELLAY=0; stf_loop: MAIN_RELLAY = 0;wait_sec();MAIN_RELLAY = 1;wait_sec(); MAIN_RELLAY = 0;wait_sec();MAIN_RELLAY = 1;wait_sec(); MAIN_RELLAY = 0;wait_sec();wait_sec();wait_sec(); goto stf_loop; }else if(STKPTRbits.STKUNF)//StackEmpty RESET { FUEL_PUMP=0; //LPG_RELLAY=0; stu_loop: MAIN_RELLAY = 0;wait_sec();MAIN_RELLAY = 1;wait_sec(); MAIN_RELLAY = 0;wait_sec();MAIN_RELLAY = 1;wait_sec(); MAIN_RELLAY = 0;wait_sec();MAIN_RELLAY = 1;wait_sec(); MAIN_RELLAY = 0;wait_sec();wait_sec();wait_sec(); goto stu_loop; } //else FUEL_PUMP=0;//some shit } //************************AD******************************* void waitAD(void){while(ADCON0bits.GO);} void get_AD(void)//get AD result as low 4 bits of the byte { ADCON2 = ADCON2initL;//A/D result LEFT! justified ADCON0bits.ADON = 1;//A/D enabled ADCON0bits.GO=1;//start AD waitAD(); AD_8 = ADRESH; } //Tc=25C, V=3, 10mv/C => 75C V=3.5(ADRES716) 95C=3.7V (ADRES=758), WATERTEMP=12(3.5/5*1024/4/16) //Tc=-25 V=2.5 (ADRES=512) Tc=100 V=3.75V //engine warm V=3.2V 655 //12 gradusa V=2.92 598 //=> (ADRESH-128)>>2 //MAP: 15 PSI(1atm) = 2.5V MAP=127 // 0 PSI = 0.5V ADRES = 102 MAP=25 //=> (ADRES-25)/204*256 //!!!1atm-0.5V!!! SPD015GA !!! /*void get_AD_LAMBDA(void) { //lambda 0.45V - OK 0.45/5*1024 = 92 //1V - high //0.2V - low //channel 1 on low half byte of PORTD LAMBDA! ADCON1 = 0b00001010; ADCON0bits.CHS3 = 0;ADCON0bits.CHS2 = 0;ADCON0bits.CHS1 = 0;ADCON0bits.CHS0 = 1; ADCON2 = ADCON2initR;//A/D result RIGHT! justified ADCON0bits.ADON = 1;//A/D enabled ADCON0bits.GO=1;//start AD waitAD(); LAMBDA =ADRESL; if(LAMBDA&&LAMBDA<200)LAMBDAbad=0; else LAMBDAbad=1; } */ void ADnOTHR(void) { // TPS ADCON1 = 0b00001010; ADCON0bits.CHS3 = 0;ADCON0bits.CHS2 = 0;ADCON0bits.CHS1 = 0;ADCON0bits.CHS0 = 0; get_AD(); TPS = AD_8; if(TPS<(TPSmin+3)){PEDAL_OFF=1;if(TPS111)MAPNORM = 7; else MAPNORM = H>>4;//0..7 H=((H*100)/127)+27;//27 to 127 range!!! MAP=H; if(!RCyc){//to save time // WATERTEMP ADCON1 = 0b00001010; ADCON0bits.CHS3 = 0;ADCON0bits.CHS2 = 0;ADCON0bits.CHS1 = 1;ADCON0bits.CHS0 = 0; get_AD(); h=AD_8; if(h>127) { h = (h-127)>>3;//LM335Z specific!!! if(h>7)WATERTEMP=7; else WATERTEMP=h;//0..7 }else WATERTEMP = 0; //get_AD_LAMBDA(); // LAMBDA // AIRTEMP ADCON1 = 0b00001010; ADCON0bits.CHS3 = 0;ADCON0bits.CHS2 = 0;ADCON0bits.CHS1 = 1;ADCON0bits.CHS0 = 1; get_AD(); h = AD_8; if(h>127) { h = (h-127)>>3;//LM335Z specific!!! if(h>7)AIRTEMP =7; else AIRTEMP = h; }else AIRTEMP=0; }else RCyc=200; RCyc++; // Watch Dog Timer clear _asm CLRWDT _endasm // COMMON STATISTICS ACTIONS if(FUEL_OFF){// LPG_RELLAY=1; FUEL_PUMP=0;} else {// LPG_RELLAY=0; FUEL_PUMP=1;} if(TPS>TPSprev) { h=TPS-TPSprev; if(h>7)DeltaTPS=7; else DeltaTPS=h; }else if(DeltaTPS)DeltaTPS--; if(BTN_PLUS){ if(PEDAL_OFF)InjPedalOff++; else REQ_FUEL++; while(BTN_PLUS) { _asm CLRWDT _endasm }; } if(BTN_MINUS){ if(PEDAL_OFF)InjPedalOff--; else REQ_FUEL--; while(BTN_MINUS) { _asm CLRWDT _endasm }; } // SIMULATIONS //if(TPSbad)if(!MAPbad)TPS=MAPTPSsimu[MAP>>ByteToTblRange];else TPS=64;//dirty simulation of TPS, using MAP //if(MAPbad)if(!TPSbad)MAP = TPSMAPsimu[TPS>>ByteToTblRange];else MAP = 30;//dirty simulation of MAP, using TPS if((!WATERTEMP)&&(TactsHigh>30))WATERTEMP = TEMPHOT;// probably temp sensor bad! }//ADnOTHR(void) //********************************************************* void pre_start(void) { MAIN_RELLAY=1; wait(); FUEL_PUMP =1; T2CON=T2CONinit; ADnOTHR(); TPSprev=TPS; TPSmin=TPS; if(!FUEL_OFF)//priming pulse { wait_sec(); TMR1H =255-12;//3ms TMR1L=0; INJECTORS=ALLINJECTORS; T1CON = T1CONinit;//start PIE1bits.TMR1IE=1;//enbl TIMER1 int } } void main_loop(void) { CCPR2L = ISCVcranking; if(FUEL_OFF)MSINJH=0;//anti flood, LPG else{ h=(CRNK_PLSx8[WATERTEMP]/3)+INJ_OPEN_TIMEx16; MSINJH = h/4; MSINJL = (h%4)*64; } cranking_loop: ADnOTHR(); if((MS120>MS120_CRANKING||TactsLow<3)&&TactsLow<9)goto cranking_loop; CCPR2L = ISCVstarting; TactsLow=1; CRANKING=0; starting_loop: ADnOTHR(); h=70+MS120; if(h>102)DEG_CNT_IGN=102-COILCHRG[MS120NORM]; else DEG_CNT_IGN=h-COILCHRG[MS120NORM]; if(FUEL_OFF)MSINJH=0;//LPG else calc_inj_ms_starting(); if(!TactsHigh) { STARTINGindx=TactsLow>>ByteToTblRange; goto starting_loop; } batch=1; normal_loop: ADnOTHR(); h=70+MS120; if(h>102)DEG_CNT_IGN=102-COILCHRG[MS120NORM]; else DEG_CNT_IGN=h-COILCHRG[MS120NORM]; if(FUEL_OFF)MSINJH=0;//LPG else calc_inj_ms(); CCPR2L = ISCV[WATERTEMP]; goto normal_loop; } void main() { init(); pre_start(); main_loop(); }