Strumenti Utente

Strumenti Sito


simon

Differenze

Queste sono le differenze tra la revisione selezionata e la versione attuale della pagina.

Link a questa pagina di confronto

Entrambe le parti precedenti la revisioneRevisione precedente
Prossima revisione
Revisione precedente
Prossima revisioneEntrambe le parti successive la revisione
simon [2021/01/11 18:23] – [Software] adminsimon [2021/01/17 18:24] – [Software] admin
Linea 250: Linea 250:
  
 Prerequisiti: Prerequisiti:
-  * sapere come funzionano gli [[wpi>Operazione_bit_a_bit|operatori bitwise]], il [[wp>Mask_(computing)|bit masking]], lo shift a destra (>>) e sinistra (<<)+  * sapere come funzionano gli [[wpi>Operazione_bit_a_bit|operatori bitwise]], il [[wp>Mask_(computing)|bit masking]], lo shift a destra (''%%>>%%'') e sinistra (''%%<<%%'')((vedi anche [[https://playground.arduino.cc/Code/BitMath/|questo tutorial]] dal sito di Arduino))
   * essere in grado di trovare le informazioni nel datasheet di un microcontrollore, in particolare la parte che riguarda i registri, il nome dei bit nei registri e la funzione svolta (in questo caso è utile il sommario a pagina 158 del datasheet dell'ATtiny13A)   * essere in grado di trovare le informazioni nel datasheet di un microcontrollore, in particolare la parte che riguarda i registri, il nome dei bit nei registri e la funzione svolta (in questo caso è utile il sommario a pagina 158 del datasheet dell'ATtiny13A)
   * saper programmare in C   * saper programmare in C
Linea 293: Linea 293:
   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
   OTHER DEALINGS IN THE SOFTWARE.   OTHER DEALINGS IN THE SOFTWARE.
 +*/ 
    
- +/*
   **** SPIEGAZIONI INTRODUTTIVE ****   **** SPIEGAZIONI INTRODUTTIVE ****
    
   SCOPO DEL PROGRAMMA   SCOPO DEL PROGRAMMA
   Il codice implementa il classico gioco Simon con 4 LED, 4 pulsanti   Il codice implementa il classico gioco Simon con 4 LED, 4 pulsanti
-  e una sequenza da ricordare; la sequenza casuale è generata quando  +  e una sequenza di luci e suoni di memorizzar e riprodurre 
-  il pulsante start/reset avvia il gioco; la sequenza si allunga ogni +  la sequenza casuale è generata quando il pulsante start/reset avvia 
-  volta che si indovina; il gioco si interrompe quando si sbaglia; il +  il gioco si allunga ogni volta che il giocatore la riproduce 
-  punteggio massimo viene salvto su EEPROM (si può cancellare l'high- +  il gioco si interrompe quando si commette un errore 
-  score premendo il pulsante del LED rosso durante lo start) +  il punteggio massimo viene salvto su EEPROM (per cancellare l'high- 
 +  score tenere premuto il pulsante del LED rosso durante lo start)  
 +  il watchdog timer viene usato per il debouncing, lo sleep mode e all' 
 +  avvio per il random generator 
 +  il timer viene usato per generare il segnale PWM per il buzzer
    
   PREREQUISITI   PREREQUISITI
Linea 311: Linea 316:
    
   CONFIGURAZIONE   CONFIGURAZIONE
-  Quando si carica il programma il MCU va anche configurato (usando +  Il MCU va configurato per andare a 1.2MHz (usando i "fuses" per 
-  i "fuses"per andare a una frequenza di 1.2MHz (il clock interno +  scegliere una delle due frequenze e il valore del prescaler) o 
-  ha due possibili frequenze di funzionamento un prescaler per +  l'esecuzione non sarà corretta come tempi
-  ridurre la frequenza). Settando una frequenza diversa l'esecuzione +
-  non sarà corretta come tempi+
    
   REGISTRI PIU' IMPORTANTI UTILIZZATI   REGISTRI PIU' IMPORTANTI UTILIZZATI
Linea 328: Linea 331:
    
   INGRESSI E USCITE   INGRESSI E USCITE
-  DDRB imposta come uscite i bit a 1 (pagina 50). I pin sono usati  +  DDRB imposta come uscite i bit a 1 (pagina 50). I pin sono sempre  
-  come ingressi tranne quando viene chiamata play().+  usati come ingressi tranne quando viene chiamata play()
   Il pin 5 (PB5) viene usato pulsante di start (RESET attivo basso)   Il pin 5 (PB5) viene usato pulsante di start (RESET attivo basso)
   e subito dopo come ingresso analogico (ADC0) scollegato per generare   e subito dopo come ingresso analogico (ADC0) scollegato per generare
-  il seed del random generator (una volta sola all'avvio).+  il seed del random generator (una volta sola all'avvio)
   Il pin 6 (PB1/OC0B) è usato per pilotare il buzzer con un'onda    Il pin 6 (PB1/OC0B) è usato per pilotare il buzzer con un'onda 
-  quadra generata col timer/counter in modalità waveform generator. +  quadra generata col timer/counter in modalità waveform generator 
 + 
   Per la gestione del timer/counter si usano i registri:   Per la gestione del timer/counter si usano i registri:
   - TCNT0 che contiene il valore del conteggio   - TCNT0 che contiene il valore del conteggio
Linea 342: Linea 345:
   frequenza, e quello in corrispondenza del quale c'è la commutazione   frequenza, e quello in corrispondenza del quale c'è la commutazione
   tra livello alto e basso. Il waveform generator usa il risultato    tra livello alto e basso. Il waveform generator usa il risultato 
-  della comparazione per produrre un segnale PWM nel pin OC0B del buzzer. +  della comparazione per produrre un segnale PWM nel pin OC0B del buzzer 
-   +  
-  Il timer/clock, che si ferma se non si seleziona una sorgente di clock, +  Il timer/clock si ferma se non si seleziona una sorgente di clock; 
-  ha più modi di funzionamento che si impostano con WGM0[2:0] e COM0x[1:0]: +  ha più modi di funzionamento che dipendono da WGM0[2:0] e COM0x[1:0]: 
-  - normal: conta in su fino a 0xFF poi produce un interrupt e ricomincia+  - normal: conta in su fino a 0xFF poi genera un interrupt e ricomincia
   - CTC: conta fino a OCR0A   - CTC: conta fino a OCR0A
   - fast PWM: va basso sul match con OCR0A e alto su 0xFF (fig. 11-6)   - fast PWM: va basso sul match con OCR0A e alto su 0xFF (fig. 11-6)
   - phase correct PWM: conta in su e in giù   - phase correct PWM: conta in su e in giù
-  Nel programma si usa la modalità phase correct PWM per il buzzer.+  Nel programma si usa la modalità phase correct PWM per il buzzer
 */ */
    
Linea 356: Linea 359:
 // LIBRERIE UTILIZZATE (da https://www.nongnu.org/avr-libc/ ) // LIBRERIE UTILIZZATE (da https://www.nongnu.org/avr-libc/ )
    
-// sleep mode per ridurre il consumo. Al termine di ogni partita, se  +// sleep mode 
-// scade il watchdog timer il MCU va in POWER-DOWN per ridurre al minimo +// Al termine di ogni partita, se scade il watchdog timer il MCU va in 
-// il consumo; si risveglia col un reset+// POWER-DOWN per ridurre il consumo; si risveglia col un reset
 #include <avr/sleep.h> #include <avr/sleep.h>
    
 +// delay 
 // funzione simile a delay() di Arduino (cicli di CPU buttati). Va va // funzione simile a delay() di Arduino (cicli di CPU buttati). Va va
 // bene per piccole temporizzazioni, altrimenti meglio usare il timer. // bene per piccole temporizzazioni, altrimenti meglio usare il timer.
Linea 369: Linea 373:
 #include <util/delay_basic.h> #include <util/delay_basic.h>
    
 +// eeprom
 // per salvare l'high-score nella EEPROM // per salvare l'high-score nella EEPROM
 #include <avr/eeprom.h> #include <avr/eeprom.h>
Linea 377: Linea 382:
 // https://www.nongnu.org/avr-libc/user-manual/FAQ.html#faq_varinit // https://www.nongnu.org/avr-libc/user-manual/FAQ.html#faq_varinit
    
-// i quattro elementi dell'array, tramite il registro PORTB, impostano +// nella fase di gioco in cui viene mostrata la sequenza con la funzione 
-// come uscite PB1 (il buzzer) e uno tra PB3, PB2, PB0 e PB4 per accendere +// play() i quattro elementi dell'array, applicati al registro PORTB, 
-// rispettivamente i LED 1, 4, 3 e 2 nella fase di gioco in cui viene +// impostano come uscite PB1 (il buzzer) e uno tra PB3, PB2, PB0 e PB4 
-// mostrata la sequenza con la funzione play()+// (i LED 1, 4, 3 e 2)
 const uint8_t buttons[4] = { const uint8_t buttons[4] = {
   0b00001010, 0b00000110, 0b00000011, 0b00010010   0b00001010, 0b00000110, 0b00000011, 0b00010010
Linea 392: Linea 397:
 }; };
    
-uint8_t lastKey; // ultimo tasto premuto per il debouncing dei pulsanti+uint8_t lastKey; // ultimo tasto premuto (per il debouncing pulsanti)
 uint8_t lvl = 0; // livello (parte da 0 -> sequenza con un solo LED) uint8_t lvl = 0; // livello (parte da 0 -> sequenza con un solo LED)
-uint8_t maxLvl;  // livello massimo+uint8_t maxLvl;  // livello massimo (high-score salvato su EEPROM)
    
-// variabili per pseudo-random generator LFSR+// variabili per pseudo-random generator
 uint16_t seed; // generato con l'ADC su un pin scollegato (e mischiato) uint16_t seed; // generato con l'ADC su un pin scollegato (e mischiato)
 uint16_t ctx; // valori successivi generati a partire dal seed uint16_t ctx; // valori successivi generati a partire dal seed
Linea 410: Linea 415:
    
 void sleepNow() { void sleepNow() {
-  // power-down riduce al massimo il consumo; il risveglio avviene col  +  // power-down riduce al massimo il consumo 
-  // pulsant start/reset+  // il risveglio avviene col pulsant start/reset
   // di default tutti i pin sono ingressi; in power-down gli ingressi   // di default tutti i pin sono ingressi; in power-down gli ingressi
-  // flottanti è meglio che siano scollegati (pag. 53) +  // flottanti è meglio che siano scollegati cioè tri-state (pag. 53) 
-  PORTB = 0b00000000; // tri-state (disabilita la resitenza di pullup)+  PORTB = 0b00000000; // tri-state (disabilita la resistenza di pullup)
   cli(); // disabilita gli interrupt   cli(); // disabilita gli interrupt
   WDTCR = 0; // spegne il Watchdog timer   WDTCR = 0; // spegne il Watchdog timer
Linea 424: Linea 429:
 void play(uint8_t i, uint16_t t = 45000) { void play(uint8_t i, uint16_t t = 45000) {
   // accende un LED e suona la nota corrisponente col buzzer   // accende un LED e suona la nota corrisponente col buzzer
-  // i è l'indice del LED da 0 a 3t è usanto nella funzione delay +  // i è l'indice del LED da 0 a 3 
-  // per ritardare di (4/1.2M)*t sec (45000 -> il delay è di 150ms)+  // t è usato nella funzione delay per ritardare di (4/1.2M)*t sec  
 +  // il valore di default (45000corrisponde a 150ms
    
-  // con i pin impostati come ingressi modifico PORTB sapendo che: +  // quando non viene eseguita la funzione play() i pin sono impostati 
-  // 0 -> se è un input disabilita la resistenza di pull-up +  // come ingressi con resistenza di pull-up interna 
-  // 0 -> se è un output imposta il livello basso di tensione +  // prima di passare da ingresso a uscita bisogna impostarli come  
-  // questa operazione serve nel passaggio da ingresso con pull-up a +  //tri-state (pagina 51) quindi si modifica PORTB sapendo che: 
-  // uscita ed è indicata a pagina 51+  // 0 -> come input disabilita la resistenza di pull-up (tri-state) 
 +  // 0 -> come output imposta il livello basso di tensione
   PORTB = 0b00000000;   PORTB = 0b00000000;
    
Linea 439: Linea 446:
   DDRB = buttons[i];     DDRB = buttons[i];  
    
 +  // a pagina 67 un diagramma temporale del funzionamento phase-correct
   // assegno a OCR0A il valore massimo del conteggio del timer/counter   // assegno a OCR0A il valore massimo del conteggio del timer/counter
-  // in modo da modificare la frequenzada pag. 68 si capisce che la  +  // in modo da modificare la frequenza  
-  // frequenza minima si otterrebbe senza usare OCR0A (quindi contando +  // da pag. 68 si capisce che la frequenza minima si otterrebbe senza 
-  // sempre fino a 0xFF - 255f = 1.2M/(255+255)= 1200000/510 = 2.3kHz+  // usare OCR0A (quindi contando sempre fino a 0xFF - 255 
 +  // f = 1.2M/(255+255)= 1200000/510 = 2.3kHz
   // con i valori in tones si ottiene ad es. f=1.2M/(239+239)=2.5kHz   // con i valori in tones si ottiene ad es. f=1.2M/(239+239)=2.5kHz
   // gli altri valori sono 3.3, 4.2 e 5 kHz (re# sol# do re#)   // gli altri valori sono 3.3, 4.2 e 5 kHz (re# sol# do re#)
Linea 451: Linea 460:
   // TCCR0A/B sono impostati nel main prima di chiamare play() in modo   // TCCR0A/B sono impostati nel main prima di chiamare play() in modo
   // che il waveform generator funzioni in modalità PWM phase correct   // che il waveform generator funzioni in modalità PWM phase correct
-  // WGM02 imposta il conteggio fino a OCR0ACS01 il prescaler a 8+  // WGM02 imposta il conteggio fino a OCR0A (pag. 73) 
 +  // CS01 imposta il prescaler a 8 (pag. 74)
   TCCR0B = (1 << WGM02) | (1 << CS01);   TCCR0B = (1 << WGM02) | (1 << CS01);
    
Linea 462: Linea 472:
   // spegne il LED e disabilita il buzzer (tutti i pin come ingressi)   // spegne il LED e disabilita il buzzer (tutti i pin come ingressi)
   DDRB = 0b00000000;   DDRB = 0b00000000;
-  // abilita le resistenze di pul-up per i pulsanti+  // abilita le resistenze di pull-up per i pulsanti
   PORTB = 0b00011101;   PORTB = 0b00011101;
 } }
Linea 490: Linea 500:
    
 uint8_t simple_random4() { uint8_t simple_random4() {
-  // linear-feedback shift register (Galois)+  // LFSR linear-feedback shift register (Galois)
   // per una spiegazione di come funziona vedi il progetto originale   // per una spiegazione di come funziona vedi il progetto originale
   // o la pagina wikipedia (e l'AN della Maxim linkata):   // o la pagina wikipedia (e l'AN della Maxim linkata):
   // it.wikipedia.org/wiki/Registro_a_scorrimento_a_retroazione_lineare   // it.wikipedia.org/wiki/Registro_a_scorrimento_a_retroazione_lineare
-  // modifica ctx e restituisce un indice tra 0 e 3 per i LED+  // modifica ctx e restituisce un indice tra 0 e 3 corrispondente a  
 +  // uno dei quattro LED
   // la sequenza pseudo-casuale di valori di ctx si ripete sempre    // la sequenza pseudo-casuale di valori di ctx si ripete sempre 
-  // uguale se non cambia il seed -> riportando ctx al valore del seed +  // allo stesso modo se non cambia il seedriportando ctx al valore 
-  // si può ripetere la sequenza e confrontarla con la pressione dei  +  // del seed si può ripercorrere la sequenza e confrontarla con la 
-  // pulsanti +  // pressione dei pulsanti per capire se il giocatore ha sbagliato o no 
 + 
   // servono due bit per un nuovo indice da 0 a 3 (00 -> 11)   // servono due bit per un nuovo indice da 0 a 3 (00 -> 11)
   for (uint8_t i = 0; i < 2; i++) {   for (uint8_t i = 0; i < 2; i++) {
Linea 506: Linea 517:
     if (lsb || !ctx) { // se LSB (uscita) è 1 o se ctx contiene tutti 0     if (lsb || !ctx) { // se LSB (uscita) è 1 o se ctx contiene tutti 0
                        // (con tutti zeri la sequenza non cambia mai)                        // (con tutti zeri la sequenza non cambia mai)
-      ctx ^= 0xB400; // inverte i bit secondo la maschera (XOR con 1)+      ctx ^= 0xB400;   // inverte i bit secondo la maschera (XOR con 1) 
 +                       // 0xB400 -> 1011010000000000 quindi XOR con i  
 +                       // bit 16, 14, 13 e 11, vedi su wikipedia en 
 +                       // Linear-feedback_shift_register#Galois_LFSRs
     }     }
   }   }
Linea 514: Linea 528:
 } }
    
-ISR(WDT_vect) { // Watchdog Timeout Interrupt da avr-libc +ISR(WDT_vect) {  
-  // eseguita ogni volta che scade il timer (16ms) +  // Watchdog Timeout Interrupt Server Routine da avr-libc 
-  // ogni 16ms viene incrementato il valore della variabile usata per  +  // eseguita ogni volta che scade il timer 
-  // gestire il poweroff dopo 64s di inattività e il debouncing+  // ogni 16ms viene incrementato il valore della variabile time usata 
 +  // per gestire il poweroff (64s di inattivitàe il debouncing (16ms)
   time++; // increase each 16 ms   time++; // increase each 16 ms
-  // dopo ogni reset viene mischiato il seed per 8 volteil seed non +  // il watch timer viene usato anche all'avvio per mischiare 8 volte il 
-  // cabia più fino al reset successivo+  // seed con l'ADC; il seed non cambia più fino al reset successivo
   if (nrot) {   if (nrot) {
     nrot--;     nrot--;
-    // mischia il seed facendo uno shift a sinistra e XOR con valore +    // mischia il seed facendo uno shift a sinistra e XOR con il valore 
-    // del timer/counter (8bit senza prescaler a 1.2MHz)+    // del timer/counter che nella fase iniziale è funziona da contatore 
 +    // a 8bit senza prescaler, quindi a 1.2MHz
     seed = (seed << 1) ^ TCNT0;     seed = (seed << 1) ^ TCNT0;
   }   }
Linea 535: Linea 551:
    
 int main(void) { int main(void) {
-  // pull-up sui 4 pulsanti dei LED (tutti ingressi di default)+  // pull-up sui 4 pulsanti dei LED (sono tutti ingressi di default)
   PORTB = 0b00011101;   PORTB = 0b00011101;
    
   // GENERAZIONE DEL SEED   // GENERAZIONE DEL SEED
-  // ADC+  
   // Il pin PB5/ADC0 (start/reset) viene usato per generare il seed    // Il pin PB5/ADC0 (start/reset) viene usato per generare il seed 
-  // attivando l'ADC quando è scollegato per ottenere un valore casuale +  // attivando l'ADC sul pin scollegato per ottenere un valore casuale 
-  // il valore viene poi mischiato otto volte nella ISR usando il timer+  // il valore viene poi mischiato per otto volte nella ISR richiamata 
 +  // allo scadere del watchdog timer 
 +   
 +  // ADC 
 +  
   ADCSRA |= (1 << ADEN); // abilita l'ADC (pagina 82 e 92)   ADCSRA |= (1 << ADEN); // abilita l'ADC (pagina 82 e 92)
   ADCSRA |= (1 << ADSC); // parte la conversione sul pin ADC0 scollegato   ADCSRA |= (1 << ADSC); // parte la conversione sul pin ADC0 scollegato
Linea 553: Linea 573:
   seed = ADCL;   seed = ADCL;
   ADCSRA = 0b00000000; // spegne l'ADC   ADCSRA = 0b00000000; // spegne l'ADC
 +  
   // WATCHDOG TIMER   // WATCHDOG TIMER
 +  
   // abilita l'interrupt del watchdog timer (interrupt mode pag 43)   // abilita l'interrupt del watchdog timer (interrupt mode pag 43)
-  // il WDT usa un oscillatore separato a 128kHz (il timer va col clock)+  // il WDT usa un oscillatore separato che va a 128kHz (il timer invece 
 +  // va col clock)
   // senza prescaling c'è un timeout ogni 16ms (2048 cicli, pag 43) e   // senza prescaling c'è un timeout ogni 16ms (2048 cicli, pag 43) e
   // viene eseguita la ISR   // viene eseguita la ISR
   WDTCR = (1 << WDTIE); // parte il watchdog timer con prescaler da 16ms   WDTCR = (1 << WDTIE); // parte il watchdog timer con prescaler da 16ms
   sei(); // global interrupt enable (mette a 1 il bit I nello SREG)   sei(); // global interrupt enable (mette a 1 il bit I nello SREG)
 +  
   // TIMER/COUNTER   // TIMER/COUNTER
 +  
   // imposta il timer/counter in normal mode (WGM[2:0] a zero) e senza    // imposta il timer/counter in normal mode (WGM[2:0] a zero) e senza 
-  // prescaler (CS00 a uno): conta fino a 0xFF poi ricomincia e segnala +  // prescaler (CS00 a uno): conta fino a 0xFFsegnala con TOV0 e  
-  // con TOV0 (pag. 64)+  // ricomincia il conteggio (pag. 64)
   // il timer comincia a contare quando si imposta una sorgente per il    // il timer comincia a contare quando si imposta una sorgente per il 
   // clock (pag. 60)   // clock (pag. 60)
Linea 573: Linea 598:
   // IMPOSTAZIONE TIMER/COUNTER per generare il segnale PWM del buzzer   // IMPOSTAZIONE TIMER/COUNTER per generare il segnale PWM del buzzer
    
-  // cambia la modalità di funzionamento del timer che passa da normal  +  // la modalità di funzionamento del timer cambia da normal mode a PWM 
-  // a PWM phase correct (WGM0[2:0]=001) dove conta in su e in giù fino +  // phase correct (WGM0[2:0]=001) dove conta in su e in giù fino 
-  // a 0xFF (nella funzione play() conterà fino al valore contenuto nel +  // a 0xFF  
-  // registro OCR0A per modificare la frequenza e produrre più note))+  // nella funzione play() invece, per cambiare la frequenza e produrre 
 +  // note diverse, conterà fino al valore contenuto nel registro OCR0A 
   // Si imposta il compare output mode del waveform generator in modo    // Si imposta il compare output mode del waveform generator in modo 
   // che il pin del buzzer PB1/OC0B (COM0B[1:0]=10) vada basso sul   // che il pin del buzzer PB1/OC0B (COM0B[1:0]=10) vada basso sul
   // match col valore del registro OCR0B mentre conta in su e alto    // match col valore del registro OCR0B mentre conta in su e alto 
   // mentre conta in giù (OCR0B è impostato nella funzione play() come   // mentre conta in giù (OCR0B è impostato nella funzione play() come
-  // OCR0A) generando un onda quadra con la frequenza desiderata+  // OCR0A / 2 
 +  // in questo modo si genera un onda quadra con la frequenza desiderata
   // NB il segnale PWM è presente solo se il pin è impostato come uscita   // NB il segnale PWM è presente solo se il pin è impostato come uscita
   // (pag 68) quindi il buzzer non suona finche non si chiama play()   // (pag 68) quindi il buzzer non suona finche non si chiama play()
   TCCR0A = (1 << COM0B1) | (0 << COM0B0) | (0 << WGM01)  | (1 << WGM00);    TCCR0A = (1 << COM0B1) | (0 << COM0B0) | (0 << WGM01)  | (1 << WGM00); 
    
-  // LETTURA O RESET DELL'HIGH SCORE DA EEPROM PREMENDO START+ROSSO +  // LETTURA DELL'HIGH SCORE DA EEPROM  
-  +   
-  // maxLvl viene scritto e letto negato (con l'operatore ~) perché il  +   // maxLvl viene complementato (con l'operatore ~) quando viene scritto 
-  // valore di default della EEPROM è sempre 0xFF (255 e non zero)+  // o letto perché il valore di default su EEPROM è 0xFF (255 e non 0 
 +  // e con la EEPROM "vergine" il record sarebbe il livello 255
   // (uint8_t*) 0 è un puntatore a un byte che parte dall'indirizzo 0   // (uint8_t*) 0 è un puntatore a un byte che parte dall'indirizzo 0
   maxLvl = ~eeprom_read_byte((uint8_t*) 0);    maxLvl = ~eeprom_read_byte((uint8_t*) 0); 
    
 +  // EVENTUALE RESET DELL'HIGH-SCORE PREMENDO START+ROSSO
 +  
   // legge lo stato dei pin della port B e lo confronta con la maschera   // legge lo stato dei pin della port B e lo confronta con la maschera
   switch (PINB & 0b00011101) {   switch (PINB & 0b00011101) {
-    // AND tra gli ingressi e la maschera sopra0 significa premuto +    // NB lo switch non è necessario; nel codice originale permetteva di  
-    // PB1 è il buzzer e PB5 non conta (è un reset attivo basso ma in  +    // attivare altre funzioni tenedo premuti altri pulsanti all'avvio 
-    // questo punto del programma sarà già alto); i pin dei pulsanti  +    // per ridurre le dimensioni dell'eseguibile le altre combinazioni 
-    // non premuti sono al livello alto (pull-up) quindi controlliamo  +    // sono state eliminate 
-    // se PB3 (LED rosso) è premuto e nel caso resettiamo l'high score+    // AND tra gli ingressi e la maschera sopra dove 0 significa premuto 
 +    // PB1 e PB5 non contano: uno è il buzzer e l'altro un reset attivo 
 +    // basso (che a questo punto del programma sarà già alto); i pin dei 
 +    // pulsanti non premuti sono al livello alto (pull-up)  
 +    // all'avvio controlliamo  se PB3 (LED rosso) è premuto 
     case 0b00010101: // PB3 premuto dopo il reset -> azzera high-score     case 0b00010101: // PB3 premuto dopo il reset -> azzera high-score
       eeprom_write_byte((uint8_t*) 0, 255); // scrive 255 -> livello 0       eeprom_write_byte((uint8_t*) 0, 255); // scrive 255 -> livello 0
Linea 608: Linea 642:
   while (1) {   while (1) {
     // MOSTRA LA SEQUENZA     // MOSTRA LA SEQUENZA
 +    
     // reimposta ctx al valore del seed; la sequenza di valori di ctx      // reimposta ctx al valore del seed; la sequenza di valori di ctx 
     // sarà sempre la stessa sequenza finché non si resetta     // sarà sempre la stessa sequenza finché non si resetta
Linea 613: Linea 648:
     // accende in sequenza un numero di LED pari al livello più uno     // accende in sequenza un numero di LED pari al livello più uno
     for (uint8_t cnt = 0; cnt <= lvl; cnt++) {      for (uint8_t cnt = 0; cnt <= lvl; cnt++) { 
-      // attesa tra un LED e il successivovalore massimo 65536 (2^16) +      // attesa tra un LED e il successivo 
-      // -> 218ms poi scende se aumenta lvl+      // il valore iniziale è quello massimo (2^16 -> 65536 -> 218ms
 +      // poi diminuisce all'aumentare del livello 
       _delay_loop_2(4400 + 489088 / (8 + lvl));       _delay_loop_2(4400 + 489088 / (8 + lvl));
-      // accende il LED con indice da 0 a 3 restituito da simple_random4() +      // accende il LED con l'indice restituito da simple_random4(), un 
-      // generato come resto della divisione per 4 di ctx, il cui valore +      // numero tra 0 e 3 che è il resto della divisione per 4 di ctx 
-      // viene aggiornato ad ogni chiamata+      // il valore di ctx viene aggiornato ad ogni chiamata
       play(simple_random4());       play(simple_random4());
     }     }
Linea 624: Linea 660:
     // INSERIMENTO SEQUENZA DA PARTE DEL GIOCATORE     // INSERIMENTO SEQUENZA DA PARTE DEL GIOCATORE
    
-    // azzera il conteggio che porta al poweroff+    // azzera il conteggio che porta al power-off
     time = 0;     time = 0;
-    // imposta lastKey a un valore che non corrisponde a nessun pulsante+    // per il debouncing imposta lastKey a un valore che non corrisponde 
 +    // a nessun pulsante (0-3)
     lastKey = 5;     lastKey = 5;
     // riporta ctx al valore iniziale uguale al seed     // riporta ctx al valore iniziale uguale al seed
Linea 632: Linea 669:
     // tante volte quanti sono i LED da indovinare     // tante volte quanti sono i LED da indovinare
     for (uint8_t cnt = 0; cnt <= lvl; cnt++) {     for (uint8_t cnt = 0; cnt <= lvl; cnt++) {
 +      // azzero pressed
       bool pressed = false;       bool pressed = false;
       // finché non si preme un bottone       // finché non si preme un bottone
Linea 638: Linea 676:
         for (uint8_t i = 0; i < 4; i++) {         for (uint8_t i = 0; i < 4; i++) {
           // controlla se il pulsante i è premuto           // controlla se il pulsante i è premuto
-          // buttons & maschera -> bit a 1 solo per il pin/pulsante i+          // buttons & maschera -> bit a 1 solo per il pin/pulsante "i"
           // PINB ha tutti i bit a 1 (resistenze di pull-up attivate           // PINB ha tutti i bit a 1 (resistenze di pull-up attivate
           // nella funzione play) tranne quello del pulsante premuto           // nella funzione play) tranne quello del pulsante premuto
Linea 645: Linea 683:
           if (!(PINB & buttons[i] & 0b00011101)) {           if (!(PINB & buttons[i] & 0b00011101)) {
             // DEBOUNCE             // DEBOUNCE
-            // se sono passati 16ms (tempo max per eventuali rimbalzi o+            // se sono passati 16ms (tempo max per eventuali rimbalzio
             // se è stato premuto un pulsante diverso (non è rimbalzo)             // se è stato premuto un pulsante diverso (non è rimbalzo)
             if (time > 1 || i != lastKey) {             if (time > 1 || i != lastKey) {
Linea 674: Linea 712:
           }           }
         }         }
-        // se passano 64s (time = 4000) e non succede niente poweroff+        // se passano 64s (time = 4000) e non viene premuto nessun  
 +        // pulsante si attiva il power-off
         if (time > 4000) {         if (time > 4000) {
           sleepNow();           sleepNow();
Linea 689: Linea 728:
   }   }
 } }
 +
  
 </code> </code>
simon.txt · Ultima modifica: 2023/10/27 18:02 da admin