Leggere il numero di giri di una vetola PC Nexus

Ciao a tutti..
Mi so imbattutto in un strano problema, ho comprato una ventola per pc Nexus D12SL-12 (nexustek.nl -). Questa ha un filo per regolare la velocità (PWM) e un filo per leggere il numero di giri. Come tante altre ventole.
Questa ha un minimo di 500 RPM a un massimo di 2000 RPM.
Avevo già fatto questo con molte altre e leggevo regolarmente il numero corretto RPM, ma con questa ho dei problemi.
Più precisamente, dal minimo al massimo leggo solo una differenza di 300 RPM invece dovrebbero essere 1500 RPM e inoltre non riesco mai a leggere un numero corretto... MIN 3500 massimo 3800.
E' una ventola che ha 4 step al giro.. e il circuito con cui la leggo ha una resistenza pull-up di 10K.
Mi potete dire dove sbaglio ? Tenete presente che con altre ventole più piccole non ho mai avuto problemi.
Questo è il codice con cui leggo i dati tramite un pin analogico dell' arduino.
int fanPulse = A2;
unsigned long pulseDuration;

void setup()
{
Serial.begin(9600);
pinMode(fanPulse, INPUT);
digitalWrite(fanPulse,HIGH);
}

void readPulse() {
pulseDuration = pulseIn(fanPulse, LOW);
double frequency = 1000000/pulseDuration;

Serial.print("pulse duration:");
Serial.println(pulseDuration);

Serial.print("time for full rev. (microsec.):");
Serial.println(pulseDuration4);
Serial.print("freq. (Hz):");
Serial.println(frequency/4);
Serial.print("RPM:");
Serial.println(frequency/4
60);

}

void loop()
{
analogWrite(3,0);
delay(15000);
readPulse();
analogWrite(3,255);
delay(15000);
readPulse();
}

Grazie

al posto della pulseIn fai:

unsigned long time;
while (digitalRead(fanPulse) == LOW){
   continue;//wait to be HIGH
}

while (digitalRead(fanPulse) == HIGH){
   continue;//wait to be LOW
}
time = micros();
while (digitalRead(fanPulse) == LOW){
   continue;//wait to be HIGH
}
pulseDuration = micros()-time;

in pratica conm questo codice sei sicuro di posizionarti ALL'INIZIO del segnale basso, e non magari di iniziare a leggerlo da metà (non ricordo se la puilseIn lo faccia, ma non sarebbe la prima volta che la pulseIn sfasa) che versione di IDE hai?

poi al posto di 1000000 scrivi 1000000.0 (se non forzi la divisione ad essere in double perdi i decimali!)

Grazie, questa sera provo.
Ho la 1.0.1 praticamente appena scaricata dal sito :slight_smile:
Tu hai esperienza con la lettura rpm delle ventole ?

nessuna esperienza di ventole, mi spiace, ma solo di arduino :slight_smile:

Ciao... ho fatto un po' di prove e il tuo codice va molto bene, ma ha un difetto... se la ventola è spenta il sistema si ferma perchè aspetta sempre un valore che non arriva.
Sarebbe da mettere un timeout... della serie ... se non arriva niente entro 1/2 secondo... salta...
Che dici ?

devi modificare le condizioni nel while in modo che se supera un certo tempo dentro il while esce in automatico.
Poi quando esce in automatico potresti memorizzarti il fatto ed evitare i while fino a quando per caso non rilevi una differenza facendo una digitalRead ogni tanto.

oppure fai il passo successivo e usi gli interrupt

gli interupt li ho già provati, ma mi danno dei vincoli e non sono precisi.
Se intendi per leggere gli impulsi.

veramente gli interrupt son proprio il contrario;
precisi e meno limitanti, in quanto non bloccano il codice se non effettivamente quando avviene qualcosa..
in cambio sono un poco più complessi da usare, ma basta ricordarsi che le variabili tra loop e interrupt vanno dichiarate volatile e quasi tutto è ok.
Posta il codice degli interrupt che vediamo.

@lesto:
l'ultima versione della pulseIn permette anche di iniziare a leggere mentre il pin ha uno stato diverso da quello atteso.
pulseIn(pin, value, timeout)
"value" è lo stato atteso, se lo stato è differente, la pulseIn attende che si verifichi lo stato atteso e poi inizia a cronometrare la durata dell'impulso.

Ciao.. questo è il codice... che usavo... ma con queste ventole non ho la lettura corretta.

 cli();                
 sei();               
                                 
int NbTopsFan; 
int Calc;

                                 
int hallsensor = 2;

                        
typedef struct{                  
  char fantype;
  unsigned int fandiv;
}fanspec;


fanspec fanspace[3]={{0,1},{1,2},{2,8}};

char fan = 1; 

void rpm ()      
{ 
 NbTopsFan++; 
} 

 
void setup() 
{ 
 pinMode(hallsensor, INPUT); 
 Serial.begin(9600); 
 attachInterrupt(0, rpm, RISING); 
} 
void loop () 
{
   NbTopsFan = 0;	
   sei();		
   delay (1000);	
   cli();		
   Calc = ((NbTopsFan * 60)/fanspace[fan].fandiv); 
   Serial.print (Calc, DEC); 
   Serial.print (" rpm\r\n"); 
}

Scusa Leo ma non è come lo utilizzavo io ? Pulsein intendo...

Rispondevo a lesto, che ti aveva consigliato un codice dove metteva in attesa il micro dell'avvento del segnale low, mi pare. La nuova pulseIn permette di fare tutto in automatico

uh questo è il codice con gli interrupt.
allora
int NbTopsFan;

deve essere volatile se no ci sono casini con il modo in cui viene otimizzato il codice quindi
volatile int NbTopsFan;

poi inizializzala a 0
voaltile int NbTopsFan = 0;

sei() e cli() toglie, ance perdi un valore chissene. Piuttosto alza il delay a 10 secondi, che diminuisci l'errore, e anche elimina l'uso dell'array che non capisco perchè lo usi, tanto vale che metti direttamente 2, che velocizzi il codice.

sa questo punto il numero di rpm deve essere corretto per forza!

Scusami Lesto...
Ma la penultima riga non sono riuscito a capirla molto..
"sei() e cli() toglie, ance perdi un valore chissene" volevi dire di togliere quei 2 comandi ?

Certo che però 10 sec per ventola = 20 sec. per ciclo... mi sembrano tanti.
Comunque provo lo stesso.
Se non sbaglio, bisogna collegare le ventole a dei pin particolari dell' ardudino uno/mega per usare gli interrupt, vero ?

sono 2 pin, il 4 e 5 se non ricordo male, cmq la misurazione la puoi fare in contemporanea...