Applicazione con i moduli 8 display a LED con HC595: Visualizzatore in/out

Ciao a tutti

Armeggiando un po' sono riuscito a fare questo visualizzatore, utile in particolari applicazioni.
Va tutto alla velocità della luce :smile:, con uno switch/case che instrada l'esecuzione verso l'impostazione corrente. In questo modo posso fare il multiplexing, indispensabile con il 595, e l'intermittenza della cifra che si sta impostando.
Sia la rotazione dell'encoder che la pressione del pulsante sono rilevate mediante un Pin Change Interrupt, che incrementa lo stato a ogni pressione del pulsante.

La tabella dei caratteri è limitata ai numeri da 0 a 9 e alle lettere che mi servivano, ma è facile ampliarla con tutti i caratteri che servono. E' ancora più semplice per la negazione bit a bit che ho fatto, che non rende più necessario fare i calcoli con logica inversa.

Sarà utile per chi vuole capire come vanno usati i moduli con 8 display a 7 segmenti pilotati da HC595 (e comunque...: Lunga vita e prosperità al MAX7219! :vulcan_salute:).

#include <EEPROM.h>

volatile uint8_t stato=0; // 0:Riposo; 1:In/Out; 2...5:Le 4 cifre.
volatile bool puls_prec=true; // true = premuto.
volatile int16_t contatore=0; // Fino a oltre +/-32000. Ho previsto anche i valori negativi.
volatile uint8_t s=0; // Valore decimale dei bit.
volatile uint8_t sp=0; // Stato precedente di s.
volatile uint8_t x=0;
volatile int8_t E=0; // Encoder 1:Orario; -1:Antiorario.

uint8_t InOut=1; // 1:In; 0=Out.
int16_t contatorep=0; // Valore precedente.
bool acceso=false; // Intermittenza - true: adesso è acceso; false:adesso è spento.
uint32_t t_intermittenza=0;
uint8_t c[5]; // Sono le 4 cifre, per c da 1 a 5.

#define PULS_PREMUTO !((PINB^0xFF)&0b00000100) // Inverte il PINB con un XOR, ne prende solo il terzo bit e fa un casting invertente a bool con '!'.

/*
EEPROM:
0 InOut
1 c[1]
2 c[2]
3 c[3]
4 c[4]
*/


void Bip()
  {
  digitalWrite(7, HIGH);
  delay(50);
  digitalWrite(7,LOW);
  }
  
void imposta_InOut()
  {
  if(E) // In.
    {
    InOut=1-InOut; // Alterna In/Out.
    }
  E=0;
  if(InOut) // In
    {
    if(acceso)
      {
      disp_l(2, 'I');
      disp_l(3, 'n');
      }
    else // Spento. Serve per mantenere costante il tempo impiegato
      {  // e non alterare la luminosità delle altre cifre.
      disp_l(2, ' ');
      disp_l(3, ' ');
      }
    }
  else // Out
    {
    if(acceso)
      {
      disp_l(1, 'O');
      disp_l(2, 'u');
      disp_l(3, 't');
      }
    else // Spento. Serve per mantenere costante il tempo impiegato
      {  // e non alterare la luminosità delle altre cifre.
      disp_l(1, ' ');
      disp_l(2, ' ');
      disp_l(3, ' ');
      }
    }
  }
void imposta_cifre()
  {
  uint8_t n = stato-1; // Stato==2: 1a cifra.
  if(E) // Se l'encoder è stato ruotato:
    {
    if(E==-1)
      {
      if(c[n]>0) c[n]-=1;
      else if(c[n]==0) c[n]=9;
      }
    else // E==+1:
      {
      if (c[n]<9) c[n]+=1;
      else if(c[n]==9) c[n]=0;
      }
    E=0;
    }
  if(acceso) 
    {
    disp_n(n+4, c[n]);
    disp_l(n+5, ' ');
    }
  else // Spento. Serve per non alterare la luminosità delle altre cifre.
    {
    disp_l(n+5, ' ');
    }
  }


ISR (PCINT0_vect)
{
if(!PULS_PREMUTO) // Pulsante non premuto:
  {
  puls_prec=false; // Non premuto.
  }
if (PULS_PREMUTO && puls_prec==false) // Pulsante premuto:
  {
  puls_prec=true;
  stato+=1;
  if(stato>10) stato=0;
  Bip();
  }
else // E' stato ruotato l'encoder.
  {
  //                   bit AB
  s=((PINB^0xFF) & 0b00000011); // Inverto i bit, perché l'encoder chiude a massa, e considero solo D9 e D8. S è composto dai bit A e B.
  s^=s>>1; // Faccio AB XOR A, ottenendo un valore decimale fra 0 e 3.
  if (s!=sp && s==0) x=0;
  if (x==0)
    {
    if (sp==1 && s==2)
      {
      E=1;
      x=1;
      }
    else if (sp==3 && s==2)
      {
      E=-1;
      x=1;
      }
    else if (!s) x=0;
    sp=s;
    } 
  }
}


void setup() 
{
pinMode( 4, OUTPUT); // DIO (Data)
pinMode( 5, OUTPUT); // RCK (Latch)
pinMode( 6, OUTPUT); // SCK (Clock)
pinMode( 7, OUTPUT); // Cicalino.
pinMode( 8, INPUT_PULLUP); // A encoder.
pinMode( 9, INPUT_PULLUP); // B encoder.
pinMode(10, INPUT_PULLUP); // Pulsante encoder verso massa con 100nF in parallelo.

InOut=EEPROM.read(0);
if(InOut>1) InOut=0;
c[1]=EEPROM.read(1);
if(c[1]>9) c[1]=0;
c[2]=EEPROM.read(2);
if(c[2]>9) c[2]=0;
c[3]=EEPROM.read(3);
if(c[3]>9) c[3]=0;
c[4]=EEPROM.read(4);
if(c[4]>9) c[4]=0;

// Pin Change Interrupt Control Register (PCICR): PORTD=PCIE2; PORTC=PCIE1; PORTB=PCIE0; 
// PCICR |= 0b00000001; // PORT B.
PCICR |= 1<<PCIE0;
// PORT B: PMSK0; D10, D9 e D8 sono i bit 2, 1 e 0:
// PCMSK0 |= 0b00000111; 
PCMSK0 |= 1<<PCINT2 | 1<<PCINT1 | 1<<PCINT0;
}


void loop() 
{
if(millis()-t_intermittenza>300)
  {
  t_intermittenza=millis();
  acceso=!acceso;
  }

switch(stato)
  {
  case 0: // Riposo
  break;
  
  case 1: // Sel. In/Out.
    imposta_InOut();
  break;

  case 2: // Salva InOut e imposta la 1a cifra.
    EEPROM.update(0, InOut);
    imposta_cifre();
  break;

  case 3: // Salva la 1a cifra e imposta la 2a.
    EEPROM.update(1, c[1]);
    imposta_cifre();
  break;

  case 4: // Salva la 2a cifra e imposta la 3a.
    EEPROM.update(2, c[2]);
    imposta_cifre();
  break;
  
  case 5: // Salva la 3a cifra e imposta la 4a.
    EEPROM.update(3, c[3]);
    imposta_cifre();
  break;

  case 6: // Salva la 4a cifra e azzera lo stato per eventualmente ricominciare.
    EEPROM.update(4, c[4]);
    stato=0;
  break;
  } // END switch/case.


if(stato!=1) // Se non sto regolando InOut, nel qual caso In o Out deve
  {          // essere libero di lampeggiare, lo scrive stabilmente:
  if(InOut)
    {
    disp_l(2, 'I');
    disp_l(3, 'n');
    }
  else
    {
    disp_l(1, 'O');
    disp_l(2, 'u');
    disp_l(3, 't');
    }
  }
  
for(uint8_t cifra=1; cifra<5; cifra++)
  { // Se non è la cifra che sto regolando, la scrive stabilmente:
  if(cifra != stato-1) disp_n(cifra+4, c[cifra]);
  else disp_l(8, ' ');
  }
}


#define DATA  4
#define LATCH 5
#define CLOCK 6

void disp_n(byte p, byte v)
  {
  // 16 32 64 128 1 2 4 8  
  switch(p)
    {
    case 1: p= 16; break;
    case 2: p= 32; break;
    case 3: p= 64; break;
    case 4: p=128; break;
    case 5: p=  1; break;
    case 6: p=  2; break;
    case 7: p=  4; break;
    case 8: p=  8; break;
    }
    //   ---1---
    //   32    2
    //   --64---
    //   16    4
    //   ---8---  128
  switch(v)
    {
    case 1: v=  6; break;
    case 2: v= 91; break;
    case 3: v= 79; break;
    case 4: v=102; break;
    case 5: v=109; break;
    case 6: v=125; break;
    case 7: v=  7; break;
    case 8: v=127; break;
    case 9: v=111; break;
    case 0: v= 63; break;
    }
    
  v=~v; // ATTENZIONE! I display sono ad anodo comune,  perciò i segmenti
  // si accendono a livello basso! Facendo così, però, possiamo ragionare
  // nei calcoli precedenti secondo una logica non inversa.
  digitalWrite(LATCH, LOW);
  shiftOut(DATA, CLOCK, MSBFIRST, v); // matrice per numero decimale
  shiftOut(DATA, CLOCK, MSBFIRST, p); // Posizione particolare delle cifre
  digitalWrite(LATCH, HIGH);
  }


void disp_l(byte p, char l)
  {
  // 16 32 64 128 1 2 4 8  
  switch(p)
    {
    case 1: p= 16; break;
    case 2: p= 32; break;
    case 3: p= 64; break;
    case 4: p=128; break;
    case 5: p=  1; break;
    case 6: p=  2; break;
    case 7: p=  4; break;
    case 8: p=  8; break;
    }
    //   ---1---
    //   32    2
    //   --64---
    //   16    4
    //   ---8---  128
  switch(l)
    {
    case 'I': l=  6; break;
    case 'n': l= 84; break;
    case 'O': l= 63; break;
    case 'u': l= 28; break;
    case 't': l=120; break;
    case ' ': l=  0; break;
    }
    
  l=~l; // ATTENZIONE! I display sono ad anodo comune,  perciò i segmenti
  // si accendono a livello basso! Facendo così, però, possiamo ragionare
  // nei calcoli precedenti secondo una logica non inversa.
  digitalWrite(LATCH, LOW);
  shiftOut(DATA, CLOCK, MSBFIRST, l); // matrice per numero decimale
  shiftOut(DATA, CLOCK, MSBFIRST, p); // Posizione particolare delle cifre
  digitalWrite(LATCH, HIGH);
  }


/*

0.2 10/5/23 Funziona
0.3 10/5/23 Ho messo la regolazione continua 9->0 senza fine corsa.
0.4 11/5/23 Faccio la funzione salva_visualizza_salta().
0.5 15/5/23 Versione per visualizzazione su moduli con 8 display con HC595.
0.6 15/5/23 Ho ridotto gli stzti  a solo 6, togliendo quelli intermedi. Adesso
          anche i calcoli delle posizioni sono più semplici, perché da una ci-
          fra all'altra è uno stato.
0.7 15/5/23 Metto l'impostazione InOut in una funzione apposita: imposta_InOut.
            Rinomino imposta_cifre() in imposta_cifre().
*/

Ti ho "rubato" la routine dell'encoder.
Devo però lavorarci su per renderla configurabile in modo più semplice.
encoderdatman.zip (2.0 KB)
Ciao.

:slight_smile:
Quella è tutta mia, eh! L'ho inventata qualche anno fa partendo dal codice Gray che esce dall'encoder. A volte la uso in loop stretti, altre volte con l'interrupt.

Ma l'hai presa dallo stroboscopio, non da qui! Qui il "3-" non c'è più, perché uso lo XOR!

Non ricordavo da quale progetto deriva, sono dovuto andare a cercare.
Il programmatore parallelo.

Non ci ho fatto caso.

Il bello di copiare, ricopiare e adattare blocchi di codice è che ogni volta si può notare qualcosa e migliorarli.

Ho aggiunto l'antirimbalzo SW:

#include <EEPROM.h>

volatile uint8_t stato=0; // 0:Riposo; 1:In/Out; 2...5:Le 4 cifre.
volatile bool puls_prec=true; // true = premuto.
volatile uint32_t t_premuto; // Prende il tempo per l'antirimbalzo. Funziona come un conden-
  // satore: finché è premuto, aggiorna il tempo  con millis(); se viene lasciato, ciò viene
  // rilevato solo dopo che sono trascorsi 80ms. Due pressioni più ravvicinate, quindi, sono
  // come un'unica pressione continua.
volatile uint8_t s=0; // Valore decimale dei bit.
volatile uint8_t sp=0; // Stato precedente di s.
volatile uint8_t x=0;
volatile int8_t E=0; // Encoder 1:Orario; -1:Antiorario.

uint8_t InOut=1; // 1:In; 0=Out.
bool acceso=false; // Intermittenza - true: adesso è acceso; false:adesso è spento.
uint32_t t_intermittenza=0;
uint8_t c[5]; // Sono le 4 cifre, per c da 1 a 5.

#define PULS_PREMUTO !((PINB^0xFF)&0b00000100)

/*
EEPROM:
0 InOut
1 c[1]
2 c[2]
3 c[3]
4 c[4]
*/


void Bip()
  {
  digitalWrite(7, HIGH);
  delay(50);
  digitalWrite(7,LOW);
  }
  
void imposta_InOut()
  {
  if(E) // In.
    {
    InOut=1-InOut; // Alterna In/Out.
    }
  E=0;
  if(InOut) // In
    {
    if(acceso)
      {
      disp_l(2, 'I');
      disp_l(3, 'n');
      }
    else // Spento. Serve per mantenere costante il tempo impiegato
      {  // e non alterare la luminosità delle altre cifre.
      disp_l(2, ' ');
      disp_l(3, ' ');
      }
    }
  else // Out
    {
    if(acceso)
      {
      disp_l(1, 'O');
      disp_l(2, 'u');
      disp_l(3, 't');
      }
    else // Spento. Serve per mantenere costante il tempo impiegato
      {  // e non alterare la luminosità delle altre cifre.
      disp_l(1, ' ');
      disp_l(2, ' ');
      disp_l(3, ' ');
      }
    }
  }
void imposta_cifre()
  {
  uint8_t n = stato-1; // Stato==2: 1a cifra.
  if(E) // Se l'encoder è stato ruotato:
    {
    if(E==-1)
      {
      if(c[n]>0) c[n]-=1;
      else if(c[n]==0) c[n]=9;
      }
    else // E==+1:
      {
      if (c[n]<9) c[n]+=1;
      else if(c[n]==9) c[n]=0;
      }
    E=0;
    }
  if(acceso) 
    {
    disp_n(n+4, c[n]);
    disp_l(n+5, ' ');
    }
  else // Spento. Serve per non alterare la luminosità delle altre cifre.
    {
    disp_l(n+5, ' ');
    }
  }


ISR (PCINT0_vect)
{
if(PULS_PREMUTO)
  {
  t_premuto=millis(); // Se il pulsante è premuto, viene continuamente aggiornata.
  } 
else if(millis()-t_premuto>70) // Pulsante non premuto e tempo di antirimbalzo trascorso:
  {                            // Facendo delle prove, ho rilevato  che  con 70ms vengono
  puls_prec=false; // Non premuto.          // rilevate anche più pressioni molto rapide.
  }
  
if (PULS_PREMUTO && puls_prec==false) // Pulsante premuto:
  {
  puls_prec=true;
  stato+=1;
  if(stato>10) stato=0;
  Bip();
  }
else // E' stato ruotato l'encoder.
  {
  //                   bit AB
  s=((PINB^0xFF) & 0b00000011); // Inverto i bit, perché l'encoder chiude a massa, e considero solo D9 e D8. S è composto dai bit A e B.
  s^=s>>1; // Faccio AB XOR A, ottenendo un valore decimale fra 0 e 3.
  if (s!=sp && s==0) x=0;
  if (x==0)
    {
    if (sp==1 && s==2)
      {
      E=1;
      x=1;
      }
    else if (sp==3 && s==2)
      {
      E=-1;
      x=1;
      }
    else if (!s) x=0;
    sp=s;
    } 
  }
}


void setup() 
{
pinMode( 4, OUTPUT); // DIO (Data)
pinMode( 5, OUTPUT); // RCK (Latch)
pinMode( 6, OUTPUT); // SCK (Clock)
pinMode( 7, OUTPUT); // Cicalino.
pinMode( 8, INPUT_PULLUP); // A encoder.
pinMode( 9, INPUT_PULLUP); // B encoder.
pinMode(10, INPUT_PULLUP); // Pulsante encoder (con antirimbalzo SW 70ms).

InOut=EEPROM.read(0);
if(InOut>1) InOut=0;
c[1]=EEPROM.read(1);
if(c[1]>9) c[1]=0;
c[2]=EEPROM.read(2);
if(c[2]>9) c[2]=0;
c[3]=EEPROM.read(3);
if(c[3]>9) c[3]=0;
c[4]=EEPROM.read(4);
if(c[4]>9) c[4]=0;

// Pin Change Interrupt Control Register (PCICR): PORTD=PCIE2; PORTC=PCIE1; PORTB=PCIE0; 
// PCICR |= 0b00000001; // PORT B.
PCICR |= 1<<PCIE0;
// PORT B: PMSK0; D10, D9 e D8 sono i bit 2, 1 e 0:
// PCMSK0 |= 0b00000111; 
PCMSK0 |= 1<<PCINT2 | 1<<PCINT1 | 1<<PCINT0;
}


void loop() 
{
if(millis()-t_intermittenza>300)
  {
  t_intermittenza=millis();
  acceso=!acceso;
  }

switch(stato)
  {
  case 0: // Riposo
  break;
  
  case 1: // Sel. In/Out.
    imposta_InOut();
  break;

  case 2: // Salva InOut e imposta la 1a cifra.
    EEPROM.update(0, InOut);
    imposta_cifre();
  break;

  case 3: // Salva la 1a cifra e imposta la 2a.
    EEPROM.update(1, c[1]);
    imposta_cifre();
  break;

  case 4: // Salva la 2a cifra e imposta la 3a.
    EEPROM.update(2, c[2]);
    imposta_cifre();
  break;
  
  case 5: // Salva la 3a cifra e imposta la 4a.
    EEPROM.update(3, c[3]);
    imposta_cifre();
  break;

  case 6: // Salva la 4a cifra e azzera lo stato per eventualmente ricominciare.
    EEPROM.update(4, c[4]);
    stato=0;
  break;
  } // END switch/case.


if(stato!=1) // Se non sto regolando InOut, nel qual caso In o Out deve
  {          // essere libero di lampeggiare, lo scrive stabilmente:
  if(InOut)
    {
    disp_l(2, 'I');
    disp_l(3, 'n');
    }
  else
    {
    disp_l(1, 'O');
    disp_l(2, 'u');
    disp_l(3, 't');
    }
  }
  
for(uint8_t cifra=1; cifra<5; cifra++)
  { // Se non è la cifra che sto regolando, la scrive stabilmente:
  if(cifra != stato-1) disp_n(cifra+4, c[cifra]);
  else disp_l(8, ' ');
  }
}


#define DATA  4
#define LATCH 5
#define CLOCK 6

void disp_n(byte p, byte v)
  {
  // 16 32 64 128 1 2 4 8  
  switch(p)
    {
    case 1: p= 16; break;
    case 2: p= 32; break;
    case 3: p= 64; break;
    case 4: p=128; break;
    case 5: p=  1; break;
    case 6: p=  2; break;
    case 7: p=  4; break;
    case 8: p=  8; break;
    }
    //   ---1---
    //   32    2
    //   --64---
    //   16    4
    //   ---8---  128
  switch(v)
    {
    case 1: v=  6; break;
    case 2: v= 91; break;
    case 3: v= 79; break;
    case 4: v=102; break;
    case 5: v=109; break;
    case 6: v=125; break;
    case 7: v=  7; break;
    case 8: v=127; break;
    case 9: v=111; break;
    case 0: v= 63; break;
    }
    
  v=~v; // ATTENZIONE! I display sono ad anodo comune,  perciò i segmenti
  // si accendono a livello basso! Facendo così, però, possiamo ragionare
  // nei calcoli precedenti secondo una logica non inversa.
  digitalWrite(LATCH, LOW);
  shiftOut(DATA, CLOCK, MSBFIRST, v); // matrice per numero decimale
  shiftOut(DATA, CLOCK, MSBFIRST, p); // Posizione particolare delle cifre
  digitalWrite(LATCH, HIGH);
  }


void disp_l(byte p, char l)
  {
  // 16 32 64 128 1 2 4 8  
  switch(p)
    {
    case 1: p= 16; break;
    case 2: p= 32; break;
    case 3: p= 64; break;
    case 4: p=128; break;
    case 5: p=  1; break;
    case 6: p=  2; break;
    case 7: p=  4; break;
    case 8: p=  8; break;
    }
    //   ---1---
    //   32    2
    //   --64---
    //   16    4
    //   ---8---  128
  switch(l)
    {
    case 'I': l=  6; break;
    case 'n': l= 84; break;
    case 'O': l= 63; break;
    case 'u': l= 28; break;
    case 't': l=120; break;
    case ' ': l=  0; break;
    }
    
  l=~l; // ATTENZIONE! I display sono ad anodo comune,  perciò i segmenti
  // si accendono a livello basso! Facendo così, però, possiamo ragionare
  // nei calcoli precedenti secondo una logica non inversa.
  digitalWrite(LATCH, LOW);
  shiftOut(DATA, CLOCK, MSBFIRST, l); // matrice per numero decimale
  shiftOut(DATA, CLOCK, MSBFIRST, p); // Posizione particolare delle cifre
  digitalWrite(LATCH, HIGH);
  }


/*

0.2 10/5/23 Funziona
0.3 10/5/23 Ho messo la regolazione continua 9->0 senza fine corsa.
0.4 11/5/23 Faccio la funzione salva_visualizza_salta().
0.5 15/5/23 Versione per visualizzazione su moduli con 8 display con HC595.
0.6 15/5/23 Ho ridotto gli stzti  a solo 6, togliendo quelli intermedi. Adesso
          anche i calcoli delle posizioni sono più semplici, perché da una ci-
          fra all'altra è uno stato.
0.7 15/5/23 Metto l'impostazione InOut in una funzione apposita: imposta_InOut.
            Rinomino regola_cifre() in imposta_cifre().
0.8 17/5/23 Introduco l'antirimbalzo software per il pulsante. Funziona esatta-
          mente come un condensatore.
*/

qui un piccolo for non sarebbe più leggibile ?

Si, certo...

for(uint8_t n=1; n<5; n++)
  {
  c[n]=EEPROM.read(n);
  if(c[n]>9) c[n]=0;
  }

Sono 48 byte in meno. :slight_smile:

1 Like

Così è un po' più complesso, ma giustamente anche se uno solo è fuori limite bisogna azzerare tutto:

bool error=false;
InOut=EEPROM.read(0); 
if(InOut>1)
  {
  error=true;
  }
else for(uint8_t n=1; n<5; n++)
       {
       c[n]=EEPROM.read(n);
       if(c[n]>9)
         {
         error=true;
         break; // Grazie, nid69ita :)
         }
       }
if(error)
  {
  InOut=0;
  for(uint8_t n=0; n<5; n++)
    {
    c[n]=0; // In realtà, c[0] non è usato.
    EEPROM.update(n, 0);
    }
  }

Per forzare uscita da for usa break;

1 Like

Ah! Break esce da for-while-switch, mentre return esce dalla funzione in cui si trova, eventualmente ritornando un valore:

Si anche in java è così, ma come mai, stai usando java?

Ciao.

No, no! Mi sembrava, però, che nominassero anche il C... Mi sono sbagliato?
Ci sono differenze in C rispetto a quanto ho scritto?

Ho capito, no, java nei costrutti base è identico al C, if, while ecc, non ricordo se c'è switch. Comunque ho avuto la curiosità perché ho letto java e mi son detto vuoi vedere che sta imparando java. Nel frattempo mi dicevo ma che c'èntra?
Tra i post qualcuno ha postato:

public void myMethod()
{
    int i = 10;

    if(i==10)
        return;

    System.out.println("This will never be printed");
}

Che è proprio java. :grinning:

Comunque è facile confondersi tanto sono simili.

Si break, esce dai cicli e si usa nello switch case. Ma return restituisce il controllo al chiamante, cioè se nel loop ci metti un return si restituisce il controllo alla main(). A conti fatti esce da qualunque cosa, for, while switch, if. Detta in altri termini termina la funzione anticipatamente.

Ciao.



Cercavo informazioni sul 7219 e le sue librerie e ricordavo male, pensavo fosse questo il topic. Nonostante ciò ho dato una occhiata al codice che non capivo o meglio mi aspettavo si facesse una cosa e non la trovavo. La cosa che credevo si facesse è scrivere su buffer c string nul terminato per poi decodificarlo byte per byte e spedirlo via spi, mi aspettavo anche che lo facesse byte per byte ed per ognu byte restituisse il controllo al loop principale e fino che non ha spedito il contenuto del buffer risultasse occupato (busy) cioè non è possibile scrivere sul buffere mentre questo non è ancora spedito.

Pensi possa migliorare la gestione del multiplexing?

PS: se hai a portata di mano il link a tuo topic su max7219 8x8 postalo grazie. :smiley:

Ciao.

Ciao
Non ho capito il discorso... A quale codice ti riferisci?
Parli del multiplexing col 595? Non credo che si possa migliorare... Bisogna solo scrivere una cifra per volta (al massimo si possono scrivere contemporaneamente cifre uguali, se presenti, ma diminuisce la luminosità, perché stanno in parallelo con le resistenze in comune) in continuazione...

Il 7219, invece, una volta ricevuta la stringa multiplexa da solo.

È questa la discussione che cerchi?

Io lo avevo realizzato il multiplex con 4 bjt, quindi solo 4 digit e non ho mai avuto problemi, ma usavo un timer e la isr aggiornava il display ricavando i digit da un array (il buffer di cui accennavo).

Una cosa simile a quella che ho trovato su wokwi ma in questo caso usa proprio il 595 e un attiny85.

Provalo qui.

Ci sarebbe da provare ad usare la SPI hardware.

Ciao.

Scusa, ma per risolvere quale problema?...