Aiuto Pulsante premuto e motore stepper

Buonasera ragazzi, tentavo nell'eseguire tramite stepper un ciclo con assegnati degli angoli come posizioni, ovvero ogni 90° il motore deve fermarsi 4 volte per 5 secondi, il tutto azionando un pulsante pull up.
Chiedo aiuto in quanto il programma non ha errori nell'ide, ma una volta caricato su un mega2560 non funziona. Grazie in anticipo.

const int  IN1 = 44;   // filo motore BLUE
const int  IN2 = 45;   // filo motore ROSA
const int  IN3 = 46;  // filo motore GIALLO
const int  IN4 = 47;  // filo motore ARANCIO

const int MotoreOFF = 99; // motore spento

#define BUTTON 2             // pin di input dove è collegato il pulsante
int  val = 0;

void Uscita( int i4,int i3,int i2,int i1)
{
  if (i1==1) digitalWrite(IN1,HIGH); else digitalWrite(IN1,LOW);
  if (i2==1) digitalWrite(IN2,HIGH); else digitalWrite(IN2,LOW);
  if (i3==1) digitalWrite(IN3,HIGH); else digitalWrite(IN3,LOW);
  if (i4==1) digitalWrite(IN4,HIGH); else digitalWrite(IN4,LOW);
}

void EseguiPasso(int stato)
{
int i1,i2,i3,i4;

  switch ( stato )
    {// vedi tabella nel pdf del motore passo passo
       case 0: Uscita(0,0,0,1); break;
       case 1: Uscita(0,0,1,1); break;
       case 2: Uscita(0,0,1,0); break; 
       case 3: Uscita(0,1,1,0); break;
       case 4: Uscita(0,1,0,0); break;
       case 5: Uscita(1,1,0,0); break;
       case 6: Uscita(1,0,0,0); break;
       case 7: Uscita(1,0,0,1); break;
       case MotoreOFF: //OFF
          Uscita(0,0,0,0); break;
    } 
   delay(1); //ritardo almeno 1 mS
}  

void RitardoAccensione()
{ //attesa prima di attivare il motore
  EseguiPasso(MotoreOFF); 
  for(int i=0; i<20; i++)
   {
     digitalWrite(13,HIGH);
     delay(250);
     digitalWrite(13,LOW);
     delay(250);
   } 
}  

void setup()
{
    pinMode(BUTTON, INPUT);     // imposta il pin digitale come input
    pinMode(IN1, OUTPUT); 
    pinMode(IN2, OUTPUT); 
    pinMode(IN3, OUTPUT); 
    pinMode(IN4, OUTPUT);
    pinMode(13,OUTPUT); 
    RitardoAccensione();  //5 secondi di pausa prima di iniziare
}

void loop()
{
int stato;  
val = digitalRead(BUTTON);  // legge il valore dell'input e lo conserva


  if (val == HIGH) {
     stato=0; //inizio da uno stato arbitrario
  digitalWrite(13,HIGH);  //acceso LED13
  for(int k=0; k<4; k++) //Rotazione Oraria
    {
    for (int i=0; i<1024; i++)  //90 gradi a ciclo
      { 
        EseguiPasso(stato);
        stato+=1; // avanza nella tabella
        if ((stato)>7) stato=0; 
      } 
    EseguiPasso(MotoreOFF);  
    delay(500);  // pausa di mezzo secondo
    }  
  delay(5000); // pausa di 1 secondo
  digitalWrite(13,LOW);  //spento LED13
  delay(1000);  
    
  }
  
  stato=0; //inizio da uno stato arbitrario
  digitalWrite(13,HIGH);  //acceso LED13
  for(int k=0; k<4; k++) //Rotazione Oraria
    {
    for (int i=0; i<1024; i++)  //90 gradi a ciclo
      { 
        EseguiPasso(stato);
        stato+=1; // avanza nella tabella
        
      }
      if ((stato)>7) stato=0; 
      else {
    EseguiPasso(MotoreOFF);  
    delay(500);  // pausa di mezzo secondo
    }  
  delay(5000); // pausa di 1 secondo
  digitalWrite(13,LOW);  //spento LED13
  delay(1000);  
    }
}

Ciao! Non capisco il problema ma... nella funzione void EseguiPasso(int stato) vedo un delay(1); tra un passo e l'altro, mi domandavo se forse serve un intervallo di tempo un po più lungo, esempio delay(100); per permettere al motore di eseguire fisicamente il passo.

Poi un osservazione, HIGH vale 1, LOW vale 0

Questa riga

if (i1==1) digitalWrite(IN1,HIGH); else digitalWrite(IN1,LOW);

Può essere scritta nella forma

digitalWrite(IN1,i1); // Se i1=1 come HIGH, se i1=0 come LOW

Anzi, e qui entrano le mie idee strane:
Secondo me quella funzione potrebbe essere ri scritta in modo da accettare in ingresso un unico byte la cui con formazione in bit sia quella che le uscite devono prendere, e le uscite stesse possono essere messe in un array di quattro elementi. La funzione è composta da un ciclo for nel quale si esegue una digitalwrite sul giusto del valore direttamente giusto (se serve la scrivo)
Già che stiamo semplificando mi è venuto in mente questo più veloce del quale credo ci sia solo la manipolazione diretta della porta, se fattibile. Ho anche un altro paio di idee per rendere il codice più snello ma al momento non è questo il problema.
Domanda: ma perché usi un Arduino mega, con 50 e passa pin, per comandarne soltanto sei?

marcoresind:
il programma non ha errori nell'ide, ma una volta caricato su un mega2560 non funziona

Eh, per favore definisci "non funziona".
"non funziona" significa solo che "non fa quello che voglio", per cui o ci descrivi cosa fai e cosa vedi, altrimenti è più complicato doverlo dedurre dal solo codice...

L'obiettivo finale consiste nel premere un pulsante connesso al pin 2, se premuto avvierà l'secuzione dei passi del motore che svolgerà un ciclo composto da 4 fermate (seggiolini), il progetto consiste in una ruota panoramica composta da 4 seggiolini corrispondenti a 0°,90°,180° e 270°. Giunto a 270° il motore compirà N giri da 360° per poi riprendere le fermate.
Con lo sketch postato tentavo il primo step riguardo le fermate, la ruota si ferma ogni 90°, il pulsante non funziona e a volte effettua un giro da 180° a 0° e quindi ricomincia.

Silente:
Anzi, e qui entrano le mie idee strane:
Secondo me quella funzione potrebbe essere ri scritta in modo da accettare in ingresso un unico byte la cui con formazione in bit sia quella che le uscite devono prendere, e le uscite stesse possono essere messe in un array di quattro elementi. La funzione è composta da un ciclo for nel quale si esegue una digitalwrite sul giusto del valore direttamente giusto (se serve la scrivo)
Già che stiamo semplificando mi è venuto in mente questo più veloce del quale credo ci sia solo la manipolazione diretta della porta, se fattibile. Ho anche un altro paio di idee per rendere il codice più snello ma al momento non è questo il problema.
Domanda: ma perché usi un Arduino mega, con 50 e passa pin, per comandarne soltanto sei?

utilizzo un mega perchè vorrei ampliare il progetto in seguito, ed un arduino uno r3 non basterebbe.

Ok. Anche se non influisce sull'esecuzione, inizia indentando meglio il codice (Ctrl-T nell'IDE di Arduino te lo fa lui) perché aiuta di più sia te sia noi a capire più rapidamente il codice.

A parte questo, tu dici che il pulsante "non funziona e a volte effettua un giro da 180° a 0° e quindi ricomincia", e queste cose in genere sono dovute a bounce del pulsante (tu non hai citato alcun debounce hardware, e via software hai solo i delay del movimento).

Poi hai detto che hai un pulsante pullup, ma nella setup() lo dichiari solo INPUT e non INPUT_PULLUP, hai messo tu una resistenza di pullup esterna? Ed il pulsante come lo hai connesso (tra pin e GND o pin e +5V)?

Poi un pulsante in pullup se non è premuto sarà sempre HIGH (come ti ha evidenziato torn24)mentre tu nel codice ha una if() che va invertita ossia non devi fare:

if (val == HIGH)

ma:

if (val == LOW)

(e questo è il principale "indiziato"...).

PS: a parte alcuni commenti che non coincidono con quello che fa, e che ti conviene sempre allineare, ad esempio:

RitardoAccensione(); //5 secondi di pausa prima di iniziare

ma nella funzione fai 20 cicli da 250+250ms=500ms quindi sono 10 secondi; :slight_smile:
Oltre all'evidente:

delay(5000); // pausa di 1 secondo

che sono 5... :wink:

docdoc:
Ok. Anche se non influisce sull'esecuzione, inizia indentando meglio il codice (Ctrl-T nell'IDE di Arduino te lo fa lui) perché aiuta di più sia te sia noi a capire più rapidamente il codice ...

Utilizzo la resistenza esterna, secondo la configurazione pull up, ovvero un pin del pulsante direttamente al positivo, il secondo con la resistenza al negativo ed in mezzo prelevo il pin.
ho appena modificato lo schetch:

const int  IN1 = 44;   // filo motore BLUE
const int  IN2 = 45;   // filo motore ROSA
const int  IN3 = 46;  // filo motore GIALLO
const int  IN4 = 47;  // filo motore ARANCIO

const int MotoreOFF = 99; // motore spento

#define BUTTON 2             // pin di input dove è collegato il pulsante
int  val = 0;

void Uscita( int i4, int i3, int i2, int i1)
{
  if (i1 == 1) digitalWrite(IN1, HIGH); else digitalWrite(IN1, LOW);
  if (i2 == 1) digitalWrite(IN2, HIGH); else digitalWrite(IN2, LOW);
  if (i3 == 1) digitalWrite(IN3, HIGH); else digitalWrite(IN3, LOW);
  if (i4 == 1) digitalWrite(IN4, HIGH); else digitalWrite(IN4, LOW);
}

void EseguiPasso(int stato)
{
  int i1, i2, i3, i4;

  switch ( stato )
  { // vedi tabella nel pdf del motore passo passo
    case 0: Uscita(0, 0, 0, 1); break;
    case 1: Uscita(0, 0, 1, 1); break;
    case 2: Uscita(0, 0, 1, 0); break;
    case 3: Uscita(0, 1, 1, 0); break;
    case 4: Uscita(0, 1, 0, 0); break;
    case 5: Uscita(1, 1, 0, 0); break;
    case 6: Uscita(1, 0, 0, 0); break;
    case 7: Uscita(1, 0, 0, 1); break;
    case MotoreOFF: //OFF
      Uscita(0, 0, 0, 0); break;
  }
  delay(1); //ritardo almeno 1 mS
}

void RitardoAccensione()
{ //attesa prima di attivare il motore
  EseguiPasso(MotoreOFF);
  for (int i = 0; i < 20; i++)
  {
    digitalWrite(13, HIGH);
    delay(250);
    digitalWrite(13, LOW);
    delay(250);
  }
}

void setup()
{
  pinMode(BUTTON, INPUT_PULLUP);     // imposta il pin digitale come input
  pinMode(IN1, OUTPUT);
  pinMode(IN2, OUTPUT);
  pinMode(IN3, OUTPUT);
  pinMode(IN4, OUTPUT);
  pinMode(13, OUTPUT);
  RitardoAccensione();  //5 secondi di pausa prima di iniziare
}

void loop()
{
  int stato;
  val = digitalRead(BUTTON);  // legge il valore dell'input e lo conserva


  if (val == LOW) {
    stato = 0; //inizio da uno stato arbitrario
    digitalWrite(13, HIGH); //acceso LED13
    for (int k = 0; k < 4; k++) //Rotazione Oraria
    {
      for (int i = 0; i < 1024; i++) //90 gradi a ciclo
      {
        EseguiPasso(stato);
        stato += 1; // avanza nella tabella
        if ((stato) > 7) stato = 0;
      }
      EseguiPasso(MotoreOFF);
      delay(500);  // pausa di mezzo secondo
    }
    delay(5000); // pausa di 5 secondo
    digitalWrite(13, LOW); //spento LED13
    delay(1000);

  }

  stato = 0; //inizio da uno stato arbitrario
  digitalWrite(13, HIGH); //acceso LED13
  for (int k = 0; k < 4; k++) //Rotazione Oraria
  {
    for (int i = 0; i < 1024; i++) //90 gradi a ciclo
    {
      EseguiPasso(stato);
      stato += 1; // avanza nella tabella

    }
    if ((stato) > 7) stato = 0;
    else {
      EseguiPasso(MotoreOFF);
      delay(500);  // pausa di mezzo secondo
    }
    delay(5000); // pausa di 1 secondo
    digitalWrite(13, LOW); //spento LED13
    delay(1000);
  }
}

caricato il programma, dopo il lampeggio del pin 13 come segnalazione, la ruota gira, circa 90° si ferma, 45 e 45 e si ferma..... dopo qualche secondo riparte e compie 3 rotazioni da 90, se premo il pulsante 4 giri da 45

>marcoresind: Quando si quota un post, NON è necessario riportarlo (inutilmente) tutto; bastano poche righe per far capire di cosa si parla ed a cosa ci si riferisce. Gli utenti da device "mobile" ringrazieranno per la cortesia :wink:

Guglielmo

P.S.: ho troncato io il quote del post qui sopra :slight_smile:

grazie del consiglio :slight_smile:

marcoresind:
Utilizzo la resistenza esterna, secondo la configurazione pull up, ovvero un pin del pulsante direttamente al positivo, il secondo con la resistenza al negativo ed in mezzo prelevo il pin.
ho appena modificato lo schetch:

Eh? Guarda che quello che hai descritto è un PULLDOWN mica un pullup! Se il pulsante porta il pin a +5V e la resistenza lo porta a GND, è esattamente il contrario di quello che hai detto.
Inoltre nel codice hai anche messo:

pinMode(BUTTON, INPUT_PULLUP); // imposta il pin digitale come input

Insomma, devi decidere se sto pulsante deve essere pullup o pulldown, ma UNA sola cosa! O lasci il codice con la INPUT_PULLUP e TOGLI la resistenza esterna, oppure rimetti INPUT ma allora nella if() devi confrontare con HIGH per determinare se il pulsante è premuto.

Sistema questa cosa, e poi descrivi passo-passo cosa succede e cosa fai, esempio:

  1. accendo Arduino ed il LED lampeggia
  2. finisce di lampeggiare e succede che...
  3. premo il pulsante una volta e...

docdoc:
oppure rimetti INPUT ma allora nella if() devi confrontare con HIGH per determinare se il pulsante è premuto.

Per quanto riguarda il primo step, hosostituito l'INPUT_PULLUP con INPUT ma non capisco come confrontare HIGH nella if

Pull-Up e Pull-Down sono due configurazioni per ancorare un pin configurato come ingresso ad
ad un determinato potenziale.

Pull-Up
La resistenza può essere interna (INPUT_PULLUP) o esterna (INPUT).

Pulsante non premuto: La digitalRead() restituisce HIGH.
Pulsante premuto: La digitalRead() restituisce LOW.

Pull-Down
La resistenza è esterna perché arduino non accetta configurazione con pulldown interna.

Pulsante non premuto: La digitalRead() restituisce LOW.
Pulsante premuto: La digitalRead() restituisce HIGH.

  if (val == LOW)  // entra nella if se val è LOW
  //   if (val == HIGH)  // entra nella if se val è HIGH

Ciao.

1 Like

marcoresind:
Per quanto riguarda il primo step, hosostituito l'INPUT_PULLUP con INPUT ma non capisco come confrontare HIGH nella if

Se il pulsante è quindi in "pull-down" devi mettere questa condizione:

...
  val = digitalRead(BUTTON);  // legge il valore dell'input e lo conserva

  if (val == HIGH) { // In "pull-down" il pulsante premuto va HIGH
...

Fatto questo, fai la prova e dacci l'esito (la descrizione passo-passo come ti ho chiesto nel mio precedente post):

Sistema questa cosa, e poi descrivi passo-passo cosa succede e cosa fai, esempio:

  1. accendo Arduino ed il LED lampeggia
  2. finisce di lampeggiare e succede che...
  3. premo il pulsante una volta e...

ragazzi posso lincare un mio video da youtube per farvi vedere i comportamenti del seguente programma?

fonte: video del sottoscritto, qui mostro il funzionamento della ruota con il programma modificato e ricaricato sulla scheda

Visto io video, carina la ruota con i pupiddi. :slight_smile:

Il problema è risaputo, il delay mal si sposa con eventi che possono accadere in qualunque momento come appunto la pressione di un pulsante. La CPU è una sola ed esegue una istruzione per volta, quando è impegnata ad eseguire delay(1000) le altre istruzioni a seguire non vengono eseguite appunto per 1 secondo.

Solitamente si usano i timer, gli interrupt e tutto quello di cui la MCU è dotata per rendere tutto reattivo.

Mi pare di avere capito che generi la sequenza per fare avanzare il motore passo passo, mentre dovresti usare una libreria la quale internamente usa un timer hardware per generare impulsi da inviare al driver step a cui è connesso il motore.

Poi se è richiesta interattività i delay di delay non ci deve essere l'ombra. Tutto viene fatto con millis() e una delle condizioni if (millis() - oldMillis() > 1000) { esegui questo }

Ciao.

marcoresind:
fonte: video del sottoscritto, qui mostro il funzionamento della ruota con il programma modificato e ricaricato sulla scheda

Programma modificato ok, ma COME? Se dopo il lampeggiamento iniziale inizia da solo a muoversi, entra nella prima if() quindi come è fatta sta if()? E il pulsante è quindi in pull-up (internal) o pull-down (resistenza esterna a massa)? Poi nel video (accendi due luci magari per farci vedere qualcosa...) parli dei "pulsanti", cos'è ora questo plurale?

Maurotec:
il delay mal si sposa con eventi che possono accadere in qualunque momento come appunto la pressione di un pulsante

Verissimo, ma per ora lui si limita (teoricamente) a premere un pulsante e far avanzare la ruota, non credo gli interessi per ora gestire letture di altri pulsanti per fare altre cose, ed alla fine del movimento premerà il nuovo pulsante, per cui per ora soprassiederei su questa cosa... :wink:

Mi pare di avere capito che generi la sequenza per fare avanzare il motore passo passo, mentre dovresti usare una libreria la quale internamente usa un timer hardware per generare impulsi da inviare al driver step a cui è connesso il motore.

Concordo pienamente, una volta che avrà capito inizialmente come far andare questo codice, poi magari usando la Stepper potrà anche migliorare il codice, così come se volesse introdurre altre azioni dovrebbe convertire il tutto con millis() invece dei delay...

docdoc:
if (val == HIGH) { // In "pull-down" il pulsante premuto va HIGH

Pull-down significa "tira giù": se dici così, significa che il pulsante tira giù...
Il discorso corretto è questo:
Con una resistenza di pull-down (la resistenza!), serve un pulsante che chiuda a +V; con una resistenza di pull-up (interna o esterna), invece, il pulsante deve chiudere a massa. Questa seconda configurazione può sembrare illogica, ma chiudere a massa offre diversi vantaggi e lo dimostra il fatto che le resistenze integrate sono di pull-up!

Datman:
Pull-down significa "tira giù": se dici così, significa che il pulsante tira giù...

Ma no, scusa, dobbiamo capirci con i termini: quando dico "configurato in pull-down" intendo dire che il pin ha una resistenza di "pull-down" quindi normalmente (se non premi il pulsante) leggi "LOW" perché è la resistenza che lo porta a GND, mentre quando lo premi va "HIGH" perché il pulsante lo porta a+5V.

Tu invece lo intendi per "dove tira il pulsante", cosa che non ho mai sentito/letto... :smiley: In genere se si parla di pin pull-down significa resistenza in pull-down, e viceversa per pull-up.

Quindi la sua if() che ho scritto (e relativo commento) per me è corretta... :wink:

const byte  IN1 = 44;   // filo motore BLUE
const byte  IN2 = 45;   // filo motore ROSA
const byte  IN3 = 46;  // filo motore GIALLO
const byte  IN4 = 47;  // filo motore ARANCIO

const byte MotoreOFF = 99; // motore spento
const byte ReadButton = 255;                            

#define BUTTON 2             // pin di input dove è collegato il pulsante
byte  val = 0;

byte mState = 0;
byte eseguiPassoState = ReadButton;
boolean buttonState = 0; 

byte buttonCounter = 10;
boolean command = false;

uint16_t nSteps = 0;

void Uscita( boolean i4, boolean i3, boolean i2, boolean i1)
{
  if (i1 == 1) digitalWrite(IN1, HIGH); else digitalWrite(IN1, LOW);
  if (i2 == 1) digitalWrite(IN2, HIGH); else digitalWrite(IN2, LOW);
  if (i3 == 1) digitalWrite(IN3, HIGH); else digitalWrite(IN3, LOW);
  if (i4 == 1) digitalWrite(IN4, HIGH); else digitalWrite(IN4, LOW);
}

void EseguiPasso(int stato)
{
  //int i1, i2, i3, i4;

  switch ( stato )
  { // vedi tabella nel pdf del motore passo passo
    case 0: Uscita(0, 0, 0, 1); break;
    case 1: Uscita(0, 0, 1, 1); break;
    case 2: Uscita(0, 0, 1, 0); break;
    case 3: Uscita(0, 1, 1, 0); break;
    case 4: Uscita(0, 1, 0, 0); break;
    case 5: Uscita(1, 1, 0, 0); break;
    case 6: Uscita(1, 0, 0, 0); break;
    case 7: Uscita(1, 0, 0, 1); break;
    case MotoreOFF: //OFF
      Uscita(0, 0, 0, 0); break;
       
  }
  buttonState = digitalRead(BUTTON);  // legge il valore dell'input e lo conserva   
  delay(1); //ritardo almeno 1 mS
}

void RitardoAccensione()
{ //attesa prima di attivare il motore
  EseguiPasso(MotoreOFF);
  for (int i = 0; i < 20; i++)
  {
    digitalWrite(13, HIGH);
    delay(250);
    digitalWrite(13, LOW);
    delay(250);
  }
}

void setup()
{
  pinMode(BUTTON, INPUT_PULLUP);     // imposta il pin digitale come input
  pinMode(IN1, OUTPUT);
  pinMode(IN2, OUTPUT);
  pinMode(IN3, OUTPUT);
  pinMode(IN4, OUTPUT);
  pinMode(13, OUTPUT);
  RitardoAccensione();  //5 secondi di pausa prima di iniziare
}

void loop()
{
  EseguiPasso(eseguiPassoState);
  if (buttonState && buttonCounter > 0) {
      buttonCounter--;
  }
  if (buttonCounter == 0 && !buttonState) {
      // il pulsante è stato premuto e rilasciato
      command ^= true;
      buttonCounter = 10;
      digitalWrite(13, HIGH); //accendo LED13
      delay(200);
  }  
  
  if (command) {
      if (nSteps < 1024 * 4) {
        nSteps++;
      
        eseguiPassoState++; // avanza nella tabella
        if ((stato) > 7) eseguiPassoState = 0;
      }
  } else {
      
      nSteps = 0;
      delay(200); 
      digitalWrite(13, HIGH); //accendo LED13
      delay(200);
      digitalWrite(13, LOW); //spengo LED13
  } 
    
}

All'accensione dovrebbe lampeggiare il led 13 fino a che non tieni premuto il pulsante fino che il led
13 si accende fisso, attendi 200ms e dovrebbe partire un ciclo 1024 * 4 step, ciclo che puoi fermare
tenendo premuto il pulsante fino che il led inizia a lampeggiare e via discorr
endo va avanti così;

Non testato ma scritto su un editor.
Ciao.