quinta-feira, 16 de janeiro de 2014

LCD Nokia 5110 com Arduino #sucesso

No meu post anterior eu falei que comprei um display LCD Nokia 5110 no MercadoLivre e, inicialmente não consegui fazê-lo funcionar... Depois eu atualizei o post dizendo que ele funcionou e fiquei de dar mais detalhes depois. Bom, aqui estão os detalhes!

Display Nokia 5110 sobre datasheet Philips PCD8544

Apesar de todo mundo se referir ao display como Nokia 5110, a parte importante para conhecer é o controlador que ele tem dentro, que na verdade é feito pela Philips! O controlador/driver é um Philips PCD8544.

O datasheet dele é bem extenso (32 páginas), mas você não precisa se preocupar, está numa linguagem bem acessível e tem até um exemplo de como desenhar uma palavra na tela, mostrando o que você deve enviar, bit a bit (página 22).


Para tentar entender o funcionamento do módulo, imprimi as páginas 14 e 22 e ainda montei uma "cola" para anotar o que cada byte representava em bits.


O problema que eu estava tendo com este módulo parecia estar na definição do contraste, então criei o código abaixo para vocês testarem o módulo de vocês. O que ele faz é desenhar uma barra que vai crescendo a medida que o contraste vai aumentando.

Este gif animado dá uma ideia do resultado. O contraste ideal é aquele em que a barra fica bem escura sobre um fundo claro. Se o fundo do seu LCD escurecer, é porque você passou da conta e deve diminuir um pouquinho.


//Controlador de Display LCD Nokia 5110 (84x48 pixels)
//em 13 de janeiro de 2014
//Mais informacoes: umcarneiro.blogspot.com
//Licenca: MIT (use como quiser!)

//Pinos utilizados no arduino
#define PIN_SCE   7  //pino 2 do display
#define PIN_RESET 6  //pino 1 do display
#define PIN_DC    5  //pino 3 do display
#define PIN_SDIN  4  //pino 4 do display
#define PIN_SCLK  3  //pino 5 do display

//Tamanho do LCD em pixels:
#define LCD_X     84
#define LCD_Y     48

//Estas variaveis restringem o menor e o maior contraste a ser testado
//Se sua tela estiver muito escura desde o inicio do teste, diminua este valor
const int MIN_CONTRAST = 175; //tem que ser maior que 128
//Se sua tela estiver muito clara no fim do teste, aumente este valor
const int MAX_CONTRAST = 200; //tem que ser menor que 255


void setup(void)
{
  pinMode(PIN_SCE, OUTPUT);   // Inicializa os pinos...
  pinMode(PIN_RESET, OUTPUT);
  pinMode(PIN_DC, OUTPUT);
  pinMode(PIN_SDIN, OUTPUT);
  pinMode(PIN_SCLK, OUTPUT);
  digitalWrite(PIN_RESET, LOW); //RESET no controlador
  digitalWrite(PIN_RESET, HIGH);
  LcdWrite(LOW, 0x21 );  // Function set: PD=0 (On); V=0 (Horizontal); H=1 (Extended instruction set)
  LcdWrite(LOW, 0xBA );  // Define o LCD Vop (Contraste). //XXXXXXXXXXXXXXX
  LcdWrite(LOW, 0x04 );  // Define o coeficiente de temperatura (??)
  LcdWrite(LOW, 0x14 );  // LCD bias mode 1:48  (??)
  LcdWrite(LOW, 0x20 );  // Function set: PD=0 (On); V=0 (Horizontal); H=0 (Basic instruction set)
  LcdWrite(LOW, 0x0C );  // Display control = 10 (Normal)
  
  //Clear - apaga todas as posicoes
  for (int index = 0; index < LCD_X * LCD_Y / 8; index++)
  {
    LcdWrite(HIGH, 0x00); //bit 0 em todo mundo!
  }

}

//Cuida da burocracia: envia o comando ou dado seguindo o protocolo do chip
void LcdWrite(byte dc, byte data)
{
  digitalWrite(PIN_DC, dc); //define se vai mandar dado ou comando
  digitalWrite(PIN_SCE, LOW); //ativa o chip para receber dados
  shiftOut(PIN_SDIN, PIN_SCLK, MSBFIRST, data); //envia um bit de cada vez, comecando pela esquerda
  digitalWrite(PIN_SCE, HIGH); //desativa o envio de dados
}

