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
simon [2020/10/02 13:57] – [Risorse] adminsimon [2023/10/27 18:02] (versione attuale) – [Software] admin
Linea 18: Linea 18:
   * cinque bottoni (uno per avviare il gioco)   * cinque bottoni (uno per avviare il gioco)
   * un microcontrollore che esegue il software che gestisce il gioco   * un microcontrollore che esegue il software che gestisce il gioco
 +
 +Un video che descrive il progetto:
 +
 +{{vimeo>487444206}}
 ===== Specifiche hardware e scelta componenti ===== ===== Specifiche hardware e scelta componenti =====
  
Linea 68: Linea 72:
 Coi pulsanti - che a tutti gli effetti sono dei contatti normalmente aperti - si può generare un segnale alto o basso utilizzando i 3 Volt di alimentazione e una resistenza di [[wpi>Resistenza_pull-up|resistenza di pull-up]]. Queste resistenze sono già disponibili negli ingressi dell'ATtiny13 e devono solo essere attivate via software. Il problema del [[https://leonardocanducci.org/wiki/ee3/sezione_5a#logica_antirimbalzi|anti-rimbalzo]], sempre presente ogni volta che ci sono parti mobili in un contatto, può essere gestito via software per risparmiare componenti. Coi pulsanti - che a tutti gli effetti sono dei contatti normalmente aperti - si può generare un segnale alto o basso utilizzando i 3 Volt di alimentazione e una resistenza di [[wpi>Resistenza_pull-up|resistenza di pull-up]]. Queste resistenze sono già disponibili negli ingressi dell'ATtiny13 e devono solo essere attivate via software. Il problema del [[https://leonardocanducci.org/wiki/ee3/sezione_5a#logica_antirimbalzi|anti-rimbalzo]], sempre presente ogni volta che ci sono parti mobili in un contatto, può essere gestito via software per risparmiare componenti.
  
-I LED si collegano ai pin dei pulsanti corrispondenti. Quando i pin, usati come uscite, saranno al livello basso permetteranno alla corrente di scorrere dall'alimentazione a massa accendendo il LED. Naturalmente serve un resistore per limitare la corrente nel LED; il suo dimensionamento si fa considerando una Vf di 2 Volt uguale per tutti i LED e una corrente di mA((la Vf dei quattro LED è diversa (dipende dal colore e dal materiale con cui è realizzato il LED) ma così scegliamo quattro resistori uguali e minimizziamo gli errori in fase di montaggio; la corrente è più bassa dei 20 mA standard per ridurre il consumo)):+I LED si collegano ai pin dei pulsanti corrispondenti. Quando i pin, usati come uscite, saranno al livello basso permetteranno alla corrente di scorrere dall'alimentazione a massa accendendo il LED. Naturalmente serve un resistore per limitare la corrente nel LED; il suo dimensionamento si fa considerando una Vf di 2 Volt uguale per tutti i LED e una corrente di mA((la Vf dei quattro LED è diversa (dipende dal colore e dal materiale con cui è realizzato il LED) ma così scegliamo quattro resistori uguali e minimizziamo gli errori in fase di montaggio; la corrente è più bassa dei 20 mA standard per ridurre il consumo)):
  
 `R = (V_(\C\C)-V_F)/(I_d) = (3 - 2)/0.002 = 500 \Omega` `R = (V_(\C\C)-V_F)/(I_d) = (3 - 2)/0.002 = 500 \Omega`
Linea 85: Linea 89:
   * il circuito non è simulabile (non si simula un microcontrollore!)   * il circuito non è simulabile (non si simula un microcontrollore!)
   * il componente ATtiny13A non è disponibile in Multisim e va creato   * il componente ATtiny13A non è disponibile in Multisim e va creato
-  * tutti i componenti neri non hanno un footprint e non vengono considerati quandi si passa Ultiboard per progettare il PCB; bisogna assegnargli un footprint o sostituirli con componenti blu o verdi+  * tutti i componenti neri non hanno un footprint e non vengono considerati quando si passa Ultiboard per progettare il PCB; bisogna assegnargli un footprint o sostituirli con componenti blu o verdi
   * il colore dei LED non è importante perché in fase di montaggio si possono montare in qualunque ordine (i resistori sono tutti uguali)   * il colore dei LED non è importante perché in fase di montaggio si possono montare in qualunque ordine (i resistori sono tutti uguali)
  
Linea 93: Linea 97:
   * __assegnare i footprint corretti__ agli altri componenti, se possibile (LED e buzzer non lo consentono e bisogna farlo in Ultiboard)   * __assegnare i footprint corretti__ agli altri componenti, se possibile (LED e buzzer non lo consentono e bisogna farlo in Ultiboard)
  
-**Prima di creare componenti conviene [[simon#creare_un_footprint|creare i footprint]]** in Ultiboard usando le informazioni contenute nei datasheet. L'abbinamento componenti-footprint è questo+Per risparmiare tempo è possibile utilizzare due file per Multisim e Ultiboard disponibili tra le risorse a fondo pagina e importare simboli e footprint: 
-  * resistori: ''RES10'' +  * in Mutisim cliccando col tasto destro e scegliendo ''Save component to database'', poi nel Group '' Misc'' aggiungendo la Family ''Simon'' e cliccando su Ok; il componente sarà disponibile nel database ''User'' invece che in quello predefinito ''Master'' 
-  * LED: ''LED5R2_5V'', da cambiare in Ultiboard +  * in Ultiboard selezionando il componente e scegliendo ''Add selection to database'' dal menu Tools|Database, poi cliccando su Ok
-  * ATtiny13A: ''PDIP-8(P)'', da indicare quando si crea il componente +
-  * pulsanti: footprint custom ''TACT-SPST'' da creare in Ultiboard +
-  * portabatteria: footprint custom <del>''DS1092-05''</del>''DS1092-06'' da creare in Ultiboard +
-  * buzzer: footprint custom ''LD-BZPN-1307'' da creare in Ultiboard+
  
 +In alternativa si procede come descritto nel paragrafo seguente. 
  
-Fatte queste considerazioni creati i componenti ATtiny13A, portabatteria e buzzer si ottiene il circuito finale:+Dopo aver creato footprint (portabatteria, buzzer pulsanti) e simboli dei componenti (portabatteria, microcontrollore pulsanti) e dopo aver abbinato a tutti i componenti un footprint (che per resistori, buzzer e LED andrà cambiato in Ultiboard) si ottiene il circuito finale:
  
-{{:simon_4b.png|}}+{{::schematico_simon_2021.png|schematico simon}}
  
 +==== Creare un componente in Multisim ====
  
 +**NB non è necessario se si importano i simboli del file Multisim disponibile tra le risorse**
 +
 +**Prima di creare i componenti conviene [[simon#creare_un_footprint|creare i footprint]]** in Ultiboard usando le informazioni contenute nei datasheet. L'abbinamento componenti-footprint è questo:
 +  * buzzer: footprint custom ''LD-BZPN-1307'' da creare in Ultiboard 
 +  * ATtiny13A: ''PDIP-8'', da indicare quando si crea il componente
 +  * pulsanti: footprint custom ''TACT-65R-F'' da creare in Ultiboard
 +  * portabatteria: footprint custom ''DS1092-04'' da creare in Ultiboard
  
-==== Creare un componente in Multisim ==== 
  
 Si usa una procedura guidata: Si usa una procedura guidata:
Linea 133: Linea 141:
 Indicazioni per la creazione del pulsante TACT-65R-F: Indicazioni per la creazione del pulsante TACT-65R-F:
   * step 1: TACT-65R-F, NINIGI, Tactile Switch SPST-NO, layout only   * step 1: TACT-65R-F, NINIGI, Tactile Switch SPST-NO, layout only
-  * step 2: footprint custom TACT-SPST da creare in Ultiboard copiandolo da SKHH1_1 (in //Through Hole Technoly Parts|Buttons and Switches|Tact//) e aggiustando la piedinatura, single section, 4 pin+  * step 2: footprint custom TACT-SPST da creare in Ultiboard copiandolo da SKHH1 (in //Through Hole Technoly Parts|Buttons and Switches|Tact//) e aggiustando la piedinatura, single section, 4 pin
   * step 3: copiare da DPST-2NO-DB (//Electro mechanical|Supplementary switches//) e modificare aggiustando il nome dei pin del simbolo   * step 3: copiare da DPST-2NO-DB (//Electro mechanical|Supplementary switches//) e modificare aggiustando il nome dei pin del simbolo
   * step 4: nominare i pin come indicato nel datasheet   * step 4: nominare i pin come indicato nel datasheet
Linea 139: Linea 147:
   * step 6: creare la famiglia //SWITCH// nel gruppo //Basic// del database User e cliccare su //Finish//   * step 6: creare la famiglia //SWITCH// nel gruppo //Basic// del database User e cliccare su //Finish//
  
-Indicazioni per la creazione del portabatteria DS1092-05+Indicazioni per la creazione del portabatteria DS1092-04
-  * step 1: <del>DS1092-05</del> DS1092-06, Connfly, CR2032 battery holder, layout only +  * step 1: DS1092-04, Connfly, CR2032 battery holder, layout only 
-  * step 2: footprint custom <del>DS1092-05</del> DS1092-06 da creare in Ultiboard secondo usando le informazioni contenute nel datasheet+  * step 2: footprint custom DS1092-04 da creare in Ultiboard secondo usando le informazioni contenute nel datasheet
   * step 3: copiare da 1028 (in //Connectors|POWER//)   * step 3: copiare da 1028 (in //Connectors|POWER//)
   * step 4: accettare la piedinatura   * step 4: accettare la piedinatura
Linea 148: Linea 156:
  
 ===== Layout del PCB ===== ===== Layout del PCB =====
 +
 +In questa fase di procede alla definizione delle dimensioni della scheda, poi al layout (posizionamento) dei componenti e infine allo sbroglio, cioè al disegno delle piste in rame che collegano i componenti **che non devono mai toccarsi o incrociarsi**.
  
 Requisiti per la realizzazione nella sala acidi della scuola: Requisiti per la realizzazione nella sala acidi della scuola:
   * single layer   * single layer
   * piste da 1 mm   * piste da 1 mm
-  * testo specchiato col nome dello studente+  * clearance 1 mm (0,5mm dove non è possibile fare altrimenti) 
 +  * testo specchiato e in bold col nome dello studente
   * massimo 2 piste sotto l'integrato   * massimo 2 piste sotto l'integrato
  
 Altri requisiti: Altri requisiti:
   * dimensioni massime 6 x 5 cm    * dimensioni massime 6 x 5 cm 
-  * pulsanti facilmente raggiungibili+  * pulsanti facilmente raggiungibili (agli angolo o su un lato)
   * minimizzare ingombri   * minimizzare ingombri
  
 Indicazioni varie: Indicazioni varie:
   * imparare a usare i filtri di selezione!   * imparare a usare i filtri di selezione!
 +  * imparare a misurare le dimensioni usando le indicazioni delle coordinate in basso a destra; un click del mouse imposta il punto di partenza della misura poi dx, dy e L indicano lo spostamento orizzontale, verticale e la distanza da quel punto mentre si muove il puntatore del mouse)
   * ridimensionare il board outline prima di piazzare i componenti (selezionare il layer //Board outline// e attivare il filtro //Enable selecting other objects// per cambiare le dimensioni del rettangolo giallo che delimita il PCB)   * ridimensionare il board outline prima di piazzare i componenti (selezionare il layer //Board outline// e attivare il filtro //Enable selecting other objects// per cambiare le dimensioni del rettangolo giallo che delimita il PCB)
   * posizionare e ruotare i componenti per facilitare lo sbroglio   * posizionare e ruotare i componenti per facilitare lo sbroglio
-  * disabilitare l'opzione //Part Shoving// dal menu //Desing// per poter avvicinare tra loro i componenti  +  * disabilitare l'opzione //Part Shoving// dal menu //Design// per poter avvicinare tra loro i componenti  
-  * impostare l'ampiezza delle tracce dalla spreadsheet view (selezionarle tutte dalla scheda //Net//e cambiare il campo //width//+  * impostare l'ampiezza delle piste dalla spreadsheet view (selezionarle tutte dalla scheda //Net// e cambiare il campo //width//
-  * dove è possibile usare piazzole circolari con foro da 0,6mm e diametro 2,6mm  +  * dove è possibile usare piazzole circolari con foro da 0,6 mm e diametro 2,6 mm  
-  * per i componenti con i pin troppo vicini tra loro usare [[simon#creare_una_piazzola_custom|piazzole ovali custom]] o piazzole rettangolari+  * per i componenti con i pin troppo vicini tra loro usare piazzole ovali (o [[simon#creare_una_piazzola_custom|custom]])
   * imparare a creare footprint custom   * imparare a creare footprint custom
  
 Cominciamo così: Cominciamo così:
   * la prima volta che si passa da Multisim a Ultiboard si usa //Transfer|Transfer to Ultiboard//; viene generata una //netlist//, cioè un file che contiene le indicazioni su quali componenti piazzare nel PCB, quale footprint hanno i componenti e come sono collegati tra loro   * la prima volta che si passa da Multisim a Ultiboard si usa //Transfer|Transfer to Ultiboard//; viene generata una //netlist//, cioè un file che contiene le indicazioni su quali componenti piazzare nel PCB, quale footprint hanno i componenti e come sono collegati tra loro
-  * se dopo aver creato il file Ultiboard si fanno modifiche nello schematico in Multisim bisogna riportarle usando //Transfer|Forward Annotate to Ultiboard// invece che //Transfer|Transfer to Ultiboard//; in questo modo non si perde il lavoro fatto ma si prosegue il lavoro con una nuova //netlist// che tiene conto delle modifiche fatte +  * se dopo aver iniziato il progetto in Ultiboard si fanno delle modifiche nello schematico in Multisim bisogna riportarle usando //Transfer|Forward Annotate to Ultiboard// invece che //Transfer|Transfer to Ultiboard//; in questo modo non si perde il lavoro fatto ma si prosegue il lavoro con una aggiornata //netlist// che riporta le modifiche fatte 
-  * la prima cosa da fare è guardare il layout di ogni componente per capire se è sbagliato (nel dubbio misurare o guardare il footprint nel database usando il pulsante //Show Dimensions//); i footprint sbagliati si cambiano dalla //Spreadsheet View// cliccando sulla casella corrispondente nella colonna //Footprint// della scheda //Parts// e selezionandoli dal database; vanno sicuramente sistemati i footprint di LED e buzzer perché non è possibile scegliere quelli giusti in Multisim+  * la prima cosa da fare è osservare se il footprint dei vari componenti è corretto (nel dubbio misurare le dimensioni usando il mouse o selezionando //Show Dimensions// nella scheda Part delle proprietà del componente); i footprint sbagliati si cambiano dalla //Spreadsheet View// cliccando sulla casella corrispondente nella colonna //Footprint// della scheda //Parts// e selezionandoli dal database; vanno sicuramente sistemati i footprint di LED e buzzer perché non è possibile scegliere quelli giusti in Multisim 
 + 
 +Andranno cambiati i footprint di: 
 +  * resistori scegliendo ''RES10''  (da //Through Hole Technology|Resistors|Various//
 +  * LED: ''LED5R2_5V'', da cambiare in Ultiboard (da da //Through Hole Technology|LED Displays|LEDs//
 + 
 +Prima di procedere allo sbroglio è bene anche aggiustare se necessario le dimensioni delle piazzole: 
 +  * dove possibile foro da 0,6mm e diametro 2,6mm  
 +  * per microcontrollore e LED piazzole ovali, scegliendo //Rounded Rectangle// con foro da 0,6mm e Pad diameter 3mm, Length 1,8mm e Corner radius 0,9mm
  
 Dopo aver ridimensionato il PCB si dovrebbe ottenere qualcosa di simile: Dopo aver ridimensionato il PCB si dovrebbe ottenere qualcosa di simile:
Linea 181: Linea 201:
 Da qui si procede con lo sbroglio, piazzando i componenti e tracciando le piste. Qualche indicazione: Da qui si procede con lo sbroglio, piazzando i componenti e tracciando le piste. Qualche indicazione:
   * bisogna fare più tentativi, spostando i componenti e ridisegnando le piste, per trovare la soluzione migliore   * bisogna fare più tentativi, spostando i componenti e ridisegnando le piste, per trovare la soluzione migliore
-  * seguire le //Ratsnest// (linee gialle che indicano quali piedini vanno collegati tra loro) e tracciare le piste usando sempre il layer //Copper Bottom// (rosso) e la larghezza di 1 mm+  * seguire le //Ratsnest// (linee guida di colore giallo che indicano quali piedini vanno collegati tra loro) e tracciare le piste usando sempre il layer //Copper Bottom// (rosso) con larghezza di 1 mm
   * fare attenzione a non sovrapporre piste/piazzole che non si devono toccare   * fare attenzione a non sovrapporre piste/piazzole che non si devono toccare
   * verificare che la //clearance// (distanza minima da piste e piazzole) sia almeno di 0.5 mm (si può impostare in //Options|PCB Options// per segnalare automaticamente gli errori col DRC)   * verificare che la //clearance// (distanza minima da piste e piazzole) sia almeno di 0.5 mm (si può impostare in //Options|PCB Options// per segnalare automaticamente gli errori col DRC)
-  * verificare che il PCB abbia l'aspetto previsto aiutandosi con il render 3D (//View|3D Preview//)+  * verificare che il PCB abbia l'aspetto previsto aiutandosi con la vista 3D (//View|3D Preview//)
   * a sbroglio completato verificare che il progetto non contenga errori osservando il risultato nella scheda //Results// della //Spreadsheet View// degli strumenti:   * a sbroglio completato verificare che il progetto non contenga errori osservando il risultato nella scheda //Results// della //Spreadsheet View// degli strumenti:
     * //Desing|Connectivity Check// controlla che tutti i collegamenti previsti nello schematico siano stati realizzati nel PCB     * //Desing|Connectivity Check// controlla che tutti i collegamenti previsti nello schematico siano stati realizzati nel PCB
Linea 190: Linea 210:
  
 Un possibile sbroglio è mostrato in figura: Un possibile sbroglio è mostrato in figura:
 +
 +
 +
 +
  
 {{:sbroglio.png|sbroglio scheda simon}} {{:sbroglio.png|sbroglio scheda simon}}
  
-Il render 3D ha questo aspetto:+ 
 +Il render della vista 3D ha questo aspetto: 
 + 
 + 
 + 
  
 {{::vista_3d_top.png?400|render 3D}} {{::vista_3d_top.png?400|render 3D}}
 +
 +
 ==== Creare un footprint ==== ==== Creare un footprint ====
  
-Ultiboard organizza i footprint in più database; quello predefinito si chiama //Ultiboard Master// e contiene i footprint di migliaia di componenti. Quando un progetto include un componente il cui footprint che non è disponibile in questo database bisogna crearne uno custom e salvarlo nel database //User//. Si può:+**NB non è necessario se si importano i footprint del file Ultiboard disponibile tra le risorse** 
 + 
 +Ultiboard organizza i footprint in più database; quello predefinito si chiama //Ultiboard Master// e contiene i footprint di migliaia di componenti. Quando un progetto include un componente il cui footprint non è disponibile in questo database bisogna crearne uno custom e salvarlo nel database //User//. Si può:
   * creare il footprint da zero e salvarlo nel database //User//   * creare il footprint da zero e salvarlo nel database //User//
   * copiare un footprint dal database master per poi modificarlo e salvarlo nel database //User//   * copiare un footprint dal database master per poi modificarlo e salvarlo nel database //User//
-  * importare un footprint da un file Ultiboard dal //Database Manager//+  * importare un footprint da un file Ultiboard dal //Database Manager// ((per farlo aprire il file Ultiboard, selezionare il componente di cui si vuole importare il footprint poi dal menu Tools|Database selezionare "Add selection to Database" e salvarlo nello User Database eventualmente rinominandolo se ce n'è già un altro con lo stesso nome))
  
 Il footprint di buzzer e portabatteria va creato da zero, quello dei pulsanti si può fare modificandone uno di Ultiboard.  Il footprint di buzzer e portabatteria va creato da zero, quello dei pulsanti si può fare modificandone uno di Ultiboard. 
Linea 209: Linea 242:
   * nella vista ad albero a sinistra selezionare //User database// (in questa fase, volendo si può creare un gruppo/sottogruppo per catalogare i footprint con //Create New Group// o importare un footprint da un progetto esistente)   * nella vista ad albero a sinistra selezionare //User database// (in questa fase, volendo si può creare un gruppo/sottogruppo per catalogare i footprint con //Create New Group// o importare un footprint da un progetto esistente)
   * cliccare l'icona //Create new part// (tratteggiata) e selezionare //PCB part// per creare un footprint (//Custom Pad Shape// serve a creare una piazzola)   * cliccare l'icona //Create new part// (tratteggiata) e selezionare //PCB part// per creare un footprint (//Custom Pad Shape// serve a creare una piazzola)
-  * l'editor dei footprint mostrerà solo l'etichetta per //Value// e //RefDes// del componente((il punto interrogativo indica dove comparirà un numero progressivo o un valore)); questi elementi di testo possono essere spostati, resi invisibili o modificati (ad esempio J va bene per un connettore, U per un integrato, ecc.)+  * l'editor dei footprint mostrerà solo l'etichetta per //Value// e //RefDes// del componente((il punto interrogativo indica dove comparirà un numero progressivo o un valore)); questi elementi di testo possono essere spostati, resi invisibili o modificati (ad esempio J va bene per un connettore, U per un integrato, LS per il buzzer, S per i pulsanti, ecc.)
   * piazzare i pin con //Place|Pins// indicando posizione, distanza e disposizione (file/righe), tipo di piazzola   * piazzare i pin con //Place|Pins// indicando posizione, distanza e disposizione (file/righe), tipo di piazzola
-  * utilizzando il layer //Silkscreen Top// disegnare il layout (contorno) del componente usando gli strumenti del menu //Place|Graphics//+  * utilizzando il layer //Silkscreen Top// disegnare il layout (contorno) del componente usando gli strumenti del menu //Place|Graphics// (impostare stile e larghezza della linea)
   * dopo aver **controllato attentamente le dimensioni del layout((le misure si possono fare cliccando in un punto e osservando in basso a destra il valore delle coordinate e delle distanze dX dY e L)), la distanza tra i piedini e il posizionamento dei piedini nel layout del componente** salvare il footprint nel database User (eventualmente in un gruppo adatto) dandogli un nome significativo   * dopo aver **controllato attentamente le dimensioni del layout((le misure si possono fare cliccando in un punto e osservando in basso a destra il valore delle coordinate e delle distanze dX dY e L)), la distanza tra i piedini e il posizionamento dei piedini nel layout del componente** salvare il footprint nel database User (eventualmente in un gruppo adatto) dandogli un nome significativo
  
 ==== Creare una piazzola custom ==== ==== Creare una piazzola custom ====
  
-I LED e l'ATtiny13A hanno dei pin molto vicini tra loro (100mil = 2,54mm) e non è possibili utilizzare piazzole rotonde delle dimensioni proposte sopra (2,6mm) perché si toccherebbero tra loro. Bisogna usare piazzole rettangolari o - meglio ancora - ovali. Ultiboard permette di creare piazzole ovali in maniera molto semplice (selezionandole e scegliendo //round rectangle// come forma) ma purtroppo non vengono stampate (è un bug del programma) quindi, se si vogliono piazzole ovali, bisogna creare delle piazzole custom.+**NB non è necessario da Multism 14.2 o superiore** 
 + 
 +I LED e l'ATtiny13A hanno dei pin molto vicini tra loro (100mil = 2,54mm) e non è possibili utilizzare piazzole rotonde delle dimensioni proposte sopra (2,6mm) perché si toccherebbero tra loro. Bisogna usare piazzole rettangolari o - meglio ancora - ovali. Ultiboard permette di creare piazzole ovali in maniera molto semplice (selezionandole e scegliendo //round rectangle// come forma) ma purtroppo non vengono stampate (è un bug del programma **risolto da Multisim 14.2**) quindi, se si vogliono piazzole ovali, bisogna creare delle piazzole custom.
  
 Creare la piazzola custom: Creare la piazzola custom:
Linea 241: Linea 276:
 ===== Software ===== ===== Software =====
  
-Il programma che caricheremo nel microcontrollore non usa nessuna delle funzioni di Arduino ma opera direttamente sui registri dell'ATtiny13A. Questa soluzione permette di ridurre la dimensione del programma compilato e migliora nettamente le prestazioni ma il software sarà  più complicato da scrivere funzionerà solo su microcontrollori ATtiny13.+Il programma(({{ :simon-stripped.zip |qui una versione ridotta con meno commenti}})) che caricheremo nel microcontrollore non usa nessuna delle funzioni di Arduino ma opera direttamente sui registri dell'ATtiny13A. Questa soluzione migliora nettamente le prestazioni e permette di ridurre la dimensione del programma compilato (quello che caricheremo occupa praticamente tutta la memoria disponibile) ma complica la scrittura del programma lo rende incompatibile con altri tipi di microcontrollore.
  
-commenti spiegano come funziona il codice ma è necessario sapere: +Il programma non è spiegato nel dettaglio ma dai commenti si capisce come funziona.
-  * come funzionano gli [[wpi>Operazione_bit_a_bit|operatori bitwise]], il [[wp>Mask_(computing)|bit masking]], lo shift a destra (>>) e sinistra (<<) e le forme  +
-  * interpretare i 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)+
  
-Ad esempio nel codice è facile trovare istruzioni tipo questa:+Prerequisiti: 
 +  * 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) 
 +  * saper programmare in C 
 + 
 +Il codice non è banale! E' facile imbattersi in istruzioni come questa:
     while (ADCSRA & (1 << ADSC));     while (ADCSRA & (1 << ADSC));
 che si interpreta così: che si interpreta così:
-  * ADSC, definito in una macro, corrisponde al numero 6 (secondo bit più significativo)+  * ADSC è un bit del registro ADCSRA e corrisponde al numero 6, cioè il secondo bit più significativo((è definito in una macro, vedi [[https://github.com/vancegroup-mirrors/avr-libc/blob/master/avr-libc/include/avr/iotn13.h|qui]] ad esempio))
   * 1 << ADSC corrisponde a 01000000   * 1 << ADSC corrisponde a 01000000
-  * ADCSRA (ADC Control and Status Register A) è uno dei registro a 8 bit che gestisce il convertitore analogico-digitale (vedere il datasheet) +  * ADCSRA (ADC Control and Status Register A) è uno dei registro a 8 bit che gestisce il convertitore analogico-digitalequando la conversione analogico digitale termina il bit ADSC del registro ADCSRA passa a 0 
-  * quando la conversione analogico digitale termina il bit ADSC del registro ADCSRA passa a 0 +  * allora l'operatore & (AND bitwiserestituisce 00000000 e termina il ciclo while 
-  * allora l'operatore AND bitwise restituisce 00000000 e termina il ciclo while, che serviva ad attendere il completamento della conversione+ 
 +Insomma per capire cosa succede in questa istruzione, che serve ad attendere il termine della conversione analogico-digitale dell'ADC, bisogna conoscere i registri dell'ATtiny13A (le informazioni si trovano sul datasheet) e saper operare con i bit (bit-shift, operatori bitwise).
  
 <code C> <code C>
Linea 285: Linea 324:
   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.
 +*/ 
    
-  +/* 
-  **** COMMENTI E 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 da memorizzare 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
-  generalità sui microcontrollori e programmazione in C, +  generalità sui microcontrollori e programmazione in C 
-  saper leggere un datasheet lungo e complessobitwise operation e  +  saper leggere un datasheet lungo e complesso 
-  bit masking per la gestione dei registri+  - bitwise operation e bit masking per la gestione dei registri
    
   CONFIGURAZIONE   CONFIGURAZIONE
-  Quando si carica il programma il MCU va anche configurato (usando +  Il MCU va configurato per andare a 1.2MHz l'esecuzione non sarà 
-  i "fuses"per andare a una frequenza di 1.2MHz (il clock interno +  corretta come tempi.
-  ha due possibili frequenze di funzionamento e un prescaler per +
-  ridurre la frequenza). Settando una frequenza diversa l'esecuzione +
-  non sarà corretta come tempi+
    
   REGISTRI PIU' IMPORTANTI UTILIZZATI   REGISTRI PIU' IMPORTANTI UTILIZZATI
   I numeri di pagina nei commenti fanno riferimento al datasheet    I numeri di pagina nei commenti fanno riferimento al datasheet 
-  dell'ATtiny13A. Nella sezione sui registri c'è il link alle pagine  +  dell'ATtiny13A (rev. 8126F-AVR-05/12). Nella pagina "Register Summary"  
-  con una descrizione e i seguenti valori di default: +  c'è il link alle pagine che descrivono i registri e i loro valori di   
-  DDRB   0b00000000 -> tutti ingressi +  default: 
-  PORTB  0b00000000 -> pull-up disabilitato (tri-state)+  DDRB   0b00000000 -> tutti ingressi 
 +  PORTB  0b00000000 -> pull-up disabilitato (tri-state)
   ADCSRA = 0b00000000 -> ADC spento   ADCSRA = 0b00000000 -> ADC spento
-  ADMUX  0b00000000 -> ADC0 selezionato+  ADMUX  0b00000000 -> ADC0 selezionato 
 +  
 +  GESTIONE INGRESSI E USCITE 
 +  DDRB imposta come uscite i pin che hanno il bit corrispondente a 1 
 +  (pagina 50). I pin sono sempre usati come ingressi tranne quando  
 +  viene chiamata la funzione play(). 
 +  Il pin 1 (PB5) è usato sia per il pulsante start (è un RESET attivo 
 +  basso che come ingresso analogico (ADC0) scollegato, per generare 
 +  il seed del random generator. 
 +  Il pin 6 (PB1/OC0B) è usato per pilotare il buzzer con un'onda  
 +  quadra generata col timer/counter in modalità waveform generator.
    
-  DDRB imposta come uscite i bit a 1 (pagina 50) 
-  Tutti i pin sono ingressi tranne quando viene chiamata play(); il  
-  pin 5 (PB5) viene usato come: 
-  * RESET attivo basso (start) 
-  * ADC0 scollegato  per generare il seed con l'ADC all'avvio 
-  Sul pin 6 (PB1/OC0B) si genera l'onda quadra per il buzzer usando il 
-  timer/counter e la 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
-  - OCR0A e OCR0B con dei valori da comparare con TCNT0 (valore  +  - OCR0A e OCR0B che contengono i valori da comparare con TCNT0  
-  massimo che fissa la frequenza e valore in corrispondenza del +  Questi due registri contengono il valore massimoche fissa la 
-  quale c'è la commutazione tra livello alto e basso+  frequenzaquello in corrispondenza del quale c'è la commutazione 
-  Il waveform generator usa il risultato della comparazione per  +  tra livello alto e bassoIl waveform generator usa il risultato  
-  produrre un segnale PWM nei pin OC0A e OC0B (collegato al buzzer) +  della comparazione per produrre un segnale PWM nel pin OC0B (buzzer)
-  Il timer/clock si ferma se non si seleziona una sorgente di clock +  
-  il modo di funzionamento si imposta con WGM0[2:0] e COM0x[1:0]: +  Il timer/counter si ferma se non si seleziona una sorgente di clock. 
-  - normal: conta in su fino a 0xFF poi interrupt e ricomincia+  Ha più modi di funzionamento che dipendono da WGM0[2:0] e COM0x[1:0]: 
 +  - 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 su match con OCR0A alto su 0xFF (fig. 11-6)+  - fast PWM: va basso sul match con OCR0A 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.
 */ */
    
    
-// LIBRERIE+// LIBRERIE UTILIZZATE (da https://www.nongnu.org/avr-libc/ )
    
-// sleep mode per ridurre il consumo. Al termine di ogni partita +// sleep mode 
-// il MCU va in POWER-DOWN per non consumare e si sveglia col reset+// Al termine di ogni partita, se scade il watchdog timer il MCU va in 
 +// POWER-DOWN per ridurre il consumo; si risveglia col un reset.
 #include <avr/sleep.h> #include <avr/sleep.h>
    
-// come la funzione delay() di Arduinocicli di CPU buttati ma va bene +// delay  
-//  per piccole temporizzazioni (altrimenti meglio usare il timer) +// funzione simile a delay() di Arduino (cicli di CPU buttati). Va  
-// il codice usa _delay_loop_2(t) dove t è un int a 16 bit +// bene per piccole temporizzazionialtrimenti meglio usare il timer. 
-// il ritardo dipende dal clock del MCU e si calcola moltiplicando +// Il codice usa _delay_loop_2(t) dove t è un int a 16 bit; il ritardo  
-// t per il tempo di quattro cicli di clock. Ad esempio con clk 1.2MHz  +// dipende dal clock del MCU e si calcola moltiplicando t per il tempo  
-// e t=25000 si calcola (1/clock)*4*t = 83ms+// di quattro cicli di clock. Ad esempio col clock a 1.2MHz e t=25000  
 +// l'attesa è (1/clock)*4*t = 83ms
 #include <util/delay_basic.h> #include <util/delay_basic.h>
    
-// per salvare l'high score nella EEPROM+// eeprom 
 +// per salvare l'high-score nella EEPROM
 #include <avr/eeprom.h> #include <avr/eeprom.h>
    
Linea 361: Linea 411:
    
 // NB le variabili dichiarate e non inizializzate valgono zero, vedi // NB le variabili dichiarate e non inizializzate valgono zero, vedi
-// www.microchip.com/webdoc/AVRLibcReferenceManual/FAQ_1faq_varinit.html+// https://www.nongnu.org/avr-libc/user-manual/FAQ.html#faq_varinit
    
-// i quattro elementi impostano come uscite PB1 (il buzzer) e uno tra +// nella fase di gioco in cui viene mostrata la sequenza con la funzione 
-// PB3, PB2, PB0 e PB4 per accendere rispettivamente i LED 1, 4, 3 e 2 +// play() i quattro elementi dell'array, applicati al registro PORTB, 
-// nella fase di gioco in cui viene mostrata la sequenza+// impostano come uscite PB1 (il buzzer) e uno tra PB3, PB2, PB0 e PB4 
 +// (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 371: Linea 422:
    
 // array con quattro valori usati dal waveform generator per produrre  // array con quattro valori usati dal waveform generator per produrre 
-// le note: re# sol# do re# (2.5, 3.3, 4.2 e 5 kHz)+// le note: re fala re
 // vedere la funzione play() per interpretare i valori // vedere la funzione play() per interpretare i valori
 const uint8_t tones[4] = { const uint8_t tones[4] = {
Linea 377: Linea 428:
 }; };
    
-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 (mischiato)+uint16_t seed; // generato con l'ADC su un pin scollegato (poi mischiato)
 uint16_t ctx; // valori successivi generati a partire dal seed uint16_t ctx; // valori successivi generati a partire dal seed
    
 // variabili volatile modificate dalla ISR del watchdog // variabili volatile modificate dalla ISR del watchdog
 +// vedi http://gammon.com.au/interrupts o la reference di Arduino per
 +// le motivazioni circa il qualificatore "volatile"
 volatile uint8_t nrot = 8; // quante volte si mischia il seed nella ISR volatile uint8_t nrot = 8; // quante volte si mischia il seed nella ISR
-                           // usando il valore del timer 
 volatile uint16_t time; // conteggio incrementato dall'ISR ogni 16ms volatile uint16_t time; // conteggio incrementato dall'ISR ogni 16ms
                         // usato per il debouncing dei pulsanti e per                         // usato per il debouncing dei pulsanti e per
Linea 395: Linea 447:
    
 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 409: Linea 461:
 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;
    
   // imposta come uscite il buzzer e uno dei pin collegati ai LED   // imposta come uscite il buzzer e uno dei pin collegati ai LED
-  // con i bit di PORTB a 0 (livello basso) il LED si accende e sul +  // con i bit di PORTB a 0 (livello basso) il LED si accende
-  // buzzer viene generato il segnale PWM +
   DDRB = buttons[i];     DDRB = buttons[i];  
    
 +  // generazione del segnale PWM per il buzzer con il waveform generator
 +  // modo PWM phase-correct (con TTCR0A e TTCR0B)
 +  // - OCR0A e OCR0B impostano la frequenza della nota e il duty-cicle
 +  // - bit di TTCR0B impostano il modo PWM e il prescaler
 +  // la frequenza vale (pag. 68): f=(1.2M/[(prescaler)x(OCR0A+OCR0A)]
 +  // con i valori in tones (239, 179, 143, 119) -> 314 419 524 e 630 Hz
 +  // che per qualche strana ragione che andrebbe investigata diventano
 +  // re, fa#, la, re (294 370 440 587 Hz)
 +  
   // 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 frequenza; da pag. 68 si capisce che la  +  // per modificare la frequenza (nota)
-  // frequenza minima si otterrebbe senza 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 +
-  // gli altri valori sono 3.3, 4.2 e 5 kHz (re# sol# do re#)+
   OCR0A = tones[i];   // ad esempio 239 -> 11101111 per tones[0]   OCR0A = tones[i];   // ad esempio 239 -> 11101111 per tones[0]
-  // a OCR0B la sua metà+  // assegno a OCR0B la sua metà (duty-cycle 50%)
   OCR0B = tones[i] >> 1; //shiftR di 1: 01110111 (239 diviso 2: 119)   OCR0B = tones[i] >> 1; //shiftR di 1: 01110111 (239 diviso 2: 119)
    
-  // TCCR0A/B sono impostati nel main prima di chiamare play() in modo +  // TCCR0A è impostato nel main prima di chiamare play(); si cambia  
-  // che il waveform generator funzioni in modalità PWM phase correct +  // TTCR0B in modo che il waveform generator funzioni in modalità PWM 
-  // WGM02 imposta il conteggio fino a OCR0A, CS01 il prescaler 8+  // phase correct e conteggio fino a ORC0A con prescaler 8
   TCCR0B = (1 << WGM02) | (1 << CS01);   TCCR0B = (1 << WGM02) | (1 << CS01);
 +  // TTCR0A = 00100001 e TTCR0B = 00001010 quindi:
 +  // WGM0[2:0] = 101 -> modo phase correct fino a OCR0A
 +  // CS0[2:1] = 010 -> prescaler 8
    
   // suona la nota e tiene il LED acceso per 150ms   // suona la nota e tiene il LED acceso per 150ms
   _delay_loop_2(t);   _delay_loop_2(t);
    
-  // spegne il timer/counter interrompendo il segnale PWM+  // spegne il timer/counter (niente clock) interrompendo il segnale PWM
   TCCR0B = 0b00000000;    TCCR0B = 0b00000000; 
    
   // 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 458: Linea 519:
   // se si batte l'high score salva il livello raggiunto su eeprom   // se si batte l'high score salva il livello raggiunto su eeprom
   if (lvl > maxLvl) {   if (lvl > maxLvl) {
-    eeprom_write_byte((uint8_t*) 0, ~lvl); // write best score+    eeprom_write_byte((uint8_t*) 0, ~lvl); // high score complementato
     //animazione high score (3 volte l'animazione level up)     //animazione high score (3 volte l'animazione level up)
     for (uint8_t i = 0; i < 3; i++) {      for (uint8_t i = 0; i < 3; i++) { 
Linea 475: Linea 536:
    
 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 su come funziona vedi il progetto originale 
-  // o la pagina wikipedia (e l'AN della Maxim linkata):+  // o la pagina wikipedia (e l'Application Note 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 
 + 
   // 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 491: Linea 553:
     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 499: Linea 564:
 } }
    
-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 520: Linea 587:
    
 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 538: Linea 609:
   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 per mischiare il seed 
 + 
   // 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)
   TCCR0B = (1 << CS00);   TCCR0B = (1 << CS00);
 +  // TTCR0A = 00000000 e TTCR0B = 00000001 quindi:
 +  // - WGM0[2:0] = 000 -> normal mode (pag 73)
 +  // - CS0[2:0] = 001  -> no prescaling (clock a 1,2MHz)
    
   // il watchdog timer scade otto volte e la ISR mischia il seed    // il watchdog timer scade otto volte e la ISR mischia il seed 
   while (nrot);    while (nrot); 
    
-  // IMPOSTAZIONE TIMER/COUNTER per generare il segnale PWM del buzzer+  // 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 (tabella a pagina 73) 
-  // registro OCR0A per modificare la frequenza e produrre più note)) +  // nella funzione play() invece, per cambiare la frequenza e produrre 
-  // Si imposta il compare output mode del waveform generator in modo  +  // note diverse, conterà fino al valore contenuto nel registro OCR0A  
-  // che il pin del buzzer PB1/OC0B (COM0B[1:0]=10) vada basso sul +  // Si imposta il compare output mode del waveform generator  
-  // match col valore del registro OCR0B mentre conta in su e alto  +  // (COM0B[1:0]=10)in modo che il pin del buzzer PB1/OC0B vada basso  
-  // mentre conta in giù (OCR0B è impostato nella funzione play() come +  // sul match col valore del registro OCR0B mentre si conta in su e  
-  // OCR0A) generando un onda quadra con la frequenza desiderata+  // alto mentre si conta in giù; 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) e se è impostata una sorgente per il clock (pag 60) 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); 
 +  // TTCR0A = 00100001 e TTCR0B = 00000001 quindi:
 +  // - WGM0[2:0] = 001 -> phase correct mode (pag 73)
 +  // - COM0B[1:0] = 10 -> reset up-counting, set down-counting (pag 72)
    
-  // 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
 +  // (dove 0 significa premuto)
   switch (PINB & 0b00011101) {   switch (PINB & 0b00011101) {
-    // AND tra gli ingressi e la maschera sopra0 significa premuto,  +    // NB lo switch non è necessarionel 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+    // 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 593: Linea 684:
   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 598: Linea 690:
     // 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 609: Linea 702:
     // 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 617: Linea 711:
     // 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 623: Linea 718:
         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 630: Linea 725:
           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 641: Linea 736:
               if (i != correct) {               if (i != correct) {
                 // accendi il LED giusto tante volte pari al livello raggiunto                 // accendi il LED giusto tante volte pari al livello raggiunto
-                for (uint8_t j = 0; j < lvl; j++) {+                for (uint8_t j = 0; j <lvl; j++) {
                   _delay_loop_2(65536); // 33ms                   _delay_loop_2(65536); // 33ms
                   play(correct, 45000); // 66ms                   play(correct, 45000); // 66ms
Linea 659: Linea 754:
           }           }
         }         }
-        // 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 674: Linea 770:
   }   }
 } }
 +
  
 </code> </code>
Linea 684: Linea 781:
 ===== Programmazione del microcontrollore ===== ===== Programmazione del microcontrollore =====
  
-Per programmare il micro ATtiny13A useremo una scheda Arduino Uno come programmatore come descritto in [[https://create.arduino.cc/projecthub/taunoerik/programming-attiny13-with-arduino-uno-07beba|questo tutorial]].+Per programmare il micro ATtiny13A useremo una scheda Arduino Uno((funziona anche con una Arduino Duemilanove ma bisogna collegare un condensatore da 10uF tra reset e ground altrimenti l'upload fallisce)) come programmatore come descritto in [[https://create.arduino.cc/projecthub/taunoerik/programming-attiny13-with-arduino-uno-07beba|questo tutorial]].
  
 La soluzione più semplice è quella di usare una breadboard e sei cavi rigidi collegati come nella figura seguente((LED e resistori non servono ma permettono di testare velocemente se la programmazione funziona caricando sul micro uno sketch che fa lampeggiare il led)): La soluzione più semplice è quella di usare una breadboard e sei cavi rigidi collegati come nella figura seguente((LED e resistori non servono ma permettono di testare velocemente se la programmazione funziona caricando sul micro uno sketch che fa lampeggiare il led)):
Linea 719: Linea 816:
  
   * spazzolare la scheda per togliere il photoresist e facilitare la saldatura   * spazzolare la scheda per togliere il photoresist e facilitare la saldatura
-  * forare con punta da 0.8mm+  * forare in corrispondenza delle piazzole usando la punta da 0.8mm per LED, zoccolo, resistenze e quella da 1mm per portabatteria, pulsanti e buzzer
   * come saldare (vedi immagine) e la pagina sull'[[attrezzatura#come_si_salda|attrezzatura]]   * come saldare (vedi immagine) e la pagina sull'[[attrezzatura#come_si_salda|attrezzatura]]
   * montare i LED rispettando la polarità   * montare i LED rispettando la polarità
Linea 738: Linea 835:
     * {{ :attiny13a-datasheet.pdf |datasheet ATtiny13A}}     * {{ :attiny13a-datasheet.pdf |datasheet ATtiny13A}}
     * [[https://www.tme.eu/Document/a9f06aaefce48a31c93d25914fbf5b1b/B3F.PDF|datasheet pulsanti]]     * [[https://www.tme.eu/Document/a9f06aaefce48a31c93d25914fbf5b1b/B3F.PDF|datasheet pulsanti]]
-    * <del>{{ ::portabatteria_ds1092-05-b6p.pdf |datasheet portabatteria}}</del> {{ :ds1092-06-b6p.pdf |datasheet portabatteria}}+    * {{ ::ds1092-04-b6p.pdf |datasheet portabatteria}}
     * [[https://www.tme.eu/Document/0a17907767f24177db91ee2c59b5dff5/LD-BZPN-1307_DTE.pdf|datasheet buzzer]]     * [[https://www.tme.eu/Document/0a17907767f24177db91ee2c59b5dff5/LD-BZPN-1307_DTE.pdf|datasheet buzzer]]
 +    * [[https://www.tme.eu/it/parking/e6d36a77b8f63a8a739c24177417da827373e810.html|BOM componenti su tme.eu]]
   * Tutorial National Instruments   * Tutorial National Instruments
     * [[http://www.ni.com/tutorial/3173/en/|creare un componente per Multisim]]     * [[http://www.ni.com/tutorial/3173/en/|creare un componente per Multisim]]
Linea 745: Linea 843:
   * altro   * altro
     * [[https://hackaday.io/project/18952-simon-game-with-attiny13|progetto ispiratore]] su hackaday.io     * [[https://hackaday.io/project/18952-simon-game-with-attiny13|progetto ispiratore]] su hackaday.io
 +    * [[https://playground.arduino.cc/Code/BitMath|Bit Math Tutorial]] dal playground Arduino
     * [[https://www.instructables.com/id/ATTiny-Port-Manipulation/|port manipulation per ATtiny]]     * [[https://www.instructables.com/id/ATTiny-Port-Manipulation/|port manipulation per ATtiny]]
     * [[http://mightyohm.com/files/soldercomic/translations/FullSolderComic_IT.pdf|fumetto tutorial sulla saldatura]]     * [[http://mightyohm.com/files/soldercomic/translations/FullSolderComic_IT.pdf|fumetto tutorial sulla saldatura]]
 +    * [[https://it.emcelettronica.com/sbrogliare-un-pcb|articolo sullo sbroglio dei PCB]]
     * {{ :riservata:documentazione_scheda_simon.zip |file zip con tutta lo documentazione del progetto}}     * {{ :riservata:documentazione_scheda_simon.zip |file zip con tutta lo documentazione del progetto}}
-    * [[https://www.tme.eu/it/parking/c1f910e58e6fe4b0689fef9fd00dfc15fd773807.html|BOM componenti su tme.eu]]+    * {{ ::simon.zip |}} 
 +    * [[https://oshwlab.com/leonardo.canducci_6153/ministage-pascal-2020/|progetto su easyeda.com]] importato da kicad 
 +    * {{ :simon-kicad.zip |lo stesso progetto realizzato con KiCad}} 
 +    * {{ ::simon_custom_components.zip |Simboli e footprint custom per Multisim e Ultiboard}} 
 + 
  
  
simon.1601647021.txt.gz · Ultima modifica: 2020/10/02 13:57 da admin