ECU- styrning till en VW pumpdysediesel.

Berätta om dina pågående projekt.
svanted
Inlägg: 5082
Blev medlem: 30 augusti 2010, 21:20:38
Ort: Umeå

Re: ECU- styrning till en VW pumpdysediesel.

Inlägg av svanted »

ok, du mäter alltså flera tidsluckor för att skapa ett tröskelvärde som används för att detektera en lång tidslucka...?
när den kompar blir de ju bara lite längre...
man behöver kanske inte hålla reda på mer än två tidsluckor
om man jämför två efter varandra följande tidsluckor A och B,
när A är mindre än typ 1/5 av B är B en långtidslucka, om inte, lägger man A=B och mäter nästa som blir B,
skillnaden mellan två efterföljande korta luckor verkar inte bli mindre än 25%.
Janson1
Inlägg: 1338
Blev medlem: 1 december 2016, 09:06:02
Ort: Marks Kommun

Re: ECU- styrning till en VW pumpdysediesel.

Inlägg av Janson1 »

mrfenzy: Först och främst är jag ju skyldig att ha rätt sketch och visa rätt förutsättningar för en seriös felsökningshjälp, så här kommer mitt senaste alster. Jag har numera bara 17 case dvs. jag kör "halvvarvsprincipen", har visat sig funka bäst.

