Esercitazioni ASM - PIC18

 


ESERCITAZIONE # 9


Gestione di un display a 7 segmenti

Tutti conoscono i display a LED a 7 segmenti, caratteristici per la loro luminosità tipicamente rossa.

In questa esercitazione comandiamo un display del genere per presentare numeri e simboli.

Ecco come si presenta esternamente uno di questi componenti.

Elettricamente si tratta di 8 diodi LED (1 per ogni segmento più quello per il punto decimale) assemblati in un contenitore plastico sagomato in modo tale che essi illuminino delle aree ristrette che formano i segmenti.

Esistono display di numerosissime varietà, forme e colori, ma, principalmente, li possiamo suddividere in due categorie:

  • display ad anodo comune: tutti gli anodi dei LED sono collegati assieme
  • display a catodo comune: tutti i catodi sono collegati assieme

Questo facilita il comandare i display in sistemi multiplexati.

I segmenti hanno un indicatore standard, costituito da una lettera.

Accendendo i LED opportuni sarà possibile ottenere tutti i simboli numerici più una vasta gamma di simboli alfabetici e altro.

Ad esempio, il numero 8 sarà rappresentato accendendo tutti i LED. 
Il numero 3 si evidenzierà accendendo i segmenti A, B, C, D, G.
Il numero 6 si otterrà accendendo il segmenti A, C, D, E, F, G

Una H maiuscola apparirà accendendo i segmenti B, C, B, E, F, G.
E così via.

Il modo più semplice di comandare il display è facendolo direttamente dai pin del PIC come si trattasse (e così in effetti è) di comuni LED.

Quindi colleghiamo ogni segmento ad un pin di un por, ad esempio PORTC, avendo cura di inserire una resistenza di limitazione in serie ad ogni segmento.
Il valore della resistenza può variare da 220 ohm a 1 kohm a seconda della sensibilità del display. Mediamente 470 ohm può andare bene.

=

Fino a qui non c'è niente di strano, ma dobbiamo porre l' attenzione su un punto particolare: come abbiamo visto prima c'è una relazione tra i segmenti accesi e la cifra presentata. Dunque c'è una relazione tra lo stato dei pin del PIC che comandano i LED e i segmenti accesi.

Ovvero, e questa è la chiave del problema, c'è un rapporto tra il numero binario posto nel registro di uscita del PORT e il numero presentato.

Nell' esempio schematico qui sopra abbiamo collegato un display a catodo comune, ovvero costituito da 8 LED con i catodi uniti assieme, mentre gli anodi sono disponibili separatamente. 
Ne risulta che un LED (= segmento) è acceso quando il suo pin di comando assume il livello alto (1) e spento quando assume il livello basso (0).

Ora, sarebbe un lavoro poco produttivo definire, ogni volta che dobbiamo fare apparire una cifra, la corrispondente sequenza di bit 1 e 0 da scrivere nel PORT. Ed in effetti questa non  è la via corretta.
L' alternativa valida è quella di creare una tabella di "scambio" che faccia equivalere il carattere voluto con la giusta combinazione di bit.

Queste tabelle, dette lookup tables (tabelle di ricerca) sono uno degli elementi più comuni nella programmazione dei microcontroller; attraverso queste trattiamo i dati in uscita, che corrispondono in questo caso a caratteri numerici e letterali, semplicemente come elementi esadecimali puri.
La stessa via sarà sfruttata in mille altre situazioni, ad esempio per generare forme d' onda, per correggere valori letti in ingresso, per scambiare formato ai dati, ecc.

Creiamo quindi una tabella che collega carattere da presentare sul display-LED accesi-bit a 1
Detto così sembra complesso, ma non lo è per niente.

Per prima cosa verifichiamo la coincidenza pin-segmento; nello schema presentato sopra abbiamo:  

Segmento Bit del PORT
A 0
B 1
C 2
D 3
E 4
F 5
G 6
dp 7

Verifichiamo quali segmenti vanno accesi per ottenere i caratteri numerici

e facciamo una tabella di collegamento tra caratteri e segmenti:

Carattere Segmenti
A B C D E F G
0 x x x x x x  
1   x x        
2 x x   x x   x
3 x x x x     x
4   x x     x x
5 x   x x   x x
6 x   x x x x x
7 x x x        
8 x x x x x x x
9 x x x x   x x

Nella configurazione a catodo comune, per accendere il LED il pin deve andare a livello 1, quindi aggiungiamo alla tabella il valore logico che devono assumere i pin, in binario e in esadecimale.
Il valore esadecimale è aggiunto in quanto è più semplice da trattare che non la lunga stringa di 1 e 0 del numero binario; e una coppia di cifre esadecimali rappresenta proprio la condizione logica di un byte (8 bit), che è la lunghezza del dato trattato dai PIC che stiamo analizzando. 
(Maggiori informazioni sui sistemi di numerazione qui)..

Carattere Segmenti   Livello Pin Binario HEX
dp G F E D C B A 7 6 5 4 3 2 1 0
0       x x x x x L L H H H H H H 00111111 3F
1           x x   L L L L L H H L 00000110 06
2   x   x x   x x L H L H H L H H 01011011 5B
3   x     x x x x L H L L H H H H 01001111 4F
4   x x     x x   L H H L L H H L 01100110 66
5   x x   x x   x L H H L H H L H 01101101 6D
6   x x x x x   x L H H H H H L H 01111101 7D
7           x x x L L L L L H H H 00000111 07
8   x x x x x x x L H H H H H H H 01111111 7F
9   x x   x x x x L H H L H H H H 01101111 6F

Per accendere il punto decimale basterà portare a livello alto (1) il pin 7.

Questo sistema consente di utilizzare qualsiasi combinazione pin-segmenti che sia necessaria, ad esempio, a causa dei collegamenti sul circuito stampato.

Ora si tratta di convertire questa tabella in modo tale da poter essere compresa dal processore.
La via più semplice è quella di scrivere una tabella RETLW.

Possiamo altresì aggiungere alle cifre numeriche alcuni caratteri alfabetici, ottenuti per accensione di un adeguato numero di segmenti.

;--------------------------------------------------------------
; 7 segments display code Table
;--------------------------------------------------------------
;**************************************************************
;* Table for 7 segment display
;* Displayport: 0 Segment A   AAAAA
;*              1 Segment B   F   B
;*              2 Segment C   F   B
;*              3 Segment D   GGGGG
;*              4 Segment E   E   C
;*              5 Segment F   E   C
;*              6 Segment G   DDDDD
;*              7 Segment dp        dp
GetDigitCode

     andlw   0x0F        ; filter for 16 codes only
     rlncf   WREG, f
     addwf   PCL, f

; segments table for H drive
; pin       76543210
; segment   pGFEDCBA    pos  hex

    retlw b'00111111'  ; 0 - 0x3F
    retlw b'00000110'  ; 1 - 0x06
    retlw b'01011011'  ; 2 - 0x5B
    retlw b'01001111'  ; 3 - 0x4F
    retlw b'01100110'  ; 4 - 0x66
    retlw b'01101101'  ; 5 - 0x6D
    retlw b'01111101'  ; 6 - 0x7D
    retlw b'00000111'  ; 7 - 0x07
    retlw b'01111111'  ; 8 - 0x7F
    retlw b'01101111'  ; 9 - 0x6F
    retlw b'01110111'  ; A - 0x77
    retlw b'01111100'  ; b - 0x7C
    retlw b'00111001'  ; C - 0x39
    retlw b'01011110'  ; d - 0x5E
    retlw b'01111001'  ; E - 0x79
    retlw b'01110001'  ; F - 0x71

Su questa base realizziamo un piccolo programma di verifica.

Il suo flow chart è questo.

Dopo la necessaria inizializzazione del processore e del port utilizzato per il controllo del display, trasferiamo allo stesso le cifre che abbiamo tabellato, una dopo l' altra con un intervallo di tempo tra ogni operazione tale da permetterne la visualizzazione.

Un contatore viene utilizzato per il codice del carattere da presentare, partendo da 0, che. attraverso la tabella genererà la cifra 0.
Il contenuto del counter è incrementato ad ogni passo, producendo la successione dei 16 caratteri tabellati.

Una pausa tra un carattere e il successivo ne permette la visualizzazione.

Quando sono stati esauriti i caratteri disponibili, il ciclo riprende dall' inizio.

La tabella di conversione per i segmenti va considerata un modulo funzionale e quindi si utilizzerà la tecnica di "passare" il dato in uscita attraverso l' accumulatore WREG.

Le routines di tempo sono quelle già viste in precedenza.

 

 


L' esercizio richiede le seguenti risorse:

  • MPLAB IDE installato
  • Pickit3 (o Pickit2)
  • 28-40pin UniBoard con PIC18F2321 0 4321 (o 2221 o 4221 o altro hardware similare)
  • il modulo DISP-1 oppure l' hardware che realizza lo schema equivalente, presentato nella pagina seguente

Il listato sorgente è una estensione di quello già visto negli altri esercizi e che fa da base per tutti i seguenti, aggiungendo gli elementi necessari al nuovo lavoro.


Il template utilizzato contiene qualche elemento di diversità dai precedenti, diventando leggermente più ricco di informazioni, come l' assegnazione iniziale dei pin del processore.

Ed una area di parametri calcolati dall' Assembler, che, non utilizzati in questa esercitazione, saranno invece  pratici in altre occasioni.

;========================================================================
;= DEFINIZIONI =
;========================================================================
; CLOCK frequency = internal osc. - default al POR

XTAL_FREQ equ 1000000          ; INTIO1 1 MHz
CLOCK     equ XTAL_FREQ/4      ; processor clock [Hz]
TCYC      equ 1000000000/CLOCK ; cycle time [ns]

Anche l' assegnazione della RAM necessaria contiene un meccanismo che genera un errore nel caso in cui l' area dichiarata superi la capacità dell' Access RAM del processore.

;========================================================================
;= AREA ACCESS BANK - RAM =
;========================================================================

; bank 0 - 128 bytes
; -------------------
     
CBLOCK 0x00
   
d1                ; 2 bytes per le routines di tempo
   
d2
   
counter           ; contatore a 1 byte
   
end_Accbank0:0    ; dummy for overrun check
     
ENDC
 
if end_Accbank0 > 0x7F ; check for overrun
   
error "Access Bank 0 space overrun"
 endif

Aggiungiamo anche una immagine grafica delle assegnazioni dei pin del port utilizzato.

;========================================================================
;= I/O definitions =
;========================================================================
; Dive display 7 segmenti direttamente collegato a PORTC
; Common Kathode
;
; PORTC map
;| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
;|-----|-----|-----|-----|-----|-----|-----|-----|
;| dp | G | F | E | D | C | B | A |

;
#define SegmentTris TRISC ; direzione port
#define SegmentPort LATC  ; latch uscita port

Il programma vero e proprio parte con un salto, dopo il quale è posizionata la tabella RETLW, il che ne garantisce la localizzazione all' inizio di una pagina di memoria:

;========================================================================
;= PROGRAMMA =
;========================================================================

; vettore del reset
; ----------------

      ORG 0x00
   nop    
     ; per ICD
   goto Main   ; vai al main

Segue dunque la tabella RETLW con i codici dei caratteri da visualizzare e l' equivalente esadecimale.

;-----------------------------------------------------------------------
; 7 segments display code
;-----------------------------------------------------------------------
;***********************************************************************
; Table for 7 segment display
;* Displayport: 0 Segment A   AAAAA
;*              1 Segment B   F   B
;*              2 Segment C   F   B
;*              3 Segment D   GGGGG
;*              4 Segment E   E   C
;*              5 Segment F   E   C
;*              6 Segment G   DDDDD
;*              7 Segment dp        dp

GetDigitCode
     andlw 0x0F        ; 16 codes only
     rlncf WREG, f
     addwf PCL, f
; segments table for H drive
;            76543210
;            pGFEDCBA   chr  hex

     retlw b'00111111' ; 0 - 0x3F
     retlw b'00000110' ; 1 - 0x06
     retlw b'01011011' ; 2 - 0x5B
     retlw b'01001111' ; 3 - 0x4F
     retlw b'01100110' ; 4 - 0x66
     retlw b'01101101' ; 5 - 0x6D
     retlw b'01111101' ; 6 - 0x7D
     retlw b'00000111' ; 7 - 0x07
     retlw b'01111111' ; 8 - 0x7F
     retlw b'01101111' ; 9 - 0x6F
     retlw b'01110111' ; A - 0x77
     retlw b'01111100' ; B - 0x7C
     retlw b'00111001' ; C - 0x39
     retlw b'01011110' ; d - 0x5E
     retlw b'01111001' ; E - 0x79
     retlw b'01110001' ; F - 0x71

Vengono definiti 16 caratteri, con codici da 0h a Fh; i primi 10 sono le cifre da 0 a 9, i rimanenti rappresentano alcune lettere.

Come al solito, il programma è costituito da un numero minimo di istruzioni, dato che gran parte del lavoro viene effettuato dai moduli della tabella e della subroutine di pausa.

;----------------------------------------------------------------------
; Main loop
;----------------------------------------------------------------------

Main:
; I/O setup
     clrf  SegmentPort     ; preset a 0 latch uscita
     clrf  SegmentTris     ; Port comando segmenti = Out

; loop primario
loop clrf counter          ; parte con contatore = 0

; loop secondario
loop1 movf counter, W      ; copia counter in W

     rcall GetDigitCode    ; richiama codice per 7 segmenti

     movwf SegmentPort     ; scrivi in uscita sul port

     rcall Pausa           ; pausa di visualizzazione

     incf  counter, f      ; incrementa counter
     btfss counter, 4      ; counter > 0Fh ?
      bra  loop1           ; no - altro loop

     rcall Pausa           ; si - breve pausa
     bra   loop            ; riprendi dall' inizio

Il programma ricalca il flow chart visto prima.
Il carattere da presentare viene impostato in un counter a partire da 00h (carattere 0) e ad ogni passo del loop viene incrementato, facendo puntare la tabella al codice successivo.
Il test di fine dei codici disponibili si effettua sul valore del bit 4 del counter:se, dopo un incremento, questo bit va a 1, significa che il numero raggiunto (10h) supera il limite di valori codificati in tabella (0Fh).
Quindi il loop viene terminato e riprende il loop primario che ri azzera il counter e riprende da capo.
Una pausa viene inserita ad ogni passo per visualizzare il carattere e una pausa è introdotta anche alla fine del set di caratteri.

La subroutine di pausa è analoga a quelle fino ad ora utilizzate. 

Il sorgente termina con lo statement END.


Se si incontrano errori nella compilazione è opportuno verificarli con la lista di descrizione degli errori e correggere dove si è sbagliato.


Il file compresso di questa esercitazione è scaricabile dall'  area di download.

 

 

Copyright © afg. Tutti i diritti riservati.
Aggiornato il 22/04/11.