Guida alla Programmazione in C del PIC, 5° Parte

Nella Quinta Parte si Parlerà dei Supporti Visivi come i Display 7-Segmenti e i Display LCD Proponendo una serie di Programmi di Esempio…

 
 
 
 




 

I DISPLAY 7-SEGMENTI
I display 7-segmenti sono dei componenti passivi che al loro interno racchiudono 8 led di cui sette sono a forma di segmento e uno a forma di punto, i 7 led a forma di segmento vanno a formare un numero decimale in base a quale segmento è acceso.

Ogni LED ha un contatto connesso a un pin univoco del display e l’altro contatto connesso insieme a tutti quelli degli altri e portato in uscita. Il display può essere a anodo comune o a catodo comune in base a quale contatto i led hanno tutti in comune, o l’anodo o il catodo.

display 7-segmenti

I display possono essere composti da una singola cifra, fino a 4 e più cifre. I display con più di una cifra non sempre presentano un contatto per ogni segmento, infatti vengono collegati tutti insieme i led che rappresentano lo stesso segmento del numero, in questo modo attivando un solo pin si attivano più segmenti nella stessa posizione per più cifre, ovviamente vi sarà un contatto in comune separato dagli altri per ogni cifra.

Per avere un numero a 4 o a 2 cifre si usa la tecnica TDM ovvero Time Division Multiplexing, si invia ai pin dei segmenti il segnale per avere il numero e una per volta si attiva la cifra, ad esempio: Se abbiamo il numero “298” si invia ai pin dei segmenti prima i livelli logici adeguati per visualizzare “8” e si attiva tramite il contatto comune della prima cifra quest’ultima. In questo modo si hanno 2 cifre spente e la cifra delle unità che rappresenta “8”, poi si attiva la seconda cifra e si invia ai pin dei segmenti il segnale per visualizzare “9” e così anche per la terza cifra, poi questo processo si ripete ricominciando dalla prima cifra. Si sa che se un led lampeggia velocemente gli occhi lo vedono come sempre accesso, quindi iterando il processo TDM sul display a 3 cifre con una velocità elevata si vedrà il numero “298” per intero.
TDM dISPLAY 7-SEGMENTI

Questo è una tipica connessione per display 7-Segmenti con più di una cifra. Invece dei transistor si può usare un buffer, se invece ho un display ad anodo comune, collego il pin comune a VCC tramite un transistor di tipo PNP o un buffer. Per accendere un segmento si deve avere una tensione di VCC collegata al pin univoco del segmento tramite una resistenza nel caso si ha un display a catodo comune, se invece si ha un display a catodo comune bisogna connettere il pin del segmento tramite una resistenza al pin del microcontrollore e porre questo pin a 0 logico.

 




 

COMANDO DI UN SINGOLO DISPLAY 7-SEGMENTI                               

Nel primo esempio si va a visualizzare su un display 7-segmenti i numeri da 0 a 9. In questo caso non si usa la tecnica multiplexing perchè abbiamo un unico display. Si simula l’utilizzo di un display per un contatore che conta da 0 a 9 e ricomincia da capo.

Prima di tutto si inizializza una variabile chiamata “conta” che sarà il numero visualizzato sul display, la seconda variabile inizializzata è un vettore contenente dieci elementi, questi elementi sono le configurazioni che deve assumere il registro PORTB per visualizzare i numeri.

Nel programma principale vengono configurate tutte le porte come uscite e successivamente implementato un ciclo while infinito.

Il ciclo while contiene un ciclo “for” che inizializza “conta=0”, ad ogni passaggio incrementa la variabile “conta” finchè “conta<10”.

Nel ciclo for si ha nella prima riga un comando per inviare in uscita la configurazione per visualizzare il numero contenuta in posizione “conta” del vettore “segm”, dopo di che si ha un ritardo di un secondo e il ciclo for ricomincia.

Il codice è il seguente:

unsigned short conta;                           //iniz. conta
char segm[10] = {0x3F, 0x06, 0x5B, 0x4F,        //iniz. il vettore segmenti
                 0x66, 0x6D, 0x7D, 0x07,
                 0x7F, 0x6F};
void main() {                              //inizio programma
  TRISB = 0x00;                           //RB0:RB7 uscite
  PORTB = 0x00;                           //RB0:RB7 livello basso

    while(1) {                            //ciclo infinito
      for(conta=0; conta<10; conta++){    //ciclo for che conta
        PORTB=segm[conta];                //RB0:RB7 assumono valore segm[conta]
        Delay_ms(1000);                   //ritardo di un secondo
      }
    }
}

Lo schema circuitale è:

SCHEMA SINGOLO DISPLAY

Il PIC è alimentato con una tensione continua di 5V, R1 porta un livello logico alto su pin 4 del PIC16F84A evitando il reset. Il quarzo e i due condensatori C1 e C2 servono per generare il per il clock.

Nello schema si ha un display a catodo comune, quindi il contatto in comune a tutti i segmenti è catodo ed è connesso a massa come si può vedere. L’anodo dei segmenti invece viene collegato al PIC16F84A tramite le resistenze di protezione da 330Ω.

Se il display a vostra disposizione è ad anodo comune il contatto di anodo va collegato a VCC e il catodo dei segmenti va connesso al PIC16F84A sempre tramite le resistenze di protezione, va inoltre modificato la configurazione delle uscite all’interno del vettore “segm” e si inserisce la configurazione delle uscite per i numeri con display ad catodo comune.

Mikroc fornisce un tools molto utile a questo scopo, cliccando sui segmenti per accenderli questo tools fornisce in fine la configurazione desiderata.

tool 7-segmenti mikroc

Cliccando sull’icona che rappresenta un 7 con un display 7-segmenti si aprirà:

tool 7-segmenti mikroc 2

che ci fornisce le due configurazioni per i diversi tipi di display.

 




 

COMANDO DI UN DISPLAY 7-SEGMENTI A 3 CIFRE

Per pilotare 3 cifre bisogna usare la tecnica TDM sovra citata.

Per realizzare questo programma si realizza un sottoprogramma che riceve un numero intero composto da tre cifre, lo scompone in unità decine e centinaia e poi realizza la tecnica TDM inviando prima la configurazione per visualizzare le unità e attivando la relativa cifra. Stessa cosa per le decine e centinaia fino a visualizzare l’intero numero a tre cifre.

In questo caso il microcontrollore deve principalmente controllare il display 7-segmenti, quindi non può svolgere tante altre funzioni senza andare a creare problemi di visualizzazione. Non si può avere un delay di 1 secondo perché altrimenti si accenderebbero per pochi millisecondi le cifre di unità e decine mentre rimarrebbe accesa solo l’ultima cifra per un secondo, senza poter visualizzare quindi un numero completo.

Nell’esempio sottostante viene visualizzato in modo fisso il numero 137, che in un applicazione reale potrebbe essere ricavato da un ADC oppure da un conteggio tramite interrupt.

Nel codice sottostante si inizializza la variabile “numero” che contiene il numero da visualizzare, è un valore che va da 0 a 999 quindi uso un intero. La variabile “cifra” invece contiene una per volta le cifre delle unità, decina e centinaia quindi un valore da 0 a 9 di conseguenza basta utilizzare un short int senza segno.

La variabile “segm”, come nel caso precedente è un vettore contenente le combinazioni per i numeri da 0 a 9.

Dopo di che vi è il sottoprogramma che esegue la tecnica TDM, riceve un intero ed esegue le operazioni per la visualizzazione, prima di tutto estraggo le unità facendo % 10 del numero, poi attivo la cifra delle unità e configuro PORTB come la configurazione contenuta in posizione “cifra” del vettore “segm”.

