delay e led

buongiorno a tutti
ne capisco poco di programmazione e ora avendo del tempo a disposizione sto cercando di imparare con un arduino, acquistato da diverso tempo ma mai preso in considerazione più del dovuto

capito da esempi come accendere un led, accenderlo e spegnerlo con lo stesso pulsante come passo-passo e ora voglio provare con timer

nella breadboard ho cablato2 pulsanti che devono accendere 2 led e spegnersi dopo N tempo anche se non rilascio il pulsante realizzandolo con delay.

li ho chiamati pulsante A e led A, pulsante B e led B e il mio scopo è quello di 2 circuiti separati: il pulsante A accende il led A e il pulsante B il led B

dovrebbe funzionare cosi:
premo pulsanteA accende led A, inizia conteggio tempo N si spegne il led A anche se ancora non ho rilasciato il pulsante

durante tutto questo tempo di led A acceso o pulsante A premuto se premo il pulsante B il secondo circuito deve comportarsi nello stesso modo.

prendendo in esame gia solo pulsanteA non riesco a far spegnere il led A dopo N tempo se il pulsante rimane premuto. si accende premendo il pulsante, ma spegne dopo N tempo aver rilasciato il pulsanteA

poi provando anche il secondo circuito questo si accende solo allo scadere del primo delay premuto
qualcuno puo aiutarmi?

allego mio sketch

/*
  - LED collegato fra pin e negativo
  - pulsante collegato fra pin e +5V
  - resistenza 10k collegata fra pin e negativo
*/


const int pulsanteA = 7;           // pulsanteA
const int pulsanteB = 8;           // pulsanteB
const int ledA =  2;               // ledA
const int ledB =  3;               // ledB

int statopulsanteA = 0;            // variabile per lettura del pulsanteA non premuto
int statopulsanteB = 0;            // variabile per lettura del pulsanteB non premuto

void setup() {

  pinMode(pulsanteA, INPUT);   // il pulsanteA è un ungresso
  pinMode(pulsanteB, INPUT);   // il pulsanteB è un ungresso
  pinMode(ledA, OUTPUT);      //il ledA è una uscita
  pinMode(ledB, OUTPUT);      //il ledB è una uscita
}

void loop() {
  statopulsanteA = digitalRead(pulsanteA);// qui definisco lo stasto del pulsanteA

  if (statopulsanteA == HIGH) {  //se il  pulsanteA è premuto
    digitalWrite(ledA, HIGH);      // accendo il ledA
    delay(2000);                   //questo è il tempo di accensione dopo aver rilasciato il pulsanteA
  } else {                        // se rilascio il pulsanteA
    digitalWrite(ledA, LOW);      // spengo il ledA
  }
  statopulsanteB = digitalRead(pulsanteB);// qui definisco lo stasto del pulsanteB

  if (statopulsanteB == HIGH) {  //se il  pulsanteB è premuto
    digitalWrite(ledB, HIGH);      // accendo il ledB
    delay(2000);                   //questo è il tempo di accensione dopo aver rilasciato il pulsanteB
  } else {                        // se rilascio il pulsanteB
    digitalWrite(ledB, LOW);       // spengo il ledB
  }

}

lampadina915:
prendendo in esame gia solo pulsanteA non riesco a far spegnere il led A dopo N tempo se il pulsante rimane premuto. si accende premendo il pulsante, ma spegne dopo N tempo aver rilasciato il pulsanteA.
poi provando anche il secondo circuito questo si accende solo allo scadere del primo delay premuto

1a) Il primo problema deriva dal fatto di testare il livello attuale del pulsante e non sua variazione che avviene solo nell'istante della pressione. Per rilevare l'istante di pressione basta fare il controllo con la lettura precedente, quindi: se lettura attuale diversa da precedente E corrisponde al livello premuto (in questo caso HIGH) allora abbiamo rilevato l'istante di pressione (che non si verifica più finché non si rilascia e si ripreme). Naturalmente alla fine di ogni giro la lettura precedente va aggiornata con il valore di quella attuale.

1b) In parallelo alla resistenza di ogni pulsante va collegato anche un condensatore 100nF per eliminare i rimbalzi di chiusura e apertura che verrebbero letti come pressioni multiple. In alternativa la via più spiccia (ma non sempre applicabile) è aggiungere un delay(50) alla fine del loop in modo da rallentarne l'esecuzione a circa venti giri al secondo (i rimbalzi si esauriscono in pochi millisecondi o anche in uno solo).

  1. Il secondo problema invece nasce direttamente dall'uso di lunghi delay che interrompono completamente l'esecuzione del programma fino allo scadere del tempo, per cui nel frattempo non si può fare niente altro. Temporizzare con lunghi delay va bene solo nei programmi che devono compiere una e una sola operazione alla volta. Quando si devono eseguire almeno due compiti la logica va ripensata in altro modo. Ad esempio:
leggi stato pulsante A
SE diverso da stato precedente E stato attuale == HIGH:
    attiva timer A           // imposta una variabile a 1)
    memorizza tempo inizio A // salva il valore letto con millis)

aggiorna variabile stato precedente = stato attuale

se timer A attivo:
    se timeout:              // se valore attuale millis - tempo inizio > periodo voluto
        disattiva timer A    // imposta variabile a 0
        spegni LED A
    altrimenti:
        accendi LED A

ci sto provando da più di 2 ore ma senza risultati con i millis pulsante rilasciato si spegne n secondi dopo il rilascio
pulsante premuto blinka
ci sto perdendo la testa

Prova a postare lo sketch attuale.

posto lo sketch per 1 solo pulsante e led

const int pulsante = 8;
const int led = 2;

unsigned long tempoledacceso;

bool ledacceso;

void setup() {

  pinMode(led, OUTPUT);
  pinMode(pulsante, INPUT);

  ledacceso = false;

}

void loop() {

  if (digitalRead(pulsante) == HIGH) {
    digitalWrite(led, HIGH);
    ledacceso = true;
    tempoledacceso = millis();
  }
  if (ledacceso)
    if (millis() - tempoledacceso > 2000) {
      digitalWrite(led, LOW);
      ledacceso = false;
    }
}

L'uso di millis è corretto. Il problema come detto prima è che testi il livello del pulsante (sempre HIGH finché premuto) e non la sua variazione (passaggio da LOW precedente a HIGH attuale), quindi il timer viene "avviato" ad ogni giro, e il tempo parte dal momento in cui si rilascia il pulsante.

si questo dopo tante prove ci sono arrivato ma non capisco come fare la variazione

La variabile 'onPress' va a 1 per un ciclo di loop nel momento in cui il pulsante viene premuto:

in = digitalRead(pulsante);
onPress = ((in == HIGH) && (inPrec == LOW));
inPrec = in;

Abbreviabile in:

in = digitalRead(pulsante);
onPress = in && !inPrec;
inPrec = in;

grazie per i tuoi consigli ma non so proprio cosa devo fare
non ho le basi per capire certe programmazioni
è da stamattina che sono sopra sto sketch senza ricavarne nulla
mi son proprio demoralizzato
ho utilizzato plc di diverse marche utilizzando ladder ma questo arduino ha una progammazione per me difficile da comprendere, specialmente se non si ha nessuna base
mi sto proprio demoralizzando

lampadina915:
ho utilizzato plc di diverse marche utilizzando ladder

Allora pensa in ladder :slight_smile:

|  pulsante                   in       |
|----] [----------------------( )------| in = digitalRead(pulsante);
|                                      |
|    in       inPrec        onPress    |
|----] [-------]/[------------( )------| onPress = in & !inPrec;
|                                      |
|    in                      inPrec    |
|----] [----------------------( )------| inPrec = in;
|                                      |
|                          T1          |
|                        .-----.       |
|   onPress              |     |       |
|----] [-----------------|Toff |-------| if (onPress) { T1 = 1;  inizio = millis(); }
|                        |     |       | else if (millis()-inizio > 2000) { T1 = 0; }
|                        '-----'       |
|                                      |
|    T1                       led      |
|----] [----------------------( )------| digitalWrite(led, T1);
|                                      |

PS: non so in ladder come si indica esattamente un timer che si avvia con un impulso.

PS2: il bello di un linguaggio general purpose è che può essere usato per codificare qualsiasi tipo di logica (a contatti, a stati, ad algoritmo, misto di tutte ecc).

grazie Cludio vedrò di darmi da fare

sono riuscito a a fare questo. Non capisco la funzione del timer:

se metto il byte !in nel comando del timer è giusto che si fermi perchè rilasciando il pulsante si diseccita
ho creato allora una autoritenuta A quindi mettendo nel timer !A dovrebbe rimanere attivo.
Invece si comporta al contrario, si accende ma si spegne dopo aver rilasciato il pulsante

questo schema con autoritenuta

in T1 A
|----] [---------|-]/[-----------( )------|
| |
| A |
|----] [-----|
|
| A T1
|----] [-------------------------( )------|
|
|
|
| A led
|----] [-------------------------( )------|

lo sketch scritto che allego al mio caso dovrebbe andare bene in quanto si presuppone che fra pulsante premuto e pulsante rilasciato intercorra piu di T1
ora ho provato ad associare un buzzer ma questo non ne vuole proprio sapere di funzionare

#define pulsante          8    //  pulsante
 #define led               2    //  led
 #define buzzer            6    //buzzer
 
 byte A = 0;
 byte T1 = 0;

 uint32_t t1 = 0;

 void setup()
 {
   Serial.begin (9600);

  pinMode(pulsante, INPUT);
  pinMode(led, OUTPUT);
  pinMode(buzzer, OUTPUT);  
 
  digitalWrite (pulsante, LOW);
  digitalWrite (led, LOW);
  digitalWrite (buzzer, LOW);
  
 }
void loop(){

  byte in = digitalRead(pulsante);

  A = (in | A ) & !T1 ;

  // Accendo il led
  digitalWrite(led, A );
  
  //digitalWrite(buzzer, A );
  //tone (buzzer,3500,1000);
  
  //  --------------------------------------------------------------------------------------
  //  ritardo all'eccitazione
  // pulsante premuto si accende immediatamente il led e si spegne dopo il tempo
  // se il pulsante viene rilasciato prima del tempo il timer si blocca e non spegne il led
 
  T1 = 0;
  if (!in )
  {
    t1 = millis();
  }
  else if (millis() - t1 >= 1500) T1 = 1;
  //  --------------------------------------------------------------------------------------
 }

lampadina915:
quindi mettendo nel timer !A dovrebbe rimanere attivo.

Hai scritto un timer tipo Ton (ritardo in attivazione) quasi giusto, l'azzeramento di T1 però va sotto condizione:

if (!A) { T1 = 0;  t1 = millis(); } else if (millis() - t1 >= 1500) T1 = 1;

Quello che avevo scritto io è un timer Toff (ritardo in disattivazione) retriggerabile:

if (A) { T1 = 1;  t1 = millis(); } else if (millis() - t1 >= 1500) T1 = 0;

Se si vuole un Toff non retriggerabile (ma che comunque si riattiva se alla fine del periodo A vale ancora 1):

if (A & !T1) { T1 = 1;  t1 = millis(); } else if (millis() - t1 >= 1500) T1 = 0;

Per non farli riavviare, i Toff basta comandarli con una variabile/coil/condizione impulsiva (come la 'onPress' del post #10).

ho provato ad associare un buzzer ma questo non ne vuole proprio sapere di funzionare

Cosa dovrebbe fare? Un beep alla partenza? Mi sembra che la soluzione più semplice sia avviare tone con una condizione impulsiva:

|     A          B       .------.      |
|----] [--------]/[------|buzzer|------| if (A & !B) tone(buzzer,3500,1000);   // beep avvio
|                        '------'      |
|                                      |
|     A                        B       |
|----] [----------------------( )------| B = A;
|                                      |

chiaro quello che hai scritto
non capisco comunque perchè lo sketch che ho scritto io con temporizzatore

T1 = 0; if (!in ) { t1 = millis(); } else if (millis() - t1 >= 1500) T1 = 1;

se tengo premuto il pulsante funziona

se metto autoritenuta no

A = (in | A ) & !T1 ;

T1 = 0; if (!A ) { t1 = millis(); } else if (millis() - t1 >= 1500) T1 = 1;

in questo nel mio progetto va bene anche cosi ma in altre condizioni l' autoritenuta è fondamentale

ho provato anche il buzzer come dicevi ma non va

il suo scopo è di rimanere acceso per un tempo

ora voglio risolvere il problema della condizione del pulsante/autoritenuta per evitare eventuale anomalia in future installazioni, poi vedo anche per il buzzer

questo progetto lo voglio installare su una serranda.
Il suo lampeggiante di segnalazione inizia a lampeggiare 3 secondi prima che la serranda inizi a muoversi.
voglio aggiungerci un cicalino per far capire che la serranda inizierà a muoversi

il led mi serve solo per capire lo sketch, nella realtà poi non servira ma ora per me utile a capire il funzionamento

sicuramente se acquistavo un temporizzatore avevo già risolto il problema senza perderci tanto tempo, ma dopo 2 giorni che ci perdo la testa devo continuare

grazie Claudio del tuo aiuto

ho creato queste condizioni, naturalmente con PULSANTE PREMUTO perchè la ritenuta non mi funziona

 A= (in | A) & !T1  ;
   B = (A);
   digitalWrite(ledprova, A );         // Il led si accende e si spegne dopo T1 
 
 if ( A & !B ) tone (buzzer,3500,1000 ); il buzzer suona e smette 1 secondo dopo aver rilasciato il pulsante
  
    T1 = 0;
  if (!in )
  {
    t1 = millis();
  }
  else if (millis() - t1 >= 1000) T1 = 1;

lampadina915:
ho creato queste condizioni, naturalmente con PULSANTE PREMUTO perchè la ritenuta non mi funziona

  1. Il timer va comandato con 'A' non con 'in' (e il T1=0 va assieme al t1=millis).

  2. L'espressione 'B = A' va scritta dopo la riga che usa la condizione 'A & !B' e non prima, altrimenti la condizione sarà sempre falsa e il buzzer non può suonare. Se suona vuol dire che il codice qui riportato non è quello eseguito.

eccomi di nuovo

il buzzer non riesco proprio a farlo funzionare

ho eliminato la ritenuta di A in quanto il segnale che arriva dalla centrale allarme è continuo quindi inutile
il led prova è solo per prova
il buzzer o suona sempre o non suona
allego sketck

A= in & !T1  ;
   digitalWrite(ledprova, A );  // Accendo il led solo per verificare che il buzzer segue il led e che lo sketch funzioni
                                //  poi verra eliminato
   tone ( buzzer, 3500 );
   T1 = 0;
   if (!in )
   {
   t1 = millis();
   }
   else if (millis() - t1 >= 2000) T1 = 1;
   }

Come già detto nel post #13, e ripetuto nel #16, l'azzeramento di T1 va sotto condizione, altrimenti ti ritrovi con 'A' che può andare alta per due secondi ogni 1193 ore (il massimo tempo gestibile direttamente con millis).

Poi tone, essendo un processo che va avanti per i fatti suoi, va attivato e disattivato su condizione, non attivato sempre, quindi se vogliamo che suoni solo quando 'A' è alta bisogna rilevare i momenti di salita o discesa di 'A'

|     A       B       .----------.      |
|----] [-----]/[------|buzzer on |------| if (A & !B) { tone(buzzer, 3500); }
|                     '----------'      |
|     A       B       .----------.      |
|----]/[-----] [------|buzzer off|------| if (!A & B) { noTone(buzzer); }
|                     '----------'      |
|     A                           B     |
|----] [-------------------------( )----| B = A;

O in alternativa, se vuoi che faccia solo un beep quando 'A' diventa alta, e si fermi da solo dopo un certo tempo indipendentemente da tutto il resto:

|     A       B       .----------.      |
|----] [-----]/[------|buzzer on |------| if (A & !B) { tone(buzzer, 3500, 500); }  // beep avvio 0,5s
|                     '----------'      |
|     A                           B     |
|----] [-------------------------( )----| B = A;