problema con controllo motore

Buongiorno a tutti, ho un problema: devo controllare se un motore gira. Ho un controller, che ho collegato a un ingresso digitale, che mi rende 000000000000000 o 111111111111111 se il motore è fermo e 01001110101110101101 se gira! Il problema è che Arduino crede che il motore si fermi dopo un tempo variabile ( a volte 3” a volte 12-13” ) Grazie a tutti

int in1 = 0, in2 = 0,in3 = 0,in4 = 0,in5 = 0,in6 = 0,in7 = 0,in8 = 0,in9 = 0, in10=0,in11 = 0, in12 = 0,in13 = 0,in14 = 0,in15 = 0,in16 = 0,in17 = 0,in18 = 0,in19 = 0,a=0,b=0;// variable for reading the pushbutton status
int tempo = 0, tempoiniziale=0, motor=0;
int out = 0, secondi=0;
void setup() {


    Serial.begin(9600); 
  // initialize the LED pin as an output:
  pinMode(10, OUTPUT); //motore 1  
  pinMode(11, OUTPUT);   // motore 2

  pinMode(2, INPUT); // controllo motore (controlla se il motore gira
  pinMode(4, INPUT);  // pulsante di start
}

void loop(){

  if (millis()-tempoiniziale >= 900000) { // fermo tutto dopo 15 minuti
  motor=0; 
  // aggiungere qui biip biip per gelato pronto
  }
if (digitalRead (4)== HIGH) { //parte il motore per se schiaccio il pulsante
  motor =1;
  digitalWrite(11, HIGH);
}

if (motor==1) { //tutto o quasi avviene se motor =1
delay(300);


  in1 = digitalRead(2);
  delay (40);
  in2 = digitalRead(2);
  delay (40);
  in3 = digitalRead(2);
  delay (40);
  in4 = digitalRead(2);
  delay (40); 
  in5 = digitalRead(2);
  delay (40);
   in6 = digitalRead(2);
  delay (40);
 in7 = digitalRead(2);
  delay (40);
 in8 = digitalRead(2);
  delay (40);
 in9 = digitalRead(2);
  delay (40);
  in10 = digitalRead(2);
  delay (40);
  
  in11 = digitalRead(2);
  delay (40);
  in12 = digitalRead(2);
  delay (40);
  in13 = digitalRead(2);
  delay (40);
  in14 = digitalRead(2);
  delay (40); 
  in15 = digitalRead(2);
  delay (40);
  in16 = digitalRead(2);
  delay (40);
  in17 = digitalRead(2);
  delay (40);
  in18 = digitalRead(2);
  delay (40);
  in19 = digitalRead(2);
  delay (40);


if (in1 == in2 && in1 == in3 && in1 == in4 && in1 == in5 && in1 == in6 && in1 == in7 && in1 == in8 && in1 == in9 && in1==in10 && in1 == in12 && in1 == in13 && in1 == in14 && in1 == in15 && in1 == in16 && in1 == in17 && in1 == in18 && in1 == in19) {       
                                 //se le letture sono tutte uguali spengo tutto
  digitalWrite(11, LOW);
    a=0;
   digitalWrite(10, LOW);  
    b=0;
    motor=0;
    // aggiungere qui beep beep per motore fermato
  } 
  else {
    tempoiniziale = millis();
    if (tempo == 0){
     tempo = millis();
     digitalWrite(11, HIGH);
     a=1;
    }
    secondi = (millis()-tempo);
    if (secondi >= 10000){
      tempo = millis();
      if (out == 0){
        digitalWrite(11, LOW);
        a=0;
        delay(5);
        digitalWrite(10, HIGH);
        b=1;
        out=1;
        }
      else {
        digitalWrite(10, LOW);
        b=0;
        delay(5);
        digitalWrite(11, HIGH);
        a=1;
        out=0;
        }
    }       
  }
}






// la parte qui sotto serve solo di controllo e non servira piu'

   
 Serial.print("sensor = " );  
 Serial.print (in1);
 Serial.print (in2);
 Serial.print (in3);
 Serial.print (in4);
 Serial.print (in5);
 Serial.print (in6);
 Serial.print (in7);
 Serial.print (in8);
 Serial.println (in9);

 Serial.print ("led 11=");
 Serial.println (a);
 Serial.print ("led 13=");
 Serial.println (b);


 Serial.print ("tempo=");
 Serial.println (tempo);

 Serial.print ("secondi   ");
 Serial.println (secondi);

 Serial.print ("millis");
 Serial.println (millis());

 Serial.print ("out= ");
 Serial.println (out);
 Serial.println ("");
 Serial.println ("");

 Serial.print ("motor= ");
 Serial.println (motor);
 Serial.println ("");
 Serial.println ("");

 delay(200);


}

cecione: Buongiorno a tutti, ho un problema: devo controllare se un motore gira. Ho un controller, che ho collegato a un ingresso digitale, che mi rende 0000 0000 0000 000 o 111111111111111 se il motore è fermo e 01001110101110101101 se gira!

