Pilotaggio di un LCD con PIC16F91x

I progettisti di sistemi embedded oggi devono affrontare le richieste sempre più massicce di interfacciamento fra l’uomo e le macchine. Queste esigenze si riflettono nel sempre maggior impiego di sistemi quali LCD alfanumerici, custom e TFT. Ecco dunque come approcciare dal punto di vista tecnico queste tecnologie.

La visualizzazione delle informazioni è praticamente una delle caratteristiche più richieste in tutti i settori delle applicazioni elettroniche, come industriale, consume9r, medicale, telecom. Molteplici sono le tipologie di interfaccia HID (Human Interface Devices) che consentono alle macchine di fornire all’esterno informazioni intellegibili dalle persone. A partire dai ben noti display a segmenti led, riportati in figura 1, attraverso  i quali è possibile visualizzare  le sole cifre numeriche ed eventualmente  il punto per i decimali,  si passa agli ormai diffusissimi display  alfanumerici 16x2, ovvero 16 caratteri per due righe.

Figura 1: display a 7 segmenti

Figura 1: display a 7 segmenti

Questi display sono abitualmente disponibili in due formati, con chip di controllo a bordo oppure senza. Nel primo caso, il  chip può esser montato su un piccolo stampato che supporta anche il  vetro (è il  caso del COB, o Chip On Board, rappresentato in figura 2) oppure sul vetro stesso (COG, ossia Chip On Glass).

Figura 2: LCD 16x2 COB.

Figura 2: LCD 16x2 COB.

Chiaramente la scelta dipende dal tipo di applicazione e dal costo che si vuol dedicare al display (un chip on glass costa più di un chip on board). Oltre a questi dispositivi, esiste la possibilità di realizzare un display che invece di utilizzare caratteri e cifre, abbia delle icone realizzate secondo un particolare disegno e secondo ben determinate specifiche. E’ questo il caso dei display LCD custom. Spesso questi dispositivi vengono utilizzati laddove ci siano informazioni complesse da visualizzare, oppure dove l’aspetto estetico della grafica risulta determinante per il prodotto. Si pensi ad esempio ad un cronotermostato ambientale, che deve rappresentare la temperatura ambiente, ma che necessita anche di piccole icone per raffigurare i giorni della settimana ecc... Chiaramente, i costruttori di LCD devono realizzare delle maschere particolari, per cui il costo di un LCD customizzato è molto maggiore di un alfanumerico. Investimenti di questo tipo sono dunque realizzati solo quando le quantità produttive sono molto elevate. Per finire, la riduzione del costo della tecnologia ha reso oggi disponibili in misura sempre maggiore le tecnologie di display a matrice attiva. Questi oggetti, come suggerisce il nome, trasmettono la luce attraverso delle matrici di transitor. Il risultato è una immagine più nitida e luminosa, a partià di dimensioni. Anche i consumi sono molto ridotti, ragion per cui queste nuove tecnologie sono sicuramente preferibili a quella LCD. Chiaramente  i costi sono decisamente maggiori, anche se nell’ultimo anno le cose sono cambiate, dal momento che un numero sempre maggiore di applicazioni utilizzano questa tecnologia, con conseguente riduzione dei costi. Questi oggetti si presentano come matrici di punti (pixel) in grado riprodurre un numero di colori molto elevato (da 256 sino a 65 mila). Grazie a queste combinazioni di colori, si è in grado di riprodurre in maniera assolutamente definita la maggior parte delle immagini, con rese qualitative eccezionalmente superiori rispetto alla tecnologia LCD. A titolo di esempio si veda figura 3.

Figura 3: TFT su board Microchip.

Figura 3: TFT su board Microchip.

La proposta tecnica Microchip

Microchip fornisce microcontrollori ed integrati analogici che aiutano  il progettista ad interfacciarsi con ognuno dei display citati in precedenza. In particolare, la famiglia 16F91X è la soluzione a più basso costo per implementare visualizzazione su un micro ad 8 bit. La famiglia consta di 4 devices, PIC16F913, PIC16F914, PIC16F916, PIC16F917, che si differenziano per pin count, taglio di memoria e soprattutto per numero massimo di segmenti LCD pilotabili. In figura 4 un piccolo specchietto che riassume le caratteristiche dei devices citati.

