ESERCITAZIONE # 12a
   
Esecuzione
Per la verifica dell' hardware vale quanto detto nell' esercitazione
precedente. 
Per il software, il progetto MPLAB è scaricabile
qui. 
Una volta assemblato il sorgente e caricata la memoria del PIC, basta lanciare
il programma con   
 
Run  e, se tutto è a posto, il display visualizzerà il
messaggio di prompt. 
Se questo non succede, dopo aver verificato con cura i collegamenti, provate
a regolare il contrasto: i caratteri dovranno apparire chiaramente. 
E' possibile anche il funzionamento step by step, ma, data la complessa
ripetitività delle routines, è meglio utilizzare breakpoint da posizionare nei
punti in cui si vuole interrompere l' esecuzione. 
 
Il programma esegue la stessa sequenza dell' esercitazione precedente, ovvero: 
  - inizializza I/O per il display
 
  - inizializza il display
 
  - scrive un messaggio, cadenzando la presentazione delle lettere di 0.5
    secondi una dall' altra
 
  - attesa di 2 secondi
 
  - pulisce il display e riporta i cursore all' inizio
 
  - attesa di 1 secondo
 
  - ripresa dal punto 3
 
 
Osserviamo che il programma è uguale al precedente dell' Es 12 ! 
La sostituzione del driver, con gli stessi entry point, permette di mantenere
identico il flusso principale. 
 
Una NOTA
C'è qualcuno che commenta:" Ma come, per comandare un display occorrono
così tante righe di sorgente? Altri autori se la cavano con molto
meno...". 
Certamente vero, basta semplicemente abolire ogni commento "superfluo"
e il testo sorgente si riduce a ben poco; ecco la versione lite: 
 
  
    
      ;********************************************************** 
        ;* lcd8bf_l018.asm 
        ;* Driver per display LCD a caratteri 
        ;********************************************************** 
        ; bus dati su PORTC 
        ; RS su portB,0 
        ; RW su portB,1 
        ; E  su portB,2 
        ;********************************************************** 
        ;---------------------------- 
        LCDIoIni:             ; set I/O per LCD 
            bcf  PORTB,2        
            bcf  PORTB,0       
            bcf  PORTB,1  
            clrf PORTC  
            clrf TRISC  
            bcf  TRISB,2 
            bcf  TRISB,1 
            bcf  TRISB,0 
            return 
         
        ;---------------------------- 
        LCDSwini        ; Inizializzazione per istruzioni. 
            rcall Delay15ms 
            movlw    0x30       ; comando 30h 
            movwf PORTC 
            rcall    LCDclk     ; primo clock 
            rcall    Delay4ms   ; primo ritardo 
            rcall    LCDclk     ; secondo clock 
            rcall    Delay100us  ; secondo ritardo 
            rcall    LCDclk     ; terzo clock 
            rcall LCDrdbfa   ;check per Busy 
            movlw 0x38       ;8 bit/2 linee/ font 5x7 
            rcall LCDWrCmd 
            movlw 0x10       ;display off 
            rcall LCDWrCmd 
            movlw 0x01       ;Clear & Home 
            rcall LCDWrCmd 
            movlw 0x06       ;cursor move l->r 
            rcall LCDWrCmd 
            movlw 0x0E      
        ;display on/cursor off/blink off 
            rcall LCDWrCmd 
            return 
         
        ;---------------------------- 
        LCDwrcmd:  ; Trasmette un comando. Comando in WREG 
             bcf   PORTB,0    ; RS = 0 per comando 
             bra   lcwr 
         
        LCDwrdat:  ; Trasmette un dato. Dato in WREG 
             bsf   PORTB,0    ; RS = 1 per dati 
        lcwr  movwf LCD_portw 
             bcf   PORTB,1 ; RW = 0 per scrittura 
             rcall LCDclk  
        ; reset LCD bus e controlli 
             clrf  PORTC  
             bcf   PORTB,1  
             bcf   PORTB,0  
             return 
         
        ;---------------------------- 
        LCDclk  bsf PORTB,2    ; E = 1 
             nop 
             nop 
             bcf PORTB,2   ; E = 0 
             nop 
             return 
         
        ;---------------------------- 
        LCDrdram:  ; Leggi RAM dall' LCD 
             bcf   PORTB,0    
        ;RS=0 per la RAM 
             bra   lcdr0  
         
        LCDrdbfa:  ; Leggi BF + AC dall' LCD 
             bsf   PORTB,0    
        ;RS=1 per BF+AC 
         
        lcdr0   setf TRISC       ;data port = input 
             bsf   PORTB,1    
        ;RW=1 per leggere 
             nop               ;stabilizzazione 
         
        lcdr1   bsf  PORTB,2     ;E = 1 - abilita LCD 
             btfss PORTB,0     ;RS = 1? 
             bra   notbusy    
        ;n - legge RAM 
        ;s - test busy dall' LCD 
             btfss PORTC, 7    ;se 1 = busy 
             bra   notbusy    
        ;se = 0 busy end 
             bcf   PORTB,2  
             nop 
             nop  
             bra   lcdr1 
        notbusy movf PORTC, w ;salva il dato letto 
             nop 
             bcf   PORTB,2 
             nop 
             nop 
        ; reset LCD bus e controlli 
             clrf  PORTC 
             bcf   PORTB,1  
             bcf   PORTB,0  
             clrf  TRISC  
             return 
         
        ;---------------------------- 
        LCDWrCmd:  ; Trasmette un comando. 
            rcall  LCDwrcmd 
            bra    LCDrdbfa   ; check busy 
         
        LCDWrDat:  ; Trasmette un dato.  
            rcall  LCDWrDat   ; RS = 1 per dati 
            bra    LCDrdbfa 
         
        ;---------------------------- 
        LCDLine1   ;porta il cursore alla linea 
            movlw  0x80      ; linea 1 
            bra    LCDWrCmd 
        LCDLine2   
            movlw  0xA0      ; linea 2 
            bra    LCDWrCmd 
         
        ; end of the module 
       | 
     
   
 
E, per alleggerirlo ulteriormente, possiamo eliminare la strutturazione,
tutti i commenti, la forma in subroutine e scrivere le istruzioni direttamente
nel main... 
E poi ?  Il testo risulta certo più corto, ma è comprensibile ? E'
sensato un procedere del genere ?
 
Dato che:
 
  - La versione "completa" di commenti e costanti non impiega più
tempo ad essere compilata di quella ridotta.
 
   
  - 
Inoltre, trattandosi di un driver, nel sorgente del programma in cui verrà
usato apparirà solamente come una linea di #include. Basta
un comando  NOLIST all' inizio del driver  per impedirne la stampa nel listato
ottenuto dall' assembler, che risulterà leggero al massimo.
 
      
  - E una versione completa di commenti e descrizioni esaustive delle funzioni e
delle procedure  fornisce LO STESSO codice della versione priva di commenti, non
un bit in più !!!
  
 
 
Il driver, una volta scritto e
collaudato, non richiede più di essere nè scritto, nè letto, nè collaudato
ulteriormente: va semplicemente utilizzato richiamando i suoi entry point,
ovvero le funzioni, macro o subroutine, che svolgono un dato compito. 
 
Le versioni lite non sono per niente conformi all' idea che si sta proponendo,
ovvero quella di una programmazione quanto possibile strutturata e modulare, con
macro componenti facili da utilizzare e sorgenti semplici da gestire. 
E questa semplificazione di uso richiede una maggiore complicazione nei vari
moduli. 
Anche solo se non trasformiamo tutti gli assoluti in label, ci troveremo in
difficoltà serie una volta che si renda necessaria una modifica.  
 Ad esempio,
nel listato qui sopra, si è rinunciato ad associare i port con label. Il
risultato è che se si devono usare altri pin, occorre modificare l' intero
listato. Una serie di definizioni label= assoluti permette invece di cambiare le
assegnazioni agendo solo ed esclusivamente nelle definizioni. 
E le molte linee delle assegnazioni e delle label producono lo steso codice di
una versione priva di label e assegnazioni, ma, rispetto a questa, sono
infinitamente più maneggevoli, modulari, modificabili, comprensibili !!! 
 
Un esempio per tutti: per capire cosa faccia un movlw 0xA0 ,
occorre consultare il foglio dati; l' assegnazione di una tabella di comandi=label
esplicativa rende tutto più semplice.
 
Ovviamente ognuno potrà scegliere  la forma e lo stile che più ritiene
adeguata durante la scrittura dei sorgenti.  
Il problema non è la forma, ovvero usare  *** al posto di
 ----  o label maiuscole
al posto di minuscole, nè quanti commenti inserire, ma è quello di
 
  - usare una forma e uno stile che siano chiari  e 
 
  -  il numero di commenti necessari 
a chiarire cosa facciano le istruzioni e 
 
  -  realizzare una programmazione che non
sia fine a se stessa, funzionale solamente all' applicazione contingente, ma che
renda il proprio lavoro, tempo e sforzi impegnati, tale da poter essere
fruttuoso anche in futuro.
 
 
 
 
 |