Indicatore direzione moto

Devo realizzare un indicatore di direzione per moto, con 3 pulsanti, SX DX ed EMERGENZA.

Quando premo SX lampeggia, al successivo azionamento si spegne.E così per il DX.
Se mentre sta lampeggiando una direzione aziono il pulsante dell'altra, immediatamente commuta su
quest'ultima.
Se premo il pulsante emergenza si attivano tutt'e due le frecce.

Il progetto è ancora all'inizio, e mi sono arenato in un punto:

lo schetch qui mostrato funziona, cioè il led lampeggia con ritardo 500 ms , ma non ho il pulsante nel loop.

Se inverto il commento nel loop, se commento "sinistra();" e scommento l'if, il programma salta a funzione sinistra() ma il led resta acceso, se premo il pulsante si spegne, e si riaccende alla successiva
premuta.

In poche parole vorrei che nel loop al pigiare di un pulsante il led lampeggi.

Strano, non vedo particolari problemi, a parte una certa confusione,
Secondo me dovrebbe andare...

#define pulsante 2
#define led 7
int ledState = LOW;

unsigned long previousMillis = 0;
const long interval = 500;
void setup() {
  pinMode(pulsante, INPUT);
  pinMode(led, OUTPUT);
}

void loop() {
  // if (digitalRead(pulsante) == 0) {  lampeggio(); }
  lampeggio();
}
int  lampeggio() {

  unsigned long currentMillis = millis();

  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;
    if (ledState == LOW) {
      ledState = HIGH;
    } else {
      ledState = LOW;
    }
    digitalWrite(led, ledState);
  }
lampeggio();
}

L'ho ridotto e ripulito.
Quindi se lo lascio così il led lampeggia, se inverto il commento nel loop si accende e si spegne solo se premo il pulsante, e così non mi va bene.
Vorrei che fosse il pulsante a far iniziare il lampeggio.

Prima domanda: i pulsanti come sono collegati? Ossia hanno una resistenza di pull-down o pull-up?

Detto questo, nel codice c'è un certo disordine che indica che non hai ben chiaro cosa tu stia facendo, vedo spezzoni di copiaincolla qui e lì.. :wink:

Quando inizi un progetto, non iniziare subito dal codice, parti prima chiarendoti bene alcune cose, nell'ordine (in pratica passi al punto successivo quando hai ben chiaro il precedente):

  1. la TUA definizione dei requisiti (ossia COSA esattamente vuoi ottenere)
  2. uno schema di massima dei collegamenti (se ci sono pulsanti, quanti, se ci sono LED, o altri componenti, eccetera)
  3. inizia a scrivere il codice affrontando però UN problema alla volta
  4. unisci il tutto in un unico codice, ma partendo magari scrivendo solo i commenti, più strutturati possibile.

Per il punto 1) hai espresso abbastanza bene le cose, e puoi partire da quello.
Per il punto 2) è relativamente semplice, hai 3 pulsanti e 2 LED, e fin qui va bene (ma per i pulsanti devi stabilire se pulldown quindi se HIGH sono premuti, se invece sono pullup sono LOW quando premuti).
Per il punto 3) stai iniziando, ma a parte alcune scelte "stilistiche" che ti conviene iniziare a considerare (es. le costanti/define maiuscole per convenzione, evitare di usare "== 0" per verificare i pulsanti ma meglio "== HIGH" che è più evidente, e così via) , il discorso di "un problema per volta" è proprio qui.

Di fatto lascia perdere per ora il lampeggiamento, fai un programmino che quando premi il pulsante il LED si accende e resta acceso fino a che non lo premi nuovamente.
Questo già ti basta, perché oltre alla resistenza di pull-down (sai come si mette?) include anche un minimo di gestione del debounce (sai di cosa si tratta?) ed inversione dello stato di un pin.

Una volta che quel codice ti funziona, allora avrai capito già molte cose utili, per cui puoi iniziare a cercare di aggiungere il lampeggiamento (ossia il led deve iniziare a lampeggiare quando premi il pulsante, e smettere quando lo premi nuovamente).

Fai questi due step (o almeno il primo, se non riesci), e posta qui il risultato e cerchiamo di aiutarti.

Per iniziare, parti da questo:

#define PIN_KEY 2
#define PIN_LED 7

void setup() {
  pinMode(PIN_KEY, INPUT);
  pinMode(PIN_LED, OUTPUT);
}

void loop() {
  // Verifico se il tasto è premuto
  
    // Tasto premuto
    // Inverto lo stato del LED
    
}

Capito problema
C'è da ribaltare l'approccio..
Dopo...

Doc, va bene tutto quello che dici, ma io parto dal fare funzionare il lampeggio, per poi metterlo in bella copia..sbaglio?

Non capisco perche se la funzione la chiamo direttamente dal loop funziona, se invece la chiamo tramite un If (salto sempre alla funzione, ma si comporta in modo diverso).

In realtà è ovvio
Se la chiami sempre funziona sempre
Se la chiami ogni tanto quando non la chiami non funziona, si ferma nello stato in cui era all'istante che hai mollato il pulsante...

Standardoil:
In realtà è ovvio
Se la chiami sempre funziona sempre
Se la chiami ogni tanto quando non la chiami non funziona, si ferma nello stato in cui era all'istante che hai mollato il pulsante...

Esatto, ci ero arrivato; i soliti retaggi del Basic, una volta che si salta in un'altra serie d'istruzioni
il programma resta li se non gli si dice che deve "ritornare", al contrario delle funzioni in C...mannaggia
Vorrei fare 3 funzioni per ogni pulsante, e restare sotto di una di essa finchè
un altro pulsante non venga premuto.
Comunque credo che si possa fare tutto nel loop, ma ci devo studiare...
I pulsanti sono pulappati

Sto provando a svolgere il compito assegnatomi da docdoc,
Adesso il pulsante fa partire il lampeggio (richiamo la funzione lampeggio da se stessa)
al secondo "pigiamento" torno al loop, ed è quello che volevo, ma dopo i 100 ms dell'antirimbalzo
ritorna al lampeggio.. :confused:
Pulsante pulappato

#define PIN_KEY 2
#define PIN_LED 7
int ledState = LOW;
unsigned long previousMillis = 0;
unsigned long currentMillis;
const long interval = 500;
void setup() {
  pinMode(PIN_KEY, INPUT);
  pinMode(PIN_LED, OUTPUT);

}
void loop() {
  if (digitalRead(PIN_KEY) == LOW) {
    delay(100);
    lampeggio();
  }
}
int lampeggio() {
  currentMillis = millis();
  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;
    if (ledState == LOW) {
      ledState = HIGH;
    } else {
      ledState = LOW;
    }

    digitalWrite(PIN_LED, ledState);
  }
  if (digitalRead(PIN_KEY) == LOW) {
    digitalWrite(PIN_LED, LOW);
    delay(100);
    loop();
  }
  lampeggio();
}

Ma dal tuo codice lampeggia fin quando il pulsante è premuto, è questo quello che vuoi?
Se invece vuoi che i led lampeggino in automatico dovresti avere una variabile stato per ogni led.

statosx, statodx

a stato 1 tramite if faccio lampeggiare il led

premendo il pulsante sx inverto lo stato di statosx=!statosx e statodx=0
premendo il pulsante dx inverto lo stato statodx=!statodx e statosx=0
premendo emergenza porto statosx=1 e statodx=1, in questo modo lampeggiano entrambi

Allora, intanto quello che ti serve più che "ledState" (che puoi anche ricavare leggendo il pin stesso) è una variabile (diciamo "blinking") che ti dica se il led deve lampeggiare o meno, quindi basta una bool. Se è "true" allora va fatto lampeggiare, se è "false" devi spegnere il LED.

Poi nella funzione lampeggio() tu gestisci (male) il rilascio del pulsante: quando programmi devi ricordare sempre di separare la logica. La gestione del pulsante lasciala fuori, nella funzione lampeggio() gestisci solo il lampeggiamento! Tu nel loop() pensa prima ad impostare la variabile ("blinking") che indica se debba lampeggiare o meno in base alla pressione del tasto, e POI chiamerai "lampeggia()" ma solo se è attivo il lampeggiamento ("blinking == true").

Per finire, vedo una cosa pericolosissima, tu dentro alla funzione lampeggio() richiami nuovamente se stessa, che fai, le chiamate ricorsive??? Evita! La "lampeggio()" deve limitarsi, quando chiamata, a gestire l'accensione/spegnimento del led in caso di lampeggiamento e se il tempo dall'ultima azione è trascorso.

Ora prova a rivedere il tuo codice in base a queste indicazioni, e manda qui l'esito (anche negativo, ma con l'ultima versione del codice e relativo comportamento rilevato).
Eventualmente in serata se non riesci proprio, provo a darti qualche indicazione più specifica (ma preferirei se tu ti impegnassi in prima persona a capire e correggere, più che darti "la pappa pronta" :wink: ).

@docdoc, ci sto riuscendo, sono arrivato alle due frecce, mi manca solo l'emergenza
ecco dove sono arrivato:
accendo e spengo le frecce dal loro pulsante, e se mentre sta andando una e premo l'altro
pulsante il lampeggio commuta.
Quindi basta fare così anche per l'emergenza, ridondando i led.

Purtroppo sto richiamando una funzione da se stessa, cosa che mi hai sconsigliato
ma non so come restare sotto quella funzione, se non faccio nulla ritorna al loop :frowning:

Stilita:
Purtroppo sto richiamando una funzione da se stessa, cosa che mi hai sconsigliato
ma non so come restare sotto quella funzione, se non faccio nulla ritorna al loop :frowning:

Eh certo che DEVE tornare al loop... Come ti ho detto, ogni porzione di codice deve gestire una cosa, non mescolare la gestione del lampeggiamento con quella del pulsante.

Ok, dai, avevo 5 minuti, vedi questa versione del singolo pulsante e dimmi cosa ci vedi di diverso, oltre ai commenti (SEMPRE metterli):

#define PIN_KEY 2
#define PIN_LED 7

bool blinking = false;
int curKey, prevKey = LOW;
  
unsigned long previousMillis = 0;
unsigned long currentMillis;
const long interval = 500;

void setup() {
  pinMode(PIN_KEY, INPUT);
  pinMode(PIN_LED, OUTPUT);
}
void loop() {
  // Vedo se è stato premuto il pulsante (deve passare
  // da LOW a HIGH, ignoro tutti gli altri stati!)
  curKey = digitalRead(PIN_KEY);
  if (curKey == HIGH && prevKey == LOW) {
    delay(100); // Un minimo di debounce
    blinking = !blinking;
    // Se non deve più lampeggiare spengo il led
    if ( !blinking ) 
      digitalWrite(PIN_LED, LOW);
  }
  prevKey = curKey;
  
  if ( blinking ) 
    lampeggio();
}

int lampeggio() 
{
  // Gestisco il lampeggiamento
  currentMillis = millis();
  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;
    digitalWrite(PIN_LED, !digitalRead(PIN_LED));
  }
}

EDIT: ovviamente qui dò per scontato che il pulsante sia in pulldown, se pullup devi cambiare l'inizializzazione "prevKey = LOW" in "prevKey = HIGH" ed invertire il test "curKey == HIGH && prevKey == LOW" in "curKey == LOW && prevKey == HIGH"...

Volevo rispondere, ma docdoc ha già fatto "cancellato post"

torn24:
Premi il pulsante richiami la funzione, rilasci il pulsante non richiami più la funzione, allora richiamando la funzioni in se stessa resti sempre nella funzione premendo una sola volta il pulsante. UNA SOLUZIONE SBAGLIATA.

Più che quello, una chiamata ricorsiva infinita alla fine farà andare in crash il povero Arduino appena finisce lo spazio per lo stack...

torn24:
Volevo rispondere, ma docdoc ha già fatto "cancellato post"

Non è importante, non è una gara :slight_smile: potevi lasciarlo.

Era inutile, la tua spiegazione è più completa! Poi due teste è meglio che una, non è sempre vero, due soluzioni un po diverse possono confondere più che aiutare. :slight_smile:

Il pulsante è puluppato.
Noto che hai usato il punto esclamativo per invertire lo stato.
Altre considerazioni, ho usato millis e non interrupt perché il micro ne ha solo 2, altrimenti credo
sarebbe stato più facile.
Domani ci rimetto mani e vedo di fare qualche progresso.
Per ora dico come stavo pensando di fare, che già mi hai anticipato che non ti piace:
Nel loop mi metto in attesa che qualche pulsante venga premuto, uando accade azzero l'altro led e salto alla sua funzione lampeggio di quello che voglio far lampeggiare, e nel frattempo che faccio i controlli sul tempo sento se è stato premuto un altro pulsante, se non è stato premuto resto sotto lampeggia, altrimenti spengo il primo e salto ad un altro lampeggia.

Ho letto che richiamare continuamente una funzione da se stessa non va bene, nemmeno se la chiamata viene effettuata sempre ripetutamente dal loop?

boh, io avevo avanzato un 30 minuti e ho fatto questo

// di Nelson "StandardOil"
// Idea da sviluppare:
// lampeggiatore


byte pulsanti[3] = {2, 3, 4} ;// i 3 pulsanti destra sinistra, emergenza
#define DX 12 // led destro
#define SX 13 // led sinistro (built-in)
byte stato; // lo stato attuale 0 non lampeggia 1 dx 2 sx 3 sx+dx
unsigned long int tprec; //tempo precedente del lampeggio
#define PASSO 500 // il passo di lampeggio
bool lampeggio;

void setup(void)
{
    for (byte i = 0; i < 3; i++)
    {
        pinMode(pulsanti[i], INPUT);
    }

    pinMode(DX, OUTPUT);
    pinMode(SX, OUTPUT);
}

void loop(void)
{
    byte j = 0; // il pulsante premuto, occhio che parte da 1 non da zero

    for (byte i = 0; i < 3; i++)
    {
        if (digitalRead(pulsanti[i]))
        {
            // trovato pulsante premuto
            delay(50); //tempo di debounce

            while (pulsanti[i]);

            j = i + 1; // lo salvo
            break;// trovato premuto, atteso debounce, atteso rilascio, uscito
        }
    }

    if (j)
    {
        // un pulsante è premuto
        if (j == stato)
        {
            //premuto lo stesso tasto che era stato premuto prima, smetto di lampeggiare
            stato = 0;
        }
        else
        {
            if (!stato)
            {
                // non cambio, ma prima accensione
                //  riazzero il conto, che parta sempre da acceso
                tprec = millis();
                lampeggio = 1;
            }

            // comunque aggiorno lo stato
            stato = j;
        }
    }

    // lampeggio

    if (millis() - tprec >= PASSO)
    {
        tprec = millis();
        lampeggio = !lampeggio;
    }

    digitalWrite(DX, lampeggio & stato % 2);
    digitalWrite(SX, lampeggio & stato > 1);
}

Lo sketch usa 1362 byte (4%) dello spazio disponibile per i programmi. Il massimo è 32256 byte.
Le variabili globali usano 19 byte (0%) di memoria dinamica, lasciando altri 2029 byte liberi per le variabili locali. Il massimo è 2048 byte.
gestisce tre pulsanti , indiretti attraverso un array, se serve di spostari o espandere il programma
sente il cambio di lampeggio, la pressione una seconda volta dello stesso pulsante, e riparte col lampeggio sempre da zero
facilmente espandibile.......
a perte il piccolo trucco sulla scrittura delle uscite, dato che li non mi serviva scandire nulla
ma se serve si può cambiare in una switch case, e allora si espande bene

ma non ho qui adesso nessuna macchina, quelche anima pia me lo prova?

@Standardoil, avevo pensato anch'io ad un array, ma visto che erano solo 3 alternative ho ridondato le funzioni, che però già mi hanno detto che devo rivedere per come le sto usando.
Appena riesco studio anche il tuo programma e ti faccio sapere, a dopo.