Lezione 13
🎓 PIC16 — From Zero to Hero · Lezione 13 · Modulo 2
Display a 7 segmenti 🔢
Come tradurre una cifra in pattern di segmenti con una lookup table RETLW.
Multiplexing di due display con una sola PORTB e alternanza a 100 Hz.
🎯 Cosa impari in questa lezione
- Come è fatto un display 7 segmenti (Common Cathode vs Common Anode)
- Come costruire una lookup table con RETLW e come funziona l’indirizzamento con PCL
- Il pericolo del boundary di pagina con ADDWF PCL,F
- Programma completo: contatore 0–9 su singola cifra con reset da pulsante
- Tecnica del multiplexing: due display con una sola PORTB
- Subroutine SPLIT_DIGITS: divisione senza istruzione DIV
- Anti-ghosting: il blanking tra le cifre
📋 Scheda lezione
Lezione: 13 / 42
Modulo: 2 — I/O Digitale
Device: PIC16F84A
Prerequisiti: Lez. 09 (RETLW, PCL)
Difficoltà: ★★★☆☆
Pattern chiave: lookup table, multiplexing
1 · La struttura del display 7 segmenti
Un display 7 segmenti è composto da 7 LED etichettati a–g (più il punto decimale dp). In configurazione Common Cathode tutti i catodi sono collegati a GND: portare un anodo a +5V accende il segmento. Ogni bit di PORTB controlla un segmento: RB0=a, RB1=b, … RB6=g, RB7=dp.
Per visualizzare il numero 5 servono i segmenti a, c, d, f, g → bit 0,2,3,5,6 = 0b01101101 = 0x6D.
⚠ Common Anode: la logica si inverte — 0 accende, 1 spegne. Usare COMF sui pattern prima di scrivere su PORTB. Nel simulatore si usa Common Cathode.
2 · La lookup table con RETLW
Invece di calcolare il pattern a runtime, usiamo una tabella in Program Memory: ogni RETLW k ritorna con W=k. L’indice della cifra viene sommato a PCL per saltare direttamente alla RETLW corretta.
; Tabella codifica 0–9, Common Cathode ; La tabella DEVE stare interamente in una pagina da 256 word. ; Piazzarla dopo GOTO INIT (ORG 0x0001) lo garantisce. SEG_TABLE ADDWF PCL,F RETLW 0x3F ; 0: a b c d e f RETLW 0x06 ; 1: b c RETLW 0x5B ; 2: a b d e g RETLW 0x4F ; 3: a b c d g RETLW 0x66 ; 4: b c f g RETLW 0x6D ; 5: a c d f g RETLW 0x7D ; 6: a c d e f g RETLW 0x07 ; 7: a b c RETLW 0x7F ; 8: tutti i segmenti RETLW 0x6F ; 9: a b c d f g
⚠ Boundary di pagina: ADDWF PCL,F somma solo gli 8 bit bassi del PC. Se la tabella attraversa il confine 0x0FF/0x100, il salto finisce nella pagina sbagliata. Soluzione: piazzare SEG_TABLE subito dopo ORG 0x0000 / GOTO INIT, oppure usare PCLATH per tabelle più grandi.
3 · Programma — Contatore 0–9 su singolo display
; ============================================================ ; Lezione 13 — Display 7 segmenti, singola cifra ; Contatore 0-9 con lookup table. Reset pulsante RA0. ; PIC16F84A @ 4 MHz PORTB: RB0=a ... RB6=g, RB7=dp ; ============================================================ LIST P=16F84A #INCLUDE <p16f84a.inc> __CONFIG _XT_OSC & _WDT_OFF & _PWRTE_ON & _CP_OFF CBLOCK 0x0C DIGIT ; cifra corrente (0-9) D_HI ; delay loop esterno D_LO ; delay loop interno ENDC ORG 0x0000 GOTO INIT ORG 0x0005 INIT BSF STATUS,RP0 ; Bank 1 CLRF TRISB ; PORTB tutto output (segmenti) MOVLW 0x01 MOVWF TRISA ; RA0 = input (pulsante) BCF STATUS,RP0 ; Bank 0 CLRF PORTB ; display spento CLRF DIGIT LOOP ; 1. Converti DIGIT → pattern segmenti MOVF DIGIT,W CALL SEG_TABLE MOVWF PORTB ; 2. Aspetta ~500ms (2 × 250ms) CALL DELAY_250MS CALL DELAY_250MS ; 3. Pulsante reset (RA0 = 0 se premuto) BTFSS PORTA,0 CLRF DIGIT ; 4. Incrementa, azzera dopo 9 INCF DIGIT,F MOVF DIGIT,W SUBLW D'10' ; W = 10 - DIGIT BTFSS STATUS,Z GOTO LOOP CLRF DIGIT GOTO LOOP ; ============================================================ ; SEG_TABLE — deve stare tutta in una pagina da 256 word ; W in: cifra (0-9) W out: pattern PORTB (Common Cathode) ; ============================================================ SEG_TABLE ADDWF PCL,F RETLW 0x3F ; 0: a b c d e f RETLW 0x06 ; 1: b c RETLW 0x5B ; 2: a b d e g RETLW 0x4F ; 3: a b c d g RETLW 0x66 ; 4: b c f g RETLW 0x6D ; 5: a c d f g RETLW 0x7D ; 6: a c d e f g RETLW 0x07 ; 7: a b c RETLW 0x7F ; 8: a b c d e f g RETLW 0x6F ; 9: a b c d f g ; ============================================================ ; DELAY_250MS ≈ 250ms @ 4 MHz ; D_HI=250, D_LO=0 (→256): 250×256×3 cicli ≈ 192000 µs ; + overhead → ~250ms (abbastanza per uso didattico) ; ============================================================ DELAY_250MS MOVLW D'250' MOVWF D_HI DLY_OUTER CLRF D_LO ; 256 iterazioni DLY_INNER DECFSZ D_LO,F ; 1 ciclo (2 se skip) GOTO DLY_INNER ; 2 cicli DECFSZ D_HI,F GOTO DLY_OUTER RETURN END
4 · Multiplexing — Due cifre con una sola PORTB
Con due display collegati in parallelo su PORTB, si usa un pin di abilitazione per ciascuno (RA0 → DIG0, RA1 → DIG1). Si accende un solo display alla volta per 5 ms, poi si commuta: l’occhio percepisce entrambe le cifre accese contemporaneamente (effetto persistenza, frequenza = 100 Hz).
Programma completo — Contatore 00–99 con multiplexing
; ============================================================ ; Lezione 13 — Multiplexing 2 display 7 segmenti ; Contatore 00-99. PORTB=segmenti, RA0=DIG0, RA1=DIG1 ; ============================================================ LIST P=16F84A #INCLUDE <p16f84a.inc> __CONFIG _XT_OSC & _WDT_OFF & _PWRTE_ON & _CP_OFF CBLOCK 0x0C COUNTER ; valore corrente 0-99 DIGIT0 ; unità (0-9) DIGIT1 ; decine (0-9) REFRESH ; contatore cicli refresh D_LO ; delay interno TEMP ; variabile temporanea ENDC ORG 0x0000 GOTO INIT ORG 0x0005 INIT BSF STATUS,RP0 CLRF TRISB ; PORTB tutto output (segmenti) CLRF TRISA ; PORTA tutto output (abilitazioni) BCF STATUS,RP0 CLRF PORTA ; display spenti CLRF PORTB CLRF COUNTER MOVLW D'50' MOVWF REFRESH ; 50 × 10ms = 500ms ; --- Loop principale: ogni iterazione = 1 ciclo refresh (10ms) --- LOOP CALL SPLIT_DIGITS ; calcola DIGIT0, DIGIT1 ; DIG0 (unità) per 5ms MOVF DIGIT0,W CALL SEG_TABLE MOVWF PORTB BSF PORTA,0 ; RA0=1: DIG0 ON BCF PORTA,1 ; RA1=0: DIG1 OFF CALL DELAY_5MS ; Blanking: evita ghosting durante la commutazione CLRF PORTA CLRF PORTB ; DIG1 (decine) per 5ms MOVF DIGIT1,W CALL SEG_TABLE MOVWF PORTB BCF PORTA,0 ; RA0=0: DIG0 OFF BSF PORTA,1 ; RA1=1: DIG1 ON CALL DELAY_5MS CLRF PORTA CLRF PORTB ; Ogni 50 cicli (500ms) incrementa COUNTER DECFSZ REFRESH,F GOTO LOOP MOVLW D'50' MOVWF REFRESH INCF COUNTER,F MOVF COUNTER,W SUBLW D'100' ; == 100? BTFSS STATUS,Z GOTO LOOP CLRF COUNTER GOTO LOOP ; ============================================================ ; SPLIT_DIGITS: COUNTER → DIGIT0 (unità) + DIGIT1 (decine) ; Tecnica: sottrazione ripetuta (no istruzione DIV sul PIC) ; ============================================================ SPLIT_DIGITS MOVF COUNTER,W MOVWF TEMP CLRF DIGIT1 SPLIT_LOOP MOVLW D'10' SUBWF TEMP,F ; TEMP -= 10 BTFSS STATUS,C ; C=0 → sottratto troppo → stop GOTO SPLIT_DONE INCF DIGIT1,F ; decine++ GOTO SPLIT_LOOP SPLIT_DONE MOVLW D'10' ADDWF TEMP,F ; ripristina ultima sottrazione MOVF TEMP,W MOVWF DIGIT0 RETURN ; ============================================================ ; SEG_TABLE (identica al programma singola cifra) ; ============================================================ SEG_TABLE ADDWF PCL,F RETLW 0x3F RETLW 0x06 RETLW 0x5B RETLW 0x4F RETLW 0x66 RETLW 0x6D RETLW 0x7D RETLW 0x07 RETLW 0x7F RETLW 0x6F ; ============================================================ ; DELAY_5MS ≈ 5ms @ 4 MHz ; 7 × 256 × 3 cicli = 5376 ≈ 5.4ms ; ============================================================ DELAY_5MS MOVLW D'7' MOVWF TEMP D5_OUTER CLRF D_LO D5_INNER DECFSZ D_LO,F GOTO D5_INNER DECFSZ TEMP,F GOTO D5_OUTER RETURN END
5 · Riepilogo — Punti chiave
✓ Lookup table con RETLWADDWF PCL,F come primo elemento. La tabella deve stare in una singola pagina. Il valore di ritorno è in W dopo RETURN.
✓ Multiplexing
Una PORTB per N display. Un pin di abilitazione per cifra. Frequenza ≥ 50 Hz. Blanking tra le cifre contro il ghosting.
✓ SPLIT_DIGITS
Divisione senza DIV: sottrazione ripetuta di 10. Il numero di sottrazioni = quoziente; il residuo = resto. Tecnica usabile per qualsiasi base.
🧪 Prova tu
- Carica il programma singola cifra e osserva il ciclo 0→9→0. Premi il pulsante su RA0 durante la visualizzazione di “7”: il display torna subito a 0?
- Nella SEG_TABLE, cambia
RETLW 0x07(cifra 7) conRETLW 0x4F(cifra 3). Cosa vedi sul display alla terza posizione del ciclo? - Sfida: aggiungi le lettere A e b alla tabella (indici 10 e 11) e porta il limite da
D'10'aD'12'. Codici: A =0x77, b =0x7C. - Sfida multiplexing: modifica il programma 00–99 per incrementare ogni 200ms invece di 500ms. Quante iterazioni da 10ms servono?
❓ Quiz rapido
1. Perché ADDWF PCL,F può causare errori se la tabella è mal posizionata?
Mostra risposta
PCL è solo gli 8 bit bassi del Program Counter. Se la tabella attraversa il confine 0x0FF/0x100, l’addizione fa traboccare PCL da 0xFF a 0x00 senza cambiare PCLATH, saltando nella pagina sbagliata (tipicamente ORG 0x000). Soluzione: posizionare la tabella subito dopo il GOTO iniziale.
2. Qual è il valore da scrivere su PORTB per visualizzare il numero 4 su un display Common Cathode?
Mostra risposta
Il 4 è composto dai segmenti b, c, f, g → bit RB1, RB2, RB5, RB6 = 0b01100110 = 0x66. È la quinta RETLW nella tabella (indice 4).
3. Nel multiplexing, perché si fa CLRF PORTA / CLRF PORTB tra DIG0 e DIG1?
Mostra risposta
Senza blanking, nel breve istante in cui si cambia il pin di abilitazione entrambi i display sono attivi con lo stesso pattern (quello di DIG0), causando il ghosting: DIG1 mostra per un attimo la cifra delle unità invece delle decine. Il blanking elimina la sovrapposizione.
4. In SPLIT_DIGITS, dopo il ciclo si aggiunge 10 a TEMP. Perché?
Mostra risposta
Quando il ciclo si ferma (C=0 dopo SUBWF), TEMP contiene il risultato di una sottrazione di troppo ed è “andato sotto zero” (wrapped a un valore alto). Aggiungere 10 annulla quell’ultima sottrazione errata e recupera il resto corretto. Esempio: 23→13→3→253 (C=0, stop) → 253+10=263 mod 256=7? No: 3+10=13… Verifica: 23, decine=2 (due sottrazioni da 10 riuscite), TEMP dopo due sottrazioni = 3, terza sottrazione 3-10 = -7 = 249 unsigned (C=0), ADDWF 249+10 = 259 mod 256 = 3. Corretto: resto = 3.
Prossima lezione →
Lezione 14 — Multiplexing LED e Matrice 4×4
Come controllare una matrice 4×4 di LED con soli 8 pin, scansione per riga, framebuffer in RAM e indirizzamento indiretto con FSR/INDF.
© Prof. D. Bertolino · PIC16 From Zero to Hero · WebPicSimulator · Lezione 13