Tiro a segno elettronico

Salve vorrei costruire un tiro a segno elettronico, dove segna i punti elettronicamente su un display.
Avevo pensato a dei pulsanti collegati agli ingressi digitali di arduino.
Ho abozzato qualcosa del codice ma ho alcuni dubbi da chiarire.

  1. Ai valori digitali 0,1 che appaiono sul display vorrei associare dei punteggi che stabilisco io e possibile la cosa?

  2. Vorrei anche che il punteggio, una volta premuto il tasto, rimarrebbe fisso sul display andandosi a sommare con il punteggio degli altri pulsanti, però non ho trovato qualche pezzo di codice che mi fosse utile.

C’e ne sarebbero tante altre cose da aggiungere, ma andiamo per gradi, efacciamo per ora le cose principali :smiley: .

Ringrazio anticipatamente chi vorrà aiutarmi in questo progetto e mi scuso se sono stato poco esplicito nelle richieste, ma resto a vostra disposizione per eventuali dubbi.

PS: Allego il codice che ho compilato io, cosi da farvi un idea di quello che ho combinato :grin:

// Bersaglio per tiro a segno v1.0
/*
 * Questo sketch è stato creato per visualizzare in un display il punteggio di un tiro a segno.
 */
 
#include <LiquidCrystal.h>
#include <LiquidCrystal_I2C.h>
 
LiquidCrystal_I2C lcd(0x27,16,2);  // set the LCD address to 0x27 for a 16 chars and 2 line display


void setup() {
  Serial.begin(9600);
  pinMode(2, INPUT);
  pinMode(3, INPUT);
  
  lcd.init();                      // initialize the lcd 
 
  // Print a message to the LCD.
  lcd.backlight();
  lcd.print("Tiro a Segno");
  lcd.setCursor(0,1);
  lcd.print("V._1.0_by_Melo92");
  lcd.setCursor(0,1);
  delay(3000);
  lcd.clear();
 
}
 
void loop() {
  int sensorValue = digitalRead(2); 
  sensorValue = digitalRead(3);
  Serial.println(sensorValue, DEC);
  
  lcd.setCursor(0, 1);
  lcd.print("Punti: ");
  lcd.print(sensorValue);
  lcd.print("pnt");
  delay(100);
}

Ciao Melo92,

sicuramente passerà un moderatore chiedendoti di presentarti nell'apposita sezione QUI e di leggere bene il regolamento QUI.
Dopo che lo avrai fatto potremmo iniziare a discutere del tuo progetto...per il momento, senza malizia sia chiaro, c'è un bel po' di confusione.

ciao

ORSO2001:
sicuramente passerà un moderatore chiedendoti di presentarti nell'apposita sezione QUI e di leggere bene il regolamento QUI.

Eccomi :smiley:

>Melo92: essendo il tuo primo post, nel rispetto del regolamento (… punto 13, primo capoverso), ti chiedo cortesemente di presentarti QUI (spiegando bene quali conoscenze hai di elettronica e di programmazione ... possibilmente evitando di scrivere solo una riga di saluto) e di leggere con MOLTA attenzione il su citato REGOLAMENTO ... Grazie. :wink:

Guglielmo

Fatto mi sono presentato.

ORSO2001:
Ciao Melo92,

sicuramente passerà un moderatore chiedendoti di presentarti nell'apposita sezione QUI e di leggere bene il regolamento QUI.
Dopo che lo avrai fatto potremmo iniziare a discutere del tuo progetto...per il momento, senza malizia sia chiaro, c'è un bel po' di confusione.

ciao

Si si hai pienamente ragione, ma con le conoscenze che ho e stato gia un miracolo riuscire a prelevare l'input del pulsante e visualizzarlo sul display :smiley:
Comunque aspetto vostre domande per delucidazioni.
Saluti a tutti

  int sensorValue = digitalRead(2);
  sensorValue = digitalRead(3);
  Serial.println(sensorValue, DEC);

con int dichiari la variabile sensorValue a cui associ da subito il valore letto dal pin2, e fin qui ci può stare, se non fosse che subito dopo associ a sensorValue lo stato del pin 3 quindi la lettura precedente è andata persa e il display ti visualizza solo lo stato 0 o 1 del pin 3. Per avere un incremento del punteggio devi fare una cosa del tipo:

if (pulsante premuto) sensorValue = sensorValue + 1
delay (200)
e poi far visualizzare al display il valore

Il delay è molto importante in quanto evita al micro di conteggiare i rimbalzi del pulsante e conteggiare inpulsi in più, non è il modo più elegante per risolvere il problema ma per iniziare è sicuramente il più semplice.

