Progetti - PIC

 

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.



 

 

Copyright © afg. Tutti i diritti riservati.
Aggiornato il 25/09/18.