On/off motore DC con interrupt e ULN2003

Sto cercando di accendere e spegnere un motore tramite lo stesso pulsante. L'idea è che il pulsante inverti una variabile booleana attraverso un interrupt. Nel loop ci sarà l'accensione o lo spegnimento a seconda del valore della variabile.
Allego il codice relativo.

Per quanto riguarda l'hardware ho usato Arduino UNO, l'integrato ULN2003, due led con le relative resistenze, un motorino DC di quelli che escono con gli starter kit di Arduino.
Allego a titolo illustrativo un immagine del circuito realizzato tramite tinkercad, dove ho sostituito i transistor darlington dell'integrato utilizzando componenti discreti.

Ho testato motore ed ic e funzionano entrambi correttamente, utilizzandoli anche in altri progetti e pilotando il motore tramite Arduino.
Anche lo sketch che ho allegato funziona correttamente per alimentare carichi non induttivi, quali ad esempio i led di segnalazione.

Quando collego il motore invece ci sono anomalie di vario genere come start & stop continui del motore o comunque risposte diverse da quelle volute. Ho cercato di debuggare inserendo dei Serial.print nel codice e dal risultato sembrerebbe che all'accensione del motore venga richiamato continuamente l'interrupt, come se ci fossero cambiamenti nello stato logico del pin 2.
Ho anche provato a modificare gli argomenti della funzione attachInterrupt, utilizzando le modalità LOW e RISING con gli stessi risultati.

Mi chiedo se c'è bisogno di ulteriori accorgimenti per stabilizzare lo stato logico sul pin 2.
Grazie in anticipo per la pazienza


motore_forum.ino (658 Bytes)

ci devi mettere un debounce, hardware o sftware, scegli tu, ma senza debounce non ne cavi ragni da buchi

Grazie per la risposta. Visto che utilizzando solo dei led lo sketch funziona pensavo fosse legato al carico induttivo del motore. Quando utilizzo anche il motore l'ISR viene richiamata di continuo come se sul pin continuasse a scendere e salire la tensione.

Debounce hardware credo di riuscire a farlo con una rete RC o con un multivibratore monostabile (correggetemi se sbaglio) ma per quanto riguarda quello software non mi viene in mente come fare perché non posso utilizzare nè millis() nè delay() all'interno della funzione dell'interrupt. Con delayMicroseconds() forse?

E difatti, per tutto quello che riguarda ISR, si usano solo debouncing hardware ... :roll_eyes:

Guglielmo

Leggendo sul reference di Arduino in effetti pensavo fossi vincolato ad utilizzarlo solo hardware.
Vista la risposta precedente mi sono documentato per quanto riguarda debounce software di ISR ed ho trovato questo topic.
Devo ancora fare delle prove riguardo quello che suggeriscono, ma sembrerebbe una soluzione valida anche questa.

Che ne pensate?

A seconda di come hai collegato il pulsante questi sono gli schemi da usare .. ribadisco, con le ISR NON si devono usare soluzioni software.

Guglielmo

Questo non è del tutto corretto
È vero che millis() non viene incrementato all'interno della ISR, ma questo non ti impedisce di leggerne il valore per salvarlo in una variabile e poi fare quel che devi con tutta calma nel loop() principale ed implementare anche un debounce software

Ok, infatti nel topic che avevo linkato nella risposta precedente sfruttano questo principio. Riporto una bozza di ISR scritta in quel topic:

void my_interrupt_handler()
{
  static unsigned long last_interrupt_time = 0;
  unsigned long interrupt_time = millis();
  // If interrupts come faster than 200ms, assume it's a bounce and ignore
  if (interrupt_time - last_interrupt_time > 200) 
  {
    ... do your thing
  }
  last_interrupt_time = interrupt_time;
}

Proverò appena possibile sia quello hardware che software cosi da averne contezza di persona.
Grazie dei pareri e delle risposte, aggiornerò appena fatto.

Io però non farei cosi.
Le ISR, di norma, devono essere della durata più breve possibile.

Più un qualcosa del genere:

const uint32_t BOUNCE_TIME = 1000; // Volutamente esagerato
volatile uint32_t btnTime;
volatile bool btnFlag = false;

void btnISR() {
  if (!btnFlag) {
    btnTime = millis();
    btnFlag = true;
  }
}

void loop() {

  if (btnFlag && ((millis() -btnTime) > BOUNCE_TIME)) {
    btnFlag = false;
    Serial.println("Debounced click");
  }
}


Rilancio, verificare se dopo il debtime l'ingresso si trova ancora al livello premuto. Così si tagliano fuori anche i disturbi impulsivi, che senza la doppia lettura verrebbero presi per segnali buoni.

void loop() {
    if (btnFlag && ((millis() - btnTime) > BOUNCE_TIME)) {
        btnFlag = false;
        if (digitalread(PIN_INGRESSO) == PRESSLEVEL) {
            Serial.println("Debounced click");
        }
    }
}
1 Like

Grazie per i consigli finora arrivati sul debounce: ho provato entrambi i tipi, sia software che hardware e funzionano evitando di interpretare i rimbalzi meccanici del pulsante come nuovi impulsi.
Tutto questo funziona però solo con un carico diverso dal motorino DC, ad esempio se provo ad applicarlo per accendere un semplice led.
Aggiungo che la parte hardware ( Arduino, ULN2003 e DC Motor) è funzionante: è stata testata con un semplice sketch che fa il blynk del motore (accensioni intermittenti con periodi nell'ordine del secondo)

Purtroppo nonostante i debounce di vario tipo sembrano esserci variazioni sulla tensione del pin 2 quando alimento un carico induttivo. Questo si evince semplicemente debbugando attraverso il codice. Non riesco a fare misure adatte in quanto non ho un oscilloscopio.

Potreste dirmi se le ipotesi fatte riguardo questo malfunzionamento sono sensate? Nel caso cosa potrei fare per evitare questi disturbi?

Sono lo stesso tipo di disturbi di cui parla @Claudio_FF? Ammetto che l'ultima modifica suggerita non è stata ancora implementata per motivi di tempo. Grazie

Prova ad alimentare il motore con un altro alimentatore.

È già alimentato senza usare i 5 volt di arduino come nello schema allegato ad inizio topic. Provato sia con alimentatore da laboratorio che con due pile li ion in serie.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.