terça-feira, setembro 29, 2015

Outra Opção de Display Alfanumérico com Interface I2C

Já vimos aqui um display alfanumérico com interface I2C. A aparência e legibilidade deste modelo são ótimas, mas é um display relativamente frágil e com um conector com espaçamento reduzido, o que dificulta a montagem. A Deal Extreme (e outros lugares) possui um display alfanumércio 2x16 "comum" já acoplado a um adaptador I2C. Vamos exercitá-lo aqui.



Examinando a placa do adaptador, observamos que:
  • Tem um trimpot para regular o contraste do display
  • Tem um jumper para habilitar/inibir o backlight
  • A conversão I2C paralelo é feita por um PCF8574
  • Tem três ilhas de configuração marcadas com A0, A1 e A2
  • O conector para ligação ao microcontrolador tem, como esperado, quatro sinais: GND, VCC, SDA e SCL.

 O PCF8574 é  um integrado bastante popular para expandir a capacidade de E/S e saída digital de microcontroladores. O seu endereço I2C é 0 1 0 0 A2 A1 A0. Ou seja, varia entre 0x20 e 0x27, dependendo dos pinos A2, A1 e A0. No caso da minha placa, as ilhas de configuração estão desconectadas e o endereço de fábrica é 0x27. A velocidade máxima no I2C é 100KHz.

O funcionamento do PCF8574 é muito simples: o valor escrito via I2C vai para os pinos P0 a P7; uma leitura via I2C retorna o valor nestes mesmos pinos.

Portanto, a única questão é saber a qual sinal do LCD corresponde cada um dos pinos P0 a P7 do PCF8574. Para isto eu liguei o display ao Arduino: GND em GND, VCC em 5V, SDA em A4 e SCL em A5 (Arduino UNO ou Nano, se for outra versão veja aqui) , carreguei no Arduino o programa abaixo e abri o Serial Monitor:
// Programa para acionar uma a uma as saída do
// conversor I2C / Paralelo PCF8574
// DQ, Set/2015

#include <Wire.h>

void setup()
{
  Serial.begin (9600);
  Wire.begin();
}

void loop()
{
  byte x = 1;
  
  delay (10000);
  for (int i = 0; i < 8; i++)
  {
    Serial.println (i);
    Wire.beginTransmission(0x27);
    Wire.write(x);
    Wire.endTransmission();
    delay (3000);
    x = x << 1;
  }
  Serial.println();
}
Usando um multímetro para ler tensão, liguei uma ponta ao terra e a outra ao sinal RS do display. Olhando o Serial Monitor e o multímetro, descobri que o sinal RS correspondia ao pino P0. Fazendo o mesmo com os demais pinos do LCD, obtive:
  • RS = P0
  • RW = P1
  • E = P2
  • A = P3 (backlight)
  • D4 = P4
  • D5 = P5
  • D6 = P6
  • D7 = P7

Existem algumas bibliotecas já prontas para displays com interface I2, mas nem todas tem a flexibilidade de configuração da conexão do PCF8574 ao display. Acabei usando a biblioteca NewLiquidCrystal de F Malpartida. É uma biblioteca que suporta vários tipos de conexão de display, o que pode ser confuso no início.

Após baixar o ZIP expanda a pasta NewliquidCrystal  dentro da pasta libraries do diretório onde ficam os seus sketches e renomeie-a para LiquidCrystal_I2c (para não confundir a IDE).O programa abaixo mostra a biblioteca funcionando:
// Exemplo simples de uso da biblioteca
// NewliquidCrystal 
//   (https://bitbucket.org/fmalpartida/new-liquidcrystal/downloads)
// com um display com conexão I2C 
//   (http://www.dx.com/p/i2c-iic-lcd-1602-display-module-with-white-backlight-4-pin-cable-for-arduino-raspberry-pi-374741)

#include <Wire.h> 
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(
  0x27,    // Endereço do PCF8574
  2,       // bit que controla o sinal E(nable) do LCD
  1,       // bit que controla o sinal RW do LCD
  0,       // bit que controla o sinal RS do LCD
  4,       // bit que controla o sinal D4 do LCD
  5,       // bit que controla o sinal D5 do LCD
  6,       // bit que controla o sinal D6 do LCD
  7,       // bit que controla o sinal D7 do LCD
  3,       // bit que controla o Backlight do LCD
  POSITIVE  // Backlight acende quando o sinal está em nível Alto
);

byte seg, minuto, hora; 

void setup()
{
  lcd.begin(16,2);    // Inicia o LCD
  DisplayWrite (0, 0, "DQSoft");   
  DisplayWrite (1, 0, "00:00:00");    
}

void loop()
{
  if (++seg == 60)  
  {  
    seg = 0;  
    if (++minuto == 60)  
    {  
      minuto = 0;  
      if (++hora == 99)  
        hora = 0;  
      DisplayWriteDec (1, 0, hora);  
    }  
    DisplayWriteDec (1, 3, minuto);  
  }  
  DisplayWriteDec (1, 6, seg);  
  delay (1000);   // aguarda um segundo  
}

// Mostra número decimal de 00 a 99  
void DisplayWriteDec (byte l, byte c, byte num)  
{  
  char aux[3];  
    
  aux[0] = 0x30 + num / 10;  
  aux[1] = 0x30 + num % 10;  
  aux[2] = 0;  
  DisplayWrite (l, c, aux);  
}  
  
// Posiciona o cursor e mostra mensagem  
void DisplayWrite (int l, int c, char *msg)
{
  lcd.setCursor(c,l);
  lcd.print(msg);
}

Nenhum comentário: