Contapezzi con display 7 segment

Salve a tutti, devo costruire un contapezzi manuale, il circuito è molto semplice, ogni volta che premo un pulsante mi va ad aumentare di una unità la variabile buttonPushCounter e il risultato viene visualizzato su un display a 7 segmenti (il modello che ho disponibile è quello in foto allegata). Un secondo pulsante mi va ad azzerare il contatore e pulisce il display.

Il tutto funziona col monitor seriale, ma se collego il display visualizzo solo le cifre da 1 a 9 poi le lettere da "a" a F poi si ferma. Io ho la necessità di arrivare a contare fino a 90, ma non so come "dire" al display di visualizzare le 2 cifre del contatore.

Ho studiato il funzionamento su Playground, Arduino Playground - LedControl
e credo che necessiti usare la funzione

void printNumber(int v) {
    int ones;
    int tens;
    int hundreds;
    boolean negative; 
[code]

ma non riesco a capirne il funzionamento. Chiedo qualche suggerimento, non la soluzione, voglio arrivarci da solo  :D 

Questo è il codice del contapezzi che ho provato.

[code]

 //State change detection (edge detection)
//We always have to include the library
#include "LedControl.h"

/*
 Now we need a LedControl to work with.
 pin 12 is connected to the DataIn 
 pin 11 is connected to the CLK 
 pin 10 is connected to LOAD 
 We have only a single MAX72XX.
 */
LedControl lc=LedControl(12,11,10,1);

/*  The circuit:
 - buttonpin attached to pin 2 from +5V
 - buttonreset attached to pin 4 from +5V
 - 10 kilohm resistor attached to pin 2&4 from ground
*/
// this constant won't change:
const int  buttonPin = 2;// the pin that the pushbutton is attached to
const int  buttonReset = 4;// the pin that the buttonreset is attached to

// Variables will change:
int buttonPushCounter = 0;   // counter for the number of button presses
int buttonState = 0;         // current state of the button
int lastButtonState = 0;     // previous state of the button

void setup(){
  /*
   The MAX72XX is in power-saving mode on startup,
   we have to do a wakeup call
   */
  lc.shutdown(0,false);
  /* Set the brightness to a medium values */
  lc.setIntensity(0,8);
  /* and clear the display */
  lc.clearDisplay(0);

  // initialize the button pin as a input:
  pinMode(buttonPin, INPUT);
  pinMode(buttonReset, INPUT);
}

void loop() {
  // read the pushbutton input pin:
  buttonState = digitalRead(buttonPin);

  // compare the buttonState to its previous state
  if (buttonState != lastButtonState) {
    // if the state has changed, increment the counter
    if (buttonState == HIGH) {
      // if the current state is HIGH then the button went from off to on:
      buttonPushCounter++;
      lc.setDigit(0,0,buttonPushCounter,false);
    } 
    // Delay a little bit to avoid bouncing
    delay(50);
  }
  // save the current state as the last state, for next time through the loop
  lastButtonState = buttonState;

  // if the buttonreset is pressed reset the buttonpushcounter
  if  (digitalRead(buttonReset) == HIGH){
      (buttonPushCounter = 0);
       lc.clearDisplay(0);
    }
  }

[/code]
[/code]

Ciao! Premettiamo che stai usando una libreria, il display si potrebbe controllare anche senza librerie ma sarebbe molto complicato!

Nel link che hai mostrato c'è la soluzione, forse non è cosi immediato capirla per un principiante come NOI! :slight_smile:

Nel display a 7 segmenti gestisci la stampa su un solo riquadro! Se il display è a 2 cifre, prima stampo le unità e poi stampo le decine, non è come un lcd che automaticamente stampa più cifre.

Per cui tu hai un numero intero che va da 0 a 90,

  1. Ti ricavi le unità
    2)Ti ricavi le decine
  2. Stampi le unità sul display
  3. Stampi le decine sul display

Adesso per ricavare le unità prendi il resto della divisione per dieci, e in C si fa con l'operatore %

Esempio :

int contatore=46;
int unità=0;
int decine=0;

