Pulsante che invia lo stato HIGH, LOW da seriale

Ciao a tutti, credo che questo sia il mio ultimo passaggio nel completare una sezione. Ho girato tantissimi siti, tutorials e latro, ma senza trovare una soluzione definitiva.

Io dovrei inviare lo stato di un pulsante al mio Saoftware su pc, ma senza delay e con antirimbalso es: "premo un tasto e solo con quella pressione invio una stringa es: D1_ON" Al rilascio del pulsante stesso, invierò il comando es: "D1_OFF" Ci sono tante soluzioni, Ee questa è quella che ho iniziato io

byte oldD10;
void setup() {
  Serial.begin(19200);
  digitalWrite(10, HIGH);
  oldD10 = digitalRead(10); //inizializzi con lo stato del pin 10 (è un esempio)
}

void loop() 
{
  byte pin10 = digitalRead(10);
  if (oldD10 != pin10) {
    oldD10 = pin10;
     Serial.println("D1_ON");
   }
}

Come vedete funziona quasi perfettamente, nel senso che anche se MANTENGO premuto il pulsante, i caratteri vengono inviati da seriale solo una volta. Naturalmente viene inviato un treno di impulsi, ma a questo si puo rimediare.

ho provato ad inserire la funzione ELSE per inviare il comando di rilascio, ma fa confusione, nel senso che invia ripetutamente il comando di rilascio non prendendo piu quello di pressione. è tutto il giorno che sto davanti al pc a trovare una soluzione, ma non riesco. non esiste un tutorial simile che racchiude un antirimbalzo e invio stato al rilascio del pulsante? Per fortuna questa è l' ultima cosa che mi serve, spero di contare sul vostro aiuto anche se io comunque sto provando da solo.

aggiungendo delay (50); si ottine un miglioramento, ma perchè anche al rilascio del pulsante viene inviato il comando? comunque non prediligo i delay perchè si blocca il processore e vorrei evitare visto che ci sono altri comandi che devono essere ricevuti

Dai che è facile ... ci devi lavorare un po' su ... ;)

Tanto per cominciare dichiara il pin su cui hai attaccato il pulsante come INPUT_PULLUP (... guarda QUI) :

pinMode(10, INPUT_PULLUP);

... in questo modo fissi il pin a HIGH (tramite una resistenza interna al chip di pull-up) e con il pulsante lo colleghi a massa portandolo LOW, dopo di che ... stavi sulla buona strada per il debouncing ...

Questo è un metodo piuttosto semplice :

byte buttonStatus;
byte lastStatus = HIGH;

........

pinMode(10, INPUT_PULLUP);

........

buttonStatus = digitalRead(10);
if (lastStatus != buttonStatus) {
   delay(60);
   buttonStatus = digitalRead(10);
   if (lastStatus != buttonStatus) {
      lastStatus = buttonStatus;
      if (buttonStatus == LOW) {
         ... qui il bottone è premuto .......
      }
      else {
         ... qui il bottone è rilasciato .......
      }
   }
}

... ora cerca di ragionare sulla parte che ti manca ... se hai difficoltà proviamo ad andare avanti assieme ;)

Guglielmo

P.S. : Come pin ho messo 10 perché ho visto che usi quello, ovviamente qualunque altro va bene ...

Gentilissimo, infatti volevo solo una indicazione, vorrei affrontare il problema da solo, con aiuto naturalmente :) mi sono portato com me il mac e naturalmente Arduino quindi, posso provare perché non sono a casa. Se ho problemi mi faccio vivo. grazie ancora :)

ho notato un delay 60, l'ho messo anche io per fare le varie prove, ma sarebbe possibile sostituirlo con una funzione che richiama il contatore millis? Vorrei che non ci siano blocchi per la conseguenza di un Delay...

... sei dentro una funzione antirimbalzo ... devi per forza aspettare per lasciare finire i rimbalzi ... per poi proseguire a seconda di come è il pulsante.

Ricorda che mica sei su un PC o su MAC che possono girare altre cose ... qui il programma è uno ed uno solo, quello che scrivi tu, quindi ... che incasini a fare il tutto quando tanto stai comunque verificando se il pulsante è stato premuto o meno ??? Complicheresti notevolmente la logica probabilmente per nulla.

Inoltre quel piccolo delay di 60 mSec si ha SOLO quando premi o rilasci il pulsante, altrimenti neanche ci passa.

Un domani che sarai più esperto e magari userai gli interrupt, sappi che la delay comunque NON li blocca ... quindi, se un domani userai gli interrupt, comunque la cosa non cambierà perché nei loro confronti la delay è ininfluente ;)

In conclusione ... non dare retta alle voci che "demonizzano" la delay() ... la delay() si può tranquillamente usare la dove comunque NON avresti altre cose da poter fare (come in questo caso in cui devi comunque capire se il pulsante è stato premuto o meno).

Ah ... In programmi dove NON puoi permetterti neanche 1 mSec di delay ... il debouncing lo fai con un apposito trigger HW così è più affidabile e non necessita di interventi da parte del SW.

Guglielmo

Sei un grande, non so come ringraziarti. Mi sono divertito a completarlo, ho visto che non hai inserito i void loop e setup, ma mi sono divertito te lo posto così vedi se è stato scritto bene. ti chiedo solo di correggerlo per quanto riguarda le parentesi così da capire come si deve ordinare un Software

byte buttonStatus;
byte lastStatus = HIGH;

void setup() {
  Serial.begin(19200);
  digitalWrite(10, HIGH);
pinMode(10, INPUT_PULLUP);
}

void loop() 
{
buttonStatus = digitalRead(10);
if (lastStatus != buttonStatus) {
   delay(60);
   buttonStatus = digitalRead(10);
   if (lastStatus != buttonStatus) {
      lastStatus = buttonStatus;
      if (buttonStatus == LOW) {
         Serial.println("D1_ON");
      }
      else {
        Serial.println("D1_OFF");
      }
   }
}}

Vada per il delay, tanto non ci son o funzioni vitali che posso essere interrotte, casomai se una stringa viene mandata al momento stesso che sto immettendo i valori del tastierino oppure un sensore allarme interviene, non succede niente. Ascolta, vista la tua esperienza e sapienza :) ne approfitto per chiederti se è un problema lasciare chiuso il contatto in modo permanente perché i sensori allarmi funzionano con un positivo di riferimento quindi, se viene a mancare, l' allarme se è ativo suona. ora mi trovo nella logica contraria, nel senso che non devo configurare via software la resistenza di pullup perché devo portare un positivo quindi, resistenza hardware da inserire come obbligo giusto? arduino accetta segnali a +12 volt oppure devo aggiungere altra resistenza? se fosse cosi, sarà il caso di utilizzare degli optoarray perché ho un totale di 20 canali impiegati per l' allarme. hai dei suggerimenti da darmi, hai sicuramente esperienze e consigli da darmi :) :) per il momento grazie infinite, sto cominciando a capire la meccanica del C ed è molto divertente.

Le stringhe sulla seriale, normalmente, sono ricevute tramite un meccanismo ad interrupt e quindi, come ti ho detto, la delay è ininfluente, la ISR (la routine che serve l'interrupt) viene comunque eseguita ;)

Mmm ... se lavori a logica contraria allora NON devi attivare la pull-up ma DEVI limitare la tensione ... Arduino accetta massimo 5v sugli ingressi, con un valore maggiore bruci il pin e poi .... probabilmente anche altro ...

Per il resto, no, non c'è problema a tenere un pin HIGH o LOW ... non cambia nulla, se non i test che fai a livello di programma.

Puoi usare sia gli optoaccoppiatori che un partitore resistivo, limitando magari, per sicurezza, l'uscita verso Arduino con uno zener ;)

Guglielmo

P.S. : QUI un'utile lettura per imparare a NON fare danni ...

Praticamente quanto presumevo. Ho visto che arduino accetta 5v, ma non voglio mettere troppi partitori resistivi, preferisco realizzare un picco hardware esterno, magari anche un maxim dedicato al' anti rimbalzo e 5 opto array per un totale di 20 foto transistor..poi vedo. In questo caso lo sketch va sempre bene, devo solo eliminare digital write pull-up perchè non dovrò portare la massa, ma un +5vcc e sono io che decido cosa inviare al rilascio. tutta la routine verrà fatta da Software esterno quindi non vedo altri problemi.

per quanto riguarda 20 positivi su 20 pin non succede nulla vero? non vorrei rschiare conflitti visto che devo collegare anche un tastierino numerico e 16 sensori temperatura lm35 e alcuni altri sensori digitali. per adesso funziona tutto, mi rimane piu un problema, il tasto 8 del tastierino che viene inviato anche se non è stata portata la massa a quel pin. :~ :~ spero si possa risolvere perché è una libreria che poi conoscono

No, puoi avere tutti i pin in stato HIGH o LOW e non cambia nulla (... se fossero in output si, dovresti valutare gli assorbimenti, ma i tuoi sono in input quindi non c'è problema) ;)

Strano il problema del tasto 8 ... ho letto la libreria e se non premi nulla dovrebbe ritornare NO_KEY che è uguale a 0x00 ... :roll_eyes:

Guglielmo

P.S. per sistemare le indentature e le parentesi usa il comando dell IDE : Tools -> Auto Format ;)

caspita, non si finisce mai di imparare...ho trovato la formattazione automatica, bastava spulciare :P ora devo capire come replicare queste istruzioni per 20 input.

la soluzione del void che richiama la funzione potrebbe andare bene?

void loop() {
  CONTEGGIONUMERI();//è il nome della funzione
  contatore_volte();//è il nome della funzione
  LEGGITEMPERATURA();//OGNI 4 CICLI, LEGGI LA TEMPERATURA
  TASTIERINO();//LEGGI VALORI DA TASTIERINO

cosa mi consigli per moltiplicare quelle istruzioni senza fare danni? ho trovato nei tutoria di michele maffucci?? correggimi se ho sbagliato nome, dove ha messo uno sketch che inizializza delle funzioni con void e che vanno tutte insieme in modo indipendente, sarebbe la strada giusta? queste sono cose che non ho trovato nei tutoria...

fatto, adesso devo capire se questa è la strada da seguire

byte buttonStatus;
byte buttonStatus2;
byte lastStatus = HIGH;
byte lastStatus2 = HIGH;

void setup() {
  Serial.begin(19200);
  digitalWrite(10, HIGH);
  digitalWrite(11, HIGH);
  pinMode(10, INPUT_PULLUP);
  pinMode(11, INPUT_PULLUP);
}

void loop() 
{
  buttonStatus = digitalRead(10);
  if (lastStatus != buttonStatus) {
    delay(60);
    buttonStatus = digitalRead(10);
    if (lastStatus != buttonStatus) {
      lastStatus = buttonStatus;
      if (buttonStatus == LOW) {
        Serial.println("D1_ok");
      }
      else {
        Serial.println("D1_null");

      }
    }
  }
  buttonStatus2 = digitalRead(11);
  if (lastStatus2 != buttonStatus2) {
    delay(60);
    buttonStatus2 = digitalRead(11);
    if (lastStatus2 != buttonStatus2) {
      lastStatus2 = buttonStatus2;
      if (buttonStatus2 == LOW) {
        Serial.println("D2_ok");
      }
      else {
        Serial.println("D2_null");

      }
    }
  }
}

Posso continuare senza problemi?? oppure è il modo più sbagliato di operare? :)

edstarink:
… ora devo capire come replicare queste istruzioni per 20 input …

Semplice, specialmente se sono su input digitali in sequenza

… fai UNA SOLA funzione a cui, con un ciclo di for passi i numeri da PINiniziale a PINfinale ogni volta incrementando di uno :wink:

byte mioPin;

.........

for (mioPin = PINiniziale; mioPin < PINfinale; mioPin ++) {

   ... qui dentro mioPin indica il pin uno dopo l'altro ...

}

Guglielmo

Edit : Insomma … se hai delle cose sequenziali … perché ripetere il codice … XD

mmmm qua faccio un po fatica :relaxed: ma ho la piena indipendenza degli ingressi con quel sistema? peccato che non sono ancora entrato in quella fase.

... in pratica oggi tu duplichi N volte la stessa cosa in sequenza ... prima controlli il primo bottone, poi il secondo e così via.

Ora, perché ripetere N volte l stesso codice ???

Racchiudi il codice all'interno di un ciclo for ed usi la variabile del for come numero del pin. Il for in sequenza incrementa la sua variabile e tu, uno dopo l'altro, verifichi tutti gli ingressi, sempre con lo stesso codice ;)

E' il sistema più pulito ed efficace :)

Guglielmo

Edit : Istruzione FOR

Si, il concetto è chiaro, io uso questa funzione nei miei Software quando devo controllare lo stato di tutti. In quel caso creo un loop quante volte sono i pulsanti e poi con diverse istruzioni, faccio l' analisi e l' inio dati alla centralina, ma qua le cose sono scritte in modo diverso, è come conoscere una poesia a memoria e adattarla in' altra lingua. Tra l' altro a proposio di lingue, l' inglese non è il mio forte. Provo a cercare sul web se trovo qualcosa in italiano che spiega questa cosa. al limite se non dovessi riuscire, replicare le istruzioni compromette rallentamenti oppure si tratta solo di memoria? anche perchè non ci sono altre istruzioni, uso arduino come lettore seriale e oltre ad inviarmi dati seriali, non fa.

Sto cercando di analizzare questo:

byte mioPin;

.........

for (mioPin = PINiniziale; mioPin < PINfinale; mioPin ++) {

   ... qui dentro mioPin indica il pin uno dopo l'altro ...

}

Credo di aver capito, nel senso che non serve scrivere una ad una le variabili, ma basta usare un ciclo for, ma questo vale anche per la condizione che controlla lo stato di ogni pulsante se premuto o rilasciato?

Mi spiego meglio: è una funzione tipo multiplexer ma software? in realtà è una sola alla volta che viene eseguita ad una frequenza velocissima?

Ci sto arrivando, ho trovato un video che lo spiega molto bene... :)

edstarink: ... al limite se non dovessi riuscire, replicare le istruzioni compromette rallentamenti oppure si tratta solo di memoria? anche perchè non ci sono altre istruzioni, uso arduino come lettore seriale e oltre ad inviarmi dati seriali, non fa.

E' essenzialmente una questione di ... eleganza di programmazione ed ottimizzazione del codice.

Se i pin diventano 50 che fai ??? 50 volte la stessa routine ???

Guarda che è veramente facile ... devi immaginare il numero di pin come una variabile che si incrementa di uno ad ogni giro ... il resto resta tutto uguale, non ti serve avere buttonStatus, buttonStatus2, buttonStatus3 ... ne basta UNO e così per le altre cose, cambia solo il pin da cui leggi ... ;)

Dai, dai, provaci ... ;)

Guglielmo

Lo so, io faccio gia quella cosa, ma scritta con un codice differente. La logica è la stessa e mi sta intrippando parecchio perchè la so fare, ma mi mancano alcune cosette.

Ci sto provando....

EDIT: Ma con la funzione for, devo per forza utilizzare i pin che stanno dentro al numero compreso tra l' inizio del ciclo e la fine es: se ho utilizzato i pin 1,2,3,4,9,11,15 questa cosa non la posso fare, perchè devo avere tutti i pin in ordine progressivo...giusto?

:astonished: :astonished: :astonished: :astonished: scusami, ma ho notato una cosa mi ha mandato in confusione piu totale Il delay....

se io ho 10 ingressi, se faccio la duplicazione dei codici per ogni canale tutti sono indipendenti, nel senso che se premo un pulsante, si esegue quell istrizione, ma con il for, se ho un delay di 60ms, quando arrivo alla lettura dell' ultimo pulsante, il decimo, avrà un delay totale di 60x10=600ms piu di mezzo secondo. se il ciclo for è iniziato e premo immediatamente il decimo pulsante, non succede niente perchè il ciclo for sarà arrivato forse a metà. Se ho capito bene credo dia cosi, giusto? se invece di mettere 60, mettessi 1 secondo, per completare un ciclo di for, con 10 pulsanti, passano dieci secondi??? se è cosi mi sembra bizzarra la cosa, ma la mia solo una interpretazione. Ho visto esempi di for con delay, ma fanno una cosa sola, mentre io da quei pulsanti ho un cambio di stato anche repentino.