Uno Switch case che non mi fà dormire ( principiante )

Buon giorno,
anche quest' anno non ho resistito a giocare con Arduino e i trenini,
sono partito per tempo perchè mi servirebbe questo Sketch funzionante per Natale...
Comunque ho questo problema lo sketch parte con il case 1, passando sul Reed o "pulsante" è
lo stesso, poi fà quello che deve fare per poi essere una seconda volta sul reed e passare al
case 2, ancora una volta avanza con il ciclo passando sul Reed e "swiccia" al case 3...
E poi con una nuova sollecitazione del Reed invece di saltare il case 1 e andare al case 2,
fà come gli pare... Ora è un mese che ci provo da solo ma avrei bisogno di un'aiuto, o forse
miracolo! :smiley:
Il funzionamento sarebbe:
ho un trenino che Và dalla stazione A e arriva alla stazione B, il ciclo è sempre il solito,
tranne che per la partenza perchè facendo partire lo sketc ho pensato di far partire in treno
in un punto tra A e B in modo che la partenza fosse sempre verso B (Stazione di Monte) nello sketch.

Grazie a chi mi riesce a dare un'imbeccata! Marco


```cpp
// Esempio 10: conta quante volte il pulsante viene premuto, per un ciclo di 4 pressioni,
// ad ogni pressione del pulsante si accende un led per volta
// alla quinta pressione i led lampeggia per 5 volte in sequenza dal 4' al 1' led e poi si riavvia il ciclo.
// Il controllo del numero di volte in cui il pulsante viene premuto viene fatto con l'istruzione "case"

//Questo sketch l'ho modificato ed è l'ultimo che ho fatto, con l'aiuto della pagina di Maffucci,
//Vorrei sistemare un pochino lo sketch, togliere l'ultima parte anche se mi può tornare utile pensandoci...
//Sicuramente voglio mettere una rampa in accelerazione e una din decelerazione almeno ci provo. Marco.

#define BUTTON 2          // pin di input a cui è collegato il pulsante che diventereà il Reed Magnetico
#define DIREZIONE_M 11                              // LED collegato al pin digitale 11
#define DIREZIONE_V 10                              // LED collegato al pin digitale 10
//#define LED3 12                                   // LED collegato al pin digitale 12 ****questi led erano inseriti per controllo***
//#define LED4 13                                   // LED collegato al pin digitale 13 ****Magari li attivo per semaforo stazione****

// Variabili
int ContatorePulsantePremuto = 0;                   // conta il numero di volte che il pulsante è premuto buttonPushCounter
int StatoPulsante = 0;                              // stato corrente del pulsante
int StatoPulsantePrecedente = 0;                    // stato precedente del pulsante

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

  pinMode(DIREZIONE_M, OUTPUT);                     // imposta il pin digitale come output
  pinMode(DIREZIONE_V, OUTPUT);                     // imposta il pin digitale come output
  //pinMode(LED3, OUTPUT);                            // imposta il pin digitale come output
  //pinMode(LED4, OUTPUT);                            // imposta il pin digitale come output
  Serial.begin(9600);                               // apre la porta seriale e la inizzializza a 9600 bps
}

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

  if (StatoPulsante != StatoPulsantePrecedente) {   // compara lo stato del pulsante attuale con il precedente
    if (StatoPulsante == HIGH) {                    // se lo stato è cambiato incrementa il contatore
      // se lo stato corrente è alto, il pulsante è passato da off a on
      ContatorePulsantePremuto++;

      switch (ContatorePulsantePremuto) {
        case 1:  
          Serial.println("SKETCH Nome: Disperazione");          

          Serial.println(ContatorePulsantePremuto, DEC);       // stampa il numero di volte che il pulsante è stato premuto
          Serial.println("Il Treno si avvia verso la S.Monte");
          analogWrite(DIREZIONE_M, 10); //Partenza gioco del treno, direzione verso la S. Monte
          Serial.println("Modulazione analogwrite su PIN 11");
          Serial.println("Manetta al 10%");
          delay(5000);
          Serial.println("Manetta al 20%");
          analogWrite(DIREZIONE_M, 20); //Pin 11
          delay(5000);
          Serial.println("Manetta al 40%");
          analogWrite(DIREZIONE_M, 40);
          delay(5000);
          Serial.println("Manetta al 75%");
          analogWrite(DIREZIONE_M, 75);
          delay(5000);
          Serial.println("Manetta al 100%");
          analogWrite(DIREZIONE_M, 100);
                                         
          
          break;
        
        case 2:  // controlla se il Reed  è stato premuto due volte
          Serial.println("2");                               
          Serial.print("Arrivo alla S.Monte Treno Locale proveniente da S.Valle  ");    // stampa sulla console "numero di volte tasto premuto:"
          Serial.println(ContatorePulsantePremuto, DEC);       // stampa il numero di volte che il pulsante è stato premuto
          digitalWrite(DIREZIONE_M, LOW);// spegne il LED11
          
          delay(10000);                                 
          digitalWrite(BUTTON, LOW);
          Serial.println("Si ferma alla S.Monte");//sosta stazione
          Serial.println("si disattiva il Reed");
          delay(12000);

          Serial.println("Parte il Treno verso S.Valle");
          analogWrite(DIREZIONE_V, 10); //riparte verso la S. Monte
          Serial.println("Modulazione analogwrite su PIN 10");
          Serial.println("Manetta al 10%");
          delay(5000);
          analogWrite(DIREZIONE_V, 20);
          Serial.println("Manetta al 20%");
          delay(5000);
          analogWrite(DIREZIONE_V, 40);
          Serial.println("Manetta al 40%");
          delay(5000);
          analogWrite(DIREZIONE_V, 75);
          Serial.println("Manetta al 75%");
          delay(5000);
          Serial.println("Manetta al 100%");
          analogWrite(DIREZIONE_V, 100); //Velocità al 100% Verificare se pin analogico!!!!!!

          digitalWrite(BUTTON, HIGH);
          Serial.println("Fine Pausa reed di 32000 millisecondi");// stampa sulla console "off"

          break;

        case 3:  // controlla se il Reed è stato premuto tre volte
          Serial.println("3");                                // stampa sulla console "on"
          Serial.print("Arrivo alla S.Valle Treno Locale proveniente da S.Monte ");    // stampa sulla console "numero di volte tasto premuto:"
          Serial.println(ContatorePulsantePremuto, DEC);       // stampa il numero di volte che il pulsante è stato premuto
          Serial.println("Si ferma il Treno a S. Valle");
          digitalWrite(DIREZIONE_V, LOW);
          delay(10000); //sosta stazione
          Serial.println("si disattiva il Reed");
          Serial.println("Parte il Treno verso S.Monte");
          
          digitalWrite(BUTTON, LOW);
          delay(12000);
          analogWrite(DIREZIONE_M, 10); //riparte verso la S. Monte
          Serial.println("Manetta al 10%");
          delay(5000);
          analogWrite(DIREZIONE_M, 20);
          Serial.println("Manetta al 20%");
          delay(5000);
          analogWrite(DIREZIONE_M, 40);
          Serial.println("Manetta al 40%");
          delay(5000);
          analogWrite(DIREZIONE_M, 75);
          Serial.println("Manetta al 75%");
          delay(5000);
          analogWrite(DIREZIONE_M, 100); //Velocità al 100% Verificare se pin analogico!!!!!!
          Serial.println("Manetta al 100%");

          digitalWrite(BUTTON, HIGH);
          Serial.println("Fine Pausa reed di 32000 millisecondi");
          break;





        case 4:  // controlla se il Reed  è stato premuto 4 torna a case 2
          if (ContatorePulsantePremuto > 3) {
          ContatorePulsantePremuto = 0;
          StatoPulsante = 0;
          StatoPulsantePrecedente = 0; // NON RIESCO A FAR COMINCIARE DAL CASE2
          break;
      }
    }
  }}}

  
  

Dovresti indentare correttamente il codice e vedrai che le magagne saltano fuori molto più facilmente.

Sarebbe anche utile se tutte le operazioni che fai in ciascuno stato le riorganizzi in delle funzioni, così lo switch/case rimane più leggibile.

Infine, hai cablato il pulsante a pullup, ma vai a testarne lo stato HIGH.
Con un pulsante a pullup, quando premi lo stato attivo è LOW.

Aggiungo inoltre che con tutti quei delay infiniti che hai inserito, questo firmware è molto poco "reattivo".
Una volta che hai premuto il pulsante ed avviato la sequenza, il microcontrollore non prenderà altri input fino a quando lo step non viene concluso

Se deve tornare al 2, perché imposti 0? :wink:

Grazie Cotestatnt,

ho aggiunto tutti quei delay perchè mi è comodo che ci siano delle piccole rampe,
per me facilmente gestibili senza usare millis che non riesco a usare come vorrei...
Anche semplificado lo sketch, fà le bizze.
Ho provato a sostituire il valore di " ContatorePulsantePremuto = 2 " come suggerito da
Claudio_FF ma lo schetch "swiccia" in maniera autonoma.
Se provo a togliere il "pulup" il (pulsante che uso al posto di un Reed momentaneamente )
lo sketch dorme.

Sono settimane che provo leggo e rileggo i libri ma non riesco a venirci fuori.

Marco

L'uso di delay() condiziona in modo determinante il comportamento dell'algoritmo. Gli algoritmi che usano delay() saranno sempre sequenziali, dove anche il delay() è un elemento della sequenza. Le difficoltà che incontri sono comuni a tutti gli utenti anche non principianti.
Io ancora non sono riuscito a mettere in sequenza i concetti che il principiante deve affrontare per uscire dal modo vincolante di pensare che lo porta ad usare delay().
La traduzione di delay è "ritardare" secondo google translate, traduzione che è aderente al compito svolto dalla funzione delay. In effetti delay ritarda di T tempo l'esecuzione della prossima istruzione e di tutte quelle a seguire.

Abbiamo inventato i timer proprio per evitare di stare davanti al forno osservando tutti gli istanti del processo di cottura fino al termine della cottura. Durante il tempo trascorso osservando il processo di cottura non possiamo fare altro (neanche grattarsi la testa) e questo comportamento equivale a delay(25minuti). Durante i 25 minuti se squilla il telefono noi non lo sentiamo neanche perché siamo impegnati nel delay. In verità durante il delay anche i nostri sensi incluso la vista sono bloccati, per cui non possiamo neanche osservare il processo di cottura.

Ora a me risulta evidente che il delay non è la strategia giusta, ma non so come fare per farti rendere conto di ciò. Devi essere tu a trovare un modo di pensare differente che non si basi su delay ma su i timer.

Potrei mostrarti una applicazione funzionante al simulatore dove se aggiungi un delay(10000) l'applicazione smette di funzionare o meglio si comporta in modo non reattivo tanto da risultare non usabile.

Le conseguenze di delay non le trovi descritte in alcun libro, devi (imperativo) nel senso che devi importi un modo differente di ragionare e questo modo non dovrà basarsi sul delay.

Ciao.

Rieccomi,
non sò perchè non riesco a usare millis, ho provato a inserire delle rampe che accelerano
da 0 a 100% per accendere led o far girare piccoli motori DC ma solo con curve di durata
breve...
Nella mia testa non è sbagliato( e quà le battute si fanno largo :smiley: ) inserire dei ritadi, non riesco a capire perchè i ritardi non rimangono isolati nel singolo "Switch Case".

Sono riuscito a far parzialmente a fargli fare quello che volevo (lo sketch) ma mi continua a
non saltarmi il case 1.
Sono anche sincero la struttura del software non mi è tanto chiara, avrei centomila domande
e pian piano mi diverto a scoprirle.

P.S. Ricordo che sono un'autodidatta del '76. Ciao Marco
P.S.2 L'uso del delay nel principiante è causato dal classico esempio del semaforo che
per me e altri penso, che venga preso da esempio per creare cose più bizzarre oppure
scrivi mille if e non sai più che cosa stai scrivendo ( io ).

Non c'è modo di associare delay ad un case n.

pinMode(BUTTON, INPUT_PULLUP);

Ciò vuole dire che digitalRead restituisce HIGH. Quando premi restituisce LOW.

if (StatoPulsante != StatoPulsantePrecedente) { 

Il valore di StatoPulsantePrecedente è zero (LOW).
if (HIGH != LOW) {

Ciao.

... intervengo solo per ribadire un concetto ... il delay() è una funzione che FERMA il tuo programma (quindi NON può fare altro) per tutto il tempo che tu imposti nella chiamata ... quindi, quando il programma lo incontra, si inchioda li fino a quando non è passato il tempo che hai indicato.

Detto questo se lo metti all'interno di uno dei "case:" lo incontrerà solo quando quel "case:" viene eseguito e si fermerà li per tutto il tempo previsto.

A te ora capire se ne tuo programma una cosa del genere crea problemi o meno ...
... personalmente NON demonizzo il delay() come il "male assoluto", ma è ovvio che lo uso solo e soltanto dove il mio programma NON ha altro da fare e si può FERMARE, altrimenti, se invece devo far passare del tempo per una certa cosa, ma intanto devo fare anche altre cose, ovviamente NON posso usare il delay() e devo trovare un qualche altro sistema per temporizzare le mie attività ... :wink:

Guglielmo

Non è il male assoluto quando sai ragionare anche senza delay. Cioè il fatto che in un programma compaia un delay, non vuole dire che il programmatore ha ragionato basandosi esclusivamente su delay.
La funzione delay(t) è l'unica che impiega t tempo per essere eseguita. :wink:

Ciao.

:grin: :grin: :grin:

Guglielmo

Se il pulsante fosse in pullup (che tira su, verso il positivo), sarebbe giusto verificare lo stato HIGH per vedere quando è premuto. Invece nel setup viene attivata la resistenza di pullup, il pulsante è collegato verso massa e quando è premuto si legge LOW.

Ciao, Marco!
Come va? Natale si avvicina, eh?... :slight_smile:
Per eliminare i delay() potresti fare così:

uint32_t t0;
uint8_t contatore = 0;

***loop:*** 
bool PulsantePremuto = !digitalRead(BUTTON); // Il pulsante chiude a massa.
if (PulsantePremuto) { // Se è premuto:
  if (!PulsantePremutoPrecedente) { // Se è stato premuto adesso:
  PulsantePremutoPrecedente=HIGH;
  contatore++;
  }
}
else PulsantePremutoPrecedente=LOW;

switch (contatore) {
case 1:  
          t0=millis();
          contatore=2;
break;
case 2:  
          Serial.println("SKETCH Nome: Disperazione");          
          Serial.println('1'); // stampa il numero di volte che il pulsante è stato premuto
          Serial.println("Il Treno si avvia verso la S.Monte");
          analogWrite(DIREZIONE_M, 10); //Partenza gioco del treno, direzione verso la S. Monte
          Serial.println("Modulazione analogwrite su PIN 11");
          Serial.println("Manetta al 10%");
          contatore=3;
break;
case 3:
          if(millis()-t0>5000) {t0=millis(); contatore=4;}
break;
case 4:
          Serial.println("Manetta al 20%");
          analogWrite(DIREZIONE_M, 20); //Pin 11
          contatore=5;
break;
case 5:
          if(millis()-t0>5000)  {t0=millis(); contatore=6}
break;
case 6:
          Serial.println("Manetta al 40%");
          analogWrite(DIREZIONE_M, 40);
          contatore=7;
break;
case 7:
          if(millis()-t0>5000)  {t0=millis(); contatore=8}
break;
case 8:
          Serial.println("Manetta al 75%");
          analogWrite(DIREZIONE_M, 75);
          contatore=9;
break;
case 9:
          if(millis()-t0>5000)  {t0=millis(); contatore=10}
break;
case 10:
          Serial.println("Manetta al 100%");
          analogWrite(DIREZIONE_M, 100);
 break;
}

Metti un condensatore da 100nF...1uF in parallelo al pulsante.

NOTA: Per come è realizzato, le temporizzazioni non sono precise al millisecondo, ma per
questo scopo vanno benissimo ugualmente.

Buon giorno a tutti ( se leggete di giorno ),

grazie Dataman, gentile come sempre!

Questa notte tanto per cambiare, mi incaponito e ho fatto le ore piccole e stamane
invece di essere concentrato con il lavoro penso a "millis"... Una volta pensavo a cose serie (tipo le ragazze di baywatch) :smiley:

Ho riscritto il codice o meglio ho fatto raglia e incolla e sono arrivato a uno sketch che ferebbe proprio quello che voglio tranne che le pause e altri piccoli dettagli che inserirò.

// Esempio 9: conta quante volte il pulsante viene premuto, per un ciclo di 4 pressioni,
// ad ogni pressione del pulsante si accende un led per volta
// alla quinta pressione il primo led lampeggia per 10 volte.
// Il controllo del numero di volte in cui il pulsante viene premuto viene fatto con l'istruzione "case"

#define BUTTON 4          // pin di input a cui è collegato il pulsante che diventereà il Reed Magnetico
#define DIREZIONE_M 11                              // LED collegato al pin digitale 11
#define DIREZIONE_V 10                              // LED collegato al pin digitale 10
//#define LED3 12                                   // LED collegato al pin digitale 12 ****questi led erano inseriti per controllo***
//#define LED4 13 

uint32_t t0;
uint8_t contatore = 0;

// Variabili
int ContatorePulsantePremuto = 0;                   // conta il numero di volte che il pulsante è premuto buttonPushCounter 
int StatoPulsante = 0;                              // stato corrente del pulsante
int StatoPulsantePrecedente = 0;                    // stato precedente del pulsante

void setup() {
  pinMode(BUTTON, INPUT);                    // imposta il pin digitale come output
   pinMode(DIREZIONE_M, OUTPUT);                     // imposta il pin digitale come output
  pinMode(DIREZIONE_V, OUTPUT);                     // imposta il pin digitale come output
  //pinMode(LED3, OUTPUT);                            // imposta il pin digitale come output
  //pinMode(LED4, OUTPUT);                            // imposta il pin digitale come output
  Serial.begin(9600);                               // apre la porta seriale e la inizzializza a 9600 bps
}

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

  if (StatoPulsante != StatoPulsantePrecedente) {   // compara lo stato del pulsante attuale con il precedente
    if (StatoPulsante == HIGH) {                    // se lo stato è cambiato incrementa il contatore
      // se lo stato corrente è alto, il pulsante è passato da off a on
      ContatorePulsantePremuto++;
       

      switch (ContatorePulsantePremuto) {
      case 1:  // controlla se il pulsante è stato premuto una volta
        Serial.println("Sketch Disperato");                                // stampa sulla console "on"
        Serial.print("numero di volte tasto premuto:  ");    // stampa sulla console "numero di volte tasto premuto:"
        Serial.println("Il Treno si avvia verso la S.Monte");
        Serial.println(ContatorePulsantePremuto, DEC);       // stampa il numero di volte che il pulsante è stato premuto
        analogWrite(DIREZIONE_M, 10); //Partenza gioco del treno, direzione verso la S. Monte 
        
        //if(millis()-t0>1000) {
        //analogWrite(DIREZIONE_M,0);}
        
        
        Serial.println("Avvio Ferrovia Tasto Start");                               // stampa sulla console "off"
        break;
      case 2:  // controlla se il pulsante è stato premuto due volte
        Serial.println("on");                                // stampa sulla console "on"
        Serial.println("Parte da M");
        Serial.print("numero di volte tasto premuto:  ");    // stampa sulla console "numero di volte tasto premuto:"
        Serial.println(ContatorePulsantePremuto, DEC);       // stampa il numero di volte che il pulsante è stato premuto
        analogWrite(DIREZIONE_M, 0);                            // spegne il LED  
        analogWrite(DIREZIONE_V, 10);
       // accende il LED  
        
        break;
      case 3:  // controlla se il pulsante è stato premuto tre volte
        Serial.println("on");                                // stampa sulla console "on"
        Serial.println("Parte da V");
        Serial.print("numero di volte tasto premuto:  ");    // stampa sulla console "numero di volte tasto premuto:"
        Serial.println(ContatorePulsantePremuto, DEC);       // stampa il numero di volte che il pulsante è stato premuto
        analogWrite(DIREZIONE_V, 0);                             // spegne il LED  
        analogWrite(DIREZIONE_M, 10);                            // accende il LED  
       
      
        
      }
    } 
  }

  // salva lo stato corrente nella variabile che indica lo stato precedente per il loop successivo 
  StatoPulsantePrecedente = StatoPulsante;

  // controlla se il pulsante è stato premuto quattro volte se vero indica che è finito il ciclo

  // vengono inizializzate nuovamente le variabili
  // si riavvia il ciclo

  if (ContatorePulsantePremuto > 2) {
    ContatorePulsantePremuto = +1;
                            
  }
}

Più semplice, con meno if annidati:

void loop() {

  bool StatoPulsante = (digitalRead(BUTTON) == LIVELLO_PREMUTO);
  bool IstantePressione = (StatoPulsante && !StatoPulsantePrecedente);
  StatoPulsantePrecedente = StatoPulsante;

  if (IstantePressione) {
      ContatorePulsantePremuto++;
      ....

Probabilmente in questo caso specifico l'uso di delay() così lunghi non è troppo deleterio in quanto la sequenza del treno quella è e devi comunque aspettare che venga conclusa prima di avviare la successiva.

Però di sicuro il fatto che ti stai interrogando sull'argomento al fine di usare un approccio più "smart" è molto positivo :smiling_face:

Un possibile modo per evitare di usare ritardi cosi lunghi è spezzettare il tuo switch case in tanti sottostati ed inserendo uno stato di attesa dove andari a controllare il tempo trascorso (ho fatto la cosa solo per la sequenza 1)

È ciò che ho fatto nel #12! :slightly_smiling_face:
Mi sembra che in myDelay manchi qualcosa..

:rofl: :rofl: :rofl:

Eh, ma del resto con lo sketch impostato in questo modo non vedo molte altre alternative..

No, no funziona. Ho messo tutto nel simulatore proprio per poterlo provare rapidamente.

Cavolo!

Complimenti per l'aiutissimo! Non vedo l'ora di montare la nuova vetrina Natalizia, e preparati Dataman, con il nuovo cell i miei video saranno ancora più HD.

Una cosa che però non riesco a capire e che vorrei approfondire, non capisco cos'è questa
funzione " uint32_t " è una cosa che non ho mai usato. :frowning:

Vi ringrazio ancora molto, ormai sono nel turbine e così anche stanotte farò pochi millis di sonno! HAhaha!

Vi aggiorno e ancora grazie Marco.

E' una "scorciatoia" per definire un unsigned int lungo 32 bit (ovvero un unsigned long)

Allo stesso modo puoi usare int8_t, uint8_ e, int16_t, uint16_t

Siccome la lunghezza dei tipi dati int cambia in funzione della piattaforma usata (ad esempio nei microcontrollori a 32 bit di solito un int è da 4 byte invece che da 2) ho preso l'abitudine di definire le variabili in questo modo esplicito cosi da non incappare in stupidi errori dovuti al tipo di dati sbagliato.

1 Like

Io ti consiglio di leggere un libro per principianti di programmazione.
Mi è capitato di dare una occhiata al libro: "Programmare: Impara a scrivere qualsiasi tipo di software" di Paolo Aliverti. Ad esempio su amazon è a circa 20 euro.
C'e' anche un bel capitolo su programmare una macchina a stati finiti.
Il tipo ha anche un canale Youtube con dei video interessanti su Arduino e sulla programmazione

P.S. a me non viene nulla in tasca per quel libro. Non è pubblicità la mia ma solo un consiglio.