Interpretare segnale crank proveniente da ruota fonica di un motore a scoppio

Ciao a tutti, vi presento il progetto su cui sto lavorando: gassificare un motore a benzina. Tralasciando tutta la parte teorica sul funzionamento del motore e della miscelazione, per ora mi sto concentrando sull'interpretazione del segnale di crank proveniente dalla ruota fonica tramite un sensore magnetico.

La parte hw è già definita e funzionante, tramite un MAX9924 converto gli impulsi del sensore magnetico in onda quadra TTL compatibile: il treno d'impulsi corrispondente ai 60-2 denti della ruota fonica viene replicato dall'integrato come un segnale alto durante il passaggio del dente davanti al sensore e un segnale basso durante il passaggio della gola davanti al sensore. Quando si hanno i "denti mancanti", l'integrato solleva a Vcc l'uscita grazie al pullup, quindi si ha un segnale alto di durata t multiplo dei denti mancanti.

Bene.. sperando di aver chiarito, ora vi posterei il codice da me scritto con l'intento di avere in uscita da Arduino UNO un'impulso corrispondente ai "denti mancanti". Inutile dire che non è funzionante... :(

const int led = 13;
volatile unsigned long trif=0;             //tempo corrente
volatile unsigned long trif_1=0;          //tempo precedente


void setup()
{
 pinMode(led, OUTPUT);
 attachInterrupt(0,conteggio,FALLING);
}

void loop()
{

}
void conteggio()
{
 trif=pulseIn(2,HIGH);

   if (trif > trif_1) 
 {
   digitalWrite(led,HIGH);
   delay(trif);
   trif_1=trif;
 }
 else
 {
   digitalWrite(led,LOW);
   trif=0;
 }

}

Vi ringrazio anticipatamente per l'aiuto... Attualmente in uscita ottengo un segnale costante a livello logico basso. Grazie dell'attenzione. Aldo

Rileggendo ho già trovato un errore: non posso porre trif_1=trif alla fine dell'if senno come tempo precedente avrò sempre il periodo massimo dell'impulso.

Ho modificato in questo modo e ora ottengo un segnale sempre alto:

   if (trif > trif_1) 
  {
    digitalWrite(led,HIGH);
    delay(trif);
    trif=0;
  }
  else
  {
    digitalWrite(led,LOW);
    trif_1=trif;
  }

Per capirci, il mio segnale è questo:

ciao per il conteggio degli impulsi devi usare la finzione interrupt

In teoria la sto già usando, applico il segnale sul pin dell'interrupt 0 e poi abilito la funzione "conteggio" ogni fronte di discesa.

Poi dentro alla funzione "conteggio" misuro la durata dell'impulso alto e la confronto con la durata del precedente impulso alto. Se la durata dell'impulso corrente è maggiore della durata dell'impulso precedente, allora sono in presenza del dente mancante. Quindi genero un impulso in uscita con Delay(durata impulso corrente).

Perché non dovrebbe funzionare così?

se il tuo scopo è sapere la posizione dell'albero motore usa l'interrupt è fatto apposta per cogliere gli istanti

Ok, quindi come potrei fare per trovare l'impulso mancante usando gli interrupt?

devi semplificare l'interrupt che stai usando contando quanti millis() tra un evento e l'altro e confrontandolo con quello precedente

Quindi dovrei usare un millis() tra 2 interrupt diversi, uno sul fronte di salita e uno sul fronte di discesa, per sapere quanto tempo è passato tra i 2 eventi? Perché mi sembra di aver capito dalle faq che all'interno di una isr non si possa usare millis()

il millis() nel loop() nell'interrupt metti solo il cambio di valore della variabile hai provato qualcosa del genere?

nell'interrupt { stato = 1; time_0 = millis(); }

nel loop()

if(stato == 1 && digital.Read(pin) == 1) { time_1 = millis(); } else { stato = 0; }

Adesso provo e poi aggiorno la situazione. Nel frattempo ti ringrazio stefa24

Io farei in modo anche di eliminare il delay che blocca tutti i processi(interrupt compresi).

il delay che blocca tutti i processi(interrupt compresi).

da quando ?

Nel frattempo ho scoperto che, scritto come l'ultima versione da me postata, trif=0 sempre in ogni caso, guardando il monitor seriale. Tra l'altro effettua 3 letture e poi si interrompe.

Di eliminare i delay ci avevo già pensato, ma non sapevo come fare.

Ora provo la soluzione di stefa24

Brunello: da quando ?

Che io sappia da sempre... Correggimi se sbaglio ma altrimenti non sarebbe tra i primi esercizi proposti per i debuttanti il "blink without delay"

Da qui :

....the use of delay() in a sketch has significant drawbacks. No other reading of sensors, mathematical calculations, or pin manipulation can go on during the delay function, so in effect, it brings most other activity to a halt.

Ho qualche serio problema con l'interrupt... Esegue solo 11 letture e poi si blocca. Con questo codice

void conteggio()
{
  stato = 1;
  trif_0 = millis();
  Serial.println(stato);
}

sul monitor vedo

0
0
0
0
0
1
0
0
0
0
0

Sempre o solo quando inserisci il serial print all'interno dell'interrupt? Perché ho letto più di una volta che il serial print all'interno degli interrupt genera problemi..

Kafer: Sempre o solo quando inserisci il serial print all'interno dell'interrupt? Perché ho letto più di una volta che il serial print all'interno degli interrupt genera problemi..

Hai ragione, mettendo tutto nel loop() stampa correttamente

Allora ho provato e modificato la soluzione di stefa24 in questo modo:

void conteggio()
{
  if(digitalRead(3)==1)
  {
    stato=1;
    trif_0 = millis();
  }
}

void loop()
{

  if(stato == 1)
    {
      trif_1 = millis();
      tempo=trif_1-trif_0;
    }
  else
    {
      stato = 0;
    }
  Serial.println("trif");
  Serial.println(trif_1);
  Serial.println("stato");
  Serial.println(stato);
  Serial.println("tempo");
  Serial.println(tempo);
  delay(700);
}

L'interrupt si attiva ogni cambiamento del segnale. Noto che ogni tanto la variabile tempo assume un valore sensato, però rimangono dei dubbi: 1_ teoricamente la variabile tempo dovrebbe stamparmi il valore del periodo del segnale corrispondente al dente mancante 2_ il loop e l'interrupt sono sincronizzati? Nel senso, l'interrupt si attiva ogni cambiamento del segnale ma il loop ogni quanto si attiva? Ogni colpo di clock o comunque con una frequenza relativa al colpo di clock?

il programma è sempre in loop, l'interrupt prende il sopravvento quando si manifesta l'evento, per poi ritornare al loop,

if(stato == 1) && digitalRead(3)==1 questa istruzione nel loop non funziona bene?