Aiuto per un vecchio appassionato

Ciao a tutti,

sono un'appassionato e ogni tanto mi diletto con il modellismo e anche con dei semplici (ebbenesì) copia incolla per fare dei giochini con i miei bambini...

Ora volevo fare qualcosa di diverso ma sono un pò di giorni che mi sono arenato e Vi chiedo cortesemente un' aiuto perchè non sò come fare...

Per Natale volevo fare con un trenino un tracciato ovale semplice semplice e dare un tempo di riposo in galleria al treno facendolo passare su un reed, e dopo alcuni min farlo ripartire...

Ma non riesco a farlo da solo.

Grazie a chi mi aiuterà, Marco.

Switch_Case_bottone_Trenino.ino (2.1 KB)

mmmm ho dato un'occhiata veloce al programma.
Quando arrivi in galleria e lo switch o chi per esso viene attivato devi fermare il treno e cominciare a contare il tempo che passa.... passato il tempo previsto far ripartire il treno.
quindi ti serve usare il "fatidico" millis() !

Per capire come funziona e come applicare la funzione millis(), puoi studiare prima QUI, poi QUI ed infine leggere anche QUI e QUI e questo post di Claudio_FF... vedrai che ti sarà tutto più chiaro

Grazie Patrick,

ma leggendo e rileggendo il forum, non posso fare da me, cercherò qualcuno che magari sotto compenso mi possa realizzare la cosa.

Ci rinuncio non riesco a ricordarmi più nulla, non voglio fare pena a nessuno, ma è la verità, non posso chiedere un aiuto se non mi ricordo più come si usa.

Ritorno alle mie cose quando mi serviranno copia e incolla e pazienza.

Grazie e buon divertimento a tutti, Marco.

Un uso di millis() per attendere 3 minuti di treno fermo.

Se hai bisogno di arrestare il treno o farlo ripartire in altre parti del programma, devi mettere stato=0 IL TRENO PARTE, stato=1 IL TRENO SI FERMA.

// descrizione: Partenza Treno, si spegne la croce di S.andrea, il treno rientra in galleria preme un contatto e si interrompe la corsa al treno, 
//si riaccende la Croce di S.Andrea e dopo 3 min riparte il treno




const int  BUTTON = 2;    // pin di input a cui è collegato il pulsante
const int LED_A = 13;       // led A croce di S.Andrea
const int LED_B = 11;       // led B croce di S.Andrea 
const int TRENO = 10;       // Treno collegato al pin digitale 13
// Variabili globali (tutti interi)
int statoButton     = 0;      // stato del pulsante (inizialmente non premuto)
int lastStatoButton = 0;      // ultimo stato del pulsante (per ora non premuto)
int countButton     = 0;      // Conteggio del bottone

unsigned long tempo=0;
byte stato=0; // Se stato vale zero il treno funziona, se stato vale 1 il treno si ferma

// Avvio dell'applicazione


void setup()
{
  pinMode(LED_A, OUTPUT);       // imposta il pin digitale come output
  pinMode(LED_B, OUTPUT);
  pinMode(TRENO, OUTPUT);
  pinMode(BUTTON, INPUT);     // imposta il pin digitale come input
}

// Avvio del loop
void loop()
{

  // Verifico se l'utente ha premuto il bottone ??? 
  if(digitalRead(BUTTON))
  {
    // Aspetto 15ms per far alzare il dito all'utente
    delay(15);
    // Cambio l'ultimo stato del bottone
    if(lastStatoButton==0) lastStatoButton=1;
    else lastStatoButton=0;
    // Aumento il count del bottone
    if(countButton<=3) countButton=countButton+1;
    else countButton=0;
  }

  // In base allo stato del bottone scelgo l'azione del led
  switch (countButton)
  {
    // Led lampeggia ogni mezzo secondo
  case 1:
    digitalWrite(LED_A, HIGH);  // accende il LED
    delay(500);              // aspetta un secondo
    digitalWrite(LED_B, LOW);   // spegne il LED
    delay(500);              // aspetta un secondo
     digitalWrite(LED_B, HIGH);  // accende il LED
    delay(500);              // aspetta un secondo
    digitalWrite(LED_A, LOW);   // spegne il LED
    stato=1; // Ferma il treno
	tempo=millis(); // Inizia il conteggio
     
    break;
// quando il treno arriva in galleria c'è lo switch o tasto ma la funzione dovrebbe portarmi il riavvio dell loop come faccio???
  }
  if(stato){// Ferma il treno se stato vale 1
  
      digitalWrite(LED_A, LOW);
      digitalWrite(LED_B, LOW);
      digitalWrite(TRENO, LOW); 
  
  }else{
	  
	  digitalWrite(TRENO, HIGH); // Se stato vale 0 il treno è in moto
  }
  
  if(stato==1 && millis()-tempo >= (3*60*1000)){
	  /* Se stato è uguale a uno e sono passati 
	     tre minuti, mette stato a zero e quindi accende il treno */
       stato=0;
  }
}

Ciao, Marco.
Perché conti il numero di pressioni del pulsante? Vedo che poi metti solo un case 1... Che cosa vuoi fare?
Per quello che ho capito, farei così:

// Descrizione: Partenza Treno, si spegne la croce di S.andrea, il treno rientra in galleria,
// preme un contatto e si interrompe la corsa al treno, 
// si riaccende la Croce di S.Andrea e dopo 3 min. riparte il treno.

const int  BUTTON = 8;   // pin di input a cui è collegato il pulsante
const int LED_A = 13;     // led A croce di S.Andrea
                                  // N.B.: Il pin 13 lampeggia all'accensione per la presenza del bootloader.
const int LED_B = 11;     // led B croce di S.Andrea 
const int TRENO = 10;    // Treno collegato al pin digitale 10

// Variabili globali (tutti interi)
byte statoButton     = 0;  // stato del pulsante (inizialmente non premuto)
byte lastStatoButton = 0; // ultimo stato del pulsante (per ora non premuto)
byte countButton     = 0;  // Conteggio del bottone
byte lastCountButton = 0;
unsigned long t1; // millis() per i 3 minuti di attesa.

void(* Riavvia)(void)=0; // Dove scriverai "Riavvia();" verrà riavviato il loop.

void setup()
{
pinMode(0,OUTPUT); // Segmento A di un display ad anodo comune via 1,5kOhm circa.
pinMode(1,OUTPUT); // Segmento B di un display ad anodo comune via 1,5kOhm circa.
pinMode(2,OUTPUT); // Segmento C di un display ad anodo comune via 1,5kOhm circa.
pinMode(3,OUTPUT); // Segmento D di un display ad anodo comune via 1,5kOhm circa.
pinMode(4,OUTPUT); // Segmento E di un display ad anodo comune via 1,5kOhm circa.
pinMode(5,OUTPUT); // Segmento F di un display ad anodo comune via 1,5kOhm circa.
pinMode(6,OUTPUT); // Segmento G di un display ad anodo comune via 1,5kOhm circa.
pinMode(7,OUTPUT); // Punto  (.) di un display ad anodo comune via 1,5kOhm circa.
  
pinMode(LED_A, OUTPUT);
pinMode(LED_B, OUTPUT);
pinMode(TRENO, OUTPUT);
pinMode(BUTTON, INPUT);
pinMode(BUTTON, INPUT_PULLUP); // Resistenza di pullup interna per mettere il pulsante verso massa.
                               // Il pulsante verso massa è anche comodo perché non devi portare fuori il +V.
}                              // Mettere un condensatore da 10uF tra il pin di ingresso e massa come antirimbalzo.

void loop()
{
if(lastStatoButton==1 && !digitalRead(BUTTON)) // Se il pulsante non era premuto e adesso è premuto (chiude a massa)
  {
    lastStatoButton=0;  // 0 = premuto
    if(countButton<=3) countButton+=1; // Fino a 3 incrementa di uno.
    else countButton=0;
  }
if(digitalRead(BUTTON)==1) lastStatoButton=1; // Se il pulsante viene lasciato, ne prende nota.

// In base allo stato del bottone scelgo l'azione del led
switch(countButton)
  {
  case 1: // Se il pulsante è stato premuto 1 volta:
    {
    if(countButton==1 && lastCountButton!=1) // Se è diventato 1 adesso
      {
      lastCountButton=1;
      //      .gfedcba
      PORTD=0b11111001; // Visualizza "1" sul display.
      t1=millis(); // Si segna il tempo in t1.   
      }  
    if(millis()-t1<180000)
      {   // Fa lampeggiare i LED A e B in base al resto di millis() diviso 2000:
      if(millis()%2000<1000) {digitalWrite(LED_B, LOW); digitalWrite(LED_A, HIGH);} // spegne il LED B e accende il LED A.
      else                   {digitalWrite(LED_A, LOW); digitalWrite(LED_B, HIGH);} // spegne il LED A e accende il LED B.
      }
    else
      {
      digitalWrite(LED_A, LOW);
      digitalWrite(LED_B, LOW);
      digitalWrite(TRENO, HIGH); // dopo 3 min parte il treno.
       }
    } // END case 1
  case 2:
    {
    if(countButton==2 && lastCountButton!=2) // Se è diventato 2 adesso
      {
      lastCountButton=2;
      //      .gfedcba
      PORTD=0b10100100; // Visualizza "2" sul display.
      // ... ... ...
      }
    } // END case 2
  case 3:
    {
    if(countButton==3 && lastCountButton!=3) // Se è diventato 3 adesso
      {
      lastCountButton=3;
      //      .gfedcba
      PORTD=0b10110000; // Visualizza "3" sul display.
      // ... ... ...
      }
    }  // END case 3
  case 4:
    {
    if(countButton==4 && lastCountButton!=4) // Se è diventato 4 adesso
      {
      lastCountButton=4;
      //      .gfedcba
      PORTD=0b10101100; // Visualizza "4" sul display.
      // ... ... ...
      }
    }  // END case 4
  } // END switch
              
  // quando il treno arriva in galleria c'è lo switch o tasto ma la funzione dovrebbe portarmi il riavvio dell loop come faccio???
  // Vedi quanto scritto poco prima del setup().

} // END loop()

Ho previsto anche un display a 7 segmenti ad anodo comune per indicare lo stato delle pressioni del pulsante (1...4).

Buona sera,

dopo un pò di prove fatte in modo empirico e guardando altre prove che avevo fatto sono riuscito a far lampeggiare correttamente la Croce di S.Andrea ma non a far funzionare lo sketch nel modo che mi serviva... A questo punto provo a sforzarmi un pò di più. Tra un cliente e un' altro però se entro il giorno che dovrò montare la vetrina vi dovrò rompere ancora.

Il treno non parte da solo dopo 3 min, e se modifico i valori avvio arduino, parte il treno lampeggia la croce di S.Andrea e non si ferma più.

Giuro metto in vetrina Grazie Forum Arduino! E posto la foto.

Grazie Datman ma per me è arabo ciò che hai scritto, troppo diffcile... Mi sono diplomato come peritomeccanico nel '98 al serale... Mi ricordo a malapena il quadrato di un binomio...

Grazie Mille torn24 dell'aiuto non sperato, Marco.

Atrain1.ino (2.46 KB)

Che cosa è troppo difficile?... Il display è in più. Se non lo monti, il resto funziona ugualmente. :slight_smile:

Il pulsante, anziché tra l'ingresso e il positivo, devi metterlo tra l'ingresso e massa. D'altra parte, se metti il pulsante verso il positivo devi mettere una resistenza esterna verso massa. Mettendo il pulsante che chiude a massa, invece, usiamo la resistenza già disponibile dentro al microcontrollore atmega328p.

Per risolvere il problema dei rimbalzi del pulsante, prendi un comune condensatore elettrolitico da circa 10 microfarad 16 volt (o 25 volt o 50 volt o quello che è) e lo colleghi tra l'ingresso e massa, in parallelo al pulsante, con il + sull'ingresso e il - a massa.

Scusami,

ma sono andato in crisi dopo che ho visto il codice così complicato... In realtà il pulsante lo cambierò con un reed magnetico, perchè sotto la locomotiva ci metterò un magnete.

Ora mi faccio coraggio :o Marco.

Che cosa è troppo difficile?.

Datman Non sono critiche solo un osservazione!

L'idea di arduino è rendere semplice o meglio più semplice l'uso di un microcontrollore!
Per cui nel linguaggio semplificato di arduino non si usano registri, porte, puntatori a funzione e valori binari di bit :slight_smile:
Mentre nel tuo codice ne fai uso, programmare un altro microcontrollore in questo modo è la norma, ma
l'idea di arduino era di avere un astrazione da questo modo di programmare :slight_smile:

Per cui un utente medio di arduino non capisce il codice e quindi lo trova difficile :slight_smile:

Domanda un puntatore a funzione inizializzato a zero equivale a chiamare la funzione loop()?
Forse basta un return, esce dalla funzione che poi verrà richiamata e ricomincerà .

ArTex se il treno non deve ripartire da solo non ti serve millis() che conta la pausa, però ti potrebbe servire per altri scopi.

torn24:
Domanda un puntatore a funzione inizializzato a zero equivale a chiamare la funzione loop()?

Io invece faccio una critica a "dataman" (... e, se non vado errato, non è la prima volta), che utilizza, nei sui codici, cose "da non fare", come questa di usare un puntatore a zero per fare un "reset" software (... e quindi far ripartire TUTTO, non solo il loop()) che è ovunque sconsigliata (... è una cosa fatta a metà, in cui la MCU fa un salto alla locazione zero, ma l'hardware non viene reinizializzato come in un vero reset o un attivazione del watchdog).

Se si vuole far ripartire il loop(), come giustamente dice "torn24", basta una banale "return" dato che loop() è semplicemente una funzione continuamente richiamata dentro un ciclo FOR ... con "return" si esce ed il cliclo FOR la riattiva dall'inizio.

Guglielmo

P.S.: per inciso, anche setup() è una semplice funzione che, occorrendo, si può richiamare da dove si vuole ...

Ciao, Guglielmo
Il riavvio l'ho usato una sola volta nei miei progetti per ricominciare il loop dopo aver fatto delle impostazioni. Sicuramente, però, sarebbe stato sufficiente impostare diversamente la struttura del programma.
Forse non l'ho neanche chiesto qui, ma l'ho trovato già trattato in inglese. Essendo stato chiesto esplicitamente senza ulteriori spiegazioni ed essendo molto semplice, l'ho riportato, senza pensare che quasi sicuramente non ne avrebbe avuto realmente bisogno.

Datman:
... Forse non l'ho neanche chiesto qui, ma l'ho trovato già trattato in inglese. ...

... dai retta, butta via la discussione dove l'hai trovato :smiley: :smiley: :smiley:

Guglielmo

Ciao, torn24
Anch'io ho iniziato a programmare Arduino con tutte le sue funzioni "astrattive" ma, ben presto, mi sono reso conto delle limitazioni e delle complicazioni che portavano, ad esempio non contemporaneità delle commutazioni dei bit di una porta, dover scrivere 8 righe anziché una sola con un byte binario (senza essere più comprensibili nel pilotaggio di 7 segmenti, anzi viceversa), rallentamento del loop, senza contare cose che vanno fatte necessariamente a un livello più basso. A quel punto, da tecnico elettronico che sono da oltre trent'anni, non mi sono più concentrato sulla portabilità ma sull'ottimizzazione per ottenere il massimo che può offrire questa tecnologia. D'altra parte penso che, dati i costi non esorbitanti, se qualcuno vuole costruire qualcosa non sia fortemente limitato dalla scheda in suo possesso. Considera anche che io uso Arduino uno solo per fare qualche prova iniziale, ma poi monto l'atmega328p su millefori con ciò che serve.

Datman:
... A quel punto, da tecnico elettronico che sono da oltre trent'anni, non mi sono più concentrato sulla portabilità ma sull'ottimizzazione per ottenere il massimo che può offrire questa tecnologia. ...

Tutto esatto, ma ... dimentichi che qui il 90% degli utenti NON è né un esperto di elettronica, né di programmazione di MCU e che quindi, la cosa più semplice per loro e più chiara da capire ed apprendere, è usare il framework "wiring" (...con tutti i suoi appesantimenti e rallentamenti).

Quindi, sempre meglio proporre soluzioni "classiche", comprensibili appunto anche da quel 90% dei lettori :slight_smile:

Se poi c'è quello esperto che deisidera ottimizzare ed approfondire ... chiede :wink:

Guglielmo

torn24:
Nel linguaggio semplificato di arduino non si usano registri, porte, puntatori a funzione e valori binari di bit :slight_smile:
Mentre nel tuo codice ne fai uso, programmare un altro microcontrollore in questo modo è la norma

In realtà, riguardando ciò che ho scritto, mi sembra di aver solo usato il PORT per il display proprio per rendere più comprensibile l'associazione dei bit con i segmenti. Proprio per questo ho anche messo il commento
"// .gfedcba" sopra ai bit di ogni PORT.
Vedo che mi sono anche astenuto dallo scrivere un DDRD per l'impostazione delle uscite :smiley:
Come detto, il Riavvia(); l'ho messo solo perché è stato chiesto esplicitamente (pur senza specificarne lo scopo) e mi è sembrato una cosa un po' curiosa e interessante.

Datman:
Come detto, il Riavvia(); l'ho messo solo perché è stato chiesto esplicitamente (pur senza specificarne lo scopo) e mi è sembrato una cosa un po' curiosa e interessante.

No, come spiegato ... è solo un'emerita porcheria :wink:

Guglielmo

Ah! Ah! Ah! :smiley:
Comunque il sito era italiano, perché c'era proprio scritto "Riavvia". Non so quale fosse, ma vedo che ce ne sono parecchi. Li facciamo fuori tutti? :smiley:

Datman:
Comunque il sito era italiano, perché c'era proprio scritto "Riavvia". Non so quale fosse, ma vedo che ce ne sono parecchi. Li facciamo fuori tutti? :smiley:

Solito branco di pecoroni incompetenti ... uno scrive una "bojata" e tutti dietro con copia/incolla :smiling_imp:

Se il codice è scritto come di deve, NON ci può essere la necessità di un "reset" se non per cause NON previste.

Per questa cosa però c'è apposta il watchdog che, se il programma impazzisce (es. una scarica elettrostatica, un'interferenza elettromagnetica, ecc.) e ... "non da più da mangiare nei tempi giusti al cane da guardia", quello s'arrabbia e resetta la MCU :smiley:

Guglielmo

Rieccomi quà!

Ho letto tutto e.... Mammamia, poi facciamo a cambio venite da me e vediamo se riuscite a incorniciare un quadro... HAhahaa!

Insomma con il Primo sketch ho la croce di S.Andrea che (ho modificato la sequenza) lampeggia che è una meraviglia, solo che parte la prima volta dopo che premo il tasto e poi si blocca tutto quando il treno ritornerebbe in galleria (premo il tasto) si spengono tutti i led.

Secondo skech lampeggia la croce di S.Andrea che è anche bellino come lampeggio, parte solo la sequenza se premo il tasto ( ho messo anche il condensatore) solo che all'arrivo (simulato ancora su bred board) và in tilt!
Rimane in corsa il treno (simulato con un led) e uno dei due led della croce di S.Andrea acceso fisso.

Siccome non contento ho qualche arduino uno Originale, ho provato gli sketch su tutti e due con analoghe conseguenze...

Conclusione sono sfigxto io!

Comunque sia mi sono letto tutto.

Grazie davvero Marco.

P.S. Se riesco a far funzionare sto coso giuro che a tutti i maker fino al 25 Dicembre gli faccio fare lo sconto al negozio di mio fartello.