EEPROM - Armazenando dados na memória não volátil do Arduino

Armazenando dados de forma não volátil no Arduino - EEPROM

A necessidade de se armazenar informações é algo bastante recorrente no desenvolvimento de projetos embarcados. Sejam elas um conjunto de variáveis para configurar o seu sistema, ou até  mesmos dados que você queira visualizar após um intervalo de tempo, o armazenamento de informações é muito importante em praticamente todos os tipos de projetos. Porém nem sempre dispomos de um cartão SD, seja por limitações de custo ou até mesmo pinos de I/O, impossibilitando  assim que a utilização de um cartão SD resolvesse o problema. Sabendo disso, neste tutorial, você aprenderá como utilizar a memória EEPROM existente nos microcontroladores Atmega das placas Arduino para armazenar dados permanentemente.

[toc]

Memória EEPROM

A memória EEPROM ou Electrically-Erasable Programmable Read-Only Memory, consiste em um modelo de memória onde diferente da memória RAM, podemos manter dados armazenados após desligarmos o nosso equipamento. Desta forma, é possível salvar informações que podem ser necessárias para o funcionamento do sistema após o seu desligamento, como por exemplo:

  • Configurações
  • Dados de difícil obtenção
  • Dados  estáticos

A utilização de memórias EEPROM, possibilitam com que o desenvolvedor seja capaz de armazenar diversas informações do sistema para uso posterior. Porém, este tipo de  memória possui um ciclo muito pequeno de escritas, o que torna o seu uso viável apenas para o armazenamento de informações que serão pouco modificadas.

Memória eeprom i2c com encapsulamento dip.

O processo de leitura e escrita neste tipo  de memória pode ser feito de duas formas:

  • Paralelo: Cada byte é escrito de forma paralela na memória, sendo  este escrito com base no endereço definido no barramento. Mais rápida, porém gasta uma maior quantidade de pinos para I/O

  • Serial: Cada byte é escrito de forma serializada (normalmente utilizando o protocolo i2c) na memória eeprom. Mais lenta, porém gasta uma menor quantidade de pinos para I/O

Memória EEPROM no Arduino

Os microcontroladores ATmega possuem em sua arquitetura uma pequena memória eeprom, que pode ser utilizada como uma unidade de armazenamento. Cada microcontrolador possui uma de tamanho específico,  segmentada em 1 byte por endereço. A lista abaixo ilustra a quantidade de memória disponível para a microcontroladores utilizados em plataformas como Arduino Nano, Arduino Uno e Arduino Mega:

  • ATmega8,ATmega168 - 512 Bytes
  • ATmega326 - 1024 Bytes
  • ATmega1280, ATmega2560 - 4096 Bytes

Mãos à obra – Armazenando dados na memória EEPROM do Arduino

Neste projeto iremos apenas aprender a como manipular e realizar leituras e escritas na memória EEPROM do Arduino, desta forma iremos precisar apenas de um Arduino com algum dos microcontroladores citados acima.

Componentes Utilizados

Neste projeto iremos utilizar um Arduino Nano, porém praticamente todos os  microcontroladores ATmega dispõem de uma memória eeprom nativa.

Programando

- Bibliotecas

Como iremos apenas aprender como armazenar e ler dados da memória EEPROM do Arduíno, iremos utilizar apenas a biblioteca EEPROM.h que já é nativa da ide que pode ser importada ao seu código da seguinte forma:

#include <EEPROM.h>

- Código Utilizado

Agora que temos o nosso sistema montado, e as bibliotecas adicionadas ao projeto, podemos partir para o código. Observem o código a seguir que utilizaremos como base para o nosso manipulador de memória.

#include <EEPROM.h> // Biblioteca para acesso e manipulação da EEPROM
void setup()   
{
  Serial.begin(115200); // Inicialização da comunicação serial

  Serial.print("Espaco Disponivel em Bytes: "); // Mostra a quantidade  de memória da EEPROM do seu microcontrolador
  Serial.println(EEPROM.length()); // Mostra a quantidade de memória da EEPROM do seu microcontrolador
  escreveByte(0,254); // Escreve o valor 255 na posição 0 da memória  
  byte valor = leByte(0); // Lê o endereço 0 da memória ( onde escrevemos 255 )
  Serial.print("Byte Armazenado: "); // Mostra o Byte Armazenado
  Serial.println(valor); // Mostra o Byte Armazenado
  escreveInt(1,2,1200); // Escreve o valor 1200 na EEPROM ( por ser um int de 2 bytes precisamos utilizar 2 endereços para armazenar)
  Serial.print ("Inteiro Armazenado: "); // Mostra o inteiro Armazenado
  Serial.println(lerInt(1,2)); // Mostra o inteiro Armazenado
  escreveString(3,"Vida de Silício"); // Escreve a String Vida de Silício na EEPROM, começando no  endereço 3
  Serial.println("String Armazenada: "+leString(3)); // Mostra a String armazenada
}

void loop(){
  
}

byte leByte (int endereco1){
  return EEPROM.read(endereco1); // Realizamosa leitura de 1 byte  e retornamos
}

void escreveByte (int endereco1, byte valor){ // Escreve um byte na EEPROM no endereço especificado
  byte valorAtual = leByte(endereco1); // Lemos o byte que desejamos escrever
  if (valorAtual == valor){ // Se os valores forem iguais não  precisamos escrever ( economia de ciclos de escrita )
    return;
  }
  else { // Senão escrevemos o byte no endereço especificado na função
    EEPROM.write(endereco1,valor); // Escreve o byte no endereço especificado na função
  }
  
}



void escreveInt(int endereco1, int endereco2, int valor){ // Escreve um inteiro de 2 bytes na EEPROM
  int valorAtual = lerInt(endereco1,endereco2); // Lemos o valor inteiro da memória
  if (valorAtual == valor){ // Se o valor lido for igual ao que queremos escrever não é necessário escrever novamente
    return;
  }
  else{ // Caso contrário "quebramos nosso inteiro em 2 bytes e escrevemos cada byte em uma posição da memória
      byte primeiroByte = valor&0xff; //Executamos a operação AND de 255 com todo o valor, o que mantém apenas o primeiro byte
      byte segundoByte = (valor >> 8) &0xff; // Realizamos um deslocamento de 8 bits para a direita e novamente executamos um AND com o valor 255, o que retorna apenas o byte desejado
      EEPROM.write(endereco1,primeiroByte); // Copiamos o primeiro byte para o endereço 1
      EEPROM.write(endereco2,segundoByte); // Copiamos o segundo byte para o endereço 2
  }
}

int lerInt(int endereco1, int endereco2){ // Le o int armazenado em dois endereços de memória
  int valor = 0; // Inicializamos nosso retorno
  byte primeiroByte = EEPROM.read(endereco1); // Leitura do primeiro byte armazenado no endereço 1
  byte segundoByte = EEPROM.read(endereco2); // Leitura do segundo byte armazenado no endereço 2
  valor = (segundoByte << 8) + primeiroByte; // Deslocamos o segundo byte 8 vezes para a esquerda ( formando o byte mais significativo ) e realizamos a soma com o primeiro byte ( menos significativo )
  return valor; // Retornamos o valor da leitura

}

void escreveString(int enderecoBase, String mensagem){ // Salva a string nos endereços de forma sequencial
  if (mensagem.length()>EEPROM.length() || (enderecoBase+mensagem.length()) >EEPROM.length() ){ // verificamos se a string cabe na memória a partir do endereço desejado
    Serial.println ("A sua String não cabe na EEPROM"); // Caso não caiba mensagem de erro é mostrada
  }
  else{ // Caso seja possível armazenar 
    for (int i = 0; i<mensagem.length(); i++){ 
       EEPROM.write(enderecoBase,mensagem[i]); // Escrevemos cada byte da string de forma sequencial na memória
       enderecoBase++; // Deslocamos endereço base em uma posição a cada byte salvo
    }
    EEPROM.write(enderecoBase,'\0'); // Salvamos marcador de fim da string 
  }
}

String leString(int enderecoBase){
  String mensagem="";
  if (enderecoBase>EEPROM.length()){ // Se o endereço base for maior que o espaço de endereçamento da EEPROM retornamos uma string vazia
    return mensagem;
  }
  else { // Caso contrário, lemos byte a byte de cada endereço e montamos uma nova String
    char pos;
    do{
      pos = EEPROM.read(enderecoBase); // Leitura do byte com base na posição atual
      enderecoBase++; // A cada leitura incrementamos a posição a ser lida
      mensagem = mensagem + pos; // Montamos string de saídaa
    }
    while (pos != '\0'); // Fazemos isso até encontrar o marcador de fim de string
  }
  return mensagem; // Retorno da mensagem
}


Colocando pra funcionar

Se nada tiver sido modificado no código e sua EEPROM ainda possuir ciclos de escrita, a seguinte mensagem será apresentada no monitor serial:


Entendendo a Fundo

Software

- Incluindo bibliotecas necessárias

Para este sistema, iremos precisar apenas da biblioteca EEPROM.h que já é  nativa do Arduíno e será utilizada como interface entre a EEPROM e o nosso código, desta forma ela pode ser adicionada  da seguinte forma:

#include <EEPROM.h>

- Função Setup

Em nossa função setup, iremos basicamente escrever e ler as variáveis que desejamos armazenar na EEPROM, foram definidos um conjunto de 6 funções, sendo três para escrita e três para leitura de tipos de dados normalmente utilizados, sendo eles:

  • Int
  • Byte
  • String

Sendo assim, no setup iremos apenas utilizar estas funções, da seguinte forma:

- Função escreve byte

Escreve um valor em byte no endereço especificado, neste exemplo estamos escrevendo o valor 254 no endereço 0 da memória.

  escreveByte(0,254); // Escreve o valor 255 na posição 0 da memória

- Função lê byte

Realiza a leitura de um único byte no endereço especificado pelo usuário, neste exemplo estamos lendo o endereço 0.

byte valor = leByte(0);

- Função escreve int

Escreve um valor inteiro composto por 2 bytes, em duas posições quaisquer da eeprom, neste exemplo estamos escrevendo o valor 1200 utilizando os endereços 1 e 2.

escreveInt(1,2,1200);

- Função lê int

Realiza a leitura de dois endereços especificados pelo usuário, reconstruindo o valor inteiro que elas representam, neste exemplo estamos lendo os endereços 1 e 2 da memória.

Serial.println(lerInt(1,2));

- Função escreve string

Escreve uma determinada string de forma sequencial na EEPROM, neste exemplo estamos utilizando um total de 15 endereços (começando do endereço 3) para escrever a string "Vida de Silício" em nossa memória.

escreveString(3,"Vida de Silício");

- Função lê string

Dado um endereço base fornecido, esta função lê sequencialmente toda a string armazenada.

leString(3);

Entendendo cada função implementada

Cada função implementada possui um grau complexidade devido a realização de operações lógicas para quebra de bytes e armazenamento sequencial, desta forma iremos mostrar a forma como cada função é capaz de salvar e recuperar seus respectivos tipos de dados. Porém antes vamos entender um pouco a forma como a nossa memoria funciona.

Imagine a sua  memória como um um conjunto de blocos onde podemos armazenar valores em um intervalo de 0 até 255, e cada um desses intervalos está associado a um endereço, sendo assim, podemos imaginar a nossa memória da seguinte forma: Com essa estrutura de memória podemos salvar qualquer tipo de informação, desde  que o espaço seja suficientemente grande para armazenar todos os valores.

- Função escreveByte

A função escreveByte recebe como argumentos o endereço  e o valor a ser escrito naquela  posição, verificando apenas se o byte que desejamos escrever já não está lá, desta forma economizamos uma escrita que seria feita desnecessariamente, prologando assim a vida útil de nossa memória.

void escreveByte (int endereco1, byte valor){
  byte valorAtual = leByte(endereco1);
  if (valorAtual == valor){
    return;
  }
  else {
    EEPROM.write(endereco1,valor);
  }
}

Estruturalmente, podemos dizer que esta função executa a seguinte operação:

- Função leByte

Já a função leByte, basicamente realiza a leitura do endereço especificado em seu argumento, retornando assim o valor que está armazenado naquele endereço.

byte leByte (int endereco1){
  return EEPROM.read(endereco1);
}

Utilizando o nosso modelo de memória, podemos dizer que estamos realizando a seguinte operação:

- Função escreveInt

Nos microcontroladores ATmega, uma variável  do tipo int, é representada por um total de 2 bytes, sendo estes divididos entre mais significativos (HB) e menos significativos (LB), como a nossa memória permite apenas o armazenamento de 1 byte por endereço. Sabendo disso, é necessário que a nossa função seja capaz de "quebrar" o nosso  valor inteiro de 2 bytes, em duas variáveis de 1 byte cada, para que assim seja possível armazenar esta informação na memória. Para que isso seja feito, iremos utilizar dois tipos de operações lógicas existente em praticamente todas as arquiteturas de computadores, que são as operações rigth shift e and bitwise.

void escreveInt(int endereco1, int endereco2, int valor){
  int valorAtual = lerInt(endereco1,endereco2);
  if (valorAtual == valor){
    return;
  }
  else{
      byte primeiroByte = valor&0xff;
      byte segundoByte = (valor >> 8) &0xff;
      EEPROM.write(endereco1,primeiroByte);
      EEPROM.write(endereco2,segundoByte);
  }
}

 

Sabendo disso o algoritmo funciona da seguinte forma:

  1. Inicialmente verificamos se o valor que desejamos inserir é igual ao que está na memória ( se for economizamos duas escritas na memória )
  2. Caso não seja executamos a seguinte operação:
    1. Dado o nosso valor de exemplo 1001, serão executadas as seguintes operações:
    2.  Aplicamos uma operação AND bit a bit sob o valor que desejamos quebrar com o número 255, desta forma iremos preservar apenas os bits da primeira cadeia de byte que desejamos armazenar. A figura abaixo ilustra como o processo é feito e o resultado obtido através da operação realizada.
    3. Para o segundo byte, realizaremos o mesmo processo do passo 2, porém ao invés apenas aplicar a operação lógica AND, iremos antes deslocar os bits que estão na camada superior. Para que dessa forma, cheguem a posição dos bits menos significativos para a aplicação da  máscara.
    4.  Por fim, com os bytes separados, a  função salva cada um deles no endereço especificado como mostra a figura abaixo:

- Função leInt

O processo de leitura segue praticamente a lógica inversa do processo de escrita, onde iremos ler cada byte e montar o nosso valor da seguinte forma:

  1. Relizamos uma leitura do endereço de valor mais significativo, este  valor é deslocado 8 bits a esquerda para que volte a sua posição de bit mais significativo.
  2. Realizamos uma leitura do endereço de valor menos significativo, este valor é somado ao  valor deslocado para que volte a posição de bit menos significativo.
  3. Temos o nosso  valor montado novamente.

 

int lerInt(int endereco1, int endereco2){
  int valor = 0;
  byte primeiroByte = EEPROM.read(endereco1);
  byte segundoByte = EEPROM.read(endereco2);
  valor = (segundoByte << 8) + primeiroByte;
  return valor;
}

- Função escreveString

A função escreve string por sua vez, não utiliza de recursos de deslocamento de bits, devido ao fato de que cada caractere, é um único byte. Ou seja, uma string nada mais é do que um vetor de bytes alocados sequencialmente. Sabendo disso, o nosso algoritmo de salvar uma string na memória segue a seguinte lógica:

  1. Dado um endereço base, e o tamanho da string verificamos se é possível o armazenamento ou não.
    1. Caso não seja possível, o  valor não é salvo.
    2. Caso seja possível, a string é alocada sequencialmente na memória começando com o endereço base e terminando sempre com um ''\0''
void escreveString(int enderecoBase, String mensagem){
  if (mensagem.length()>EEPROM.length() || (enderecoBase+mensagem.length()) >EEPROM.length() ){
    Serial.println ("A sua String não cabe na EEPROM");
  }
  else{
    for (int i = 0; i<mensagem.length(); i++){
       EEPROM.write(enderecoBase,mensagem[i]);
       enderecoBase++;
    }
    EEPROM.write(enderecoBase,'\0');
  }
}

- Função leString

A função leString por sua vez, realiza praticamente o mesmo processo que a leitura, porém ao invés de armazenar os bytes como na função escreveString, ela utiliza a função read, para ler cada byte armazenado sequencialmente. Desta forma podemos dizer que o algoritmo funciona da seguinte forma:

  • Com base no endereço inicial, a função lê cada byte lido, até que o caractere de fim de texto '\0', seja encontrado. Quando encontrado uma string montada é retornada pela função.
String leString(int enderecoBase){
  String mensagem="";
  if (enderecoBase>EEPROM.length()){
    return mensagem;
  }
  else {
    char pos;
    do{
      pos = EEPROM.read(enderecoBase);
      enderecoBase++;
      mensagem = mensagem + pos;
    }
    while (pos != '\0');
  }
  return mensagem;
}

Desafio

Agora que sabemos como manipular a memória EEPROM do nosso Arduino, tente adicionar esta funcionalidade a algum projeto que seja necessária a configuração de uma variável em tempo real.  Um exemplo de sistema desse tipo são os dataloggers, onde  precisamos configurar informações como tempo de leitura e configuração de sensores.

Considerações finais

Este tutorial, teve como objetivo mostrar como manipular a memória EEPROM, interna do seu Arduino, funcionando como uma pequena unidade de armazenamento para informações importantes. Espero que tenham gostado do conteúdo apresentado, sinta-se à vontade para nos dar sugestões, críticas ou elogios. Lembre-se de deixar suas dúvidas nos comentários abaixo.


Shield Ethernet W5100 - Criando um Servidor Web com Arduino

Shield Ethernet W5100 - Primeiros passos na criação de um Servidor Web com Arduino

Em uma das nossas publicações anteriores ensinamos como você deve proceder para criar um Servidor Web com o NodeMCU. Neste tutorial, iremos utilizar um Shield Ethernet W5100 para criar um Servidor Web que terá como função fornecer uma página web contendo informações enviadas pelo Arduino UNO.

Respostar do servidor web - Página feita através do Arduino Uno em conjunto com o Ethernet Shield W5100
Resultado deste projeto.

[toc]

O que é um Servidor Web?

Ao navegarmos pelo gigante universo de possibilidades da internet, podemos não nos dar conta do que existe por trás disso tudo.

A internet é uma união de redes de computadores em nível mundial conversando entre si através de um conjunto próprio de protocolos de comunicação, como por exemplo, o TCP/IP, que por sua vez, consiste em um protocolo para transmissão de informações orientado à conexão, ou seja, cuja função consiste em permitir que as maquinas se comuniquem e gerenciem o estado atual da transmissão.

- Os Servidores

Um dos protagonistas desse universo são os servidores. A grosso modo, esses servidores são computadores responsáveis por fornecer e receber dados dos diversos clientes, atuando como centralizadores de informação.

servidor cliente
Conexão cliente/servidor

Indo um pouco a fundo, um servidor consiste em um software dentro um computador centralizador. Através de uma rede particular ou da internet,  esse servidor pode receber dados de clientes bem como fornecê-los.

O estabelecimento das relações entre o conjunto Servidor/Cliente é baseado em um sistema de recebimento, processamento e resposta, no qual, o servidor recebe, processa e responde a requisições feitas por um Cliente através de algum protocolo de comunicação.

- O HTTP - Protocolo de Transferência de Hipertexto

Um dos principais exemplos da relação Servidor/Cliente é a relação entre os computadores que atuam como servidores hospedando sites e os navegadores que utilizamos em nossos computadores ou celulares, os clientes. Neste tipo de relação, utiliza-se para estabelecer a comunicação, o procotolo o HTTP (Hypertext Transfer Protocol), o qual, é responsável pelo tratamento dos pedidos e respostas entre cliente e servidor na World Wide Web ou em uma rede localNesse contexto, chamamos os servidores de Servidores Web.

Comunicação requisição http servidor web
Utilização do protocolo HTTP.


- HTML - Linguagem de Marcação de Hipertexto

As informações que o Servidor Web envia para seu navegador a partir de uma requisição HTTP feita pelo mesmo, pode ocorrer em alguns determinados formatos que precisarão ser interpretados. Um desses formatos é o HTML (HyperText Markup Language), que por sua vez, é uma linguagem utilizada na construção de páginas na Web.

Por trás de uma Página web
Linguagem HTML.

O Shield Ethernet W5100

Como sabemos, os shields compatíveis com o Arduino UNO são placas de circuito que podem ser conectadas sobre o mesmo, encaixando-se perfeitamente, com o intuito de expandir suas capacidades em determinada vertente.

Neste tutorial, apresentamos o Shield Ethernet W5100, que por sua vez, consiste em um shield dotado de dois módulos, um módulo Ethernet que irá permitir a conexão do Arduino UNO, em um primeiro momento, com uma rede local e um módulo para cartão SD.

Sendo assim, perceba que é perfeitamente possível utilizar este módulo somente para ler/escrever dados em um cartão de memória ou apenas para conectar o Arduino UNO a uma rede local.

Shield Ethernet W5100 servidor web arduino
Shield Ethernet W5100.

Neste tutorial iremos utilizar apenas o módulo Ethernet do shield em questão, pois, iremos elaborar uma pagina simples para ser apresentada ao usuário através do navegador, no entanto, o módulo de cartão SD é muito útil para conter arquivos necessários para a construção de uma página mais rica em informações, como por exemplo, imagens.


Mãos à obra - Criando um Servidor Web com o Arduino UNO e o Shield Ethernet W5100

Nesta seção iremos demonstrar todos os passos que você deve seguir para aprender a criar um Servidor Web.

Componentes necessários

Para reproduzir este projeto, você irá precisar dos seguintes componentes:

Montando o projeto

Shield Ethernet W5100 no Arduino uno
Hardware utilizado.

Gostaríamos de sugerir que você tenha bastante cuidado no momento em que for encaixar o Shield Ethernet W5100 no Arduino UNO, pois, além da possibilidade de entortar os pinos do shield, você também pode se machucar.

Lembre-se que o shield ethernet W5100 possui uma série de pinos em sua parte inferior, tanto nas laterais como em sua parte dianteira, portanto, antes de pressionar o mesmo sobre o Arduino UNO, certifique-se de que os pinos estejam levemente posicionados em suas respectivas entradas para que então você possa ir realizando o encaixe lentamente.

Realizando as conexões

Para reproduzir este projeto, garanta que o seu Shield Ethernet W5100 esteja ligado corretamente a uma das portas LAN presentes no seu modem ou roteador.

Programando

Este programa foi elaborado a partir do código-exemplo da biblioteca Ethernet.h denominado WebServer.

Antes de utilizar este código, leia a seção Entendendo a fundo para adaptar os trechos necessários para o funcionamento da sua aplicação.

#include <SPI.h>
#include <Ethernet.h>

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(192, 168, 25, 16); 
EthernetServer server(80);     

void setup() 
{
    Ethernet.begin(mac, ip);  
    server.begin();           
} 

void loop() 
{
    EthernetClient client = server.available();  

    if (client) 
    { 
      
        boolean currentLineIsBlank = true;
        while (client.connected()) 
        {
            if (client.available())
            {   
                char c = client.read(); 
                
                if (c == '\n' && currentLineIsBlank) 
                {
                  
                    client.println("HTTP/1.1 200 OK");
                    client.println("Content-Type: text/html");
                    client.println("Connection: close");
                    client.println();
                    client.println("<!DOCTYPE html>");
                    client.println("<html>");
                    client.println("<head>");
                    client.println("<title>Servidor Web VDS</title>");
                    client.println("</head>");
                    client.println("<body>");
                    client.println("<h1>Meu primeiro Servidor Web</h1>");
                    client.println("<p>Esperamos que voce tenha gostado deste tutorial</p>");
                    client.println("</body>");
                    client.println("</html>");
                    break;
                }
                
                if (c == '\n') 
                {
                    currentLineIsBlank = true;
                } 
                else if (c != '\r') 
                {
                    currentLineIsBlank = false;
                }
            } 
        }
        
        delay(1);      
        client.stop(); 
        
    } 
}

Colocando para funcionar

Veja como ficou nosso primeiro Servidor Web.

Respostar do servidor web - Página feita através do Arduino Uno em conjunto com o Shield Ethernet W5100
Página da web criada.

Entendendo a fundo

Software

- Incluindo as bibliotecas a serem utilizadas no projeto

Inicialmente, observe que foi necessário incluir duas bibliotecas no código para que o mesmo pudesse funcionar corretamente. A biblioteca SPI.h é a responsável pela comunicação dos módulos do Shield Ethernet W5100 com o Arduino UNO utilizando o protocolo SPI e a biblioteca Ethernet.h atua possibilitando a conexão do conjunto, em um primeiro momento, com uma rede local.

#include <SPI.h>
#include <Ethernet.h>

- Definindo o endereço MAC do Arduino UNO

O próximo passo consiste em definir o endereço MAC que será atribuído ao Arduino UNO.

Na prática, o endereço MAC pode ser qualquer um, desde que seja único na rede. Como sugestão, copie a sentença abaixo.

byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};

- Definindo o endereço IP do Arduino UNO

Além do endereço MAC definido anteriormente, torna-se necessário definir um endereço IP para o nosso Arduino UNO. Isso é imprescindível para que seja possível estabelecer a conexão entre o mesmo e a rede.

Este endereço deve estar disponível na sua rede local para que possa ser utilizado

Existem várias maneiras de encontrar um endereço válido na sua rede local, de modo que, demonstraremos uma forma bastante simples de realizar este procedimento, confira abaixo:

  1. Acesse um computador que esteja conectado na sua rede local
  2. Abra o Prompt de Comando do Windows (supondo que o sistema operacional seja Windows)
  3. Digite ipconfig

Neste momento, um conjunto de informações será disponibilizado, no entanto, o dado que requer sua atenção é justamente o endereço IP da máquina que você está utilizando (ele estará apresentado pelo nome IPV4).

Verificando o ip a ser usado pelo ethernet shield w5100

Primeiramente, repare que o endereço IP destacado possui quatro partes separadas por pontos. Para encontrarmos um possível endereço disponível em nossa rede local, basta modificarmos a última parte do endereço encontrado, como por exemplo, o endereço 192.168.25.16 . Geralmente, este procedimento é suficiente para encontrar possíveis endereços disponíveis em redes locais pequenas, como as das nossas casas.

IPAddress ip(192, 168, 25, 16);

- Criando o objeto server

Neste momento, cria-se um objeto chamado server, que por sua vez, será responsável por representar o Servidor Web no código do Arduino UNO.

Note que ao criarmos o objeto, passamos o número 80 como parâmetro, pois estamos determinando a porta que o Servidor Web utilizará para enviar as páginas web que serão criadas posteriormente.

A título de curiosidade, quando digitamos o endereço de algum site no navegador, ele automaticamente procura a porta 80 do servidor no qual está se conectando, de modo que, se o serviço responsável por disponibilizar as páginas da web para o cliente estiver em outra porta, devemos especificar esta no endereço do site citado, por exemplo: www.exemplo.com.br:1234

EthernetServer server(80);

- Iniciando a comunicação com a rede local e o Servidor Web

Na função setup() iniciamos a conexão com a rede local através da função Ethernet.begin() (passando como parâmetro os endereços MAC e IP definidos anteriormente) e também iniciamos o Servidor Web por meio da sentença server.begin() (lembre-se que server é o objeto criado para representar o Servidor Web no código).

Ethernet.begin(mac, ip);
server.begin();  

Veja como ficou nossa função setup():

void setup() 
{
   Ethernet.begin(mac, ip);
   server.begin();
}

- Respondendo as requisições de um navegador

Verificando se existe requisição de conexão

Primeiramente, na função loop(), temos a sentença server.available() que verifica se existe tem algum cliente tentando fazer uma conexão. Como dito anteriormente, vamos chamar de cliente, o navegador que está tentando fazer a conexão com o Servidor Web através do endereço IP do mesmo. Repare que foi criada uma variável para conter o valor retornado pela função server.available().

EthernetClient client = server.available();

Em seguida, temos uma função if() cujo conteúdo será executado apenas no caso de termos um cliente tentando se conectar ao Servidor Web criado e iniciado anteriormente.

if (client)
{
   ***** Conteúdo da função if() *****
}

Supondo que temos um cliente tentando se conectar com o nosso Servidor Web, primeira sentença do conteúdo da função if() apresentada anteriormente consiste na declaração de uma variável de controle booleana que será utilizada na leitura da requisição feita pelo navegador.

boolean currentLineIsBlank = true;

Posteriormente, temos uma função while(), que por sua vez, fará com que a execução do programa fique restrita ao seu conteúdo enquanto o parâmetro passado para mesma for verdadeiro. O parâmetro citado corresponde à sentença client.connected(), responsável por retornar verdadeiro ou falso, caso o cliente esteja conectado ou não com o Servidor Web, respectivamente.

Portanto, enquanto o cliente estiver conectado com o nosso servidor, o programa ficará preso na função while().

while (client.connected())
{
       ***** Conteúdo da função while()
}

Imagine que a conexão do cliente (navegador) com o nosso Servidor Web tenha sido estabelecida. Neste momento o programa irá se preparar para receber a requisição feita pelo cliente, que por sua vez, é dada em forma de um grande texto, logo, utilizamos a função if() juntamente com a sentença client.available() para verificar se ainda existe alguma informação proveniente do navegador para ser lida. Caso exista, o conteúdo desta função será executado.

if (client.available())
{
      ***** Conteúdo da função if() *****
}

Lendo a requisição do cliente

Caso exista alguma informação para ser lida, utilizamos a sentença client.read() para ler caractere por caractere do grande texto de requisição citado anteriormente, de modo que, a cada passagem por esta sentença (lembre-se que isso é feito de maneira cíclica), um novo caractere será armazenado na variável do tipo char c.

 char c = client.read();

Após preenchermos a variável c com um determinado caractere da requisição, fazemos uma série de comparações deste com alguns parâmetros específicos para saber se o Arduino UNO recebeu o pacote de informações inteiro ou não.

O objetivo aqui não é entender tudo que esta vindo do cliente mas simplesmente entender que existe uma solicitação acontecendo e que após o término da mesma, vamos devolver como resposta uma pagina da web, sendo assim, devemos esperar que venha o texto completo de solicitação, até a ultima linha.

Caso a condição desta primeira função de tratamento da variável c seja verdadeira, quer dizer que recebemos o pacote completo e que o conteúdo desta função if() será executado.

if (c == '\n' && currentLineIsBlank)
{
      ***** Conteúdo da função if() *****
}

Enviando informações para o navegador

Neste momento, nós iremos criar as funções necessárias para que o nosso Arduino UNO envie uma página da web como resposta à solicitação do navegador. As instruções que utilizaremos para enviar informações ao navegador serão baseadas na sentença client.println().

Primeiramente, enviamos um cabeçalho padrão informando ao navegador que estamos mandando uma página da web utilizando o protocolo HTTP, feita utilizando a linguagem HTML.

                     client.println("HTTP/1.1 200 OK");
                     client.println("Content-Type: text/html");
                     client.println("Connection: close");  
                     client.println();

- Usando HTML para montar a página web

HTML é uma linguagem, porém, não exatamente uma linguagem de programação mas sim uma linguagem de marcação, ou seja, através desta nós enviamos comandos para um navegador, que por sua vez, irão orientar o mesmo na montagem da pagina.

Uso de tags em HTML

Em um primeiro momento, nós devemos saber que a linguagem HTML é composta por elementos que iremos chamar de tags. Estes consistem em comandos que são enviados para o navegador para informarmos alguma coisa ao mesmo, para pedirmos que ele mostre algo, para definirmos o formato de fonte que queremos, se é negrito, qual cor, entre outros.

Todos as tags em HTML são declaradas entre os sinais de maior e menor <nome_da_tag>. Torna-se importante ressaltar que muitas tags possuem uma abertura e um fechamento (este possui o mesmo nome da tag, porém, com uma "/" antes do respectivo nome, por exemplo, </nome_da_tag>), de modo que, tudo o que está entre a abertura e o fechamento de uma determinada tag será afetado pelo comando gerado pela função da mesma.

A estrutura da página em HTML

Vamos começar a entender a estrutura de uma pagina em HTML. Primeiramente, qualquer pagina em HTML precisa possuir a tag <html> cuja função é indicar para o navegador que estamos começando um bloco de programação utilizando a linguagem HTML (opcionalmente podemos utilizar também a tag <!DOCTYPE HTML> para informar o tipo documento, de modo que, se não colocarmos isto, o navegador entenderá da mesma forma) e o fechamento da mesma </html>, que por sua vez, indica o fim do bloco citado.

client.println("<!DOCTYPE HTML>");
client.println("<html>");
           . 
           .
***** Conteúdo da página *****
           .
           .
client.println("</html>"); 
 

Dentro do bloco citado anteriormente, temos o conteúdo da página que queremos enviar para o navegador, de modo que, neste, devemos ter pelo menos dois blocos, um responsável pelas informações gerais do documento, limitado pelo uso do par <head></head> e o outro, por sua vez, deve conter o corpo da página e está entre as tags <body> e </body>.

client.println("<!DOCTYPE HTML>");
client.println("<html>");
client.println("<head>");
           .
           .
   ***** Bloco 1 *****
           .
           .
client.println("</head>");
client.println("<body>");
           .
           .
   ***** Bloco 2 *****
           .
           .
client.println("</body>");
client.println("</html>"); 

Definido o título para a página

Neste momento, vamos utilizar apenas uma tag dentro do bloco 1, denominada <title>, cuja função consistirá em definir um título para a página (este título aparecerá na aba do navegador). Para executarmos a ação proposta, devemos colocar o título desejado entre o par <title></title>.

client.println("<!DOCTYPE HTML>");
client.println("<html>");

client.println("<head>");
client.println("<title>Servidor Web VDS</title>"); 
client.println("</head>");

client.println("<body>");
           .
           .
   ***** Bloco 2 *****
           .
           .
client.println("</body>");
client.println("</html>"); 

Veja como ficou o título da nossa página:

endereço IP do servidor web
Título da página.

Escrevendo o corpo da página web

Quanto ao corpo da página, a primeira coisa que faremos será colocar um título visível na própria página. Para realizar este procedimento, utilizaremos a tag <h1>, que por sua vez, consiste em uma tag de cabeçalho, cuja função consiste em apresentar um determinado texto em um modelo predefinido. Lembre-se que os textos que tiverem fora do par <h1></h1> serão apresentados fora do padrão citado.

client.println("<!DOCTYPE HTML>");
client.println("<html>");

client.println("<head>");
client.println("<title>Servidor Web VDS</title>"); 
client.println("</head>");

client.println("<body>");
client.println("<h1>Meu primeiro Servidor Web</h1>");  
client.println("</body>");

client.println("</html>");

Veja como está nossa página até agora

Shield Ethernet W5100 - tela acessada via navegardor
Primeiro texto da página.

Opções de cabeçalhos

Devemos ressaltar que não há nenhum problema em utilizar vários cabeçalhos iguais, portanto, você pode tranquilamente criar vários textos utilizando o cabeçalho h1, pois, ele apenas indica uma certa formatação. Além do cabeçalho que já utilizamos, temos também os cabeçalhos h2,h3,h4,h5,h6, os quais, nesta ordem, possuem fontes cada vez menores.

Escrevendo um texto simples

Por fim, utilizaremos uma tag voltada para a escrita de textos simples. Esta pode ser referenciada no código pelo par <p></p>.

client.println("<!DOCTYPE HTML>");
client.println("<html>");

client.println("<head>");
client.println("<title>Servidor Web VDS</title>"); 
client.println("</head>");

client.println("<body>");
client.println("<h1>Meu primeiro Servidor Web</h1>");  
client.println("<p>Esperamos que voce tenha gostado deste tutorial</p>");
client.println("</body>");

client.println("</html>"); 

Veja nosso resultado final:

Página da web criada.

- Verificando se a requisição foi finalizada

Após o desenvolvimento da nossa página, saímos da função if() utilizada para saber se a requisição foi finalizada e encontramos outras duas funções if() que cumprem o teste das condições não contempladas pela primeira, ou seja, atuam no tratamento da variável enquanto a requisição não foi finalizada.

if (c == '\n') 
{
    currentLineIsBlank = true; 
} 
else if (c != '\r')
{
    currentLineIsBlank = false;
}

Por fim utilizamos a função delay() para garantir que o navegador receba esta informação que estamos mandando e também a sentença client.stop() para parar a conexão.

delay(1);     
client.stop();

Considerações finais

Neste tutorial, demonstramos como você pode dar os primeiros passos na criação de um Servidor Web utilizando um Arduino UNO e um Shield Ethernet W5100. Esta foi apenas a primeira parte de uma série de artigos sobre a criação de Servidores Web, portanto, esperamos que continue nos acompanhando e sinta-se à vontade para nos dar sugestões, críticas ou elogios. Lembre-se de deixar suas dúvidas nos comentários abaixo.


Display LCD 20x4 e 16x2 com Adaptador I2C

Display LCD 20x4 e LCD 16x2 com Adaptador I2C – Utilizando o display com Arduino

No tutorial sobre a utilização de um display lcd 16x2 com Arduino aprendemos a importância dos displays e como usar um LCD de caracteres, em especial o 16x2. Apesar de esse LCD ser prático e simples, ele possui um problema, uma grande demanda por ligações. Para resolver isso, podemos usar um módulo adaptador I2C que facilita ainda mais o uso desse tipo de recurso. Nesse tutorial iremos aprender a usar o Display LCD 20x4 com Adaptador I2C junto a um Arduino.

O uso tanto do display LCD 16x2 tanto do display LCD 20x4 é muito semelhante, a diferença entre eles é o numero de caracteres que dispõem na tela. Como falamos sobre o modelo 16x2 no último tutorial, iremos aproveitar a oportunidade para mostrar um pouco mais sobre o modelo 20x4. Caso você tenha em suas mão o 16x2, você poderá facilmente adaptar o programa usado nesse tutorial para você.

[toc]

Porque usar comunicação I2C para controlar seu LCD?

Display LCD 20x4 Azul
Display LCD 20x4 Azul

Na figura acima, percebemos a existência de uma grande quantidade de contatos para realização do seu acionamento. Para facilitar o seu uso, iremos trabalhar com o adaptador I2C para display LCD.

Para usar esse LCD diretamente no Arduino, você irá precisa, além das ligações de alimentação,  de 6 pinos: RS, EN, D7, D6, D5, e D4 para que seu LCD converse com seu Arduino. Se você estiver trabalhando com um projeto mais complexo, talvez você não terá tantos pinos disponíveis no seu Arduino para seu LCD da forma usual.

Com o módulo de interface I2C, você precisará de apenas 2 pinos (I2C) para imprimir as informações que deseja em seu LCD. Se você já tiver usando outros componentes I2C em seu projeto, esse pino não precisará usar mais nenhuma porta, visto que ele poderá usar os mesmo pinos já usado para o outro dispositivo I2C.

Adaptador I2C para Display LCD 20x4 e 16x2

Adaptador I2C para display LCD
Adaptador I2C para display LCD

Para que seja possível a comunicação entre o Arduino e o LCD, precisaremos de um adaptador I2C. Esse adaptador nada mais é  que um conversor cuja função consiste em manipular os contatos do LCD, de modo que, após este processo, teremos apenas 2 contatos para realizar a comunicação com uma placa Arduino através do protocolo I2C.

Ele conta com o chip PCF8574T ou PCF8574AT que é responsável por essa interface . Você pode encontrar vários modelos de módulos ligeiramente diferentes.

Em geral eles possuem o seguinte formato:

detalhamento Adaptador I2C LCD
detalhamento Adaptador I2C para display LCD

Como você pode ver na imagem, a maioria dos módulos de interface I2C para LCD possuem:

  • Pinos para conexão com o Display (16 pinos);
  • Pinos de Alimentação do Módulo (GND e VCC);
  • Pinos de comunicação I2C (SDA e SCL);
  • Trimpot para ajuste de contraste da tela;
  • Jumper para ligar e desligar a luz de fundo (Backlight);
  • Led indicador de módulo ligado.
  • Chip de Interface (PCF8574T ou PCF8574AT )

Endereço do módulo I2C

Para alguns modelos ainda é possível configurar o endereço do módulo I2C através de A0, A1 e A2. Abaixo você pode conferir a tabela de endereços possíveis para cada um dos chips (PCF8574T ou PCF8574AT ):

Endereços configuráveis para os chips PCF8574T e PCF8574AT.( L para 0V e H para 5V)

A0, A1 e A2 são portas do nosso Chip:

Portas do chip PCF8574T e PCF8574AT
Portas do chip PCF8574T e PCF8574AT

Que em geral vem ligados a alimentação do módulo (VCC):

Esquema de ligação dos pinos de endereço
Esquema de ligação dos pinos de endereço

Quando conectamos o ponto 1 com 1, 2 com 2 ou 3 com 3, estamos colocando um nivel lógico baixo em A0, A1 ou A2 respectivamente. Na figura anterior, os pinos A0, A1 e A2 estão conectados ao chip do módulo. Veja que segundo esse esquemático, estamos com 5V em cada um dos 3 pinos. Ou seja, nosso endereço será 0x27 caso o chip seja o PCF8574T ou 0x3F caso o chip seja o PCF8574AT.

tabela do lcd i2c

Para alterar o endereço podemos colocar um ponto de solda para conectar os pinos A0, A1 ou A2 ao GND para as placas que tenha essa opção:

Opção para alteração de endereço

Para conectar os pinos A0, A1 ou A2 ao GND, você precisa pode usar solda de estanho para ligar o ponto de baixo com o de cima, tal como na figura a seguir:

Adaptador com chip PCF8574T com A0, A1 e A2 conectados ao GND. logo o endereço será 0x20.

Display LCD 20x4 com adaptador I2C

Para o nosso tutorial, iremos usar um LCD que já possui o adaptador soldado ao módulo display. Para o display que usaremos não temos a opção de mudança de endereço:

Display LCD 20x4 com adaptador
Display LCD 20x4 com adaptador

Veja em detalhes o módulo I2C usado:

Repare que ele não tem a opção de mudança de endereço. O chip dele é o PCF8574T, ou seja, iremos usar o endereço 0x27.

Display LCD 16x2 com adaptador I2C

Você também pode usar a versão do Display LCD 16x2 com adaptador I2C. A maior diferença é a quantidade de caracteres. Explicaremos mais a frente como adaptar o programa que usamos nesse tutorial para o display LCD 16x2.

O endereçamento funcionará da mesma forma que o explicado anteriormente. Verifique o modelo do seu adaptador para descobrir o endereço do mesmo.

Display LCD 16x2 Azul + Adaptador I2C
Display LCD 16x2 Azul + Adaptador I2C

Mãos à obra – Imprimindo informações no display LCD 20x4 I2C

Componentes utilizados

Caso tenha um LCD 16x2 ou 20x4 e queira adapta-lo, basta adquirir o Módulo i2C separado.  Módulo I2C para Display LCD compativel com 16x02 e 20x4

Montando o projeto

Na figura abaixo, o leitor poderá conferir como foi realizada a montagem do projeto apresentado neste tutorial.  Lembre-se de montar o projeto com o seu Arduino desligado.

Esquema de montagem do Display LCD 20x4 Azul + Adaptador I2C com Arduino Micro
Esquema de montagem do Display LCD 20x4 Azul + Adaptador I2C com Arduino Micro

Esquema de montagem do Display LCD 20x4 Azul + Adaptador I2C com Arduino UNO
Esquema de montagem do Display LCD 20×4 Azul + Adaptador I2C com Arduino UNO

Veja como ficou o nosso:

Projeto montado com Display LCD 20x4 Azul + Adaptador I2C com Arduino Micro

Programando

Antes de adentrarmos na apresentação do código, disponibilizamos uma seção para ajudar aqueles que são iniciantes no assunto. Sinta-se livre para prosseguir caso você já tem domínio da IDE do Arduino.

Conectando o Arduino ao computador

Primeiramente, conecte seu Arduino ao computador e abra a IDE Arduino. Em seguida, é necessário selecionar a porta COM na qual o Arduino está conectado (este procedimento pode ser feito clicando no menu Ferramentas (tools) e em seguida escolhendo-se a porta correspondente no submenu Porta (port). Neste caso, a porta na qual está o Arduino é apresentada da seguinte maneira: COM3 (Arduino Micro).

Por fim, garanta também que o tipo de placa apropriado esteja selecionado (isso pode ser feito acessando o menu Ferramentas (tools) e o submenu Placa (board)).

- Biblioteca

Para desenvolver o projeto proposto com o Display LCD I2C 20X4 utilizou-se uma biblioteca capaz de atuar sobre o protocolo I2C para facilitar os processos de endereçamento e troca de dados que fazem parte do funcionamento do protocolo citado. Esta biblioteca pode ser encontrada aqui.

Adquirindo e instalando a biblioteca que será utilizada

Após a realização do download dos arquivos compactados no formato ZIP, abra a IDE do Arduino, selecione o menu Sketch, o submenu Incluir Bilioteca e por fim, basta clicar na opção Adicionar biblioteca .ZIP (Add ZIP Library) e encontrar o arquivo que acabou de ser baixado.

Uma outra forma de fazer isso é extrair o conteúdo do arquivo ZIP dentro da pasta Libraries (onde foi instalada a IDE do Arduino).

– Código do projeto

Segue o código a ser utilizado no Arduino para imprimir informações no Display LCD I2C 20x4.

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

// Inicializa o display no endereco 0x27
LiquidCrystal_I2C lcd(0x27,2,1,0,4,5,6,7,3, POSITIVE);
 
void setup()
{
 lcd.begin (20,4);
}
 
void loop()
{
  lcd.setCursor(0,0);
  lcd.print("********************");
  lcd.setCursor(9,1);
  lcd.print("VIDA");
  lcd.setCursor(5,2);
  lcd.print("DE SILICIO");
  lcd.setCursor(0,3);
 lcd.print("********************");
}

Entendendo a fundo

Software

- Incluindo as bibliotecas

Inicialmente, observe que foi necessário incluir duas bibliotecas no código para que o mesmo pudesse funcionar corretamente. A biblioteca wire.h é a responsável pela comunicação utilizando o protocolo I2C enquanto a biblioteca LiquidCrystal_I2C.h atua sobre a biblioteca wire.h simplificando o processo de comunicação através do protocolo citado, para que assim, o usuário possa utilizar o Display LCD I2C 20x4 de maneira mais fácil.

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

- Criando o objeto lcd 

Em seguida, cria-se um objeto que será utilizado posteriormente para representar o Display LCD I2C 20x4 no código.

Lembre-se: lcd é apenas um nome, sendo assim, é importante ressaltar que este objeto poderia ser chamado por qualquer outro nome, como por exemplo, display.

LiquidCrystal_I2C lcd(0x27,2,1,0,4,5,6,7,3, POSITIVE);

Essa função é padrão tanto para o LCD 20x4 como para o 16x2. Nela definimos o endereço do adaptador, que para o nosso equivale sempre 0x27.

Além do endereço, definimos, nesse comando, os  pinos no chip I2C usados para conexões no LCD. Como esse pinos sempre são os mesmos, temos esse comando sendo usado para definir apenas o endereço, que para alguns módulos pode ser alterado. As demais configurações são padrões.

// Define os pinos do chip I2C usados para as conexões do LCD:
//               (Endereço,en,rw,rs,d4,d5,d6,d7,bl, blpol)
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);

- Definindo as configurações iniciais

Dentro da função setup() utilizamos a função lcd.begin() (repare que o nome lcd corresponde ao objeto criado anteriormente) para inicializar o Display LCD I2C 20x4, de modo que, os parâmetros utilizados são o número de colunas e o número de linhas do display, nesta ordem.

void setup()
{
 lcd.begin (20,4);
}

Veja que, caso esteja usando um display LCD 16x2, aqui você definirá o tamanho do LCD com 16 colunas e 2 linhas:

void setup()
{
 lcd.begin (16,2); //configuração para display 16x2
}

- Imprimindo informações no Display

O primeiro passo na manipulação do display consiste em localizar o cursor no local adequado. Este cursor nada mais é do que o elemento que apontará para o espaço que será preenchido com um caractere, sendo assim, utilizamos a função setCursor() para determinar qual será o ponto de partida da escrita de uma sequência de caracteres.

Perceba que a as posições dos espaços para escrita são dadas da seguinte forma:

Desta maneira, ao utilizarmos "0" e "0" como parâmetros, estaremos definindo a coordenada (0,0) como ponto de partida para o começo da escrita.

lcd.setCursor(0,0);

Em seguida, utilizamos a função print() para poder escrever algo a partir da posição que definimos como ponto de partida. Neste caso, simplesmente preencheremos com '*'.

lcd.print("********************");

Posteriormente, utilizamos novamente a função setCursor() para posicionar o cursor na segunda linha.

lcd.setCursor(9,1);

Com o cursor posicionado, escrevemos a palavra 'VIDA'.

 lcd.print("VIDA");

Para continuar, posicionamos o cursor na próxima linha.

lcd.setCursor(4,2);

E escrevemos as palavras "DE SILICIO".

lcd.print("DE SILICIO");

Para finalizar, posicionamos o cursor no início da última linha.

lcd.setCursor(0,3);

Neste momento, iremos proceder da mesma maneira que fizemos na primeira linha, preenchendo a mesma com '*'.

lcd.print("********************");

Veja como ficou nossa função loop():

void loop()
{
  lcd.setCursor(0,0);
  lcd.print("********************");
  lcd.setCursor(0,1);
  lcd.print("aaaaaaaaaaaaaa");
  lcd.setCursor(0,2);
  lcd.print("ssssssssssssssss");
  lcd.setCursor(0,3);
  lcd.print("ddddddddddddddd");
}

Adaptando o programa para o display LCD 16x2

Para adaptar esse programa para o LCD 16x2 você precisa ter em mente que a tela é menor. Tendo 16 colunas e 2 linhas.

- Definindo as configurações iniciais

Dentro da função setup() utilizamos a função lcd.begin()  para inicializar o Display LCD I2C 16x2, de modo que, os parâmetros utilizados são o número de colunas e o número de linhas do display, nesta ordem.

void setup()
{
 lcd.begin (16,2); //configuração para display 16x2
}

- Imprimindo informações no Display

Na manipulação do display precisamos localizar o cursor no local adequado usando o comando setCursor() . Perceba que a as posições dos espaços para escrita são dadas da seguinte forma:

Em seguida basta usar o comando lcd.print().


Considerações finais

Neste tutorial buscamos elaborar um conteúdo semelhante ao que já temos sobre a utilização de displays LCD, no entanto, neste caso, utilizamos um display que ao invés de utilizar vários pinos numa placa Arduino, este necessita apenas de 4 pinos em virtude de a comunicação ser feita através do protocolo de comunicação I2C. Esperamos que você tenha gostado deste conteúdo, sinta-se à vontade para nos dar sugestões, críticas ou elogios. Lembre-se de deixar suas dúvidas nos comentários abaixo.


Como fazer um tutorial?

Como fazer um tutorial?

Nós, da equipe Vida de Silício, apresentamos este documento como forma de demonstrar os principais pontos que devem ser observados pelos autores durante o processo de desenvolvimento de conteúdos para o portal.

Este material visa trazer algumas diretrizes de padronização para que todo conteúdo produzido obedeça certos requisitos de organização. Além disso, este também tem a função de nortear o autor no processo criação, por meio da execução de uma sequência predefinida passos.

É importante ter em mente de que, com esse padrão, conseguimos fazer um tutorial em uma linha de raciocínio didática. Ajuda a orientação tanto do autor durante a escrita como do leitor no momento do aprendizado.

Lembre-se que o objetivo do Portal Vida de silício é concentrar em um só lugar tutoriais de alta qualidade dos mais diversos assuntos. Tudo isso organizado de forma simples e intuitiva.

“Se quer ir rápido, vá sozinho. Se quer ir longe, vá acompanhado.”

Toda sugestão será bem vinda!

[toc]


Sobre qual assunto falar?

Você pode escrever sobre praticamente qualquer assunto ligado a robótica no portal Vida de Silício. Como queremos impactar o máximo de pessoas possíveis, a grande sacada é fazer conteúdos sobre assuntos que são de interesse geral.

Exemplos de temas:
  • Tutoriais sobre o básico de Raspberry pi
  • Tutorias Básicos de NodeMCU
  • Tutoriais de sensores e módulos com Arduino

Existem muitas outras plataformas, tais como: Freescale , MSP, Beaglebone, Orange Pi. Se você tiver conhecimento sobre qualquer uma delas, sua contribuição com certeza será bem vinda. A única recomendação é que sempre se comece com um tutorial de apresentação da plataforma trabalhada. Um tutorial no estilo:"O que é Arduino?"


Criando um tutorial no Wordpress

Depois de criado sua conta como autor do site, você terá acesso exclusivo à área administrativa do Portal.  Iremos explicar a partir daqui como criar seu primeiro tutorial

Criando um post

O primeiro passo para que um determinado conteúdo seja publicado no portal Vida de Silício consiste no acesso do autor ao ambiente de desenvolvimento  adequado, utilizando o login e a senha previamente criados e cedidos pela nossa equipe.

Em seguida, deve-se localizar a opção Posts na barra de ferramentas localizada à esquerda da tela e posteriormente clicar em Adicionar novo.

Após a realização do procedimento anterior, o autor terá acesso à página em que poderá desenvolver o conteúdo desejado. Neste local, existem basicamente dois campos a serem preenchidos pelo mesmo: o título (lembre-se de escolher um que consiga expressar o conteúdo abordado de maneira clara) e o texto em si.

Em relação ao texto, torna-se necessário fazer uma ressalva, que consiste no fato de que o autor deve usar formatações diferentes para os tópicos e subtópicos existentes ao longo do conteúdo.

É importante resaltar que você precisa alternar a barra de ferramentas para que tenha acesso as configurações que usaremos para formatar o texto. Para isso clique no ícone "Alternar barra de ferramentas"

Como será visto posteriormente, o tutorial a ser desenvolvido possui basicamente três partes: Uma parte introdutória, uma parte de desenvolvimento e uma parte voltada para que o autor apresente um maior detalhamento sobre os elementos que constituem o projeto. Sendo assim, sempre que uma destas seções for iniciada, é necessário utilizar o Cabeçalho 1 para apresentar o título da mesma, no entanto, em relação às divisões internas de casa uma das partes citadas, utiliza-se o Cabeçalho 2 como título de cada subparte destasPara as demais partes do texto, basta selecionar a opção Parágrafo.

Anexando imagens

Deve-se ressaltar que além dos elementos escritos, existe também a possibilidade de realizar a inclusão elementos gráficos no espaço reservado para o desenvolvimento. Para inserir, por exemplo, uma imagem no conteúdo que esta sendo produzido, basta que o autor clique no botão Adicionar mídia.

Em seguida, deve-se selecionar  imagem desejada (este procedimento pode ser feito arrastando a imagem para a tela ou clicando no botão Selecionar arquivos e escolhendo a mesma manualmente).

Apenas como uma observação, sugerimos que o autor não utilize legenda nas imagens, no entanto, deve-se salientar que é necessário que o significado de uma eventual imagem utilizada esteja condizente com o conteúdo apresentado.

Inserindo códigos

Assim como é possível anexar imagens ao conteúdo, pode-se também realizar a escrita de códigos de programação caso seja necessário. Para realizar este procedimento, deve-se clicar no seguinte ícone.

Em seguida, basta somente escrever o código no espaço adequado (não é necessário que o autor altere qualquer uma das configurações preestabelecidas apresentadas nesta janela) e clicar em OK

Será adiciona uma caixa com o código na área de edição do seu tutorial.

O código ficará assim quando postado:

//Exemplo de código 

// Função Setup void 
setup() { 
   pinMode(LED_BUILTIN, OUTPUT); 
} 

// Função Loop void 
loop() {
   digitalWrite(LED_BUILTIN, HIGH); // Liga o LED 
   delay(1000); // Espera 1 segundo 
   digitalWrite(LED_BUILTIN, LOW); // Desliga o LED 
   delay(1000); // Espera 1 segundo 
}

 

Inserindo partes expansíveis em seu tutorial

Caso queira, você pode criar partes expansíveis em seu tutorial tal como o exemplo abaixo.

Para usar isso em seu tutorial, você precisará usar da o seguinte código

Coloque aqui o conteúdo

Veja como ficou nesse tutorial:


Como o post deve está organizado?

Como forma de padronização, nós pedimos aos autores que dividam os conteúdos em algumas seções predeterminadas. Basicamente, um tutorial deve conter três partes, nas quais, a primeira delas deve ser voltada para introduzir o conteúdo para o leitor, a segunda corresponde ao desenvolvimento do projeto, enquanto a terceira faz explicação detalhada do funcionamento do mesmo.

  • Parte 1: O que será aprendido; (H1)
    • O que vamos aprender? (H2)
    • Contexto histórico ou Aplicação prática  (H2)
    • Introdução e Explicação sobre os componentes-chave  (H2)
  • Parte 2: Mão à obra - Exemplo;   (H1)
    • Componentes necessários  (H2)
    • Montando o projeto  (H2)
    • Conectando ao computador  (H2)
    • Programando  (H2)
    • Colocando para funcionar  (H2)
  • Parte 3: Entendendo a fundo - Explicação detalhada do projeto da parte 2 (H1)
    • Software (H2)
      • Divida sua explicação em subtítulos; (H3)
    • Hardware (Opcional) (H2)
      • Divida sua explicação em subtítulos; (H3)

No fim do Tutorial costumamos adicionar uma quarta parte com os seguintes tópicos:

  • Desafio (Opcional)
  • Fechamento

Sobre o uso dos cabeçalhos

Para organizar esse esqueleto de forma visivelmente agradável, usamos a divisão em cabeçalhos.  Dividimos o tutorial em três tipos de cabeçalhos

Cabeçalho 1 - Tópicos principais (H1) 

Esse cabeçalho precisa ser azul e no formato Oswald.

Cabeçalho 2 - Divisão dos tópicos principais (H2)

Esse cabeçalho só precisa ser preto

- Cabeçalho 3  - Subtítulos (H3)

Esse cabeçalho é preto e adicionamos um traço antes do titulo.

Veja que no tópico anterior adicionamos na frente de cada título e subtítulo as abreviações: H1, H2 e H3. Eles mostram quais as configurações de cabeçalhos a serem usados para da um deles.

A seguir, disponibilizamos um roteiro para que fique mais fácil seguir as diretrizes necessárias para a realização de um tutorial bem claro e didático para o leitor.


O que vamos aprender? (Aqui entra o título que responde essa pergunta)

(QUAL É O OBJETIVO DESSE ARTIGO/POST/CONTEÚDO/MATERIAL? OU DEIXAR SEM NADA PARA O AUTOR COMEÇAR JÁ COM O TEXTO?)

Este espaço está reservado para que o autor fale sobre o objetivo do projeto proposto, ou seja, sugerimos para o autor que elabore um ou dois pequenos parágrafos explicando sobre o que será desenvolvido e o que o leitor poderá aprender com a leitura do conteúdo em questão.

Esse primeiro paragrafo é muito importante para que o Google consiga saber do que se trata o projeto e que ele possa direcionar às pesquisas certas. Então sempre coloque os assuntos principais em negrito, tal como o nome do módulo.

Contexto Histórico e aplicação prática

Nesta seção, sugere-se que o autor elabore um pequeno conteúdo referente ao contexto histórico do assunto proposto, de modo que, através da apresentação do mesmo, o leitor possa compreender um pouco a importância do que está sendo tratado, além de adquirir uma noção básica sobre a aplicabilidade do projeto e por que aprender sobre o mesmo é interessante.

Introdução aos Componentes-chave

Em geral, a maioria dos tutoriais possuem algum módulo ou controlador que pode ser encarado como o elemento mais importante do projeto, portanto, entende-se que, para uma melhor didática e clareza é necessário que o autor descreva um ou mais parágrafos sobre o(s) mesmo(s). O objetivo desta seção consiste em criar um ambiente em que o leitor, caso não tenha um entendimento muito abrangente sobre o assunto que está sendo tratado, possa sentir-se confortável, seguro e interessado para aprender sobre o mesmo.

Foto do módulo ou componente que será explicado

Mãos à Obra - Desenvolvimento do projeto

Esta é a seção onde, de fato, ocorre o desenvolvimento do projeto em si. Sugerimos dividir esta seção em 5 partes para auxiliar na escrita do conteúdo proposto.

Componentes Necessários

Primeiramente, o autor deve listar os componentes que serão utilizados no desenvolvimento do projeto e também associá-los aos respectivos links existentes na loja. Veja o exemplo abaixo:

Nesta seção, pedimos que o autor faça o uso marcadores para listar os componentes utilizados. Para realizar este procedimento deve-se apenas clicar no ícone correspondente conforme a figura abaixo.

Montando o Projeto

Em seguida, é necessário que o autor elabore uma imagem clara e didática do circuito utilizando o Fritzing (http://fritzing.org/home/).

Aqui é legal colocar uma foto do projeto montado depois do esquemático, caso seja possível, para que o leitor veja a montagem na prática.

Conectando o Arduino no Computador

Neste ponto, o autor deve lembrar ao leitor como configurar a IDE do Arduino para receber o código que será apresentado posteriormente. Este passo é necessário pois muitas vezes ocorrem erros ao carregar o programa no Arduino em virtude de uma configuração inadequada da interface utilizada. Sugerimos o uso do seguinte texto padrão:

Conecte seu Arduino ao computador e abra a IDE Arduino.

Antes de carregar um programa, você precisa selecionar qual porta você deseja usar para fazer carregar o programa no Arduino (upload). Dentro do Arduino IDE, clique no menu Ferramentas (tools) e abra o submenu Porta(Port). Clique na porta que seu Arduino está conectado, tal como COM3 ou COM4. Geralmente aparece o nome da placa Arduino : “COM3 (Arduino/Genuino Uno)”.

Você também precisa garantir que o tipo de placa apropriado está selecionado em Ferramentas(Tools) no submenu Placa (Board).

Programando

Esta seção é dedicada ao código da aplicação que está sendo desenvolvida neste tutorial.

- Biblioteca (Apenas se for usada alguma biblioteca)

Caso o autor tenha usado uma biblioteca é importante mostrar onde baixa-la e se possível como instala-la.

- Código do Projeto

Aqui basta que o autor coloque o código inteiro, comentado e de maneira bem organizada visualmente pois isso facilita para o leitor que não tem muita intimidade com a linguagem de programação utilizada.

É interessante escrever algo como:

"Segue o código a ser usado no exemplo"

// Programa Exemplo

uint32_t referencia = 0;
uint32_t tempoAtual;
void setup() {
pinMode(13,OUTPUT); // Configura o pino 13 (LED) como saída
}
 
void loop()
{
     tempoAtual = millis(); // Captura o tempo atual
// Verifica se já se passaram 1 segundo (1000 milissegundos)
// desde a última vez em que o LED foi invertido
     if(tempoAtual - referencia >= 1000) {
        // Se sim, inverte o LED e atualiza a referencia
        digitalWrite(13,!digitalRead(13));
        referencia = millis();
     }
}

Colocando para Funcionar

Aqui, sugerimos que o autor coloque uma foto do circuito montado fisicamente, um gif, ou até mesmo um pequeno vídeo, demonstrando a aplicação em funcionamento.

Entendendo a fundo

Esta é a terceira parte do tutorial que está sendo desenvolvido. Aqui, o autor deve elaborar duas seções para que possa explicar de maneira mais detalhada, tudo o que acontece por trás dos passos realizados anteriormente, ou seja, pede-se ao autor  que elabore um conteúdo teórico que explique o funcionamento do hardware e também que realize a análise código que foi inserido no Arduino, porém, com um nível maior de detalhamento.

Aqui colocamos a explicação do software antes do Hardware, mas você pode explicar na ordem que preferir.

Software (Importante)

Aqui o autor precisa explicar os comandos usados ao longo do projeto de forma a explicar ao leitor a função de cada comando visando o melhor entendimento.

É importante dividir a explicação em subtítulos tais como o abaixo:

- Declarando biblioteca

Exemplo de explicação

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

- Função digitalRead()

Explicação exemplo.

estadoSensor = digitalRead(3);

Hardware (Opcional)

Aqui o autor pode explicar conceitos importantes sobre o Hardware tais como propriedades físicas ou como ele funciona.

Aqui vale também a divisão em subtítulos.

Desafio (OPCIONAL)

Caso o autor deseje, pode-se propor um desafio relacionado ao assunto tratado no conteúdo desenvolvido.

Fechamento

Para finalizar o tutorial, basta que o autor escreva um parágrafo de conclusão sobre o assunto e também peça ao leitor que não deixe de fazer seus elogios, críticas e sugestões sobre o conteúdo em questão. Além disso, também é importante abrir o espaço para que o leitor possa fazer perguntas e tirar as suas dúvidas.


Exemplos de tutoriais

Este foi o modelo referente à estrutura que deve ser seguida na elaboração de tutoriais. Acreditamos que, de acordo com esta proposta, seja possível produzir materiais de ótima qualidade e de fácil entendimento para o leitor.

Recomendamos que consulte alguns tutoriais para verificar essa organização:

Como dito no inicio desse tutorial, esse padrão visa o melhor entendimento de quem ler mas também visa facilitar a vida de quem escreve criando uma linha de raciocínio fácil de ser seguida. Caso tenha uma sugestão de como melhorá-la, ficaremos contentes e te ouvir.


Finalizando o conteúdo

Após a finalização da elaboração do conteúdo, o autor deve enviar o mesmo para revisão e avisar a equipe Vida de Silício, por e-mail, que o material está concluído.


Respondendo aos comentários

Recomendamos que o autor fique atento aos comentários e sempre que possível responda as dúvidas dos leitores nos seus respectivos conteúdos. Assim você gerará uma interação bacana com seus leitores e ainda ajudará pessoas que provavelmente possuem a mesma dúvida.

Caso seja necessário, você pode utilizar links externos nas respostas, desde que não sejam de concorrentes diretos da loja Vida de Silício.