Risolto Problema di visualizzazione con sevseg

Salve Ragazzi,

è trascorso un pò di tempo dall'ultima volta che ho chiesto consigli; prima un ringraziamento a gpb01, Standardoil, maubrazi, che con il loro suggerimenti mi hanno aiutato a comprendere meglio la logica di programmazione ed il funzinamento di arduino.
In questo tempo mi sono esercitato su alcune funzioni tipo il map, millis etc, letto vari post ed info sul web.
Mettendo in pratica ciò che ho imparato sono giunto al risultato che volevo ma non in modo perfetto.
Vi spiego il mio progettino di esercitazione.
Partendo dal primo proggetto quello di leggere la temperatura del motore della moto utilizzando un sensore TMP36 lo ho implementato facendo lampeggiare i diplay raggiunta una certa temperatura diciamo 95° e credetemi funziona bene.
Poi mi è balenata l'idea di visualizzare in modo alternato (ciclico) la temperatura del motore e la tensione della batteria e per fare ciò ho usato il comando SevSeg includendo la libreria medesima nello sketch ed utilizzando la tecnica del blinki Led senza delay e sono giunto a questo sketch che appunto mi visualizza alternativamente in due valori, almeno sul serial monitor tutto è corretto, ma sul display la visuallizzazione è pessima xkè lo scrolling dei digit è condizionato dal tempo di unsigned long interval.
Sto provando diversi soluzioni ma senza ottenere un buon risultato.
A questo punto vi chiedo se ce un modo per mentenere lo scrolling dei digit senza essere condizionato dall'unsigned long interval.

Un sempre grazie in anticipo per il vostro aiuto.

Qui di seguito lo sketch :

#include <SevSeg.h>

//la visualizzazione alternata delle due variabili funziona ma la
// visuallizzazione sul display è pessima. Lo scrolling dei digit è condizionato dal tempo del blink.
// e viene mostarto un digit per volta,

SevSeg sevseg; //Instantiate a seven segment object

const int TEMP = A0;  // coprrispnde a cavo1 a0
const int BattVolt = A1; // corrisponde a cavo2 a1
//Variabile dopo conversione in temp e Volt
int val_TEMP; // corrisponde a lettura1
int val_BattVolt; // corrisponde a lettura2



unsigned long previousMillis = 0;
unsigned long interval = 2000;

bool stato = false;
void setup() {
  byte numDigits = 4;
  byte digitPins[] = {9, 10, 11, 12};; //Digits: 1,2,3,4
  byte segmentPins[] = {2, 3, 4, 5, 6, 7, 8, 13}; //Segments: A,B,C,D,E,F,G,Dp
  bool resistorsOnSegments = true;             //Resistore per ogni segmento
  byte hardwareconfig = COMMON_CATHODE;        //uso display a Katodo comune
  bool updatewithdelays = false;               
  bool leadingzeros = false;                   //Usa 'true' se vuoi vedere lo zero sulle cifre non significative 

  bool disableDecPoint = false; // Use 'true' se il tuo punto decimale non esiste o non è collegato. Poi devi solo specificare i 7 segmentPins[
  sevseg.begin(hardwareconfig, numDigits, digitPins, segmentPins, resistorsOnSegments, updatewithdelays, leadingzeros);
  sevseg.setBrightness(100);
  Serial.begin(9600);
}

void loop() {
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= interval) {
   previousMillis = currentMillis;
    if (stato == false) {
      val_TEMP = analogRead(TEMP);
      // Serial.println(val_TEMP);
      float voltage = (val_TEMP * 0.0048828) * 100;
      //Serial.println(voltage);
      float TEMPC = (voltage - 50);
      Serial.print("Temp= ");
      Serial.println(TEMPC);
      sevseg.setNumber(TEMPC, 1);  
      sevseg.refreshDisplay();
      stato = true;
    }
    else {
      val_BattVolt = analogRead(BattVolt);
      // Serial.println(val_BattVolt);
      //float misura = map(val_BattVolt, 0, 1023, 0, 2000);   //  il valore della tensione
      // Serial.println(misura);
      float Volt = (val_BattVolt * (5.0 / 1023.0)) * 4; // cambiare il 4 per il fondo scala che si desidera 
      Serial.print("Batt Volt =  ");
      Serial.println(Volt);
      sevseg.setNumber(Volt, 1);
      sevseg.refreshDisplay();
      stato = false;
    }
  }
}

Saluti,
Lorenzo

Ciao a tutti, volevo farvi spere che ho trovato la soluzione ed ho risolto il problema.

Grazie comunque a tutti.

@Lollo65, se hai voglia, pubblica la soluzione. Magari un altro utente un giorno può avere lo stesso problema e cercando nel forum può trovare la tua soluzione.

Ciao nid69ita,
si certo la soluzione è stata semplice ho eleiminato il sevseg.refreshDisplay(); dalla lettura della temperatura e della batteria e spostato dopo la chiusura dell'if (currentMillis - previousMillis >= interval) { e posto prima della chiusura del loop.
Il suggerimento lo ho trovato qui su un post che aveva problemi con il refresh del sevseg ma non trovo più il link.

}
  void loop() {
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;
    if (stato == false) {
      val_TEMP = analogRead(TEMP);
      // Serial.println(val_TEMP);
      float voltage = (val_TEMP * 0.0048828) * 100;
      //Serial.println(voltage);
      float TEMPC = (voltage - 50);
      Serial.print("Temp= ");
      Serial.println(TEMPC);
      sevseg.setNumber(TEMPC, 1);
      // sevseg.refreshDisplay();
      stato = true;

    }
    else {
      val_BattVolt = analogRead(BattVolt);
      // Serial.println(val_BattVolt);
      //float misura = map(val_BattVolt, 0, 1023, 0, 2000);   //  il valore della tensione
      // Serial.println(misura);
      float Volt = (val_BattVolt * (5.0 / 1023.0)) * 4; // inserire il valore del fondo scala che si desidera
      Serial.print("Batt Volt =  ");
      Serial.println(Volt);
      sevseg.setNumber(Volt, 1);
      //sevseg.refreshDisplay();
      stato = false;
    }
  }
  sevseg.refreshDisplay();
}
}

Visto che cisono ti chiedo un consiglio. Questo sketch fa visualizzare le due misure con gli stessi tempi dettati dal valore di interval.
Io invece volevo fare visualizzare i due valori con tempi differenti diciamo 30sec la temperatura e 5 sec la batteria.
Mi sono letto questa discusione https://forum.arduino.cc/index.php?topic=711202.0 dove
fabpolli riporta di leggere due esempi di Leonardi Milani

  1. http://www.leonardomiliani.com/2012/come-gestire-loverflow-di-millis/
  2. http://www.leonardomiliani.com/2013/programmiamo-i-compiti-con-millis/

Il secondo link, con gli esempi che mostra, ed in particolare l'ultimo sketch con la creazione di due variabili mi sembra quello più indicato per realizzare la visualizzazione a tempi differenziati.
sono sulla strada giusta?

Grazie per la risposta.

Direi di si, secondo link

Ciao nid69ita,
ci ho provato a seguire i suggerimenti del link, in particolare il 2ndo link,
me senza successo rispetto a quello che io vorrei.

Con quei suggerimenti ho ottenuto si la visualizzazione alternata delle due variabili ma ognuna viene visualizzata sencondo il proprio intervallo di tempo ed ad un certo punto le due visualizzazioni si sovrappongono e una viene mostrata per un brevissimo tempo; oppure ciò che ho ottenuto è per i primi 10 sec visualizzo la temp, poi passa a visualizzate i volt BATT e qui rimane a visualizzare la Batt.
Io vorrei arrivare a questo modo di visualizzazione non bloccante:
accendo Arduino, parte il timer interno, per i primi 10 sec visualizzo la temperatura poi dal 10mo a 12simo sec visualizza i volt della batt. e poi di nuovo la temperatura e cosi via in maniera ciclica.
Ci sto perdendo tutti i pochi capelli che mi sono rimasti.
In che modo devo dire ad arduino di resettare millis e ripartire da 0?
Ho letto su un altro post che non è possibile resettare il timer interno di ardu ed allora come faccio ad dirgli che deve ripetere il loop anche se gli intervalli di tempo sono stati superati?

se provo ad usare questa impostazione:

if (currentMillis - previousMillis >interval &&  currentMillis - previousMillis <interval2) {
if (currentMillis - previousMillis >interval ) {
    previousMillis = currentMillis;
    if (stato == false) {
      val_TEMP = analogRead(TEMP);
      // Serial.println(val_TEMP);
      float voltage = (val_TEMP * 0.0048828) * 100;
      //Serial.println(voltage);
      float TEMPC = (voltage - 50);
      Serial.print("Temp= ");
      Serial.println(TEMPC);
      sevseg.setNumber(TEMPC, 1);
      // sevseg.refreshDisplay();
      stato = true;
   }else {
if (currentMillis - previousMillis >interval2 &&  currentMillis - previousMillis <interval3)
     val_BattVolt = analogRead(BattVolt);
      // Serial.println(val_BattVolt);
      float Volt = (val_BattVolt * (5.0 / 1023.0)) * 4; // sostituire il 4 con valore del fondo scala che si desidera, ovvio modificare il circuito partitore per misurare i volt.
      Serial.print("Batt Volt =  ");
     // Serial.println(misura);
      Serial.println(Volt);
     sevseg.setNumber(Volt, 1);
     stato = false;

Non mi visualizza ne temperatuta ne batteria

Poi mi sono messo a ragionare un momento e ho cambiato la logica, ho utilizzato un ciclo for per per la variabile temp e uno per la variabile volt batt ed in questo modo alterno la visualizzazione seconto gli intervalli che io desidero, però mesa che mi si crea un problema di flikering sul display.

void loop();{
for (i=0; i< 1500; i++){
    val_TEMP = analogRead(TEMP);
     float voltage = (val_TEMP * 0.0048828) * 100;
     float TEMPC = (voltage - 50);
     Serial.print("Temp= ");
     Serial.println(TEMPC);
     sevseg.setNumber(TEMPC, 1);
     sevseg.refreshDisplay();
      }
   for (i=1500; i<1800; i++){
     val_BattVolt = analogRead(BattVolt);
     float Volt = (val_BattVolt * (5.0 / 1023.0)) * 4; // sostituire il 4 con valore del fondo scala che si desidera, ovvio modificare il circuito partitore per misurare i volt.
     Serial.print("Batt Volt =  ");
     Serial.println(Volt); 
     sevseg.setNumber(Volt, 1);
     sevseg.refreshDisplay();
        }
        i=0;
      }

Poi ieri non so perchè sfiga vuole che la borad mi da l’errore “avrdude error, mismatch error at first byte 0x0000 0x00 != 0x0c
avrdude mismatch content” di cui ho aperto un post chiedendo consigli. >:(

Eppure stava funzionando regolrmente mentre era collegato al PC e quindi non posso verificare la visualizzazione delle due misure.
Mi tocca aspettare l’arrivo di un nuova board nel frattempo che cerco di sistemare questa non funzionante.

Quali Suggerimenti hai per quella bestia del millis()?

Ciao, Lollo
Puoi fare così:

unsigned long t_visual=0; // millis() - t_visual va da 0 a 12000 (12 secondi).
byte visual_T_V=1; // Se è 1, viene visualizzata la temperatura;
                   // se è 2, viene visualizzata la tensione.
void loop()
{
if(millis()-t_visual<10000)  // Siamo nei primi 10 secondi, probabilmente nelle
  {                          // prime frazioni di secondo del ciclo di visualizzazione.
  if(visual_T_V==1) // Se visual_T_V è 1, deve visualizzare la temperatura;
    {               // appena visualizzata diventerà 2 e non la visualizzerà più.
    visualizza_temperatura();
    visual_T_V=2;
    }
  }
else // Sono trascorsi 10 secondi, quindi deve visualizzare la tensione.
  if(visual_T_V==2) // Se visual_T_V è 2, deve visualizzare la tensione;
    {               // appena visualizzata diventerà 1 e non la visualizzerà più.
    visualizza_tensione();
    visual_T_V=1;
    }
if(millis()-t_visual>=12000) t_visual=millis(); // Trascorsi 12 secondi, azzera la
}                                               // differenza tra millis() e t_visual.

Ciao Dataman Karma meritato,
il tuo suggerimento funziona bene,
In effetti è molto simile allo sketch del primo post dove uso la logica a stati come nell’esempio del led blinkwithout delay,
infatti visual_T_V=1; è uguale alla impostazione bool stato = false;
if(visual_T_V==1) è uguale a if (stato == false) etc…

Quello che mi mancava e non riusci a capire come farlo era l’ultimo if che azzera il millis() del tuo suggerimento.
Ora sono giunto a questo:

unsigned long prevMillis=0;
bool stato= false;


void loop() {
    if (millis()-prevMillis<1000) {
     if (stato == false) {
      val_TEMP = analogRead(TEMP);
      // Serial.println(val_TEMP);
      float voltage = (val_TEMP * 0.0048828) * 100;
      //Serial.println(voltage);
      float TEMPC = (voltage - 50);
      Serial.print("Temp= ");
      Serial.println(TEMPC);
      sevseg.setNumber(TEMPC, 1);
      stato = true;
   }
   }
    else if (stato == true){
      val_BattVolt = analogRead(BattVolt);
      // Serial.println(val_BattVolt);
        float Volt = (val_BattVolt * (5.0 / 1023.0)) * 4; // sostituire il 4 con valore del fondo scala che si desidera, ovvio modificare il circuito partitore per misurare i volt.
      Serial.print("Batt Volt =  ");
      Serial.println(Volt);
     sevseg.setNumber(Volt, 1);
     stato = false;
    } // inseriti suggerimenti di DATAMAN 
   if (millis()-prevMillis>=2500) // Trascorsi xx secondi, azzera la
   prevMillis=millis();           // differenza tra millis() e t_visual.
   sevseg.refreshDisplay();
}

Ma ora viene il bello voglio aggiungere una nuova sfida a me stesso far blinkare il display quando la temp è sopra un certo valore.
Provero a sfuttare l’esempio di uno sketch che ho fatto un pò di tempo fà.

Grazie ancora per il tuo suggerimento.
Ciao Lorenzo

Mi fa piacere esserti stato utile a risolvere il problema.
Non avevo messo quei nomi a caso:

  • t_visual: se usi il nome prevMillis, come farai a fare un'altra temporizzazione? Se lo chiamerai prevMillis2, non sarà più facile capire, in futuro, a che cosa si riferisce l'azzeramento del tempo con prevMillis2=millis().
  • se, in futuro, vorrai modificare il programma, non ti ricorderai che cosa vuol dire "stato". Se usi le lettere T e V, invece, ti ricorderai facilmente che si riferisce alla lettura alternata di temperatura e tensione.

P.S.: sono DATMAN, da Digital Audio Tape (come leggi a sinistra) :slight_smile:

Prendi anche l'abitudine di non usaare inutilmente le variabili float, che occupano il quadruplo di una byte in RAM e rallentano i calcoli successivi:

float Volt = (val_BattVolt * (5.0 / 1023.0)) * 4;

puoi sostituirlo con:
byte Volt = (val_BattVolt/1023.0*50*4);

oppure:
int Volt = (val_BattVolt*50/1023.0*4);

visualizzando, poi, Volt/10.

Non so se, in questo caso, usando int (necessario per appoggiare i calcoli all'interno della seconda formula) avresti un guadagno in risoluzione... Mi sa di no, perché i calcoli all'interno della formula sono svolti in virgola mobile, grazie al 1023.0.

Ciao Dataman Grazie ancora per i consigli,
In effetti ho scritto lo sketch con i nomi da te indicati e me lo sono salvato,
poi lo ho reiscritto usando i nomi che avevo con la mia impostazione solo per capire se funzionava o meno.
Allinizio la mia impostazione non funzionava correttamente perchè cerano degli errori con le parentesi graffe e confrontandolo con il tuo esempio mi ha permesso di capire dove erano gli errori che ho poi corretto.

Ho notato che hai usato byte anziche un bool e mi sto documentando anche sull’uso di byte.
In un primo momento non capivo come avveniva l’associazione livello logico 1 o 0 poi mi sono reso conto che è la stessa cosa di false o true.

Testerò le modifìche sulla variabile float in byte e vedrò cosa succede.
Nella formula dei volt come della temp sono tornato a averli in virgola mobile usando il float anziche il map perche volevo avere il decimale. Ho conservato anche lo skect con la formula map vedrò cosa scegliere in seguito.

Una cosa che mi sta saltando agli occhi e che fatta la prima lettura della temp e la visualizza sul display poi per xx secondi non vengono fatte più letture di temp; poi per yy sec si passa ai Volt batt e poi si ritorna alla temp.
Ora ponendo che quesi xx secondi diventano zz minuti il ciclo non si aggiorna finche non siano passati zzminuti+yysecondi.

Quindi in quei zz minuti la temperatuta potrebbe aumentare oltre il limite di utilizzo del motore e io non me ne rondo conto immediatamente ma solo dopo zz minuti.
Allora mi domandavo se è il caso di inserire un ciclo for nella lettura della temp in modo da averla costantemente aggiornata al trascorrere del tempo di millis come
in questo esempio che avevo utilizzato per fare delle letture di un sensore di pressione.

   int Pr1 = analogRead(A0) - analogRead(A1);
   
   fil[i]= Pr1;
  if (i < (fsize-1)) i++;   // nelle registrazionei degli array il primo array[0] con vaore 0 viene eliminato, 
                           //  raggunti i cento il ciclo ricomincia e viene eliminato l'array [1] etc. 
  else i = 0;
  avg=0;
  for (int j=0; j< fsize; j++) {
    avg+=(float)fil[j];
  }
  avg = avg / (float)(fsize);

Avro un bel pò da divertirmi con Arduino nei prossimi giorni, tra avrdude error e varie modifiche e prove.

Domani sbarco e torno a casa finalmente di stare qui negli USA mi sono abbastanza rotto…

Gianluca grazie ancora per i consigli, dato che sei di Roma e pure io mi farebbe piacere incontrarti fare quattro chiacchiere ed offrirti un caffe/birretta/bicchier di vino etc. :slight_smile:

Rieccomi
Allora Gianluca ho provato i tuoi suggerimenti sostituito il float con byte e tutto funziona bene i byte da 5878 scende a 5708 poi se elimino ancora qualche serial print scendera ancora.

Se invece vado ad usare int Volt = (val_BattVolt50/1023.04); mi da valori negativi perchè cosi impostata la formula (volt_Batt50) da valori superiori a 32xxx, esempio a 13V da 66650=33300, e ad Arduino gli rode il chicchero,
se invece uso la stessa formula del byte ma con int Volt = (val_BattVolt/1023.0504); i calcoli sono giusti ma i byte risparmiati sono pochi rispetto all'uso del float circa 50-60 byte in meno.

Ciao
Lorenzo

(volt_Batt*50) da valori superiori a 32xxx

Hai ragione. Ci ero stato attento, ma avevo considerato una capacità di 65535, invece la variabile è int, con segno. Poiché i valori negativi non servono, basta usare variabili unsigned int anziché int.

Dato che sei di Roma e pure io mi farebbe piacere incontrarti fare quattro chiacchiere ed offrirti un caffe/birretta/bicchier di vino etc. :slight_smile:

Birra volentieri, virus permettendo... :slight_smile: