Come abbiamo accennato nella prima parte di questa lezione, alcune posizioni della CGROM del controller sono vuote e scrivibili: abbiamo a disposizione 64byte liberi in cui scrivere.
Essendo ogni carattere composto da 8 byte, vuol dire che possiamo personalizzare 8 caratteri (64/8).
Come vedremo, la personalizzazione dei caratteri è in realtà molto molto semplice.
Innanzitutto immaginiamo ogni carattere costituito da 8 righe, di 5 pixel ognuna (carattere 5×8).
Ricordo che in altri documenti si fa invece riferimento ai caratteri come 5×7 : non c’è differenza in quanto l’ultima riga generalmente viene lasciata vuota per far posto al cursore, ma in fase di personalizzazione nulla ci vieta di utilizzare anche quest’ultima riga (quella identificata come byte7 nell’immagine successiva).
Ogni riga del carattere rappresenta un byte della CGROM (anche se costituito da solo 5 “posizioni”: le rimanenti 3 – per formare l’intero byte – si possono intendere poste sempre a zero: il loro valore è ininfluente).
Per disegnare, ad esempio, una freccia rivolta a destra, costruiamo una griglia 5×8, e per ogni riga, calcoliamo il valore del byte considerando i pixel pieni posti a 1, come da immagine seguente :

(grazie ancora un’altra volta a Dincer Aydin per la gentile concessione)
Per andare a caricare il nuovo carattere nella CGROM, andremo ad eseguire le seguenti operazioni (tenendo sempre conto che il pin RW è messo a massa per consentire la sola scrittura):
Si pone RS a livello logico basso per dire che dobbiamo impartire un comando.
Inviamo il comando per impostare l’indirizzo della CGROM in cui scrivere (guardiamo la tabella dei comandi nella prima parte di questa lezione). La prima posizione in cui scrivere sarà 0100 0000 (64); essendo il carattere di 8 byte, la seconda posizione (o forse meglio: il secondo quadrante) in cui incominciare a scrivere (per poter cioè personalizzare il carattere successivo), sarà invece 64+8 = 72 e così via (la routine inclusa in lcd.c fa già tutto da sè).
In pratica il primo carattere personalizzato sarà richiamabile inviando, con LCD_PUTCH, il codice 0 (prima locazione della CGROM).
Dopo aver impostato l’indirizzo della CGROM in cui scrivere, inviamo uno dopo l’altro gli 8 bytes che costituiscono il nostro carattere (nel caso della freccia, preso ad esempio poco fa, invieremo 0, poi 4, poi 2, poi 31 ecc): in questo momento il controller incrementerà in automatico la posizione del byte della CGROM in cui scrivere, per cui, dopo aver inviato il primo byte nella posizione 64, non sarà necessario specificare che il secondo byte lo vogliamo scrivere in posizione 65: basterà soltanto inviare il valore del byte.
Finita la personalizzazione dei caratteri dobbiamo lasciare la modalità di scrittura nella CGROM, per cui basterà inviare un altro comando (es.: cancellazione schermo).
I caratteri personalizzati saranno ora visibili inviando i codici da 0 a 7 (es.: con LCD_PUTCH).
Attenzione: Le locazioni in cui andremo a scrivere i nuovi caratteri sono RAM, il che vuol dire che tolta alimentazione al display, i caratteri verranno persi e al loro posto ci saranno byte posti a caso, pertanto il programma che andremo ad implementare sul picmicro dovrà prevedere, dopo l’inizializzazione del display, anche la rigenerazione dei caratteri.
Calcolo dei byte per personalizzare i caratteri
Ho preparato per i lettori che mi stanno seguendo in queste lezioni, (ma anche per tutti gli altri), un semplicissimo programmino con cui disegnare i simboli e ricavarne i valori dei byte da caricare nella CGROM: CustomCharHD44780.
Il suo utilizzo è semplicissimo, se avete capito quanto esposto sopra, non devo spiegarvi nulla:
Basta cliccare nelle celle per colorarle (settare/resettare il bit), nella textbox inferiore viene riportata la sequenza di byte del carattere, è inoltre possibile salvare il carattere e quindi riaprirlo. Nel download sono inclusi alcuni semplici caratteri che ho realizzato per questo tutorial. Quello che ci interessa è la sequenza di byte: basta cliccarci sopra e viene automaticamente copiata negli appunti, pronta per essere incollata nella routine. E’ possibile scaricare questo programma dall’apposita pagina o in fondo all’articolo.
Questo software richiede il .NET Framework 2.0 o superiore per poter funzionare.
Personalizziamo i caratteri
Nella parte precedente di questa lezione, ho esposto le funzioni disponibili con la routine lcd.c. Abbiamo visto che c’è una funzione dedicata alla personalizzazione dei caratteri:
void LCD_CUSTOMCHAR(unsigned char pos,unsigned char byte0,unsigned char byte1,unsigned char byte2,unsigned char byte3,unsigned char byte4,unsigned char byte5,unsigned char byte6,unsigned char byte7)
Il suo utilizzo è molto semplice: il primo parametro è il numero del carattere da personalizzare (valori validi: da 0 a 7), i successivi 8 parametri da passare alla funzione rappresentano la sequenza di byte calcolata col programma visto prima. Nel caso del carattere a forma di cuore (come illustrato nell’immagine di presentazione del programma) volendo personalizzare il carattere n°0 scriveremo nel main:
LCD_CUSTOMCHAR(0,0,10,31,31,14,4,0,0);
Per poter poi richiamare il carattere, possiamo utilizzare la normale funzione LCD_PUTCH:
LCD_PUTCH(0);
E’ tutto più semplice da ricordare se utilizziamo dei define per ricordarci dei numeri associati ai caratteri:
#define cuore 0 LCD_CUSTOMCHAR(cuore,0,10,31,31,14,4,0,0); LCD_PUTCH(cuore);
Quindi come avete visto, è tutto molto semplice e ci possiamo divertire in tutti i modi, creando anche semplici animazioni.

Downloads
Nel file zippato che segue è possibile scaricare 3 programmi di esempio: il primo genera la schermata così come presentato ad inizio articolo: vengono generati 8 simboli e stampati (caratteri_custom).
Il secondo genera l’immagine che vedete qui sopra (pacman_example).
Il terzo è un semplice esempio di animazione, con due pacman che mangiano i “pallini” (pacman_animated)
Gli ultimi due esempi, fanno conto di utilizzare un display lcd 16×2, per cui se state utilizzando un display di formato differente, dovrete effettuare degli aggiustamenti al codice per visualizzare il tutto in maniera ottimale. Per lo schema elettrico potete fare riferimento a quello già utilizzato nella parte precedente, facendo a meno dei pulsanti e dei led, anche il cicalino non è essenziale pur venendo utilizzato nell’esempio dell’animazione giusto per dare uno spunto.
Nota: i programmi di esempio sono stati sviluppati con una versione precedente dell’Hitec-C Compiler, per cui compilati con la nuova versione, restituiscono errori. Fate riferimento a questo articolo per maggiori informazioni su come adattare i vecchi programmi. Consiglio spassionato se volete davvero imparare a programmare: non utilizzate l’include legacy headers, ma imparate a cambiare i nomi mnemonici.
File di supporto alla settima lezione (parte 3) del corso di programmazione picmicro in C (639)
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 Ferdinando il 9 novembre 2009
Fantastico! Era da una vita che cercavo una guida così ben fatta! Complimenti!
#2 da S.D.R. il 9 novembre 2009
Buon caffè ! ;-)
Miraccomando continua con la guida .
A proposito ,cosa ne pensi del software MikroC , non sembra male , ha un sacco di funzioni che aiutano ?!
#3 da Giovanni Bernardo il 9 novembre 2009
Grazie assai, ho gradito molto :)
Mikroc a me, personalmente, non piace. Primo perchè non segue lo standard ansi, e questo può causare difficoltà se vuoi eseguire il “salto” da C a C18 o ad altri C ansi. Il non seguire lo standard ansi è dovuto proprio al fatto che ci sono queste funzioni che “aiutano”, e per me è un male perchè ti tengono all’oscuro di ciò che accade. E’ una scelta personale. Io preferisco affrontare le difficoltà una volta, imparare le cose a fatica, così le fisso meglio, ma soprattutto so cosa accade realmente. Premetto che comunque non ho mai usato MikroC, ho imparato direttamente l’ansi C sapendo di seguire uno standard universalmente riconosciuto. Ho tanto sentito parlare del MikroC e della sua semplicità dovuta a semplificazioni e alle librerie già belle e pronte, ho letto il manuale e alcune cose non mi piacciono. Un buon esercizio che puoi fare, se vuoi semplificarti la vita ma senza rinunciare a imparare uno standard, sarebbe usare il mikroc e poi riscrivere il codice per usarlo con l’hitec. E’ un po quello che sto facendo io. Ho trovato alcuni programmi di esempio scritti in MikroC e ho trovato delle sintassi a dir poco assurde, ho dovuto faticare un po’ per capire alcune parti di codice a cosa servivano e quindi convertirle in Ansi.
Se decidi di imparare il MikroC, comunque, deve essere una tua scelta personale e il mio personale commento non deve influenzarti assolutamente, ho esposto soltanto come la penso ma ovviamente ognuno deve fare ciò che più si sente a suo agio fare, è chiaro. Se il MikroC ti fa sentire più a tuo agio, allora ben venga, puoi anche pubblicare i codici che presento nelle lezioni convertiti in MikroC, cosi magari gli utenti possono capire la differenza.
#4 da S.D.R. il 17 novembre 2009
Ciao come va ;
Ho provato ad eseguire il listato proposto alla lezione 2 (led e pulsanti)del sito http://www.fisertek.it (quello in fondo alla pagina) , li usa la funzione switch , solo che non mi funziona e non riesco a capire il perchè .
Poi ho notato che inizia la main principale con “main(void)” , si può scrivere anche così ?
Alla prossima lezione che argomento tratterai ?
#5 da Giovanni Bernardo il 18 novembre 2009
Ciao tutto ok.
La funzione main la puoi scrivere anche senza il void davanti, il compilatore la accetta lo stesso, è implicito che quando ometti il void la funzione non restituisce nulla, io cerco sempre di non rimanere nulla di implicito perchè non ho idea se tutti i compilatori si comportano allo stesso modo, per cui il void lo metto sempre. Il costrutto switch è conveniente utilizzarlo quando bisogna verificare più condizioni: in questo caso invece di mettere una serie di if…else, metti lo switch così il codice è anche più leggibile, adesso non so perchè non ti funziona, se hai copiato il codice di Sergio e seguito il suo schema, ti deve funzionare, se hai fatto delle modifiche fammi vedere che modifiche hai fatto e posso esserti d’aiuto. Nella prossima lezione vorrei parlare dell’eeprom interna, per imparare come si fa a memorizzare dei dati in maniera permanente e richiarmarli anche dopo che la tensione di alimentazione è andata via. L’eeprom esterna, invece, sarà oggetto di altra trattazione perchè utilizza il protocollo I2C (almeno le memorie eeprom più diffuse – le 24xx- utilizzano questo) che è un altro paio di maniche ma penso che su questo non dirò nulla dal momento che ci sono già tanti ottimi tutorial che lo spiegano, tra cui quello di Mauro Laurenti, per cui mi limiterò a fare degli esempi di codice.
#6 da S.D.R. il 21 novembre 2009
Ciao ;
Credo di aver fatto una cosa mooooooooolto sbagliata , ossia ho incominciato a smanettare con MPLAB su Debugger ed ora non riesco più a programmare il pic ,Mannaggia a me :-S
Devo buttare via il pic , qualche consiglio !?
Uso PICkit2 e il pic 16F873A
#7 da S.D.R. il 21 novembre 2009
Dimenticavo , questo è l’errore che mi da :
PK2Error0027: Failed verify (Address = 0×0 – Expected Value 0×3FFF – Value Read 0×118A)
#8 da Giovanni Bernardo il 21 novembre 2009
La verifica fallisce quando si effettua il confronto tra il programma caricato sul pic e il programma caricato nel software di programmazione, in pratica qui ti dice: ho verificato la prima cella (0×00) della memoria programma, io (software) in quella posizione ho il valore 0×3FFF, invece sul pic ho trovato 0×118. Stai facendo la verifica del pic tenendo caricato o nessun programma sul software o un programma diverso. Esegui la cancellazione e poi fai la verifica della cancellazione (blank), se per sbaglio hai programmato i fuse per la protezione, allora non puoi piu fare niente, ma se li hai programmati così, il pickit2 te lo dice: esce scritta una cosa del tipo “ALL PROTECT” in rosso (però, a dirti il vero, questa cosa è successa pure a me anche se non era vero: avevo usato un pic vecchio che probabilmente aveva un po di ossido sui pin, ripulito non ho piu avuto problemi).
#9 da S.D.R. il 21 novembre 2009
scolleegando tutto , ossia pulsanti e led e alimentazione , quindi è alimentato solo con il PICkit2 mi da l’errore :
PK2Error0027: Failed verify (Address = 0×5 – Expected Value 0×3000 – Value Read 0×0)
#10 da Giovanni Bernardo il 21 novembre 2009
Quindi effettui la programmazione e in fase di verifica ti da il problema… Stacca il pic, passa un po di aria compressa sul pic e sullo zoccolo (non si sa mai, a me è capitato), cancellalo un paio di volte e poi riprova.
#11 da S.D.R. il 21 novembre 2009
Alla fine ci sono riuscito , però usando il software PICkit2 , ho fatto erase e poi blank check , MPLAB non lo cancellava .
Grazie
#12 da Giovanni Bernardo il 21 novembre 2009
;)
#13 da S.D.R. il 21 novembre 2009
Sicuramente smanettando con mplab ho fatto qualche casino perchè con il software PICkit2 funziona bene .
Allora torno ad un altro problema di cui ti ho accennato l’altro giorno , ossia l’istruzione switch il listato che ho creato è questo :
io uso un pic16f873A
#define XTAL_FREQ 8MHZ // questo è utilizzato dalle routine di ritardo contenute in Delay.C
#include // contiene i nomi mnemonici di registri e porte
__CONFIG (HS & WDTDIS & PWRTEN & BORDIS & LVPDIS & DUNPROT & WRTEN & DEBUGDIS & UNPROTECT);
#include “delay.c” // routine per ritardi
#define asp 120
void main(void)
{
TRISA=0b00000111;
TRISB=0b00000000;
TRISC=0b00000000;
while(1) //ripete il ciclo all’infinito
{ //graffa di apertura di while
switch (PORTA) //lettura PORTA
{ //graffa di apertura di switch
case 1: //se PORTA è 1 (0001) esegue la sequenza sotto, altrimenti salta
PORTB = 0b00000001; DelayMs(asp); //sequenza da 0 a 7
PORTB = 0b00000010; DelayMs(asp);
PORTB = 0b00000100; DelayMs(asp);
PORTB = 0b00001000; DelayMs(asp);
PORTB = 0b00010000; DelayMs(asp);
PORTB = 0b00100000; DelayMs(asp);
PORTB = 0b01000000; DelayMs(asp);
PORTB = 0b10000000; DelayMs(asp);
break; //interrompe il programma switch e torna a while
case 2: // se PORTA è 2 (0010) esegue, altrimenti salta
PORTB = 0b10000000; DelayMs(asp); //sequenza da 7 a 0
PORTB = 0b01000000; DelayMs(asp);
PORTB = 0b00100000; DelayMs(asp);
PORTB = 0b00010000; DelayMs(asp);
PORTB = 0b00001000; DelayMs(asp);
PORTB = 0b00000100; DelayMs(asp);
PORTB = 0b00000010; DelayMs(asp);
PORTB = 0b00000001; DelayMs(asp);
break;
case 4: //se PORTA è 4 (0100) esegue, altrimenti salta
PORTB = 0b10000001; DelayMs(asp); //sequenza incrociata
PORTB = 0b01000010; DelayMs(asp);
PORTB = 0b00100100; DelayMs(asp);
PORTB = 0b00011000; DelayMs(asp);
PORTB = 0b00100100; DelayMs(asp);
PORTB = 0b01000010; DelayMs(asp);
PORTB = 0b10000001; DelayMs(asp);
break;
} //graffa di chiusura di switch
PORTB=0; //spegne tutti i led
} //graffa di chiusura di while
}
#14 da Giovanni Bernardo il 21 novembre 2009
allora… manca #include <pic.h> alla seconda riga (ma penso sia piu un problema di wordpress che ha cancellato), hai messo include senza includere niente… per il resto sembra a posto…
Sei sicuro che poi il circuito sia a posto? Mettere “se PORTA è 1 (0001)” implica che hai messo la porta normalmente a massa e la “tiri su” quando premi il pulsante, probabile che hai messo la resistenza di pullup (e quindi si viene a trovare sempre a livello logico alto) e quando premi va a massa (che è la cosa piu logica da fare come illustrato nelle precedenti lezioni). Se è cosi (premendo la porta va a massa) devi cambiare i valori degli switch… 110 (6) per il primo caso, 101 (5) per il secondo e 011 (3) per il terzo
#15 da S.D.R. il 22 novembre 2009
Infatti la gestione dei tasti era invertita , ora ho messo i valori che mi hai detto tu però non riesco a capire come mai non mi funziona , premo i tasti e non si accendono il led .
Ho provato a fare il debugger-MPLABSIM con mplab per vedere come cambia lo stato delle porte solo che non so come forzare i bit della PORTA per vedere come reagisce.
Come si fa a cambiare di stato i bit per simulare la pressione dei tasti ?
#16 da Giovanni Bernardo il 24 novembre 2009
Non ho mai utilizzato il sistema di simulazione di mplab per cui non posso esserti d’aiuto, per il resto non so che dire, il programma di Sergio è corretto, il problema suppongo sia da ricercare nel circuito.
#17 da S.D.R. il 24 novembre 2009
Lo so che sono un po’ stressante però sono alle prime armi anche se anni fa ho programmato parecchio con il basic e con il PASCAL e il C è una cosa nuova per me , quindi porta pazienza .
Oltretutto sto scrivendo sulla pagina dove l’argomento è il display quindi il mio non centra molto , hai una sezione per argomenti generici così scrivo altrove .
Tornando al mio problema ho provato a fare la stessa cosa sfruttando il ciclo if else riprendendo la tua lezione sull’accensione di 2 led e funziona tutto alla perfezione quindi il circuito funziona bene , hai qualche suggerimento perchè mi scoccia questa cosa .
Grazie per l’infinita pazienza .
#18 da Giovanni Bernardo il 25 novembre 2009
Puoi scrivermi il codice che hai fatto con gli IF e che ti funziona?
#19 da S.D.R. il 25 novembre 2009
Ecco quà :
uso sempre il pic 16F873A
———————————————————–
Setting.h
#define XTAL_FREQ 8MHZ // questo è utilizzato dalle routine di ritardo contenute in Delay.C
#define BTN1 RB0
#define BTN2 RB1
#define BTN3 RB2
void settings(void)
{
TRISA=0b00000000; // Tutte output
TRISB=0b00000111;
TRISC=0b00000000;
}
———————————————-
main.c
void main(void)
{
settings(); // eseguo la funzione settings contenuta nel file header settings.h, così imposto le porte e i registri
while(1)
{
// controllo pulsante 1
if (!BTN1) // se pulsante1 premuto (quando è premuto, porta il pin allo stato logico basso)
{
DelayMs(100);// ritardo per antirimbalzo
if (!BTN1) // se dopo 100ms il pulsante è ancora premuto, non si tratta di un rimbalzo
{
PORTC=0b00000001;
DelayMs(100);
PORTC=0b00000010;
DelayMs(100);
PORTC=0b00000100;
DelayMs(100);
PORTC=0b00001000;
DelayMs(100);
PORTC=0b00010000;
DelayMs(100);
PORTC=0b00100000;
DelayMs(100);
PORTC=0b01000000;
DelayMs(100);
PORTC=0b10000000;
DelayMs(100);
}
}
else
{
PORTC=0;
}
// controllo pulsante 2
if (!BTN2) // se pulsante1 premuto (quando è premuto, porta il pin allo stato logico basso)
{
DelayMs(100); // ritardo per antirimbalzo
if (!BTN2) // se dopo 100ms il pulsante è ancora premuto, non si tratta di un rimbalzo
{
PORTC=0b10000000;
DelayMs(100);
PORTC=0b01000000;
DelayMs(100);
PORTC=0b00100000;
DelayMs(100);
PORTC=0b00010000;
DelayMs(100);
PORTC=0b00001000;
DelayMs(100);
PORTC=0b00000100;
DelayMs(100);
PORTC=0b00000010;
DelayMs(100);
PORTC=0b00000001;
DelayMs(100);
}
}
else
{
PORTC=0;
}
// controllo pulsante 3
if (!BTN3) // se pulsante1 premuto (quando è premuto, porta il pin allo stato logico basso)
{
DelayMs(100); // ritardo per antirimbalzo
if (!BTN3) // se dopo 100ms il pulsante è ancora premuto, non si tratta di un rimbalzo
{
PORTC=0b10000001;
DelayMs(100);
PORTC=0b01000010;
DelayMs(100);
PORTC=0b00100100;
DelayMs(100);
PORTC=0b00011000;
DelayMs(100);
PORTC=0b00100100;
DelayMs(100);
PORTC=0b01000010;
DelayMs(100);
PORTC=0b10000001;
DelayMs(100);
}
}
else
{
PORTC=0;
}
}// Fine ciclo continuo
} // Fine main
——————————————–
Grazie!
#20 da Giovanni Bernardo il 25 novembre 2009
Scusa un attimo… i pulsanti sulla porta B e lo switch lo fai sulla A ?!? Se i pulsanti li hai sulla porta B è la porta B che devi verificare non la A…
#21 da S.D.R. il 26 novembre 2009
No con lo switch i pulsanti sono sulla porta A infatti TRISA=0b00000111 e switch (PORTA) .
Poi ho fatto la prova di usare la porta B per i tasti e la porta C per i led però non ha funzionato lo stesso , poi ho sviluppato il software con if-else sulle ultime porte usate .
Non è che magari le limitazioni del software gratuito inibiscono questa istruzione ?
#22 da Giovanni Bernardo il 26 novembre 2009
Che io sappia l’unica limitazione della versione LITE è il fatto delle 2000H word di programma… Per il resto lo switch deve funzionare… è molto strano…
Prova con
switch(PORTA & 7)
{
case 6: // primo pulsante su porta RA0
//…
break;
case 5: // secondo pulsante su porta RA1
//…
break;
case 3: // terzo pulsante su porta RA2
//…
break;
}
in pratica: in condizioni normali (pulsanti non premuti), avendo la resistenza di pullup, il valore di PORTA è 0b00000111.
Se premo RA0, il valore di porta diviene 0b00000110, quindi facendo l’and con 0b00000111 il valore diviene 0b00000110 (ovvero 6 in decimale) ecc, mettendo l’AND con valore 7 portiamo a zero tutti i bit da 4 a 8, concentrandoci soltanto sui primi 3 bit che ci interessano, lo facciamo eventualmente qualche altro bit ci falsa il valore… Prova così e fammi sapere… devi solo aggiungere &7
#23 da S.D.R. il 27 novembre 2009
Si funziona !!!
Se non ho capito male erano gli ingressi da 4 a 8 che influivano sul funzionamento allora avrei dovuto metterli elettricamente a 5 volt ma su TRISSB da 4 a 8 sono uscite quindi dovevo mettere tutta la porta come input altrimenti bruciavo la porta ……….
Allora ho provato a mettere tutta la PORTA come INPUT ed ho fatto il CASE1 254, CASE2 253 , CASE1 251 non ho messo &7 e funziona anche così .
Ma dentro le parentesi dello switch non si può indicare solo gli ingressi che mi interessano in vece di indicare tutta la PORTA in modo che gli altri non li consideri e mi semplifico la vita ?.
In che altri contesti si può usare lo SWITCH ?
#24 da Giovanni Bernardo il 27 novembre 2009
Ecco vedi, con un po di sforzo i problemi si risolvono sempre :).
Lo switch si può usare in tutti i contesti in cui una singola variabile (PORTA in questo caso) può assumere più di due valori (fino a due soli valori si può usare l’if, ma anche lo switch). Se hai capito bene il concetto di come funziona lo switch, capisci anche che non lo puoi usare per testare una singola porta: ogni pin preso singolarmente sarebbe una variabile, nel tuo caso 3 variabili: quindi non le puoi testare tutte e 3 con un unico switch… In questo caso devi per forza ricorrere a 3 if, per rendere piu leggibile il codice si usa lo switch, ma per forza di cose in questo caso, potendo operare su una sola variabile, devi metterci per forza dentro tutto il banco di porte A. Io ti ho illustrato un sistema per mascherare le porte che non vuoi considerare, che torna utile proprio in contesti come questo.
#25 da bmx88 il 17 marzo 2010
Ciao , la tua guida è veramente bella ma non capisco perche mi succede sempre quasta cosa
Quando compilo (l’ho provato su due pc diversi)
mi da questo errore
Error [1098] C:\****\lcd.c; 248. conflicting declarations for variable “_DelayMs” (C:\****\delay.c:12)
non ho modificato niente,
nei precedenti esempi ad esempio mi dava un errore simile
definendo
#include “delay.c”
ho risolto con
#include “delay.h”
uso lo stesso pic 16f877 ma da lo stesso problema con il 16f84
uso vista sarà quello il problema.
Ciao e grazie in anticipo
#26 da Giovanni Bernardo il 17 marzo 2010
Devi includere delay.c e non delay.h, altrimenti non hai disponibile la funzione DelayMs ma solo quella DelayUs. Non arrivo a capire dove ti da l’errore… In lcd.c riga 248? E quindi riga 12 di delay.c
Ma non puo darti errore alla riga 248 di lcd.c, non ha senso, devi aver per forza modificato qualcosa se ti da l’errore li, scarica di nuovo l’esempio, non modificare nulla e compilalo per pic16f877a e vedi se ti da ancora l’errore, non è un errore causato da vista, c’è qualche problema nel codice (E’ come se DelayMs venisse dichiarato due volte), ma quello distribuito qui l’ho ricontrollato ed è ok, vedi bene il tuo.
#27 da bmx88 il 18 marzo 2010
ad esempio i sorgenti della prima lezione mi da errore in compilazione
Error [237] C:\Users\Pasquale\Desktop\PIC\Altro\delay.c; 12. function “_DelayMs” redefined
solo se cambio delay.c in delay.h compila e esegue correttamente.
Sicuramente non è un problema di codice , ma forse qualche impostazione di MPLAB?
#28 da bmx88 il 18 marzo 2010
Ok risolto , il mio problema è che aggiungevo in fase di creazione del progetto anche i file delay.c ecc. (abituato ad Eclipse o Visual cpp)
Quindi devo aggiungere solo il main , qualsiasi header o file c accessorio faccia?
Ciao e grazie
#29 da Giovanni Bernardo il 18 marzo 2010
Ecco… se seguivi le lezioni dall’inizio lo capivi subito. Devi includere solo main nel progetto e basta. Gli altri file vengono inclusi dal main con gli “include”
#30 da Livio il 7 giugno 2010
Ciao Giovanni, mi associo alla miriade di persone che ti fanno i complimenti per il sito, e per il corso sulla programmazione dei PICMicro, io sono arrivato alla lezione n..7 e ho riscontrato un problema con l’uso del display RC162051YFHLYB della APEX (non so se questi display siano di buona qualità o meno, comunque “funzionano”), quando ho caricato il programma “HELLO WORLD” il dispettoso faceva solo la sua inizializzazione interna e si fermava lì. Se invece caricavo i programmi dove si definivano dei caratteri con il comando CUSTOMCHAR funzionava tutto. Poi con un colpo di “Genio” (leggi errore di programmazione) ho scoperto che inserendo questa linea nel main , cioè:
………..
20 LCD_INIT();
21 DelayMs(100);
22 LCD_CUSTOMCHAR(bb,0,0,0,0,0,0,0,0,); // linea inserita per far funzionare il display
23 LCD_CLEAR();
………………………………
il display funzionava.
Pensando che fosse un problema di temporizzazione ho provato a inserire dei ritardi e a variare i tempi del file lcd.c, anche consultando il data sheet del display (tieni conto che io l’inglese lo fischio alla perfezione ma non so ne leggerlo ne scriverlo) non mi sembra che sia diverso dagli altri. Comunque ora funziona, ma mi è rimasta una domanda che non mi fa dormire la notte BECAUSE, WHY, PERCHE’ ???????
Non so se a altre persone è successo questo problema, ma se tu sai rispondere a questo quesito potrebbe essere utile anche ad altri (oltre a farmi dormire la notte) .
Saluti
Livio
#31 da Giovanni Bernardo il 7 giugno 2010
I display Apex sono buoni e il problema che hai non me lo so spiegare… prova a mettere un altro delay al posto dell’istruzione per il customchar, perchè alla fine non ha senso…
#32 da Livio il 11 giugno 2010
Ciao Giovanni, seguendo il tuo consiglio ho provato a sostituire l’istruzione customchar con il delay, ma il risultato non cambia, ho pure provato a mettere altre istruzioni tipo putch o puts o ancora putun, però l’unico comando che fa funzionare il display e il customchar. Come dici tu non ha senso, però ti assicuro che è così, i due display Apex
che ho funzionano solo in questo modo. Io ho scaricato i tuoi file EXE e ho usato la freedom due con il pic 16f877a mettendo il display in dotazione alla scheda di sviluppo o una di un tipo qualsiasi il tutto funziona ma mettendo le due dispettose si vedono solo i quadratini dei caratteri appena accennati, e anche regolando il trimmer del contrasto, questi diventano neri ma niente di più. A questo punto incomincio a pensare a un difetto di fabbrica, voglio provare a acquistare un’altro display di questi da un’altro centro di distribuzione di materiale elettronico e poi ti faccio sapere.
Saluti
Livio
#33 da Giovanni Bernardo il 11 giugno 2010
boh… non ti saprei dire… ma non è la prima volta che mi capitano cose strane
#34 da Ben il 21 ottobre 2010
Capita anche a me, con un Displaytech 162D!
Da 2 giorni ormai stavo impazzendo sul perché il display si rifiutasse di mostrare alcunché nonostante un corretta procedura di inizializzazione. Poi dato che usavo una libreria scritta da me mi è venuto il dubbio che avessi sbagliato qualcosa (anche se con altri LCD ha sempre funzionato) ed ho provato il codice presentato in queste lezioni, ma con gli stessi risultati.
Poco fa ho letto il commento di Livio e mi sono detto “è assurdo, ma proviamo” e ha funzionato… Mah…….. Eppure il controller è un KS0070B, perfettamente compatibile con HD44780
#35 da imugno il 13 luglio 2010
anche questo è un gran bel tutorial!! Mi sai dire però perchè se aumento la velocità di un animazione diminuendo il valore di delay di ogni ciclo non si vede quasi piu nulla? Il pacman diventa una linea verticale!!
#36 da Giovanni Bernardo il 13 luglio 2010
Se tieni conto che il carattere deve essere cancellato e poi ridisegnato in un’altra posizione è ovvio che se lo fai troppo velocemente l’immagine non ha il tempo per rimanere bene impressa nell’occhio e quindi non la vedi completa.
#37 da Pax il 15 settembre 2010
ciao ho appreso molto dalle lezionei sulla gestione di un LCD
ne appunto uno 16×2 volevo un consiglio su come poter avere più caratteri da personalizzare.
La mia idea era quella di riscrivere nelle 8 locazioni libere i caratteri custom ogni volta che ne ho bisogno nel source
ma ho appurato che nn funziona.
Ogni volta che riscrivo nelle locazioni libere durante l’esecuzione del programma cambiano anche i caratteri custom già impressi nell’LCD.
C’è qualche altro modo per avere più caratteri da personalizzare?
#38 da Giovanni Bernardo il 15 settembre 2010
Quel sistema l’ho provato pure io e pare che davvero non funzioni. Non ho idea se ci sono altri sistemi
#39 da Ben il 21 ottobre 2010
Io l’ultima volta ho risolto eseguendo una nuova inizializzazione ogni volta che devo riscrivere i caratteri personalizzati in memoria
#40 da pax il 15 settembre 2010
ricevuto. grazie cmq per la risposta
#41 da Pax il 17 settembre 2010
sono riuscito ad accontentare la mia necessità
di avere più caratteri da personalizzare.
Bisogna cmq arrivare ad un compromesso
provo a spiegare: nel mio caso avevo bisogno di
di scrivere un numero con un carattere diverso
dagli altri; un numero che va da 0 a 9
il mio numero custom è su sfondo
nero, un po’ più piccolo e stile display
sette segmenti.
Solo per avere tutto il sistema decimale
cioè i numeri da zero a nove avrei avuto bisogno
di 10 caratteri da personalizzare anzi dei soli
otto che mi può fornire il display.
Oltre a questo avevo bisogno di scrivere alcune
parole con un carattere più piccolo mettendo
anche due lettere per casella.
La soluzione a tutto questo è scegliere
quali caratteri personalizzati occorrono
sempre stampati sull’LCD e quali invece si devono
solo alternare fra loro.
nel mio caso ho sette caratteri personali che voglio
sempre stampati su LCD e un carattere (il numero)
che deve soltanto altrnarsi al valore successivo
cioè da zero a nove e poi ricominciare sempre nella
stessa posizione sul display.
Come fare:
Prima di tutto si possono programmare i primi sette
byte della “ROM” con i nostri caratteri che nn cambiano
e nell’ultimo ,l’ottavo, mettiamo il primo carattere
che dovrà cambiare nel corso del programma.
A questo punto possiamo stampare i nostri caratteri su LCD
nella posizione in cui li vogliamo.
Ora basta sapere che per cambiare il carattere “variabile”
basterà riprogrammare l’ottava posizione della “ROM”
con i byte che creano il nuovo carattere da visualizzare
senza la necessità di ristamparlo.
il carattere si modificherà automaticamente nel momento
in cui andate a riprogrammare la “ROM”.
Per i più interessati questo metodo dovrebbe anche
permettere semplici animazioni all’interno di
una singola casella. per esempio una lettera
che si sposta pixel per pixel
anzi che casella per casella.
Ovviamente scegliere quanti caratteri devono
rimanere fissi e quanti variabili è
assolutamente a discrezione personale.
Spero che tutto ciò possa servire a qualcuno.
Un grazie a SettoreZero per tutte le informazioni
utili nell’utilizzo dei PIC.
#42 da Giovanni Bernardo il 17 settembre 2010
Questo sistema non è quello che hai già esposto? Un paio di volte ci ho provato pure io ma a dire il vero non mi ha funzionato: in pratica il display si comportava in maniera strana. Quello che non ho fatto, però, è di cambiare un carattere già visualizzato come hai descritto tu adesso. Proverò. Grazie del contributo!
#43 da Tomas Zavalloni il 10 ottobre 2010
Salve, e complimenti anche da parte mia. Mi chiedevo se in futuro è previsto un tutorial anche per i display grafici….. sarebbe un interessante sviluppo dell’argomento. Reperire informazioni per i controller hitachi è infatti molto facile, ma (probabilmente per un mio limite) non è la stessa cosa per i display grafici…..
Ne approfitto per salutare tutti … ciao ciao
#44 da Giovanni Bernardo il 10 ottobre 2010
E’ previsto per i KS0108, ma non so dire quando.
#45 da Tomas Zavalloni il 12 ottobre 2010
Ottimo, sono molto curioso. Un saluto a tutti
#46 da neuro_79 il 29 gennaio 2011
Ciao Giovanni scrivo per un aiuto su questi maledetti display che mi stanno facendo dannare da qualche giorno…..
per fare le prove ho ben 3 display: Displatech 162, 162A e 162B. Tutti dovrebbero essere “identici” con controller KS0070B compatibile con Hitachi. Allora con il tuo software “Hello World” i risultati sono che sul primo si vedono i caratteri appena accennati (ovvero una asta, qualche puntino e cosi via) mentre sugli altri due si vede solo la prima riga del display tutta scritta ovvero piena di quadratini. Qualche consiglio? Ho già provato le cose suggerite nei commenti tipo aggiungere una istruzione “CustomChar()” oppure qualche ritardo. Nei data sheet dei display la fase di inizializzazione è identica a quella del controller hitachi ma c’è solo quella a 8 bit, mentre tu usi quella a 4.
#47 da Giovanni Bernardo il 29 gennaio 2011
Controlla il datasheet di quel controller (del controller, no del display) se prevede la modalità a 4 bit. Penso di si perchè vengono dichiarati compatibili.
#48 da neuro_79 il 29 gennaio 2011
Si la modalità a 4 bit è prevista, si vede anche dal datasheet che hai fornito tu….pero sembra essere decisamente diversa da quella dell’Hitachi che tu hai riportato anche nella lezione.
#49 da Giovanni Bernardo il 29 gennaio 2011
La riga piena di quadratini può anche essere un problema di contrasto. Ci può essere pure un problema di alimentazione. Inoltre alcuni display vogliono che le 4 linee dati che non hai usato siano messe a massa, altri vogliono che siano lasciate flottanti.
#50 da neuro_79 il 29 gennaio 2011
avendo letto tutti i commenti possibili ed immaginabili ho provato tutte queste cose, il contrasto (agendo sul potenziometro) funziona. Inoltre ho provato sia con pin (i 4 bit che non sono usati) a massa che flottanti. Per problema di alimentazione che intendi? i display che tu usi di solito sono proprio con controller Hitachi? io sono riuscito a trovare solo questi della displytech
#51 da Giovanni Bernardo il 29 gennaio 2011
Generalmente i display che uso io non hanno il chip, ma la quella che chiamiamo affettuosamente “la macchia”… cioè quella goccia nera che serve a coprire i chip stampati, per cui non c’è scritto nulla e non ho idea di che controller si celi li sotto. Per alimentazione intendo un’alimentazione non sufficiente, hai controllato che la tensione sia 5 volt? A quali pin del micro l’hai collegato?
#52 da neuro_79 il 29 gennaio 2011
pure i miei sono così con una o due gocce nere. Dai datasheet vedo che sono tutti KS0070B, ne ho appena provato uno displatech 20×2 con controller KS0066U semre della displaytech ma fa esattamente uguale….prima riga tutta scritta. Ho provato il micro sia su basetta di prova (realizzata da me) sia su breadbord collegamendo unicamente alimentazioni e display…stesso risultato
#53 da Giovanni Bernardo il 29 gennaio 2011
PIC/pin utilizzati?
#54 da neuro_79 il 29 gennaio 2011
PIC16F877A e pin come da tuo schema. Ovvero LCD collegato alla porta D come segue:
LCD pin 1 -> GND
LCD pin 2 ->Vcc
LCD pin 3 ->potenziometro
LCD pin 4 ->RD2
LCD pin 5 ->GND
LCD pin 6 ->RD3
LCD pin 7 ->GND
LCD pin 8 ->GND
LCD pin 9 ->GND
LCD pin 10 ->GND
LCD pin 11 ->RD4
LCD pin 12 ->RD5
LCD pin 13 ->RD6
LCD pin 14 ->RD7
Ho fatto altre prove anche con alimentazione separata per l’LCD (masse in comune) ma niente….solito risultato…prima riga tutta iena….sia sul display 162A che sul 162B mentre il 162 fà una cosa diversa ovvero si vedono qualche punto e qualche linea che ricorda vagamente la scritta “Hello World” che sto scrivendo. Insomma proprio non mi ci raccapezzo…..le prove tra i diversi LCD le ho fatte proprio togliendo uno e infilando l’altro senza alcuna modifica…ma continuano a fare cose diverse.
#55 da neuro_79 il 11 febbraio 2011
Ciao Giovanni, ho delle novità a riguardo dei problemi suddetti. Dopo aver escluso errori di cablaggi e di alimentazioni sono riuscito a far funzionare il DISPLAYTECH 162B e anche il DISPLAYTECH 162A modificando leggermente i ritardi nella funzione void LCD_STROBE( ):
void LCD_STROBE (void)
{
DelayUs(250);
LCD_EN = 1;
DelayUs(250);
DelayUs(250);
DelayUs(250);
DelayUs(250);
LCD_EN=0;
}
Lo sò che sono ritardi ENORMI ma ripeto che è l’unico modo per far funzionare la libreria da te fornita. Quando dico UNICO intendo proprio UNICO…nel senso che se abbassi anche uno solo di quei tempi a 200 per esempio non funziona piu!!!! Con ritardi cosi grandi è chiaro che las crittura dei caratteri risulta molto lenta, ho quindi risolto abbassando il ritardi tra i caratteri:
#define LCD_TW_DELAY 1 // milliseconds between characters
ottenendo discreti risultati.
Recentemente ho acquistato la FREEDOM II con PICkit2. Assieme alla scheda viene fornito un LCD proprio DISPLAYTECH 162A e ho potuto verificare quando suddetto anche con questo nuovo hardware. Quindi posso escludere ogni problema di programmatore/scheda di sviluppo che usavo prima.
Purtroppo questa soluzione NON funziona NE con il DISPLAYTECH 162D ne con il DISPLAYTECH 202B. Avendo un po di tempo mi metterò ad indagare anche su questi…rifacendo magari le funzioni di inizializzazioni con una versione ad 8 bit invece che 4. Premetto però che tutti gli LCD menzionati hanno datasheet identici (parlo della descrizione dei ritardi, della descizione della fase di inizializzazione ecc) quindi mi sembra strano si comportino in maniera diversa.
Hai qualche idea?!
#56 da Giovanni Bernardo il 11 febbraio 2011
Scusa, invece di mettere 4 delayus(250) non era più logico mettere DelayMs(1) ?! Poi: non usare le funzioni di ritardo che ci sono con le lezioni perchè non forniscono ritardi precisi. Scarica quelle nuove dal menu picmicro -> librerie il perchè danno problemi con quei due display non te lo so dire ma penso sia sempre una questione di temporizzazioni. Appena ho tempo quelle librerie le devo sistemare un po.
#57 da neuro_79 il 11 febbraio 2011
Hai assolutamente ragione per il DelayMs(1), usavo i 4 ritardi perchè stavo provando ad abbassarli/alzarli ecc e giocare con i us era meglio che con i ms. Provero con i nuovi timer, comunque pure io vorrei indagare di piu….magari rifacendo le funzioni anche nella versione a 8 bit. Se ridai un occhio alle tue librerie magari tieni in considerazione questo problema con i display della DIPLAYTECH…in fondo sono i piu economici e diffusi…..pure sulla FREEDOM II usa quelli.
#58 da Giovanni Bernardo il 11 febbraio 2011
Quella libreria non l’ho fatta io, come specificato, e l’ho utilizzata con successo con molti display senza mai avere problemi, per tale motivo decisi di pubblicarla, aggiungendo soltanto qualche funzione che mancava come quella appunto dei caratteri personalizzati che per me sono molto importanti. La libreria però non segue i miei personali “standard” di scrittura del codice e in più ci sono alcuni errori e molte migliorie da fare. In aggiunta quelle librerie di Delay ho scoperto che sono un vero orrore: inducono un ritardo di quasi il doppio di quello che si imposta e questo pure causa non pochi problemi. Il funzionamento a 8 bit è piu semplice: anzichè inviare i dati in 2 nibble, li invii tutti insieme. Inoltre a 8 bit puoi anche eseguire la lettura del display e questo è comodo per creare effetti particolari anche se quasi nessuno usa questa funzione.
#59 da neuro_79 il 17 febbraio 2011
Ciao Giovanni, eccomi con una nuova puntata della guerra contro gli LCD! :-)
Ho provato come da te suggerito la nuova libreria delay direttamente su FREEDOM II (per evitare problemi di cablaggi, ritardi ecc) ma niente di buono. La libreria LCD fornita con le lezioni non funziona a meno che non si mettano mani ai ritardi come con la vecchia delay. In particolare è sufficiente aumentare il delay nello strobe:
void LCD_STROBE (void)
{
LCD_EN = 1;
DelayMs(10);
LCD_EN=0;
}
Inoltre ho testato queste librerie delay nuove con un semplice lampeggio di led…..bhe non sono per nulla precise. Per esempio con una chiamata del tipo:
…
…
…
LED1 = LED1 ^ 1;
DelayS(50);
…
…
Ottengo un ritardo di circa 10 secondi (led 10 secondi acceso e 10 secondi spento).
Ho fatto altre prove anche con le funzioni DelayMs() e DelayBigMs() ottenendo errori analoghi. Tu ottenevi risultati migliori?
Ottengo un ritardo
#60 da Giovanni Bernardo il 21 febbraio 2011
A me questi ritardi così alti non mi convincono. Secondo me hai problemi col quarzo o cose del genere
#61 da gabriel il 18 ottobre 2011
Ciao Giovanni, condivido i problemi che descrive neuro_79, nel mio caso con Displaytech 202A. Riesco a farlo funzionare soltanto con un impulso di strobe di almeno 5 mSec. Dato che anche a me, la cosa non mi convince afatto (secondo il datasheet i tempi dovrebbero essere di nanosecondi!!) ho fatto una seconda routine di strobe di 5 mSec e ho provato a rimpiazzare progressivamente nel programma le chiamate alla funzione di strobe normale. Ho scoperto che soltanto una chiamata necessita della funzione “lunga” per funzionare ed è all’interno di LCD_NIBBLE_OUT.
Di seguito riporto una parte del codice modificato che a me funziona:
/****************************************
Enable LCD to read data
*****************************************/
void LCD_STROBE (void)
{
LCD_EN = 1;
DelayUs(1);
LCD_EN=0;
}
/****************************************
Enable LCD to read data
*****************************************/
void LCD_STROBELUNGO (void)
{
LCD_EN = 1;
DelayMs(5);
LCD_EN=0;
}
/****************************************
Write a nibble to the LCD
****************************************/
void LCD_NIBBLE_OUT (unsigned char c)
{
if (c & 0b10000000)
LCD_D7=1;
else LCD_D7=0;
if (c & 0b01000000)
LCD_D6=1;
else LCD_D6=0;
if (c & 0b00100000)
LCD_D5=1;
else LCD_D5=0;
if (c & 0b00010000)
LCD_D4=1;
else LCD_D4=0;
LCD_STROBELUNGO();
}
Secondo me, nella funzione LCD_NIBBLE_OUT c’è qualcosa che non va. In passato ho lavorato con display di diversi tipi e non ho mai avuto dei problemi anche se riconosco che è la prima volta che uso la modalità a 4 bit. Spero di trovare la risposta a questo mistero.
A presto.
#62 da neuro_79 il 21 febbraio 2011
Bhe come specificato le prove le ho fatte con la FREEDOM II senza nessun cablaggio esterno. Cmq a proposito delle nuove librerie Delay scaricate dal tuo sito….tu ottieni risultati precisi?! Ovvero, con un programmino lampeggio led tipo:
LED1 = LED1 ^ 1;
DelayS(50);
ottieni proprio il tempo voluto? Perche io con questa ottengo circa 10 secondi…sempre prove fatte su FREEDOM II.
#63 da Giovanni Bernardo il 21 febbraio 2011
Si ottengo tempi precisi, verificati con l’oscilloscopio. Mi riferisco sempre alle librerie enanched precision. Ho quel problema che dici tu con le librerie vecchie che si trovano nei primi esempi che ho messo.
#64 da Cicche il 10 marzo 2011
Con il Cambio di STROBE l’lcd funziona pure a me!
Io ho dovuto aggiungere nei setting RD1=0 perchè sulla nuova Freedom il pin R/w è collegato e se lasciato indefinito mi dava il problema della prima riga riempita di quadratini neri.
Aggiungo inoltre che pure io ho problemi con i delay, sia quelli di Giovanni sia quelli della microchip, quando ho tempo provo con quelli enanched precision e le vecchie librerie su il pic in dotazione della FreedomII v3(18F4550)
Cosi a occhio con le prime lezioni notavo una discrepanza di 1/4 dei tempi proposti, domani provo con delay alti per verificare meglio. (su fredom + 16F877A)
#65 da Giovanni Bernardo il 10 marzo 2011
Si quei ritardi sono imprecisi, durano quasi il doppio. Le routine enanched precision danno alcuni problemi, la funzione delayBigUs non va quindi non usarla mai.
#66 da aledio il 16 marzo 2011
Complimenti per l’ottimo lavoro.
Vorrei fare ancora una donazione e volevo contattarti per usare la posta pay e non paypal con cui ho avuto problemi .
Non puoi mettere il tuo indirizzo di posta per comunicazioni in generale ?
Ciao Alessandro
#67 da Giovanni Bernardo il 17 marzo 2011
Vi ringrazio ma non uso la postepay.
#68 da McGyver86 il 5 giugno 2011
ciao giovanni, è da un pò che non frequento il sito e devo dire che è cresciuto e ricco di informazioni! ti scrivo per un consiglio, ho un display 4×20 (credo) che monta 3 ks0086 e un toshiba t6963c. non sono riuscito trovare niente in giro per la rete, non è che per caso e gentilmente avresti qualche informazione??? il display ha 28 pin suddivisi sui 2 lati più corti (8+8 su un lato e 6+6 sull’altro) ho notato che alcuni pin sono cortocircuitati! non so se posso utilizzarlo per questi bellissimi progetti che proponi, quindi ti chiedo una mano a reperire qualche informazione!!
grazie mille, un saluto!
#69 da Etti il 30 settembre 2011
Ciao, che ricordi sulla creazione e programmazione di una matrice o degli sprites che dovevano apparire sul video per creare qualche giochino o effetti usando il commodore 64, computer di altri tempi, con poca memoria, velocità, colori, suoni (pochi byte ma allegri), ma con tantissima semplicità, fantasia e passione, ma soprattutto divertimento e gratificazione assicurata.
Ciao a tutti…..
#70 da Cecco il 3 dicembre 2011
Ciao Etti.
Mi associo ai ricordi degli sprites del C=64.
Bei tempi.
#71 da gabriel il 19 ottobre 2011
Buongiorno a tutti, i problemi segnalati da Neuro_79 e da Cicche con alcuni modelli di display mettono alla luce un difetto abbastanza serio della library lcd.c legato alla mancanza di lettura dello stato di BUSY (flag di LCD occupato e non disponibile per ricevere altri comandi). Giocare sulle temporizzazioni risolve provvisoriamente il problema ma rende la library dipendente da un modello specifico di display, rallenta il funzionamento del sistema e per ultimo impegna lo sviluppatore per lungo tempo di prove / errori per trovare i tempi giusti rischiando però che questi non siano ideali in tutte le circostanze.
Di conseguenza, ho introdotto alcune modifiche nell library per la gestione del busy con ottimi risultati. L’unica complicazione consiste nel dover aggiungere una linea di controllo (R/W) per poter leggere i dati dal LCD (la linea LCD_RW bisogna scollegarla da massa e collegarla a un pin del micro).
Le modifiche introdotte nella library consistono semplicemente nella creazione di una funzione chiamata LCD_BUSY che restituisce un bit con lo stato del display. Questa funzione viene chiamata da un ciclo while introdotto all’inizio della funzione LCD_WRITE. Troverete anche le definizioni di TRIS delle linee di dati D4/D7 all’inizio della library perché per leggere un dato dal display le linee di dati devono essere configurate come ingressi.
La commutazione TRIS per ogni linea di dati all’interno della funzione LCD_BUSY non è elegantissima ma evita problemi nel caso i pin di dati del micro siano discontinui oppure si trovino su porte diverse (ricordate di modificare i pin in base all’hardware).
Dato che la library ha una sola funzione per la scrittura di un dato oppure di un comando nel display (LCD_WRITE) ho dovuto aggiungere la variabile statica tempRs all’interno di LCD_BUSY per memorizzare e poi ripristinare lo stato di LCD_RS.
Avendo operativa la linea LCD_RW si potrebbe aggiungere anche una funzione di lettura del tipo LCD_READ. Un’altra cosa che si potrebbe fare è una gestione di timeout del loop di attesa del busy perchè se il display non risponde il micro rimane bloccato. Lascio aperta la strada ed spero che il mio lavoro sia utile.
A presto.
Modifice del codice:
#define LCD_RW RD1 // Read / Write register (19/10/2011 by Gabriel)
#define LCD_RS RD2 // Register select
#define LCD_EN RD3 // Enable
#define LCD_D4 RD4 // LCD data 4
#define LCD_D4_TRIS TRISD4 // LCD data 4 tris (19/10/2011 by Gabriel)
#define LCD_D5 RD5 // LCD data 5
#define LCD_D5_TRIS TRISD5 // LCD data 5 tris (19/10/2011 by Gabriel)
#define LCD_D6 RD6 // LCD data 6
#define LCD_D6_TRIS TRISD6 // LCD data 6 tris (19/10/2011 by Gabriel)
#define LCD_D7 RD7 // LCD data 7
#define LCD_D7_TRIS TRISD7 // LCD data 7 tris (19/10/2011 by Gabriel)
/****************************************
LCD BUSY
(19/10/2011 by Gabriel)
*****************************************/
bit LCD_BUSY (void)
{
static bit busyFlag;
static bit tempRS;
LCD_D4_TRIS = 1; // Set data lines D7-D4 as input
LCD_D5_TRIS = 1;
LCD_D6_TRIS = 1;
LCD_D7_TRIS = 1;
tempRS = LCD_RS; // Save the LCD_RS value
LCD_RW = 1; // Set Read mode
LCD_RS = 0; // Command mode
LCD_EN = 1; // read bits 4-7 (bit7 = busy status)
DelayUs(1);
busyFlag = LCD_D7; // copy busy status in busyFlag Var
LCD_EN = 0;
DelayUs(1);
LCD_STROBE(); // read bit 0-3 (not used)
LCD_D4_TRIS = 0; // Set data lines D7-D4 as output
LCD_D5_TRIS = 0;
LCD_D6_TRIS = 0;
LCD_D7_TRIS = 0;
LCD_RW = 0; // Set write mode
LCD_RS = tempRS; // Load LCD_RS with the value saved
return busyFlag;
}
/****************************************
Write a byte to the LCD (4 bit mode)
****************************************/
void LCD_WRITE (unsigned char c)
{
while(LCD_BUSY());
LCD_RW = 0; // write mode
LCD_NIBBLE_OUT(c);
c <<= 4;
LCD_NIBBLE_OUT(c);
DelayUs(50);
#if LCD_TYPEWRITE==1
if (LCD_RS)
{
DelayMs(LCD_TW_DELAY); // Delay between characters
}
#endif
}
#72 da plotino il 4 novembre 2011
ciao bernardo
prima di tutto complimenti. La tue guide sono eccellenti
Volevo chiedere a te che sei un esperto, esiste un buon simulatore per PIC,
che appunto simuli LCD, USART, etc, ovvero tutto il “mondo esterno” che può essere collegato al
microntrollore, in modo da fare un completo debug software del nostro programma?
Grazie e complimenti ancora
#73 da Alessio il 12 novembre 2011
Ciao volevo solo ringraziarti per il tuo lavoro.
grazie a questo articolo e ad altri simili ho compreso la logica alla base dei display LCD alfanumerici e ho imparato a programmarli in assembler! sono in debito! (non son ancora passato al C)
Un sincero Grazie.
#74 da Cecco il 2 dicembre 2011
Buona sera a tutti.
E’ il mio primo post.
Sto anche io iniziando col C per PIC ma invece di Hi-Tech uso il CCS.
Grazie a SettoreZero e LaurTech dal quale ho preso una Freedom2, sto apprezzando la potenza e la versatilità dell’elettronica digitale.
Bello e stimolante anche se il C a livello avanzato è molto impegnativo.
In questi giorni, anzi…notti, sto lavorando sul LCD.
Una domanda, quando lancio il programma CustomChar, mi viene fuori un errore tipo ” unable to find the runtime for the application”
Nella barra dell’errore c’è scritto .Net Framework Initialization error.
Ho controllato e ho tutti i .NetFramework installati.
Grazie1000
Fra.
#75 da Cecco il 12 dicembre 2011
OK risolto.
Reinstallate tutte le versioni, ora va.
#76 da giulio_93 il 28 marzo 2012
ciao.. complimenti per le lezioni! allora ho appena provato a compilare l’hello world ma mi dice ..conflicting declarations for variable “DelayMs”.. in delay.c
Ho cambiato solo 2 define:
#define LCD_RS RE0
#define LCD_EN RE1
nella mia scheda è così.
#77 da Giovanni Bernardo il 28 marzo 2012
includi solo il MAIN nel progetto. Come sta scritto nell’articolo.