UDA 5 — Interrupt e periferiche avanzate
9 ore (3 di teoria + 6 di laboratorio) · Settimane 9-11
Obiettivi
Sezione intitolata “Obiettivi”Al termine di questa unità:
- distingui polling e interrupt e scegli la strategia giusta;
- conosci la catena di un interrupt: richiesta → IM2 → tabella dei vettori → servizio →
RETI; - configuri un device vettorato del G80 (vettore <
0x80, poi0x83) e scrivi il servizio; - usi il timer CTC (
0x70/0x71) e il counter/nastro (0xE0/0xE1); - piloti motore, forno, beeper e leggi potenziometro e chart recorder;
- hai completato l’Esercizio 6 e sostieni la prova pratica n. 3.
Piano delle tre settimane — Sett. 9: polling vs interrupt, IM2, esempio 08 + Esercizio 6. Sett. 10: timer e counter, esempi 09–10. Sett. 11: motore/forno/chart/potenziometro/beeper, sfide e prova pratica n. 3.
1. Polling o interrupt?
Sezione intitolata “1. Polling o interrupt?”Finora abbiamo chiesto noi ai device se avevano novità (il “polling”: in a,(0xC0) in ciclo).
È semplice, ma ha due costi: spreco di tempo e ritardo nella risposta.
| Polling | Interrupt | |
|---|---|---|
| Chi decide | il programma, con un ciclo | il device, quando serve |
| Costo | alto (ciclo continuo di lettura) | quasi zero finché non arriva l’evento |
| Reattività | dipende da quanto spesso si legge | immediata |
| Complessità | bassa | media (servizio, stack, flag) |
| Uso tipico | tastiere, semplici ingressi | timer, eventi periodici, “allarmi” |
Con gli interrupt il programma principale può fare altro (contare, aggiornare il display…) e il device lo “interrompe” solo quando c’è davvero qualcosa da fare.
2. Come funziona un interrupt (IM2)
Sezione intitolata “2. Come funziona un interrupt (IM2)”La sequenza completa:
- il device alza la richiesta (nel G80:
INTAK); - se gli interrupt sono abilitati (
EI, cioèIFF1 = 1), la CPU finisce l’istruzione in corso, salva il PC sullo stack e salta al servizio; - il servizio lavora, poi esegue
EIeRETI; RETIripristina il PC: il programma principale riprende esattamente da dove era.
Nel G80 (e nello Z80) l’hardware dei device usa la modalità IM2 — “vettorata”:
.org 0x0010 ; la tabella dei vettori (indirizzo PARI)VTab: .dw servizio ; una parola: l'indirizzo del servizio
ld a, 0 ld i, a ; I = byte ALTO della tabella im 2 ; modalità 2 ei ; abilita gli interruptQuando arriva la richiesta, la CPU forma l’indirizzo con I come byte alto e il vettore
fornito dal device come byte basso(con il bit 0 a 0): in pratica “nella pagina puntata da I,
all’indirizzo del vettore, c’è la parola con l’indirizzo del servizio”.
Altre cose utili:
DIdisabilita gli interrupt (le richieste restano in attesa);EIli riabilita — e ricordati cheEIfa effetto dopo l’istruzione successiva (una piccola rete di sicurezza del processore);- NMI (interrupt non mascherabile) è una cosa a parte: non si può disabilitare con
DIe salta a un indirizzo fisso (0x0066).
3. Lo schema dei device vettorati del G80
Sezione intitolata “3. Lo schema dei device vettorati del G80”Ogni device vettorato ha due porte: una per la costante (quanto contare) e una di controllo, che serve a due cose:
| Passo | Cosa si scrive | Perché |
|---|---|---|
| 1 | il byte basso del vettore (valore < 0x80) | il device lo memorizza |
| 2 | 0x83 | bit 0 = run, bit 1 = abilita IRQ |
Perché il vettore deve essere
< 0x80? Perché la porta di controllo distingue le due cose dal bit 7: se è 0 il byte è un vettore, se è 1 (come0x83=1000 0011) è un comando. Se sbagli l’ordine non funziona nulla — è l’errore classico.
| Device | Costante | Controllo | Vettore tipico |
|---|---|---|---|
| timer — CTC | 0x70 | 0x71 | 0x10 (come nell’esempio 08) |
| keypad | — | 0x81 | 0x20 |
| counter/nastro | 0xE0 | 0xE1 | 0x70 (come nell’esempio 09) |
La tabella dei vettori va in una pagina ad indirizzo pari (spesso 0x0010, 0x0070…) e
contiene parole .dw: I fornisce il byte alto, il device quello basso.
4. Scrivere un servizio
Sezione intitolata “4. Scrivere un servizio”Il servizio (o ISR, interrupt service routine) è una subroutine con obblighi speciali:
servizio: push af ; 1) salva TUTTO quello che usi push hl push bc ; ... fai il lavoro (breve!) ... pop bc ; 2) ripristina (ordine inverso!) pop hl pop af ei ; 3) riabilita gli interrupt reti ; 4) ritorno "speciale": ripristina anche IFF1Regole d’oro:
- breve: il main resta fermo finché il servizio gira;
- salva i registri che usi: il main non deve accorgersi di nulla (flags compresi:
push af); EI+RETIalla fine: senzaEI, dopo il primo interrupt non ne arrivano più;- non chiamare subroutine lunghe o che usano gli stessi registri senza salvarli;
- se il servizio e il main si scambiano dati, usa variabili in memoria (RAM), non i registri.
5. Il timer CTC — 0x70 / 0x71
Sezione intitolata “5. Il timer CTC — 0x70 / 0x71”Il timer conta i cicli della CPU (T-state) e genera un interrupt periodico:
periodo (in T-state) = COSTANTE × PRESCALER- la costante si scrive su
0x70(es.0x08= 8); - il prescaler (16, 64 o 256) si sceglie dalla tendina CTC nella UI: è il fattore di scala del contatore (default 256);
- ogni volta che il conteggio raggiunge il periodo, il device chiede l’interrupt.
Esempio di calcolo: costante 0x20 (32) e prescaler 256 → periodo = 32 × 256 =
8192 T-state. Se vuoi un ritmo più veloce: costante più piccola o prescaler più basso.
Il timer è perfetto per: lampeggiatori regolari, “orologi”, campionamenti periodici. (Per tempi “da orologio” in millisecondi reali il G80 usa invece il nastro: 500 ms fissi.)
Il counter / nastro — 0xE0 / 0xE1
Sezione intitolata “Il counter / nastro — 0xE0 / 0xE1”Il nastro trasportatore avanza di un passo ogni 500 ms (tempo reale, come nel simulatore originale). Il counter conta i passi e, a zero, ricarica la costante e chiede l’interrupt:
costante = quanti passi del nastro tra un interrupt e il successivoCon costante 4: un interrupt ogni 2 secondi (= 4 × 500 ms) — come nell’esempio 09.
Uso tipico: contare pezzi su un nastro, gestire lotti, sincronizzare il motore.
Motore stepper — 0xB0
Sezione intitolata “Motore stepper — 0xB0”Al motore si invia un impulso: la transizione 0 → 1 fa fare un passo.
ld a, 1 out (MOTOR), a ; fronte 0->1: un passo xor a out (MOTOR), a ; torna a 0 (pronto per il prossimo passo)Nell’esempio 09 il servizio del counter fa avanzare il motore di un passo a ogni interrupt.
Forno (kiln) — 0xF0 / 0xF1
Sezione intitolata “Forno (kiln) — 0xF0 / 0xF1”0xF1in OUT: bit 0 = riscaldatore ON/OFF;0xF1in IN: bit 7 = “dato pronto” (una nuova conversione ogni 500 ms);0xF0in IN: la temperatura misurata.
Schema dell’esempio 10 (polling): imposta il riscaldatore, aspetta il bit 7, leggi la temperatura, traccia il valore sul chart.
Potenziometro, chart recorder, beeper
Sezione intitolata “Potenziometro, chart recorder, beeper”| Periferica | Porta | Uso |
|---|---|---|
| Potenziometro | 0x40 IN | valore 0–255 da uno slider (setpoint, velocità…) |
| Chart recorder | 0x30 OUT | ogni scrittura = un campione tracciato (canale 0) |
| Marker | 0x31–0x33 OUT | marcatori rosso/verde/blu sul grafico |
| Beeper | 0x60 OUT | un beep (un impulso sonoro) |
Combinazione tipica: potenziometro → soglia → riscaldatore (forno); temperatura → chart (grafico); evento → beep.
6. Laboratorio guidato
Sezione intitolata “6. Laboratorio guidato”Attività A — Esempio 08 e Esercizio 6 (timer + IM2)
Sezione intitolata “Attività A — Esempio 08 e Esercizio 6 (timer + IM2)”Apri 08-timer-interrupt.asm e individua le tre parti:
- la tabella dei vettori (
.org 0x0010,.dw servizio); - il setup: costante, vettore,
0x83,I,im 2,ei; - il servizio:
push,OTIRverso l’LCD,pop,ei,reti.
Poi fai l’Esercizio 6 (esercizi/06-timer.asm): il servizio è vuoto, completalo.
Verifica: il messaggio compare ripetutamente e il conteggio LED prosegue (il main è vivo).
Da osservare con Passo: il salto al servizio avviene tra due istruzioni del main e lo
stack cresce di 2 byte (indirizzo di ritorno). Alla fine SP torna al valore iniziale.
Attività B — Esempi 09 e 10 (counter, motore, forno, chart)
Sezione intitolata “Attività B — Esempi 09 e 10 (counter, motore, forno, chart)”09-motore-counter.asm: costante4→ un interrupt ogni 4 passi del nastro (2 s); a ogni interrupt il motore fa un passo. Prova a cambiare la costante: cosa cambia?10-kiln-chart.asm: alza l’interruttore 0 (riscaldatore ON) e osserva: la temperatura sale, il chart disegna la curva; spegnilo e guarda la discesa. Domanda: perché il programma aspetta il bit 7 prima di leggere la temperatura?
Attività C — Sfide
Sezione intitolata “Attività C — Sfide”C1 — Lampeggiatore “preciso”: un LED che lampeggia a interrupt (niente cicli di ritardo!).
Mostra una soluzione (C1)
TIM = 0x70TIM_C = 0x71
.seg CODE (abs) .org 0x0010VTab: .dw servizio .org 0x0020stato: .db 0
.org 0x0100inizio: ld sp, 0xFFFF ld a, 0x20 ; costante del timer (prova a cambiarla) out (TIM), a ld a, VTab out (TIM_C), a ld a, 0x83 out (TIM_C), a ld a, 0 ld i, a im 2 eiciclo: nop jp ciclo
servizio: push af push hl ld hl, stato ld a, (hl) xor 0x01 ; inverte il bit 0 ld (hl), a out (0x20), a pop hl pop af ei retiLo stato del LED sta in memoria (stato): il servizio non può “ricordarsi” nulla nei
registri… perché il main li usa!
C2 — Pianola: premi un tasto del keypad, il numero compare sull’LCD e il beeper suona.
C3 — Linea di trasporto: il counter fa avanzare il motore e conta i pezzi sui LED (mostra il totale).
7. Prova pratica n. 3
Sezione intitolata “7. Prova pratica n. 3”In coda a questa unità c’è la prova pratica sugli interrupt (1 ora al simulatore): un servizio IM2 che interagisce con una periferica mentre il programma principale continua a lavorare. La trovi nella pagina “UDA 5 — Esempio di prova pratica n. 3” (due tracce + griglia di correzione).
8. Autoverifica
Sezione intitolata “8. Autoverifica”- Perché con il polling si “spreca” tempo di CPU? In che caso è comunque la scelta giusta?
- Descrivi la catena: richiesta del device → … →
RETI. - A cosa servono
I, la tabella dei vettori e il vettore < 0x80? - Perché nel servizio si esegue
EIprima diRETI? E perché si salvaAF? - Timer e counter: quale dei due misura il tempo reale (500 ms) e quale conta i cicli della CPU? Come si calcola il periodo del timer?
9. Compiti e materiali
Sezione intitolata “9. Compiti e materiali”📎 I file
.asmdi esempi ed esercizi si scaricano dalla pagina Materiali.
- Compito: completa l’Esercizio 6 e le tre sfide (almeno C1 e C2); prepara la prova pratica n. 3 sul foglio.
- Pre-lettura: manuale, sezione Interrupt (IM2) e tabella delle porte.
- Materiali: esempi
08–10; esercizio06-timer.asm(+ soluzione). - Nota per il docente: i percorsi interrupt di questa unità sono coperti da test
automatici end-to-end (
tests/interrupt-e2e.test.ts): timer CTC → IM2 → servizio, counter/nastro → motore, keypad → servizio con main attivo. - Prossima unità: progetto finale (UDA 6).