//desenha uma barra repetindo o byte informado
void desenhaBarra(int largura, byte caracter)  
{
  //Coloca o cursor no local correto
  LcdWrite( 0, 0x80 | 0);  // Coluna 0
  LcdWrite( 0, 0x40 | 2);  // Linha 2

  //barra horizontal
  for (int index = 0; index < largura; index++)
  {
    LcdWrite(HIGH, caracter);
  }
}

void loop(void)
{  
  //dentro dos limites que estabelecemos, define o contraste a mostrar
  for (int contrast = MIN_CONTRAST; contrast < MAX_CONTRAST; contrast++)
  {  
    LcdWrite(LOW, 0x21 );  // Function set: PD=0 (On); V=0 (Horizontal); H=1 (Extended instruction set)
    LcdWrite(LOW, contrast );  // Define o contraste (VOP)
    
    //define a largura da barra proporcional ao contraste
    int largura = map(contrast, MIN_CONTRAST, MAX_CONTRAST, 0, LCD_X); 

    LcdWrite(LOW, 0x20 );  // Function set: PD=0 (On); V=0 (Horizontal); H=0 (Basic instruction set)
    LcdWrite(LOW, 0x0C );  // Display control = 10
  
    //desenha a barra horizontal na largura que definimos
    desenhaBarra(largura, 0x7f);
    delay(350); //dah um tempo para podermos ver o resultado
  }
  
  //desenha uma barra invisivel da largura da tela
  desenhaBarra(LCD_X, 0x00); //ou seja, apaga a barra!
}


Juro que este foi o código mais simples que eu consegui fazer! Enchi de comentários para ver se conseguia torná-lo inteligível. Defini o contraste usando números decimais de propósito, para facilitar a leitura.  Tem um ótimo conversor de números entre binário, decimal e hexa nesta página. Eu usei um bocado para tentar entender o que estava acontecendo.

O circuito ficou assim:



Pino LCDResistorArduinoCor
1-RST10kPino 6Vermelho
2-CE10kPino 7Azul
3-DC10kPino 5Amarelo
4-DIN10kPino 4Verde
5-CLK10kPino 3Azul
6-VCC-3.3vVermelho
7-LIGHT330RGNDAzul
8-GND-GNDPreto

O código que eu tinha usado da outra vez usava, obrigatoriamente os pinos 11 e 13, mas este é mais simples e não tem essa exigência.

Repare também que o backlight (pino 7 do LCD) foi para o GND. Confesso que não entendi bem a lógica disso, já que o backlight se acende quando colocamos +3V direto no pino 7 e GND no pino 8.


O desenho do módulo de LCD no Fritzing eu fiz por conta própria. Se quiser o arquivo ou aprender a fazer você mesmo, leia este outro post.

Espero que vocês consigam colocar as suas telinhas para funcionar!

Quem sabe em um próximo post a minha já terá virado um olho de brinquedo?

Aguardem!

UPDATE: Desenhei o olho para colocar no LCD. Vejam neste outro post.

Você pode ver todas as etapas deste projeto usando este link, ou clicando no marcador "olho_de_lcd", abaixo.

4 comentários:

  1. Consegui nem ligar a minha. não aparece nada na tela. Peguei um tutorial para usar a biblioteca Adafruit_GFX, mas deu pau e nem compilou

    ResponderExcluir
    Respostas
    1. Calieno, na minha primeira tentativa também tentei uma biblioteca e não deu em nada... Esse código do meu post não usa biblioteca nenhuma, tenta com ele. Se não conseguir, procure o grupo arduino-brasilia (do Google Groups) e posta lá detalhes do seu projeto (que peças está usando, o código, etc), que o pessoal do grupo (eu, inclusive) tenta te ajudar. Boa sorte!

      Excluir
  2. desculpe, mias poderia me ajudar fazer apenas um código parecido com o do teste de contraste, preciso criar uma barra que de acordo com uma variavel que sera incrementada ou decrementada a barra aumente ou diminua.

    ResponderExcluir
    Respostas
    1. Oi, Pc. Não parece difícil. Faça o seguinte: use o código deste post do jeito que está aí para testar seu circuito, tela, etc. Se tudo funcionar, você pode adaptá-lo trocando todo o método "void loop(void)" por:

      void loop(void)
      {
      int largura = analogRead(A0);
      desenhaBarra(largura, 0x7f);
      delay(350);
      desenhaBarra(LCD_X, 0x00);
      }

      Na variável largura eu coloquei um analogRead(A0), imaginando que você poderia ler o valor de um potenciômetro, por exemplo.

      Teste aí e conte para a gente!

      Abs!
      Otávio

      Excluir