Microcomputer: tecniche di programmazione in assembly

Giuliano Donzellini, Domenico Ponta

Generatore di byte, controllato da pulsanti, su FPGA

110043

 

v1.71

In questo laboratorio, scriveremo e verificheremo il programma in assembly DMC8 che specializza un sistema micro computerizzato (visibile nella figura sotto), come generatore di byte. Al termine del progetto, verificheremo in pratica il funzionamento del dispositivo su di una scheda FPGA di tipo Altera DE2.

Per aprire lo schema nel d-DcS, fate click sulla figura. Il sistema include, oltre al microcomputer (DMC8), alcuni componenti collegati ai porti paralleli. In ingresso, il microcomputer legge i pulsanti !Down e !Up (sul porto IA). In uscita, genera il byte (sul porto OC), e una linea Error che riporta una condizione di errore (sul bit 7 del porto OD). Per rendere più agevole la lettura del valore del byte, sono presenti sia una uscita binaria (su 8 led), che un'uscita su display esadecimale.

Specifiche del programma

Il programma è eseguito all'attivazione del comando hardware di !Reset. Durante l'inizializzazione del programma, le linee di uscita sono azzerate. Il processore, quindi, entra nel ciclo principale, infinito, nel quale periodicamente legge i pulsanti, valuta il loro stato e, di conseguenza, incrementa, decrementa o lascia invariato il byte in uscita (secondo le modalità descritte qui di seguito).

Quando i pulsanti !Down e !Up non sono premuti (a livello "alto"), il sistema mantiene invariato il valore del byte in uscita.

Quando il pulsante !Up è premuto, il byte in uscita è incrementato immediatamente di uno, e se !Up rimane premuto, è incrementato ancora di uno ogni 500 mS. Se il valore raggiunge il massimo, l'attivazione di !Up è ignorata.

In modo simile, quando il pulsante !Down è premuto, il byte in uscita è decrementato immediatamente di uno, e se !Down rimane premuto, è decrementato ancora di uno ogni 500 mS. Se il valore raggiunge il minimo, l'attivazione di !Down è ignorata.

Se !Down e !UP sono attivati nello stesso momento, il sistema mantiene invariato il valore di uscita, ma attiva la linea Error, mantenendola attiva fino a quando la condizione d'errore non è rimossa.

Suggerimenti e dettagli tecnici

Tecnica "antirimbalzo" per i pulsanti ("debouncing")

Un pulsante è un dispositivo elettromeccanico. Quando è premuto, o rilasciato, i contatti elettrici mostrano una serie di "rimbalzi" ("bounces") nel momento della chiusura o dell'apertura, causati dalla loro inerzia ed elasticità. Al posto di una transizione univoca e pulita, i rimbalzi producono commutazioni multiple e casuali, che si estinguono nel giro di qualche millisecondo (in base alle caratteristiche del dispositivo). Queste transizioni spurie devono essere filtrate, altrimenti il sistema riceverà comandi multipli e quindi sbagliati: in linguaggio tecnico, si dice che è necessario "eliminare i rimbalzi" del pulsante ("push-button debouncing").

Una soluzione semplice è confrontare il valore letto ora dal porto con quello letto un certo tempo prima (per esempio, 25 mS). Se i valori sono differenti, uno o più pulsanti sono in uno stato di transizione, cioè durante la fase di pressione o di rilascio. Se risultano uguali, si è ragionevolmente lontani dai rimbalzi, lo stato dei pulsanti è stabile e può essere tenuto in conto.

Il ciclo principale ("main loop")

Per implementare questo metodo, il ciclo principale del programma esegue, ad ogni ripetizione, un sottoprogramma di ritardo (25 mS); è poi acquisito il valore corrente del porto IA, e salvato come "valore precedente", che sarà usato al momento della prossima ripetizione del ciclo. Se il valore corrente e il precedente risultano diversi, il ciclo principale ripete da capo quanto descritto, senza fare altro, fino a quando i due valori non risultano uguali. In questo caso, il programma prosegue valutando lo stato di ciascun pulsante, come definito dalle specifiche date.

Come ripetere un comando ogni 500 mS

I pulsanti richiedono al sistema una operazione in due occasioni: a) ogni volta che sono premuti, e b) quando rimangono premuti per più di 500 mS. Quest'ultima specifica richiede che il programma tenga conto del tempo trascorso. Il ciclo principale si ripete ogni 25 mS (il tempo di esecuzione del sottoprogramma di ritardo), e quindi il programma deve semplicemente contare le ripetizioni del ciclo, dall'ultimo cambiamento di stato dei pulsanti (500 mS = 25 mS x 20).

Il conteggio deve essere azzerato ogni volta che lo stato dei pulsanti cambia (quando sono premuti, rilasciati o durante i rimbalzi). Quando lo stato dei pulsanti è stabile, invece, il conteggio è incrementato (ad ogni ripetizione del ciclo principale). Quindi, la prima volta che i pulsanti sono individuati stabili dopo una variazione, il conteggio vale 1: questo è il momento di eseguire il compito richiesto (gestire gli incrementi/decrementi del byte in uscita).

Per ripetere le operazioni ogni 500 mS, è sufficiente riazzerare il conteggio ogni volta che raggiunge il valore 20: alla successiva ripetizione del ciclo principale, il suo incremento lo porterà nuovamente a 1. In questo modo viene separata nettamente l'operazione del conteggio del tempo dal compito da svolgere: la condizione per eseguire il compito è semplicemente che il conteggio sia pari a 1, per cui sarà eseguito una prima volta alla pressione dei pulsanti, e successivamente che ogni 500 mS.

Una traccia del codice, da completare nel d-McE, è disponibile qui. Si raccomanda di aggiungere commenti al codice, in modo da renderlo più leggibile. Dopo il completamento del programma, conviene dapprima testarne la funzionalità nel debugger del d-McE. Lo si potrà, quindi, caricare nella ROM del microcomputer, nello schema del d-DcS, per simulare l'intero sistema in modalità temporale . Un'appropriata sequenza di test è disponibile nella finestra del diagramma temporale. Si raccomanda di usare lo schema fornito senza cancellare o modificare le terminazioni di ingresso e di uscita perché sono state predisposte per la esportazione del progetto sulla scheda FPGA.


A questo punto inizia la procedura per realizzare fisicamente il progetto sulla scheda FPGA. La procedura generale è descritta passo passo nei tutorial introduttivi:
   Realizzazione di un prototipo di circuito su scheda Altera DE2
   Test di una rete sequenziale su scheda Altera DE2
   Test di microcomputer su scheda Altera DE2

Il comando "Test on FPGA" (del d-DcS) apre la finestra di dialogo visibile qui sotto:

Si noti che tutte le associazioni degli ingressi e uscite con i corrispondenti dispositivi della scheda FPGA sono state già predefinite, e non è necessario modificarle. La frequenza di clock è stata definita pari a 10 MHz. E' stata predisposta la modalità di esecuzione passo-passo ("Step by Step Mode"), assegnando l'interruttore Sw[17] al compito di abilitare (al "run time") tale funzione. E' stato predisposto un LED, il LEDR[17], come visualizzatore degli impulsi di clock che saranno inviati al microcomputer. Infine, è stato scelto il pulsante Key[01] come comando manuale dell'avanzamento delle istruzioni. Se l'interruttore Sw[17] è posto a '0', la funzione di debug non è attiva e il microcomputer funziona con il clock "normale" (10 MHz). Se l'interruttore Sw[17] è a '1', il clock del processore è inibito, e il sistema di debug resta in attesa che l'utente prema il pulsante Key[01] (a ogni pressione del pulsante, il microcomputer esegue una istruzione).

Per ottimizzare la sperimentazione di quanto descritto sulla scheda FPGA, le associazioni sono evidenziate in modo riassuntivo nella figura seguente (il "pannello di controllo" del nostro sistema):