Decodifica 1 digit 7 segmenti
|
Una semplice applicazione per dimostrare come un microcontroller può
svolgere una funzione normalmente gestita da una logica integrata "non
intelligente", ovvero come decodifica
per pilotare un display a 7 segmenti.
Certamente utilizzare un microcontroller per questa applicazione può
parere eccessivo, dato che ci sono diversi circuiti integrati specifici per questo
compito.
In generale, però, questi hanno il limite di utilizzare una sola combinazione
ingresso-uscite. Così, ad esempio:
- 7447 accetta un ingresso BCD da 0000 a 1001 per presentare sul display cifre
da 0 a 9.
- DM9368 accetta un ingresso da 0000 a 1111 che rendono in uscita le cifre da 0
a F
- 4055 accetta un ingresso da 0000 a 1111 che rendono in uscita le cifre da 0 a
9 più L, H, P, A,- e blank
e così via.
Se impieghiamo un microcontroller potremo disporre di qualsiasi combinazione
possibile ingressi-uscita, con codifiche di ingresso BCD, esadecimale, gray,
alfanumerico o misto. Infatti, gli ic dedicati sono realizzati per eseguire la
traslazione dei segnali di ingresso in quelli di uscita con una matrice fissa,
mentre nel microcontroller potremo modificare le tabelle di conversione
programmate.
Inoltre, con lo stesso chip, potremo pilotare display sia ad anodo che a
catodo comune.
Per contro, gli integrati dedicati, per la loro struttura a gate che esegue
la conversione "in tempo reale", hanno tempi di risposta dell'ordine
del us o meno. Il microcontroller dovrà, invece, eseguire alcune istruzioni
per catturare gli ingressi, passarli nella lookup table e comandare le uscite e
questo richiede un tempo dipendente dalla frequenza del suo clock.
Il progetto è nato inizialmente per sostituire la decodifica DM9368 che è
da tempo fuori produzione e si è sviluppato in senso più generale per
sfruttare le possibilità offerte dal microcontroller.
Il sistema è stato dotato di una serie di segnali accessori per ampliarne le
funzioni:
- ingresso blanking input - BI
- ingresso latch enable - LE
- ingresso lamp test - LT
- ingresso selezione decodifica - code
- ingresso selezione anodo/catodo comune
I primi 4 ingressi sono sempre attivi e possono essere modificati in
qualsiasi momento.
La selezione del tipo di display, invece, è considerata solamente all'arrivo
dell'alimentazione (dato che, ragionevolmente, non si cambierà certo il
display durante il funzionamento).
Sono necessari 7 pin per il display, 5 per i controlli, 4 per l'ingresso, per
cui dobbiamo utilizzare al minimo un chip a 18 pin.
Abbiamo, quindi, questo diagramma funzionale:
|
Trattandosi di un microcontroller il rapporto tra pin e funzione non
è pre determinato, ma ottenibile attraverso le assegnazioni date nel
programma.
Nel caso in esempio si è scelto di utilizzare il chip con il minor
numero di pin possibile ed assegnare le funzioni ai pin in base a due
considerazioni: il tempo di esecuzione del programma e le esigenze del
circuito stampato del dimostratore, che è a faccia singola.
Se abbiamo necessità di una diversa disposizione dei pin o
intendiamo utilizzare un altro chip, ad esempio a 20 o 28 pin,
basterà modificare adeguatamente il sorgente. |
Questo è lo schema di demo dell'applicazione:
Al microcontroller sono stati aggiunti:
- un display a 7 segmenti, catodo o anodo comune a piacere, con le
relative sette resistenze di limitazione (330-1k a seconda della sensibilità
del display usato). Un jumper a due posizioni J1 permette di collegare il pin comune alla Vdd
per il tipo ad anodo comune o alla Vss per quello a catodo comune, in modo
da poter verificare entrambi i modelli sulla stessa scheda di prova..
- un dip switch rotativo a 16 posizioni S1 per simulare i 4 bit di
ingresso (Copal
S10130A o simile)
- un dip switch a 4 interruttori S3 per i segnali BI, LE, LT e code
- 7 resistenze da 10-22k di pull-up per gli switches
- 1 resistenza da 1k di protezione in serie all'ingresso RB7
Il circuito necessita solamente di un condensatore da 100nf tra i pin
dell'integrato (è stato aggiunto anche un elettrolitico 4.7-10uf nel caso di
alimentazione distante).
Il microcontroller è un PIC16F1826
o 16F1827, Enhanced Midrange a 18 pin, di basso costo (16F628A €1.52
- 16F1826 €1.26 , costo unitario da Mouser alla data della scrittura
di queste pagine).
Nonostante questo, dispone di un elevato numero di periferiche integrate (Timer multipli, CCP,
PWM, MSSP, UART, ecc.) che però non vengono usate. Inoltre dispone di clock interno
programmabile fino a 32MHz, che garantisce un ciclo istruzione di 125ns.
Ovviamente si potrà utilizzare qualsiasi altro PIC a 18 o più pin, ma il
set di istruzioni degli Enhanced Midrange offre alcune interessanti
possibilità nell'uso delle tabelle, cosa che semplifica la scrittura del
sorgente e velocizza l'esecuzione.
Il firmware.
La logica scelta per i segnali di controllo è la seguente:
Pin |
livello |
Funzione |
BI |
1 |
nessuna azione |
0 |
se il dato in ingresso è 0, il display viene spento |
LE |
1 |
il dato ricevuto passa alla decodifica |
0 |
il dato ricevuto non è passato alla decodifica |
LT |
1 |
nessuna azione |
0 |
indipendentemente dal livello applicato a qualsiasi altro pin, tutti
i segmenti sono accesi |
code |
1 |
viene usata la tabella di decodifica 1 |
0 |
viene usata la tabella di decodifica 0 |
K/A |
1 |
il display è a anodo comune |
0 |
il display è a catodo comune |
I segnali BI, LE, LT e code sono sempre attivi e possono essere variati
durante il funzionamento.
La scelta del display catodo/anodo comune è valida solamente all'accensione.
Lo stato di questo pin dipende da come è collegato il comune del display e
determina automaticamente la scelta della giusta gestione.
Ovviamente, modificando il firmware, sarà possibile ottenere qualsiasi
altra combinazione e funzione o attribuire livelli diversi. La scelta del
livello 0 attivo è comune nelle logiche integrate; se non attivo, il pin di
ingresso è mantenuto alto con un pull-up.
La codifica avviene con lookup table a 16 elementi. Nell'esempio sono state
usate le seguenti codifiche:
Input |
tabella
0 |
tabella
1 |
0000 |
0 |
0 |
0001 |
1 |
1 |
0010 |
2 |
2 |
0011 |
3 |
3 |
0100 |
4 |
4 |
0101 |
5 |
5 |
0110 |
6 |
6 |
0111 |
7 |
7 |
1000 |
8 |
8 |
1001 |
9 |
9 |
1010 |
A |
H |
1011 |
B |
L |
1100 |
C |
P |
1101 |
D |
- |
1110 |
E |
° |
1111 |
F |
blank |
Ovviamente, cambiando le tabelle, sarà possibile ottenere qualsiasi altra
combinazione di cifre o segmenti.
Allo scopo di velocizzare al massimo le operazioni di un ciclo, sono state
impiegate alcune soluzioni non comuni:
- è stata duplicata la struttura per il comando separato di display a
catodo ed anodo comune; questo consente di evitare test di una
configurazione fissa dell'hardware durante l'esecuzione, risparmiando
qualche ciclo
- sono state usate tabelle per dirigere il flusso di esecuzione ai vari
segmenti del programma a seconda di come sono i livelli agli ingressi di
controllo. Anche questo riduce di qualche ciclo l'esecuzione.
Inoltre, i segnali di ingresso e uscita sono stati raccolti in modo da
ridurre al minimo le operazioni necessarie per trattarli.
In particolare, per la configurazione è utilizzato un
modo multi riga, più facilmente gestibile delle lunghe righe di AND.
Il programma inizia con la solita introduzione, configurazione e
assegnazione delle risorse.
Nel sorgente proposto viene usato un clock a 8MHz, semplicemente trasformabile
in 32MHz con l'abilitazione del PLL x4.
Non casuali sono le assegnazione delle funzioni ai vari pin
;PORTA map
;| 7 | 6 | 5 | 4 |
3 | 2 | 1 | 0 |
;|-----|-----|-----|-----|-----|-----|-----|-----|
;| LT | LE | BI | HP | D | C
| B | A |
;PORTB map
;| 7 | 6 | 5 | 4 |
3 | 2 | 1 | 0 |
;|-----|-----|-----|-----|-----|-----|-----|-----|
;| KA | c | a | g | f
| b | d | e |
|
- i pin di ingresso dei dati sono dipendenti da RA3:0 in modo da avere una
concordanza tra i livelli logici e i codici BCD
- i pin di controllo sono raccolti nel nibble alto di PORTA, in modo da
poter essere indici di una tabella di salti, come vedremo più avanti
- i comandi dei 7 segmenti occupano i pi RB6:0. Il fatto che siano
disposti come in figura dipende dal circuito stampato di demo, che è
stato realizzato a faccia singola. Non ha alcuna importanza, dato che
possiamo assegnare la funzione al pin e questo non influisce sul tempo di
esecuzione della decodifica.
- il pin di selezione catodo/anodo occupa il bit rimanente.
In particolare, le tabelle di decodifica sono di questo genere:
;********************************************************************
; SegTblHexa_16E.asm
; Titolo : Lookup table per display 7 segmenti.
;
16 elementi Hexa code 0-9, A-F.
;
Il dato da convertire entra ed esce in W
; PIC : 8bit - Enhanced Midrange
; Supporto : MPASM
; Versione : 1.0
; Data : 01-05-2013
; Ref. hardware :
; Autore : afg
;
;********************************************************************
NOLIST
;--------------------------------------------------------------------
;--------------------------------------------------------------------
; segment data table 16 chars. - 7 bit (b6:0) on the same port
SegTblHexa_16E:
brw
start_segtblhexa:
; Tabella retlw di conversione dati-segmenti per display 7segmenti
; Hexa code: cifre 0-9 e A-F
retlw (_sa|_sb|_sc|_sd|_se|_sf)
; 0
retlw (_sb|_sc)
; 1
retlw (_sa|_sb|_sd|_se|_sg)
; 2
retlw (_sa|_sb|_sc|_sd|_sg)
; 3
retlw (_sb|_sc|_sf|_sg)
; 4
retlw (_sa|_sc|_sd|_sf|_sg)
; 5
retlw (_sa|_sc|_sd|_se|_sf|_sg)
; 6
retlw (_sa|_sb|_sc)
; 7
retlw (_sa|_sb|_sc|_sd|_se|_sf|_sg)
; 8
retlw (_sa|_sb|_sc|_sd|_sf|_sg)
; 9
retlw (_sa|_sb|_sc|_se|_sf|_sg)
; A
retlw (_sc|_sd|_se|_sf|_sg)
; b
retlw (_sa|_sd|_se|_sf)
; C
retlw (_sb|_sc|_sd|_se|_sg)
; d
retlw (_sa|_sd|_se|_sf|_sg)
; E
retlw (_sa|_se|_sf|_sg)
; F
;********************************************************************
LIST
|
La tabella crea la corrispondenza tra codice di ingresso a 4 bit e
maschera di accensione dei segmenti del display. I segmenti sono indicati
come label, per poterne variare l'assegnazione fisica.
Variando la tabella, si potranno assegnare ai codici di ingresso tutte le
possibili combinazioni di segmenti.
La corrispondenza pin-segmenti, dipendente dall'hardware, è
programmabile; variando le assegnazioni si potrà ottenere qualsiasi
combinazione:
; segment value for LUT
_sa equ 0x20 ;
RB5
_sb equ 4
; RB2
_sc equ 0x40 ;
RB6
_sd equ 2
; RB1
_se equ 1
; RB0
_sf equ 8
; RB3
_sg equ 0x10 ;
RB4
|
Variando i tempi on/off, possiamo adattare il firmware a LED con differenti
caratteristiche; elementi a bassa luminosità necessiteranno di maggiore tempo
on.
L'inizializzazione dell'hardware è classica: vengono assegnate le
direzioni ai TRIS, disabilitati gli ingressi analogici e settato un clock a
8MHz (quello di default è 500kHz); questo consente di passare a 32MHz
semplicemente abilitando il PLL.
Pur potendo usare pull-up integrati (weak pull-up) sui pin RB0 e RA5, si è
preferito utilizzare pull-up esterni, che, dove non servisse, potranno essere
rimossi.
|
Esaurita l'inizializzazione, il firmware analizza l'ingresso di definizione
del display e deriva l'esecuzione su due mainloop speculari, uno per il
display a catodo comune, l'altro per quello ad anodo comune.
Si tratta di uno
"spreco" di memoria programma, ma consente di velocizzare
l'esecuzione.
Peraltro, 16F826 dispone di 2k (16F1827 ne ha 4), dei quali il
programma completo occupa solamente 159 (mentre non utilizza memoria
RAM). |
I segnali di controllo invece di essere valutati singolarmente, sono
considerati in blocco ed usati come dato di ingresso ad una tabella di 16
salti. Questo riduce il numero delle istruzioni usate e quindi velocizza
l'esecuzione (sempre a scapito dell'impiego di memoria, dato che ogni uscita
dalla tabella corrisponde ad una diversa gestione.
Vediamo quella per il display a catodo comune.
; =========================================================
; mainloops for common anode and common cathode
; jump by table depending from input signals
; LT LE BI HP
; 0 x x x 0 LT=0 set on all segments
; 0 x x x 1
; 0 x x x 2
; 0 x x x 3
; 0 x x x 4
; 0 x x x 5
; 0 x x x 6
; 0 x x x 7
; 1 0 x x 8 LE=0 do nothing
; 1 0 x x 9
; 1 0 x x A
; 1 0 x x B
; 1 1 0 0 C BI=0 + tabella
0
; 1 1 0 1 D BI=0 + tabella
1
; 1 1 1 0 E tabella 0
; 1 1 1 1 F tabella 1
......
; check mode
swapf PORTA,w
andlw 0x0F
brw
bra lamptestK
; 0
bra lamptestK
; 1
bra lamptestK
; 2
bra lamptestK
; 3
bra lamptestK
; 4
bra lamptestK
; 5
bra lamptestK
; 6
bra lamptestK
; 7
bra mainloop_K
; 8 latched
bra mainloop_K
; 9
bra mainloop_K
; A
bra mainloop_K
; B
bra bi0K
; C BI + table0
bra bi1K
; D BI + table1
bra hp0K
; E table0
bra hp1K
; F table1
|
- Se LT=0, qualsiasi siano le altre condizioni, tutti i segmenti del display
sono accesi.
- Se LT=1 e LE=0 qualsiasi variazione dell'ingresso non viene considerata
- Se LT=1 , LE=1 e BI=0, e il dato in ingresso è 0, tutti segmenti sono spenti;
- se il dato è diverso da 0, viene decodificato secondo la tabella indicata
dallo stato del bit HP.
- Se LT=1 , LE=1 e BI=1, il dato in ingresso viene decodificato secondo la
tabella indicata dallo stato del bit HP.
La combinazione delle istruzioni brw e bra
rendono la tabella semplice.
Una struttura speculare è scritta per il display ad anodo comune, dove
sono invertiti i dati in uscita dalla lookup table di decodifica e quanto
inviato al display per il blanking.
Nonostante la presenza dei registri LATB, i comandi in uscita sono inviati
al PORTB per due ragioni:
- si rimane in banco 0 per tutta l'esecuzione del
mainloop (mentre occorrerebbe cambiare banco per passare da PORT a LAT) e
- comandando i segmenti di un display, quindi essenzialmente dei LED, il problema
RMV non si pone.
Ovviamente, nel caso si comandassero carichi capacitivi, occorrerà prendere
in considerazione l'uso del LAT.
Ecco, ad esempio, la gestione per catodo e anodo comune della situazione LT=1 ,
LE=1 e BI=1. Il dato in ingresso è inviato alla tabella di decodifica
e invertito nel caso di anodo comune.
hp1K: movf PORTA,w
; read portA
andlw 0x0F
; only four low bits
call
tabel1 ; decode w/ table1
movwf PORTB
bra
mainloop_K
....
hp1A: movf PORTA,w
; read portA
andlw 0x0F
; only four low bits
call
tabel1 ; decode w/ table1
andlw 0xFE
; invert
movwf PORTB
bra
mainloop_A
|
Il sorgente è compilabile sia per 16F1826 che 16F1827.
Il progetto è realizzato con MPLAB 8.92, ma è altrettanto (e meglio)
gestibile con MPLAB-X.
La scheda demo.
La semplicità del circuito di prova rende possibile una realizzazione su
breadboard, ma, come solito, riteniamo che un circuito stampato sia
decisamente meglio (anche perchè, con un attimo di organizzazione, si passa
dal disegno al circuito in meno di un'ora).
Una nota: lo switch rotativo a 16 posizioni dell'ingresso, se non
disponibile, potrà essere sostituito da uno switch quadruplo come quello
usato per i segnali di controllo e, se non disponibili, entrambi potranno
essere sostituiti da ponticelli a spina.
Le resistenze di pull-up e quelle sui segmenti sono del tipo in array (SIL le
prime e DIL le seconde), ma, ovviamente, si potranno usare resistenze singole.
Il chip usato può funzionare tra 1.8 e 5.5V nella versione F e tra
1.8 e
3.6V nella versione LF. La tensione di alimentazione e le caratteristiche del
display serviranno per dimensionare le resistenze in serie ai segmenti,
tenendo presente il massimo di 25mA (a 5V) di capacità dei pin del
PIC.
Una nota: è possibile risparmiare un jumper collegando il pin K/A al pin
comune del display: se il livello è 1 si tratta di anodo comune, se è 0 è
catodo comune; questo evita errori nella definizione del tipo di display.
Per utilizzare la scheda, basta inserire il display voluto e il jumper che
ne identifica il tipo.
|