Kod: Markera allt

    // Förändrad 2018-09-17 och inlagd 09/18, aktiv/inaktiv fungerar
    // utmärkt. max ändrat till strax under 4000 rpm ua. Tändläget verkar ua ochså.
    // nu läser den av alla analogread i följd om 2 och 2.= fungerar!!
    // batterispänningens inverkan grovjusterad = fungerar
    // en individuell möjlig injustering per spridare finns med. 
   
    
            // här är olika justerbara parametrar som påverkar enligt följande:
   // const byte lageffekt = 5;         // effektläge tomgång utan gaspot (5) (nödkörning)
   // const byte marcheffekt = 230;     // effektläge marcheffekt utan gaspot (230)(nödkörning)
   // const byte fulleffekt = 252;      // effektläge fulleffekt utan gaspot (252) (nödkörning)
    const byte totaltid = 13;         // totaltid för case 16: x * motorns duration (13)
    const int tryckminskn = 60;       // turbotrycket ställs in här, högre tal = mindre tryck (60)
    const int lagstavarv = 500;       // tomgångsvarvet 500 uS motsvarar ca 800 Rpm (500)
    const byte hogstavarv = 120;      // fullgasvarvet 100 uS motsvarar ca 4200 RPM  (100)(160 = ca 2500 RPM)
    const byte aggrfaktorlag = 8;     // hur mycket spridar PWM skall öka vid belastning mellanvarv (8)
    const byte aggrfaktorhog = 20;    // hur mycket spridar PWM skall öka vid belastning högvarv (20)
    const int minfart = 3800;         // lägsta startvarv för spridarfunktion (3300 uS = 152 RPM)(3300)
    const byte startmangd = 9;        // avgör max startmäng 9 = 1,5 vevaxelpulser = 9 grader ontid (9)
    const float maxdeltalag = 5.0;    // max insprutningstid mellanvarv mdutation * 6.0 ger 3 vevaxelpulser = 18 gr ontid (9.0)
    const byte lagmangd = 4;          // max lågvarvsmängd 4 =  2 vevaxelpulser = 9 grader ontid (under tomgångsvarv)(4)
    const int tid1 = 2500;            // tid 1 är för att hitta pulsluckan vid start/lågvarv < 300 RPM (400)                            
    const int tid2 = 1500;            // tid 2 är för att hitta pulsluckan i mellanvarv 1100--> (1200)
    const int tid3 = 1000;            // tid 3 är för att hitta pulsluckan i alla andra förekommande varv 1100--> (300)
    const int tid4 = 100;             // tid 4 är för att hitta pulsluckan på högsta varvtal
    const byte turbostartregl = 150;  // när tubotrycket börjar avläsas och bli aktivt (150 = uS mduration ca 3200RPM)(150)
    const float senasteinspr = 7.0;   // senaste insprutningstid (vid tomgång)(7.0 = 3,5 vevaxelpulser = 21 grader delaytid
    const byte tidigasteinspr = 60;   // kortaste insprutningsfördröjning (vid maxvarv)(60=t19=24grFödp)(30=t20=18grFödp)
    const int sprtroghet = 400;       // ett grundvärde för spridarnas påslagsfördröjning i uS.                           
    const int sprdiff1 = 0;           // en ev tidigareläggning av spridare 1 om den avviker i startfördröjning (uS)
    const int sprdiff2 = 0;           // en ev tidigareläggning av spridare 2 om den avviker i startfördröjning (uS)
    const int sprdiff3 = 0;           // en ev tidigareläggning av spridare 3 om den avviker i startfördröjning (uS)
    const int sprdiff4 = 0;     //20  // en ev tidigareläggning av spridare 4 om den avviker i startfördröjning (uS)                                 
    
   
    int vevpin = 2;                   // pulsingång vevaxelgivare, (aktivt hög).
    int kampin = 3;                   // kamaxelgivarens ingång, (aktivt låg). 
    int pulsutpin = 7;                // pulsutgång 2 pulser per varv (kontrollutgång för övervakningen).
    int sprpins [] ={11,10,9,8};      // till spridarna (blir aktivt höga)
    int Disable = 12;                 // aktivt hög stoppar utsignalerna till spridarna
    int sprControl = 13;              // kontrollutgång för spridare till övervakningen
    unsigned long delvalue;           // delvärde av pulstid i uS.
    unsigned int ondelay;             // tillslagsfördröjning spridare i uS (mS)(inne i case 18)
    long puls, priv, delta;           // senaste, föregående och delta (totalöppningstid) i uS(mS)
    float error;                      // error = varvfelet i decimalform 
    float starttandf, finKorr;        // starttand i decimalform för att få startfördröjningstid och finkorrigering av öppninstiden +-.
    float  mduration, bduration;      // varvfelet = motorduration/börduration i decimalform
    byte tand = 0;                    // vevpin räknare 0 till 28, i alla fall till 26
    byte gas;                         // gas 0-255
    byte pekare = 0 ;                 // pekare för att välja rätt spridarutgång, startar på 0 
    byte kamtand = 0;                 // Kamtand för att sluta detektera kamaxelgivaren efter 51 (max 255)tänder, startar på 0
    int fasttid = 300;                // Fasttid = tid,tid2 eller tid3 beroende på varvtal, startar alltid på 300 uS
    byte analogval;                   // En switch/case till analogread
    int turbotryck;                   // turbotryck
    int battVolt = 400;               // mäter systemspänning till spridare
    int variabel1;                    // bra att ha variabel 1
    int variabel2;                    // bra att ha variabel 2
    int ambTemp = 300;                // mäter omgivningstemperaturen
    int atmtryck = 330;               // mäter atmosfärstrycket
    int sprstartkorr = 50;            // spridarstartkorregering i uS, spänningsberoende
    int sprtroghetklar;               // korrektion för den inbyggda påslagströgheten i spridarna
    int spridardiff = 0;              // en ev. individuell spridartid korrigering (uS)
    
    void setup()                     
 {
 
   pinMode(vevpin, INPUT_PULLUP);     // satt vevpin som ingång (2) Testar nu med pullup...                        
   pinMode(kampin, INPUT);            // satt kampin som ingång (3)
   pinMode(sprpins[pekare], OUTPUT);  // spridarutgångar satta som arrey (11,10,9,8)
   pinMode(sprControl, OUTPUT);       // en spridarutgång som blir hög varje gång en spridare öppnas (13)(Övervakningen)
   pinMode(Disable, INPUT_PULLUP);    // ECU väljare Hög = on, Låg = off (12)
   pinMode(pulsutpin, OUTPUT);        // satt pulsutpin som utgång (2 pulser per varv)(7)(övervakningen)
   //Serial.begin(250000);
 }
    //______________________________________________________________________
    void loop()
 {
        
                                    // Det får plats ca 1700 klockcykler mellan varje x tal(case) (1 till 17) 
                                    // Det tar lite mer än 100 mikrosek att läsa av en analogingång,
                                    // så ingen analogRead här, skall vara i case 17!
                                    
                                 
     if (digitalRead(Disable)==LOW)     // Disable låg stänger av ECU:n och gör den passiv
      {  
      delta = 0;                        // Genom att delta (insprutningstid) förblir 0.
      pinMode(sprpins[pekare], INPUT);  // Gör om spridarutgångarna till ingångar för att ej belasta
      pinMode(sprControl, INPUT);       // Gör om spridarcontrollen till ingång för att ej belasta
      }
      
     else 
      {
      pinMode(sprpins[pekare], OUTPUT); // Vid aktiv igen så gäller spridarutgångarna som utgångar igen.
      pinMode(sprControl, OUTPUT);      // Vid aktiv så gäller spridarcontrollen som utgång igen
      }                            //*Detta är normalläget, samma som i setup*
        
             
 
        
      if (kamtand <= 250)              // när kamtanden är räknad 251 gånger så slutar den detektera kampin.
       { 
        if (digitalRead(kampin)== HIGH)// varje gång kamaxelns hempuls detekteras så resetas 4 räknaren
         { 
          pekare = 0;                  // resetas till 0. Denna funktion läses utanför switch.
          kamtand ++;                  // räknar upp kamtandräknaren vid varje kampin låg upp till max.
         }
       }
       
     switch (tand)                    // här startar switch och case, tandräknaren stegar fram ett steg (case)
  {
     case 1:               // Detta case ger första pulstid 
          delvalue = priv;            // Första pulstid läggs in som deltid 1
     break; 
      
     case 2:              // Detta case ger andra pulstid
          delvalue = priv + delvalue; // föregående pulstid + föregående deltid läggs ihop
          sprstartkorr =map(battVolt, 150, 700, 0, 400); // batterispänningen blir spridartidskorrigering
          sprstartkorr = constrain(sprstartkorr,50,400);
     break;
       
     case 3:             // Detta case ger tredje pulstid
          delvalue = priv + delvalue; // föregående pulstid + föregående deltid läggs ihop
     break; 
       
                                     
     case 4:             // Detta case ger fjärde pulstid
          delvalue = priv + delvalue; // föregående pulstid + föregående deltid läggs ihop
     break;                          
       
     case 5:             // Detta case ger femte pulstid
          delvalue = priv + delvalue; // föregående pulstid + föregående deltid läggs ihop
     break;
     
      
     case 6:              // Detta case ger sexte pulstid
           delvalue = priv + delvalue; // föregående pulstid + föregående deltid läggs ihop 
     break;          
       
     case 7:              // Detta case ger sjunde pulstid      
           delvalue = priv + delvalue; // föregående pulstid + föregående deltid läggs ihop
     break;
       
     case 8:             // Detta case ger motorns börvärde från gaspoten som blir lägsta och högsta varvtal
           bduration =map(gas,0, 255, lagstavarv, hogstavarv); // ställs in högst upp
                         // Och åttonde pulstid
           delvalue = priv + delvalue; // föregående pulstid + föregående deltid läggs ihop
     break;
       
     case 9:            // Detta case ger motorns verkliga fart baserat på dom 9 första tänderna. (660 - 115 uS vid normalvarv ca 800 till 4200 rpm.)
           mduration = delvalue/12;   // Motorns totala pulstid i mikrosek dividerat med 12 ger motorns duration
                       //  Och avgör om tillräcklig fart är uppnådd för motorstart              
           if(mduration >= minfart)  // motorn måste upp i x fart för att få bränsle, ställs högst upp (minfart i uS) 
            {                         
             mduration = 0;           // Om underfart, motorduration resetas
             delta = 0;               // och delta(insprutningstid)resetas
            }
     break;        
      
     case 10:          // Detta case räknar ut skillnaden mellan är och börvärde - 1 = error
          error = (mduration / bduration)-1; 
       if (error <=0.)                       // om error under noll
        {
         error = 0.;                         // förblir error 0 för att ej få minusvärden
        }
     break;        // felet i uS mellan är och börvärde för motorns fart 
     
      
     case 11:   // detta case räknar ut tidsdiff per spridare plus systemspänningsdiff
     sprtroghetklar = sprtroghet + spridardiff - sprstartkorr; // spridartröghet klart värde räknas ut här
               //       500      + (0 till 50) - (0 till 400)
     break;    //       500      +     0       -      50
      
    // case 12:
          // ledigt
   //  break;                         
    
     case 12:           // Detta case för insprutningsfördröjning i gånger, ställs högst upp               
       starttandf = mduration /tidigasteinspr; // starttandf, ett flyt-tal = motorns duration/ minsta duration/max RPM. ställs högst upp
       if (starttandf >= senasteinspr)         // om fördröjning över målvärdet, som vid tex startvarv (ställs in högst upp)
        {                  
         starttandf = senasteinspr;            // blir det målvärdet ändå
        }
     break;
 
     case 13:                     // Detta case ger förtändningen  
        ondelay = (mduration * starttandf);  // tillslagsfördröjning = motorns duration * starttandsfördröjning (decimaltal)       
     break;                                  // Ondelay uS = mduration uS * starttandf i decimalform 
                                                               
     case 14:          // Detta case ger motorns karaktärstik på arbetsvarv
     if (mduration >=161)                          // "mellanvarv"
      {                                            // Felkorrigeringsvärde som ger spridaröppningstid i uS 
       delta = mduration * error * aggrfaktorlag;  // aggrfaktor låg avgör hur mycket extra ontid spridarna får vid belastning lägre varv
        if (delta >= maxdeltalag * mduration)      // om delta är mer än max tillåten delta x mduration
         {
          delta = maxdeltalag * mduration;         // förblir delta max tillåten
         }                     
      }
     if (mduration <= 160)                        // "högvarv"
      {
       delta = mduration * error * aggrfaktorhog; // Felkorrigeringsvärde som ger spridaröppningstid i uS 
      }                                           // aggrfaktor hög avgör hur mycket extra on tid spridarna får vid belastning högre varv
     break;

     case 15:         // (används ej) Detta case bestämmer varvtalet när turbon skall börja regleras ner
     if (mduration <= turbostartregl)        
      {                                      // via kortare spridartider, ställs högst upp
       delta = delta ;                        // används ej än så delta förblir delta oförändrat            
       if (delta <=0)
        {
         delta = 0;                          // för att undvika minusvärden
        }
      }
                    // och mjukstartsfunktion
     if (mduration >= 700)                   // Vid lite över startfart
      {
       delta = lagmangd * mduration;         // blir det mjukstart som justeras via lågmängd högst upp              
      }
      
                   // och absolut längsta insprutningstid
     if (delta + ondelay >= totaltid * mduration) // om delta och ondelay i uS blir mer än totaltid
      {            // så justeras endast delta ner
       delta = (totaltid * mduration)-ondelay;// Absolut max insprutningstid (delta), ställs högst upp
      }           // denna justering gäller bara på högvarv, hög belastning
     break;
     
     case 16:    // Detta case är insprutningsfasen "spridar-on-off-mode"
     if (ondelay >=10000)                     // Om ondelay är mer än 10000 uS. ( < 300RPM )
       {                                      // går tiden över från uS till mS.
        ondelay = ondelay/1000;               // Ondelay uS blir mS.
        delta = delta/1000;                   // Delta uS blir mS.
                // och startmängden vid motorstart
       if ((delta * 2)>= startmangd)               // här ställs startmängden in (högst upp) 
        {
         delta = startmangd;                  // så det blir rätt startmängd/slag (5 = 0,75 tänder = 4,5 vevgrader)
        }
        delay(ondelay);                       // Fördröjer starttiden x antal mS beroende på varvtalet (mdurationen)
        digitalWrite (sprpins[pekare],HIGH);  // Spridarpinne hög,insprutning börjar. sprpins [pekare 8,9,10 eller 11]. 
        digitalWrite(sprControl, HIGH);       // Kontrollpinne som går hög vid varje insprutningstillfälle.
        delay(delta);                         // Här läggs insprutningstiden in som sen fördröjer processorn i delta mS
        digitalWrite (sprpins[pekare],LOW);   // Spridarpinne låg,insprutning avslutad sprpins [pekare 8,9,10 eller 11].
        digitalWrite (sprControl, LOW);       // Kontrollpinne som går låg efter varje insprutningstillfälle.
       }                                     // Detta paket används vid låga farter såsom start/lågvarv < 250 RPM
     
     else                                     // Eller om delay är mindre än 10000 uS. (> 300 RPM)
       {
        if (delta > 50)                       // Delta under 50 uS har inget värde
        {
        delta = delta + sprtroghetklar;       // Delta över 50 blir x delta + trögheten i spridaren (ca 250 uS)
        }
        ondelay = ondelay - sprtroghetklar;   // tidigarelägger insprutningstart med hänsyn till spridartrögheten
        delayMicroseconds(ondelay);           // Fördröjer starttiden i ondelay uS beroende på varvtalet (mdurationen)
        digitalWrite (sprpins[pekare],HIGH);  // Spridarpinne hög,insprutning börjar. sprpins [pekare 11,10,9 eller 8]. 
        digitalWrite(sprControl, HIGH);       // Kontrollpinne som går hög vid varje insprutningstillfälle.
        delayMicroseconds(delta);             // Här läggs insprutningstiden in som sen fördröjer processorn i on spridare delta uS
        digitalWrite (sprpins[pekare],LOW);   // insprutning avslutad sprpins [pekare 8,9,10 eller 11] går låg.
        digitalWrite (sprControl, LOW);       // Kontrollpinne som går låg efter varje insprutningstillfälle.
       }                                      //Detta paket används vid varv (250 -> RPM = nästan alltid, förutom vid motorstart)
     break;                         //Dessa paket tar 1 till 6 tänder att genomföra beroende på varvtal och belastning
       
     case 17:                       // är mellan  tand 19 och 24
          switch (analogval)
      {
        case 0:   
           gas = analogRead(A0)>>2;           // analogingång för gasreglage 0 till 255( skiftad 2 gånger)
           turbotryck = analogRead(A4);
        break;  

        case 1:
         variabel1 = analogRead(A1)>>5;        //(enginetmp) 0 till 512 0,1 Volt/10 grad använder LM-35 tempgivare (skiftad 1 gång)
         battVolt = analogRead(A7);            // skall vara A7!!
        break;

        case 2:
         gas = analogRead(A0)>>2;           // analogingång för gasreglage 0 till 255( skiftad 2 gånger)
         turbotryck = analogRead(A4);        // analogingång för turbotryck 0 till 127 (skiftad 3 gånger)ambTemp = analogRead(A3);                              
  
        case 3:
         variabel2 = analogRead(A2)>>3;        // (turboAirTemp) skall vara turboAirTemp,
         atmtryck = analogRead(A6);          // analogingång för lufttrycket max 255
        break;

        case 4:
         gas = analogRead(A0)>>2;           // analogingång för gasreglage 0 till 255( skiftad 2 gånger)
         turbotryck = analogRead(A4);        // analogingång för turbotryck 0 till 127 (skiftad 3 gånger)
        break;

        case 5:
          variabel1 = analogRead(A5)>>5;        // A7!!
          ambTemp = analogRead(A3);
        break;                                
       }
       analogval ++;                             // räkna upp analogval 1 steg   
      if (analogval == 5)                        // när analogval har blivit 5 så
        {
         analogval = 0;                          // resettas analogval till 0 igen
        }   
    break;   // analalogRead tar ca 120 uS att läsa = 1-2 tänder vid fullvarv
  }
     //______________________________________________________________________________________________________   
        tand  ++ ;                              // räkna upp ett steg för varje ny puls, kommer via pulseIn()funkt.
        priv = puls;                            // lägger in den förra pulstiden i värdet "priv" (uS)
       
        //Serial.println(priv);
       if (mduration >1800)                     // när motorn går på allra lägsta varv (start)
       {
        fasttid = tid1;                         // används tid1 (4000 uS i grundinställning)
       }
      if ((mduration > 1200)|| (mduration < 1800))
       {
        fasttid = tid2;
       }
       if ((mduration > 500)||(mduration < 1200)) // Om motorn går under 1100 RPM
        {
         fasttid = tid3;                        // används tid2 (1200 uS i grundinställning)
        }
       if (mduration <500)                      // Om motorn går över 1100 RPM
        {
          fasttid = tid4;                       // används tid3 (300 uS i grundinställning)
        }
        
        puls = pulseIn(vevpin, LOW, 30000);   // Ett färdigt kommando som väntar in nästa puls (tand = case).
                                              // vid stillastående motor blir det en timeout 
                                              // efter 0,03 Sek 
   //ex 1  if 12000 > 3000 + 2500    blir 12000 > 5500   sant 
   // ex 2 if 12000 > 3000 + 8000 blir 12000 >  11000  sant               
      if  (puls > priv + fasttid)             // jämför om ny pulstid i uS är större än föregående + tid1 eller tid2.
       {
        digitalWrite (pulsutpin, HIGH);       // utpin blir hög när pulsluckan återgår till pulser
         
    tand = 0;         // resetar 0 till 28 räknaren som bara har hunnit räkna mellan 17, upp till 27 tänder

    pekare ++;                                //  och räknar upp spridarpinpekräknare

    if (pekare > 3)                           // när fjärde pinnen är nådd börjar den om igen
    {
      pekare = 0;                             // spridarpinne 1 är igång igen (1 = D11)
    }         // Denna if-sats är bara sann varje halv-varv vid luckan
  }
                                  
                                  
  if (pekare == 0)                           // om spridarpekaren pekar på 0
  {
    spridardiff = sprdiff4;                  // skall det individuella värdet för spridare 4 hämtas
  }

  if (pekare == 1)                           // om spridarpekaren pekar på 1
  {
    spridardiff = sprdiff2;                  // skall det individuella värdet för spridare 2 hämtas
  }

  if (pekare == 2)                           // om osv... upp till 3 (fjärde spridaren)
  {
    spridardiff = sprdiff1;
  }

  if (pekare == 3)
  {
    spridardiff = sprdiff3;
  }



   // ex 1: 3000 < 12000 - 2500 blir    3000 <  9500   sant 
   // ex 2: 3000 < 12000 - 8000 blir     3000 < 4000    sant     
       if  (puls < priv - fasttid)            // jämför on ny pulstid är mindre än förgående - fasttid.     
         {   
         digitalWrite (pulsutpin, LOW);       // utpin blir låg igen nästa uppgång i pulståget.
   
         } 
 }        
        
                                              // end void loop()
Jag tror själv felet sitter allra längst ner i denna sketch "if (puls < priv -fasttid) digitalwrite = LOW." Där går det snett, den förblir hög i kanske 3-5 pulser för mycket innan den blir låg, den skall bli låg direkt efter att luckan är över och första tanden kommer. Jag funderar på att göra om "puls", "priv" från long till unsigned long, då kan det aldrig bli minustal vilket jag misstänker nu? Jag gjorde ett par räkneexempel här inne i koden men det ser faktiskt riktigt ut... Jag kan bara konstatera att det är här det går snett!!
Annars förstår jag nog inte riktigt vad du menar. Skulle du mrfenzy kunna gen en fördjupad förklaring?, dessutom till rätt kod!
Motorn går alltid ett halvt till två varv innan den börjar spruta in bränsle. Problemet uppstår precis när den skall till att starta, det blir en ordentlig skjuss precis när den tänder och det är då sista delen av koden gör fel, den går inte ur "if (puls > priv + fasttid) " och kommer således aldrig till "if (puls < priv - fasttid)" ...
edit: glömde ett ord: ner.
Senast redigerad av Janson1 19 september 2018, 06:58:02, redigerad totalt 1 gång.
Janson1
Inlägg: 1338
Blev medlem: 1 december 2016, 09:06:02
Ort: Marks Kommun

Re: ECU- styrning till en VW pumpdysediesel.

Inlägg av Janson1 »

svanted: Nu har jag lagt ut rätt sketch, men annars stämmer ditt resonemang. Egentligen är det bara två tidsluckor som jag håller reda på åt gången. Dom här 9 tidsluckorna är bara för att räkna ut är-varv och stör nog inte nåt annat. Jag känner jag har en flyktig idé om hur detta kan lösas, måste fånga den bara, eller få hjälp...
Användarvisningsbild
mrfrenzy
Co Admin
Inlägg: 14818
Blev medlem: 16 april 2006, 17:04:10

Re: ECU- styrning till en VW pumpdysediesel.

Inlägg av mrfrenzy »

Felet är att du har vissa moment i loopen när inte pulserna från givaren övervakas. Så fort du gör beräkningar, analog read eller liknande och förflyttning sker fortare än du förutsett går det snett.

Detta beror på att du använder pulseIn som är en blockerande funktion. När den kör kan du inte göra nåt annat och därför kan den inte köras hela tiden.

Rätt metod är att använda ett interrupt, antingen ett timerinterrupt eller attachinterrupt.

Alternativ 1: Timerinterrupt
Du har en timer som snurrar i bakgrunden med hög noggrannhet
Din vanliga kod kör på som vanligt med beräkningar och states och events.
En gång per tidsenhet (exempelvis X µS) pausas din mainloop automatiskt och interruptet körs
I interruptkoden så kollas om ingången är hög eller låg.
Lite pseudokod:

Kod: Markera allt

if (vevaxelpuls == low) //Vi befinner oss mellan två tänder, räkna upp räknaren
{
  counter++;
  break;
} else //Vi befinner oss vid en tand, kolla om detta är första gången eller om vi var här vid förra interruptet
{
  if (counter > 0) //Detta är första interruptet vid tanden
  {
    state++;
    if (state == 26 || state == 58) //Vi är vid dubbelluckan så halvera tiden)
    {
      currentrpm = counter / (interrupttime * 2);
      break;
    }
    else // Vi befinner oss vid en enkeltand
    {
      currentrpm = counter / interrupttime;
      break;
    }
  } else //vi är kvar vid samma tand som förra gången
  {
    counter = 0;
    break;
  }
}
Är den låg så räknas ett värde upp med 1 och interruptet avslutas - din vanliga kod fortsätter
Är den hög och räknaren inte är 0 så används räknaren för att kalkylera hastigheten och spara i en variabel för hastighet, sedan nollas räknaren och interruptet avslutas - din vanliga kod fortsätter

På detta sättet har du alltid i din mainloop tillgång till ett pålitligt värde på state och currentrpm och du behöver aldrig hålla på och ändra räknesätt eller slösa tid på att sitta och vänta på en tand.
Se exempel 1 här: https://www.instructables.com/id/Arduin ... nterrupts/

Alternativ 2 har jag ingen pseudokod för men det fungerar omvänt. Istället för att det körs med bestämt tidsintervall så körs det varje gång ingången ändras från låg till hög. Sedan kollar man i interruptet hur lång tid som förflutit sedan förra gången. https://www.arduino.cc/reference/en/lan ... interrupt/

Samma sak gäller dina analogreads. Du startar en läsning i bakgrunden och fortsätter med din kod. Sedan när läsningen är klar triggas ett interrupt som hämtar värdet och sparar i lämplig variabel http://www.glennsweeney.com/tutorials/i ... atmega328p
Användarvisningsbild
Bosen
Inlägg: 1753
Blev medlem: 18 juli 2005, 10:56:31
Ort: Karl Gustav, Varberg
Kontakt:

Re: ECU- styrning till en VW pumpdysediesel.

Inlägg av Bosen »

Om man kör alternativ 2 och kollar pulserna via interrupt så är nog interrupt på analogRead överflödig.
Janson1
Inlägg: 1338
Blev medlem: 1 december 2016, 09:06:02
Ort: Marks Kommun

Re: ECU- styrning till en VW pumpdysediesel.

Inlägg av Janson1 »

Den här pulsIn() har inga som helst problem med att hänga med på låga varv, jag har stresskört och runt 6000-6500 RPM börjar den krokna. I dag kör jag ju alla analogread på slutet efter det att insprutningen är klar och det inte har någon betydelse om en eller flera tänder missas då det blir en långlucka förr eller senare som resetar tandräknaren. Jag får ta mig en funderare om fortsättningen då jag tror jag inte riktigt fattar, än i alla fall...
Användarvisningsbild
mrfrenzy
Co Admin
Inlägg: 14818
Blev medlem: 16 april 2006, 17:04:10

Re: ECU- styrning till en VW pumpdysediesel.

Inlägg av mrfrenzy »

det blir en långlucka förr eller senare
Problemet är att vid ostabilt varvtal exempelvis start, misständning osv är det omöjligt att avgöra vad som är lång respektive kort lucka.

Med "min" metod så spelar varvtalets fluktuationer ingen roll då du alltid räknar alla tänder.

Hela programflödet blir mycket enklare att hantera när man sköter räkningen separat och kontinuerligt.
svanted
Inlägg: 5082
Blev medlem: 30 augusti 2010, 21:20:38
Ort: Umeå

Re: ECU- styrning till en VW pumpdysediesel.

Inlägg av svanted »

Problemet är att vid ostabilt varvtal exempelvis start, misständning osv är det omöjligt att avgöra vad som är lång respektive kort lucka.
jag tror det,
om man alltid jämför två intilliggande luckor så hinner inte varvtalet variera så mycket att en kort blir 5 - 6 ggr längre.
siffrorna ovan
11310, 1804
för lång resp kort
det är mer än 6 ggr?
vilket är konstigt, det borde inte vara mer än 5 men det kan ha att göra med att koden för mätning tar lite tid från båda värdena vilket ökar differensen.
största skillnaden mellan två intilliggande korta är under 10%.
man kan tycka att "luckdetektorn" alltid ska vara aktiv, för om den av någon anledning tappar en lucka? hur det skulle kunna hända, kan man diskutera, glapp i elsystemet kanske?
går motorn skit då allt flyttas 6°,
tills man startar om den.
Användarvisningsbild
mrfrenzy
Co Admin
Inlägg: 14818
Blev medlem: 16 april 2006, 17:04:10

Re: ECU- styrning till en VW pumpdysediesel.

Inlägg av mrfrenzy »

Min pseudokod är bara en startpunkt för att visa hur det funkar. Den behöver kompletteras med två saker:

Initieringsrutin:
Vid första tändning på är alltid sync = false
Så länge sync = false aktiveras inte spridarna, och istället för interruptet ovan körs en specialfunktion som räknar långa och korta luckor samt jämför med kamaxelgivaren.
När startpositionen hittats sätts sync = true. Då börjar "drftinterruptet" köra och spridarna aktiveras.

Korrigeringsrutin:
Om RPM ändras mer än 80% mellan två taggar så sätts sync = false och state = 0.
Spridarna stängs då av ett halvvarv tills det hela har synkroniserats igen.
Samtidigt loggas en felkod.

Överkurs för hög driftsäkerhet: fortsätt köra på endast kamaxelgivare.
Janson1
Inlägg: 1338
Blev medlem: 1 december 2016, 09:06:02
Ort: Marks Kommun

Re: ECU- styrning till en VW pumpdysediesel.

Inlägg av Janson1 »

Det ända jag kan svara på exakt är att luckan är 5 gånger längre än en vanlig liten lucka mellan två tänder. Resten behöver jag nog klura på ett tag för att fatta... Så: Pass så länge.
Janson1
Inlägg: 1338
Blev medlem: 1 december 2016, 09:06:02
Ort: Marks Kommun

Re: ECU- styrning till en VW pumpdysediesel.

Inlägg av Janson1 »

Jag kollade lite nu och gjorde en del räkneexempel och får ibland minustal på long nästan längst ner i sketchen

