aiuto tachimetro+ display 7 segmenti...conflitto

Ciao a tutti sono nuovo e se aveste avuto modo di dare un’occhiata nella sezione dedicata alle presentazioni, potrete facilmente realizzare che sono proprio alle prime armi.
Vorrei realizzare un tachimetro sfruttando un sensore hall e un display 7 segmenti a 4 digit, e devo dire che frugando sul forum ho trovato dei grandi aiuti.
Il sensore sono riuscito a farlo funzionare bene grazie a questo codice

int sensorvalue;
int state1 = HIGH;
int state2;
float rpm;
float kmh;
float circonferenza;
long prevMillis = 0;
long interval = 200;
long currentTime;
long prevTime = 1;
long diffTime;
int sensorthreshold = 440;  



void setup()
{
  Serial.begin(9600);
}
void loop()
{
  sensorvalue = analogRead(0); 
  if(sensorvalue < sensorthreshold)
    state1 = HIGH;
   else
    state1 = LOW;
   if(state2!=state1){      
     if (state2>state1){
       currentTime = micros();   
       diffTime = currentTime - prevTime;  
         
       rpm = 60000000/diffTime;  
      kmh=rpm*circonferenza*60; 
       unsigned long currentMillis = millis();
       
       
       if(currentMillis - prevMillis > interval){ 
       prevMillis = currentMillis;       
       Serial.print(rpm); Serial.println(" rpm");
       }
       
       prevTime = currentTime;
     }
     state2 = state1;
   }

}

e per ora facendomi stampare solo i giri risulta essere abbastanza preciso(controllando dal monitor seriale).
Il problema sorge nel cercare di farmi stampare i giri sul display 7 segmenti: in particolare sto usando la libreria sevseg, il mio obiettivo sarebbe quello di far stampare i giri a schermo e lasciarli impressi (quindi no refresh) finchè il programma non aggiorna il valore di rpm ossia finchè non rientra nel terzo if.
Ho provato a scrivere questo codice (che in teoria dovrebbe consentirmi la lettura a display) ma i numeri sul display rimangono accesi per una frazione di secondo rendendo illeggibile la lettura (vedo solo di sfuggita dei segmenti che si accendono…ciò nonostante il numero dei giri letto nel monitor seriale è perfetto(quindi lo sarebbe anche sul display se solo si riuscisse a leggere) :cold_sweat:

#include <SevSeg.h>
int K=359;
SevSeg sevseg;


//comandi contagiri da qui
int sensorvalue;
int state1 = HIGH;
int state2;
float rpm;
float kmh;
float circonferenza;
long prevMillis = 0;
long interval = 200;
long currentTime;
long prevTime = 1;
long diffTime;
int sensorthreshold = 440;  
// this value indicates the limit reading between dark and light,
// it has to be tested as it may change acording to the 
// distance the leds are placed.
// to see what number is good, check the sensorvalue variable value
// as printed out in the serial monitor


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

  
  byte numDigits = 4;   
  byte digitPins[] = {10, 11, 12, 13}; //Digits: 1,2,3,4 <--put one resistor (ex: 220 Ohms, or 330 Ohms, etc, on each digit pin)
  byte segmentPins[] = {2, 3, 4, 5, 6, 7, 8, 9}; //Segments: A,B,C,D,E,F,G,Period
  sevseg.begin(COMMON_CATHODE, numDigits, digitPins, segmentPins);
  sevseg.setBrightness(10); 
}
void loop()
{
  sensorvalue = analogRead(0); 
  if(sensorvalue < sensorthreshold)
    state1 = HIGH;
   else
    state1 = LOW;
   if(state2!=state1){      
   
   if (state2>state1){

 
       
       currentTime = micros();   
       diffTime = currentTime - prevTime;  
       rpm = 60000000/diffTime;  
      kmh=rpm*circonferenza*60; 
       unsigned long currentMillis = millis();
       
       
       if(currentMillis - prevMillis > interval){ 
       prevMillis = currentMillis;       
       Serial.print(rpm); Serial.println(" rpm");
        
         



       static byte decPlace = 0;
      
  sevseg.setNumber((int)rpm,decPlace);
  
  sevseg.refreshDisplay();
   
 
       
       
       
       }
   
       prevTime = currentTime;
     }
        
     state2 = state1;
   }
    
    
  
   
}

