Dopo aver visto tutta (o quasi) la teoria che c’è alla base del pilotaggio dei display LCD basati sul controller Hitachi HD44780 (o compatibile) eccoci qui pronti a scrivere qualche programmino di esempio da caricare sul nostro picmicro.
In questa lezione sfrutteremo una libreria per il pilotaggio degli LCD scritta dal sig. Andrea Bonzini e disponibile anche sul sito di Sergio Fiocco.
Tale libreria prevede il controllo dell’LCD in modalità 4 bit e in sola lettura (il pin RW, difatti, andrà collegato a massa e non sarà pilotabile via software). Ho apportato delle piccole modifiche a tale libreria in maniera da avere disponibili anche altre funzioni. L’elenco delle modifiche da me apportate è descritto nel file changelog.txt allegato alla libreria, ho inoltre incluso la libreria originale.
Se spulciate nella cartella “samples” dell’installazione Hitec-C, troverete una routine simile in “LCDemo”
Passiamo a vedere come montare il circuito.
Schema e montaggio del circuito
Anche se in apparenza può sembrare complicato, lo schema in realtà è abbastanza semplice, non vi impressionate:
A parte le porzioni di circuito che abbiamo già visto nelle precedenti lezioni, ci sono le seguenti novità:
- I 4 led: ogni led avrà la sua resistenza da 330Ohm in serie, il terminale lungo del led andrà verso il pic (con la resistenza in serie), il terminale corto verso massa. Il led contrassegnato come LED1 andrà collegato ad RB7 fino ad arrivare a LED4 collegato a RB4.
- I 3 pulsanti: sono contrassegnati sullo schema come BTNOK (collegato a RB2), BTNDOWN (collegato a RB1) e BTNUP (collegato a RB0). I 3 pin del picmicro ai quali sono collegati i pulsanti sono costantantemente alimentati ognuno da una propria resistenza di pullup da 1KOhm. Premendo il pulsante, il pin relativo viene a trovarsi a massa, quindi intercetteremo via software la pressione del pulsante verificando che il pin relativo sia a livello logico basso.
Se si abilitano le resistenze di pullup sulle porte B, non è necessario includere le resistenze da 1KOhm.
- Cicalino: collegato su RE1. Per questa prova è assolutamente necessario utilizzare un cicalino non autooscillante dal momento che genereremo un diverso tono per ogni funzione. La resistenza in serie al cicalino può anche essere omessa.
- Il display LCD. Controllate bene la piedinatura del display che avete in vostro possesso. Il terminale GND va a massa, il terminale Vcc va ai 5 volt positivi, il terminale V0 (contrasto) va collegato al cursore (pin centrale) di un trimmer da 10KOhm, le altre due estremità del trimmer vanno una ai 5 volt e l’altra a massa.
Il terminale dell’LCD contrassegnato come RS (Register Select) lo collegheremo sul pin 21 del 16F877 (RD2).
Il terminare dell’LCD E o EN (Enable) va al pin 22 (RD3)
I terminali da D4 a D7 vanno rispettivamente collegati ai pin da 27 a 30 (da RD4 a RD7)
Se vogliamo, possiamo collegare all’alimentazione i due pin del display destinati alla retroilluminazione.
I rimanenti pin del display vanno posti a massa.
Se utilizzate la scheda Freedom di Mauro Laurenti, è disponibile il connettore LCD, i quali pin portano già alle porte del picmicro qui definite.
La libreria per il pilotaggio dell’LCD
La libreria (lcd.c) è scaricabile in fondo all’articolo insieme ai programmi presentati in queste pagine, è caldamente raccomandata la lettura del codice sorgente da effettuarsi confrontandola con la prima parte di questa lezione: solo così potete capire perfettamente tutta la tecnica che c’è alla base.
Tale libreria comprende numerose utili funzioni, basterà semplicemente includerla nel nostro programma nel modo consueto:
#include "lcd.c"Tale libreria ha bisogno delle routine Delay per poter funzionare, tali routine sono comunque incluse nel download e sono le stesse presenti nelle lezioni precedenti.
Riassumo qui le funzioni disponibili:
LCD_INIT();
Serve ad effettuare l’inizializzazione del display come detto nella parte precedente, va richiamata una solta volta e prima di qualsiasi altra funzione, altrimenti il display non sarà in grado di operare.
LCD_CLEAR();
Effettua la pulizia del display, ovvero cancella il contenuto della DDRAM e porta il cursore nella prima posizione (riga 1, colonna 1).
LCD_CMD(char);
Invia un comando al display, tale funzione viene utilizzata, ad esempio da LCD_CLEAR e da altre, è anche possibile inviare comandi personalizzati, come ad esempio i codici numerici associati ai vari entry mode, sarà comunque una funzione molto poco sfruttata direttamente.
LCD_GOTO(riga,colonna);
Posiziona il cursore per la scrittura alla riga e alla colonna specificata. La numerazione è in base 1, per cui scrivendo:
LCD_GOTO(1,1);
Il cursore si posizionerà alla prima riga, prima colonna.
LCD_PUTCH(char);
Scrive un unico carattere sul display, char ovviamente può essere immesso in qualsiasi formato numerico (decimale, binario -anteponendo come sempre 0b-, esadecimale -anteponendo 0x- o formato carattere -scrivendo il carattere tra singoli apici ”-), è utile per scrivere quei caratteri che non hanno corrispondenza del codice ascii sulla tastiera, come specificato nella precedente parte della lezione: basta avere sottomano la tabella con l’elenco dei codici carattere del controller che abbiamo a disposizione sull’LCD. Esempio:
LCD_PUTCH(0b11110100); //scrive il simbolo omega
LCD_PUTS(“stringa”);
Scrive una stringa intera sul display. Se ci posizioniamo alla prima colonna della prima riga, e abbiamo a disposizione un LCD 16×2 e in tale stringa scriviamo una parola superiore ai 16 caratteri, ovviamente i caratteri dal diciassettesimo in poi non saranno visibili, per cui stiamo attenti quando utilizziamo questa funzione se non vogliamo avere effetti indesiderati sul display. Esempio:
LCD_PUTS("Settorezero.com");
LCD_PUTUN(numero);
Scrive un numero privo di segno sul display, come numero sono accettati il formato CHAR (8bit) o INT (16 bit), per cui sono ammessi numeri interi da 0 fino a 65535.
LCD_PUTSN(numero);
Scrive un numero compreso di segno. Per numeri positivi il segno non viene rappresentato, per numeri negativi, viene anteposto il segno meno davanti al numero. Supporta sia CHAR che INT in ingresso, ovviamente accettando un numero “signed” i valori ammissibili vanno da -32768 a 32767.
LCD_CUSTOMCHAR(pos,byte1…byte8);
Permette la personalizzazione del carattere in posizione “pos”. Vedremo questa funzione nei dettagli nella terza parte di questa lezione, che sarà dedicata soltanto alla personalizzazione dei caratteri.
Il file lcd.c va impostato prima di poter essere utilizzato. Innanzitutto apriamolo e andiamo alla riga 94:
94 95 96 97 98 99 | #define LCD_RS RD2 // Register select #define LCD_EN RD3 // Enable #define LCD_D4 RD4 // LCD data 4 #define LCD_D5 RD5 // LCD data 5 #define LCD_D6 RD6 // LCD data 6 #define LCD_D7 RD7 // LCD data 7 |
Qui impostiamo le linee dati. Se seguite lo schema elettrico proposto in cima alla lezione, vedete che i pin del display (indicati come LCD_XX) sono già associati ai rispettivi pin del picmicro.
Successivamente dalla riga 110 fino alla riga 115 incontriamo altri parametri da impostare:
110 | #define LCD_ROWS 2 // valid numbers are: 1,2 (set to 2 for 2 or more rows) |
Qui va impostato il numero di righe che ha il nostro display, per le nostre prove terremo conto di avere un display da 2 righe, se avete un display da 4 righe dovete comunque lasciare il valore 2, se avete un display da una riga dovrete cambiare il 2 con l’1, ma poi dovrete anche modificarvi i programmi mostrati in questa lezione.
111 | #define LCD_COLS 16 // valid numbers are: 8,16,20 |
numero di colonne dell’LCD, qui utilizzo un display da 16 colonne, se avete un display da 20 colonne, modificate il numero, se avete un display da 8 colonne, oltre al numero dovrete modificarvi anche i programmi.
112 | #define LCD_CURSOR_VISIBLE 0 // 1:cursor on 0:cursor off |
se mettiamo 0, il cursore non sarà visibile, se mettiamo 1, potremo vedere il cursore visualizzato sul display, il quale si presenterà come una lineetta in basso ai caratteri.
113 | #define LCD_CURSOR_BLINK 0 // 1:cursor blinks 0:cursor doesn't blinks |
se mettiamo 0, il cursore rimarrà fisso, impostando ad 1 il cursore lampeggerà
114 | #define LCD_TYPEWRITE 0 // 1:delay between characters |
se mettiamo 0, la scrittura sul display sarà immediata, impostando ad 1, ci sarà un breve ritardo tra la scrittura di un carattere e l’altro, dando un effetto “macchina da scrivere”.
115 | #define LCD_TW_DELAY 50 // milliseconds between characters |
questo rapprenta il ritardo espresso in millisecondi tra la scrittura di un carattere e il successivo, se abilitiamo il settaggio precedente.
Gli ultimi 4 settaggi, relativi per lo più ad effetti grafici, sono già impostati ai valori più adatti per gli esempi, difatti avere la scrittura rallentata, col cursore, in un menù può essere molto fastidioso.
Impostati questi parametri, non abbiamo bisogno più di niente per far funzionare il display (a parte richiamare la funzione LCD_INIT prima di usarlo).
In questa lezione farò 2 esempi di programma: il primo, molto semplice, è il classico “HELLO WORLD!” che non poteva mancare, serve soltanto a farvi capire in maniera molto elementare come scrivere sul display, ed è un tutorial che si trova un po dappertutto, pertanto in questo esempio non faremo uso ne dei led, ne dei pulsanti ne del cicalino. Il secondo esempio, un po’ più elaborato è un semplice menù mostrato sul display, nel quale potremo navigare con i pulsanti e attivare/disattivare le 4 uscite alle quali sono collegati i led, visualizzandone lo stato sul display.
Hello World!
Il file settings è molto semplice, abbiamo soltanto impostato tutte le porte del pic come uscita.
Nel file main.c, dopo la config word, abbiamo le 3 inclusioni:
#include "settings.h" #include "delay.c" #include "lcd.c"
Come già detto in precedenza, è necessario includere prima delay.c e poi lcd.c, in quanto lcd.c fa uso delle funzioni delay.
Abbiamo quindi il main:
void main(void) { settings(); // imposto le porte LCD_INIT(); // inizializzo l'LCD DelayMs(100); // piccolo ritardo iniziale LCD_CLEAR(); // ripulisco il display LCD_GOTO(1,1); // posiziono il cursore sull'LCD: riga1, colonna1 LCD_PUTS("HELLO"); LCD_GOTO(2,1); // riga2, colonna1 LCD_PUTS("WORLD !"); while(1) { } }
Come vedete, dopo aver eseguito le impostazioni, inizializzamo il display come detto prima con l’apposita funzione, personalmente dopo l’inizializzazione do sempre un piccolo ritardo per stabilizzare le linee di comunicazione, in realtà non ce ne sarebbe bisogno.
Effettuo quindi la pulizia del display con LCD_CLEAR(), mi posiziono alla prima riga, prima colonna e scrivo “HELLO”, mi posiziono quindi alla seconda riga, prima colonna e scrivo “WORLD !”, effettuo quindi il ciclo continuo, vuoto, per non far bloccare il pic. Il risultato è il seguente:

Avendo impostato il cursore lampeggiante e l’effetto macchina da scrivere, vedrete il cursore muoversi mentre compone la scritta.
Come vedete, utilizzando una apposita routine, scrivere su un LCD è un gioco da ragazzi: bastano poche righe di codice per avere una gran bella soddisfazione!
Spero non vi siate accontentati di questo semplice esempio, preparatevi perchè vi attende qualcosa di molto più complicato (ma non troppo).
Esempio di semplice menù con LCD e PICmicro
In questo programma, controlleremo lo stato di 4 uscite del picmicro dal display: due tasti (BTNUP e BTNDOWN) ci permetteranno di muoverci su e giù nel menù, un terzo tasto (BTNOK) ci permetterà di cambiare lo stato dell’ uscita selezionata. Lo stato dell’uscita sarà segnalato sul display (e comunque evidenziato anche dall’accensione/spegnimento del led ad essa collegato: tenete conto che al posto dei led potete anche montare dei relè come spiegato nelle precedenti lezioni). Premendo i tasti di navigazione, sarà udibile un suono prodotto dal cicalino, la pressione del tasto OK, invece, produrrà un suono di tipo diverso.
Il menù avrà questo aspetto:

In pratica con i tasti su e giù spostiamo la freccia, posizionandola affiando alla voce desiderata (L1 sta per LED1), premendo OK, cambiamo lo stato dell’uscita selezionata, la scritta affianco quindi si aggiornerà riflettendo lo stato dell’uscita (ON se livello logico alto e quindi relativo led acceso).
Analizziamo prima il file di configurazione, settings.h:
#define BTNUP RB0 #define BTNDOWN RB1 #define BTNOK RB2 #define LED1 RB7 #define LED2 RB6 #define LED3 RB5 #define LED4 RB4 #define PRESSED 0 // per verifica pulsante premuto #define ARROW 0x7E // codice del carattere freccia #define ON 1 #define OFF 0 #define CICALINO RE1
Qui ci sono i vari define, abbiamo soltanto dato dei nomi più semplici da ricordare alle varie uscite/ingressi.
Ho definito un simbolo PRESSED che utilizzerò per fare la verifica del pulsante premuto, avrei difatti potuto fare come sempre:
if (!BTNOK) // oppure if(BTNOK==0) { // istruzioni }
Ma qui espongo invece un metodo alternativo, che può aiutare a capire meglio:
if (BTNOK==PRESSED) { // istruzioni }
avendo definito PRESSED come zero, la sostanza non cambia, ma forse, scritto così, il programma è più semplice da leggere.
C’è quindi un simbolo “ARROW” che corrisponde al codice carattere della freccia rivolta verso destra sul controller HD44780 (vedete la tabella caratteri nella prima parte di questa lezione), ho espresso il codice in esadecimale (come vedete infatti il numero è preceduto da 0x).
Ho quindi definito due simboli ON e OFF, difatti per alcuni il codice è più leggibile se scriviamo:
LED1=ON; // anzichè LED1=1;
Segue quindi il define del cicalino. Proseguendo troviamo:
signed char menupos=0; // variabile che tiene conto della posizione della freccia nel menù
Questa variabile la utilizzo per tenere in memoria la posizione attuale della freccia che utilizzo per navigare nel menù: in alto a sinistra (posizione L1) questa variabile varrà zero, fino ad arrivare al valore 3 nell’ultima posizione (4 posizioni in totale). Le do l’attributo signed perchè può accadere che assuma anche valore negativo.
Segue quindi la funzione settings che non ha nulla di particolare: tutte le porte impostate come uscita, tranne quelle destinate ad alloggiare i pulsanti. I led e il cicalino vengono posti a livello logico basso all’accensione.
La routine lcd.c allegata al progetto (scaricabile insieme al resto in fondo all’articolo per gli utenti iscritti) è configurata in maniera tale da non visualizzare il cursore e da fornire una scrittura diretta (senza ritardi).
Analizziamo quindi il main.c, notiamo qualcosa che fino ad ora non avevamo utilizzato, ovvero i prototipi di funzione:
// prototipi di funzione void main(void); // programma principale void beep(char beeptype); // esegue il beep, usato quando premo i tasti void posizionafreccia(char posizione); // posiziona la freccia nel menù void cambiastato(char posizione); // inverte lo stato del led void scrivistato(char posizione,char stato); // scrive lo stato del led sul display
Come vedete, un prototipo di funzione è la funzione scritta normalmente, ma seguita dal punto e virgola anzichè dalle parentesi graffe contenenti le routine da eseguire (una funzione definita, ma vuota). Questo viene fatto per avvisare il compilatore delle funzioni (che verranno poi definite realmente), in maniera tale da non generare errori se incontra un simbolo che non è stato precedentemente dichiarato, è la stessa cosa che si fa con le variabili: così come dichiaramo una variabile scrivendo:
signed char menupos=0;
Così dichiaramo una funzione, dicendo anche se restituisce o meno un valore e se accetta o meno parametri in ingresso
Ricordo ancora una volta che il void indica che non ci sono valori: il void davanti indica che la funzione non ritorna valori, il void tra parentesi indica che la funzione non prevede argomenti da elaborare.
Nel main prepariamo quindi il display, in maniera da farlo apparire come l’immagine presentata più in alto.
Nel ciclo infinito controlliamo unicamente la pressione dei 3 pulsanti. Ogni pulsante è dotato di antirimbalzo software come spiegato nelle precedenti lezioni. La pressione del tasto BTNUP (SU) decrementa la variabile menupos (che come abbiamo detto serve per tener traccia di dove si trova la freccia: un indice, in pratica, che ci permette di ricordarci in tutto il programma, in quale punto del menù ci troviamo), se il valore di questa variabile diviene minore di zero, allora le assegno il valore 3, in maniera tale che se ci troviamo in posizione 0 e premiamo ancora SU, la freccia verrà a trovarsi in posizione 3 (ultima posizione):
// pressione tasto SU // decremento il contatore che mi posiziona la freccia if (BTNUP==PRESSED) { DelayMs(100); if (BTNUP==PRESSED) { beep(0); // suono menupos--; // decremento la posizione // se in posizione 0 ho premuto su // vado in posizione 3 if (menupos<0) { menupos=3; } // posiziono quindi la freccia posizionafreccia(menupos); } } // fine pressione tasto su
Per chi non lo ricordasse: la seconda verifica della pressione del pulsante, dopo un ritardo, costituisce l’antirimbalzo software come spiegato in una lezione precedente.
All’atto della pressione, richiamo la funzione beep per emettere il suono. La funzione beep accetta in ingresso un valore numerico (da 0 a 2) in maniera tale da emettere un suono diverso (una diversa frequenza) in base al valore che passiamo:
void beep(char beeptype) { char F; switch (beeptype) { case 0: F=70; break; case 1: F=90; break; case 2: F=110; break; } for (char a=40; a--; a!=0) { DelayUs(F); CICALINO=ON; DelayUs(F); CICALINO=OFF; } }
Questa funzione in pratica è uguale a quella vista nelle precedenti lezioni con due sostanziali differenze: il ritardo necessario a generare l’onda quadra è variabile e dipendente dall’argomento passato alla funzione, e inoltre viene eseguito un ciclo di 40 ripetizioni, ma anzichè andare da 0 a 40 come normalmente è spontaneo scrivere, il ciclo viene eseguito al contrario: da 40 verso zero. La sostanza non cambia, ma scritto in questo modo ci permette di rendere il ciclo più efficiente come spiegato in questo articolo su microchipc.
Le funzioni svolte dal tasto BTNDOWN sono pressochè identiche ma eseguite al contrario: il contatore verrà incrementato, se supera il valore di 3, gli verrà dato il valore zero in maniera tale da far ricomparire la freccia in prima posizione.
La pressione di questi due pulsanti (BTNUP e BTNDOWN), richiama la funzione “posizionafreccia” la quale accetta in ingresso il valore di posizione attuale. Tale routine esegue 3 funzioni principali. Prima di tutto cancella (scrive uno spazio) nelle 4 posizioni in cui deve apparire la freccia, in maniera tale da cancellare il carattere freccia precedente:
LCD_GOTO(1,1); LCD_PUTCH(32); // 32=codice dello spazio LCD_GOTO(2,1); LCD_PUTCH(32); LCD_GOTO(1,10); LCD_PUTCH(32); LCD_GOTO(2,10); LCD_PUTCH(32);
Facile capire che quei LCD_GOTO puntano alle posizioni dove le frecce devono comparire:

Successivamente si fa utilizzo di un costrutto switch (vedi manuale Tricky C per sapere come si usa) per analizzare la posizione attuale (passata alla funzione): in base al numero di posizione, viene piazzato il cursore nella “casella” giusta del display:
switch (posizione) { case 0: LCD_GOTO(1,1); break; case 1: LCD_GOTO(2,1); break; case 2: LCD_GOTO(1,10); break; case 3: LCD_GOTO(2,10); break; }
Infine, viene stampato il carattere della freccia:
LCD_PUTCH(ARROW);
Ricordo che abbiamo definito il valore di “ARROW” in settings.h. Come vedete utilizzo la funzione LCD_PUTCH che mi permette di scrivere un solo carattere.
Spero che fin qui sia tutto chiaro: premiamo i pulsanti su e giù e quindi posizioniamo la freccia sul display. Andiamo avanti.
La pressione del tasto BTNOK, produce un beep differente e richiama un’altra routine: cambiastato, alla quale viene sempre passato il valore di posizione attuale. Tale routine definisce innanzitutto una variabile:
char STATO_LED;
la quale serve per tener conto dello stato attuale dell’uscita dopo il cambio. Viene quindi effettuato uno switch in base alla posizione nel menù, in maniera tale da invertire lo stato dell’uscita relativa:
switch (posizione) { case 0: LED1=LED1^1; STATO_LED=LED1; break; case 1: LED2=LED2^1; STATO_LED=LED2; break; case 2: LED3=LED3^1; STATO_LED=LED3; break; case 3: LED4=LED4^1; STATO_LED=LED4; break; }
La variabile STATO_LED, come vedete, memorizza lo stato attuale dell’uscita (del led) che abbiamo selezionato. Infine viene richiamata l’ultima funzione:
scrivistato(posizione,STATO_LED);
la quale ha la funzione di scrivere ON oppure OFF nella posizione relativa sul display: per fare questo dovremo sempre passare la posizione in cui ci troviamo e quindi anche lo stato dell’uscita. Quest’ultima funzione si articola nella stessa maniera delle altre, tranne che per la posizione in cui andare a scrivere. Da notare che ON sarà scritto con uno spazio finale, in maniera tale da cancellare l’ultima lettera (F) di OFF, se tralasciamo lo spazio, apparirà sul display una cosa del genere: L1:ONF
Downloads
Il file zip contiene lo schema elettrico, la routine lcd.c e i codici sorgente e compilati dei due programmi di esempio qui esposti, per ognuno dei due programmi c’è la copia della routine lcd.c già impostata, ho inoltre incluso il foglio excel che ho utilizzato io per disegnare come appare il display, che può essere utile per fare i vostri progetti di menù e ricavare quindi la posizione del cursore.
File di supporto alla settima lezione (parte 2) del corso di programmazione picmicro in C (1417)
Lasciate commenti.
Articoli che potrebbero interessarti
Se desiderate che settorezero continui a rimanere gratuito e fruibile da tutti, non copiate il nostro materiale e segnalateci se qualcuno lo fa

Questo sito e tutto il suo contenuto sono distribuiti sotto la licenza 








#1 da emanuele il 29 novembre 2009
ciao ma e possibile convertire il codice in arduino???
#2 da Giovanni Bernardo il 29 novembre 2009
E’ possibile sicuramente dal momento che arduino ha degli I/O e può essere programmato in C
#3 da cimistrufoli il 1 dicembre 2009
Ciao, t ho già fatto i complimenti e credo ke t sarò riconoscente a vita x questo splendido tutorial sui pic!!! :)
continuando nelle mie prove con il pic 18f452 e utilizzando come board d sviluppo la PICDEM2 sto riscontrando un problema con il display LCD…
lo sto utilizzando in modalita 4 bit, e l’iniziallizazione e il posizionamento del cursone funzionano perfettamente…purtroppo ho un problema con la visualizzazione dei caratteri,perkè dopo aver settato la linea RS a 1 e posto sulle linee dati le prime 4 cifre del codice x la visualizzazione del carattere, quando faccio lo strobe dell’enable appena la linea E diventa atttiva la linea RS torna a 0 e nn riesco a capire il motivo…in fondo sono collegate su due linee distinte della porta A, rispettivamente alla RA1 per RS e RA3 per E!! :(
secondo te pkè nn riesco a mantenere ad 1 entrambe le linee contemporaneamente?
#4 da Giovanni Bernardo il 1 dicembre 2009
Posta il codice che stai usando
#5 da cimistrufoli il 2 dicembre 2009
questa è la libreria LCD ke uso…le porte D e A le setto nel main come uscite cioè a inizio main scrivo TRISA = 0×00; e TRISD = 0×00;
#ifndef FLAG_LCD
#define FLAG_LCD
//*****************************************************************************
// Costanti LCD
#define LCD_D4 PORTDbits.RD0
#define LCD_D5 PORTDbits.RD1
#define LCD_D6 PORTDbits.RD2
#define LCD_D7 PORTDbits.RD3
#define LCD_E PORTAbits.RA1
#define LCD_RW PORTAbits.RA2
#define LCD_RS PORTAbits.RA3
//*********************************************************************************************
//altre costanti
#define LEFT 0
#define RIGHT 1
//*********************************************************************************************
// Funzione ritardo per il display
void delayLCD (int attesa)
{
int i = 0;
for (i; i> 7;
D2 = (Element & 0b01000000) >> 6;
D1 = (Element & 0b00100000) >> 5;
D0 = (Element & 0b00010000) >> 4;
SendCommand (D3,D2,D1,D0);
D3 = (Element & 0b00001000) >> 3;
D2 = (Element & 0b00000100) >> 2;
D1 = (Element & 0b00000010) >> 1;
D0 = (Element & 0b00000001);
SendCommand (D3,D2,D1,D0);
LCD_RS = 0;
}
//*********************************************************************************************
// Funzione che permettere di scrivere sul display una stringa costante
// ESEMPIO WriteStringLCD (“Hello World”) scrivo la stringa costante
void WriteStringLCD(const rom char *buffer)
{
while(*buffer)
{
WriteCharLCD(*buffer);
buffer++;
}
return;
}
//*********************************************************************************************
// Funzione che permette di scrivere una stringa (Array di caratteri) sul display.
// La stringa di caratteri deve avere come ultimo elemento il valore speciale ”
void WriteVarLCD(char *buffer)
{
while(*buffer)
{
WriteCharLCD(*buffer);
buffer++;
}
return;
}
//*********************************************************************************************
// Funzione che pulisce il Display
void ClearLCD (void)
{
SendCommand (0,0,0,0);
SendCommand (0,0,0,1);
}
//*********************************************************************************************
// Questa funzione permette di settare visibile o invisibile il cursore del display e il suo lampeggio
// 0 = Invisibile 1 = Visibile
void CursorLCD(char ON_OFF,char Blink)
{
SendCommand (0,0,0,0);
SendCommand (1,1,ON_OFF,Blink);
}
/************************************************************************************************
* Inizializza il display LCD : queste funzione deve essere utilizzata una sola volta e sempre *
* prima di iniziare ad utilizzare le altre funzioni. Lo scopo è inizializzare il display, *
* pulire le righe, posizionare il cursore all’inizio e togliere il suo lampeggio. *
* N.B.: una mancata esecuzione di tale funzione lascia scura la prima riga del display *
*************************************************************************************************/
void OpenLCD(void)
{
LCD_RS = 0;
LCD_E = 0;
delayLCD (4000);
SendCommand (0,0,1,1);
delayLCD (4000); // delay is more than 4mS
SendCommand (0,0,1,1);
delayLCD (4000); // delay is more than 4mS
SendCommand (0,0,1,1);
delayLCD (4000); // delay is more than 4mS
SendCommand (0,0,1,0);
SendCommand (0,0,1,0); // invio al display il comando 0010 1000 che indica
SendCommand (1,0,0,0); // al display l’interfaccia a 4 bit, 2 righe e grandezza font 5×8
SendCommand (0,0,0,0);
SendCommand (1,1,1,0);
CursorLCD (1,0);
ClearLCD ();
}
/****************************************
Writes unsigned numbers to the LCD
FUNZIONE PRESA DALLA TUA LIBRERIA LCD :)
*****************************************/
void visualizza (unsigned int visio)
{
unsigned char t1,i,wrote;
unsigned int k;
wrote=0;
for (i=4;i>=1;i–)
{
switch(i)
{
case 4: k=10000;
break;
case 3: k=1000;
break;
case 2: k=100;
break;
case 1: k=10;
}
t1=visio/k;
if((wrote)||(t1!=0))
{
WriteCharLCD(t1+’0′);
wrote=1;
}
visio-=(t1*k);
}
WriteCharLCD(visio+’0′);
}
#endif
#6 da cimistrufoli il 2 dicembre 2009
scusa nn so cosa ho toccato ma mi si è cancellato un pezzo…
void delayLCD (int attesa)
{
int i = 0;
for (i; i> 7; // Splitting of the first nibble
D2 = (Element & 0b01000000) >> 6;
D1 = (Element & 0b00100000) >> 5;
D0 = (Element & 0b00010000) >> 4;
SendCommand (D3,D2,D1,D0);
D3 = (Element & 0b00001000) >> 3; // Splitting of the second nibble
D2 = (Element & 0b00000100) >> 2;
D1 = (Element & 0b00000010) >> 1;
D0 = (Element & 0b00000001);
SendCommand (D3,D2,D1,D0);
LCD_RS = 0;
}
#7 da cimistrufoli il 2 dicembre 2009
ok copiando e incollando il pezzo mancante da notepad++ viene fuori sempre la stessa cosa, cioè m elimina un pezzo di codice :(
provo a mandarti via mail il codice sxando ke nn si cancelli nuovamente il pezzo!!
#8 da Giovanni Bernardo il 2 dicembre 2009
Ricevuto. Dato che è parecchia roba devi darmi un po di tempo per controllarlo, nel frattempo prova ad utilizzare soltanto la mia libreria lcd e vedi se ti funziona, le modifiche che devi fare per usarla con un pic18 a quanto vedo sono ben poche, oppure forse funziona già così… Fai una prova.
#9 da Giovanni Bernardo il 2 dicembre 2009
Dando uno sguardo rapido, posso dire che quel “DelayLCD” non mi piace affatto, non tiene conto della frequenza del quarzo utilizzato, per cui a 40Mhz quel ritardo sarà brevissimo, sarà più lungo con un quarzo da 10MHz ecc ecc, quindi già con questo i ritardi non vengono rispettati, e i ritardi sono essenziali per gestire le corrette temporizzazioni. Usa il DelayMs come nel mio codice, ma arrivati a questo punto ti direi di modificare la mia libreria per usarla col C18, sono pochissime modifiche da fare (al posto di RB6, ad esempio, devi mettere PORTBbits.RB6), ma almeno ti rendi indipendente dal quarzo assicurando la giusta temporizzazione. Tieni conto, inoltre, che non tutti i controller, pure se dichiarati compatibili, hanno le stesse temporizzazioni e a volte pure un millisecondo fa la differenza. Il codice originale che usavo io, difatti, testato su un HD44780 a me dava problemi col KS0066: ogni tanto la seconda linea del display non appariva, ho aumentato di poco i ritardi e ora funziona sia con l’uno che con l’altro.
#10 da cimistrufoli il 2 dicembre 2009
ho pensato di fare proprio quello, cioè usare la tua libreria modificando solamente la dichiarazione dei pin dell’LCD per impostarle come predefinite dalla board ma niente da fare…mi da lo stesso errore!!
ho fatto un altra prova: ho provato ad impostare i pin di comando dell’LCD sulla porta D (bit 7, bit6, bit5), e in questo caso nn ho avuto nessun problema ad impostare ad 1 contemporaneamente la linea E e la linea RS e il progetto funziona!!peccato ke nella PICDEM siano collegati i piedini sulla portA e nn posso cambiarli…tornerò a leggere il datasheet del pic 18f452 x vedere d scoprire come mai la portA si comporti differentemente dalla portD!!
#11 da Giovanni Bernardo il 2 dicembre 2009
Ho dato uno sguardo rapido, l’unica porta a collettore aperto è la RA4, per cui se usi RA4 non puo darti il livello logico alto se non metti una resistenza di pullpup, secondariamente il banco A sul 18F452 è anche analogico, per cui abbi l’accortenza di settare le porte in digitale anzichè in analogico, questo magari lo fai prima di richiamare la libreria LCD.
#12 da Giovanni Bernardo il 2 dicembre 2009
Non è che la porta A è a collettore aperto? In questo caso non è in grado di fornire il segnale logico alto ma solo quello basso, in questo caso devi mettere una resistenza di pullup sui piedini interessati. Ora controllo pure io il datasheet.
#13 da cimistrufoli il 3 dicembre 2009
è proprio quello che ho fatto ieri sera dopo aver rivisto la parte sulle porte del datasheet!! :) m sono accorto infatti che non impostando il registro ADCON1 in modo da far funzionare la porta in modo digitale queste lavorano come analogiche!!! adesso funziona anche con i pin del display collegati alla portA!!
Grazie ancora x il tempo dedicatomi…utilizzerò la tua libreria così da non avere problemi di temporizzazione!! ;)
#14 da Giovanni Bernardo il 3 dicembre 2009
:) ok, ottimo.
#15 da S.D.R. il 21 febbraio 2010
Ciao Gianni ;
Ho notato che hai messo sul Setting.h l’istruzione “define BTN4 RB3″ e poi l’hai inibita come testo e poi hai prediposto la main per una terza tonalità di suono per il cicalino ,
Avevi intenzione di fare altre cose ?
#16 da Giovanni Bernardo il 21 febbraio 2010
Il BTN4 l’ho messo perchè avevo fatto una schedina con 4 pulsanti e 4 led da collegare interamente alla porta B, ma per quell’applicazione il 4° pulsante non lo utilizzavo quindi l’ho commentato. Il tipo di suono per il cicalino è una possibilità in più che ho rimasto così… giusto per far vedere in che modo si può fare per suonare diversamente…. Mi fa piacere che te ne sei accorto, sei molto attento.
A tal proposito, visto che sei così interessato all’argomento, ne approfitto per renderti partecipe di uno stupendo link che ho trovato girovagando: http://www.romanblack.com/picsound.htm leggi attentamente anche l’algoritmo, concettualmente è abbastanza semplice anche se ancora non ho capito bene come metterlo in pratica. Qui: http://www.talkbotbrain.com/TalkBot_SourceFiles.htm ci sono anche dei sorgenti di esempio, però scritti in MikroC. Il primo che riesce a combinarci qualcosa… Dà un colpo… ok? VALE PER TUTTI QUELLI CHE STANNO LEGGENDO!!!! ;) Penso sia una cosa davvero stupenda… Suonare un wav con un pic, senza costosi hardware esterni… Una favola non trovi? Pensa alla marea di applicazioni che si possono creare
#17 da subliminal il 26 febbraio 2010
ciao giovanni….ho provato a scaricare i tuoi file di questa lezione per poterli testare…quando ho importato i file in MPLAB e dopo compilato ho avuto una serie di errori…mi potresti aiutare?
#18 da Giovanni Bernardo il 26 febbraio 2010
Spero che hai letto le prime lezioni. Devi importare solo “main.c” e non tutto
#19 da Luca il 7 marzo 2010
Stavolta ti contatto proprio per disperazione, sono ancora fermo ancora all’hello world. Il display è questo http://cgi.ebay.it/ws/eBayISAPI.dll?ViewItem&item=390156241378&ssPageName=STRK:MEWNX:IT
il resto già lo sai.
Modificato l’ lcd.c impostando le porte giuste , cancellando il setting.h e includendo nel main TRISA=0 e TRISB=0 e INTCON=0 (perchè usarlo?), ho messo anche dei led per una sorta di debugging, noto che: il programma funziona a dovere poichè i led di controllo mi notificano che il programma funziona e non si blocca (ho messo che il primo si spegne prima dell’inizializzazione ed il secondo si spegne prima del ciclo while (anche questo, a cosa serve?). Ma sopratutto il problema è: sullo schermo per un’istante si intravede un cursore fuggire via, poi lo schermo bianco…(o nero, dipende da come regolo il trimmer). Sono due giorni che riprovo daccapo, rifacendo tutto nuovamente ogni volta, dal circuito al programma, ed ho provato anche tre display diversi…
Qualche hint? Mi stanno proprio cadendo le braccia…
#20 da Giovanni Bernardo il 7 marzo 2010
Ho visto il datasheet di quel particolare display, la piedinatura è corretta. Prova, nel file lcd.c, a mettere a zero l’impostazione per il cursore e l’impostazione per l’effetto “macchina da scrivere”. Poi: non mi hai detto che pic stai usando. Adesso non ne ho idea, ma se stai utilizzando un circuito diverso non tutto potrebbe essere uguale. La porta RA4, per esempio, su quasi tutti i pic è a collettore aperto, il che vuol dire che non può fornire il segnale logico alto ma solo il basso, è quindi necessaria una resistenza di pullup (un 10K verso il +5V). Se stai utilizzando la porta RA4 senza la resistenza di pullup per comandare l’lcd, questo potrebbe essere uno dei problemi. La dimenticanza del resistore di pullup su RA4 quando viene usato come uscita è un errore molto comune. (leggete sempre bene il datasheet! All’ inizio c’è una pagina in cui, per ogni pin, viene indicato come funziona). Poi sono importanti le temporizzazioni come spiegato all’inizio dell’articolo, se ancora non va, prova ad aumentare un poco i ritardi nei “Delay” messi nell’ultima funzione di lcd.c, che si occupa del settaggio dell’ LCD. Come spiegato, alcuni controller, pur essendo compatibili, hanno dei tempi leggermente differenti. Se ancora non va, dimmi che pic stai usando, e a quali linee hai collegato l’ LCD.
Poi:
INTCON=0; (perchè usarlo?) => difatti l’ho messo a zero e quindi non lo sto usando! Ho incluso l’istruzione perchè vorreste poterlo usare.
Il ciclo while(1), come già spiegato, serve per far eseguire all’infinito la parte di programma incluso in esso, trattandosi solo di visualizzare una scritta sul display, potrebbe anche essere omesso ma è buona regola usarlo sempre per non perdere l’abitudine e incorrere in errori. Alcuni dicono che ci vuole per forza per non far bloccare il pic, in realtà non è vero niente perchè se provi a toglierlo, in questo esempio, tutto dovrebbe funzionare lo stesso. Si mette quando una parte di programma deve essere eseguita di continuo, altrimenti, ovviamente, giunti all’ultima istruzione il programma termina.
#21 da Luca il 7 marzo 2010
Sto usando un pic16f628a, quarzo 20mhz esterno, data4-7 rb0-rb3 , en ra3, rs ra2. Su rb4 e rb5 ho i due led di controllo. I tempi da modificare sono quelli di lcd_init? I tempi del main li ho già aumentati leggermente.
RA4 non l’ho utlizzata…
:-S veramente non sò più dove mettere mano…
Piedinatura LCD/Funzione/relativo Pin pic16f628a
1 gnd gnd
2 vdd vdd
3 V0 trimmer
4 RS RA2
5 R\W gnd
6 E ra3
7-10 data 0-3 gnd
11-15 data4-7 RB0-RB3
15 leda vdd
16 ledb gnd
Main:
————————————————
#define XTAL_FREQ 20MHZ
#include
__CONFIG (UNPROTECT & LVPDIS & BORDIS & MCLREN & PWRTEN & WDTDIS & HS);
#include “delay.c”
#include “lcd.c”
#define LED RB5 // invece di scrivere RD0, scriverò LED, così mi è più facile ricordare
#define LED2 RB4
void main(void)
{
TRISA=0b00000000;
TRISB=0b00000000;
INTCON=0b00000000;
LED2=1;
LED=1;
DelayMs(500);
LED=0;
LCD_INIT(); // inizializzo l’LCD
DelayMs(100); // piccolo ritardo iniziale
LCD_CLEAR(); // ripulisco il display
LCD_GOTO(1,1); // posiziono il cursore sull’LCD: riga1, colonna1
LCD_PUTS(“Ciao”);
LCD_GOTO(2,1); // posiziono il cursore sull’LCD: riga2, colonna1
LCD_PUTS(“Funzionaa”);
LED2=0;
while(1){}
}
————————————————
Impostazioni in lcd.c:
#define LCD_RS RA2 // Register select
#define LCD_EN RA3 // Enable
#define LCD_D4 RB0 // LCD data 4
#define LCD_D5 RB1 // LCD data 5
#define LCD_D6 RB2 // LCD data 6
#define LCD_D7 RB3 // LCD data 7
…
#define LCD_ROWS 2 // valid numbers are: 1,2 (set to 2 for 2 or more rows)
#define LCD_COLS 16 // valid numbers are: 8,16,20
#define LCD_CURSOR_VISIBLE 1 // 1:cursor on 0:cursor off
#define LCD_CURSOR_BLINK 1 // 1:cursor blinks 0:cursor doesn’t blinks
#define LCD_TYPEWRITE 1 // 1:delay between characters
#define LCD_TW_DELAY 200 // milliseconds between characters
… — … !!!!
#22 da Giovanni Bernardo il 7 marzo 2010
Sotto il define del quarzo c’è un include vuoto, toglilo.
Non puoi mettere 500 come valore in DelayMs, quella funzione accetta un char come argomento, quindi puoi mettere massimo 255, così come sta ti causa il blocco del pic. E poi aumentare quel ritardo non serve a nulla. Dopo fatta questa modifica riprova, se ancora non va prova poi a mettere tutti le linee di controllo su un’unica porta, tutto solo su PortB o tutto solo su PortA.
#23 da Luca il 7 marzo 2010
Avevi ragione, ho spostato tutto sulle porte B ed ora funziona; ma com’è possibile? Sembra che il problema sia sul RA2 col Register Select, poichè se sposto il rs sulle porte B e rimango l’Enable sul RA3 funziona. Qualche idea?
Ps. Hai ragione sul DelayMs; ma ignorando il problema anche dandogli in pasto x>255 mi ha sempre funzionato..bha..strano sul serio!
Quando ho tempo finisco la lezione, ora scappo, e grazie mille per la disponibilità. Buona domenica
#24 da Giovanni Bernardo il 7 marzo 2010
Suppongo sia sempre legato a qualche problema di temporizzazione dovuto al collegamento delle linee di controllo del display su due banchi diversi e/o ottimizzazione del codice scritto in C da parte del compilatore
#25 da Epicus il 12 marzo 2010
Ciao, io sono alle prime armi con la programmazione dei pic, quindi probabilmente mi è sfuggito qualche cosa…
In pratica al momento ho assemblato il circuito esattamente come indicato sul tuo schema (tranne per il fatto che sto usando un pic18f4550), dopo innumerevoli tentativi adesso ho provato ad utilizzare il codice che ho scaricato qui (supporto lezione) senza modificare nulla…però mi da lo stesso problema.
In pratica quando tento di compilare mi da una fila di errori
undefined identifier “RD3″
undefined identifier “RD4″
undefined identifier “RD5″
undefined identifier “RD6″ …ecc ecc
e la stessa cosa mi succede con qualsiasi programma…
qualche consiglio?
ps:Sto usando mplab ide 8.46 e Hitec Pic e Pic18
#26 da Giovanni Bernardo il 12 marzo 2010
Per i pic18 le definizioni sono differenti. Ti riscrivo quello che ho scritto in un commento precedente :
“sui pic18 per controllare le porte, oltre ai registri TRIS e PORT hanno introdotto un terzo registro chiamato LAT che è direttamente connesso al latch che controlla lo stato della porta fisica. In realtà i registri LAT e PORT dovrebbero svolgere la stessa, identica, funzione ma operano a livelli diversi: può difatti succedere che impostiamo un pin a livello alto ma in realtà il circuito esterno, a causa di problemi, potrebbe non permettere questo per cui il pin rimane basso e quindi avremo che per quel pin i registri PORT e LAT porteranno due valori discordanti. Il cambiare stato del pin con un’istruzione o con l’altra potrebbe portare a questo tipo di problemi.”
Poi, sui pic18 non si identifica il singolo bit della porta con “RD7″ ma con LATD7 o PORTD7.
Comunque troverai altri problemi di sicuro, leggi il manuale del pic18 oppure scarica il corso sui pic18 su http://www.laurtec.com
#27 da Epicus il 12 marzo 2010
grazie 1000 :)
#28 da MayTs il 18 aprile 2010
ciao,
ho collegato il display come nel circuito postato, ma il display rimane bianco.
ho quindi scollegato tutto per ricercare il problema(forse nei collegamenti), e così ho provato a collegare solo l’alimentazione del display per vedere se intento questo funziona.
Risultato: alimentando solo il pin1(GND), il pin 2(+5), ed il pin3 con opportuno trimmer da 10kOhm quando alimento il display, si accende la retroilluminazione e tutta la seconda fila di caratteri appare nera mentre la prima resta sempre invisibile. Regolando il contrasto cambia solo la visibilità della seconda riga…
è normale? non dovrei riuscire a vedere comunque entrambe le righe?
#29 da Giovanni Bernardo il 18 aprile 2010
Il fatto del contrasto può essere normale. Devi collegare i pin di controllo tutti sullo stesso banco (tutti su PORTA o PORTB). Se hai collegato i pin di controllo ad un banco che ha funzione analogica, ricordati di disattivare la funzione analogica, se usi RA4 per uno dei segnali, e questo è a collettore aperto, ricordati di mettere la resistenza di pullup
#30 da MayTs il 18 aprile 2010
scusa, mi son dimenticato di postarti il datasheet del display, visibile a questo indirizzo:
http://www.winstar.com.tw/products_detail_ov.php?ProID=22
#31 da MayTs il 18 aprile 2010
grazie mille, ora funziona:
ho rifatto i collegamenti e va alla grande…
#32 da Giovanni Bernardo il 18 aprile 2010
Prego ;)
#33 da Davide il 22 aprile 2010
Ciao, intanto ti ringrazio per il lavoro che stai facendo per noi,il risultato è veramente eccellente. Cissà che tu risca a risolvere il mio problema… Ho preso il tuo codice di “Hello word”, caricato su un 16F876 utilizzando le porte C (dalla 2 alla 7). Ho tolto per comodità il tuo file di setting ed ho messo al posto:
ADCON1 = 0b00000110;
Sulle porte C non ci sono moduli AD ma l’ho lasciata comunque.
TRISA=0b00000000;
TRISB=0b00000000;
TRISC=0b00000000;
Il dispaly che ho tra le mani è pin compatibile con l’hitachi. Risultato? Non si legge nulla. Contrasto regolato ma niente di niente. Nessuna uscita open drain sulle porte C. Collegamenti controllati 10 volte.Tutto a posto. La cosa strana è che alla partenza del programma mi pare di vedere un leggero e velocissimo sfarfallio dell’LCD (penso che sia l’Init… penso). Ne ho 3 di LCD e li ho provati tutti… Ne sto uscendo pazzo…. :D
#34 da Giovanni Bernardo il 23 aprile 2010
16F876 OPPURE 16F876A ? C’è la A? Se c’è la A puoi mettere il quarzo da 20MHz, se la A non c’è puoi mettere al massimo quello da 4
#35 da davide.giraudo il 23 aprile 2010
Il pic è il 16f876 non il 16f876A ma per progettini più semplici con led e pulsanti il quarzo da 20MHz funziona. Sul datasheet c’è scritto 20Mhz ma forse sono io che non sono stato in grado di leggere. :(
Ti vorrei spiegare brevemente come sto facendo le mie prove… dimmi che sbaglio qualcosa. :) Uso una Breadboard su cui sono montati tutti i compomenti, ho fatto un cavo a 6 poli per la programmazione (uso PICKIT2) che ho collegato alla breadboard e quindi agli ingressi PGD e PGC del PIC. La programmazione avviene correttamete (test con i led funzionano al 100%). Le alimentazioni di display e PIC sono separate, il display da un alimentatore lineare (4.5V) e il pic direttamente dal pickit. Accendo prima l’LCD e poi faccio l’ENABLE sul pickit.
#36 da Giovanni Bernardo il 23 aprile 2010
Hai messo in comune le masse delle due alimentazioni?
#37 da davide.giraudo il 23 aprile 2010
No, non l’ho fatto. Sta sera provo anche se l’inizializzazione del display penso venga fatta correttamente…. Ho visto su altri siti che:
1- A display da inizializzare la prima riga è completamente “spenta” mentre la seconda completamente accesa. (con il controller ym1602c capita così ma non so se valga per tutti i controller). A inizializzazione effettuata entrambe le righe sono spente. Da questo deduco che viene fatta l’inizializzazione.
2- Una persona sostiene che ha risolto non mettendo a massa i pin D0-D3.
Sta sera provo nell’ordine:
1- Collegare le masse delle due alimentazioni
2- Scollegare da massa i pin Dati non utilizzati, scollegando le masse
Ti dirò cosa succede, Quando riuscirò a farlo funzionare forse la mia esperienza sarà di aiuto a qualcun’altro…
PS: ma sei sicuro dei 4Mhz massimi per il 16f876?
#38 da Giovanni Bernardo il 23 aprile 2010
Se non hai collegato insieme le due masse il problema è solo quello li. Come vuoi che comunichino due dispositivi se non hanno un riferimento comune? Se non colleghi insieme le masse i due sistemi sono completamente isolati a livello di comunicazione.
I pin inutilizzati possono rimanere indifferentemente “appesi” o a massa. Metterli a massa è comunque una buona norma, ma in questo caso non è strettamente necessario per il funzionamento del display: l’inizializzazione viene fatta a livello software, e se lo inizializzi a 4 bit, allora gli altri 4 pin non verranno presi in considerazione. Ma se non si ha un riferimento in comune l’inizializzazione non viene nemmeno effettuata.
La prima o la seconda riga nera o bianca non è un parametro da tenere in considerazione, dipende da troppi fattori anche non legati all’inizializzazione, è uno stato iniziale che può variare da display a display.
#39 da Davide il 24 aprile 2010
Grazie Giovanni. Tutto funziona correttamente ora… il pickit lo uso solo più in fase di programmazione. L’alimentazione per tutto il circuito arriverà dall’alimentatore.
Grazie ancora.
#40 da demastyle il 27 aprile 2010
Ciao Giovanni,
anche se è ripetitivo ti volevo ringraziare anch’io per questo fantastico corso che mi ha dato la possibilità di “imparare” (per quanto posso riuscire ad imparare io) ad utilizzare i pic. Non credo che tu possa capire quanto sia contento del tuo corso.
Tornando a noi, anche io come altri ho qualche problema con lo schermo lcd.
ti spiego meglio: in pratica lo schermo mi rimane alla schermata con la riga nera come se nessuna linea di dati fosse collegata. Ti posso dire che ho provato con 3 pic differenti (logicamente cercando di adattare il programma) il 16F684 dove ho provato sia le PORTA che le PORTC (ancora utilizzavo il pickit 1), dopodichè ho provato il 16F690 (in dotazione con il pickit 2) provando anche li i vari set di porte (prevalentemente PORTC), ed infine negli ultimi 2 giorni con il 16F877 nuovo nuovo (solo le porte definite dal tuo sorgente).
Posso dire anche che ho provato il tuo sorgente sia con mplab con tutte le tue librerie (“setting”, “delay” e “lcd”) che con microC utilizzando le librerie fornite da microC e riscrivendo il codice. Ho utilizzato addirittura il codice di prova che fornisce l’HELP di microC che senza farlo apposta usa come esempio un 16F877.
A questo punto arriviamo al cablaggio: l’errore ci può sempre essere però ho smontato e rimontato su breadboard il circuito decine di volte tanto da aver imparato a memoria la piedinatura degli schermini utilizzando anche 2 tipi di lcd tutti e due compatibili HD44780 e tenedo conto che con arduino non ho avuto il ben che minimo problema… come lo collego funziona. Dimenticavo di dire che lo schermo è 16X2 e una cosa che ancora non ho provato sono le modifiche al cursore. La visibilità, etc…
Cosa posso dire ancora… i pic comunque con altri programmi funzionano. ho provato a mettere o a togliere la massa sul piedino R/W usare 2 alimentazioni con e senza massa in comune, usare una sola alimentazione con integrato lm317 a 5 volt (lm317 se non mi sbaglio….), ho provato sia a caricare il tuo sorgente che a ricompilarlo (nel 16F877). una cosa che non ho provato è accendere l’lcd prima o dopo del pic.
AIUTO! non so più cosa provare.
in ogni caso grazie veramente per il corso che mi da la possibilità di coltivare una mia passione!
Simone.
#41 da Giovanni Bernardo il 27 aprile 2010
Gli errori più comuni sono quelli appunto di non collegare tutte le linee dati alla stessa porta e di non mettere le masse in comune. Indubbiamente il display deve essere acceso prima del picmicro, ma usa la stessa alimentazione in maniera che si accendano contemporaneamente, poi ti faccio sempre le stesse raccomandazioni:
1 – collega le linee dati tutte alla stessa porta
2 – controlla se le porte che stai utilizzando hanno pure funzione analogica: in tal caso opera sui registri opportuni per togliere la funzione analogica
3 – controlla se uno dei pin che stai utilizzando è a collettore aperto (tipo RA4 sul 16F877): se è a collettore aperto (è indicato come OC sul datasheet, nella tabella che descrive le funzioni di ogni pin), devi mettere una resistenza di pullup
4 – controlla che sia collegato e regolato bene il trimmer del contrasto: non ti limitare a girarlo: controlla che sia collegato bene
5 – se usi due alimentazioni separate, accendi prima il display e metti le masse in comune
6 – Le breadboard io le odio perchè oramai di buona qualità in giro non se ne trovano più, pure se te le vendono per buone, e molto spesso i contatti non fanno contatto, per cui prova a spostare il circuito in un’altra parte della breadboard. riprova tutto e fammi sapere.
#42 da peppers il 17 giugno 2010
Buondì,
innanzitutto i miei più sinceri complimenti per il sito!
Sto simulando ogni esercizio con Proteus, tanto per farmi una idea
di quanto possa/non possa essere utile uno strumento simile dal punto didattico…e allo stesso tempo
sto seguendo questo bel corso di C applicato ai picmicro.
Compilando il codice con mplab 8.36 e hi-tech 9.60, a parte i warning di missing newline, ho seguenti errori:
Error [987] C:\Documents and Settings\pier\Desktop\Nuova cartella (2)\main.c; 26.1 arguments redeclared
Error [195] C:\Documents and Settings\pier\Desktop\Nuova cartella (2)\main.c; 120.6 expression syntax
Error [192] C:\Documents and Settings\pier\Desktop\Nuova cartella (2)\main.c; 120.17 undefined identifier “a”
Riguardo al primo errore se commento la linea 19 del prototipo di funzione del main in questo modo,
//void main(void); // programma principale
l’errore scompare, infatti ricompilando ho:
Error [195]….. main.c; 120.7 expression syntax
Error [192]….. main.c; 120.18 undefined identifier “a”
…a questo proposito chiedo: il main va dichiarato come prototipo di funzione?… sinceramente è la prima volta che lo vedo in ANSI C…
per quanto riguarda: Error [192]…. main.c; 120.18 undefined identifier “a”…
il compilatore vuole che nella funzione void beep(char beeptype) la variabile char a sia dichiarata all’inizio della stessa, e non “al volo”
dentro l’inizializzazione del for…
void beep(char beeptype)
{char a;
mentre per l’errore: Error [195]….. main.c; 120.7 expression syntax…
modificando la dichiarazione nel ciclo for ( char a = 40; a –; a != 0 ) in for ( a = 40; a –; a != 0 ), tutto fila liscio…
Ho fatto una prova veloce con Dev-C++ con compilatore gcc, impostando un ciclo for con dichiarazione di variabile dentro lo stesso,
non compila e mi dice che non è conforme al C99 (ANSI).
Possibile così tanti errori tra una versione e l’altra di hi-tech?
Ultima postilla: il suono per i tasti su e giù del cursore sono uguali…beep(0); per entrambi..
Comunque ottimo lavoro…!
Saluti
Pier
#43 da Giovanni Bernardo il 17 giugno 2010
Mi pare strano, durante la compilazione hai incluso soltanto il main nel progetto?
#44 da peppers il 17 giugno 2010
Assolutamente si!
Mi pare strano anche a me, questo codice per esempio lo compila… t è dichiarato al volo nel for, mistero…forse è la versione “pistolata” del compilatore che dà problemi…
/*semplice pwm software*/
#include
#include
__CONFIG(0×3F38);
int pwm1, p, ton1;
p=32; // n di punti PWM (precisione)
main()
{
PORTB=0b00000000;
TRISB=0b00000000;
PORTA=0; // azzera il latch porta
TRISA=0b11111111; // setta le porte A del pic come entrate
CMCON=0X7; // disabilito i comparatori del 628
ton1=16;
while(1)
{
for(int t=0;t<=p;t++)
{
if(t=ton1) RB0=0;
DelayMs(10);
}
}
}
#45 da Marpin il 26 giugno 2010
Ciao Gianni, causa improvviso ricovero al policlinico casilino ho ripreso solo oggi a continuare le mie prove. Volevo informarti che il problema riscontrato sia da Livio che dal sottoscritto sul display lcd apex si presenta identico anche sul displaytech 162b: i caratteri girano ma non gira hello world. Per quanto riguarda il problema della programmazione in-circuit ho verificato la porta parallela, che è ok. Allora ho provato un cavetto lungo 35 cm (cannibalizzato da un vecchio computer, grosso un dito e con fili da 1mm all’interno della guaina ) che, rispetto al cavetto che avevo costruito in precedenza, ha due masse in meno (ti ricordo che nelle demoboard di Sergio le cinque masse sono collegate tra loro dalla pista dello stampato. Ebbene, con questo cavetto la programmazione va a buon fine. Mistero….
Ci sentiamo. Ciao
#46 da Marpin il 29 giugno 2010
Ciao Gianni, un aggiornamento che ritengo possa essere importante. Premetto due cose: la prima è che sto iniziando a programmare in C, quindi sono un pivellino, la seconda è che oltre a “hello world” non girava neanche “trimmer e lcd”. Leggendo il codice lcd.c da te modificato, ho pensato di aggiungere una istruzione ai main.c dei programmi sopra citati, come riportato qua sotto:
LCD_INIT(); // inizializzo l’LCD
DelayMs(100); // piccolo ritardo iniziale
LCD_CMD(LCD_CONTROL); // linea inserita per far funzionare il display
LCD_CLEAR(); // ripulisco il display
Il risultato è che, dopo ricompilazione, girano ambedue senza problemi, sia sull’apex sia sul displaytech. Il semplice ragionamento che ho fatto (non so se giusto) è stato questo: dopo avere definito le proprietà del cursore, con la condizione if definisco il settaggio di LCD_CONTROL. Ma il semplice #define LCD_CONTROL non basta: devo “dire al display” come deve utilizzarlo dopo l’inizializzazione e glielo dico, detto in modo poco ortodosso, facendoglielo “leggere” con quella riga di codice che ho aggiunto al main.c. Vorrei avere un tuo parere in proposito, soprattutto se ho detto una cavolata: mi aiuterà per il futuro.
Grazie ancora
#47 da buby72 il 29 dicembre 2010
Salve, ho notato che non sono l’unica a non riuscire ad inizializzate il display DISPLAYTECH 162. mi sono avvicinato ai PIC un anno fa con il tutorial di Tanzilli, ora sono bloccato con l’LCD che per quanto prova mi mette sempre la prima riga nera ( se aumento il contrasto) e nessun carattere. nei simulatori tutto ok, ma nel displaytech nulla! Come sistema operativo uso l’assembly. Ho visto che in C con la riga
LCD_CMD(LCD_CONTROL); // linea inserita per far funzionare il display
siete riusciti a far partire il display, in assembly ha qualche corrispondenza? Mi potete aiutare? Grazie
#48 da Giovanni Bernardo il 29 dicembre 2010
“Come sistema operativo uso l’assembly”: Al limite l’assembly lo usa come linguaggio di programmazione.
Nella libreria che utilizza lei c’è sicuramente già la funzione che invia il comando lcd_control, si trova nelle funzioni di inizializzazione o in altro. Se ha letto il tutorial sull’LCD e l’assembly lo capisce, non dovrebbe esserle difficile trovare da sè la funzione.
#49 da a.screm il 28 marzo 2011
Ciao credo di aver trovato la sozione per il Displaytech:
Il problema sta nell iniziolizzazione :
cioe’ quando viene eseguito il clear display occorre dare un ritardo di 1,5 ms
(come da datasheet Displaytech con cController LCD SAMSUNG KS0070B)
la funzione LCD_WRITE(0b00000000); // clear display
effettua un delay di soli 50 us non sono sufficienti.
ho sostituito la funzione:
LCD_WRITE(0b00000000); con LCD_CLEAR();
che fa esettamente la stessa cosa ma da il delay corretto.
Con questa piccola correzione funziona sia “hello world” che “lcd menu”
Spero di essere stato utile.
ciao
Alesssandro
Ricapitolando la routine LCD_INIT() diventa:
*******************************************************************
void LCD_INIT (void)
{
LCD_RS = 0; // write control bytes
DelayMs(50); // power on delay
LCD_D4=1;
LCD_D5=1;
LCD_D6=0;
LCD_D7=0;
LCD_STROBE();
DelayMs(6);
LCD_STROBE();
DelayUs(150);
LCD_STROBE();
DelayMs(6);
LCD_D4=0; // set 4 bit mode
LCD_STROBE();
DelayUs(100);
#if (LCD_ROWS==1)
LCD_WRITE(0b00100000); // 4 bit mode, 1 line, 5×8 font
#else
LCD_WRITE(0b00101000); // 4 bit mode, 2 or more lines, 5×8 font
#endif
LCD_WRITE(0b00001000); // display off
LCD_CLEAR(); // clear display
LCD_WRITE(LCD_CONTROL);// display on, set the cursor behavior as specified
LCD_WRITE(0b00000110); // entry mode, display not shifted, cursor increments
}
************************************************************************
#50 da Fabio il 3 luglio 2010
Grandiii
#51 da Skynet il 28 luglio 2010
Ciao,
come mai questi errori su lcd.c:
Clean: Deleted file “E:\pic\main.p1″.
Clean: Deleted file “E:\pic\16F877A.mcs”.
Clean: Done.
Build E:\pic\16F877A for device 16F877A
Using driver D:\Programmi\HI-TECH Software\PICC\PRO\9.65\bin\picc.exe
Executing: “D:\Programmi\HI-TECH Software\PICC\PRO\9.65\bin\picc.exe” –pass1 E:\programmazione_picmicro_04\hello_world\sorgenti\delay.c -q –chip=16F877A -P –runtime=default –opt=default -D__DEBUG=1 -g –asmlist “–errformat=Error [%n] %f; %l.%c %s” “–msgformat=Advisory[%n] %s” “–warnformat=Warning [%n] %f; %l.%c %s”
Executing: “D:\Programmi\HI-TECH Software\PICC\PRO\9.65\bin\picc.exe” –pass1 E:\programmazione_picmicro_04\hello_world\sorgenti\lcd.c -q –chip=16F877A -P –runtime=default –opt=default -D__DEBUG=1 -g –asmlist “–errformat=Error [%n] %f; %l.%c %s” “–msgformat=Advisory[%n] %s” “–warnformat=Warning [%n] %f; %l.%c %s”
Error [192] E:\programmazione_picmicro_04\hello_world\sorgenti\lcd.c; 164.1 undefined identifier “RA3″
Warning [361] E:\programmazione_picmicro_04\hello_world\sorgenti\lcd.c; 165.1 function declared implicit int
Error [192] E:\programmazione_picmicro_04\hello_world\sorgenti\lcd.c; 175.1 undefined identifier “RB3″
Error [192] E:\programmazione_picmicro_04\hello_world\sorgenti\lcd.c; 179.1 undefined identifier “RB2″
Error [192] E:\programmazione_picmicro_04\hello_world\sorgenti\lcd.c; 183.1 undefined identifier “RB1″
Error [192] E:\programmazione_picmicro_04\hello_world\sorgenti\lcd.c; 187.1 undefined identifier “RB0″
Error [192] E:\programmazione_picmicro_04\hello_world\sorgenti\lcd.c; 203.5 undefined identifier “RA2″
Warning [361] E:\programmazione_picmicro_04\hello_world\sorgenti\lcd.c; 205.1 function declared implicit int
Error [192] E:\programmazione_picmicro_04\hello_world\sorgenti\lcd.c; 215.1 undefined identifier “RA2″
Error [192] E:\programmazione_picmicro_04\hello_world\sorgenti\lcd.c; 253.1 undefined identifier “RA2″
Error [192] E:\programmazione_picmicro_04\hello_world\sorgenti\lcd.c; 314.1 undefined identifier “RA2″
Error [192] E:\programmazione_picmicro_04\hello_world\sorgenti\lcd.c; 344.1 undefined identifier “RA2″
Error [192] E:\programmazione_picmicro_04\hello_world\sorgenti\lcd.c; 347.1 undefined identifier “RB0″
Error [192] E:\programmazione_picmicro_04\hello_world\sorgenti\lcd.c; 348.1 undefined identifier “RB1″
Error [192] E:\programmazione_picmicro_04\hello_world\sorgenti\lcd.c; 349.1 undefined identifier “RB2″
Error [192] E:\programmazione_picmicro_04\hello_world\sorgenti\lcd.c; 350.1 undefined identifier “RB3″
Executing: “D:\Programmi\HI-TECH Software\PICC\PRO\9.65\bin\picc.exe” –pass1 E:\programmazione_picmicro_04\hello_world\sorgenti\main.c -q –chip=16F877A -P –runtime=default –opt=default -D__DEBUG=1 -g –asmlist “–errformat=Error [%n] %f; %l.%c %s” “–msgformat=Advisory[%n] %s” “–warnformat=Warning [%n] %f; %l.%c %s”
********** Build failed! **********
#52 da Giovanni Bernardo il 28 luglio 2010
hai dimenticato di includere pic.h ? Li dice che non sono definiti RA3 ecc ecc per cui posso solo supporre che non hai incluso quel file.
#53 da Skynet il 29 luglio 2010
Giovanni,
se non sbaglio dovrebbe essere incluso, dato che sono gli esempi
che ho preso dal file .zip.
#54 da Giovanni Bernardo il 29 luglio 2010
Quegli errori dicono chiaramente che i simboli “RA2″ ecc non sono definiti, il che vuol dire che nel tuo codice non è mai stato specificato, in nessun punto, cosa vuol dire “RA2″. Dal momento che i nomi delle porte sono dichiarati nel file include del pic da te utilizzato, vuol dire o che non hai incluso pic.h (il quale poi si richiama da solo il file H del pic che hai specificato in fase di progetto) o che hai qualche altro tipo di problema, sempre relativo a questa questione. Ma devi controllare tu perchè io non so cosa c’è sul tuo pc e non so cosa hai scritto nel codice.
#55 da Skynet il 29 luglio 2010
OK!
Piu’ tardi inizializzero’ tutto!
#56 da Skynet il 30 luglio 2010
Niente!
Build E:\pic\LCD for device 16F84A
Using driver D:\Programmi\HI-TECH Software\PICC\PRO\9.65\bin\picc.exe
Make: The target “E:\pic\main.p1″ is up to date.
Make: The target “E:\pic\lcd.p1″ is up to date.
Make: The target “E:\pic\delay.p1″ is up to date.
Executing: “D:\Programmi\HI-TECH Software\PICC\PRO\9.65\bin\picc.exe” -oLCD.cof -mLCD.map –summary=default –output=default main.p1 lcd.p1 delay.p1 –chip=16F84A -P –runtime=default –opt=default -D__DEBUG=1 -g –asmlist “–errformat=Error [%n] %f; %l.%c %s” “–msgformat=Advisory[%n] %s” “–warnformat=Warning [%n] %f; %l.%c %s”
HI-TECH C PRO for the PIC10/12/16 MCU family (Lite) V9.65
Copyright (C) 1984-2009 HI-TECH SOFTWARE
(1273) Omniscient Code Generation not available in Lite mode (warning)
Error [237] E:\pic\delay.c; 12. function “_DelayMs” redefined
Error [237] E:\pic\lcd.c; 164. function “_LCD_STROBE” redefined
Error [237] E:\pic\lcd.c; 175. function “_LCD_NIBBLE_OUT” redefined
Error [237] E:\pic\lcd.c; 196. function “_LCD_WRITE” redefined
Error [237] E:\pic\lcd.c; 208. function “_LCD_CMD” redefined
Error [237] E:\pic\lcd.c; 218. function “_LCD_GOTO” redefined
Error [237] E:\pic\lcd.c; 236. function “_LCD_CLEAR” redefined
Error [237] E:\pic\lcd.c; 246. function “_LCD_PUTCH” redefined
Error [237] E:\pic\lcd.c; 256. function “_LCD_PUTUN” redefined
Error [237] E:\pic\lcd.c; 284. function “_LCD_PUTSN” redefined
Error [237] E:\pic\lcd.c; 298. function “_LCD_PUTS” redefined
Advisory[1] too many errors (11)
********** Build failed! **********
#57 da Giovanni Bernardo il 30 luglio 2010
- o elimini tutti gli “#include” nel main e includi tutti i file nel progetto
- rimani gli “#include” nel main però quandi crei il progetto devi aggiungerci SOLO MAIN. MAIN. E BASTA
#58 da Fidus il 22 agosto 2010
Ciao,
sto utilizzando un PIC184450, per scrivere su un HD44780, ho riutilizzato il tuo sorgente (con poche modifiche) ho realizzato correttamente tutto il circuito, però mi deve arrivare il quarzo (20 Mhz) il circuito potrebbe funzionare lo stesso? Ho fatto svariate prove sul display non viene visualizzato nulla.
Poi è normale che nella regolazione del contrasto, quando modifico il valore della resistenza, solamente la riga in alto cambia il contrasto e quella in basso resta uguale?
#59 da Giovanni Bernardo il 22 agosto 2010
Si dovrebbe funzionare correttamente anche con un altro quarzo. Poi su alcuni display è normale che si scurisce di piu la riga di sopra.
#60 da Fidus il 22 agosto 2010
Nel caso non ci fosse il quarzo non funzionerebbe niente? o un modo per farlo andare ci sarebbe?
#61 da Giovanni Bernardo il 22 agosto 2010
E’ ovvio che un microcontrollore senza un oscillatore non funziona. Se il pic che usi ha l’oscillatore interno, puoi utilizzare l’oscillatore interno invece del quarzo.
#62 da Fidus il 22 agosto 2010
Ti ringrazio. Ottimo sito complimenti per tutto.
#63 da dinus01 il 3 settembre 2010
sto provando a compilare il main.c di questo progetto
ma il compilatore mplab v8.0 mi da questi errori:
Error [987] C:\pic pr\asettorecica.c; 26.1 arguments redeclared
Error [195] C:\pic pr\asettorecica.c; 120.6 expression syntax
Error [192] C:\pic pr\asettorecica.c; 120.17 undefined identifier “a”
********** Build failed! **************
sono alle prime armi
grazie anticipatamente
#64 da Giovanni Bernardo il 4 settembre 2010
arguments redeclared => hai ridichiarato stesse variabili o stesse funzioni che hai già dichiarato da altre parti, errore comune è quello di utilizzare sia gli include nel codice che includere anche i file nel progetto, o usi un sistema o l’altro.
expression syntax => errore di sintassi. Hai dimenticato un ; di chiudere delle virgolette o delle parentesi o altro.
undefined identifier “a” => c’è una ‘a’ che non hai dichiarato nè come funzione nè come variabile.
il numero prima dell’errore è la riga: 26.1 = riga 26, 1° carattere, ma non sempre l’errore è dato in quella riga, in particolar modo gli errori di sintassi non te li ritroverai quasi mai sulla riga indicata. Per altre info leggi i commenti al di sotto delle lezioni.
#65 da dinus01 il 4 settembre 2010
allora il main.c che ho scaricato non e’ completo?
vorrei capirci meglio.
ero convinto che inserendo il setting.h nella cartella include potessi
compilare il main.c senza avere errori.
#66 da Giovanni Bernardo il 4 settembre 2010
Il main è completo, e se segui le istruzioni date anche nelle lezioni precedenti non hai problemi. I file devono rimanere tutti dove sono, non devi mettere settings nella cartella include, lo devi restare dove sta il main. Crei il progetto e nel progetto includi solo il main.
#67 da dinus01 il 4 settembre 2010
mi potresti dire cosa devo fare per compilare questo main.c
io mi sono scaricato la cartella sorgenti che contiene:delay.c-delay.h-main.c-setting.h
scusa la mia ignoranza
#68 da Giovanni Bernardo il 4 settembre 2010
http://www.settorezero.com/wordpress/corso-programmazione-picmicro-in-c-lezione-3-il-primo-programma-in-c-scrivere-un-semplice-programma-in-c-per-picmicro-impostare-mplab-e-flashare-il-picmicro-con-il-pickit2/
#69 da dinus01 il 4 settembre 2010
allora apro mplab 8.0
faccio tutta la procedura ,carico il file main.c:
//*************************************************
// CORSO PROGRAMMAZIONE PICMICRO
// Lezione 5
// http://www.settorezero.com
//
// modulo: main.c
// autore: Bernardo Giovanni
// data: 26/09/09
// descrizione: lampeggia un led su RD0 tramite interrupt e suona un cicalino su RE1
// picmicro: PIC16F877A
// clock: 20MHz
//
//*************************************************
#define XTAL_FREQ 20MHZ // questo è utilizzato dalle routine di ritardo contenute in Delay.C
#include // contiene i nomi mnemonici di registri e porte
// Fuses di configurazione
__CONFIG (HS & WDTDIS & PWRTEN & BORDIS & LVPDIS & DUNPROT & WRTEN & DEBUGDIS & UNPROTECT);
#include “delay.c” // routine per ritardi
#define TEMPOLED 250
#define LED RD0
#define CICALINO RE1
unsigned char TimerLed=0;
// funzione principale, eseguita all’avvio del picmicro
void main(void)
{
// Tutte le porte come output
TRISA=0;
TRISB=0;
TRISC=0;
TRISD=0;
TRISE=0;
// Impostazione del registro OPTION (pag.55 del datasheet)
OPTION=0b11000100;
// bit 0 -> Prescaler Rate Select bit 0
// bit 1 -> Prescaler Rate Select bit 0
// bit 2 -> Prescaler Rate Select bit 0 (1:32)
// bit 3 -> Prescaler assegnato al Timer0
// bit 4 -> Non importa
// bit 5 -> Clock per Timer0 derivato da ciclo di clock interno
// bit 6 -> Non importa
// bit 7 -> Resistenze di pull-up su porta B disattivate
// Impostazione Interrupt
INTCON=0b10100000;
// bit 0 -> RBIF – Flag interrupt su porte B
// bit 1 -> INTF – Flag interrupt su RB0/INT
// bit 2 -> T0IF – Flag interrupt su Timer0
// bit 3 -> RBIE, Interrupt su porte B disattivato
// bit 4 -> INTE, Interrupt su porta RB0/INT disattivato
// bit 5 -> TMR0IE, Interrupt su Timer0 attivato
// bit 6 -> PEIE, Interrupt di periferica disattivato
// bit 7 -> GIE, Gestione Interrupt attiva
TMR0=100; // Imposto Timer0 a 100
while(1) // eseguo un ciclo finito
{
/*
L’unica cosa che eseguo durante questo ciclo infinito, è l’inversione
dello stato del cicalino ogni 200microsecondi, in maniera tale da generare
un’onda quadra di 2,5KHz che, applicata al cicalino, appunto,
mi permette di farlo suonare facendogli emettere una nota a tale frequenza
*/
DelayUs(200);
CICALINO=1;
DelayUs(200);
CICALINO=0;
}// Fine ciclo continuo
} // Fine main
/*
Questa routine, avendo l’attributo “interrupt” prima del nome della routine stessa, viene chiamata in automatico
ogni qualvolta si verifica un interrupt. Essendo le sorgenti di interrupt di vari tipi, in questa routine dobbiamo
capire quale elemento ha generato l’interrupt. Con le impostazioni utilizzate, Timer0 genererà un interrupt ogni
millisecondo.
*/
void interrupt ISR (void)
{
if (T0IF) // L’interrupt è stato causato da un overflow del timer0 ?
{
TMR0 = 100; // Reimposto Timer0
TimerLed++; // Incremento il Timer per il lampeggio del led
if (TimerLed >= TEMPOLED) // Se il tempo è passato
{
LED=LED^1; // Inverto lo stato del led per farlo lampeggiare
TimerLed=0; // Ricarico il timer del led per ricominciare daccapo
}
T0IF=0; // Resetto il flag interrupt su timer 0,
} // fine che interrupt verificatosi su timer0
} // fine interrupt service routine
lo compilo e mi da questo errore:
Build C:\pic pr\progetto_1 for device 16F877A
Using driver C:\Programmi\HI-TECH Software\PICC\LITE\9.60\bin\picl.exe
Executing: “C:\Programmi\HI-TECH Software\PICC\LITE\9.60\bin\picl.exe” -C “C:\pic pr\progetto.c” –chip=16F877A -P -q -g –asmlist “–errformat=Error [%n] %f; %l.%c %s” “–msgformat=Advisory[%n] %s” “–warnformat=Warning [%n] %f; %l.%c %s”
Error [195] C:\pic pr\progetto.c; 19.0 expression syntax
Error [300] C:\pic pr\progetto.c; 19.0 unexpected end of file
Executing: “C:\Programmi\HI-TECH Software\PICC\LITE\9.60\bin\picl.exe” -C “C:\pic pr\settcica.c” –chip=16F877A -P -q -g –asmlist “–errformat=Error [%n] %f; %l.%c %s” “–msgformat=Advisory[%n] %s” “–warnformat=Warning [%n] %f; %l.%c %s”
Error [195] C:\pic pr\settcica.c; 17.0 expression syntax
Error [300] C:\pic pr\settcica.c; 17.0 unexpected end of file
Executing: “C:\Programmi\HI-TECH Software\PICC\LITE\9.60\bin\picl.exe” -C “C:\pic pr\sett.cicaled.c” –chip=16F877A -P -q -g –asmlist “–errformat=Error [%n] %f; %l.%c %s” “–msgformat=Advisory[%n] %s” “–warnformat=Warning [%n] %f; %l.%c %s”
Error [139] ; . end of file in comment
********** Build failed! **************
#70 da dinus01 il 4 settembre 2010
io ho una breadboard ,ho montato un pic 16f877a un display 2-16
quattro pulsanti
mi sto esercitando scrivendo dei semplici programmini(premo il pulsante 1 e sul display mi appare “pulsante 1 premuto”,premo pulsante 2 e sul display appare “pulante 2 premuto)
quindi mi scrivo il programmino me lo compilo e funziona tutto perfettamente.
ora ho visto questo progetto ho provato a compilarlo ma il compilatore mi da errore
#71 da Giovanni Bernardo il 4 settembre 2010
Hai cambiato qualcosa nel programma: già vedo che i nomi dei files sono cambiati, per cui probabilmente hai cambiato qualcosa pure all’interno. Il file che hai incollato qui mi pare giusto, se ti da errore di sintassi vuol dire che ne stai compilando uno che ha degli errori. Apri il file “programma.c” (ma quello che stai compilando, non un altro: controllati bene i percorsi!) e vedi alla riga 19 e 18 se ci sono errori del tipo che manca un punto e virgola o cose del genere.
#72 da dinus01 il 7 settembre 2010
ho ricompilato il main.c del progetto “menu”
e mi da questi errori:
Error [987] C:\pic pr\settworld\main.c; 25.1 arguments redeclared
Error [195] C:\pic pr\settworld\main.c; 119.5 expression syntax
Error [192] C:\pic pr\settworld\main.c; 119.16 undefined identifier “a”
********** Build failed! **************
l’errore [987] arguments redeclared e’ dovuto al fatto che c’e’ scritto
void main(void) riga 19 infatti togliendolo non mi da piu’ l’errore.
gli altri 2 errori sono dovuti a questa riga :
for(char a=40; a–; a!=0);
togliendo solo char e dichiarando la variabile “a” allinizio del programma
riesco a togliere anche questi errori.
ora mi domando dove sta il problema?
E ‘il mio compilatore?,un errore nel tuo listato o io che non capisco niente?
sto seguendo le tue lezioni perche’ mi sembrano piu’ chiare
e ti faccio i miei complimenti.
solo che ho questo problema al momento della compilazione
mi da errore.
#73 da Giovanni Bernardo il 7 settembre 2010
Togliendo la dichiarazione del main non hai più errore?! E scommetto che ti funziona pure? Non penso proprio e l’errore di sicuro non sta li. Ma se continui a non scrivermi per intero il codice che stai tentando di compilare, non posso farci nulla ed eliminare intere righe da un programma non è certo il sistema per correggere gli errori, addirittura poi eliminare la dichiarazione del main (spera che queste righe non le legga nessuno!).
Poi:
for (char a=40; a–; a!=0);
L’errore è dovuto a quel punto e virgola dopo la parentesi chiusa, non ci vuole, se hai capito come si struttura un ciclo for… capisci che non si scrive così.
In hitec-C si può mettere la dichiarazione tipo “char a” stesso nel ciclo for, in altri no e da errore.
Inviami per email il codice che stai provando a compilare (gianni at settorezero.com) altrimenti è inutile continuare così.
Secondariamente: stai usando l’Hitec-C o qualche altro compilatore? Per altri compilatori non posso esserti d’aiuto.
Ciao
#74 da Giovanni Bernardo il 7 settembre 2010
Allora: mi sono riletto il mio sorgente:
Alla riga 19 c’è il prototipo di funzione, e deve esserci il punto e virgola dopo, cioè la riga 19 deve essere scritta così:
void main(void);
col punto e virgola alla fine! Per cui se non c’è è ovvio che ti da errore, ma l’hai cancellato tu perchè nel codice ci sta.
Il ciclo for incriminato sta alla riga 120 e il punto e virgola non c’è, quindi il punto e virgola che hai tolto sopra lo hai messo qui?!
I codici prima di pubblicarli è ovvio che li provo sempre, per cui errori non ce ne possono essere, se ci sono o li hai creati tu o non stai seguendo le istruzioni.
#75 da Bruno62 il 17 settembre 2010
Salve a tutti.
Ho provato a compilare ed eseguire l’esempio della lezione nella Freedom II del grande Mauro Laurenti e con mia grande sorpresa nel display non appariva niente.
Anche dopo aver inserito un’istruzione per accendere l’illuminazione del display (nella Freedom II è attivabile via software) ed aver collegato fisicamente a massa la linea r/W (comunque già a 0 dallo stato del pin RD1) il display rimaneva vuoto.
Ho ricontrollato il montaggio ed era tutto OK.
Ero disperato quando qui ho letto qui il commento di Marpin che è stato risolutivo.
Pertanto, per far girare l’esempio nella Freedom II con il display “DISPLAYTECH 162A” ho dovuto modificare il main nel modo seguente:
#define BACKLIGHT RC1
void main(void)
{
settings(); // imposto le porte
LCD_INIT(); // inizializzo l’LCD
DelayMs(100); // piccolo ritardo iniziale
LCD_CMD(LCD_CONTROL); // linea inserita per far funzionare il display
LCD_CLEAR(); // ripulisco il display
LCD_GOTO(1,1); // posiziono il cursore sull’LCD: riga1, colonna1
LCD_PUTS(“HELLO”);
LCD_GOTO(2,1); // riga2, colonna1
LCD_PUTS(“WORLD !”);
BACKLIGHT = 1; accendo l’illuminazione del display
while(1)
{
}
}
Ecco il display:
http://www.displaytech.com.hk/upload/product/attachment/980-162a%20series-v20.pdf
Un saluto a tutti ed un particolare ringraziamento a Marpin
#76 da Scollo Giovanni il 10 novembre 2010
Ciao sono, sono un appasionato di Elettronica ed Iformatica,
Ti faccio i miei complimenti per il lavoro che hai svolto veramente ottimo,
Ti scrivo per un consiglio, io tempo fa avevo realizzato qualcosa di simile al Tuo Menu’ con LCD solo che lo avevo sviluppato, usando un PIC 16F628A, programmato in PIC Basic e tutto funziona correttamente.
Adesso volevo provarlo con il tuo programma in C, ho scaricato i tuoi programmi e dopo aver modificato:
il file settings.h configurando opportunamente PORTA e PORTB come uscite (CMCON=00000111, TRISA=00000000, TRISB=00000000);
il file lcd.c modificando le assegnazioni dei pin (infatti la scheda da me montata usava RA=D1, D2, D3, D4, RA4=RS ed RB2=Enable le assgnazioni standard di PIC Basic per gestire LCD);
nel main.c ho modificato la frequenza di clock (4 Mhz) e la configuration word (3F21).
Ho compilato il tutto con MPLAB (tutto OK), ho usato un PICKIT2 per trasferire il programma ma LCD non funziona, fa un lieve sfarfallio iniziale ma non visualizza niente, mentre i controlli dei tasti (su, giù e OK) funzionano correttamente.
Ti sarei grato se potessi darmi qualche suggerimento, sottolineo che la stessa scheda con il programma sviluppato in basic funziona correttamente.
Grazie anticiapato.
#77 da Giovanni Bernardo il 10 novembre 2010
Potrebbe trattarsi di un problema di temporizzazione del display. Alcuni hanno questo problema strano con taluni display. Leggi il commento 46, fai questa prova e fammi sapere.
#78 da Scollo Giovanni il 11 novembre 2010
Ciao, sono ancora Scollo Giovanni
ho provato la modifica LCD_CMD(LCD_CONTROL) sul main.c e per incanto tutto ha funzionato perfettamente al primo tentativo.
Colgo l’occassione per complimentarmi ancora una volta per il lavoro che stai facendo e per evidenziare come non si finisce mai di imparare anche se a volte non si capisce bene il perchè.
Ti ringrazio per la gentilezza e la puntualità con cui curi queste discussioni, a presto.
#79 da giorgio1986 il 15 novembre 2010
Ciao, intanto ti faccio i complimenti per il lavoro che svolgi per noi, poi premetto che ho iniziato a programmare i pic da 3 giorni ovviamente seguendo le tue lezioni, ora veniamo al problema.
io uso un 16F876 con quarzo da 4 Mhz
e questo lcd http://pdf1.alldatasheet.com/datasheet-pdf/view/100767/OPTREX/DMC16205.html
circuito alimentato tutto con lo stesso alimentatore
ho montato lo schema cambiando solo le porte usando queste:
RA0 buzzer
RB0 BTNUP
RB1 BTNDOWN
RB2 BTNOK
RB4 – RB7 LED1 – LED4
RC0 RS
RC1 EN
RC2 – RC5 D4 – D7
le prove che ho fatto sono:
1) alimentare lcd prima del pic
2) tutte le masse sono collegate insieme così come le vcc
3) aggiunta riga LCD_CMD(LCD_CONTROL) senza successo
4) ovviamente cambiato le porte nel file lcd.c
5) aumentato i delay nella funzione init dell’lcd
ma continuo a vedere solo la prima riga nera (trimmer regolato bene) e nella seconda nulla,
chiaramente non scrive nulla,
io penso che sia un problema di init del display
puoi aiutarmi grazie
#80 da Giovanni Bernardo il 15 novembre 2010
La linea RW del display sta a massa? Su alcuni display per usare la modalità a 4 bit devi collegare a massa anche D0-D3. le porte RC poi mi pare sono condivise col convertitore A/D per cui devi disattivarlo
#81 da giorgio1986 il 15 novembre 2010
grazie per la risposta immediata, allora rw è a massa anche i pin D0-D3 lo sono e ovviamente ho disattivato tutti i convertitori A/D settando tutte le porte come digitali usando ADCON1 = 0b00000110.
basta scrivere solo questo o serve qualche altra istruzione per disattivare le porte e settarle come digitali?
cmq rileggendo il datasheet del display mi sono accorto che per la modalità 4 bit non vuole i pin D0-D3 collegati a massa ma li vuole scollegati.
infatti appena li ho scollegati ha subito funzionato tutto. era una cavolata per un errore di disattenzione
grazie
#82 da Giovanni Bernardo il 15 novembre 2010
Ok
#83 da brunotech il 21 novembre 2010
Ciao giovanni, avrei bisogno di qualche chiarimento e coscendo la tua disponibilità ti ringrazio in anticipo. Stò utilizzando un PIC16F690 con oscillatore interno impostato alla frequenza di 8 Mhz, uso questo per interfacciarmi con un display della APEX 16×4 con controller KS0066.
Volevo chiederti se ci sono quali modifiche da fare nei file Display.h e Display.c visto che utilizzo una frequenza diversa dai 20 Mhz e non sò se si rispettano i tempi richiesti dal controller?
Come impostare il registro ADCON0 o ADCON1 per far funzionare le porte come uscite digitali perchè anche leggendo il Datascheets non mi è chiaro?
Quale pin del PIC16F690 se c’è è a collettore aperto?
#84 da Giovanni Bernardo il 21 novembre 2010
1- il settaggio del quarzo serve solo ai delay, quindi non ci sono problemi. Se riesci usa però le routine di delay ad elevata precisione che trovi qui: http://www.microchipc.com/sourcecode/#delay16x
2-la funzione analogica dei pin su questo pic si setta con i registri ANSEL e in questo caso anche ANSELH. Pagina 61 del datasheet. Bit messo a 1:porta come analogica, 0:porta come digitale. Quindi:
ANSEL=0
ANSELH=0
per avere tutte le porte come digitali
3- le caratteristiche elettriche di ogni singola porta, come su tutti i pic, sono riassunte nella tabella “pinout description” che si trova sempre nelle prime pagine del datasheet. Pagina 14 nel tuo caso. Nessuna porta è a collettore aperto
#85 da Mephiston il 29 novembre 2010
Ciao giovanni, innanzi tutto vorrei ringraziarti per il lavoro che svolgi per tutti noi. Essendo il più principiante tra i principianti ti posso dire che tutto quello che scrivi è totalmente comprensibile e, visto la materia di cui tratti, è veramente una grandissima cosa!
sto provando a lavorare un un LCD a singola riga, ma ho un comportamento strano. Premesso che sto utilizzando Mikro C Pro come compilatore (si può dire in televisione? :P) ed ho quindi a disposizione una libreria per “parlare” con gli LCD. Ho provato ad usarla e il risultato è che riesco a scrivere solo 8 caratteri su 16.
Ho subito pensato che fosse un problema di libreria, così ho importato quella utilizzata nel tuo esempio, togliendo dalle librerie incluse automaticamente quelle sulle funzioni e costanti degli LCD (LCD ed LCD Constants). Purtroppo così facendo non riesco nemmeno ad inizializzare l’LCD pur compilando perfettamente il progetto.
Sto utilizzando un PIC16F628A ed ho collegato tutti i pin dell’LCD alle porte b. L’LCD usa un Controller SPLC780D1 (Datasheet http://www.andilcd.de/medien/en/download/controller/andilcd_conchar_sheet_en_splc780d1.pdf)
questo è il Datasheet dell’LCD http://www.microbot.it/shared_files/display%2016×1%20Tinsharp.pdf
non riesco a venirne a capo… qualche consiglio?
#86 da Giovanni Bernardo il 30 novembre 2010
Con il MikroC non posso esserti d’aiuto. Non lo utilizzo. Pure se lo compila perfettamente nulla vieta che pezzi di codice scritto per l’hitec uniti a pezzi scritti per il miKroC non siano compatibili.
#87 da Mattia il 5 dicembre 2010
Ciao, complimenti per il lavoro svolto. Guardando il programma da te scritto mi sembra che, premendo uno dei pulsanti per un tempo superiore a quello di esecuzione del ciclo infinito contenuto nel main, il micro lo percepisca come una doppia, tripla, ecc pressione perchè, a ciclo ultimato, il micro ricontrollerebbe lo stato dei pulsanti e rieseguirebbe le stesse operazioni già svolte il ciclo prima. Potresti dirmi se e dove sbaglio? Grazie di tutto
#88 da Giovanni Bernardo il 5 dicembre 2010
Mi sembra abbastanza ovvio che si comporti così! Perchè dovresti tenere premuto il pulsante per tutto questo tempo?! Se vuoi fare in modo che tenendo premuto il pulsante anche fino al 2054 ma venga percepita una sola pressione, ti devi mettere un flag che non esegue il ricontrollo del pulsante fino a che questo non viene rilasciato
#89 da Sebastiano il 10 dicembre 2010
ciao.. ho provato a realizzare la lettura analogica con lcd; ho qualche problemino.. quando do corrente il display si illumina con la backlight e, mentre nella seconda riga compaiono tutti quadratini la prima riga rimangono spenti, in ogni caso non si riescono a vedere i caratteri coretti.. non riesco a capire cosa sbaglio, ho inserito il tuo file hex helloworld e ho realizzato il circuito come lo descrivevi.. sai capire dove è l’errore? ti mando il datasheet dell’lcd che ho comprato..
http://docs-europe.electrocomponents.com/webdocs/06dd/0900766b806dda15.pdf
ti ringrazio anticipatamente.
In fede Sebastiano
#90 da Sebastiano il 10 dicembre 2010
forse non sono stato chiaro cosi ti mando anche la foto del display acceso:
http://picasaweb.google.com/112138225753649370704/Display#
#91 da Giovanni Bernardo il 10 dicembre 2010
uno dei seguenti: regolazione del contrasto, alimentazione sbagliata, temporizzazioni non corrette, display guasto.
#92 da ricello il 31 dicembre 2010
Ciao… sto smanettando con la demoboard Freedom2 per cercare di far funzionare LCD ma senza esiti positivi.
Sto usando un 16F877A ì, ho settato le porte ma sull’LCD non compare niente.
Vedo entrambe le line nere, di conseguenza penso che il display si sia inizializzato in modo corretto.
O provato a d aumentare i tempi ma senza successo.
Tu cosa mi suggerisci di fare?
Premetto che con un pic 18 e il software di test della demoborad il display funziona.
Grazie.
#93 da Madnov il 15 gennaio 2011
Ciao. Ho un problema con il mio lcd CRYSTAL CLEAR TECHNOLOGY: non fa nulla.
Credo che il problema sia l’ inizializzazione
Allego la procedura del datasheet.
POWER ON
Wait time >40mS
After Vcc >4,5V
Function set
RS R/W DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0
0 0 0 0 1 1 N F – -
Wait time >37uS
Display ON/OFF control
RS R/W DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0
0 0 0 0 0 0 1 D C B
Wait time >37uS
Display clear
RS R/W DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0
0 0 0 0 0 0 0 0 0 1
Wait time >1.53mS
Entry mode set
RS R/W DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0
0 0 0 0 0 0 0 1 I/D S
Initialization end
Le instructions sono le stesse del Hitachi HD44780
Non so come fare a modificare la procedura indicata in questa lezione, credo che dovrei modificare anche lo schema elettrico per gestire l’inizializzazione.
Aiutatemi non so cosa fare.
Ringrazio in anticipo.