Figura 4: famiglia PIC16F91x.

Figura 4: famiglia PIC16F91x.

Questi oggetti, avendo a bordo un “LCD Driver Module” sono in grado di generare direttamente la sequenza di controllo nei tempi corretti, in modo da poter pilotare LCD senza controller a bordo in maniera statica o multiplexata. La differenza fra queste due modalità consiste nel pilotare staticamente ogni singolo segmento del LCD, dando così origine ad una accensione persistente del pixel-segmento, oppure nell’accendere a turno i vari segmenti del LCD secondo una logia di tipo matriciale, facendo in modo che la frequenza di pilotaggio rimanga sempre superiore alla frequenza minima chiamata di “persistenza retinica”, pari a circa 16Hz. Basandosi infatti sullo studio effettuato da Roget oltre un seccolo fa, si è dimostrato che se si sottopone una immagine pulsante all’occhio umano con frequenza di pulsazione maggiore dei 30 Hertz, l’occhio umano non percepisce sfarfallii. Per questo motivo è quindi possibile pilotare un numero elevato di segmenti facendo uso di pochi pin dedicati al pilotaggio (funzione riga) e di alcuni altri dedicati alla selezione di alcune regioni (funzione colonna). Proprio per questo motivo, i microcontrollori  di questa famiglia sono costituti da un controllore dei tempi che, interfacciandosi sul DATA bus, raccoglie le informazioni di multiplexing desiderato e, combinando le proprie informazioni di tempo con le informazioni di segmento contenute nei registri LCDDATAx, genera un insieme di segnali che vanno a comporre la matrice di informazione per l’accensione o lo spegnimento dei vari segmenti dell’LCD da pilotare. In figura 5 si riporta lo schema a blocchi della periferica LCD Driver dei PIC in esame.

Figura 5: Block Diagram famiglia PIC16F91x.

Figura 5: Block Diagram famiglia PIC16F91x.

Prendendo ad esempio il modello PIC16F913, potremo pilotare staticamente solo16 segmenti, ma se passiamo ad un pilotaggio in multiplexing 1/2, avremo un massimo di 32 segmenti. Utilizzando invece un multiplexing 1/3 avremo ben 48 segmenti pilotabili. Per finire, il massimo multiplexing supportato dalla famiglia è di 1/4, attraverso  il quale si potranno pilotare, sempre con lo stesso microcontrollore, ben 60 segmenti, ossia più del triplo degli effettivi PIN del micro stesso! (28 pin). In figura 6 una schematizzazione di queste informazioni.

Figura 6: tabella multiplexing - segmenti.

Figura 6: tabella multiplexing - segmenti.

Dal punto di vista pratico, questi multiplexing si traducono anche in un trade-off della potenza inviata all’LCD nell’unità di tempo, che si riflette in un contrasto meno spiccato nel medeismo LCD in caso di pilotaggio in Multiplexing. A questo proposito esiste un parametro, chiamato “Discrimination Ratio” (d’ora in avanti menzionato come D), che fornisce una indicazione della tensione (Von/Voff). Dal momento che nel caso ottimo, ossia nel caso di pilotaggio statico, si ha una Voff di 0 ed una Von di 1, il D è pari ad infinito. A tale proposito si veda figura 7.

Figura 7: Discrimination Ratio nel caso di pilotaggio statico

Figura 7: Discrimination Ratio nel caso di pilotaggio statico

Per quanto riguarda invece, ad esempio, un multiplexing di ½, le tensioni da portare al LCD per fornire tutte le informazioni sono fornite attraverso tre diverse tensioni. La tensione efficace nel caso di pixel acceso è di 1,58 Volt, mentre nel caso di pixel spento è di 1 Volt. Per questo motivo il D vale 1,58. In figura 8 e 9 lo studio di questo caso. Microchip, attraverso una dettagliata analisi dei bias di tensione in funzione dei mux desiderati, fornisce una tabella descrittiva dei diversi valori di Discrimination Ratio, dando origine ad una interessante osservazione.

Figura 8: caso di pixel ON con 1/2 MUX.

Figura 8: caso di pixel ON con 1/2 MUX.

 

Figura 9: caso di Pixel Off con MUX 1/2 e conseguente D ratio.