Fatto ciò ripeto le stesse operazioni, estraendo prima le decine dividendo il numero per 10 e facendo sempre %10, successivamente estraggo le centinaia dividendo questa volta per 100 e facendone sempre il modulo.

Finite queste operazioni, richiamando di continuo questa funzione è possibile vedere il numero per intero.

Nel programma principale vengono settate tutte le porte come uscite e viene settato il valore di numero ad un valore di 137. Dopo di che viene fatto un ciclo infinito in cui si richiama la funzione che implementa la TDM. In questo ciclo infinito inoltre si possono eseguire altre operazioni se necessarie, ma non possono richiedere troppo tempo.

Il codice è il seguente:

 

unsigned int numero;                        //numero da visualizzare
unsigned short int cifra;                   //iniz. variabile cifra
char segm[10] = {0x3F, 0x06, 0x5B, 0x4F,    //iniz. il vettore segmenti
                0x66, 0x6D, 0x7D, 0x07,
                0x7F, 0x6};

void tre_cifre(unsigned int numero){         //sottoprogramma
            cifra = numero % 10u;            //estrae dal numero le unità
            PORTA = 0b11111011;              //accensione unità con buffer(con transistor 0b00000100)
            PORTB = segm[cifra];             //inizializza la cifra unità

            cifra = (numero / 10u) % 10u;    //estrae dal numero le decine
            PORTA = 0b11111101;              //accensione decine con buffer(con transistor 0b00000010)
            PORTB = segm[cifra];             //inizializza la cifra decine
            
            cifra = (numero / 100u) % 10u;   //estrae dal numero le centinaia
            PORTA = 0b1111110;               //accensione centinaia con buffer(con transistor 0b00000010)
            PORTB = segm[cifra];             //inizializza la cifra centinaia
}


void main() {                     //programma principale

TRISB = 0;                        //Configurazione uscite
TRISA = 0;
numero = 137;                     //numero = 137

  while(1){                       //ciclo infinito
       tre_cifre(numero);         //richiama il sottoprogramma
  }
}

Lo schema è molto simile al precedente, solo che in questo caso si usano 3 buffer per pilotare le cifre del display 7-segmenti. In alternativa si possono usare 3 transistor NPN inviando in uscita 1 invece di 0 come indicato tra i commenti del codice. Lo schema è:

SCHEMA 3 cifre DISPLAY 7-segmenti

Come si può vedere dall’immagine solo un display alla volta riceve il livello logico basso e quindi un display alla volta è acceso anche se i nostri occhi li vedono accesi tutti e tre. Il buffer o il transistor è necessario perché il PIC16F84A, e nessun altro PIC, hanno la capacità di far passare tutta la corrente dei segmenti in un unico pin, quindi una connessione diretta lo brucierebbe.

 




 

IL DISPLAY LCD                                                                                      

L’acronimo LCD significa “Liquid Crystal Display” e sono dei supporti grafici usati come output in molti dispositivi. Gli LCD sono migliori dei 7-segmentim in quanto ormai sono economici, facili da programmare e inoltre non hanno vincoli sui caratteri visualizzabili.

La dicitura LCD 16×2 informa che il display è formato da 2 righe da 16 caratteri ognuna dove ogni carattere viene visualizzato grazie ad una matrice da 5×7 pixel. Esistono vari tipi di LCD.

Il display LCD ha due registri al suo interno, uno per memorizzare i comandi da eseguire (cancellare il display, settare il cursore, inizializzare il display….)  e l’altro serve a memorizzare i caratteri che verranno visualizzati sul display LCD.

La piedinatura del display è:

PIEDINATURA DISPLAY LCD

Il primo pin, chiamato “GND” è il terminale di massa del display, “VCC” è l’alimentazione, tra VCC e massa deve esserci una potenziale di 5V. Il pin “VEE” serve a regolare il contrasto del display, si va a collegare quindi una resistenza variabile come in figura:

CONTRASTO DISPLAY LCD

Il pin “RS” serve a selezionare il tipo di registro da usare, o il registro data o il registro comando, il pin “R/W” seleziona se scrivere i registri o leggere i dati immagazzinati in essi.
Il pin “E” è il pin Enable, quando si invia un fronte di salita su questo pin viene abilitata la lettura dei pin data: questi pin sono “D0,D1,D2,D3,D4,D5,D6,D7” e sono i pin su cui vengono inviati i dati da memorizzare sui registri.

Gli ultimi due pin, “A” e “K” sono i pin del led di retroilluminazione, uno è l’anodo e l’altro è il catodo. L’anodo è collegato tramite una resistenza da 330Ω all’alimentazione, questa resistenza regola la corrente nel LED di retroilluminazione e di conseguenza la luminosità. Si consiglia di non scendere sotto il valore indicato per non bruciare la retroilluminazione.

L’LCD può essere usato in due modalità di invio dati, la prima ad 8bit è più veloce ma richiede 11 linee di comunicazione e quindi 11 pin del PIC, la seconda modalità richiede solo 7 linee di comunicazione anche se è più lenta.

Nel secondo caso il carattere o il comando da inviare al display, composto da un char quindi a 8 bit, viene diviso in 4 LSB e 4MSB e inviati uno per volta, per questo richiede più tempo e meno linee.

Mikroc dispone di una libreria per eseguire tutte le operazioni necessarie per una corretta visualizzazione delle stringhe o dati desiderati.

Purtroppo MIKROC ha la libreria per il display LCD connesso in modalità 4bit, quindi a meno di non scaricare librerie esterne o implementare l’algoritmo da se, la via più semplice è quella di utilizzare questo tipo di comunicazione tra PIC e LCD. Bisogna quindi indicare alla libreria come sono connessi questi due dispositivi e si fa con le seguenti stringhe di codice:

sbit LCD_RS at RA0_bit;                 //CONFIGURAZIONE CONNESSIONI
sbit LCD_EN at RA1_bit;
sbit LCD_D4 at RB0_bit;
sbit LCD_D5 at RB1_bit;
sbit LCD_D6 at RB2_bit;
sbit LCD_D7 at RB3_bit;


sbit LCD_RS_Direction at TRISA0_bit;   //CONFIGURAZIONE PIN I/O
sbit LCD_EN_Direction at TRISA1_bit;
sbit LCD_D4_Direction at TRISB0_bit;
sbit LCD_D5_Direction at TRISB1_bit;
sbit LCD_D6_Direction at TRISB2_bit;
sbit LCD_D7_Direction at TRISB3_bit;

Lcd_Init();                            //INIZIALIZZAZIONE LCD
  

Come sembra logico queste linee indicano che il PIN RS è connesso a al PIN RA0 del PIC e così via, inoltre settano il PIN come output. Infine Lcd_Init(); abilita l’LCD e inizializza le istruzioni base. Quest’ultima istruzione va inserita nel main, le altre prima dell’inizializzazione delle variabili.

Analizziamo prima di tutto i comandi. Per inviare i comandi si usa la seguente stringa:

Lcd_Cmd(Comando_desiderato);

dove i comandi disponibili sono:

Comando LCD Funzione
_LCD_FIRST_ROW Muovi il cursore nella prima posizione della prima riga
_LCD_SECOND_ROW Muovi il cursore nella prima posizione della seconda riga
_LCD_THIRD_ROW Muovi il cursore nella prima posizione della terza riga
_LCD_FOURTH_ROW Muovi il cursore nella prima posizione della quarta riga
_LCD_CLEAR Pulisci il display, pulisce il registro dati
_LCD_RETURN_HOME Muovi il cursore nella posizione originale
_LCD_CURSOR_OFF Rendi invisibile il cursore
_LCD_UNDERLINE_ON Il cursore sottolinea le stringhe
_LCD_BLINK_CURSOR_ON Fai lampeggiare il cursore
_LCD_MOVE_CURSOR_LEFT Muovi a sinistra il cursore senza variare i dati del registro
_LCD_MOVE_CURSOR_RIGHT Muovi a destra il cursore senza variare i dati del registro
_LCD_TURN_ON Accendi il cursore
_LCD_TURN_OFF Spegni il cursore
_LCD_SHIFT_LEFT Muovi i dati del display a sinistra senza variarli
_LCD_SHIFT_RIGHT Muovi i dati del display a destra senza variarli

Il cursore è un puntatore, che nel display LCD è visibile come una linea sotto un carattere che può essere visibile o no e che tiene conto di quale carattere si va a scrivere, si può quindi spostare a piacimento per variare specifici caratteri senza modificarli tutti, concatenare stringhe oppure spostare il testo. Se non indicato diversamente il cursore si muove da sinistra verso destra scandendo tutti i caratteri e arrivato alla fine ricomincia da capo.

Per scrivere invece stringhe di testo si usa il seguente comando:

 

Lcd_Out(1, 3, “NE555.IT”);

 

Questa istruzione serve per scrivere la stringa “NE555.IT” sulla prima riga a partire dalla posizione 3. La posizione di partenza può essere al massimo 16 – dim_stringa, in questo caso 16 – 8 = 8.

 

Lcd_Out_Cp(“NE555.IT”);

 

Serve a scrivere nella posizione corrente del cursore la stringa “NE555.IT”. Si possono usare i comandi per muovere il cursore per cambiare posizione.

 

Lcd_Chr(2, 3, ‘i’);

Lcd_Chr_Cp(‘i’);

 

La prima riga di codice serve a scrivere un singolo carattere sulla seconda riga in posizione 3, la seconda riga di codice invece scrive un carattere nella posizione corrente del cursore.

Finito di illustrare la libreria, lo schema circuitale di connessione è il seguente:

SCHEMA CONNESSIONE LCD

Ad esempio un semplice codice per scrivere la stringa “CIAO A TUTTI” sulla prima riga a partire dalla posizione 2 e la stringa “NE555.IT” sulla seconda riga a partire dalla posizione 4, è il seguente:

sbit LCD_RS at RA0_bit;                     //CONNESSIONE LCD-PIC
sbit LCD_EN at RA1_bit;
sbit LCD_D4 at RB0_bit;
sbit LCD_D5 at RB1_bit;
sbit LCD_D6 at RB2_bit;
sbit LCD_D7 at RB3_bit;

sbit LCD_RS_Direction at TRISA0_bit;       //CONFIGURAZIONE PIN
sbit LCD_EN_Direction at TRISA1_bit;
sbit LCD_D4_Direction at TRISB0_bit;
sbit LCD_D5_Direction at TRISB1_bit;
sbit LCD_D6_Direction at TRISB2_bit;
sbit LCD_D7_Direction at TRISB3_bit;


char txt0[] = "CIAO A TUTTI";            //INIZIALIZZAZIONE PRIMA STRINGA
char txt1[] = "NE555.IT";                //INIZIALIZZAZIONE SECONDA STRINGA

void main(){

  Lcd_Init();                            //INIZIALIZZA LCD

  Lcd_Cmd(_LCD_CLEAR);                   //PULISCI DISPLAY

  Lcd_Cmd(_LCD_CURSOR_OFF);              //RENDI INVISIBILE IL CURSORE

  Lcd_Out(1,2,txt0);                    //SCRIVI TXT0 SULLA PRIMA RIGA
  Lcd_Out(2,4,txt1);                    //SCRIVI TXT1 SULLA SECONDA RIGA

}

 