Sembra tanto trattarsi di un out tachimetrico, se il motore è fermo ottieni sempre l'ultimo stato, 0 o 1, se il motore gira ottieni una serie di variazioni 0-1 in funzione della velocità di rotazione del motore e di quanto velocemente campioni l'out. Il modo più semplice per capire se il motore gira è campionare l'out e verificare se ha cambiato stato entro un certo timeout, quanto dipende dalla velocità di rotazione del motore e da quanti impulsi rotazione fornisce l'out del controller. Sarebbe una cosa intelligente sfruttare un pin INT, 0 o 1, abilitando l'interrupt on change in modo da non dover eseguire un polling continuo del pin.

potresti spiegarmi cosa vuole dire

pin INT, 0 o 1, abilitando l'interrupt on change in modo da non dover eseguire un polling continuo del pin.

e, soprattutto come lo inserisco nel codice? grazie 1000 per la risposta!

Ho provato a cercare ma non ho trovato niente: il mio problema è che non so lo stato iniziale ma devo verificare se cambia. Grazie a tutti

cecione: Ho provato a cercare ma non ho trovato niente ...

Vai sul reference e studiati : attachInterrupt(), detachInterrupt(), interrupts(), noInterrupts(). Dopo di che cerca con Google "Arduino Interrupts" e vedrai che ti verrano fuori un'infinità di informazioni.

Guglielmo

Grazie delle dritte! mi metto subito al lavoro!!

Ho studiato tutto (non è detto che abbia imparato) ma il mio problema è che devo capire quando passo da 01100111011 a 111111111 o 00000000000 e se ho capito bene non posso farlo con "interrupt": interrupt posso usarlo solo quando vario una situazione (da 00000 a 11111 o viceversa) Suggerimenti? Grazie a tutti!!

Nessun suggerimento? Grazie

Da quello che vedo per Arduino non è un problema aquisire 19 valori a distanza di pochi ms ma credo che il problema sia in

if (in1 == in2 && in1 == in3 && in1 == in4 && in1 == in5 && in1 == in6 && in1 == in7 && in1 == in8 && in1 == in9 && in1==in10 && in1 == in12 && in1 == in13 && in1 == in14 && in1 == in15 && in1 == in16 && in1 == in17 && in1 == in18 && in1 == in19) {

(è solo una piccola parte del codice)

prima di scrivere questo avevo scritto:

“if(in1==in2 && in2==in3 &&…”

questo dava ancora più problemi di funzionamento! avete idea del perchè? è un baco di Arduino o di qualcosa altro?

Grazie a tutti

Secondo me ti stai inutilmente complicando la vita ... :roll_eyes:

... quando il pin cambia stato (0 -> 1 oppure 1->0), cosa che rilevi facilmente con l'opportuno interrupt, tu azzeri un contatore che poi incrementi in continuazione nel loop(). Se avviene un cambiamento di stato, quel contatore si azzera e ricomincia a contare, se non avviene ... dopo un tempo X avrà raggiunto un valore Y che per te significherà che il motore è fermo.

Dato che dovrai usare la millis() ti do direttamente i link da studiare per capire come sfruttarla al meglio : PRIMO e SECONDO .

Guglielmo

OK, ci ho messo un po' ma credo di avere dei problemi: per capire la funzione attachInterrupt() ho scritto questo codice:

void setup() {
  Serial.begin(9600); 
  pinMode(2, INPUT); // controllo motore (controlla se il motore gira
  attachInterrupt(2,via,CHANGE);
}

void loop(){ 
}


 void via(){
 Serial.println ("via");
  
delayMicroseconds(2000000); //attende 2 secondi
}

mi aspetterei che sul monitor seriale compaia "via" tutte le volte che apro o chiudo il circuito collegato al pin 2 e invece non accade: a volte non compare niente altre volte compaiono una decina di "via".

Go qualche difetto hardware?

Grazie a tutti

Peccato che il delayMicroseconds() non funziona nel interrupt. Puoi neanche mettere un Serial.println() .

Rileggiti i testi del interrupt. e quello che Ti ha suggerito Guglielmo

Ciao Uwe

ciao vedo un paio di problemi;il primo è questo:attachInterrupt(2,via,CHANGE);quel "2" non è il pin di arduino ma il numero dell'interrupt. Ora Arduino uno ha 2 interrupt: l'int0 collegato al pin 2 e l'int1 collegato al pin3.l'int2 NON C'E'. il codice guisto per qualcosa di collegato al pin 2 è:attachInterrupt(0,via,CHANGE); seconda cosa: l'ISR ( ovvero la funzione che l'interrupt va a richianare; in questo caso la funzione via) normalmente non deve contenere delay ma di solito la si usa per modificare delle variabili e basta. Un approccio più corretto (credo) potrebbe essere questo:

volatile boolean pippo = FALSE;// creo variabole booleana 
void setup() {
  Serial.begin(9600); 
  pinMode(2, INPUT); // controllo motore (controlla se il motore gira
  attachInterrupt(0,via,CHANGE);
}
void loop(){ 
  if(pippo){
Serial.println ("via");
delayMicroseconds(2000000); //attende 2 secondi
pippo = FALSE;
}
}
 void via(){
 pippo = TRUE;
}

ovvero l'ISR cambia solo lo stato della variabile pippo. All'intero del loop verifico la variabile e faccio quello che mi interessa dopo di che risetto la variabile.

ciao pippo72

p.s. non ho provato il codice quindi ci portebbero essere errori di sintassi. p.p.s quoto uwe e mi associo:

Rileggiti i testi del interrupt. e quello che Ti ha suggerito Guglielmo

scusa uwefed, ma qui http://arduino.cc/en/Reference/AttachInterrupt ho letto:

"Generally, an ISR should be as short and fast as possible. If your sketch uses multiple ISRs, only one can run at a time, other interrupts will be ignored (turned off) until the current one is finished. as delay() and millis() both rely on interrupts, they will not work while an ISR is running. delayMicroseconds(), which does not rely on interrupts, will work as expected. "

ho capito male?

pippo72 ti ringrazio della spiegazione (non avevo capito la tabella http://arduino.cc/en/Reference/AttachInterrupt) ma ho verificato che con Leonardo il codice guisto per qualcosa di collegato al pin 2 è:

 attachInterrupt(1,via,CHANGE);

ancora grazie

ciao

…ma ho verificato che con Leonardo…

Non sapevo che si parlava di una Leonardo :o :o (credo di non averlo letto da nessuna parte su questo tread).
infatti avevo scritto

…Ora Arduino uno…

:wink:
Riguardo alla questione delaymicroseconds (scusa uwe se mi intrometto) nel reference c’è si scritto che funziona all’interno di una ISR MA c’è anche scritto che una ISR deve essere più corta e più veloce possibile. quindi un delaymicroseconds all’interno di una ISR funziona sicuramente ma probabilmente (secondo me) un ritardo di 2 secondi all’interno si una ISR non ha tanto senso senso.

ciao
pippo72

Si, la delayMicrosecond() NON si lega ad alcun timer (… ovvero a qualche interrupt), e contrariamente a quello che fanno le altre delay, usa delle istruzioni assembler per “perdere” tempo :smiley:

Basta osservarne il sorgente per verificarlo :

/* Delay for the given number of microseconds.  Assumes a 8 or 16 MHz clock. */
void delayMicroseconds(unsigned int us)
{
	// calling avrlib's delay_us() function with low values (e.g. 1 or
	// 2 microseconds) gives delays longer than desired.
	//delay_us(us);
#if F_CPU >= 20000000L
	// for the 20 MHz clock on rare Arduino boards

	// for a one-microsecond delay, simply wait 2 cycle and return. The overhead
	// of the function call yields a delay of exactly a one microsecond.
	__asm__ __volatile__ (
		"nop" "\n\t"
		"nop"); //just waiting 2 cycle
	if (--us == 0)
		return;

	// the following loop takes a 1/5 of a microsecond (4 cycles)
	// per iteration, so execute it five times for each microsecond of
	// delay requested.
	us = (us<<2) + us; // x5 us

	// account for the time taken in the preceeding commands.
	us -= 2;

#elif F_CPU >= 16000000L
	// for the 16 MHz clock on most Arduino boards

	// for a one-microsecond delay, simply return.  the overhead
	// of the function call yields a delay of approximately 1 1/8 us.
	if (--us == 0)
		return;

	// the following loop takes a quarter of a microsecond (4 cycles)
	// per iteration, so execute it four times for each microsecond of
	// delay requested.
	us <<= 2;

	// account for the time taken in the preceeding commands.
	us -= 2;
#else
	// for the 8 MHz internal clock on the ATmega168

	// for a one- or two-microsecond delay, simply return.  the overhead of
	// the function calls takes more than two microseconds.  can't just
	// subtract two, since us is unsigned; we'd overflow.
	if (--us == 0)
		return;
	if (--us == 0)
		return;

	// the following loop takes half of a microsecond (4 cycles)
	// per iteration, so execute it twice for each microsecond of
	// delay requested.
	us <<= 1;
    
	// partially compensate for the time taken by the preceeding commands.
	// we can't subtract any more than this or we'd overflow w/ small delays.
	us--;
#endif

	// busy wait
	__asm__ __volatile__ (
		"1: sbiw %0,1" "\n\t" // 2 cycles
		"brne 1b" : "=w" (us) : "0" (us) // 2 cycles
	);
}

… ma, come giustamente osservato da pippo72, una ISR deve durare il minor tempo possibile e quindi il sistema migliore è proprio quello da lui indicato … nella ISR alzare solo una FLAG (per indicare l’avvenuto evento) che verrà poi trattata nel codice :wink:

Guglielmo