MODULI: Esempio DISPLAY LCD CON INTERFACCIA I2C

CIAO - Per implementare questo progetto occorre un display LCD con interfaccia I2C "YwRobot Arduino LCM1602 IIC V1").

Interfaccia yWRobot

Il potenziometro blu serve ad aggiustare il contrasto del display. La linea dei dati è riconoscibile con la sigla SDA mentre quella del clock con SCL.  Grazie a tale interfaccia I2C è possibile collegare il display, che solitamente prevederebbe un minimo di 6 pin (RS, E, D4, D5, D6, D7) più un pin per la gestione della retroilluminazione (vedi esempio sul display LCD 16x2) ,

Display LCD - Connessioni dirette

con soli 2 pin ( SCL ed SDA ) oltre all’alimentazione +5v e Gnd.

I²C è l'abbreviazione di Inter Integrated Circuit (pronuncia i-quadro-ci o i-due-ci), è un sistema di comunicazione seriale bifilare utilizzato nei circuiti integrati.

Il protocollo hardware dell'I2C richiede due linee seriali di comunicazione:
SDA (Serial DAta) per i dati
SCL (Serial CLock) per il clock.
Per la presenza del clock I2C è un bus sincrono.
Va aggiunta una connessione di riferimento, (detta talvolta impropriamente GND)  e una linea di alimentazione Vdd a cui sono connessi dei resistori di pull-up (le resistenze di pull-up e pull-down sono usate per garantire che gli ingressi di un sistema logico siano a livelli logici previsti) e che può anche non essere condivisa da tutti i dispositivi connessi.
L'I²C ha 7 bit di indirizzo e quindi può gestire 128 possibili indirizzi (detti nodi).

Il classico bus I²C è composto da almeno un master ed uno slave. Il nodo master è il dispositivo che emette il segnale di clock mentre il nodo slave è quello che si sincronizza sul segnale di clock senza poterlo controllare.

Per poter utilizzare tale interfaccia è necessario scaricare un'altra libreria LiquidCrystal_I2C alternativa a quella di sistema LiquidCrystal fornita con l'ambiente IDE di Arduino.

Per utilizzarla è necessario rimuovere la cartella originale associata alla libreria di sistema.Successivamente occorre scompattare il file e copiare la cartella prodotta (LiquidCrystal) all'interno della cartella contenente le librerie di Arduino (solitamente C:\Program Files\Arduino\libraries). Terminare aggiungendo la cartella appena copiata, mediante il menu "Add Library", all'interno dell'IDE di Arduino.

Agiunta libreria

Al termine dell'importazione i files vengono ricopiati nella cartella C:\Users\<User>\Documents\Arduino\libraries. Se ci sono problemi nell'installazione occorre svuotare la cartella di libreria appena ricopiata.

La libreria "LiquidCrystal_I2C" possiede tutte le funzioni presenti nella libreria di sistema "LiquidCrystal". Inoltre supporta gran parte delle funzioni listate nella specifica ufficiale per i display LCD presente all'indirizzo http://playground.arduino.cc/Code/LCDAPI. I metodi disponibili della classe LiquidCrystal_I2C sono: begin(), clear(), home(), setCursor(), write(), print(), cursor(), noCursor(), blink(), noBlink(), display(), noDisplay(), scrollDisplayLeft(), scrollDisplayRight(), autoscroll(), noAutoscroll(), leftToRight(), rightToLeft(), createChar()

Esercitazione pratica 1:

Obiettivo progetto: Scrivere sul display LCD la scritta "AVE\nPROF" (su 2 righe) seguita dalla frase (sempre su 2 righe) che indica i secondi trascorsi dall'avvio del programma su Arduino (non è ammesso l'utilizzo di millis()). Ad esempio: "Sono trascorsi\n2 secondi".

Consegna:

Fornire 2 soluzioni equivalenti che implementano gli obiettivi del nostro progetto.

Nella prima soluzione utilizzare il seguente template come prototipo iniziale per il programma (utilizzo la funzione predefinita loop() per aggiornare lo scorrere dei secondi).

