Fare un "beep"

Ciao a tutti.
Windows 10, IDE 1.8.4 windows store, Arduino UNO

Vi spiego velocemente cosa vorrei fare: ho un RGB che diventa rosso o verde quando viene attivato un interruttore (in questo caso un interruttore magnetico). Come faccio a far fare un beep al mio buzzer attivo per un tot di tempo quando lo stato del led cambia?
Allego lo sketch per chi volesse.

int p = 0;
int s = 0;

void setup() {
  // put your setup code here, to run once:
Serial.begin(9600);
pinMode(2, INPUT);
pinMode(3, OUTPUT);
pinMode(4, OUTPUT);
pinMode(5, OUTPUT);
}

void loop() {
  // put your main code here, to run repeatedly:
p = digitalRead(2);
Serial.println(s);

 if (p == HIGH) {  
    s = 1 - s; 
   }  

   delay(300);

 if (s == HIGH) {
    // turn LED on:
    digitalWrite(4, HIGH);
    digitalWrite(3, LOW);
  } else {
    // turn LED off:
    digitalWrite(3, HIGH);
    digitalWrite(4, LOW);
  }


}

Grazie in anticipo

Potresti usare una flag (variabile segnaposto qualsiasi) ... memorizzi lo "stato" dell'interruttore, e con un'if ogni volta che cambia lo aggiorni e mandi un tone ...

Pero', se il pulsante lo leggi cosi, ad ogni pressione ti eseguira' l'if centinaia di volte, perche' ad ogni ciclo del loop lo considerera' valido, e data la velocita' del loop. anche una pressione breve viene letta molte volte, per cui ti serve un modo per dire al sistema di eseguirlo una sola volta, poi aspettare fino al rilascio per leggere una nuova pressione ... inoltre non usare quel delay in quel modo, per fare un debounce metti una rete RC sul contatto ...

Ehm...premetto che in programmazione non sono molto ferrato, per quanto riguarda l'hardware sto imparando.
Potresti mandarmi uno sketch d'esempio e come dovrei leggere secondo te il pulsante; e poi cos'è una rete RC?

Una rete RC serve per eliminare la maggior parte dei possibili "rimbalzi" di un contatto meccanico (che data la velocita' di esecuzione, verrebbero quasi sicuramente letti come pressioni e rilasci ripetuti, causando malfunzionamenti) ... in genere, un condensatorino ceramico da 100n o simile valore fra il pin e massa, ed una resistenza da 100 ohm o valori simili fra il pin ed il pulsante, funzionano meglio di qualsiasi routine di debounce ...

Per lo sketch, ti ho buttato giu al volo due righe modificando il tuo, ma non sono un programmatore, e non ho qui un modo per testarlo, consideralo solo un'esempio di base, che va ottimizzato (come dice sempre Guglielmo, studiate, non fate copia-incolla ;)) ... ho preferito dividere la parte che attiva le uscite e genera il beep in una seconda funzione, cosi viene richiamata solo una volta ogni pressione del tasto e la cosa si semplifica ... e devi mettere i parametri corretti nella tone, perche' non so quale pin, che frequenza e che durata gli vuoi far fare ...

byte p = LOW;
byte p2 = LOW;
byte s = LOW;

void setup()
{
   Serial.begin(9600);
   pinMode(2, INPUT);
   pinMode(3, OUTPUT);
   pinMode(4, OUTPUT);
   pinMode(5, OUTPUT);
}

void loop()
{
   p = digitalRead(2);             //leggo contatto
   Serial.println(s);
 
   if ((p == HIGH) && (p2 != p))   //se contatto = 1 e flag diversa da contatto
   {
      s = !s;                      //inverto s
      p2 = p;                      //setto flag contatto
      ledchange();                 //richiamo funzione uscite
   }
   if ((p == LOW) && (p2 != p)) p2 = p;   //al rilascio resetto flag
   }
}   

void ledchange()
{
   tone (pin, frequenza, durata in millisecondi);   //metti i tuoi valori
   if (s == HIGH)
   {
      digitalWrite(4, HIGH);
      digitalWrite(3, LOW);
   }
   else
   {
      digitalWrite(3, HIGH);
      digitalWrite(4, LOW);
   }
}

Ok grazie ora provo, e poi io sto usando un buzzer attivo cioè un buzzer che emette un suono fisso al solo applicare tensione (a mio avviso molto comodo per dare segnali di "sistema"). Provo lo sketch e comunico ulteriori sviluppi

Allora devi modificare la tone, quella serve per i buzzer passivi o gli altoparlanti ...

Ho cercato di capire il tuo sketch ma me lo devo vedere bene perchè non sono a questo livello di programmazione...ho provato a compilarlo e dice "ledchange was not declared in this scope" solo che non so come risolverlo non capendo bene cosa hai fatto.
Sisi già modificata...la tone è una delle poche cose che conosco non benissimo ma abbastanza.

Lory:
Ho cercato di capire il tuo sketch ma me lo devo vedere bene perchè non sono a questo livello di programmazione...ho provato a compilarlo e dice "ledchange was not declared in this scope" solo che non so come risolverlo non capendo bene cosa hai fatto.
Sisi già modificata...la tone è una delle poche cose che conosco non benissimo ma abbastanza.

Dimmi cosa non e' chiaro, ma tieni presente che era solo un'esempio adattato al tuo sketch, non un programma completo ... ed anche che non sono un programmatore, e l'ho buttata giu al volo ...

Strano per l'errore, in teoria e' una banale funzione ... prova a spostarla (tutto il blocco della funzione ledchange) fra il setup ed il loop, magari la vuole scritta prima che venga chiamata, anche se mi sembra che dovrebbe funzionare lo stesso anche scritta dopo ... mah ...

Allora: non avevo mai usato flag prima ne un "void" diverso da setup e loop, mi sto un po studiando lo sketch.
Per quanto riguarda l'errore dice che non può andare tra setup e loop, se lo metto nel loop da errore e non credo che serva metterlo nel setup.

Aggiornamento: ho risolto l'errore di compilazione, nel 2 if del loop non avevi aperto la graffa (non credo non ci volesse ma non so ora vedi). Poi non ho capito come fare a farlo suonare. Metto lo sketch dimmi cosa sbaglio.

byte p = LOW;
byte p2 = LOW;
byte s = LOW;

void setup()
{
   Serial.begin(9600);
   pinMode(2, INPUT);
   pinMode(3, OUTPUT);
   pinMode(4, OUTPUT);
   pinMode(5, OUTPUT);
}

void loop()
{
   p = digitalRead(2);             //leggo contatto
   Serial.println(s);
 
   if ((p == HIGH) && (p2 != p))   //se contatto = 1 e flag diversa da contatto
   {
      s = !s;                      //inverto s
      p2 = p;                      //setto flag contatto
      ledchange();                 //richiamo funzione uscite
   }
   if ((p == LOW) && (p2 != p)) 
   {
   
   p2 = p;   //al rilascio resetto flag
   }
}   

void ledchange()
{
digitalWrite(12, HIGH);
   if (s == HIGH)
   {
      digitalWrite(4, HIGH);
      digitalWrite(3, LOW);
   }
   else
   {
      digitalWrite(3, HIGH);
      digitalWrite(4, LOW);
   }
}

Be', una "flag" non e' altro che una "bandierina segnaposto", cioe' una qualsiasi variabile (in questo caso byte, dato che puo essere solo alta o bassa non serve int), che usi per far "tenere a mente" allo sketch una condizione ... prendiamo ad esempio il controllo del tasto, dove ho usato p2 come flag ...

Dopo ogni lettura, il primo if controlla che p sia alta, ed allo stesso tempo p2 sia diversa da p (cioe', prima il tasto non era premuto, ed e' appena stato premuto) ... qui inverti s, rimetti p2 uguale a p, e chiami la sub ledchange, che cambia le uscite in base al valore di s, ed attiva il beep (e qui secondo me' dovresti modificarlo facendo, per il beep, dopo la digitalwrite, un delay di 50 o 100mS massimi, ed un'altra digitalwrite per spegnere il beep, cosi fa solo un breve suono ad ogni chiamata ... mentre messo cosi, rimane sempre acceso) ...

Sempre nel loop, una volta che il primo if e' stato eseguito, non verra' piu rieseguito mentre il contatto rimane ad 1, perche' p2 non sara' piu diverso da p, dopo la prima esecuzione ... questo per evitare che ad ogni ciclo del loop le istruzioni vengano rieseguite in continuazione finche' rimane ad 1 ... il secondo if legge invece il rilascio, anche qui, nel momento del rilascio, p e' basso e p2 diverso da p, quindi lo esegue una sola volta rimettendo p2 uguale a p (e nel caso servisse eseguire altre istruzioni solo nel momento in cui il contatto si apre, andrebbero richiamate qui, ma questa e' un'altra cosa)

Per la graffa, piu che altro mi sa che ne ho scritta una in piu dopo l'if, ma dato che esegue un solo comando, sia con che senza dovrebbe funzionare lo stesso ... lasciale pure entrambe che male non gli fanno :smiley: