Manual

do

Maker

.

com

LCD Nokia 5110 - Nenhum outro é tão legal!

LCD Nokia 5110 - Nenhum outro é tão legal!

LCD Nokia 5110 - Nenhum outro é tão legal!

O que tem de tão legal nesse display Nokia 5110? Primeiramente, o controle que você pode ter sobre cada pixel, de modo que você poderá desenhar o que desejar  e com isso exibir relógios, gauges, progress bar e tudo isso junto utilizando Arduino!

Nesse tutorial de hoje, veremos a maneira mais simples de interagir com esse display pra que você possa começar agora mesmo a brincar com ele. Vamos começar pela lista de materiais:

Eu preferi fazer uma plaquinha pra evitar a protoboard e também para estrear meus resistores SMD. Tentei outras vezes e só deu errado, pela primeira vez acertei (aplausos)! Porém, estou obtendo ruidos na tela. No video eu mostro o  "shot zero" com uma barra de progresso nessa placas, utilizando um Arduino Pro Mini 5V.

nokia5110-01-300x169.webp

Os pinos do Arduino a serem utilizados são a sequência de 3 a 7 e também você precisará do GND comum. Ainda, alimento o Arduino com 5V mas o display é 3V3, por isso coloquei um regulador de tensão ( na placa que fiz - aplausos novamente, porque esse também é SMD) e um diodo no GND pra garantir que nada queime em caso de fios invertidos na alimentação. Outra opção seria uma ponte de diodos, mas estou sendo o mais simplista possível.

Especificações do display Nokia 5110

Esse display tem uma resolução bacana de 84x48 pixels. Isso é mais do que um ícone grande de computador, que varia entre 32x32 ou 64x64. Isso significa que você pode desenhar com boa compreensão, mas obviamente a resolução não será a mesma de um computador porque os pixels são grandes.

Esse display está disposto em um circuito quadrado de 4.5cm e usa um controlador Philips PCD8544. Isso é o que as pessoas não sabem porque normalmente se fala apenas "display de Nokia".

Tem circuitos azuis que descrevem tensão em 5V e 3V3, mas esse vermelho certamente é 3V3, operando desde 2.7V.

Seu consumo é ínfimo; inferior a 20mA, de modo que poderia seguramente ser ligado diretamente ao 3V3 de um Arduino, mas como a alimentação do Arduino Pro Mini fiz externamente, preferi colocar um regulador de tensão pra pegar alimentação pro display.

Datasheet Nokia 5110

Nesse link você terá acesso ao datasheet com muitas informações interessantes, mas que provavelmente serão dispensadas por você, considerando o uso de uma biblioteca pronta.

Wiring

A primeira coisa que faço quando preciso de imagens é ir ao Google Images. Lá certamente terá tudo o que você precisa pra não precisar reinventar a roda. Eu peguei essa imagem abaixo que é muito parecido com o que fiz na placa de prototipagem, com algumas pequenas resalvas.

nokia_5110_wiring-300x240.webp

Eu não ia usar potenciômetro, mas aí eu não poderia aproveitar o desenho acima (e com isso não sei se estou tendo mais ou menos trabalho em não redesenhar). Já no exemplo com Arduino UNO eu não alimentei o backlight do display.

Biblioteca para Nokia 5110

Tem várias; várias "mesmo". Se você abrir a IDE do Arduino e ir em Sketch->Include Library->Library Manager e digitar "5110", verá de imediato algumas opções, mas me parece que a biblioteca da Adafruit é a mais completa porque tem funções prontas para desenho, então como queremos por o negócio pra funcionar logo, vamos direto nela, buscando-a através desse link.

Se quiser experimentar mais algumas além das já citadas, você pode pegar aquiaqui e aqui. Não se preocupe, mal não fará, sugiro que experimente todas.

Seleção dos pinos

Em algumas dessas bibliotecas você pode definir pinos diferentes do padrão, caso seu projeto já esteja utilizando os atualmente descritos. Algumas estão no código principal, outras em um dos arquivos de include, é fácil achar e modificar.

Como desenhar seu próprio caracter no Nokia 5110

É facílimo manipular cada pixel desse display. Mas precisamos de alguns conceitos básicos para isso, então primeiramente devemos definir que a matriz de um caracter é composto por 5 colunas de 8 linhas. Pense nisso como uma (inheca) planilha do excell. A segunda coisa a pensar é nos endereçamentos, que podem ser feitos de diversas maneiras, mas pra conseguir desenhar um gráfico em um espaço pequeno, vou utilizar a representação hexadecimal:

0x010x010x010x010x01
0x020x020x020x020x02
0x040x040x040x040x04
0x080x080x080x080x08
0x100x100x100x100x10
0x200x200x200x200x20
0x400x400x400x400x40
0x800x800x800x800x80

Como você pode notar, os endereços são os mesmos, o que faz todo o sentido. Mas isso precisa ser colocado em um array para dizer qual posição está sendo manipulada. Então:

static byte my_char[] = {0xff, 0x00, 0x00, 0x00, 0x00};

Isso significa que na coluna 1 foram "ligados" todos os 8 pixels. Esse resultado é obtido pela soma dos valores hexadecimais. Para fazer essa conta, você pode utilizar uma calculadora no computador com capacidade de conversão de bases ou ainda, fazer a conta em bits:

bit76543210
decimal1286432168421

Depois é só preencher o valor desejado, somando os valores decimais dessa tabela anterior. Isto é, invés de colocar em hexadecimal, você poderia colocar em bits ou em decimal:

#binario
static byte my_char = {0b11111111,0,0,0,0};
#decimal
static byte my_char = {255,0,0,0,0}

Depois, basta utilizar o método drawBitmap da biblioteca em questão:

lcd.drawBitmap(thermometer, THERMO_WIDTH, THERMO_HEIGHT);

Acalme-se e aproveite a leitura. Até aqui estamos falando das possibilidades, do funcionamento, como é escrever uma letra do display, como os caracteres são formados; só compreenda, chegaremos em excelentes exemplos.

Desenhar no display sem biblioteca

Essa parte pode ser interessante se você quiser dominar o display (não que esse seja o domínio, mas é o caminho). O código para  escrever no display diretamente sem biblioteca é bastante curto e baseando-se no exemplo de manipulação por endereço, vamos ver o que pode ser feito.

Tudo binário, coluna por coluna

É a representação mais fácil. Pense que você tem uma coluna de 8 bits. Ponto final. Desse modo você só precisa escrever sequencialmente de 8 em 8 bits. Se quiser escrever a letra "L", definindo que cada letra deva ter 8 bits de altura por 5 de largura, ficaria assim:

static byte my_char3[] = {0b11111111,0b10000000,0b10000000,0b10000000,0b10000000};

Talvez não lhe faça muito sentido de imediato, mas como estamos escrevendo do bit mais significativo, pense que estamos escrevendo da esquerda para a direita e de baixo para cima. Logo, o primeiro campo do array é a coluna preenchida e os demais campos são 1 bit do rodapé do caracter.

1
1
1
1
1
1
1
1....    1   1   1   1

Tendo montado seu caracter, basta rodar um loop para escrevê-lo na tela. No código de exemplo escrevi alguma sujeira na tela para mostrar a escrita em binário, decimal e hexadecimal. Isso significa que não importa o que você usar como base, servirá perfeitamente. Em seguida está o caracter "L" utilizando apenas 1 coluna por 1 linha. Você pode fazer o que quiser, basta montar suas estruturas.

Função para escrever letras no Nokia 5110

Se definirmos que o caracter deve ter 8x5 pixels, então uma função pode ajudar na escrita de letra a letra escrevendo os binários de uma maneira um pouco mais simplificada:

void writePixels(unsigned char *data){
    digitalWrite(PIN_DC, HIGH); //Voce pode mandar dado ou comando para o display. Por isso, necessita informar
    digitalWrite(PIN_SCE, LOW); //abre recepcao de dados
    for (int i=0;i<5;i++){
        shiftOut(PIN_SDIN, PIN_SCLK, MSBFIRST, data[i]); 
    }
    digitalWrite(PIN_SCE, HIGH); //Fim da recepcao de dados
}

O exemplo está funcional no código, como você pode ver.

Barra de progresso no Nokia 5110

Isso é um exemplo extremanente bobo, mas para introdução é perfeito para mostrar uma animação na tela. O código que disponho a seguir está devidamente comentado, inclui uma função para limpar a tela e os exemplos supracitados. Em outros artigos patrocinados pela Autocore Robóticafaremos melhores aplicações para esse display, por enquanto já é informação o suficiente para você brincar com liberdade.

Enfim, o resultado final desse tutorial está nesse código:

//Nokia 5110 sem bibliotecas
//Pinos
#define PIN_SCE   7  //display: 2
#define PIN_RESET 6  //display: 1
#define PIN_DC    5  //display: 3
#define PIN_SDIN  4  //display: 4
#define PIN_SCLK  3  //display: 5

//LCD
#define Nokia5110_X     84
#define Nokia5110_Y     48

const int CONTRAST = 175; // > 128 & < 256

void setup(void){
    pinMode(PIN_SCE, OUTPUT);
    pinMode(PIN_RESET, OUTPUT);
    pinMode(PIN_DC, OUTPUT);
    pinMode(PIN_SDIN, OUTPUT);
    pinMode(PIN_SCLK, OUTPUT);
    digitalWrite(PIN_RESET, LOW);
    digitalWrite(PIN_RESET, HIGH);
    
    writeToNokia5110(LOW, 0x21 );  // Function set: PD=0 (On); V=0 (Horizontal); H=1 (Extended instruction set)
    writeToNokia5110(LOW, 0xBA );  // Contraste
    writeToNokia5110(LOW, 0x04 );  // Temperatura aqui se refere a luminosidade
    writeToNokia5110(LOW, 0x14 );  // Datasheet...
    writeToNokia5110(LOW, 0x20 );  // Function set: PD=0 (On); V=0 (Horizontal); H=0 (Basic instruction set)
    writeToNokia5110(LOW, 0x0C );  // Display control = 10 (Normal)

    clearDisplay();
}

void clearDisplay(){
    //Limpa o array preenchendo com 0 todos os bits sequencialmente
    for (int i=0; i<((Nokia5110_X * Nokia5110_Y)/8); i++){
        writeToNokia5110(HIGH, 0x00);
    }
}

void writeToNokia5110(byte dataOrCommand, byte data){
    /*
    Logica:
    - Avisa que vai mandar dados
    - Habilita a recepcao de dados
    - Envia os dados (da esquerda para a direita)
    - Encerra o envio
    */
    digitalWrite(PIN_DC, dataOrCommand); //Voce pode mandar dado ou comando para o display. Por isso, necessita informar
    digitalWrite(PIN_SCE, LOW); //abre recepcao de dados
    shiftOut(PIN_SDIN, PIN_SCLK, MSBFIRST, data); //MSB eh "Most Significant Bit". O mais significante fica aa esquerda
    digitalWrite(PIN_SCE, HIGH); //Fim da recepcao de dados
}

void writePixels(unsigned char *data){
    digitalWrite(PIN_DC, HIGH); //Voce pode mandar dado ou comando para o display. Por isso, necessita informar
    digitalWrite(PIN_SCE, LOW); //abre recepcao de dados
    for (int i=0;i<5;i++){
        shiftOut(PIN_SDIN, PIN_SCLK, MSBFIRST, data[i]); 
    }
    digitalWrite(PIN_SCE, HIGH); //Fim da recepcao de dados
}

//Barra de progresso
void progressBar(int width) {
    //Referente a duas areas de caractere
    static byte my_char1[] = {0xff, 0x00};
    
    //Valor em decimal, binario e hexadecimal. 80 e 0b10100000 sao
    //o mesmo valor. 0b01110101 e 0x75 sao o mesmo valor, ou seja,
    //escolha a base desejada, mas eh mais facil escrever em binario 
    //por parecer um "bordado"
    static byte my_char2[] = {80, 0b01110101,0x75,0b01010000};
    
    //Comando: posicionamento do cursor
    writeToNokia5110( 0, 0x80 | 0);  // Coluna 0
    writeToNokia5110( 0, 0x40 | 0);  // Linha  0

    //Dado: escreve os valores de cada caractere no array
    writeToNokia5110(HIGH, my_char2[0]);
    writeToNokia5110(HIGH, my_char2[1]);
    writeToNokia5110(HIGH, my_char2[2]);
    writeToNokia5110(HIGH, my_char2[3]);
    writeToNokia5110(HIGH, 0b11100111);
    writeToNokia5110(HIGH, 0b00000000);
    writeToNokia5110(HIGH, 0b00000000);
    
    //escrever o "L" do tutorial:
    static byte my_char3[] = {0b11111111,0b10000000,0b10000000,0b10000000,0b10000000};
    for (int i=0;i<5;i++){
        writeToNokia5110(HIGH,my_char3[i]);
    }


    static byte b[] = {0b00000000,0b00000000,0b00000000,0b00000000,0b00000000};
    writePixels(b);
    
    static byte c[] = {0b10101010,0b01010101,0b10101010,0b01010101,0b10101010};
    writePixels(c);
    
    //Comando: reposicionamento do cursor
    writeToNokia5110( 0, 0x80 | 0);  // Coluna 0
    writeToNokia5110( 0, 0x40 | 2);  // Linha 2

    //Array da barra de progresso
    for (int i=0; i<width; i++){
    if (i%2 == 0){
        writeToNokia5110(HIGH, my_char1[0]);
    }
    else{
        writeToNokia5110(HIGH, my_char1[1]);
    }
  }
}

void loop(void)
{  
    //dentro dos limites que estabelecemos, define o contraste a mostrar
    for (int i = 175;i<200;i++){  
        //definicao da barra
        int width = map(i, 175, 200, 0, Nokia5110_X); 

        writeToNokia5110(LOW, 0x20 );  // Function set: PD=0 (On); V=0 (Horizontal); H=0 (Basic instruction set)
        writeToNokia5110(LOW, 0x0C );  // Display control = 10
  
        progressBar(width);
        delay(350);
    }
  progressBar(Nokia5110_X);
  clearDisplay();
}

O video é só uma demonstração da prova de conceito, incluindo um teste com a biblioteca da Adafruit.

https://youtu.be/r0fLp5KYcPM

 

Inscreva-se no nosso canal Manual do Maker no YouTube.

Também estamos no Instagram.

Nome do Autor

Djames Suhanko

Autor do blog "Do bit Ao Byte / Manual do Maker".

Viciado em embarcados desde 2006.
LinuxUser 158.760, desde 1997.