/* --------------------------------------------------------------------------
 1^ TEMPLATE
 Scrivo su un display LCD 20 caratteri x 4 linee, con interfaccia seriale I2C 
 "YwRobot Arduino LCM1602 IIC V1", la frase "AVE\nPROF\Sono trascorsi\n%d secondi" 
 SDA è connesso alla pin analogico A4
 SCL è connesso alla pin analogico A5
 -------------------------------------------------------------------------- */
#include <Wire.h>  // Libreria di sistema - E' richiesta da I2CIO.cpp
#include <LiquidCrystal_I2C.h> // Libreria LCD I2C

// Imposta i pin usati sul chip I2C per le connessioni 
// con il display LCD: addr, en, rw ,rs ,d4 ,d5 ,d6 ,d7 ,bl ,blpol
// ed inoltre pone l'indirizzo del display a 0x27
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);

void setup()
{
   // Devo inizializzare il display LCD 20 caratteri per 4 linee
   
   // Devo pulire lo schermo
   
   // posizionarsi nei punti del display richiesti e scrivere
   
   // le frasi richieste

}

void loop()
{
   // INSERIRE QUI LE ISTRUZIONI CHE REPUTI NECESSARIE
   // PER L'AGGIORNAMENTO DELLO SCHERMO
}

Successivamente fornire un ulteriore soluzione seguendo il template seguente (sfrutto un loop infinito all'interno della funzione setup per aggiornare lo scorrere dei secondi).

/* --------------------------------------------------------------------------
 2^ TEMPLATE
 Scrivo su un display LCD 20 caratteri x 4 linee, con interfaccia seriale I2C 
 "YwRobot Arduino LCM1602 IIC V1", la frase "AVE\nPROF\Sono trascorsi\n%d secondi" 
 SDA è connesso alla pin analogico A4
 SCL è connesso alla pin analogico A5
 -------------------------------------------------------------------------- */
#include <Wire.h>  // Libreria di sistema - E' richiesta da I2CIO.cpp
#include <LiquidCrystal_I2C.h> // Libreria LCD I2C

// Imposta i pin usati sul chip I2C per le connessioni 
// con il display LCD: addr, en, rw ,rs ,d4 ,d5 ,d6 ,d7 ,bl ,blpol
// ed inoltre pone l'indirizzo del display a 0x27
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);

void setup()
{
   // Devo inizializzare il display LCD 20 caratteri per 4 linee
   
   // Devo pulire lo schermo
   
   // posizionarsi nei punti del display richiesti e scrivere
   
   // le frasi richieste

   // INSERIRE QUI LE ISTRUZIONI CHE REPUTI NECESSARIE
   // PER L'AGGIORNAMENTO DELLO SCHERMO

}

void loop()
{
   // IN QUESTA SOLUZIONE NON E' AMMESSO SCRIVERE ALCUNA
   // ISTRUZIONE NELLA FUNZIONE DI SISTEMA LOOP()
}

Soluzioni:

Ecco la soluzione relativa al 1° template:

/* --------------------------------------------------------------------------
 2^ TEMPLATE
 Scrivo su un display LCD 20 caratteri x 4 linee, con interfaccia seriale I2C 
 "YwRobot Arduino LCM1602 IIC V1", la frase "AVE\nPROF\Sono trascorsi\n%d secondi" 
 SDA è connesso alla pin analogico A4
 SCL è connesso alla pin analogico A5
 -------------------------------------------------------------------------- */
#include <Wire.h>  // Libreria di sistema - E' richiesta da I2CIO.cpp
#include <LiquidCrystal_I2C.h> // Libreria LCD I2C
// Imposta i pin usati sul chip I2C per le connessioni 
// con il display LCD: addr, en, rw ,rs ,d4 ,d5 ,d6 ,d7 ,bl ,blpol
// ed inoltre pone l'indirizzo del display a 0x27
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);

void setup()
{
   // Devo inizializzare il display LCD 20 caratteri per 4 linee
  lcd.begin(20, 4); 
   
  // Pulisce l'LCD e pone il cursore all'inizio
  lcd.clear(); 
   
  // posizionarsi nei punti del display richiesti e scrivere
  // le frasi richieste
  lcd.print("AVE");             // Stampo a video il AVE ...
  lcd.setCursor(0, 1);          // 1° colonna - 2° riga
  lcd.print("PROF");            // e prosegue sulla stessa riga
  lcd.setCursor(0, 2);          // 1° colonna - 3° riga
  lcd.print("Sono trascorsi "); // e prosegue sulla stessa riga
  lcd.setCursor(0, 3);          // 1° colonna - 3° riga
  lcd.print("0 secondi ");      // e prosegue sulla stessa riga
}

void loop()
{
   // INSERIRE QUI LE ISTRUZIONI CHE REPUTI NECESSARIE
   // PER L'AGGIORNAMENTO DELLO SCHERMO
  lcd.setCursor(0, 3);       // 1° colonna - 3° riga
  lcd.print(millis()/1000);
  lcd.print(" SECONDI");     // e prosegue sulla stessa riga
}

e quella relativa al 2° template:

/* --------------------------------------------------------------------------
 2^ TEMPLATE
 Scrivo su un display LCD 20 caratteri x 4 linee, con interfaccia seriale I2C 
 "YwRobot Arduino LCM1602 IIC V1", la frase "AVE\nPROF\Sono trascorsi\n%d secondi" 
 SDA è connesso alla pin analogico A4
 SCL è connesso alla pin analogico A5
 -------------------------------------------------------------------------- */
#include <Wire.h>  // Libreria di sistema - E' richiesta da I2CIO.cpp
#include <LiquidCrystal_I2C.h> // Libreria LCD I2C
// Imposta i pin usati sul chip I2C per le connessioni 
// con il display LCD: addr, en, rw ,rs ,d4 ,d5 ,d6 ,d7 ,bl ,blpol
// ed inoltre pone l'indirizzo del display a 0x27
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);

void setup()
{
  // Devo inizializzare il display LCD 20 caratteri per 4 linee
  lcd.begin(20, 4); 
   
  // Pulisce l'LCD e pone il cursore all'inizio
  lcd.clear(); 
   
  // posizionarsi nei punti del display richiesti e scrivere
  // le frasi richieste
  lcd.print("AVE");             // Stampo a video il AVE ...
  lcd.setCursor(0, 1);          // 1° colonna - 2° riga
  lcd.print("PROF");            // e prosegue sulla stessa riga
  lcd.setCursor(0, 2);          // 1° colonna - 3° riga
  lcd.print("Sono trascorsi "); // e prosegue sulla stessa riga
  lcd.setCursor(0, 3);          // 1° colonna - 3° riga
  lcd.print("0 secondi ");      // e prosegue sulla stessa riga
  for (;;)                      // Loop infinito
  {
    lcd.setCursor(0, 3);        // 1° colonna - 3° riga
    lcd.print(millis()/1000);
    lcd.print(" SECONDI");      // e prosegue sulla stessa riga
  }
}

void loop()
{
   // IN QUESTA SOLUZIONE NON E' AMMESSO SCRIVERE ALCUNA
   // ISTRUZIONE NELLA FUNZIONE DI SISTEMA LOOP()
}

Si osservi come la parte  iterata del ciclo infinito for (;;) coincida con il corpo della funzione predefinita loop().

Codice Sorgente A

Obiettivo progetto: Pilotare un display lcd con interfaccia I2C in modo che appaia il testo digitato sul Serial Monitor. Si noti che la linea di invio del Serial Monitor accetta al massimo 69 caratteri.

soluzione:

Costruiamo il seguente circuito

Display LCD I2C

Display LCD I2C

utilizzando il seguente codice:

/* --------------------------------------------------------------------------
 Esempio creato partendo dal codice all'indirizzo: 
 http://arduino-info.wikispaces.com/LCD-Blue-I2C
 Scrive su un display LCD 20 caratteri x 4 linee, con interfaccia seriale I2C 
 "YwRobot Arduino LCM1602 IIC V1", quello che digito sul Serial monitor
 SDA è connesso alla pin analogico A4
 SCL è connesso alla pin analogico A5
 -------------------------------------------------------------------------- */
#include <Wire.h>  // Libreria di sistema - E' richiesta da I2CIO.cpp
#include <LiquidCrystal_I2C.h> // Libreria LCD I2C

// Imposta i pin usati sul chip I2C per le connessioni 
// con il display LCD: addr, en, rw ,rs ,d4 ,d5 ,d6 ,d7 ,bl ,blpol
// ed inoltre pone l'indirizzo del display a 0x27
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);

void setup()
{
   Serial.begin(9600); 
   lcd.begin(20,4); // Inizializzo LCD 20 caratteri per 4 linee
                    // e accende la retroilluminazione.
   // lcd.backlight(); // Accende la retroilluminazione 
   // lcd.noBacklight(); // Accende la retroilluminazione
   // Invita l'utente a scrivere qualcosa sul serial monitor
   // che verrà poi replicato sul display LCD (impostare "Nesun fine riga" o 
   // "No Line Ending" sul serial Monitor).
   lcd.clear(); // pulisce lo schermo
   lcd.setCursor(0,0); // Si posiziona sulla prima riga, prima colonna
   lcd.print("Digita sul");
   lcd.setCursor(0,1);
   lcd.print("Serial Monitor");  
   lcd.setCursor(0,2);
   lcd.print("del testo ...");
   Serial.println("Digita del testo ...");
}

void loop()
{
  char ch;
  int r=0, c=0;
    if (Serial.available()) // Se ci sono caratteri sul Serial Monitor 
    {
      // aspetta un attimo affinchè arrivi l'intero messaggio
      delay(100);
      lcd.clear(); // pulisce lo schermo
      while (Serial.available() > 0)
      {
         lcd.setCursor(c,r);
         lcd.write(Serial.read());
         c++;
         if (c==20) {c=0; r++;}
      }
    }
}

Avviato il programma sul display appare questo messaggio:

Display LCD I2C

Digitando il testo "Ciao, sono Marco Sechi ed ho implementato questo progetto"

LCD Display I2C

otteniamo sul display il seguente output:

Output display LCD I2C

Si osservi, nonostante la tipologia del circuito utilizzata sia completamente diversa, l'estrema somiglianza di questo programma con quello proposto nell'esempio (analogo come funzionalità richieste) al codice sorgente C proposto per LCD senza bus I2C.

Esercitazione pratica 2:

Obiettivo progetto: Implementare un circuito che utilizzando un keypad ed un display LCD 20x4 simula la lettura di una password di accesso e mostra la scritta "ACCESSO NEGATO" oppure "BENVENUTO" a seconda se è stata digitata la password corretta (supponiamo sia 123456) o meno. Il tasto * assume il significato di invio del codice segreto e pertanto quando Arduino rileva tale carattere deve procedere con le routine di controllo dell'accesso. Il tasto # ha la funzione di reset e pertanto quando Arduino rileva tale carattere deve scartare tutti i numeri precedentemente digitati e procedere con la lettura di una nuova password. Il sistema di accesso, una volta raggiunti gli 11 caratteri, azzera la sequenza memorizzata e si comporta come se fosse stato premuto il tasto *.

soluzione:

Connettiamo i pin del Keypad seguendo lo schema riportato:

Per il display utilizziamo il medesimo circuito visto nell'esempio specifico del dislay LCD 20x4 I2C

Prima di iniziare a scrivere il codice Immaginiamo il contenuto del display a secondo delle diverse situazioni:

MESSAGGI DI ACCESSO
L'accesso è stato autorizzato La password non è corretta

MESSAGGI DI ERRORE
Avviso quando digito più di 10 caratteri Avviso quando invio una password vuota

Il codice del programma è il seguente:

/* --------------------------------------------------------------------------
 Simulo l'accesso ad un sistema dove la password e' digitata su un keypad 
 e l'esito appare su un display LCD 20 caratteri x 4 linee, con interfaccia 
 seriale I2C "YwRobot Arduino LCM1602 IIC V1"
 SDA è connesso alla pin analogico A4 - SCL è connesso alla pin analogico A5
 -------------------------------------------------------------------------- */
// *************************************************************
// IMPOSTAZIONE PER IL KEYPAD
// *************************************************************
#include <Keypad.h>

const byte ROWS = 4; //4 righe
const byte COLS = 3; //3 colonne
char keys[ROWS][COLS] = 
{
  {'1','2','3'},
  {'4','5','6'},
  {'7','8','9'},
  {'*','0','#'}
};
byte rowPins[ROWS] = {8, 7, 6, 5}; // Pin di arduino connessi ai pin 1,2,3 e 4 delle righe del keypad
byte colPins[COLS] = {4, 3, 2};    // Pin di arduino connessi ai pin 5,6,7 delle righe del keypad
Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );

// *************************************************************
// IMPOSTAZIONI PER IL DISPLAY LCD
// *************************************************************
#include <Wire.h>  // Libreria di sistema - E' richiesta da I2CIO.cpp
#include <LiquidCrystal_I2C.h> // Libreria LCD I2C
// Imposta i pin usati sul chip I2C per le connessioni 
// con il display LCD: addr, en, rw ,rs ,d4 ,d5 ,d6 ,d7 ,bl ,blpol
// ed inoltre pone l'indirizzo del display a 0x27
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);

// -------------------------------------------------------------
// PROGRAMMA VERO E PROPRIO
// -------------------------------------------------------------
String passwd="";
int pos=3; // Posizione del carattere * relativo alla password
void PulisciRigaPassword()
{
    lcd.setCursor(0, 1);               // 1° colonna - 2° riga
    lcd.print("                    "); // Pulisce la riga
    lcd.setCursor(0, 1);               // 1° colonna - 2° riga
    lcd.print("-> ");                  // e prosegue sulla stessa riga
    passwd="";
    pos=3;
}

void ScriviRiga3e4(String Frase3, String Frase4)
{
   lcd.setCursor(0, 2);  // 1° colonna - 3° riga
   lcd.print(Frase3); 
   lcd.setCursor(0, 3);  // 1° colonna - 4° riga
   lcd.print(Frase4); 
   lcd.setCursor(pos, 1);   // Ritorno alla posizione originale
                            // sulla 2° riga
}
void Pulisci3e4Riga()
{
    String Vuota="                    ";
    ScriviRiga3e4(Vuota,Vuota);
}
void MessaggioErrore(String Frase)
{
    String Frase3="...::: AVVISO :::...";
    String Frase4=">> "+Frase;
    ScriviRiga3e4(Frase3,Frase4);
}

void setup()
{
  // Devo inizializzare il display LCD 20 caratteri per 4 linee
  lcd.begin(20, 4); 
  // Pulisce l'LCD e pone il cursore all'inizio
  lcd.clear(); 
  lcd.print("DIGITA LA PASSWORD:");
  PulisciRigaPassword();
}

void loop()
{
  char key = keypad.getKey();
  if (key != NO_KEY)
  {
    Pulisci3e4Riga();
    if (key=='#') // Tasto di reset
      PulisciRigaPassword();
    else if (key=='*') // Tasto di invio
    {
      if (passwd.length()!=0)
      {
          lcd.setCursor(0, 2); // 1° colonna - 3° riga
          if (passwd=="123456")
             lcd.print("||   BENVENUTO    ||"); 
          else
             lcd.print("** ACCESSO NEGATO **"); 
          PulisciRigaPassword();
      }
      else
         MessaggioErrore("Nessun carattere!");
    }
    else
    {
        if (passwd.length()<10)
        {
           lcd.setCursor(pos++, 1);
           lcd.print("*"); // Maschero il numero digitato
           passwd=passwd+String(key);
        }
        else
        {
           MessaggioErrore("Troppi caratteri!");
           PulisciRigaPassword();
        }
    }
  }
}