Problema con Multiplexing su schermo 4digit 7segmenti

Buongiorno a tutti,

Sto utilizzando, come da titolo, un display 7segmenti a 4digit (catodo comune), senza l'utilizzo di alcuna libreria, in quanto vorrei togliermi la soddisfazione di programmare il tutto per intero.

Il mio problema è che fino a quando utilizzo il multiplexing (con un delay di 1ms) per scrivere ad esempio il numero 23, non ci sono problemi.
Il problema sorge quando (ad esempio con un ciclo) provo ad incrementare le unità, introducendo un delay di (ad esempio) 1000ms: le decine rimangono accese mentre le unità incrementano lampeggiando con un blink di 1000ms.
Vorrei evitare questo brutto inconveniente ma non saprei come fare.

Vi includo le funzioni che ho scritto per realizzare il tutto, ed il codice del loop, giusto per farvi capire meglio la situazione.

Grazie a tutti in anticipo, Davide.

void NUMEROeDIGIT (int Numero_Inserito, int Digit_Inserito) {
  if ((Numero_Inserito>-1&&Numero_Inserito<10)&&(Digit_Inserito>0&&Digit_Inserito<5)){
  switch (Numero_Inserito) {
    case 0: ZERO();
    break;
    case 1: UNO();
    break;
    case 2: DUE();
    break;
    case 3: TRE();
    break;
    case 4: QUATTRO();
    break;
    case 5: CINQUE();
    break;
    case 6: SEI();
    break;
    case 7: SETTE();
    break;
    case 8: OTTO();
    break;
    case 9: NOVE();
    break;
  } //dove UNO, DUE, ecc, sono funzioni che accendono i relativi led sui segmenti del numero
  
  switch (Digit_Inserito) {
    case 1: 
    digitalWrite (comune1, LOW);
    digitalWrite (comune2, HIGH);
    digitalWrite (comune3, HIGH);
    digitalWrite (comune4, HIGH);
    break;
    case 2: 
    digitalWrite (comune1, HIGH);
    digitalWrite (comune2, LOW);
    digitalWrite (comune3, HIGH);
    digitalWrite (comune4, HIGH);
    break;
    case 3: 
    digitalWrite (comune1, HIGH);
    digitalWrite (comune2, HIGH);
    digitalWrite (comune3, LOW);
    digitalWrite (comune4, HIGH);
    break;
    case 4: 
    digitalWrite (comune1, HIGH);
    digitalWrite (comune2, HIGH);
    digitalWrite (comune3, HIGH);
    digitalWrite (comune4, LOW);
    break;
  }
  }
  }



void NUMERO (int decine, int unita) {
  if (decine == 0) {
  NUMEROeDIGIT(unita,1);
  delay(1);
  NUMEROeDIGIT(decine,2);
  delay(1);
  }
  else 
  NUMEROeDIGIT(unita,1);
  delay(1);
  NUMEROeDIGIT(decine,2);
  delay(1);
}


void loop() {
for (int a=0;a<10;a++) {
NUMERO (2,a);
delay(1000);
}
}

P.S. : Spero di essere stato il più chiaro possibile.

>davideerio97: ti ricordo che in conformità al regolamento, punto 7, devi editare il tuo post qui sopra (quindi NON scrivendo un nuovo post, ma utilizzando il bottone More -> Modify che si trova in basso a destra del tuo post) e racchiudere il codice all'interno dei tag CODE (... sono quelli che in edit inserisce il bottone con icona fatta così: </>, tutto a sinistra).

In pratica, tutto il tuo codice dovrà trovarsi racchiuso tra due tag: [code] _il _tuo_ codice_ [/code] così da non venire interpretato e non dare adito alla formazione di caratteri indesiderati o cattiva formattazione del testo. Grazie.

Guglielmo

P.S.: Ti ricordo che, purtroppo, fino a quando non avrai sistemato il codice come richiesto, nessuno ti potrà rispondere, quindi ti consiglio di farlo al più presto. :wink:

In pratica, tutto il tuo codice dovrà trovarsi racchiuso tra due tag.

Grazie Guglielmo per la segnalazione.

Chiaro sei stato e il problema è noto. Qualcosa comandato in multiplex via software deve essere costantemente refreshato e a intervalli di tempo il più possibile regolari. Nel caso di 4 digit si deve cambiare il digit attivo ogni 5ms (o meno).

Per contare il tempo bisogna usare 'millis', o, per tempi così brevi, molto meglio 'micros'.

Si può usare un array di quattro elementi (o quattro variabili singole ma è più complesso) da usare come "memoria video" da modificare quando serve. E chiamare in continuazione una funzione multiplex che legga questa memoria scandendo in modo regolare i vari digit.

Un ciclo for che ogni secondo varia la memoria video deve essere riscritto anch'esso senza for, contando il tempo con millis, usando un solo if, grosso modo:
se trascorso 1 sec: { salva tempo attuale, calcola nuovo valore, varia memoria }

Grazie Claudio,
cosa intendi con "memoria video" da modificare quando serve?

Intendo i valori che devono apparire sui vari digit. La funzione multiplex ogni 5ms incrementa il contatore del digit attivo, legge la memoria e comanda il digit.

Scusami ma non mi è troppo chiara la soluzione da attuare.

Io ho un conteggio su più digit creato in multiplexing. A questo punto qualsiasi altra azione, compreso un incremento/decremento di questo conteggio vanno a creare problemi sul multiplexing.
Come lo risolvo?

Bisogna impostare una logica/metodo di ragionamento diverso, nessun 'delay', nessun 'for', solo degli 'if' (continuamente testati senza rallentamenti) che decidono quando è il momento di fare qualcosa:

LOOP
{
    // questo realizza il multipex
    se trascorsi 5000µs:
        porta avanti variabile_tempo_multiplex di 5ms
        spegni digit attivo
        incrementa contatore digit 'i' (con ritorno a 0 se > 3)
        leggi la memoria video 'i' e scrivi il nuovo digit
        accendi il nuovo digit
    
    // questo realizza l'incremento
    se trascorso 1s:
        porta avanti variabile_tempo_secondi di 1s
        incrementa valore da visualizzare
        scrivilo nella memoria video scomponendolo nei vari valori digit
}

Ciao
Il discorso è molto semplice: se vuoi multiplexare, non puoi mettere dei delay nel loop e il loop deve girare continuamente, senza interruzioni.
Tempo fa ho fatto un timer a due cifre per la vecchia magnetoterapia di Nuova Elettronica: l'atmega328p, oltre a contare il tempo, pilota gli anodi dei display e, tramite 2 transistor, alimenta alternativamente i catodi comuni. Il loop gira continuamente e a ogni giro di loop passa da un display all'altro.