Centralina accensione elettronica CDI con Arduino - problema interrupt

Salve, stò provando a realizzare un prototipo di centralina di accensione programmabile per un motore 100cc. stò lavorando sul codice da dieci giorni senza riuscire a raggiungere un risultato discreto.i dati a contorno del progetto sono:

-motore 102cc;
-RPM 8000 max (percui ammissibile il lavoro di computazione nell’ordine dei millisecondi);
-sensore hall che legge un solo magnete sul volano (PIN2 con lettura interrupt) posizionato a 180° rispetto al punto morto superiore ;
-uscita di Arduino che controlla un SCR (pin 7);
-curve di anticipo a 5 zone (da0 a 200RPM, da 200 a 1400, da 1400 a 4000, da 4000 a 7000, oltre i 7000);
-ogni zona è identificata da una formula che identifica la retta che collega i due punti secondo la formula matematica della retta y=mx+q ;

l’ultima versione di codice è quello in allegato (ne ho fatte almeno 400 versioni!!);

il problema è l’Interrupt, ha cercato di relnderlo snello con sole 3 linee come suggerito dalla guida, ma poi mi creava problemi quando ritornava nel LOOP in un punto imprecisato.

adesso l’interrupt è praticamente tutto il programma, legge benissimo, è velocissimo, ma non potendo utilizzare il delay (non funziona nemmeno il delayMicroseconds a differenza di quello che c’è scritto sulla guida) non esegue il tempo di ritardo che in sostanza è lo scopo del progetto.
Qualcuno sà indirizzarmi per favore?

Grazie

test_CDI_funzionante_ma_senza_ritardo.ino (8.64 KB)

Le ISR DEVONO essere le più brevi possibili e su questo non ci piove per cui ... il tuo programma è da rifare come si deve e la ISR DEVE contenere poche righe.

Nella ISR la cosa più semplice è semplicemente, se occorre incrementare variabili e settare flag, flag che vanno poi controllate nel flusso del loop().

Guglielmo

Ciao Guglielmo,
grazie della risposta. come dicevo, ero a conoscenza della regola di ridurre all’essenziale la funzione ISR, ed ho provato in tutti i modi a metterla in pratica, allego la versioe a soli 3 comandi. Purtroppo però, considerati i tempi in gioco (millisecondi disposizione per leggere il sensore,computare ed agire) non funziona.
il problema principale è che quando l’ISR ritorna nel loop lo fà in posizioni del LOOP non prevedibili (comando successivo a l’ultimo eseguito prima dell’interruzione)pertanto il programma funziona per un pò ma poi si impalla.

devo o trovare un modo per reindirizzare il rientro dell ISR all’inizio del loop oppure non sò come fare.

per dovere di informazione, mi sono accorto che non ho inserito la piattaforma che uso che per ragioni di spazio è un arduino nano.

grazie a chiunque voglia indirizzarmi.

CDI_ISR_minimal_v382.ino (8.6 KB)

T'ho detto, devi alzare una flag nella ISR e verificare lo stato della flag nel loop() (cosa che può essere fatta anche in più punti del loop()).

Guglielmo

Presi per buoni i calcoli fatti personalmente non utilizzerei la funzione delay(), semplicemente calcolerei il tempo trascorso nell'ISR salvando in una variabile globale anche il tempo letto, poi nel loop semplicemente calcolerei in base alla velocità angolare il momento in cui deve scoccare la scintilla e confrontando questo valore con millis() saprai quando devi cambiare stato al pin d'uscita.
Praticamente:
in ISR:

  • salvi millis()
  • calcoli gli RPM
  • setti un flag per dire che hai letto un nuovo valore

in loop:

  • controlli se il flag è settato, in caso lo sia calcoli il tempo che deve trascorrere prima dello scocco della scintilla tenendo conto degli RPM, delle curve e di ciò che serve
  • confronti la somma del valore salvato di millis() in ISR con il tempo che devi attendere a millis() e se superiore fai scoccare la scintilla e resetti il flag

Credo sia tutto, un ulteriore consiglio che ti posso dare è quello di scrivere poco sulla seriale e meglio se aumenti il BAUD così sprechi meno tempo, che in uno sketch così è molto prezioso...

Magari potresti provare ad usare un sistema realtime, FreeRTOS lo puoi usare anche all'interno dell'IDE di arduino :wink:

nella tua fuzione

void pulse() {                        //funzione pulse richiamata dall'interrupt
               
            pulses++;                   //aumenta la variabile pulse di 1                                                
            last_pulsems = now_pulsems;
            now_pulsems = millis();     //associa a last_pulse il tempo in cui è avvenuto
            loop();                         
            }

Non so se è vero ma penso che utilizzare una variabile bool invece di int per pulses sia più rapido.
In questo modo il tuo loop sarà cosi':

void loop() {

  if (pulses) {                          //se pulses è diverso da 0 non è il primo giro di manovella ed è appena avvenuto uno scoppio si attende il prossimo segnale di hall
    pulses = false;                                             //rimette pulses a 0 per evitare che il loop acceda alla routine revolution          
    revolution();                           //richiama la routine revolution
  }
}

Per la funzione revolution usa dei else if
Puoi settare la velocità del seriale a 115200 anche se a regimi elevati sarà comunque un collo di bottiglia.
Metti digitalWrite(IGBT_PIN, LOW); prima di tutti quei Serial.print (meglio toglierli!), questa può essere una delle cause dei tuoi problemi.

P.S. questo post mi appassiona!! Scusa dinodf se ho ripetuto certe cose che hai detto ma abbiamo scritto quasi allo stesso momento. :slight_smile:

grazie dinodf, grazie savoriano per le risposte,
in risposta a dinodf:
ho provato anche a fare come mi suggerisci usando un while e confrontando ciclicamente il millis() con( il tempo registrato allo scoppio + il ritardo calcolato in base alla velocità di rotazione) ma è risultato piu preciso il delay (i serial.print che ho inserito sono esclusivamente di servizio e ci ho messo dentro i vari tempi,RPM, ritardi e tempi effettivi per riuscire a valutare il funzionamento poichè è l'unico modo che ho per controllare che tutto vada bene. ho anche provato ad escludere tutti i serial print e affidarmi solo su un led che ho collegato a quella che dovrebbe essere l'uscita (PIN 7).
per savoriano:
proverò questa mttina ad applicare i tuoi consigli.
cmq pulses l'avevo messa bool, in una versione primordiale, solo che poi mi serviva che facesse anche un, altra cosa: distinguere il primo impulso dai seguenti (perchè al primo giro di manovella non deve ritardare nulla poichè non può conoscere la velocità di rotazione) percui uso i valori 0, 1 e >1 per pulses rispettivamente per primo impulso, default dopo il primo impulso e nuovo impulso avvenuto.
il problema reale è che l'interrupt deve essere breve, come ha piu volte ripetuto gpb01, perrtanto il loop contiene tutto il resto dei comandi. Purtroppo però quando l'interrupt rientra nel loop dopo aver fatto quello che deve fare è imprevedibile sapere da quale riga del loop riparte.
Purtroppo a quella velocità non posso nè permettermi di mettere un controllo di stato per ogni riga di comando del loop ne di accettare la casualità del rientro. si tratta di una questione di "emergenza" dove un ritardo o un errore può rappresentare una catastrofe nella rotazione di un ipotetico motore che gira e deve essere trattato come suggeriva gpb01 in un altro thread : https://forum.arduino.cc/index.php?topic=408127.15 all'intervento n#17.
...almeno chè non esista un'altro modo.....

Purtroppo però quando l'interrupt rientra nel loop dopo aver fatto quello che deve fare è imprevedibile sapere da quale riga del loop riparte.

Facendo i calcoli a 8000 hai un impulso ogni 7ms. Secondo me tutta la procedura deve essere fatta nel limite di questo tempo in modo tale che sei sicuro che alla fine dell'interrupt riprenda dal loop in attesa del pulses.
Comunque mettendo digitalWrite(IGBT_PIN, LOW); prima dei serial.print puoi vedere a vari regimi quello che ti riesce a stampare, in modo tale da capire a partire da quale regime cominciano i problemi.
Hai provato a vedere quanto ci vuole al tuo codice di fare tutta la procedura di accensione?
Dato che oggi non ho niente da fare, faro delle prove.

ho scaricato il tuo ".ino"

la prima cosa che ho notato è che richiami la loop() da dentro la ISR

mi spiace dire che è sbagliato e cha indica che non hai capito come funziona una ISR

essa ritorna quando ha finito, automaticamente, alla funzione "durante" (e non "dalla") quale è stata richiamata

che non è sempre la loop, e nemmeno sempre l'inizio

togli quella "cosa" e ricomincia

in particolare:

  • ripensa se ti servono realmente delle variabili float
  • indenta bene quel codice
  • metti dei commenti esplicativi e non descrittivi, piottosto non metterli del tutto

inoltre il tuo programma non è ottimizzato per la velocità

e trasmetti troppa roba sulla seriale , io ho fatto un conto della serva che ti vanno via dai 40 agli 80 millisecondi per la trasmissione
tra i 25 e i 50 giri al secondo, non superi i 3000 RPM, e tutto il tempo di Arduino è impegnato a trasmettere, non fa nulla di utile

temo che non sei sulla strada giusta

ti metto qui il “.ino” commentato

#define IGBT_PIN 7    //definisce la variabile IGBT e la uguaglia a 7
// non è una variabile, forse serve di studiare ancora un po il C
#define HALL_PIN  2  
#define z2 2.85     //valore utile per la curva della zona2
#define z4 1.33     //valore utile per la curva della zona4
#define q4 28.3     //valore utile per la curva della zona4
// vaolri utili come? se non lo scrivi è inutile commentare

volatile unsigned long last_pulsems = 0;       //definisce la variabile last_pulse e la uguaglia a 0
volatile unsigned long now_pulsems = 0;        //definisce la variabile last_pulse e la uguaglia a 0
// uguagliarla a 0 è inutile, e comunque i nomi sono sbagliati, questi commenti sono inutili e fuorvianti
volatile int pulses = 0;                       //definisce la variabile di servizio pulses = 0


int delay_ = 0;                       //definisce la variabile che identifica il tempo di ritardo da attendere
int curva = 0;                        //definisce la variabile di servizio per identificare la zona della curva in cui ci si trova a seconda degli RPM
// qui basta un byte, meno spazio e più veloce da gestire

float RPM;                              //definisce la variabile RPM
float t_degree = 0;
// invece questa a cosa serve? 


float rotation_time;                  //definisce la variabile di servizio utile per il calcolo del tempo di rotazione a seconda degli RPM
float time_degree;                    //definisce la variabile di servizio utile per il calcolo del tempo di rotazione di un grado di rotazione



void pulse()                          //funzione pulse richiamata dall'interrupt
{
   pulses++;                   //aumenta la variabile pulse di 1
   last_pulsems = now_pulsems;
   now_pulsems = millis();     //associa a last_pulse il tempo in cui è avvenuto
//   loop();
// richiamare la loop da dentro una ISR è una cavolata

// millis è tipo intero, perché usare variabili float, che sono lente e imprecise?

}

void setup()
{
   Serial.begin(9600); Serial.println("Serial started");
   pinMode(IGBT_PIN, OUTPUT);                                       // inizializza il pin HALL_PIN (7) come output (pin al quale è connesso il trigger della bobina)
   pinMode(HALL_PIN, INPUT);                                        // inizializza il pin HALL_PIN (2) come input (pin al quale è connesso il sensore di hall)
   attachInterrupt(digitalPinToInterrupt(2), pulse, FALLING);       //inserisce interrupt che porta alla //routine pulse ogniqualvolta il Pin 2 (sensore HALL)  passa da HIGH a LOW
// finalmente qualche commento utile, anche se prolisso e in ritardo
// tanto già il nome IGBT_PIN ci aveva fatto capire a cosa serviva

}

void loop()
{
   if (pulses > 1)                            //se pulses è diverso da 0 non è il primo giro di manovella ed è appena avvenuto uno scoppio si attende il prossimo segnale di hall
// e se pulses fosse 1? ignora il primo giro?
// questo test vale solo dal secondo giro in poi

   {
      revolution();                           //richiama la routine revolution
   }

}

void revolution()
{
   rotation_time = (now_pulsems - last_pulsems);           //conta il tempo (periodo) di rotazione eseguendo una sottrazione fra il tempo del penultimo e dell'ultimo impulso letto
   // ennesimo commento lungo e non importante
   RPM = (60000 / rotation_time);                          //conteggia gli RPM
   // variabili float per divisioni intere? 
   time_degree = rotation_time / 360;                      //conteggia il periodo di rotazione di 1 grado, utile nelle formule dell'anticipo (ritardo da applicare dall'ultim lettura)
   // facciamo ipotesi di un regime di 3000 rpm
   // sono 20ms a giro
   // 20/360 fa? occhio che stai facendo divisioni intere
   
   pulses = 1;                                             //rimette pulses a 0 per evitare che il loop acceda alla routine revolution senza aver vuto impulsi dal sensore hall
   t_degree = time_degree;
// a cosa serve t_degree?
// a parte perdere il tempo per scriverla? non la usi da nessuna parte...
   if (RPM >= 7000)                                    //se il numero di giri è superiore a 7000, applica la curva di ritardo prevista dalla ZONA5
   {
      delay_ = (161 * time_degree);
      // l'unica formula che serviva commentare è rimasta muta
      curva = 5;
      spark();
   }
// qui ci stava bene un return, la scintilla c'é stata, inutile passare a testare casi che non saranno certamente veri
   if ((RPM >= 4000) && (RPM < 7000))                  //se il numero di giri è compreso fra 4000 e 7000, applica la curva di ritardo prevista dalla ZONA4
// che mettendo dei return prima, evitavi di fare il test <7000, caso sicuramente sicuramente escluso dal return stesso
{
      delay_ = (180 - (((RPM / 1000) * z4) + q4)) * time_degree;
      curva = 4;
      spark();
   }

   if ((RPM >= 1400) && (RPM < 4000))                  //se il numero di giri è compreso fra 1400 e 4000, applica la curva di ritardo prevista dalla ZONA3
   {
    // ibidem
      delay_ = (157 * time_degree);
      curva = 3;
      spark();
   }

   if ((RPM >= 200) && (RPM < 1400))                   //se il numero di giri è compreso fra 200 e 1400, applica la curva di ritardo prevista dalla ZONA2
   {
    // ibidem
      delay_ = (180 - (((RPM / 1000) * z2) + 19)) * time_degree;
      curva = 2;
      spark();
   }

   if (RPM < 200)                        //se il numero di giri è compreso fra 100 e 200, applica la curva di ritardo prevista dalla ZONA1
   {
    // ibidem
      delay_ = (160 * time_degree);
      curva = 1;
      spark();
   }
}

void spark()                                      //funzione di accensione a seconda del ritardo calcolato
{
   unsigned long delay_time = 0;                     //definisce la variabile che identifica il tempo di ritardo da attendere
   unsigned long time_after_calc = 0;                //definisce la variabile di servizio per valutare il tempo in cui il uP finisce i calcoli
   unsigned long spark_time = 0;                     //definisce la variabile di servizio per valutare il tempo di scoppio
   int delay_effective = 0;                          //definisce la variabile di servizio per valutare il ritardo applicato effettivamente

   if (RPM > 100)
   {
      delay_time = (now_pulsems + delay_);              //calcolo del tempo in cui deve scoccare la scintilla
      time_after_calc = millis();                       //calcolo del tempo in cui sono finiti i calcoli per la valutazione del ritardo
      delay(delay_time - time_after_calc);              //tempo di attesa ricavato dal tempo di scoppio previsto-tempo attuale
      // questi conti non li capisco
      // tempo ultimo sensore hall + tempo calcolato è il tempo della prossima scintilla, ok
      // ma perché usare una variabile uguale a millis(), usa millis() direttamente
      digitalWrite(IGBT_PIN, HIGH);                     //parte il trigger
      // e se invece il giri fossero sotto i 100 rpm il trigger non partirebbe mai
      spark_time = millis();                            //nella variabile di servizio spark_time inseriamo il tempo in cui è fisicamente avvenuto il trigger
      delay_effective = (millis() - now_pulsems);       //conteggio del ritardo effettivo intercorso dato da tempo attuale - tempo dell'ultimo impulso
   }

   Serial.print("\n");
   Serial.print(rotation_time);
   Serial.print("\n");                               // serie di dati di servizio opzionali per valutare la funzionalita del programma
   Serial.print("RPM CURVA TIMEDEG DELAY TIMEUNTIL CALCTIME SPIKE REALDELAY  ");
   Serial.print("\n");
   Serial.print(RPM, 0);
   Serial.print(" ");
   Serial.print(curva);
   Serial.print("     ");
   Serial.print(t_degree);
   Serial.print("    ");
   Serial.print(delay_);
   Serial.print("    ");
   Serial.print(delay_time);
   Serial.print("       ");
   Serial.print(time_after_calc);
   Serial.print("    ");
   Serial.print(spark_time);
   Serial.print("    ");
   Serial.print(delay_effective);
   Serial.print("\n");
   digitalWrite(IGBT_PIN, LOW);
   loop();
   // di nuovo chiamare la loop()?
   // studia un po' di programmazione strutturata
}

Scusa mio fratello

È stato un po’ brusco nello scrivere

Ma la sua (in realtà nostra) intenzione era pacifica

Casomai se hai domande risponderò io lasciando Fabio al ’ back office"

Nota al volo: tempi così brevi non si misurano con millis ma micros :wink:

valvolo:
in risposta a dinodf:
ho provato anche a fare come mi suggerisci usando un while e confrontando ciclicamente il millis()

Ciao,
non devi usare alcun while(), non devi bloccare l’esecuzione perché in caso di misfire avresti grossi problemi non ricalcolando il tempo esatto e quindi il motore si spegnerebbe, controlla direttamente dall’interno della funzione loop() che dovresti sapere viene richiamata continuamente già in automatico.
Esattamente come dice Claudio_FF usa micros() (non avevo notato che usavi millis())
Non mi sembra utile richiamare la funzione revolution() in loop(), loop() praticamente non farebbe nulla se non richiamare quella funzione a questo punto sposta direttamente i calcoli la.
Non vedo nemmeno l’utilità di incrementare pulses in pulse, a che scopo? (perdere tempo?)
Ti consiglio di riscrivere tutto tenendo conto di due cose:

  • non rifare ogni volta tutti i calcoli inutilmente solo per fare poi un confronto di valori, modifica le funzioni in maniera da avere solamente un valore da moltiplicare per una costante, ad esempio in revolution(): ora fai fare alla CPU
...
RPM = (60000/rotation_time);
...
if ((RPM>=4000)&&(RPM<7000)) {                      //se il numero di giri è compreso fra 4000 e 7000, applica la curva di ritardo prevista dalla ZONA4
                   delay_= (180-(((RPM/1000)*z4)+q4))*time_degree;
                   curva=4; 
                   spark();
}

perché ad esempio non togli RPM/1000 e lo sostituisci con il suo quoziente? non sono esperto di centraline ma dato che meno calcoli fai meno tempo perdi credo che per avere la massima precisione si debba ridurre all’osso i calcoli, di conseguenza trovati tutte le varie strade per ridurre i calcoli inserendo costanti calcolate dal preprocessore in maniera da rendere l’esecuzione il più veloce possibile.
Elimina RPM ed utilizza direttamente rotation_time così hai già due divisioni in meno da fare, certamente l’algoritmo diverrà più complesso da interpretare ma sicuramente molto più veloce nell’esecuzione.

  • non richiamare funzioni inutilmente, fa tutto dentro al loop(), inizializza le variabili in setup() così non corri rischi.
    credo sia utile calcolare il tempo come la media degli ultimi diciamo 5 cicli per ridurre l’errore, lo si fa con un array, l’ISR salva un dato e setta un flag per dire al loop che ha modificato i dati
    nel loop fai:
  • controlla se c’è stato un interrupt (il flag) in caso calcola tra quanti microsecondi devi far scoccare la scintilla
  • controlla se è passato il tempo indicato nei calcoli precedenti ed in caso affermativo resetta il flag e fa scoccare la scintilla
  • trasmetti solo pochi caratteri per evitare perdite inutili di tempo prezioso.

La vedo dura senza utilizzare un sistema RealTime avere ottimi risultati, ma discreti credo sia possibile.
Magari se hai la possibilità controlla con un oscilloscopio i tempi reali.

Ducembarr:
trasmetti troppa roba sulla seriale , io ho fatto un conto della serva che ti vanno via dai 40 agli 80 millisecondi per la trasmissione
tra i 25 e i 50 giri al secondo, non superi i 3000 RPM, e tutto il tempo di Arduino è impegnato a trasmettere, non fa nulla di utile

In realtà non supererà i 1500 giri al minuto dato che il sensore è posto a 180° dal PMS e quindi il tempo utile per i calcoli è solo la risalita del pistone, sempre se parliamo di un due tempi, altrimenti si dovrà anche tener conto della fase del motore.

dinodf:
In realtà non supererà i 1500 giri …

hai ragione, non ci avevo pensato

anche il suggerimento di fare i calcoli preventivamente è ottimo

Questa mattina ho fatto delle prove e ho capito che BISOGNA lavorare con i uSec (come diceva Claudio_FF) e usare solamente degli interi.
Sono arrivato a questo.

#define IGBT_PIN 7    //definisce la variabile IGBT e la uguaglia a 7
#define HALL_PIN  2  //definisce la variabile HALL_PIN e la uguaglia a 2 (modific)
const int z2 = 285;     //valore utile per la curva della zona2
const int z4 = 133;     //valore utile per la curva della zona4
const int q4 = 283;     //valore utile per la curva della zona4

volatile unsigned long last_pulsems = 0;       //definisce la variabile last_pulse e la uguaglia a 0
volatile unsigned long now_pulsems = 0;        //definisce la variabile last_pulse e la uguaglia a 0
volatile bool pulses = false;                       //definisce la variabile di servizio pulses = 0



void pulse() {                        //funzione pulse richiamata dall'interrupt
  pulses = true;                   //aumenta la variabile pulse di 1
  last_pulsems = now_pulsems;
  now_pulsems = micros();     //associa a last_pulse il tempo in cui è avvenuto
}

void setup() {

  Serial.begin(115200); Serial.println("Serial started");

  pinMode(IGBT_PIN, OUTPUT);                                       // inizializza il pin HALL_PIN (7) come output (pin al quale è connesso il trigger della bobina)
  pinMode(HALL_PIN, INPUT_PULLUP);                                        // inizializza il pin HALL_PIN (2) come input (pin al quale è connesso il sensore di hall)

  attachInterrupt(digitalPinToInterrupt(2), pulse, FALLING);       //inserisce interrupt che porta alla //routine pulse ogniqualvolta il Pin 2 (sensore HALL)  passa da HIGH a LOW
  last_pulsems = micros();
}

void loop() {

  if (pulses) {                          //se pulses è diverso da 0 non è il primo giro di manovella ed è appena avvenuto uno scoppio si attende il prossimo segnale di hall
    pulses = false;
    revolution();                           //richiama la routine revolution
  }
}

void revolution() {

  unsigned long rotation_time = (now_pulsems - last_pulsems); //in uSec          //conta il tempo (periodo) di rotazione eseguendo una sottrazione fra il tempo del penultimo e dell'ultimo impulso letto
  unsigned int RPM = (60000000 / rotation_time);                          //conteggia gli RPM
  unsigned int time_degree = 36000000 / rotation_time;                      //conteggia il periodo di rotazione di 1 grado, utile nelle formule dell'anticipo (ritardo da applicare dall'ultim lettura)
  if (RPM >= 70) {       //delay_=16500/Tdegree+20000/RPM-3                                 //se il numero di giri è superiore a 7000, applica la curva di ritardo prevista dalla ZONA5
    spark((1610000 / time_degree));
  }  else if ((RPM >= 40) && (RPM < 70)) {                //se il numero di giri è compreso fra 4000 e 7000, applica la curva di ritardo prevista dalla ZONA4
    spark( (1800000 - (((RPM / 10) * z4) + q4)) / time_degree);
  } else if ((RPM >= 14) && (RPM < 40)) {                //se il numero di giri è compreso fra 1400 e 4000, applica la curva di ritardo prevista dalla ZONA3
    spark(15700 / time_degree);
  } else if ((RPM >= 2) && (RPM < 14)) {                 //se il numero di giri è compreso fra 200 e 1400, applica la curva di ritardo prevista dalla ZONA2
    spark((1800000 - (((RPM / 10) * z2) + 190)) / time_degree);
  } else {                                                   //se il numero di giri è compreso fra 100 e 200, applica la curva di ritardo prevista dalla ZONA1
    spark(1600000 / time_degree);
  }   
  
}

void spark(int delay_) {                                    //funzione di accensione a seconda del ritardo calcolato
  delayMicroseconds(delay_);
  //digitalWrite(IGBT_PIN, HIGH);                     //parte il trigger
  //digitalWrite(IGBT_PIN, LOW);


}

in questo modo si va da un minimo di 33 uSec a 8000 Giri/min a un massimo di 1333 uSec a 200 Giri/min.
Domani faro’ di nuovo delle prove e vedrò’ se è veramente più stabile.
Prima di provarlo sul motore fai delle prove anche tu per confermare i risultati, non vorrei che il tuo motore si rompesse!

P.S. mi sa che le tue formule non siano giuste!

Facendo un grafico dei valori ottenuti si hanno dei valori quasi perfettamente lineari. Quindi forse si può fare una sola formula semplificando enormemente i calcoli.