Ora proviamo a scrivere un semplice codice che visualizza sulla prima riga per un secondo e mezzo la stringa “CIAO A TUTTI” poi questa stringa si cancella e compare la stringa “NE555.IT” che inizia ad oscillare a destra e sinistra sulla seconda riga. quindi i passi da fare sono:

  1. Inizializzazione LCD con definizione della connessione
  2. Inizializzazione variabili
  3. Scrittura stringa “CIAO A TUTTI”
  4. Delay di 1500ms
  5. Pulizia LCD
  6. Scrittura stringa “NE555.IT”
  7. Ciclo infinito
  8. Muovi a destra di n posizioni ogni 250ms
  9. Muovi a sinistra di n posizioni ogni 250ms

Il codice è quindi:

sbit LCD_RS at RA0_bit;                        //CONNESSIONE LCD-PIC
sbit LCD_EN at RA1_bit;
sbit LCD_D4 at RB0_bit;
sbit LCD_D5 at RB1_bit;
sbit LCD_D6 at RB2_bit;
sbit LCD_D7 at RB3_bit;

sbit LCD_RS_Direction at TRISA0_bit;         //CONFIGURAZIONE PIN
sbit LCD_EN_Direction at TRISA1_bit;
sbit LCD_D4_Direction at TRISB0_bit;
sbit LCD_D5_Direction at TRISB1_bit;
sbit LCD_D6_Direction at TRISB2_bit;
sbit LCD_D7_Direction at TRISB3_bit;


char txt0[] = "CIAO A TUTTI";          //INIZIALIZZAZIONE PRIMA STRINGA
char txt1[] = "NE555.IT";              //INIZIALIZZAZIONE TERZA STRINGA
unsigned short int i;                  //INIZIALIZZAZIONE VARIABILE MOVIMENTO

void main(){

  Lcd_Init();                        //INIZIALIZZAZIONE LCD
  Lcd_Cmd(_LCD_CLEAR);               //PULIZIA DISPLAY
  Lcd_Cmd(_LCD_CURSOR_OFF);          //CURSORE INVISIBILE
  
  Lcd_Out(1,2,txt0);                 //SCRITTURA txt0 SU PRIMA RIGA
  Delay_ms(1500);                    //ASPETTA 1.5s
  Lcd_Cmd(_LCD_CLEAR);               //PULIZIA DISPLAY
  Lcd_Out(2,9,txt1);                 //SCRIVI SULLA SECONDA RIGA txt1
  
    while(1) {                       //LOOP INFINITO
    
      for(i=0; i<8; i++) {           //CICLO ESEGUITO 7 VOLTE
        Lcd_Cmd(_LCD_SHIFT_LEFT);    //MUOVI A SINISTRA IL TESTO
        Delay_ms(500);               //ASPETTA 0.5s
      }
    
      for(i=0; i<8; i++) {           //CICLO ESEGUITO 7 VOLTE
        Lcd_Cmd(_LCD_SHIFT_RIGHT);    //MUOVI A DESTRA IL TESTO
        Delay_ms(500);               //ASPETTA 0.5s
      }
    }
}

 

Lo schema in questo caso è uguale identico al precedente.

DOWNLOAD

Potete scaricare tutti i file, compresi di simulazioni e progetti MikroC cliccando sul seguente LINK!!!




 

[Voti Totali: 0 Media Voti: 0]
Segui la Nostra Pagina Facebook: Facebook

2 pensieri su “Guida alla Programmazione in C del PIC, 5° Parte

  1. FANTASTICO
    a 70 anni mi si sta aprendo davanti un mondo nuovo (coadiuvato dal nipotino di 13 anni)
    sino ad ora avevamo utilizzato assembler ma e’ cervellotico e la maggior parte dei programmi non giravano anche se
    il debug di mplab non dava errori – utilizziamo pic 16f84a nella speranza di far girare in autonomia dei minirobot
    complimenti
    come si fa ad approfondire ?
    cordialita’ alex e riky

    • Grazie mille 🙂 se leggete le altre guide si parla anche di strutture hardware come timer counter, interrupt e PWM, la guida sul PIC e microc è abbastanza dettagliata, poi vi consiglio proteus come strumento di simulazione e debug.

Rispondi a ne555 Annulla risposta

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *