Corso programmazione PICMicro in C – Lezione 7 (parte 2/3) – Interfaccia con LCD – Hello World + semplice menu sul display per attivare delle funzioni


Scritto da Giovanni Bernardo in data 28 ottobre 2009

menu_su_display_con_picmicroDopo 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:

schema_lezione_7

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:

hello_world_display_lcd_e_picmicro

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:

menu_su_lcd

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:

menu_su_lcd_schema

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 (457)

Lasciate commenti.

Articoli che potrebbero interessarti:

L'articolo ti è piaciuto o ti è stato utile per risolvere un problema? Supporta e mantieni in vita questo sito, ci basta soltanto un caffè o una birra

  1. #1 da emanuele il 29 novembre 2009

    ciao ma e possibile convertire il codice in arduino???

  2. #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?

  3. #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

  4. #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;
    }

  5. #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.

  6. #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.

  7. #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.

  8. #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!! ;)

  9. #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

  10. #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?

  11. #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.

  12. #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.

  13. #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

  14. #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

  15. #27 da Epicus il 12 marzo 2010

    grazie 1000 :)

  16. #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

  17. #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

  18. #31 da MayTs il 18 aprile 2010

    grazie mille, ora funziona:
    ho rifatto i collegamenti e va alla grande…

  19. #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

  20. #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.

  21. #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.

  22. #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.

  23. #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.

  24. #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

  25. #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);
    }

    }

    }

  26. #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

  27. #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

  28. #47 da Fabio il 3 luglio 2010

    Grandiii

  29. #48 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! **********

    • #49 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.

  30. #50 da Skynet il 29 luglio 2010

    Giovanni,

    se non sbaglio dovrebbe essere incluso, dato che sono gli esempi
    che ho preso dal file .zip.

    • #51 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.

  31. #52 da Skynet il 29 luglio 2010

    OK!
    Piu’ tardi inizializzero’ tutto!

  32. #53 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! **********

    • #54 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

(non verrà pubblicata)
  1. Ancora nessun trackback

Fusion theme by digitalnature | Articoli (RSS) e Commenti (RSS) ^