Kod: Markera allt

  // if (10000 > 2000 + 2500 ) blir 10000 > 4500 SANT
     // if (2000 > 10000 + 2500)  blir  2000 > 12500 FALSKT              
      if  (puls > priv + fasttid)             // jämför om ny pulstid i uS är större än föregående + tid1 eller tid2.
       {
        digitalWrite (pulsutpin, HIGH);       // utpin blir hög när pulsluckan återgår till pulser 

Kod: Markera allt

// if (10000 < 2000 - 2500 ) blir 10000 < -500 FALSKT <<<<<<-------KOLLA
     // if (2000 < 10000 - 2500)  blir  2000 < 7500 SANT  
       if  (puls < priv - fasttid)            // jämför on ny pulstid är mindre än förgående - fasttid.     
         {   
         digitalWrite (pulsutpin, LOW);       // utpin blir låg igen nästa uppgång i pulståget.
         }  
Kan det störa detekteringen?
Janson1
Inlägg: 1338
Blev medlem: 1 december 2016, 09:06:02
Ort: Marks Kommun

Re: ECU- styrning till en VW pumpdysediesel.

Inlägg av Janson1 »

Jag ser antydan till inbyggda tankevurpor i våra tankesätt,(i alla fall i mitt), jag är väldigt inkörd i "mitt" tankesätt att tänka och lösa ett problem på. Jag har ju labbat fram denna kod under i princip ett och ett halvt år med mycket trail&error tills det till slut funkar i alla lägen, så kommer det ett nytt läge, ett dubbelmassahjul som ställer till det och i min värld så vill jag ju hitta en förbättring bara på ett specifikt ställe (jag TROR jag vet vilket?). När jag ber om hjälp så får jag verkligen hjälp men samtidigt så blir ju hjälpen efter er andras sätt att tänka och programmera, ibland inte ens i samma språk. Det är nog lika svårt för er att sätta er in i min kod som för mig att sätta mig in i eran kod. Så därför kan jag inte tillgodose mig av ett helt nytt sätt att se på problemet och ett helt annat sätt att programmera på. Jag ser ju att ni andra har kommit milsvidd längre i eran programmering än vad jag gjort samtidigt som jag ser mer motorns funktion fel och brister, jag är nog en mekanik-människa först och främst. Så med andra ord, fortsätt och hjälp mig men ge mig inte för svåra grejer med för mycket nytänk. Jag tror inte jag kan ta till mig det mer än med lång tids labbande för att själv få förståelsen...
Obs: Nu skall detta inte tas som något slags påhopp, jag bara inte förstår alla gånger.
mrfrenzy: Jag har kollat in ditt alster och jag tror jag förstår lite men att bara inplantera detta går nog inte sådär direkt, det kräver kanske ett helt nytt program.
Användarvisningsbild
mrfrenzy
Co Admin
Inlägg: 14818
Blev medlem: 16 april 2006, 17:04:10

Re: ECU- styrning till en VW pumpdysediesel.

Inlägg av mrfrenzy »

Janson: Jag försöker absolut inte klanka ner på ditt sätt att programmera vilket jag är glad att du ser. Det är mycket imponerande att du kommit så långt och att motorn fungerar såpass bra som den gör.

Eftersom du inte använder interrupt och timers så utnyttjar du bara en tiondel av processorns kapacitet, särskilt eftersom du utför en uppgift som skulle haft mycket stor nytta av detta.
Det sätt som du programmerat på nu är enda sättet att lösa det på om man hade haft en jättegammal processor som saknar interrupt. Om processorn är tillräckligt snabb och programmeraren har tillräckligt tålamod så går det att lösa på det sättet men det blir mycket krångligare.
Förutsatt att din processor är tillräckligt snabb så kanske det går med hjälp av tipsen som svanted gav, isåfall skulle man nog börja med att koppla upp ett oscilloskop och logga detta parallellt med utskriften av tidmätningen som processorn gör. Då finns det en chans att analysera vad som går fel och skriva en workaround. Detta känns för mig som "att gå över ån efter vatten" varför jag hellre skulle gjort om det hela med interrupt.

Jag tror inte att hela programmet behöver skrivas om, även om det i slutändan skulle bli effektivare efter det. Förmodligen räcker det med att göra om pulsmätningen och synkningen så fungerar det som tidigare men stabilare, sedan kan man förenkla efterhand.

För att komma igång när du läst lite så är det nog bäst att bygga några enkla exempel "blinka en led", "cykeldator" osv. (cykeldatorexemplet körs lämpligen med din vevaxelgivare som input)
Sen är jag övertygad över att du kommer klara att implementera det med motorn.
Här är en video som förklarar koncepten väldigt bra med liknelser mot verkliga livet:
Användarvisningsbild
Bosen
Inlägg: 1753
Blev medlem: 18 juli 2005, 10:56:31
Ort: Karl Gustav, Varberg
Kontakt:

Re: ECU- styrning till en VW pumpdysediesel.

Inlägg av Bosen »

Jag har satt ihop ett litet exempel som jag tror borde funka. Jag måste påpeka att även jag är nybörjare på arduino så kodningen är säkert inte så snygg. Jag vet också att man skall försöka hålla ner koden i interrupten så mycket som det går, och det kanske jag inte har gjort här, men jag tror inte det ska vara någon fara eftersom det är såpass lång tid mellan varje puls.

Kod: Markera allt

const int vevpin = 3;

int  tand = 0;  //Samma variabel som din egen. Räknar vilken tand du är på. startar vid en lång tandlucka
long VEVTAND_langd = 0;  //Längden på luckan mellan tänderna
long VEVTAND_start = 0;  //Starttiden för mätning mellan tänder
long VEVTAND_1 = 0;  //används för att skapa en "referenstid" att jämföra tänder med
long VEVTAND_2 = 0;  //används för att skapa en "referenstid" att jämföra tänder med
long VEVTAND_referens = 0;  //referenstid skapad av de 2 föregående variablerna
bool luckan_hittad = false;  //sätts till true när luckan är hittad. sätts aldrig till false igen i detta exemplet, men kanske man behöver göra.

int RPM = 0;  //Motorns varvtal
long RPM_time; //En variabel för att mäta tiden för ett halvt varv.

void setup(){
  pinMode(vevpin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(vevpin), VEV_pulse, RISING);
}

void loop(){
  
  //Här hamnar din egen kod

}


//Varje gång det blir en puls på vevpin så hamnar man här
void VEV_pulse(){
  VEVTAND_langd = micros()-VEVTAND_start; //Längden på nuvarande lucka hamnar i variabeln VEVTAND_langd
  VEVTAND_start = micros();  //Börja mätning av lucka
  
  tand++;
  
  if( tand = 2 ){
    VEVTAND_1 = VEVTAND_langd; //lagrar en lucklängd för bas till referenslucka
  } else if( tand = 3 ){
    VEVTAND_2 = VEVTAND_langd; //lagrar en lucklängd till för bas till referenslucka
    if( VEVTAND_1 >  VEVTAND_2 * 3 or VEVTAND_2 > VEVTAND_1 * 2 ){
      tand=0; //Är skillnaden för stor mellan VEVTAND_1 och VEVTAND_2 så börjar vi om på noll
              //Detta kan ju bero på ett fel i läsningen eller att man påträffar luckan redan i de första pulserna
    } else {
      VEVTAND_referens = VEVTAND_1 + VEVTAND_2 / 2;  //Skapar en referenstand av VEVTAND_1 och VEVTAND_2
    }  
  } else {
    if( VEVTAND_langd > VEVTAND_referens * 4){ //om luckan är mer än 3 gånger större än referenstanden så kan vi anta att vi har hittat luckan
      luckan_hittad = true; //sätt flagga att luckan är hittad
      tand = 1;  //Börja att räkna tänder igen. första tanden är redan hittad så vi börjar på 1
      RPM_time = millis();
      RPM = 60000 / (millis() - RPM_time * 2); //Hoppas jag har räknat rätt här 60000 delat med millis per varv borde bli RPM
    }
  }    
}
koden ger dig följande variabler:
tandluckan_hittad = sätts till TRUE när luckan är hittad
tand = räknar varje tand efter tandlucka, nollställs vid nästa tandlucka
RPM = varvtalet, baserat på två pulser per varv (jag har uppfattat det som att det är 2 tandluckor per varv. Har jag missuppfattat?)

Koden börjar med att mäta två tänder efter varandra och använder dessa två som referens för att hitta den "långa luckan".
När luckan är hittad så sätts luckan_hittad till true och räknaren nollställs. Två nya tänder används som referens och räknaren räknar till nästa "långa lucka" där den nollställs igen.

EDIT:
Om man nu vill fortsätta med denna koden så undrar jag lite hur kamaxelgivaren ser ut? hur många pulser per varv?
Användarvisningsbild
Bosen
Inlägg: 1753
Blev medlem: 18 juli 2005, 10:56:31
Ort: Karl Gustav, Varberg
Kontakt:

Re: ECU- styrning till en VW pumpdysediesel.

Inlägg av Bosen »

På sidan https://www.slideshare.net/shark79/19-v ... pumpe-duse så hittade jag denna infon om pulserna från kamaxeln och satte ihop ett exempel på interrupt där med:
G40.png

Kod: Markera allt

const int kampin = 2;
const int cylinderArray[]={2,1,1,3,3,4,4};
long CAM_pulses[5];
long CAM_pulse;
long CAM_pulse_time;
int  CAM_pulse_count;
int  secondCylinder = 0;
int  current_cylinder;

void setup() {
  pinMode(kampin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(kampin), camshaft_pulse, RISING);

}

void loop() {
  
  //Här hamnar din egen kod

}

//Varje gång det blir en puls på kampin så hamnar man här
void camshaft_pulse(){
  CAM_pulse=millis()-CAM_pulse_time; //Tid sedan förra pulsen
  CAM_pulse_time=millis();  //starta tidmätning
  CAM_pulse_count++;  //öka på räknaren

  if(CAM_pulse_count >= 2 and CAM_pulse_count <= 7){  // Mät längden mellan 5 pulser. Den pulsen som är längst är cylinder 2
    CAM_pulses[CAM_pulse_count-2];   //Lägg till de 5 pulserna i en array
  }

  if(CAM_pulse_count==7){  // När man har mätt den 5:e pulsen så hamnar man här.
    for (int i=0; i <= 5; i++){
      if(CAM_pulses[i] > CAM_pulses[secondCylinder]){  //Kolla om pulslängden vi mäter är längre än den längsta som är mätt
        secondCylinder=CAM_pulses[i];  //Om pulslängden är längre så tror vi nu att detta är cylinder 2
      }
    }
    //Vi har nu hittat cylinder 2, vilket är den längsta tiden. Efter Cylinder 2 så är varannan puls en ny cylinder tills vi stöter på cylinder 2 igen.
    //Vi väljer nu att CAM_pulse_count skall vara 10 på cylinder 2. Om cylinder 2 är på secondCylinder[0] så måste lägga på 5 pulser till 
    //CAM_pulse_count=14 för att få CAM_pulse_count=10 som cylinder 2 t.ex.
    CAM_pulse_count = 15 - secondCylinder;
  }   

  if(CAM_pulse_count >=10){
    current_cylinder=cylinderArray[CAM_pulse_count-10]; //Sätt currentCylinder till den cylindern det är just nu.
    if(CAM_pulse_count==17){
      CAM_pulse_count=9;  //Om vi har kommit upp till 17 pulser så börjar vi om och sätter cylinder 2 vid 10 igen.           
    }
  }
}    
  

Jag får det till att om man mäter tiden mellan 6 pulser (5 tider) så är den längsta tiden cylinder 2.
Efter att man har hittat cylinder 2 så slutar man helt enkelt kontrollera om det är rätt cylinder. Givetvis är detta dumt, så man borde väl kontrollera då och då att man verkligen är på den längsta pulstiden, alltså cylinder 2. Men det ger iallafall en hint om hur jag hade gjort...
variabeln du får ut av denna koden är current_cylinder som sätts till den cylindern den är på just nu.

koden är inte testad på något sätt, så jag kan absolut ha gjort någon form av beräkningsfel.
Du har inte behörighet att öppna de filer som bifogats till detta inlägg.
Skriv svar