questo era il codice descritto prima.
Provando invece a spostare il refreshDisplay() in fondo fuori dagli if prima dell’ultima graffa ho ottenuto quello che desidero: all’accensione visualizzo uno zero fisso, poi se faccio girare il motorino mi stampa i giri e se lo fermo rimane visualizzato l’ultimo valore di rpm rilevato.
Il problema è che in questo modo i giri risultano sballati, quando ad esempio mi dovrebbe segnare 5000 giri ne segna qualcuno a 8000 qualcuno a 3000 e ogni tanto qualcuno a 5000, problema confermato anche dal monitor seriale!
Purtoppo sto imparando ora a programmare qualcosa e fino a qualche giorno fa stentavo a capire come far accendere un singolo led; abbiate pazienza e se c’è qualche anima pia che ha avuto il coraggio di leggersi tutta sto papiro abbia il coraggio di provare ad aiutarmi :grinning: :stuck_out_tongue_closed_eyes:
grazie a tutti in anticipo

Devi usare variabili unsigned long e non long per la misura del tempo in microsecondi.

cyberhs:
Devi usare variabili unsigned long e non long per la misura del tempo in microsecondi.

Grazie mille per la disponibilità e per il consiglio purtoppo però non è cambiato nulla!

Mi sono accorto solo ora che usi analogRead(A0) per leggere lo stato del pulsante.

Questa funzione restituisce un valore tra 0 e 1023 e non è adatta per questo scopo.

Usa invece digitalRead(A0)

cyberhs:
Mi sono accorto solo ora che usi analogRead(A0) per leggere lo stato del pulsante.

Questa funzione restituisce un valore tra 0 e 1023 e non è adatta per questo scopo.

Usa invece digitalRead(A0)

Sto usando un pin analogico poiché il sensore di hall quando passa una calamita non mi da una quadra ma mi restituisce un valore preciso come giustamente mi hai fatto notare... Così facendo ho il vantaggio di poter regolare la sensibilità...in questo caso la variabile "int threshold' definita all'inizio del programma stabilisce che se il sensore rileva un campo con un valore inferiore a 450 allora deve considerarlo come un passaggio del magnete, così evito falsi conteggi in caso di campi magnetici più deboli/o di disturbo... Impostandolo come digitale invece considera 0 quando il valore è sui 550 ma appena scende a 540 ad esempio o sale a 560 lo rileva come 1 e così facendo ottengo una quadra totalmente sbagliata perché anche senza magneti vicini il valore rilevato tende a oscillare a causa di Micro campi presenti normalmente nell'aria.

Il problema nel prendere i giri detto ciò non si presenta, con analog0 i giri li prendo perfetti ma il problema è stamparli sullo schermo a 7 segmenti.. Non so dove e come impostare il refresh dello schermo
Grazie di tutto per la disponibilità!

Ho dato una rapida occhiata alla libreria SevSeg, ma ne esiste più di una, io mi riferisco a questa: GitHub - DeanIsMe/SevSeg: Seven segment display controller library for Arduino

Se tu fai riferimento ad un'altra lib posta il link.

Segue un commento estratto dalla libreria:

// refreshDisplay
/******************************************************************************/
// Flashes the output on the seven segment display.
// This is achieved by cycling through all segments and digits, turning the
// required segments on as specified by the array 'digitCodes'.
// There are 2 versions of this function, with the choice depending on the
// location of the current-limiting resistors.

Le due versione si attivano in base alla presenza della define RESISTORS_ON_SEGMENTS o meno.
Questo permette di adattarsi al circuito in base a dove/come sono collegati i segmenti e resistori.

Sinceramente non conosco la lib, la sto scoprendo adesso. Dal quel poco che ho letto rapidamente, un segmento rimane
acceso per un tempo stabilito dalla variabile membro "ledOnTime", come si vede nel costruttore:

SevSeg::SevSeg()
{
  // Initial value
  ledOnTime = 2000; // Corresponds to a brightness of 100
  numDigits = 0;
}

Riducendola a 1000 (sono us) dopo 28 * 1000 us tutti i digit sono aggiornati.

Per saperne di più dovresti mostrare/descrivere come sono collegati i segmenti o comunque un link da cui trarre
queste informazioni.

Ciao.

MauroTec:
Ho dato una rapida occhiata alla libreria SevSeg, ma ne esiste più di una, io mi riferisco a questa: GitHub - DeanIsMe/SevSeg: Seven segment display controller library for Arduino

Se tu fai riferimento ad un'altra lib posta il link.

Segue un commento estratto dalla libreria:
Le due versione si attivano in base alla presenza della define RESISTORS_ON_SEGMENTS o meno.
Questo permette di adattarsi al circuito in base a dove/come sono collegati i segmenti e resistori.

Sinceramente non conosco la lib, la sto scoprendo adesso. Dal quel poco che ho letto rapidamente, un segmento rimane
acceso per un tempo stabilito dalla variabile membro "ledOnTime", come si vede nel costruttore:

SevSeg::SevSeg()

{
  // Initial value
  ledOnTime = 2000; // Corresponds to a brightness of 100
  numDigits = 0;
}




Riducendola a 1000 (sono us) dopo 28 * 1000 us tutti i digit sono aggiornati.

Per saperne di più dovresti mostrare/descrivere come sono collegati i segmenti o comunque un link da cui trarre 
queste informazioni.

Ciao.

Innanzi tutto grazie davvero!!
Adesso sono fuori casa questa sera sul tardi tornerò e proverò a vedere un po' che libreria ho visto che non mi ricordo da dove l'avessi scaricata.
Per quanto riguarda il ledonTime potrebbe essere la soluzione giusta.. A mio avviso il refresh se posizionato fuori da tutti gli if funge da tappo poiché troppo lento ad aggiornare, cambiando quel valore dovrei ottenere un refresh più rapido dico bene?
Comunque sia se potesse tornare utile ho uno schermo 7 segmenti a catodo comune, prima di ogni anodo (7 poiché non uso il led per il punto) ho due resistenze in serie da 100 ohm.. la libreria che uso permette di impostare quale tipologia di display si possiede.. Ho impostato COMMONCATHODE e ho assegnato alla variabile digitpin i pin di arduino da d10 a d13 (collegati ai 4 catodi), mentre alla variabile segmentpin i pin di arduino collegati agli anodi con le resistenze ovvero dal d2 al d8 (d9 no poiché corrisponderebbe al segmento per il punto che non mi serve)

kygon96:
Innanzi tutto grazie davvero!!
Adesso sono fuori casa questa sera sul tardi tornerò e proverò a vedere un po’ che libreria ho visto che non mi ricordo da dove l’avessi scaricata.
Per quanto riguarda il ledonTime potrebbe essere la soluzione giusta… A mio avviso il refresh se posizionato fuori da tutti gli if funge da tappo poiché troppo lento ad aggiornare, cambiando quel valore dovrei ottenere un refresh più rapido dico bene?
Comunque sia se potesse tornare utile ho uno schermo 7 segmenti a catodo comune, prima di ogni anodo (7 poiché non uso il led per il punto) ho due resistenze in serie da 100 ohm… la libreria che uso permette di impostare quale tipologia di display si possiede… Ho impostato COMMONCATHODE e ho assegnato alla variabile digitpin i pin di arduino da d10 a d13 (collegati ai 4 catodi), mentre alla variabile segmentpin i pin di arduino collegati agli anodi con le resistenze ovvero dal d2 al d8 (d9 no poiché corrisponderebbe al segmento per il punto che non mi serve)

Allora la libreria che sto usando è esattamente quella che mi hai indicato prima, ho aperto il file sevseg.cpp nella cartella documenti->arduino->libraries con code blocks modificando il valore di ledOnTime… devo compilare in qualche modo o basta modificare il numero ,salvare e uscire?
Ho provato a modificarlo a 1000, 200 e persino 0 ma non cambia nulla :confused: :sob:…scusate la mia inesperienza.
con questo codice ( ovvero con il refresh fuori dai vari costrutti if) ottengo questi valori sballati (nella figura sotto),

#include <SevSeg.h>





int sensorvalue;
int state1 = HIGH;
int state2;
float rpm;
float kmh;
float circonferenza;
unsigendlong prevMillis = 0;
long interval = 200;
unsignedlong currentTime;
unsignedlong prevTime = 1;
unsignedlong diffTime;
int sensorthreshold = 440;  

int K=359;
SevSeg sevseg;


void setup()
{
  Serial.begin(9600);
  byte numDigits = 4;   
  byte digitPins[] = {10, 11, 12, 13}; //Digits: 1,2,3,4 
  byte segmentPins[] = {2, 3, 4, 5, 6, 7, 8, 9}; //Segments: A,B,C,D,E,F,G,Period
  sevseg.begin(COMMON_CATHODE, numDigits, digitPins, segmentPins);
  sevseg.setBrightness(10);
}




void loop()
{
  sensorvalue = analogRead(0); // read from pin 0
  if(sensorvalue < sensorthreshold)
    state1 = HIGH;
   else
    state1 = LOW;
   if(state2!=state1){      
     if (state2>state1){
       currentTime = micros();   // Get the arduino time in microseconds
       diffTime = currentTime - prevTime;  // calculate the time diff from the last meet-up
          
       rpm = 60000000/diffTime;  // calculate how many rev per minute
      kmh=rpm*circonferenza*60; 
       unsigned long currentMillis = millis();
       
       // print to serial at every interval - defined at the variables declaration
       if(currentMillis - prevMillis > interval){ // see if now already an interval long
       prevMillis = currentMillis;       
       Serial.print(rpm); Serial.println(" rpm");
        
        
        static byte decPlace = 0;
   sevseg.setNumber((int)rpm,decPlace);
  decPlace++;
  decPlace %= 4;
       
        
        
  
  //rollover back to 0 once variable gets to 4; To anyone wondering: the % is called the "modulo" operator; see here for explanation & example: https://www.arduino.cc/en/Reference/Modulo

  
       }
       
       prevTime = currentTime;
     }
     state2 = state1;
   }
   
  sevseg.refreshDisplay();
        
}

<–valori sballati

se uso questo codice invece i valori sono corretti , ma non si riescono a vedere sul display perche i led si accendono solo per una frazione di secondo…codice->

#include <SevSeg.h>





int sensorvalue;
int state1 = HIGH;
int state2;
float rpm;
float kmh;
float circonferenza;
unsignedlong prevMillis = 0;
long interval = 200;
unsignedlong currentTime;
unsignedlong prevTime = 1;
unsignedlong diffTime;
int sensorthreshold = 440;  

int K=359;
SevSeg sevseg;


void setup()
{
  Serial.begin(9600);
  byte numDigits = 4;   
  byte digitPins[] = {10, 11, 12, 13}; //Digits: 1,2,3,4 
  byte segmentPins[] = {2, 3, 4, 5, 6, 7, 8, 9}; //Segments: A,B,C,D,E,F,G,Period
  sevseg.begin(COMMON_CATHODE, numDigits, digitPins, segmentPins);
  sevseg.setBrightness(10);
}




void loop()
{
  sensorvalue = analogRead(0); // read from pin 0
  if(sensorvalue < sensorthreshold)
    state1 = HIGH;
   else
    state1 = LOW;
   if(state2!=state1){      
     if (state2>state1){
       currentTime = micros();   // Get the arduino time in microseconds
       diffTime = currentTime - prevTime;  // calculate the time diff from the last meet-up
          
       rpm = 60000000/diffTime;  // calculate how many rev per minute
      kmh=rpm*circonferenza*60; 
       unsigned long currentMillis = millis();
       
       // print to serial at every interval - defined at the variables declaration
       if(currentMillis - prevMillis > interval){ // see if now already an interval long
       prevMillis = currentMillis;       
       Serial.print(rpm); Serial.println(" rpm");
        
        
        static byte decPlace = 0;
   sevseg.setNumber((int)rpm,decPlace);
  decPlace++;
  decPlace %= 4;
sevseg.refreshDisplay();
       
        
        
  
  //rollover back to 0 once variable gets to 4; To anyone wondering: the % is called the "modulo" operator; see here for explanation & example: https://www.arduino.cc/en/Reference/Modulo

  
       }
       
       prevTime = currentTime;
     }
     state2 = state1;
   }
   
  
        
}

<—ecco infatti i valori giusti
spero di riuscire a venirne a capo …grazie a tutti

EDIT//EDIT:–>
provando a compilare il file sevseg.cpp dopo con codeblocks, dopo aver modificato il valore ledOnTime, ottengo i seguenti errori

che ho risolto rendendo una nota “//include wrprogram.h” ma poi mi si presenta quest’altro errore->

image share
che non so come risolvere

Allora la libreria che sto usando è esattamente quella che mi hai indicato prima, ho aperto il file sevseg.cpp nella cartella documenti->arduino->libraries con code blocks modificando il valore di ledOnTime… devo compilare in qualche modo o basta modificare il numero ,salvare e uscire?

In merito alle “librerie”, Arduino le compila in automatico la prima volta (credo), dovrebbe anche ricompilarle quando una lib ha subito modifiche (ma questo non so se lo fa). Le librerie compilate, lo sketch e altri file si “dovrebbero” trovare su un percorso temporaneo legato allo sketch. Per conoscere il percorso temporaneo puoi abilitare il modo “verbose” dall’IDE.
Con il modo “verbose” l’ide mostra tutti i comandi eseguiti, che dovrebbe comparire nel riquadro sotto la finestra dell’editor.

Se l’ide compila solo una volta la libreria, le modifiche al codice di queste non si riflette sul compilato e allora puoi rimuovere la cartella temporanea, chiudere e aprire l’ide e ricompilare il tuo sketch, in questo modo l’ide è costretto a ricreare il percorso temporaneo e tutti gli altri file.

Ho usato il condizionale in molti suggerimenti perché non seguo lo sviluppo dell’ide e non lo uso. Quindi le mi informazioni potrebbero essere valide con versioni vecchie dell’ide.

Non puoi compilare una libreria arduino con codeblock e non c’è necessità.

Devo solo apportare le modifiche evitando di commettere errori di sintassi, come ad esempio rimuovere il ; o { ecc.

Se apri il file .cpp trovi:

#if !(RESISTORS_ON_SEGMENTS)
//For resistors on *digits* we will cycle through all 8 segments (7 + period), turning on the *digits* as appropriate
//for a given segment, before moving on to the next segment

La #if !(RESISTORS_ON_SEGMENTS) e poi più giù #else permette di compilare due versioni di SevSeg::refreshDisplay(), di modo che si possa adattare alla tipologia del circuito.

Da quello che ho capito tutti i segmenti hanno le resistenze, quindi nel tuo sketch dovresti definire RESISTORS_ON_SEGMENTS, prima di includere la lib.
#define RESISTORS_ON_SEGMENTS 1

No errore, apri il .h e modifica la define, al posto di 0 metti 1

// If you use current-limiting resistors on your segment pins instead of the
// digit pins, then change the '0' in the line below to a '1'
#define RESISTORS_ON_SEGMENTS 0

Ciao.

grazie per le dritte, anche facendo come mi hai suggerito non cambiava molto... poi quasi a caso mi sono messo a modificare nel file sevseg.cpp anche la variabile brightness.. ho scoperto che abbassandola piu o meno proporzionalmente al valore di ledontime riuscivo a guadagnare in sensibilità. Ora non fa piu da tappo e riesco a visualizare correttamente a display il valore dei giri.
In compenso mi rimane ancora da risolvere un piccolo problema di cui non avevo ancora accennato. Il mio display ha su ogni digit un segmento che sembrerebbe bruciato, questi dovrebbero essere tutti 8

free image hosting
e questi tutti 0.

hosting immagini
Il punto è che collegando il relativo pin del display alla 5v con la resistenza da 200 ohm e a gnd, il segmento si accende perfettamente. Ho pensato potesse essere un pin di arduino difettoso ma anche invertendolo con un altro il risultato non cambia.
(vorrei specificare che se collegato ai pin il segmento non è totalmente spento, emette una leggera e flebile luce appena percettibile).
Non riesco a capire se sia un problema hardware o software :frowning:

Dovresti farci vedere lo schema di collegamento con Arduino.

Ho fatto una tabella perché con una foto non si capirebbe molto
... I collegamenti li ho controllati mentre la scrivevo non capisco come mai non funzioni

Il problema con questa libreria è che rallenta il loop bloccandolo 2000us (2ms) per ogni segmento, 2 x (8x4) = 64ms.

Per alcune applicazioni ciò non comporta problema, ma nel tuo caso evidentemente è di impiccio.
Lo schema elettrico ci è utile per capire se hai usato transistor o no, io ad esempio ho usato un transistor per catodo, quindi 4 transistor per un display a 4 digit. Il multiplex lo eseguo accendendo un digit per n tempo, per poi spegnerlo e accendere il prossimo digit, fino a 4. Io parto dal digiti a destra e termino con quello a sinistra e il ciclo si ripete all'infinito.

[ DIGIT0 ] [ DIGIT1 ] [ DIGIT2 ] [ DIGIT3 ]
ON OFF OFF OFF
OFF ON OFF OFF
OFF OFF ON OFF
OFF OFF OFF ON
ON ecc.

Ma per questo multiplex serve usare i transistor.

Comunque per il led che non si illumina, prova la libreria senza modifiche, con uno scketch che contiene solo lo stretto necessario per mostrare un numero, ad esempio lo 0. Quasi sicuramente il segmento si illuminerà.

Ciao.