Tutorials - Elettronica

 
 

8 digit con HC595


Tra i moduli di costruzione cinese con display a 7 segmenti, si trovano diversi modelli che impiegano 8 cifre comandate da due 75HC595. Il costo è talmente contenuto che non ha senso costruirselo con componenti acquistati in negozio.

Abbiamo provato questo modello:

Si tratta di due blocchi da 4 cifre ciascuno comandati da 2 shift register HC595.

Quello provato è venduto da dx.com, che riporta una etichetta JTRON sul retro. 

Simile a questo ne esistono molti altri, di diversi costruttori, che hanno schemi elettrici diversi.

Comune praticamente a tutti, però, è il fatto che non viene fornita alcuna documentazione tecnica, ma solo, al massimo, un driver per Arduino o simili.
Per poter utilizzare il prodotto al di fuori di questo ambito, occorre per prima cosa rilevare lo schema delle connessioni, altrimenti non si conosce la relazione tra le uscite degli shift register e la matrice del display.

Per quello in prova, lo schema è il seguente:

I due blocchi di display sono dei 3641BS, ad anodo comune.

I due HC595 sono collegati in cascata. 
Il primo comanda gli anodi dei display e le sue uscite devono andare a livello 1 per accendere la cifra.
Il secondo comanda i segmenti e le uscite devono andare a livello 0 per accenderli.

Il dato seriale da inviare sarà, quindi, una stringa di 16 bit: i primi trasmessi saranno relativi ai segmenti da accendere, mentre i successivi saranno relativi al digit.

Un circuito comandato da un display controller specializzato, ad es. il MAX7219, necessita solo di ricevere comandi e dati e provvede autonomamente al multiplex dei segmenti.
Nel caso in esame, invece, occorre che il microcontroller determini e comandi i ciclo di multiplex.
Questo richiede di accendere un digit per volta e, complessivamente, il refresh per gli 8 digit non deve superare il tempo di permanenza dell'immagine sulla retina.
In pratica, un refresh a 3ms (333Hz) è troppo lento: il ciclo complessivo occupa 3x8=24ms e questo comincia a evidenziare uno sfarfallio delle cifre.
Invece, un tempo inferiore, ad esempio 2.5ms (400Hz) è il massimo impiegabile (2.5x8=20ms) e 2ms (500Hz) è ottimale (2x8=16ms).

Questo genere di cadenze è facilmente ottenibile con uno dei timer del microcontroller.


Non ci sono resistenze...

Si nota immediatamente un punto che parrebbe a sfavore: la corrente nei segmenti non dispone di alcuna resistenza di limitazione. 

Si tratta, però, di una combinazione circuitale ben particolare: in condizioni statiche, accendendo un solo segmento o tutti e sette più il punto decimale, la corrente assorbita è praticamente costante nell'area dei 50mA (da 47 a 52mA).

Questo vuol dire che, per segmento, la corrente passa da 42mA (1 solo segmento acceso) a 6.5mA (cifra 8 + dp). Questo si nota osservando la differenza tra la luminosità della cifra 1 (24mA per segmento) e quella della cifra 8 (6.5mA per segmento).

Segmenti accesi 1 2 3 4 5 6 7 8
Corrente [mA] 42.3 48.2 49.4 50 50.6 51.3 51.7 51.8

Il fenomeno è dovuto alla caduta di tensione sulle resistenze di conduzione dei MOSFET di uscita degli HC595 (nella versione prodotta da Titan), che sale con l'aumentare della corrente, passando da 140mV a oltre 2.5V ed ha l'inaspettato effetto di mantenere la corrente complessiva pressochè costante.

ATTENZIONE: la misura è stata effettuata accendendo in modo statico UNA SOLA cifra per volta. Se malauguratamente più cifre sono accese contemporaneamente, la corrente complessiva sale a valori tali da riscaldare gli shift register e metterli in pericolo .
Più cifre potranno essere visibili contemporaneamente solo in un ciclo di multiplex, che, per ogni step, ne accende una sola. 

Il pericolo sussiste perchè il pin di Output Enable (OE) è a livello 0, ovvero le uscite sono sempre abilitate, e il pin di Reset è collegato al positivo e quindi all'arrivo della tensione di alimentazione i latch possono contenere valori casuali che accenderanno casualmente più segmenti. Se la situazione permane senza che il multiplex sia avviato, la corrente assorbita può superare ampiamente i 100mA.
Occorre, quindi, tra le prime azioni del processore, azzerare il contenuto dei latch inviando due bytes a 0 (o il primo byte a 1 per i segmenti e il secondo a 0 per gli anodi).in tal senso, un miglioramento del circuito potrebbe essere quello di scollegare il Reset dalla Vcc e interporre una rete RC per dare un impulso di clear ai latch all'arrivo della tensione. 

Durante il ciclo di multiplex, quindi, la corrente media è 50mA circa; la differenza percepita per la diversità della corrente nei segmenti a seconda del numero presentato si attenua per il basso duty cycle impiegato (1/8).

In sostanza, i valori delle correnti non superano i massimi assoluti e sul breve periodo non dovrebbe essere fonte di problemi, ma il concetto di usare la resistenza di conduzione dei MOSFET come limitatore di corrente non è il massimo della correttezza progettuale. A lungo termine è da verificare la reale durata del circuito, anche se, essendo multiplexato, la presenza di tempi off in cui il calore può essere dissipato migliora la situazione.


L'interfaccia di comunicazione.

Un connettore a 5 pin consente di inviare segnali al modulo, mentre un altro connettore è previsto per collegare più moduli in cascata:

# Pin ingresso Pin uscita
Indicazione Funzione Indicazione Funzione
1 GND Alimentazione negativa GND Alimentazione negativa
2 DIO Ingresso dati seriali QH Uscita dati seriali
3 RCLK Impulso di latch RCLK Impulso di latch
4 SCLK Clock di trasmissione SCLK Clock di trasmissione
5 Vcc Alimentazione positiva Vcc Alimentazione positiva

La possibilità di collegare più moduli in cascata si scontra, però, con la necessità di usare una frequenza di refresh molto alta: con 16 display occorre almeno 1kHz (1ms).

L'interfaccia verso il microcontroller è seriale a due fili, dato e clock (chiamati DIO e SCLK), ai quali si aggiunge il segnale di latch (RCLK). I pin OE e RESET dei chip sono connessi rispettivamente al GND ed alla Vcc.

HC595 è adatto ad essere gestito dall'interfaccia SPI del microcontroller e si presta bene ad essere comandato attraverso il modulo MSSP presente su molti PIC. 
Anche se è possibile manipolare i bit necessari senza usare questa periferica, va considerato che HC595 è un componente veloce e ciò consente di usare un clock di trasmissione molto elevato, con una sensibile riduzione dei tempi dell'operazione di scrittura. Da prove fatte, un clock a 1MHz è di tutta sicurezza, mentre si può arrivare tranquillamente a 4MHz e più.

In base a queste considerazioni è stato scritto un semplice driver in Assembly per PIC Enhanced Midrange.


Il driver.

Per le prove è stato usato un PIC16F1509 che consente di avere un clock di 16MHz con l'oscillatore interno ed è dotato di modulo MSSP.

Determiniamo una macchina a 8 stati che è gestita nel ciclo di interrupt e dal contatore dgtcntr.
Ogni stato corrisponde al refresh di un digit.
La maschera dei segmenti da accendere è conservata in un buffer di memoria RAM (dispbuf) a 8 bytes, ognuno dei quali contiene la situazione dei segmenti.
I punti decimali sono conservati in una locazione RAM (dpstac) apposita e sono aggiunti come ottavo bit alle maschere.

Le maschere dei segmenti sono caricate in un buffer momentaneo txbuf1, mentre in txbuf2 sono inseriti i bit per l'accensione degli anodi.

         banksel dgtcntr
; dgtcntr = 7: aggiorna digit 8 - first
; dgtcntr = 6: aggiorna digit 7
; dgtcntr = 5: aggiorna digit 6
; dgtcntr = 4: aggiorna digit 5
; dgtcntr = 3: aggiorna digit 4
; dgtcntr = 2: aggiorna digit 3
; dgtcntr = 1: aggiorna digit 2
; dgtcntr = 0: aggiorna digit 1 - last

        decf dgtcntr,f  ; digitcounter-1
        movf dgtcntr,w  ; come indice per il digit
        brw
        bra  Int_0      ; digit 1
        bra  Int_1      ; digit 2
        bra  Int_2      ; digit 3
        bra  Int_3      ; digit 4
        bra  Int_4      ; digit 5
        bra  Int_5      ; digit 6
        bra  Int_6      ; digit 7
        bra  Int_7      ; digit 8

; il digit 0 è rinfrescato per ultimo
Int_0:                  ; digit più a sinistra
       banksel dgtcntr  ; last digit
       movlw  .8        ; reload digit counter
       movwf  dgtcntr   ; for next loop
       movlw  0x80      ; select common of the digit
       movwf  txbuf2
       movf   dispbuf,w ; load data
       btfsc  dpstatc,0 ; add dp?
        bcf   WREG,7    ; y - add dp
       movwf  txbuf1    ; and copy to tx buffer
       bra    Int_end   ; digit on

Int_1:
       banksel txbuf1
       movlw  0x40      ; select common of the digit
       movwf  txbuf2
       movf   dispbuf+1,w ; load data
       btfsc  dpstatc,1 ; add dp?
        bcf   WREG,7    ; y - add dp
       movwf  txbuf1
       bra    Int_end   ; digit on
       ....

        

txbuf1 e txbuf2 sono utilizzati dalla routine di trasmissione:

Int_end:
       pagesel HC595Wr2Byte
       call    HC595Wr2Byte

.....

;************************************************************************
; HC595Wr2Byte - sub - Write a byte to HC595
; Bytes on txbuf2:1
; Locking routine - wait for BF
;************************************************************************
HC595Wr2Byte:
   GLOBAL HC595Wr2Byte
       banksel txbuf1     ; send txbuf1 to second HC595
       movf    txbuf1,w
       banksel SSPBUF
       movwf   SSPBUF
sswb1  btfss   SSPSTAT,BF ; wait for end of data transmission
        bra    sswb1
       movf    SSPBUF,W   ; clear the flag
       banksel txbuf2
       movf    txbuf2,w   ; send txbuf2 to first HC595
       banksel SSPBUF
       movwf   SSPBUF
sswb2  btfss   SSPSTAT,BF ; wait for end of data transmission
        bra    sswb2
       movf    SSPBUF,W   ; clear the flag
       banksel LATB
       bsf     LCK        ; pulse latch clock
       bcf     LCK        
       return

I due bytes sono shiftati in successione attraverso il modulo MSSP in configurazione SPI:

; configure MSSP for Master SPI
       banksel SSPSTAT
; SSPSTAT       00000000 SPI mode
; SMP  b7       1------- 1 = In data sampled at end of data out time
;                       0 = In data sampled at middle of data out time
;                          allways 0 for slave mode
; CKE  b6       -1------ 1 = Tx on transition from active to Idle clock
;                        0 = Tx on transition from Idle to active clock
; D/A  b5       --0----- 0 - I2C only
; P    b4       ---0---- 0 - I2C only
; S    b3       ----0--- 0 - I2C only
; R/W  b2       -----0-- 0 - I2C only
; UA   b1       ------0- 0 - I2C only
; BF   b0       -------0 1 = Receive complete, SSPxBUF is full
;                        0 = Receive not complete, SSPxBUF is empty

        movlw b'11000000'
        movwf SSPSTAT    ; data transmitted on rising edge

; SSPCON1       00000000 SPI mode
; WCOL  b7      0------- 0 - I2C only
; SSPOV b6      -0------ 1 = New byte is received
;                        0 = No overflow
; SSPEN b5      --1----- 1 = Enables serial port
;                        0 = Disables serial port
; CKP   b4      ---0---- 1 = Idle state for clock is a high level
;                        0 = Idle state for clock is a low level
; SSMP  b3:0    ----0001 0000 = SPI Master, clk = FOSC/4
;                        0001 = SPI Master, clk = FOSC/16
;                        0010 = SPI Master, clk = FOSC/64
;                        0011 = SPI Master, clk = TMR2 output/2
;                        0100 = SPI Slave , clk = SCKx pin, SS enabled
;                        0101 = SPI Slave , clk = SCKx pin, SS disabled

        movlw b'00100001'
        movwf SSPCON1    ; data at FOSC/16, enable SPI

La cadenza dell'interruzione è stabilita con precisione a 2ms dal Timer2:

; configure Timer2 to generate periodic interrupt every 2ms
; postscaler 1:8, prescaler 1:4

        banksel T2CON
; T2CON       b'00000000'
; ni      b7    0-------
; T2OUTPS b6:3  -0111--- 0111 Postscaler 1:8
; TMR2ON  b2    -----1-- 1 = timer on
;                        0 = timer off
; T2CKPS b1:0   ------01 00 = Prescaler 1:1
;                        01 = Prescaler 1:4
;                        10 = Prescaler 1:16
;                        11 = Prescaler 1:64

        movlw b'00111101'
        movwf T2CON
        movlw D'249'
        movwf PR2

L'uso del Timer2 presenta il vantaggio del prescaler e del postscaler, il che consente tempi piuttosto lunghi, mentre all'overflow non occorre ricaricare il contatore. Basta cancellare il flag di interruzione:

; IRQ vector
IRQVEC CODE 0x4

; irq of Timer2 ?
Int_serv:                
     bcf     PIR1,TMR2IF ; cancella flag

Ricordiamo che gli Enhanced Midrange hanno il salvataggio automatico del contesto all'ingresso in interrupt e il ripristino automatico al retfie, cosa comune con i PIC18F.
Se si intende eseguire il programma su un midrange, occorre ricordarsi di aggiungere queste azioni.

Il programma prevede luso di un doppio buffer per i dati da presentare sul display. Esistono quindi:

  • databuf, 8 bytes, che contiene i valori da portare a display e che sarà movimentato dal programma principale

  • dispbuf che contiene i dati trasformati in maschere segmenti

Un ulteriore byte dpstat contiene lo stato dei punti decimali, che può esesere così gestito separatamente dai valori nuumerici. Anche questo è copiato in un byte "operativo" (dpstatc).

La conversione fra valori numerici e maschere è effettuata con una semplice lookup table del genere retlw:

; Convert data from 0 to F in 7-segments mask
; Direct connection: bit0=segm a, bit1=segm b, etc
.
segtblF_16e:
    brw
    retlw b'00111111' ; 6F "0" -|-|F|E|D|C|B|A
    retlw b'00000110' ; 06 "1" -|-|-|-|-|C|B|-
    retlw b'01011011' ; 5B "2" -|G|-|E|D|-|B|A
    retlw b'01001111' ; 4F "3" -|G|-|-|D|C|B|A
    retlw b'01100110' ; 66 "4" -|G|F|-|-|C|B|-
    retlw b'01101101' ; 6D "5" -|G|F|-|D|C|-|A
    retlw b'01111101' ; 7D "6" -|G|F|E|D|C|-|A
    retlw b'00000111' ; 07 "7" -|-|-|-|-|C|B|A
    retlw b'01111111' ; 7F "8" -|G|F|E|D|C|B|A
    retlw b'01101111' ; 6F "9" -|G|F|-|D|C|B|A
    retlw b'01110111' ; 77 "A" -|G|F|E|-|C|B|A
    retlw b'01111100' ; 7C "b" -|G|F|E|D|C|-|-
    retlw b'00111001' ; 69 "C" -|-|F|E|D|-|-|A
    retlw b'01011110' ; 5E "d" -|G|-|E|D|C|B|-
    retlw b'01111001' ; 79 "E" -|G|F|E|D|-|-|A
    retlw b'01110001' ; 71 "F" -|G|F|E|-|-|-|A

Una routine provvede alla copia da uno all'altro buffer, usando i due puntatori indiretti FSR1 e FSR2:

CopyBuf:
; Convert data buffer in segments and copy to display buffer
       banksel lpcntr
       movlw   8             ; 8 step
       movwf   lpcntr
       movlw   LOW (databuf) ; set indirect pointer 1
       movwf   FSR1L         ; to data buffer
       movlw   HIGH (databuf)
       movwf   FSR1H
       movlw   LOW (dispbuf) ; set indirect pointer 0
       movwf   FSR0L         ; to display buffer
       movlw   HIGH (dispbuf)
       movwf   FSR0H
cblp   moviw   INDF1++
       pagesel segtblF_16e   ; convert to segments
       call    segtblF_16e
       xorlw   0xFF          ; invert mask for common anodes
       movwi   INDF0++
       decfsz  lpcntr,f
        bra    cblp
; copy dp status
       banksel databuf
       movf    dpstat,w      ; dp status
       movwf   dpstatc
       return

Le istruzioni specifiche per il controllo dei puntatori movwi e moviw  rendono le operazioni quanto mai semplici.

La tabella di conversione dei segmenti è positiva (1=segmento acceso), ma viene invertita con un XOR dato che si deve applicare ai display che sono ad anodo comune.

Lo spostamento dei buffer viene effettuato se necessario all'inizio del ciclo di refresh del display:

; first digit scanned
Int_7:                     ; right digit
; refresh cycle start point - new data to display?
       banksel flags       ; new data ready?
       btfss   flags,1     ; flag set
        bra    nonew       ; n - don't copy buffer
       bcf     flags,1     ; y - clear flag
       pagesel CopyBuf     ; copy buffer
       call    CopyBuf
nonew:
       banksel txbuf1
       movlw   0x01        ; select common of the digit
       movwf   txbuf2
       movf    dispbuf+7,w ; load data
       btfsc   dpstatc,7   ; add dp?
       bcf     WREG,7      ; y - add dp
       movwf   txbuf1

Il programma principale, quando i dati da presentare sono variati, informa la routine di interrupt del fatto alzando un bit di flag. Se il flag non è posto a 1, la copia viene saltata. 

Il programma demo carica numeri da 1 a 8 con i punti decimali accesi e lancia l'interrupt, terminando con un loop bloccato su se stesso che lascia all'interrupt la gestione completa del display.


Nota:

Usando un Enhanced Midrange, occorre l'ambiente MPLAB-X e almeno il PICKIT3.


Documentazione.

 

Copyright © afg. Tutti i diritti riservati.
Aggiornato il 19/10/17.