Figura 9: caso di Pixel Off con MUX 1/2 e conseguente D ratio.

Laddove possibile, è preferibile utilizzare una polarizzazione di 1/3, al fine di ottimizzare  il contrasto finale del LCD che si andrà a pilotare. A tal fine si veda figura 10.

Figura 10: tabella del Discrimintaion Ratio in funzione di Bias e MUX.

Figura 10: tabella del Discrimintaion Ratio in funzione
di Bias e MUX.

 

Figura 11: gestione dei segmenti.

Figura 11: gestione dei segmenti.

I data sheet della famiglia PIC16F91x sono altresì corredati di tabelle indicative delle abbinate COMSEG da utilizzare nel pilotaggio di LCD compositi. Abitualmente,  i fornitori di LCD forniscono una analoga tabella, che consente di “comporre” correttamente la matrice abbinando i singoli  segmenti da pilotare alle accoppiate COM-SEG del microcontrollore. A volte, nei modelli più “pregiati”, si ha anche una rappresentazione grafica delle connessioni dei singoli segmenti verso l’esterno, per avere anche una idea di quali abbinare ottimizzando il microcontrollore  al fine di ottenere una strategia di multiplexing ottima. Per finire, si riporta all’attenzione del lettore una routine complessa (listato 1) attraverso la quale sarà possibile pilotare un LCD di tipo alfanumerico, facendo uso del device PIC16F913.

list p=16F913
#include P16F913.inc
; LCD data bits
#define LCD_D4 PORTD, 0
#define LCD_D5 PORTD, 1
#define LCD_D6 PORTD, 2
#define LCD_D7 PORTD, 3
; LCD data bits
#define LCD_D4_DIR TRISD, 0
#define LCD_D5_DIR TRISD, 1
#define LCD_D6_DIR TRISD, 2
#define LCD_D7_DIR TRISD, 3
; LCD E clock
#define LCD_E PORTA, 1
; LCD read/write line
#define LCD_RW PORTA, 2
; LCD register select line
#define LCD_RS PORTA, 3
#define LCD_E_DIR TRISA, 1
#define LCD_RW_DIR TRISA, 2
#define LCD_RS_DIR TRISA, 3
#define LCD_INS 0
#define LCD_DATA 1
D_LCD_DATA UDATA 0x20
COUNTER res 1
delay res 1
temp_wr res 1
temp_rd res 1
GLOBAL temp_wr
PROG1 CODE
;*****************************
LCDLine_1
banksel temp_wr
movlw 0x80
movwf temp_wr
call i_write
return
GLOBAL LCDLine_1
LCDLine_2
banksel temp_wr
movlw 0xC0
movwf temp_wr
call i_write
return
GLOBAL LCDLine_2
d_write ;write data
call LCDBusy
bsf STATUS, C
call LCDWrite
banksel TXREG
;move data into TXREG
movwf TXREG
banksel TXSTA
;wait for data TX
btfss TXSTA,TRMT
goto $-1
banksel PORTA
return
GLOBAL d_write
i_write ;write instruction
call LCDBusy
bcf STATUS, C
call LCDWrite
return
GLOBAL i_write
rlcd macro MYREGISTER
IF MYREGISTER == 1
bsf STATUS, C
call LCDRead
ELSE
bcf STATUS, C
call LCDRead
ENDIF
endm
;******************************
LCDInit
clrf PORTA
;configure control lines
banksel TRISA
bcf LCD_E_DIR
bcf LCD_RW_DIR
bcf LCD_RS_DIR
movlw b’00001110’
banksel ADCON1
movwf ADCON1
; Wait ~15ms @ 20 MHz
movlw 0xff
banksel COUNTER
movwf COUNTER
movlw 0xFF
banksel delay
movwf delay
call DelayXCycles
decfsz COUNTER, F
goto $-3
;#1 Send control sequence
movlw b’00110000’
movwf temp_wr
bcf STATUS,C
call LCDWriteNibble
movlw 0xff ;Wait ~4ms@20 MHz
movwf COUNTER
movlw 0xFF
movwf delay
call DelayXCycles
decfsz COUNTER, F
goto $-3
;#2 Send control sequence
movlw b’00110000’
movwf temp_wr
bcf STATUS,C
call LCDWriteNibble
movlw 0xFF ;Wait ~100us@20
MHz
movwf delay
call DelayXCycles
;#3 Send control sequence
movlw b’0011000’
movwf temp_wr
bcf STATUS,C
call LCDWriteNibble
;test delay
movlw 0xFF ;Wait ~100us@20
MHz
movwf delay
call DelayXCycles
;#4 set 4-bit
movlw b’00100000’
movwf temp_wr
bcf STATUS,C
call LCDWriteNibble
call LCDBusy ;Busy?
movlw b’00101000’
movwf temp_wr
call i_write
;#6 Display = ON
movlw b’00001101’
movwf temp_wr
call i_write
;#7 Display Clear
movlw b’00000001’
movwf temp_wr
call i_write
;#8 Entry Mode
movlw b’00000110’
movwf temp_wr
call i_write
;DDRAM addresss 0000
movlw b’10000000’
movwf temp_wr
call i_write
;return home
; movlw b’00000010’
; movwf temp_wr
; call i_write
return
GLOBAL LCDInit
; *****************************
LCDWriteNibble
btfss STATUS, C
bcf LCD_RS
btfsc STATUS, C
bsf LCD_RS
bcf LCD_RW
banksel TRISD
bcf LCD_D4_DIR
bcf LCD_D5_DIR
bcf LCD_D6_DIR
bcf LCD_D7_DIR
NOP ; Small delay
NOP
banksel PORTA
bsf LCD_E
; Set high nibble
btfss temp_wr, 7
bcf LCD_D7
btfsc temp_wr, 7
bsf LCD_D7
btfss temp_wr, 6
bcf LCD_D6
btfsc temp_wr, 6
bsf LCD_D6
btfss temp_wr, 5
bcf LCD_D5
btfsc temp_wr, 5
bsf LCD_D5
btfss temp_wr, 4
bcf LCD_D4
btfsc temp_wr, 4
bsf LCD_D4
NOP
NOP
bcf LCD_E ; Send the data
return
; *****************************
LCDWrite
call LCDWriteNibble
BANKSEL temp_wr
swapf temp_wr, f
call LCDWriteNibble
banksel temp_wr
swapf temp_wr,f
return
GLOBAL LCDWrite
; *****************************
;
LCDRead
banksel TRISD
; Set data bits to inputs
bsf LCD_D4_DIR
bsf LCD_D5_DIR
bsf LCD_D6_DIR
bsf LCD_D7_DIR
BANKSEL PORTA
; Set the register select
btfss STATUS, C
bcf LCD_RS
btfsc STATUS, C
bsf LCD_RS
bsf LCD_RW ;Read = 1
NOP
NOP
; Setup to clock data
bsf LCD_E
NOP
NOP
NOP
NOP
; Get high nibble
btfss LCD_D7
bcf temp_rd, 7
btfsc LCD_D7
bsf temp_rd, 7
btfss LCD_D6
bcf temp_rd, 6
btfsc LCD_D6
bsf temp_rd, 6
btfss LCD_D5
bcf temp_rd, 5
btfsc LCD_D5
bsf temp_rd, 5
btfss LCD_D4
bcf temp_rd, 4
btfsc LCD_D4
bsf temp_rd, 4
; Finished reading the data
bcf LCD_E
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
; Setup to clock data
bsf LCD_E
NOP
NOP
btfss LCD_D7; Get low nibble
bcf temp_rd, 3
btfsc LCD_D7
bsf temp_rd, 3
btfss LCD_D6
bcf temp_rd, 2
btfsc LCD_D6
bsf temp_rd, 2
btfss LCD_D5
bcf temp_rd, 1
btfsc LCD_D5
bsf temp_rd, 1
btfss LCD_D4
bcf temp_rd, 0
btfsc LCD_D4
bsf temp_rd, 0
; Finished reading the data
bcf LCD_E
FinRd
return
; *****************************
LCDBusy
; Check BF
rlcd LCD_INS
btfsc temp_rd, 7
goto LCDBusy
return
GLOBAL LCDBusy
; *****************************
DelayXCycles
decfsz delay, F
goto DelayXCycles
return
; *****************************
END
Listato 1

Scrivi un commento

EOS-Academy
EOS-Academy