void loop(){

   unita=contatore%10; // Il resto della divisione per 10 sono la cifra unità
   decine=contatore/10; // Divido il numero per 10 e ottengo le decine 
   
   lc.setDigit(0,0,(byte)unita,false);// stampo le cifre delle unita
   lc.setDigit(0,1,(byte)decine,false);// stampo le cifre delle decine
   
}

Che poi è quello che cera scritto nel link da te postato :wink:

Nel link non calcola solo decine e unità ma anche le migliaia!

Dal tuo link

ones=v%10;
    v=v/10;
    tens=v%10;
    v=v/10;
    hundreds=v;			
    if(negative) {
       //print character '-' in the leftmost column	
       lc.setChar(0,3,'-',false);
    }
    else {
       //print a blank in the sign column
       lc.setChar(0,3,' ',false);
    }
    //Now print the number digit by digit
    lc.setDigit(0,2,(byte)hundreds,false);
    lc.setDigit(0,1,(byte)tens,false);
    lc.setDigit(0,0,(byte)ones,false);
}

Ok grazie Torn, con la tua spiegazione mi è più chiaro, ora provo ad applicarlo.

Ok sono riuscito nel mio intento, contare fino a 90, ma per curiosità ho provato a inserire anche la variabile per le centinaia in modo da poter contare anche oltre il 99, ma al nr. 100 appare la scritta 1a0 e a 110 appare 1b0 e così via senza però visualizzare 100...110...120... Cosa c'è di sbagliato?

 //State change detection (edge detection)
//We always have to include the library
#include "LedControl.h"

/*
 Now we need a LedControl to work with.
 pin 12 is connected to the DataIn 
 pin 11 is connected to the CLK 
 pin 10 is connected to LOAD 
 We have only a single MAX72XX.
 */
LedControl lc=LedControl(12,11,10,1);

/*  The circuit:
 - buttonpin attached to pin 2 from +5V
 - buttonreset attached to pin 4 from +5V
 - 10 kilohm resistor attached to pin 2&4 from ground
*/
// this constant won't change:
const int  buttonPin = 2;// the pin that the pushbutton is attached to
const int  buttonReset = 4;// the pin that the buttonreset is attached to

// Variables will change:
int contatore = 0;   // counter for the number of button presses
int buttonState = 0;         // current state of the button
int lastButtonState = 0;     // previous state of the button
int unita = 0;
int decine = 0;
int centinaia = 0;

void setup(){
  /*
   The MAX72XX is in power-saving mode on startup,
   we have to do a wakeup call
   */
  lc.shutdown(0,false);
  /* Set the brightness to a medium values */
  lc.setIntensity(0,8);
  /* and clear the display */
  lc.clearDisplay(0);

  // initialize the button pin as a input:
  pinMode(buttonPin, INPUT);
  pinMode(buttonReset, INPUT);
}

void loop() {
  // read the pushbutton input pin:
  buttonState = digitalRead(buttonPin);

  // compare the buttonState to its previous state
  if (buttonState != lastButtonState) {
    // if the state has changed, increment the counter
    if (buttonState == HIGH) {
      // if the current state is HIGH then the button went from off to on:
      contatore++;
 unita=contatore%10;
 decine=contatore/10;
 centinaia=contatore/100;
 
      lc.setDigit(0,2,(byte)centinaia,false);
      lc.setDigit(0,1,(byte)decine,false);
      lc.setDigit(0,0,(byte)unita,false);
    } 
    // Delay a little bit to avoid bouncing
    delay(50);
  }
  // save the current state as the last state, for next time through the loop
  lastButtonState = buttonState;

  // if the buttonreset is pressed reset the buttonpushcounter
  if  (digitalRead(buttonReset) == HIGH){
      (contatore = 0);
       lc.clearDisplay(0);
    }
  }

La sequenza corretta di operazioni é
Variabile n=numero%10;
Numero=numero/10;
Varuabile n1=numero%10;
Numero=numero/10
... E così via.
Se metti le variabilinin un array con una for ti fai fino a quando vuoi (salvo poi finire i pin)

Ciao! Di sbagliato c'è il modo in cui calcoli le migliaia!

// Tu fai cosi e non stai calcolando le migliaia...
unita=contatore%10; 
 decine=contatore/10; 
 centinaia=contatore/100;

/******************************************/

//Dovrebbe essere [b]per passare all'ordine di grandezza superiore dividi sempre per 10 e poi prendi il resto[/b]

unita=contatore%10; //Resto della divisione per dieci sono le unità
contatore=contatore/10; // Divido per dieci adesso contatore contiene le DECINE esempio 23 decine
decine=contatore%10;// Prendo il resto della divisione per dieci e sono le decine

// Esempio se contatore è uguale a 23 DECINE prendo il resto e sono 3 decine


 centinaia=contatore/10;// Adesso decine diviso 10 sono le centinaia ESEMPIO 23 decine/10=2,3 
//visto che usiamo variabili intere int, in centinaia sarà inserito solo 2

Silente:
La sequenza corretta di operazioni é
Variabile n=numero%10;
Numero=numero/10;
Varuabile n1=numero%10;
Numero=numero/10
... E così via.
Se metti le variabilinin un array con una for ti fai fino a quando vuoi (salvo poi finire i pin)

Allora seguendo la sequenza di Silente ho compilato il codice che segue, ma il risultato che ottengo è che appare solo il nr. 1 poi basta, resta fermo lì!!

[code]

 //State change detection (edge detection)
//We always have to include the library
#include "LedControl.h"

/*
 Now we need a LedControl to work with.
 pin 12 is connected to the DataIn 
 pin 11 is connected to the CLK 
 pin 10 is connected to LOAD 
 We have only a single MAX72XX.
 */
LedControl lc=LedControl(12,11,10,1);

/*  The circuit:
 - buttonpin attached to pin 2 from +5V
 - buttonreset attached to pin 4 from +5V
 - 10 kilohm resistor attached to pin 2&4 from ground
*/
// this constant won't change:
const int  buttonPin = 2;// the pin that the pushbutton is attached to
const int  buttonReset = 4;// the pin that the buttonreset is attached to

// Variables will change:
int contatore = 0;   // counter for the number of button presses
int buttonState = 0;         // current state of the button
int lastButtonState = 0;     // previous state of the button
int unita = 0;
int decine = 0;
int centinaia = 0;


void setup(){
  /*
   The MAX72XX is in power-saving mode on startup,
   we have to do a wakeup call
   */
  lc.shutdown(0,false);
  /* Set the brightness to a medium values */
  lc.setIntensity(0,8);
  /* and clear the display */
  lc.clearDisplay(0);

  // initialize the button pin as a input:
  pinMode(buttonPin, INPUT);
  pinMode(buttonReset, INPUT);
}

void loop() {
  // read the pushbutton input pin:
  buttonState = digitalRead(buttonPin);

  // compare the buttonState to its previous state
  if (buttonState != lastButtonState) {
    // if the state has changed, increment the counter
    if (buttonState == HIGH) {
      // if the current state is HIGH then the button went from off to on:
      contatore++;
      
 unita=contatore%10;
 contatore=contatore/10;
 decine=contatore%10;
 contatore=contatore/10;
 centinaia=contatore%10;
 contatore=contatore/10;
 
      lc.setDigit(0,2,(byte)centinaia,false);
      lc.setDigit(0,1,(byte)decine,false);
      lc.setDigit(0,0,(byte)unita,false);
    } 
    // Delay a little bit to avoid bouncing
    delay(50);
  }
  // save the current state as the last state, for next time through the loop
  lastButtonState = buttonState;

  // if the buttonreset is pressed reset the buttonpushcounter
  if  (digitalRead(buttonReset) == HIGH){
      (contatore = 0);
       lc.clearDisplay(0);
    }
  }

torn24:
Ciao! Di sbagliato c'è il modo in cui calcoli le migliaia!

// Tu fai cosi e non stai calcolando le migliaia...

unita=contatore%10;
decine=contatore/10;
centinaia=contatore/100;

/******************************************/

//Dovrebbe essere per passare all'ordine di grandezza superiore dividi sempre per 10 e poi prendi il resto

unita=contatore%10; //Resto della divisione per dieci sono le unità
contatore=contatore/10; // Divido per dieci adesso contatore contiene le DECINE esempio 23 decine
decine=contatore%10;// Prendo il resto della divisione per dieci e sono le decine

// Esempio se contatore è uguale a 23 DECINE prendo il resto e sono 3 decine

centinaia=contatore/10;// Adesso decine diviso 10 sono le centinaia ESEMPIO 23 decine/10=2,3
//visto che usiamo variabili intere int, in centinaia sarà inserito solo 2

Scusa ma a cosa serve calcolare le migliaia se fino a 999 bastano le centinaia?

Se guardavi il codice trovavi scritto centinaia! Quindi mi sono sbagliato ma il codice è corretto!

Nel codice ho messo commenti che spiegavano il ragionamento, ma visto che non le hai letti non hai capito.
PER L'ULTIMA CIFRA devi dividere solo per 10 e non prendere il resto

Ti faccio un esempio NUMERO=498

unita=NUMERO%10 unita vale 8 resto
NUMERO=NUMERO/10 numero vale 49 decine
decine=NUMERO%10 decine vale 9 resto di 10
Centinaia=NUMERO/10 49 DECINE/10 4 CENTINAIA

Questo perché usiamo variabili in 49/10 fa 4,9 ma noi prendiamo solo la parte intera 4

unita=contatore%10; // Resto di dieci sono le unità
 contatore=contatore/10; // Divido per dieci e ottengo le decine che potrebbero essere superiori a 46
 decine=contatore%10; // Prendo il resto e ottengo le decine
centinaia=contatore/10; // Sono già le centinaia non c'è bisogno di prendere il resto

Ho visto che hai aperto un altra discussione su display, mi sembra che ti hanno suggerito una libreria diversa da quella che usi con cui puoi stampare direttamente un numero a più cifre!
A seconda della libreria che usi fai le cose in modo diverso, più semplice o più complesso.

torn24:
Ho visto che hai aperto un altra discussione su display, mi sembra che ti hanno suggerito una libreria diversa da quella che usi con cui puoi stampare direttamente un numero a più cifre!
A seconda della libreria che usi fai le cose in modo diverso, più semplice o più complesso.

Si Torn, perchè per il mio progetto contapezzi volevo sostituire il Display 8 cifre MAX 7219 con quello a 4 cifre TM1637, visto che 4 cifre sono più che sufficienti per quello che devo contare, ma il TM 1637 sto imparando a usarlo perchè ho visto che i comandi da dargli sono diversi.

torn24:
Se guardavi il codice trovavi scritto centinaia! Quindi mi sono sbagliato ma il codice è corretto!

Nel codice ho messo commenti che spiegavano il ragionamento, ma visto che non le hai letti non hai capito.
PER L'ULTIMA CIFRA devi dividere solo per 10 e non prendere il resto

Scusa Torn o sono "de coccio" io o ... ho sostituito la porzione di codice esattamente uguale alla tua, ma non cambia nulla, appare solo il numero 001 e poi non va più avanti.

 //State change detection (edge detection)
//We always have to include the library
#include "LedControl.h"

/*
 Now we need a LedControl to work with.
 pin 12 is connected to the DataIn 
 pin 11 is connected to the CLK 
 pin 10 is connected to LOAD 
 We have only a single MAX72XX.
 */
LedControl lc=LedControl(12,11,10,1);

/*  The circuit:
 - buttonpin attached to pin 2 from +5V
 - buttonreset attached to pin 4 from +5V
 - 10 kilohm resistor attached to pin 2&4 from ground
*/
// this constant won't change:
const int  buttonPin = 2;// the pin that the pushbutton is attached to
const int  buttonReset = 4;// the pin that the buttonreset is attached to

// Variables will change:
int contatore = 0;   // counter for the number of button presses
int buttonState = 0;         // current state of the button
int lastButtonState = 0;     // previous state of the button
int unita = 0;
int decine = 0;
int centinaia = 0;


void setup(){
  /*
   The MAX72XX is in power-saving mode on startup,
   we have to do a wakeup call
   */
  lc.shutdown(0,false);
  /* Set the brightness to a medium values */
  lc.setIntensity(0,8);
  /* and clear the display */
  lc.clearDisplay(0);

  // initialize the button pin as a input:
  pinMode(buttonPin, INPUT);
  pinMode(buttonReset, INPUT);
}

void loop() {
  // read the pushbutton input pin:
  buttonState = digitalRead(buttonPin);

  // compare the buttonState to its previous state
  if (buttonState != lastButtonState) {
    // if the state has changed, increment the counter
    if (buttonState == HIGH) {
      // if the current state is HIGH then the button went from off to on:
      contatore++;
      
 unita=contatore%10;
 contatore=contatore/10;
 decine=contatore%10;
 centinaia=contatore/10;
 
      lc.setDigit(0,2,(byte)centinaia,false);
      lc.setDigit(0,1,(byte)decine,false);
      lc.setDigit(0,0,(byte)unita,false);
    } 
    // Delay a little bit to avoid bouncing
    delay(50);
  }
  // save the current state as the last state, for next time through the loop
  lastButtonState = buttonState;

  // if the buttonreset is pressed reset the buttonpushcounter
  if  (digitalRead(buttonReset) == HIGH){
      (contatore = 0);
       lc.clearDisplay(0);
    }
  }

Avevi detto che fino a 90 contava, quindi dovrebbe funzionare.
Se contava fino a 90 adesso dovrebbe contare fino a 999, non vedo motivi perché non lo faccia!
Controlla anche i collegamenti elettronica.
Prova a vedere se cosi il programma funziona! Ho semplificato la lettura del pulsante togliendo l'antirimbalzo, io i pulsanti li uso cosi con un piccolo delay() e non ho problemi.

 //State change detection (edge detection)
//We always have to include the library
#include "LedControl.h"

/*
 Now we need a LedControl to work with.
 pin 12 is connected to the DataIn 
 pin 11 is connected to the CLK 
 pin 10 is connected to LOAD 
 We have only a single MAX72XX.
 */
LedControl lc=LedControl(12,11,10,1);

/*  The circuit:
 - buttonpin attached to pin 2 from +5V
 - buttonreset attached to pin 4 from +5V
 - 10 kilohm resistor attached to pin 2&4 from ground
*/
// this constant won't change:
const int  buttonPin = 2;// the pin that the pushbutton is attached to
const int  buttonReset = 4;// the pin that the buttonreset is attached to

// Variables will change:
int contatore = 0;   // counter for the number of button presses
int buttonState = 0;         // current state of the button
int lastButtonState = 0;     // previous state of the button
int unita = 0;
int decine = 0;
int centinaia = 0;


void setup(){
  /*
   The MAX72XX is in power-saving mode on startup,
   we have to do a wakeup call
   */
  lc.shutdown(0,false);
  /* Set the brightness to a medium values */
  lc.setIntensity(0,8);
  /* and clear the display */
  lc.clearDisplay(0);

  // initialize the button pin as a input:
  pinMode(buttonPin, INPUT);
  pinMode(buttonReset, INPUT);
}

void loop() {
   
    if (digitalRead(buttonPin)==HIGH){
      
        contatore++;
      
        unita=contatore%10;
        contatore=contatore/10;
        decine=contatore%10;
        centinaia=contatore/10;
 
        lc.setDigit(0,2,(byte)centinaia,false);
        lc.setDigit(0,1,(byte)decine,false);
        lc.setDigit(0,0,(byte)unita,false);
    } 
    if(contatore>999) contatore=0; // Ritorna a zero quando deve contare 1000
    delay(200);
  
  

  
    if  (digitalRead(buttonReset) == HIGH){
        (contatore = 0);
         lc.clearDisplay(0);
    }
  }

Fa un gioco: aggiungi la seriale, anche se non sarà parte del programma definitivo. Scrivi su seriale il contatore e le sue varie parti per poter verificare se la procedura di calcolo è giusta, e se Quindi il problema si trova nella parte di rappresentazione.

Con queste righe di codice (stessi collegamenti) conta fino a 99 senza problemi e lo visualizza correttamente sul display.

unita=contatore%10;
decine=contatore/10;

      lc.setDigit(0,1,(byte)decine,false);
      lc.setDigit(0,0,(byte)unita,false);
[code]

[/code]

Il tuo codice modificato l' ho provato Torn ma non funziona, mi da lo stesso risultato, solo 001 poi si ferma.

Silente:
Fa un gioco: aggiungi la seriale, anche se non sarà parte del programma definitivo. Scrivi su seriale il contatore e le sue varie parti per poter verificare se la procedura di calcolo è giusta, e se Quindi il problema si trova nella parte di rappresentazione.

In realtà è stata la prima cosa che ho fatto Silente, infatti per la scrittura del codice del Contapezzi ho preso spunto dall' esempio dell' IDE StateChangeDetection, in cui viene usato il monitor seriale e viene visualizzato il conteggio che avanza ad ogni pressione del tasto ButtonPushCounter. Poi il problema è sorto quando a visualizzare il conteggio deve essere il display 7 segment e non più il monitor seriale.

Prova a stampare su seriale i valori di unita,decine e centinaia, ma credo che sia tutto esatto.
Ma secondo me non c'è problema nel programma, sono abbastanza sicuro che il calcolo sia corretto e la stampa su display è copiata dall'esempio del link che hai postato.
Quindi non è un errore di programma!
A volte si hanno componenti elettronici difettosi è una possibilità da tenere presente.
Prova comunque a stampare su seriale, la stampa su display è quella del link quindi non è sbagliata...

 //State change detection (edge detection)
//We always have to include the library
#include "LedControl.h"

/*
 Now we need a LedControl to work with.
 pin 12 is connected to the DataIn 
 pin 11 is connected to the CLK 
 pin 10 is connected to LOAD 
 We have only a single MAX72XX.
 */
LedControl lc=LedControl(12,11,10,1);

/*  The circuit:
 - buttonpin attached to pin 2 from +5V
 - buttonreset attached to pin 4 from +5V
 - 10 kilohm resistor attached to pin 2&4 from ground
*/
// this constant won't change:
const int  buttonPin = 2;// the pin that the pushbutton is attached to
const int  buttonReset = 4;// the pin that the buttonreset is attached to

// Variables will change:
int contatore = 0;   // counter for the number of button presses
int buttonState = 0;         // current state of the button
int lastButtonState = 0;     // previous state of the button
int unita = 0;
int decine = 0;
int centinaia = 0;


void setup(){
  /*
   The MAX72XX is in power-saving mode on startup,
   we have to do a wakeup call
   */
  lc.shutdown(0,false);
  /* Set the brightness to a medium values */
  lc.setIntensity(0,8);
  /* and clear the display */
  lc.clearDisplay(0);

  // initialize the button pin as a input:
  pinMode(buttonPin, INPUT);
  pinMode(buttonReset, INPUT);

  Serial.begin(9600);
}

void loop() {
   
    if (digitalRead(buttonPin)==HIGH){
      
        contatore++;
      
        unita=contatore%10;
        contatore=contatore/10;
        decine=contatore%10;
        centinaia=contatore/10;

        Serial.print(centinaia);
        Serial.print("-");
        Serial.print(decine);
        Serial.print("-");
        Serial.print(unita);
        Serial.println(" "); 
 
        lc.setDigit(0,2,(byte)centinaia,false);
        lc.setDigit(0,1,(byte)decine,false);
        lc.setDigit(0,0,(byte)unita,false);
    } 
    if(contatore>999) contatore=0; // Ritorna a zero quando deve contare 1000
    delay(200);
  
  

  
    if  (digitalRead(buttonReset) == HIGH){
        (contatore = 0);
         lc.clearDisplay(0);
    }
  }

Ecco fatto! Allego schermata della seriale. Restituisce tutti 0-0-1.

Toglimi uno sfizio, prova a riprodurre i collegamenti (bastano due pulsanti, due resistenze e qualche cavetto) anche se non metti il display 7 segment, e prova anche tu lo sketch che mi hai proposto con la seriale, così tagliamo la testa al toro. :smiley:

Bene. Quindi abbiamo capito dove é il problema, ovvero sul valore delle variabili. Ora é necessario capire perché é li.
A tale scopo potresi aggiungere scritte su seriale. Una potrebbe essere il valore del contatore ogni volta che lo aumenti, e una seconda una scritta che indichi quando stai azzerando.