Aumentando il valore di delay ad esempio a 500 puoi far in modo che tenendo il pulsante premuto ti incrementi di uno il punteggio ogni mezzo secondo

... o magari, ancora meglio, si usa una rete RC come debounce per ogni pulsante e si evitano del tutto i delay bloccanti ... :wink:

si impara a camminare un passo alla volta non correndo :wink:

-zef-:
si impara a camminare un passo alla volta non correndo :wink:

… vero, ma … è sicuramente più complicato un debounce software che mettere un condensatore ed una resistenza sull’ingresso :smiling_imp:

Guglielmo

Confusione… già, oltre al discorso già evidenziato della doppia assegnazione del valore di lettura, ad esempio di queste due ne va lasciata una sola (la I2C visto che ha un display di quel tipo):

#include <LiquidCrystal.h>
#include <LiquidCrystal_I2C.h>

Poi non ho proprio capito cosa intenda con “i valori digitali”. ha due pulsanti, collegati ai pin 2 e 3: che cosa dovrebbe contare il programma quando si preme l’uno o l’altro? Diciamo che il 2 incrementa le unità ed il 3 le decine? Devi mettere una variabile intera che mantiene il valore attuale, e quando si preme un tasto incrementare questa e mostrare il nuovo valore. Poi però deve prima o poi ricominciare da zero (può bastare un reset della scheda ma meglio un apposito tasto, da premere magari per 2 secondi di seguito), oppure per correggere.

gpb01:
... vero, ma ... è sicuramente più complicato un debounce software che mettere un condensatore ed una resistenza sull'ingresso :smiling_imp:

Guglielmo

Scherzi!!! :o Tu trovi più facile saldare un condensatore e una resistenza su un circuito che scrivere un delay(200)???

// Bersaglio per tiro a segno v1.0
/*
 * Questo sketch è stato creato per visualizzare in un display il punteggio di un tiro a segno.
 */
 
#include <LiquidCrystal.h>
#include <LiquidCrystal_I2C.h>
 
LiquidCrystal_I2C lcd(0x27,16,2);  // set the LCD address to 0x27 for a 16 chars and 2 line display


void setup() {
  Serial.begin(9600);
  pinMode(2, INPUT);
  pinMode(3, INPUT);
  
  lcd.init();                      // initialize the lcd 
 
  // Print a message to the LCD.
  lcd.backlight();
  lcd.print("Tiro a Segno");
  lcd.setCursor(0,1);
  lcd.print("V._1.0_by_Melo92");
  lcd.setCursor(0,1);
  delay(3000);
  lcd.clear();
 
}
 
void loop() {
  int sensorValue = digitalRead(2); 
  sensorValue = digitalRead(3);
  Serial.println(sensorValue, DEC);
  if (2,3) sensorValue = sensorValue + 1
  delay (200);
  
  lcd.setCursor(0, 1);
  lcd.print("Punti: ");
  lcd.print(sensorValue);
  lcd.print("pnt");
  delay(100);
}

Quindi il codice diventerebbe così? O come faccio a definire a “Pulsante premuto” i pin dei pulsanti?
Poi ad ogni pulsante ci sarebbe da assegnare una cifra, ad es.
Pulsante 1 → 50
Pulsante 2 → 100
Pulsante 3 → 200 e così via.
Si ci sarebbe anche da aggiungere un tastino di reset, ma questo magari e meglio vederlo piu in la per nn creare confusione.
Saluti a tutti

-zef-:
Scherzi!!! :o Tu trovi più facile saldare un condensatore e una resistenza su un circuito che scrivere un delay(200)???

... scherzi tu a pensare che basta SOLO un delay(200) vero ? ? ? :o

Sarà il caso che ti vai a vedere come si scrive una vera routine di debouncing ... ::slight_smile:

Arduino ne propone una, QUI ... ma ve ne sono altre facendo un po' di ricerche ...

Guglielmo

Melo92:
Quindi il codice diventerebbe così?

Anche no… Non è cambiato molto.

O come faccio a definire a “Pulsante premuto” i pin dei pulsanti?
Poi ad ogni pulsante ci sarebbe da assegnare una cifra, ad es.

Guarda, avevo 5 minuti ed ho provato a farti al volo qualche “ritocchino” (si fa per dire) al codice.

NON ti assicuro che funzioni da subito, però NON devi usarlo e basta, devi CAPIRE cosa ho fatto, e COME funziona. Prova a rimandarlo da te commentato spiegando cosa fa ogni sezione. Solo quando lo avrai capito, allora ti darò l’autorizzazione ad usarlo. :wink:

// Bersaglio per tiro a segno v1.1
/*
 * Questo sketch è stato creato per visualizzare in un display il punteggio di un tiro a segno.
 */
 
//#include <LiquidCrystal.h> NON SERVE!!! CANCELLARE!
#include <LiquidCrystal_I2C.h>
 
LiquidCrystal_I2C lcd(0x27,16,2);  // set the LCD address to 0x27 for a 16 chars and 2 line display

// Numero di tasti gestiti
#define NUMTASTI 2
// Array di configurazione del comportamento dei tasti
int pin[NUMTASTI] = { 2, 3 }; // Pin per i vari tasti
int valore[NUMTASTI] = { 50, 100 }; // valore da sommare per ogni tasto
int val[NUMTASTI]    = {0, 0};      // Stato dei tasti
int oldval[NUMTASTI] = {0, 0};      // stato del pin di input al passo precedente  

// Punti totali attuali
int punti = 0;

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

  for(int i=0; i<NUMTASTI; i++)
    pinMode(pin[i], INPUT);
  
  lcd.init();
 
  // Print a message to the LCD.
  lcd.backlight();
  lcd.print("Tiro a Segno");
  lcd.setCursor(0,1);
  lcd.print("V._1.0_by_Melo92");
  lcd.setCursor(0,1);
  delay(3000);
  
  mostraPunti();
 
}
 
void loop() {
  bool aggiorna = false;
  for (int i=0; i<NUMTASTI; i++)
    if ( leggiTasto(i) ) {
	  punti += valore[i];
	  aggiorna = true;
          delay(200);
	}
  if ( aggiorna ) // Dobbiamo aggiornare il totale?
    mostraPunti();

  delay(100);
}

bool leggiTasto(int tasto) {
  val[tasto] = digitalRead(pin[tasto]);  
  if ((val[tasto] == HIGH) && (oldval[tasto] == LOW)){
    oldval[tasto] = val[tasto];
    return true;
  }   
  oldval[tasto] = val[tasto];
}

void mostraPunti() {
  lcd.clear();
  lcd.setCursor(0, 1);
  lcd.print("Punti: ");
  lcd.print(punti);
  lcd.print("pnt");
  Serial.println(punti);
}

gpb01:
… scherzi tu a pensare che basta SOLO un delay(200) vero ? ? ? :o

-zef- : Aggiungo solo una considerazione … prova ad implementare una serie di routine di debounce software quando hai parecchi pulsanti, specie se devono anche interagire fra loro … :smiling_imp:

Secondo te’, perche’ il 99% dei dispositivi industriali, anche quelli che usano micro con una marea e mezza di memoria, sugli ingressi hanno sempre debounce hardware ? … :wink:

Guardate che non sto parlando del sistema migliore per farlo, ma del più semplice per chi inizia a programmare con arduino, l'ho anche scritto:

..non è il modo più elegante per risolvere il problema ma per iniziare è sicuramente il più semplice.

Inoltre sempre nel caso del programma che intende fare Stefano non penso che bloccare il programma per 200 millesimi di secondo tra un incremento e l'altro del punteggio cambi poi molto ai fini pratici per chi inizia da poco a programmare con arduino.

@Guglielmo se tu appena hai iniziato con arduino usavi già la routine di cui hai messo il link tanto di cappello, purtroppo almeno io non ero a quei livelli, molto probabile non lo sono nemmeno adesso :wink:

Ossignur.. Ogni tanto riciccia fuori la diatriba del debounce... :wink:

Per ora, visto il livello del programma, possiamo considerare sufficiente il delay(200) e chiudere la cosa qui, e tornare a vedere nello specifico il suo problema (magari ad iniziare dal codice che gli ho scritto, 3 post più sopra visto che ci ho perso tempo)?? :wink:

-zef-:
@Guglielmo se tu appena hai iniziato con arduino usavi già la routine di cui hai messo il link tanto di cappello, purtroppo almeno io non ero a quei livelli, molto probabile non lo sono nemmeno adesso :wink:

… guarda che quella è messa la da Arduino e basta fare copia/incolla … anche “senza volrela capire” (… cosa che comunque sarebbe sempre da NON fare).

Il solo delay(200) che hai messo tu li così …

if (pulsante premuto) sensorValue = sensorValue + 1
delay (200)
e poi far visualizzare al display il valore

NON elimina alcun rimbalzo e NON serve a nulla se non ha rallentare il programma … il debouncing, come detto, è un tantino più complesso … ::slight_smile:

Qui magari sembra funzionare, ma NON è sicuramente un debouncing che si può applicare genericamente nei vari casi … e solo un ritardo tra un ciclo del loop() ed un altro …

Guglielmo

si in effetti ho scritto male, doveva essere così per non avere un ritardo continuo di 200mS ad ogno loop:

if (pulsante premuto) 
   {
   sensorValue = sensorValue + 1
   delay (200)
   }

così la pausa la fa solo se viene premuto il pulsante evitando i rimbalzi e non di continuo. Ribadisco il concetto che all'inizio più sono semplici le cose, meglio si capiscono, poi una volta afferrati i concetti base si passa ad ottimizzare il tutto sia livello software che hardware :wink:

docdoc:
Anche no… Non è cambiato molto.

Guarda, avevo 5 minuti ed ho provato a farti al volo qualche “ritocchino” (si fa per dire) al codice.

NON ti assicuro che funzioni da subito, però NON devi usarlo e basta, devi CAPIRE cosa ho fatto, e COME funziona. Prova a rimandarlo da te commentato spiegando cosa fa ogni sezione. Solo quando lo avrai capito, allora ti darò l’autorizzazione ad usarlo. :wink:

// Bersaglio per tiro a segno v1.1

/*

  • Questo sketch è stato creato per visualizzare in un display il punteggio di un tiro a segno.
    */

//#include <LiquidCrystal.h> NON SERVE!!! CANCELLARE!
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27,16,2);  // set the LCD address to 0x27 for a 16 chars and 2 line display

// Numero di tasti gestiti
#define NUMTASTI 2
// Array di configurazione del comportamento dei tasti
int pin[NUMTASTI] = { 2, 3 }; // Pin per i vari tasti
int valore[NUMTASTI] = { 50, 100 }; // valore da sommare per ogni tasto
int val[NUMTASTI]    = {0, 0};      // Stato dei tasti
int oldval[NUMTASTI] = {0, 0};      // stato del pin di input al passo precedente

// Punti totali attuali
int punti = 0;

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

for(int i=0; i<NUMTASTI; i++)
   pinMode(pin[i], INPUT);
 
 lcd.init();

// Print a message to the LCD.
 lcd.backlight();
 lcd.print(“Tiro a Segno”);
 lcd.setCursor(0,1);
 lcd.print(“V._1.0_by_Melo92”);
 lcd.setCursor(0,1);
 delay(3000);
 
 mostraPunti();

}

void loop() {
 bool aggiorna = false;
 for (int i=0; i<NUMTASTI; i++)
   if ( leggiTasto(i) ) {
 punti += valore[i];
 aggiorna = true;
         delay(200);
}
 if ( aggiorna ) // Dobbiamo aggiornare il totale?
   mostraPunti();

delay(100);
}

bool leggiTasto(int tasto) {
 val[tasto] = digitalRead(pin[tasto]);  
 if ((val[tasto] == HIGH) && (oldval[tasto] == LOW)){
   oldval[tasto] = val[tasto];
   return true;
 }  
 oldval[tasto] = val[tasto];
}

void mostraPunti() {
 lcd.clear();
 lcd.setCursor(0, 1);
 lcd.print("Punti: ");
 lcd.print(punti);
 lcd.print(“pnt”);
 Serial.println(punti);
}

Ti ringrazio molto, ho commentato dove ho potuto in altri ho chiesto a cosa serve, abbiate molta pazienza ma e da poco che smanetto con aruino e molte righe di comando non le conosco. Intanto ringrazio tutti per l’aiuto

// Bersaglio per tiro a segno v1.1
/*
 * Questo sketch è stato creato per visualizzare in un display il punteggio di un tiro a segno.
 */
 
//#include <LiquidCrystal.h> NON SERVE!!! CANCELLARE!
#include <LiquidCrystal_I2C.h>
 
LiquidCrystal_I2C lcd(0x27,16,2);  // set the LCD address to 0x27 for a 16 chars and 2 line display

// Numero di tasti gestiti
#define NUMTASTI 2
// Array di configurazione del comportamento dei tasti
int pin[NUMTASTI] = { 2, 3 }; // Pin per i vari tasti
int valore[NUMTASTI] = { 50, 100 }; // valore da sommare per ogni tasto                         Si assegnagno delle specifiche funzioni hai tasti
int val[NUMTASTI]    = {0, 0};      // Stato dei tasti
int oldval[NUMTASTI] = {0, 0};      // stato del pin di input al passo precedente  

// Punti totali attuali
int punti = 0;

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

  for(int i=0; i<NUMTASTI; i++)                                    Non ho ben capito perche i pin vegono assegnati con "i" e di conseguenza vengono portati a zero???
    pinMode(pin[i], INPUT);
  
  lcd.init();
 
  // Print a message to the LCD.
  lcd.backlight();
  lcd.print("Tiro a Segno");
  lcd.setCursor(0,1);
  lcd.print("V._1.0_by_Melo92");
  lcd.setCursor(0,1);
  delay(3000);
  
  mostraPunti();                                                       Ragruppa le istruzioni da eseguire dopo le scritte iniziali.
 
}
 
void loop() {
  bool aggiorna = false;
  for (int i=0; i<NUMTASTI; i++)
    if ( leggiTasto(i) ) {
	  punti += valore[i];                                          Somma i punti di ogni tasto e aggiorna il totale.
	  aggiorna = true;
          delay(200);
	}
  if ( aggiorna ) // Dobbiamo aggiornare il totale?
    mostraPunti();

  delay(100);
}

bool leggiTasto(int tasto) {
  val[tasto] = digitalRead(pin[tasto]);  
  if ((val[tasto] == HIGH) && (oldval[tasto] == LOW)){                 Definisce il comando tasto
    oldval[tasto] = val[tasto];
    return true;
  }   
  oldval[tasto] = val[tasto];
}

void mostraPunti() {
  lcd.clear();
  lcd.setCursor(0, 1);
  lcd.print("Punti: ");                                              Funzioni da far apparire dopo la schermata iniziale
  lcd.print(punti);
  lcd.print("pnt");
  Serial.println(punti);
}

Melo92:
Ti ringrazio molto, ho commentato dove ho potuto in altri ho chiesto a cosa serve, abbiate molta pazienza ma e da poco che smanetto con aruino e molte righe di comando non le conosco.

Non ti preoccupare, il forum serve anche per aiutare chi ancora non ha molta esperienza (ed anche io stesso imparo sempre cose nuove).
Provo a darti le risposte ai tuoi dubbi:

*"int valore[NUMTASTI] = { 50, 100 }; // valore da sommare per ogni tasto *
Si assegnagno delle specifiche funzioni ai tasti"

Più che funzioni in questo vettore specifico il valore da sommare quando si preme un tasto, ossia 50 per il primo tasto (indice 0, come saprai i vettori hanno indici che iniziano da zero), e 100 per l’altro.

" for(int i=0; i<NUMTASTI; i++)

  • pinMode(pin[ i ], INPUT);*
    Non ho ben capito perche i pin vegono assegnati con “i” e di conseguenza vengono portati a zero???"

Quello è un ciclo for() con la variabile “i” che inizia da 0 e si incrementa fino a 1 (NUMTASTI è 2 quindi esce dal for quando i è minore di 2). Come funziona il for() lo leggi QUI.
Con “pin[ i ]” si intende “l’elemento i-esimo della matrice 'pin”, e se vedi l’inizializzazione, il primo valore pin[ 0 ] vale 2 quindi al primo ciclo esegue in pratica “pinMode(2, INPUT)”. Lo stesso per l’altro pin. Questo serve per generalizzare, ossia se tu in futuro dovessi avere 10 pin, avrai il simbolo NUMTASTI che vale 10 quindi quel ciclo andrà da 0 a 9, e quindi setterà i pin specificati nella matrice pin.

" mostraPunti();
Ragruppa le istruzioni da eseguire dopo le scritte iniziali."

Non proprio, qui si richiama una nuova funzione chiamata “mostraPunti” che mostra o aggiorna sul display il valore del puteggio attuale. Questo perché la stessa cosa andrà fatta ogni volta che si preme un pulsante per cambiare il punteggio per cui dato che sarebbero istruzioni identiche, è opportune metterle in una funzione separata e richiamare semplicemente questa.

" punti += valore*;*
Somma i punti di ogni tasto e aggiorna il totale."
Esatto.
" if ((val[tasto] == HIGH) && (oldval[tasto] == LOW)){
* oldval[tasto] = val[tasto];*
* return true;*
* } *
Definisce il comando tasto"
Non esattamente. la if() verifica se il tasto risulta premuto (HIGH) ma dato che dobbiamo identificare quando il tasto viene premuto e non quando resta premuto (ricorda che il loop di Arduino gira molto rapidamente ogni secondo), se in precedenza il tasto non era premuto (LOW) significa che ho “iniziato” a premerlo quindi memorizzo questa condizione e restituisco “true” per segnalare che quel tasto è stato premuto. La seconda volta che si richiama questa funzione, poiché il precedente valore del tasto è “HIGH”, non entro nuovamente nella if quindi non restituisco true ma false (tasto non premuto).
Ci sono tanti modi per gestire i pulsanti ovviamente, e questo è solo uno di questi, ma per iniziare va bene.
Spero di averti chiarito le idee… :wink: