Usiamo ancora i timer e gli interrupt: realizziamo un cronometro/timer

Ciao a tutti

Per giocare un po' con i display con il 7219 ho pensato di fare un cronometro. Inizialmente pensavo di usare semplicemente millis(), ma poi ho preferito usare un timer, che mi permette anche di aggiornare il contatore del tempo nella ISR, quindi indipendentemente da qualunque altra cosa stia accadendo.
Ho usato un interrupt anche per la lettura dell'encoder, non per non perdere impulsi, ma per avere, anche qui, una lettura continua in qualunque stato del programma, senza doverlo leggere continuamente. Per il conteggio del tempo ho impostato il timer a 10ms (100Hz), con il solito calcolatore online:
https://www.arduinoslovakia.eu/application/timer-calculator
Per l'encoder, invece, ho usato un Pin Change Interrupt.

Appena acceso, dopo la presentazione, è pronto a partire alla prima pressione dell'encoder; alla seconda si mette in pausa e alla successiva riparte. Un altro pulsante azzera il conteggio. Al momento può azzerare e tenere azzerato anche durante il conteggio ripartendo subito dopo, ma forse sarebbe meglio farlo funzionare solo a conteggio fermo. Ci vuole poco...

Durante il conteggio, ruotando l'encoder e poi premendolo si può accedere all'impostazione Centesimi/Frame. Può essere utile per usarlo per sicronizzare riprese video (a 25 frame/secondo).

Quando il conteggio è fermo, invece, il menu è più ampio:

  • prima c'è il Preset, con cui si può impostare il tempo all'avvio in ore, minuti e secondi;
  • poi c'è Avanti/Indietro, con cui si può contare alla rovescia e al raggiungimento dello zero suona la note Do-La-Fa (Fa M).
  • poi c'è ancora Centesimi/Frame.

Funziona molto bene e, dato che il conteggio avviene nella ISR, è stato facile non fermarlo mai se non richiesto.

Che ne dite? Come mi è venuto?

#include "LedControl.h"
#define DIN A0 
#define CS  A1 
#define CLK A2 
LedControl disp = LedControl(DIN,CLK,CS);
bool premuto=true;
int8_t selezione=0; // Valore selezionato nel menu.
volatile bool start=false; // true: conteggio in corso.
volatile bool fine=false; // true: tempo scaduto (conteggio all'indietro).
bool azzerato=false;
volatile uint32_t t100=0; // Tempo contato (nella ISR) in centesimi di secondo.
uint8_t secondi=0;
uint8_t minuti=0;
uint8_t ore=0;

volatile int8_t E; // Risultato della routine encoder(): 1, -1, 0.
volatile uint8_t S; // Lettura dei due valori dell'encoder.
volatile uint8_t So;// Lettura precedente dell'encoder.
volatile uint8_t X; // Usato in encoder() per evitare letture multiple.

int8_t preset_ore=0;
int8_t preset_minuti=0;
int8_t preset_secondi=0;
bool frame=false; // true:frame; false:centesimi.
volatile bool avanti=true; // false:conta indietro

// ----------------------- SETUP ----------------------- 
void setup () 
{
//Serial.begin(115200);
pinMode (6, INPUT_PULLUP); // Pulsante Start/Stop a Gnd con 100nF in parallelo.
pinMode (7, INPUT_PULLUP); // Pulsante Azzeramento.
pinMode (8, INPUT_PULLUP); // Encoder: A.
pinMode (9, INPUT_PULLUP); // Encoder: B.
pinMode (13, OUTPUT); // Cicalino.

// INTERRUPT PER L'ENCODER:
// Pin Change Interrupt Control Register (PCICR): PORTD=PCIE2; PORTC=PCIE1; PORTB=PCIE0; 
// PCICR |= 0b00000001; // PORT B.
PCICR |= 1<<PCIE0;
// PORT B: PMSK0; D9 e D8 sono i bit 1 e 0:
// PCMSK0 |= 0b00000011; 
PCMSK0 |= 1<<PCINT1 | 1<<PCINT0;

disp.shutdown (0,false); // Wakeup MAX7219.
disp.setIntensity (0,4); // Da 0 a 15.
disp.clearDisplay (0);
titolo_1();
//titolo_2();
delay(1500);
// azzera();

// INTERRUPT PER L'INCREMENTO OGNI 10ms (100Hz):
noInterrupts();
// Clear registers
TCCR1A = 0;
TCCR1B = 0;
TCNT1 = 0;
// 100 Hz (16000000/((624+1)*256))
OCR1A = 624;
// CTC
TCCR1B |= (1 << WGM12);
// Prescaler 256
TCCR1B |= (1 << CS12);
// Output Compare Match A Interrupt Enable
TIMSK1 |= (1 << OCIE1A);
interrupts();
Bip();
}

// ----------------------- LOOP ----------------------- 
void loop () 
{
if(!digitalRead(7)) // Pulsante di Reset.
  {
  if(avanti) azzera();
  else t100  = (uint32_t)(((preset_ore*60)+preset_minuti)*60+preset_secondi)*100;
  }
  
if(E) // Se l'encoder è stato ruotato:
  {
  selezione+=E;
  if(selezione<1) selezione=0;
  if(selezione>3) selezione=3;
  if(start)
    {
    while(selezione==1 || selezione==2) selezione+=E; // Se sta contando, Preset e Avanti/indietro non devono apparire.
    }
  E=0;
  visual_menu();
  } // End if(E).
  
switch(selezione)
  {
  case 0: // ----- Funzionamento normale ----- //
  scrivi_tempo();
  if(!digitalRead(6))
    {
    if(!premuto) // Se il pulsante è stato premuto adesso:
      {
      premuto=true;
      if(!start) // Se il cronometro è fermo, parte:
        {
        start=true;
        Bip();
        }
      else // Se sta contando, si ferma:
        {
        start=false;
        Biip();
        }
      } 
    }
  else // Se start/stop non è premuto in questo momento:
    {
    premuto=false;
    }
  break; 
  case 1: // --------- Preset ---------- //
  visual_menu();
  if(!digitalRead(6)) // Se viene premuto il pulsante:
    {
    imposta_tempo();
    }
  break;  
  case 2: // ----- Avanti/Indietro ----- //
  visual_menu();
  if(!digitalRead(6)) // Se viene premuto il pulsante:
    {
    avanti_o_indietro();
    }
  break; 
  case 3: // ----- Centesimi/Frame ----- //
  visual_menu();
  if(!digitalRead(6)) // Se viene premuto il pulsante:
    {
    centesimi_o_frame();
    }
  break;
  } // END switch.
  
if(start) // Se sta contando:
  {
  if(azzerato) // Se è stato appena azzerato:
    {
    Bip();
    azzerato=false;
    }
  }

if(fine)
  {
  BipEnd();
  fine=false;
  }
}

// ----------------------- ISR t100, SUONI E AZZERAMENTO ----------------------- 
ISR(TIMER1_COMPA_vect) 
{
if(start)
  {
  if(avanti) t100+=1;
  else // Indietro.
    {
    if(t100) t100-=1;
    else
      {
      start=false;
      fine=true;
      }
    }
  }
}

void Bip()   {tone(13,2000, 70);}
void Biip()  {tone(13,2000,200);}
void Biiip() {tone(13,2000,300);}
void BipEnd()
{
tone(13,2093,500); delay(500); // Do
tone(13,1760,500); delay(500); // La
tone(13,1397,1500);            // Fa
}

void azzera()
{
if(t100) Biiip(); // Fa Biiip solo se non è già stato azzerato, cioè se t100 è diverso da zero.
azzerato=true;
scrivi_cifre(1,0); scrivi_cifre(2,0); scrivi_cifre(3,0); scrivi_cifre(4,0); // Scrive 00.00.00
while(!digitalRead(7)); // Per azzerare il tempo, attende che venga lasciato il pulsante.
t100=0;
}

// ----------------------- IMPOSTAZIONI ----------------------- 
void imposta_tempo()
{
disp.clearDisplay(0); // Spegne tutti i display.
scrivi_cifre(1, preset_ore);
while(!digitalRead(6)); // Aspetta che venga lasciato il pulsante.
while(digitalRead(6)) // Finché non viene premuto il pulsante:
  {
  if(E!=0)
    {
    preset_ore+=E;
    if(preset_ore<0) preset_ore=99;
    else if(preset_ore>99) preset_ore=0;
    scrivi_cifre(1, preset_ore);
    E=0;
    }
  }
scrivi_cifre(2, preset_minuti);
while(!digitalRead(6)); // Aspetta che venga lasciato il pulsante.
while(digitalRead(6)) // Finché non viene premuto il pulsante:
  {
  if(E!=0)
    {
    preset_minuti+=E;
    if(preset_minuti<0) preset_minuti=59;
    else if(preset_minuti>59) preset_minuti=0;
    scrivi_cifre(2, preset_minuti);
    E=0;
    }
  }
scrivi_cifre(3, preset_secondi);
while(!digitalRead(6)); // Aspetta che venga lasciato il pulsante.
while(digitalRead(6)) // Finché non viene premuto il pulsante:
  {
  if(E!=0)
    {
    preset_secondi+=E;
    if(preset_secondi<0) preset_secondi=59;
    else if(preset_secondi>59) preset_secondi=0;
    scrivi_cifre(3, preset_secondi);
    E=0;
    }
  }
t100=preset_ore;
t100=t100*60+preset_minuti;
t100=t100*60+preset_secondi;
t100*=100;
Bip();
selezione=0;
premuto=true; // Per non far partire o fermare il cronometro appena ritorna.
}

void visual_preset()
  {
  scrivi_cifre(1, preset_ore);
  scrivi_cifre(2, preset_minuti);
  scrivi_cifre(3, preset_secondi);
  }

void avanti_o_indietro()
{
visual_av_ind();
while(!digitalRead(6)); // Aspetta che venga lasciato il pulsante.
while(digitalRead(6)) // Finché non viene premuto il pulsante.
  {
  if(E)
    {
    avanti=E+1; // E=-1:indietro; E=+1:avanti.
    visual_av_ind();
    E=0;
    }
  }
Bip();
selezione=0;
premuto=true; // Per non far partire o fermare il cronometro appena ritorna.
}

void centesimi_o_frame()
{
disp.clearDisplay (0); // Cancella il display.
visual_centesimi_o_frame();
while(!digitalRead(6)); // Aspetta che venga lasciato il pulsante.
while(digitalRead(6)) // Finché non viene premuto il pulsante.
  {
  if(E)
    {
    frame=E+1;
    visual_centesimi_o_frame();
    E=0;
    }
  }
Bip();
selezione=0;
premuto=true; // Per non far partire o fermare il cronometro appena ritorna.
}

// ----------------------- VISUALIZZAZIONI ----------------------- 
void visual_centesimi_o_frame()
{
if(frame)
  {
  disp.setRow (0,7,0x47); // F 
  disp.setRow (0,6,0x05); // r 
  disp.setRow (0,5,0x00); //   
  disp.setRow (0,4,0x00); //  
  }
else
  {
  disp.setRow (0,7,0x4E); // C 
  disp.setRow (0,6,0x6F); // e 
  disp.setRow (0,5,0x15); // n 
  disp.setRow (0,4,0x0F); // t
  }
}

void scrivi_tempo()// Impiega in tutto 2,1~2,2ms. Chissà perché, le prime 6 chiamate da ogni start del cronometro
{                                            // impiegano circa 2200us; poi una poco meno e le successive 2132us!
uint32_t tempo=t100; // Tempo trascorso in centesimi di secondo.
uint8_t cent;
if(!frame) cent=tempo%100; // in centesimi di secondo.
else cent=(tempo%100)/4; // in frame (25f/s). 
disp.setChar (0,0,(cent%10)+48,false); // Unità di centesimi.
disp.setChar (0,1,(cent/10)+48,false); // Decine di centesimi (decimi).
tempo/=100; // Tempo in secondi.
ore=tempo/3600;
minuti=((tempo%3600)/60)%60;
secondi=(tempo%3600)%60;
disp.setChar (0,7,(ore/10)+48,false); // Decine di ore.
disp.setChar (0,6,(ore%10)+48,true); // Ore.
disp.setChar (0,5,(minuti/10)+48,false); // Decine di minuti.
disp.setChar (0,4,(minuti%10)+48,true); // Unità di minuti.
disp.setChar (0,3,(secondi/10)+48,false); // Decine di secondi.
disp.setChar (0,2,(secondi%10)+48,true); // Unità di secondi.
}

void scrivi_cifre(uint8_t gruppo, uint8_t valore) // gruppo= 1:ore; 2:minuti; 3:secondi.
{
uint8_t p_unita = (3-gruppo)*2 +2;
disp.setChar (0, p_unita+1,(valore/10)+48,false); // Decine.
if(gruppo!=4) disp.setChar (0, p_unita,(valore%10)+48,true); // Unità.
else disp.setChar (0, p_unita,(valore%10)+48,false); // Se scrivo la cifra dei centesimi, non deve avere il punto.
}

void visual_av_ind()
{
if(avanti)
  {
  disp.setRow (0,7,0x77); // A 
  disp.setRow (0,6,0x1C); // v 
  disp.setRow (0,5,0x7D); // a 
  disp.setRow (0,4,0x15); // n 
  disp.setRow (0,3,0x0F); // t
  disp.setRow (0,2,0x10); // i 
  disp.setRow (0,1,0x00); //   
  disp.setRow (0,0,0x00); //  
  }
else
  {
  disp.setRow (0,7,0x30); // I 
  disp.setRow (0,6,0x15); // n 
  disp.setRow (0,5,0x3D); // d 
  disp.setRow (0,4,0x10); // i
  disp.setRow (0,3,0x6F); // e  
  disp.setRow (0,2,0x0F); // t
  disp.setRow (0,1,0x05); // r
  disp.setRow (0,0,0x1D); // o    
  }
}

void visual_menu()
{
switch(selezione)
  {
  //  case 0:
  //  disp.setRow (0,7,0x4F); // E
  //  disp.setRow (0,6,0x5B); // S
  //  disp.setRow (0,5,0x4E); // C
  //  disp.setRow (0,4,0x00); //
  //  disp.setRow (0,3,0x00); //
  //  disp.setRow (0,2,0x00); //
  //  disp.setRow (0,1,0x00); //   
  //  disp.setRow (0,0,0x00); //   
  //  break;
  case 1:
  disp.setRow (0,7,0x67); // P
  disp.setRow (0,6,0x05); // r
  disp.setRow (0,5,0x6F); // e
  disp.setRow (0,4,0x5B); // s
  disp.setRow (0,3,0x6F); // e
  disp.setRow (0,2,0x0F); // t
  disp.setRow (0,1,0x00); //   
  disp.setRow (0,0,0x00); //   
  break;
  case 2:
  disp.setRow (0,7,0x77); // A 
  disp.setRow (0,6,0x9C); // v.
  disp.setRow (0,5,0x01); // -
  disp.setRow (0,4,0x30); // I 
  disp.setRow (0,3,0x15); // n 
  disp.setRow (0,2,0xBD); // d.
  disp.setRow (0,1,0x00); //   
  disp.setRow (0,0,0x00); // 
  break;
  case 3:
  disp.setRow (0,7,0x4E); // C
  disp.setRow (0,6,0x6F); // e
  disp.setRow (0,5,0x15); // n
  disp.setRow (0,4,0x8F); // t.
  disp.setRow (0,3,0x01); // -
  disp.setRow (0,2,0x47); // F 
  disp.setRow (0,1,0x85); // r. 
  disp.setRow (0,0,0x00); // 
  break;
  }
}

void titolo_1()
{             //   0     1     2     3     4     5     6
uint8_t testo[]={0x5B, 0x1D, 0x15, 0x1D, 0x05, 0x17, 0x4E};
for (int8_t x=-1; x<7; x++)
  {
  for (int8_t p=x; p>-1; p--) 
    {
    disp.setRow (0,p,testo[p]);
    }
  delay(100);
  }
for (int8_t x=-1; x<7; x++)
  {
  for (int8_t p=x; p>-1; p--) 
    {
    disp.setChar (0,p,' ',false);
    }
  delay(100);
  }
}

void titolo_2()
            // 0  1  2  3  4  5  6  7   8     9    10    11    12    13    14   15 16 17 18 19 20 21 22
{           //                         0:S   1:o   2:n   3:o   4:r   5:h   6:C                  
int8_t car[]={0, 0, 0, 0, 0, 0, 0, 0, 0x5B, 0x1D, 0x15, 0x1D, 0x05, 0x17, 0x4E, 0, 0, 0, 0, 0, 0, 0, 0};
for(int8_t x=15; x>-1; x--)
  {
  for(int8_t p=0; p<8; p++){disp.setRow (0, p, car[p+x]);}
  delay(150);
  }
}
//disp.setRow (0,7,0x4E); // C
//disp.setRow (0,6,0x17); // h
//disp.setRow (0,5,0x05); // r
//disp.setRow (0,4,0x1D); // o
//disp.setRow (0,3,0x15); // n
//disp.setRow (0,2,0x1D); // o
//disp.setRow (0,1,0x5B); // S

// ----------------------- ISR Encoder ----------------------- 
ISR (PCINT0_vect)
{
//                   bit AB
S=((PINB^0xFF) & 0b00000011); // Inverto i bit, perché l'encoder chiude a massa, e considero solo D9 e D8. S (Stato) è composta dai bit A e B.
S^=S>>1; // Faccio AB XOR A, ottenendo un valore decimale di Stato fra 0 e 3.
if (S!=So && S==0) X=0; // Se lo Stato è cambiato ed è andato a 0: X=0.
if (X==0) // Pronto a rilevare una rotazione, perché lo Stato è passato per lo 0.
  {
  if (So==1 && S==2) // E' passato da 1 a 2: rotazione oraria: E=+1.
    {
    E=1;
    X=1; // Non potrà rilevare nuove rotazioni finchè S non passerà di nuovo per lo 0.
    }
  else if (So==3 && S==2) // E' passato da 3 a 2: rotazione antioraria: E=-1.
    {
    E=-1;
    X=1; // Non potrà rilevare nuove rotazioni finchè S non passerà di nuovo per lo 0.
    }
  else if (!S) X=0;
  So=S; // Aggiorno lo Stato precedente con quello corrente.
  } 
}

// ----------------------- NOTE ----------------------- 
/* 
Fis.I/OPorta
 1   - RS
 2   0 PD0
 3   1 PD1
 4   2 PD2 
 5   3 PD3 
 6   4 PD4 Encoder: A (con INPUT_PULLUP).
--
11   5 PD5 Encoder: B (con INPUT_PULLUP).
12   6 PD6 Encoder: Pulsante (con INPUT_PULLUP) verso GND con 100nF in parallelo.
13   7 PD7 Pulsante Reset.
14   8 PB0 
----------
15   9 PB1 
16  10 PB2    
17  11 PB3    
18  12 PB4    
19  13 PB5    Uscita per cicalino passivo.
--
23  14 PC0 A0 DIN |
24  15 PC1 A1 CS  |Display 8x 7segmenti.
25  16 PC2 A2 CLK |
26  17 PC3 A3 
27  18 PC4 A4 SDA 
28  19 PC5 A5 SCL 
29  20     A6 (solo in Arduino Nano)
          
Fis
 9     PB6 XTAL 16MHz In : compensatore a GND (ho messo 22+10pF).
10     PB7 XTAL 16MHz Out: 22pF a GND.
21    ARef
7,20: Vcc
8,22: GND
*/

// ----------------------- VERSIONI ----------------------- 
/*
v0.0  21/2/23  
v0.1  21/2/23   Comincia a funzionare.
v0.2  21/2/23   Premendo una prima volta, parte facendo Bip.
                Premendo una seconda volta, va in pausa facendo Biip.
                Premendo di nuovo, continua il conteggio facendo Bip.
                Premendo l'azzeramento, azzera: se non sta già a zero fa Biiip, altrimenti rimane muto.
                Se l'azzeramento è stato fatto mentre contava, poi riparte automaticamente facendo Bip.
v0.3  23/2/23   Ho aggiunto la variabile cent in scrivi_tempo().
                Ho aggiunto la possibilità di visualizzare i frame anziché i centesimi di secondo.
                Ho aggiunto un po' di commenti.
v0.6  24/2/23   Ho aggiunto il menu centesimi/frame.
v0.7temp  24/2/23 Ho aggiunto il menu avanti/indietro, ma ancora manca la logica per il conteggio indietro.
                  Funziona quasi... Ma alla rovescia, quando arriva a zero non se ne esce più!
v0.8temp  24/2/23 Leggo l'encoder con l'interrupt, così non devo chiamarlo in continuazione e posso saltare
                ai menu ruotandolo.
v0.9temp  24/2/23 Divido il programma in schede (file) e vado avanti..
v0.10temp   25/2/23 Introduco la temporizzazione dei 10ms (centesimi di secondo) fatta con il Timer 1:
                  https://www.arduinoslovakia.eu/application/timer-calculator
                    Sostituisco la variabile "indietro" con la variabile "avanti".
                    Funziona il menu: Preset / Av.-Ind. / Cent-Fr.
v0.11temp1  26/2/23 Elimino t0, che non serve più per l'incremento periodico di t100 (lo faccio con un timer)
                  e t_premuto, che serviva per la pressione lunga (ora uso la rotazione dell'encoder).
                    Aggiungo a scrivi_cifre() la possibilità di scrivere il 4°gruppo (decimi e centesimi) per
                  l'azzeramente. Sul 4°gruppo non deve accendere il punto.
                    Aggiungo nel menu 0=ESC, per tornare indietro senza fare nulla.
v0.11temp6   1/3/23 Ho sistemato  l'entrata e l'uscita  dalle impostazioni.
                    Rimane da aggiustare il blocco quando il conteggio all'indietro arriva a 0.
v0.12temp1   2/3/23 Se sta contando, oltre a non dover apparire il menu Avanti/Indietro, non deve apparire ne-
                  anche Preset.
v0.12temp2   2/3/23 Aggiungo il titolo: ChronoS.
v1.0         2/3/23 Sistemo la fine del conteggio alla rovescia e aggiungo il suono.
                    Sembra funzionare tutto! :)
v1.1         2/3/23 Faccio il titolo animato.
v1.1a        4/3/23 Ho aggiunto titolo_2() e rinominato titolo() in titolo_1().

*/

Casomai tu abbia tanta pazienza e voglia , mi permetto di usufruirne un poco e ti chiedo :


#include "LedControl.h" //libreria per display 7219. giusto?
#define DIN A0 // pin display , giusto?
#define CS  A1 // pin display , giusto?
#define CLK A2 // pin display , giusto?

pinMode (6, INPUT_PULLUP); // Pulsante Start/Stop a Gnd con 100nF in parallelo. PERCHE' ? SENZA RESISTENZE ?
pinMode (7, INPUT_PULLUP); // Pulsante Azzeramento.
pinMode (8, INPUT_PULLUP); // Encoder: A. L'ENCODER E'  HW-040 ? 
pinMode (9, INPUT_PULLUP); // Encoder: B. IO LO FACCIO GIRARE SENZA PULLUP ....VA BENE LO STESSO?

In qualche commento ho "urlato" . Ma non è un grido , vedili come un evidenziatore scolastico ( rosso).
Grazie in ogni caso.
Buona Giornata.

Ciao
Ho aggiunto i commenti relativi ai tuoi dubbi.

// Libreria per il modulo con 8 display a 7 segmenti con MAX7219 e i tre pin:
#include "LedControl.h" 
#define DIN A0 
#define CS  A1 
#define CLK A2 

pinMode (6, INPUT_PULLUP); // Pulsante Start/Stop a Gnd con 100nF in parallelo.
// Il condensatore è un semplicissimo antirimbalzo hardware. Con la resistenza
// di pullup formano un RC, che determina la costante di tempo.

// Impostazione  dei tre ingressi per l'encoder con resistenza  di pullup, indi-
// spensabile per tenere a livello alto gli ingressi quando gli interruttori so-
// no aperti. L'encoder è un comunissimo HW-040 che chiude a massa. Se ha delle
// resistenze di pulldown montate sullo stampato, vanno tolte.
pinMode (7, INPUT_PULLUP); // Pulsante.
pinMode (8, INPUT_PULLUP); // Encoder: A. 
pinMode (9, INPUT_PULLUP); // Encoder: B.

Grazie!
Adesso cerco i condensatori e voglio proprio provarli ( non so perché , ma i condensatori mi affascinano un sacco) :blush:
Non esiste che mi cimento a dissaldare dal HW-40 :smile: :smile:

è in questi casi che mi sento piuttosto ingenuo ;
ma è sempre in questi casi che imparo veramente.

Ringraziandoti ancora , ti avviso ( :thinking:) :
ho acquistato la matrice ed ho intenzione di provare il tuo sketch , certo , ora devo comprare anche i condensatori :smile: :smile:

Pensavo di fare così :
primo step : copio / incollo / imparo ad usarlo.
secondo step : sostituisco la matrice con un display 16, 2 I2c.
terzo step : boh...sicuro salterà fuori qualcosa

1 Like

Usando un lcd, la gestione del displayè molto più semplice, perché scrivi direttamente i caratteri, non devi accendere i singoli segmenti. Certo, però, dovrai apportare delle modifiche anche per posizionare i caratteri. Inoltre, l'lcd non riuscirà a seguire bene i centesimi di secondo L'occhio nemmeno ci riesce, quindi cambia solo l'effetto ottico; diverso è se lo riprendi e poi vai a rivederlo frame per frame.

Funziona davvero :smile: :smile: ed è troppo bello con i segmenti !
Ah , mica avevo dubbi sul suo funzionamento , ma escludendo i vari blink , questo è il primo
progetto che mi riesce di copiare e far girare...
Però avrei due domande : dissaldo le resistenze dell' encoder e basta? oppure devo poi chiudere il circuito? Ho visto che il pulsante è "pulito" , quindi lo posso , e devo ,trattare come un qualsiasi pulsante?

Al momento non sono in grado di fare domande migliori e più interessanti.

...pensavo di usare un lcd solo per cercare di scorporare il tutto , lo divido a blocchi fra quello che riesco a "leggere" e quello che non so. :sweat_smile:
grazie.

...E certo che funziona! L'ho scritto tutto io!
:smile::smile::smile:
L'encoder e il pulsante devono solo chiudere a massa, perché attivo le resistenze di pull-up del microcontrollore. Le resistenze di pull-up sull'encoder sarebbe meglio toglierle oppure collegare il + dell'encoder al positivo ma se funziona puoi anche lasciare così...

Adesso puoi provare a modificarlo per l'LCD.

Ho capito , io infatti ho sempre collegato tutti i pin dell' encoder.
Comunque voglio provare senza resistenze.
ancora grazie.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.