Pulsante con ritardi diversi in accensione e spegnimento

Ciao a tutti, come faccio a dire ad un pulsante che che deve essere premuto per 1 sec. per accendere e 3sec per spegnere, in pratica avere dei debounce diversi in on e off, io ho fatto così ma è uguale in on e off, mi aiutate per favore, grazie

int reading1 = digitalRead(PIN_PULS1);
  if (reading1 != lastButtonState1)
    lastDebounceTime1 = millis();

  if ((millis() - lastDebounceTime1) > 5) {
    if (reading1 != buttonState1) {
      buttonState1 = reading1;
      if (buttonState1 == LOW) {
        led1_state = !led1_state;
      }
    }
  }

  lastButtonState1 = reading1;

  digitalWrite(led1, led1_state);

Il primo passo per risolvere tutti questi problemi è esplicitare sotto forma di diagramma quello che vuoi fare, e in particolare riuscire a trasformare la descrizione fatta in italiano, in un diagramma dove risultano ben chiare ed esplicite le fasi di funzionamento. Quello che hai descritto è questo:

345474354567757

Dopo di che bisogna riuscire a disegnare un diagramma di flusso che, tenendo conto delle fasi di funzionamento, realizzi il comportamento disegnato sopra. Ad esempio:

E solo a questo punto, se entrambi i disegni sono corretti e "funzionano", si può tradurre il secondo direttamente in istruzioni.

Se non si segue questo procedimento, ogni più piccola modifica o cosa da fare è un nuovo buco nero...

E questo si traduce in qualcosa che il micro capisce, potrebbe essere così:

#define led1 ???
#define PIM_Pulsi ???

unsigned long marca;


void setup() {
  pinMode (led1, OUTPUT);
  pinMode (PIM_Pulsi, INPUT_PULLUP);
}

void loop() {
  if (digitalRead (PIM_Pulsi) == LOW) {// Rileva il pulsante 
    marca = millis();//segno per contare 
    while (((millis () - marca) <= 1000) || (digitalRead (PIM_Pulsi) == HIGH)) {} //conta fino a un secondo o rilascia il pulsante 
    if ((millis() - marca) >= 1000) {// Era dovuto al tempo o al rilascio del pulsante? 
      digitalWrite(led1, HIGH);
    }
    if (digitalRead (PIM_Pulsi == LOW)) {//Se continui a premere il pulsante, segui l'account 
      while (digitalRead (PIM_Pulsi == LOW)) {} // aspetta che il pulsante venga rilasciato 
      // il pulsante è stato rilasciato!
      if (marca >= 3000) {//È stato premuto per 3 secondi o più? 
        digitalWrite(led1, LOW);
      }
    }
  }
}

Saluti

La condizione del primo while dovrebbe essere così:

((millis () - marca) <= 1000) && (digitalRead (PIM_Pulsi) == LOW)

Comunque questo codice per quello che vuole fare lui non funzionerebbe, perché deve gestire due pulsanti contemporaneamente e potrebbe anche volere il tempo di accensione più lungo di quello di spegnimento.

Mi scuso a priori per il post che sarà un po' lunghetto...

Approfitto del passaggio involontario di @Claudio_FF che ha introdotto il concetto di macchina a stati finiti, per fare un po' di pubblicità (non che ci guadagni qualcosa, sia chiaro :rofl:) a questa libreria cotestatnt/YA_FSM sulla quale ho rimesso le mani in questi giorni (dopo averla abbandonata per un po' di tempo e pure buggata :disappointed_relieved:).
Mi piacerebbe avere qualche feedback se possibile cosi da migliorarla e far crescere il progetto (il top sarebbe una pagina web che consente di modellare graficamente la FSM e produce il codice C++ in uscita).

Per rappresentare una macchina a stati, io trovo molto intuitivo usare come rappresentazione grafica diagrammi sequenziali GRAFCET / SFC.
Per modellare il comportamento richiesto da @lidas , ad esempio farei una cosa del genere...
image

Usando la libreria in questione, questo si traduce molto semplicemente in questo codice C++ che in pratica è quasi tutto "dichiarativo", c'è giusto un po' di logica nel dare la precedenza alla pressione lunga per la scrittura delle uscite (e per il blink di un secondo led).

#include <YA_FSM.h>

const byte BTN = 2;
const byte LED = 13;
const byte BLED = 12;
const byte RLED = 11;

#define SHORT_TIME  1000
#define LONG_TIME   3000

// Create new FSM
YA_FSM buttonFSM;

// State Alias
enum State {IDLE, PRESS};

// Input variable (this will trigger transition)
bool pButton = false;

// Output variables
bool led = false;
bool shortPress = false;
bool longPress = false;
bool redLed = false;

void setup() {
  pinMode(BTN, INPUT_PULLUP);
  pinMode(LED, OUTPUT);
  pinMode(BLED, OUTPUT);
  pinMode(RLED, OUTPUT);
  
  // Configure the FSM as modelled
  setupStateMachine();
}

void loop() {
  // Read inputs
  pButton = (digitalRead(BTN) == LOW);

  // Update State Machine (true is state changed)
  buttonFSM.Update();

  // Set outputs
  if(longPress) {
    digitalWrite(LED, LOW);
  }
  else if (shortPress) {
    digitalWrite(LED, HIGH);
  }

  digitalWrite(RLED, redLed);

  // Check if FSM is really NON blocking.
  blinkLed(BLED, 250);
}

void blinkLed(const uint8_t led, const uint32_t period) {
  static uint32_t blinkTime;
  if(millis() - blinkTime > period) {
    blinkTime = millis();
    digitalWrite(led, !digitalRead(led));
  }
}

// Setup the State Machine
void setupStateMachine() {

  // Follow the order of defined enumeration for the state definition (will be used as index)
  // Add States => name,timeout, onEnter cb, onState cb, onLeave cb
  buttonFSM.AddState("IDLE", nullptr, nullptr, nullptr);
  buttonFSM.AddState("PRESS", nullptr, nullptr, nullptr); // Set MAX and MIN state duration (avoid bouncing NON blocking)

  // Add actions
  buttonFSM.AddAction(PRESS, YA_FSM::D, shortPress, SHORT_TIME);  // Delayed  action
  buttonFSM.AddAction(PRESS, YA_FSM::D, longPress, LONG_TIME);    // Delayed  action
  buttonFSM.AddAction(PRESS, YA_FSM::L, redLed, SHORT_TIME);      // Limited time action

  // Add transitions with related trigger input callback functions
  buttonFSM.AddTransition(IDLE, PRESS, pButton);
  buttonFSM.AddTransition(PRESS, IDLE, [](){ return pButton == false;} );   // simple lambda function
}

I metodi dietro le quinte usati dalla libreria non appesantiscono di molto il codice finale (anzi spesso una FSM può aiutare a snellire il tutto) perché sono basati essenzialmente sull'utilizzo dei puntatori.
Ad esempio, lo sketch proposto compilato per un Arduino Uno da questo risultato:

Questa è un'applicazione molto semplice e ovviamente le risorse occupate sono leggermente maggiori rispetto all'altro esempio nudo e crudo.

Credo però che dal punto di vista "didattico" sia molto utile per i principianti al fine di capire la logica alla base di una FSM che se ben implementata consente di realizzare algoritmi efficaci ed affidabili senza dead-lock o cose simili in modo intuitivo e facilmente scalabile.
Il vantaggio principale secondo me è che sposta l'attenzione e le energie di chi programma sulla progettazione dell'algoritmo che consente il funzionamento voluto e non sulle specifiche istruzioni da usare.

Capito il meccanismo delle macchine a stati finiti, poi è relativamente semplice estenderlo a progetti più complessi (magari suddividendo il processo in più step).

Volevo far notare che la FSM cosi definita e con l'utilizzo di questa libreria NON è bloccante (anche mentre il tasto è premuto), motivo per cui ho aggiunto il blink del secondo led come verifica.
Ho aggiunto anche un terzo led per provare l'azione Time Limited.

Se volete approfondire un po' il funzionamento dei diagrammi SFC, ho trovato ottima questa breve dispensa del Prof. Cavalieri Sequential Functional Chart

P.S.
Alo stato attuale, alla libreria manca la gestione dei rami in parallelo, che è ancora in cantiere.

Ciao @Claudio_FF Dove si dice che ci sono due pulsanti? Vedo solo un singolo pulsante nella domanda e nel codice presentato. Per quanto riguarda la condizione, va bene così, cerco di sapere se è passato un secondo o se il pulsante è stato rilasciato prima del secondo. Che programma usi per creare questi diagrammi di flusso?Non riesco a trovarne, se ne avessi uno potrei farne uno per te in modo che tu possa capire meglio il mio codice.
Saluti.

Ciao a tutti e grazie intanto, come scrive @Claudio_FF è vero, io su questo circuito ho due pulsanti, che fanno due cose separate, la prima parte i pulsanti vengono premuti assieme e creano l'accensione del tutto con autoritenuta passando allo stato POWER_ON, una volta fatto questo i due pulsanti diventano indipendenti e accendono e spengono un led (che in seguito nel circuito finale sarà un mosfet) è in questo momento che cercavo questa soluzione, se dite posto tutto qui, fatemi sapere.
Grazie ancora

Tutto inizia con questo thread che si è arrestato in attesa del codice usato.

È stato aperto un nuovo thread con schema e codice (e li oltre al problema di cui si sta discutendo qui c'è la questione più grave del codice bloccante con delay che impedisce il funzionamento in tempo reale).

Poi è stato aperto questo, in cui stiamo discutendo, riguardante un singolo sottoproblema, che però va risolto in funzione del progetto complessivo, che richiederà quattro flussi paralleli di esecuzione: gestione autoritenuta, gestione led1, gestione led2, gestione misure con comando led RGB. Il tutto leggendo i due pulsanti che svolgono funzioni indipendenti se premuti uno alla volta, o insieme se premuti entrambi. Per questo motivo non si può stare ad aspettare il rilascio di uno dentro un ciclo while, perché si perderebbe la gestione dell'altro e si bloccherebbero gli altri processi paralleli. In sostanza chiedere aiuto su un singolo sottoproblema, sperando che sia sufficiente "sostituire" quel pezzo di codice, senza tenere conto del funzionamento complessivo, è un errore dell'autore.

Appunto, si resta nel while finché non è ancora passato un secondo E il pulsante è premuto, si esce se scade il tempo O se si rilascia. Lo schema è fatto con fidocad. Se ho interpretato bene la tua logica è il seguente:

Eh no, servono anche per spegnere... quindi sempre insieme vanno controllati.

Sì giusto hai ragione mi ero scordato

L' SFC stretto non l'ho ancora digerito, nel senso che non riuscirei a tradurre in esso le varie FSM che scrivo se dovessi usare solo le "azioni" dei vari tipi disponibili. Avevo aperto questo thread per cercare di coniugare le due cose, e vedo ora che i disegni sono sbagliati, Avrei anche una nuova implementazione... quello che mancherebbe sono le azioni ripetute una volta alla disattivazione degli stati, di cui non ho ancora compreso l'utilità.

Per questo concordo pienamente, le azioni sono insufficienti anche se quando bastano, mi piace la "semplicità" di utilizzo che ne deriva.

Per questo infatti mi sono orientato principalmente sulle funzioni di callback da associare agli stati che consentono una grande flessibilità.
Ho cercato di "riprodurre" quanto si riesce a fare con i programmi SFC implementati nell'ambiente di sviluppo CodeSys.

Per quanto riguarda l'esecuzione dell'azione in uscita, io nella libreria l'ho implementata e mi torna utile per resettare qualche flag booleano o ad esempio il timestamp usato con le azioni temporizzate.

No. Rimango acceso while fino a quando non passa un secondo o il pulsante viene rilasciato entro quel secondo, Controllo se è perché è passato un secondo, se è così accendo il led Se il pulsante non è stato rilasciato attendo che venga rilasciato. Al rilascio, se sono trascorsi 3 secondi, spengo il led. La logica sarebbe questa:

Questo codice perde solo il tempo in cui viene premuto il pulsante, ma visto che ora appartiene a un codice più grande, non so se funzionerebbe. Proverò ad agganciarmi al thread principale.
Saluti

Stiamo dicendo la stessa cosa, solo che il ciclo until (finché non) in C non esiste, c'è solo il while (finché) che richiede la condizione opposta:
2468792516546

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