Colocando o Arduino na rede com o ENC28J60 Ethernet Shield

Há um tempo atrás eu comprei um shield ethernet, e, logo que chegou, conectei no Arduino e carreguei o sketch de exemplo para testar. Adivinhem? Não funcionou.

O parto começou tentando descobrir por quê não funcionava, achei até que o shield veio com defeito. Depois de muito pesquisar, descobri que o meu shield usava um chipset específico, e que por isso a biblioteca que vem com o Arduino não funcionava. Na época achei apenas uma biblioteca que funcionava, mas era demasiada complicada e acabei deixando para lá.

Hoje, depois de encontrar o blog Tweaking4All, descobri que há mais duas bibliotecas disponíveis, alem da que testei anteriormente estar bem mais funcional. Então, atente para que este post é específico para os shields que usam o chipset ENC28J60.

Arduino e o ENC28J60 Ethernet Controller

ENC28J60 refere-se a um chip desenvolvido por Microchip. Este chip tem 28 pinos  e contem um controlador ethernet completo para uma conexão de rede 10BASE-T e uma interface SPI para “falar” com microcontroladores como o Arduino.

10BASE-T é o mesmo conector encontrado nos computadores atuais para conectá-los na rede cabeada, e o 10 indica a velocidade, no caso 10Mbps. Parece pouco para os padrões atuais (gigabit), mas é mais do que o suficiente para aplicações envolvendo Arduino.

Apenas para reforçar, o controlador usado aqui é o ENC28J60. O ethernet shield padrão do Arduino usa o controlador Wiznet W5100, que vem com a biblioteca adequada na IDE, porem NÃO funciona com o ENC28J60. Para fazermos o ENC28J60 funcionar, precisaremos instalar outras bibliotecas.

Diferenças entre o ENC28J60 e o W5100

Preço. Shields que usam ENC28J60 são mais baratos que shields que usam W5100. Hoje essa diferença não é tanta(menos de $4), mas há um ano atrás um shield W5100 custava em torno de $40 enquanto um shield ENC28J60 custava abaixo de $20. Por quê essa diferença? No geral o hardware do ENC28J60 é bem mais simples que do W5100, o que traz vantagens e desvantagens. Uma das vantagens é o preço, vamos analisar as outras diferenças, todas derivadas de um chip mais barato.

Velocidade. Conforme dito, ENC28J60 funciona apenas a 10Mbps, enquanto o chip W5100 funciona a 10Mbps ou 100Mbps. Em teoria é uma vantagem do W5100, mas na prática isso não ocorre, porque não se conhece algum sketch com o mínimo de utilidade que consiga chegar em 10Mbps, procurei e não achei nem mesmo sketches de teste que consigam saturar 10Mbps.

Hardware. Aqui a grande direfença. O ENC28J60 implementa somente a camada Enlace do modelo TCP/IP, sendo capaz de tratar apenas o endereçamento MAC, detecção de colisão e retransmissão de pacotes. Possui um buffer de trasmissão/recepção de 8KBytes e não suporta conexões simultâneas. Já o W5100, implementa as camadas de Enlace, Network e Tranporte, implementando internamente(em hardware) os protocolos IP e TCP, alem de ARP, ICMP e IGMP. O buffer de transmissão/recepção é de 16KBytes.

Performance. Baseado no hardware, vemos que o ENC28J60 exige muito mais do Arduino, ao ter a pilha TCP/IP implementada na biblioteca. Isso consome a pouca memória disponível para nossos sketches, normalmente 32K. Um simples WebServer usando o sketch de exemplo consome 12K para para a biblioteca padrão do W5100(Ethernet) e 21K para a biblioteca UIPEthernet(para o ENC28J60).

Biblioteca. A IDE do Arduino vem com uma biblioteca padrão para uso com o chip W5100. Para o ENC28J60, temos as bibliotecas ETHER_28J60, EtherCard e UIPEthernet, sendo que esta última implementa exatamente os mesmos métodos da biblioteca padrão do W5100. Embora implemente os mesmos métodos, convêm lembrar que internamente elas são bem diferentes, pois enquanto a biblioteca para W5100 deixa muito do trabalho para o hardware, a UIPEthernet tem que implementar esse trabalho no código.

Resumo. Bom, o preço é um chamativo bem atraente.  Para projetos mais simples as desvantagens do shield ENC28J60 podem não ser perceptíveis, mas quando pretende-se exigir um pouco mais do Arduino, pode ser que o ENC28J60 não funcione como desejado e seja necessário desativar algumas funcionalidades da biblioteca ou adequar o projeto. Claro que desvantagem para um pode ser vantagem para outro, o maior problema do ENC28J60 é o fato de implementar o TCP/IP em software, o que penaliza seriamente a performance, mas e se você quiser, por exemplo, usar IPv6? Bem, como o W5100 implementa a camada de rede(IP) em hardware, isso seria impossível, e ai a desvantagem do ENC28J60 se torna uma vantagem, pois podemos ter um biblioteca implementando o IPv6 na camada de rede, como é o caso da biblioteca IPv6EtherShield.

 

Escolhendo sua placa ENC28J60

Caso ainda não tenha adquirido e esteja pensando em comprar, vai encontrar muitos modelos diferentes que usam o chip ENC28J60. As principais diferenças ficam por conta do layout da placa e pinagem, que pode se acoplar diretamente ao Arduino ou necessitar de cabos para conexão.

Abaixo alguns modelos que utilizam o chip ENC28J60, sendo o primeiro o que eu comprei. Na época escolhi este modelo por estar mais em conta.

IMG_3240ENC28J60_module  enc28j60 DSCN3177_zpse96e65c5 28j60_module nghlti1350351566388

 

Para quem utiliza o shield, é simples questão de conectar o shield ethernet ao arduino. Para os que possuem um módulo, vamos ver como fazer a conexão.

Os pinos usados pelo shield ENC28J60 e pelas bilbiotecas são 10, 11, 12 e 13, claro que o shield ENC28J60 ainda utiliza +5v e GND. Os pinos 10, 11, 12 e 13 são os efetivamente utilizados para a comunicação do shield ou módulo com o Arduino, e recebem os seguintes nomes:

  • Pino 10  –> SS (Slave Select) utilizado para habilitar ou desabilitar o dispositivo Slave (nosso shield/módulo ENC28J60 neste caso)
  • Pino 11   –> MOSI (Master Output Slave Input) O nome é claro, Master sendo o Arduino, dados do Arduino para o shield/módulo ENC28J60
  • Pino 12  –> MISO (Master Input Slave Outpu) Dados do shield/módulo para o Arduino.
  • Pino 13  –> SCK É o clock utilizado para sincronização SPI

No caso de módulos, normalmente os pinos são identificados pela sigla (SS, MOSI, MISO, SCK, +5v e GNP), bastando fazer a conexão destes pinos aos pinos 10, 11, 12, 13, +5v e GND do Arduino

Obtendo a biblioteca adequada

Como eu falei no início, foi um parto até descobrir que a biblioteca padrão do IDE Arduino não funcionava com minha placa, e outro parto descobrir a biblioteca certa. Ainda bem que, agora que voltei decidido a usar meu ethernet shield, encontrei o blog Tweaking4All. Segue abaixo uma quase tradução do excelente trabalho do autor com relação às bibliotecas disponíveis atualmente.

UIPEthernet  ideal para projetos que façam uso intensivo da função “print” e possui as mesmas funções da biblioteca padrão do Arduino “Ethernet”

ETHER_28J60 muito boa devido a sua simplicidade e pequeno tamanho, mas tem muitas limitações

Ethercard parece adequada para usuários muito avançados, porem UIPEthernet parece possuir todas as suas capacidades de modo mais simples

Embora o post original do Tweaking4All contenha exemplo para as três bibliotecas, aqui usaremos apenas a UIPEthernet.

Bibliotecas UIPEthernet

Como esta biblioteca possui as mesmas funções da biblioteca padrão do Arduino, a ethernet, usar exemplos disponíveis pela Internet é simplesmente questão de substituir  #include <ethernet.h> e #include <SPI.h> por #include <UIPEthernet.h>. A diferença fica por conta do código mais pesado (maior).

A biblioteca pode ser obtida no GitHub, ao abrir a página procure pelo link “Download ZIP”, normalmente a direita.

Após baixá-la, vamos importá-la para o Arduino, clicando em “Sketch” –> “Import Library” –> “Add Library”, ai é só selecionar o arquivo baixado, fechar a IDE e abrir novamente que a biblioteca deverá estar pronta para uso.

Vamos testar abrindo o sketch de exemplo, clicando em “File” –> “Examples” –> “arduino_uip” –> “TcpServer”

Abaixo o código, com algumas alterações:

1ª – Alteramos porta em que o Arduino escuta, de 1000 para a padrão(80) na seguinte linha “EthernetServer server = EthernetServer(80)”

2ª – Altere a linha “IPAddress myIP(192, 168, 1, 23);” de acordo com sua rede local.

3ª – No final, alterei a linha “client.println(“Data from Server”);” para um mais amigável “client.println(“<h1>Hello World!</h1>”);”

Algumas observações após o código

/*
 * UIPEthernet EchoServer example.
 *
 * UIPEthernet is a TCP/IP stack that can be used with a enc28j60 based
 * Ethernet-shield.
 *
 * UIPEthernet uses the fine uIP stack by Adam Dunkels <adam@sics.se>
 *
 * -----------------
 *
 * This Hello World example sets up a server at 192.168.1.6 on port 1000.
 * Telnet here to access the service. The uIP stack will also respond to
 * pings to test if you have successfully established a TCP connection to
 * the Arduino.
 *
 * This example was based upon uIP hello-world by Adam Dunkels <adam@sics.se>
 * Ported to the Arduino IDE by Adam Nielsen <malvineous@shikadi.net>
 * Adaption to Enc28J60 by Norbert Truchsess <norbert.truchsess@t-online.de>
 */

#include <UIPEthernet.h>

EthernetServer server = EthernetServer(80);

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

 uint8_t mac[6] = {0x00,0x01,0x02,0x03,0x04,0x05};
 IPAddress myIP(192,168,1,23);

 Ethernet.begin(mac,myIP);

 server.begin();
}

void loop()
{
 size_t size;

 if (EthernetClient client = server.available())
 {
 while((size = client.available()) > 0)
 {
 uint8_t* msg = (uint8_t*)malloc(size);
 size = client.read(msg,size);
 Serial.write(msg,size);
 free(msg);
 }
 client.println("<h1>Hello World!</h1>");
 client.stop();
 }
}

Certifique-se que o shield esteja conectado na rede, e faça upload do código. Após, acesse 0 servidor WEB digitando 192.168.1.23 no seu browser preferido(ou o IP que configurou). “Hello World” deverá aparecer no browser.

Este exemplo é muito simples, mas ideal para começarmos a aprender e avançar para exemplos mais complexos. Antes de darmos uma analisada no sketch, uma observação: lembram que eu falei que a biblioteca tem que implementar  camada de rede e a de transporte? Pois então, observem na janela da IDE do Arduino quanto que esse simples exemplo consumiu da memória do Arduino. No meu caso, foram 21K de 32K disponíveis.

Binary sketch size: 20.730 bytes (of a 32.256 byte maximum)

Vamos ver o que algumas linhas do sketch querem dizer:

EthernetServer server = EthernetServer(80);  Essa linha cria um objeto server, do tipo EthernetServer, e configuramos a porta em que nosso servidor irá escutar(aceitar conexões). Podemos simplificar o código e atribuir a porta logo na criação do objeto server, ficando então EthernetServer server(80); . Ah, o nome server pode ser qualquer um, poderia ser, por exemplo, servidor. Apenas lembre se de se referir a esse nome no restante do código.

uint_t mac[6] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05};  Aqui estamos criando uma variável mac(um array na verdade, contendo 6 bytes), para utilizá-lo na hora de iniciar a camada de rede do ENC28J60. Outra forma de escrever seria byte mac[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05};  O resultado é o mesmo.

IPAddress myIP(192, 168, 1, 23); Para usarmos um endereço IP, precisamo criar uma variável do tipo IPAddress, passando como iniciador do objeto o endereço, separado por vírgula. Neste sketch é dado o nome myIP para o objeto, mas podemos usar qualquer nome que acharmos mais adequado. Por exemplo, se quisermos criar um objeto IPAddress para armazenar o IP de um servidor DNS, o nome da variável poderia ser… dns … que tal?

Ethernet.begin(mac, myIP); Inicializa a biblioteca e as configurações de rede, no nosso caso estamos informando os endereços MAC e IP.  Caso não seja informado um endereço IP, somente Ethernet.begin(mac);  a biblioteca tenta buscar as configurações por DHCP. Podemos informar outras configurações de rede, sempre seguindo a seguinte sequência Ethernet.begin(mac, ip, dns, gateway, subnet);

server.begin(); Inicializa propriamente o servidor. A partir deste momento ele esta apto a receber conexões na porta anteriormente definida (80 em nosso caso).

Ethernet client = server.available();  server.available() retorna um objeto do tipo Ethernet Client, que armazenamos na variável client , reparem que Client (C maiúsculo) é a classe do objeto, e client (c minúsculo) é o objeto em si. Se nenhum cliente esta conectado ao servidor no momento da chamada, uma validação da chamada retorna false. Caso uma conexão exista, o objeto client contém todas as informações necessárias para ler informações do cliente e também para retornar informações. Neste sketch temos uma função que lê informações do cliente, mas não falaremos nada aqui, vamos deixar isso para um post específico.

client.println(“<h1>Hello World</h1>”); Esta é simples, uma fez que uma conexão exista, a função envia para o cliente os dados passados para ela. Neste exemplo informamos ao cliente (browser) para exibir Hello World, formatado entre as tags html <h1>…</h1>

client.stop(); As conexões TCP tendem a ser persistentes, ou seja, uma vez criadas tendem a serem mantidas ativas. O TCP possui mecanismos como timeout para detectar quando uma conexão se torna inativa, mas o correto é uma lado informar ao outro quando a conexão não é mais desejada e deve ser encerrada. Essa função informa ao cliente que a conexão esta encerrada, liberando recursos do servidor e do cliente.

Em um aplicação real, o código poderia ser melhorado, retirando a parte que exibe as informações na serial, comente os trecho abaixo(// no início da linha), faça upload novamente e teste. O resultado é o mesmo.

 void loop()
{
 size_t size;

 if (EthernetClient client = server.available())
 {
// while((size = client.available()) > 0)
// {
// uint8_t* msg = (uint8_t*)malloc(size);
// size = client.read(msg,size);
// Serial.write(msg,size);
// free(msg);
// }
 client.println("<h1>Hello World!</h1>");
 client.stop();
 }
}

Pronto, seu Arduino esta na rede utilizando o chip ENCj2860. Nada demais, eu sei, mas calma que devagar vamos incrementando 🙂

 

8 thoughts on “Colocando o Arduino na rede com o ENC28J60 Ethernet Shield

  1. Lenilson Amaral Barreto

    Seu artigo é de excelente qualidade, e bastante exclarecedor.
    Eu estou trilhando o mesmo caminho que você usou, consegui por em funcionamento rapidamento com um MEGA2560 graças a um vídeo do professor Afonso Miguel, publicado no You Tube.
    Eu comecei sózinho com assemble em PIC e passei para Freescale, depois de algum tempo comecei com “C” no Freescale, a IDE deste fornece mais informações que a do Arduino; estou tentando retirar as blibliotecas usada em tentativas e não deram certo, mas não consegui.

    Reply
  2. Leonardo Felini

    Olá, tenho uma duvida sobre esse método de servidor e não encontro a resposta em lugar nenhum. Pode ser até bobo, mas queria saber se esse webserver funciona apenas para dispositivos conectados na mesma rede, ou se dessa forma o servidor é aberto para qualquer dispositivo em qualquer rede de internet. Tenho um projeto de automação que necessita de controle pela internet a partir de qualquer dispositivo em qualquer lugar, mas não consigo achar uma resposta para essa pergunta.
    Obrigado.

    Reply
    1. Valdinei Rodrigues dos Reis Post author

      Ola Leonardo. Desculpe o abandono do blog.

      Neste exemplo não setamos um gateway, portanto seria acessível apenas pela rede local. Mas a biblioteca suporta a especificação de um gateway.
      No caso de usar um gateway, ele seria sim acessível pela Internet caso você configure um redirecionamento no seu roteador. Lembando que a maioria dos provedores bloqueiam portas comumente utilizadas por servidores, como a porta 80.

      Abs.

      Reply
    2. Junior

      Oi, é possível acessar de qualquer rede, mas é mais complicado, procura no youtube que você achará!

      Reply
  3. Vitor Bandeira

    Olá,
    Amigo é a primeira vez que tenho contato com Arduino pois tenho que desenvolver um trabalho para uma matéria do curso que faço de Engenharia.
    Comprei um Arduino Mega e um Shield Ehernet HR911105A e adicionei a Biblioteca UIPEhertnet pois foi a que o professor sugeriu.
    Até tudo certo. Estou usando o Exemplo que vem nessa Biblioteca que se chama EchoServer (sugestão também do professor) e fiz conforme procedimento informado de mudar o IP para um IP dentro da faixa que meu PC esta conectado.
    O problema é que quando mando carregar o código no Arduino sempre aparece a mensagem abaixo:
    AVISO: A categoria ” na biblioteca UIPEthernet é invalida. Definindo para ‘Uncategorized’
    Ao término do carregamento eu tento fazer um ping via prompt no IP que informei no código e não há comunicação.
    Poderia me ajudar? Será que esse avisa esta afetando em algo o meu teste?

    Abaixo segue o código do EchoServer:

    #include
    // The connection_data struct needs to be defined in an external file.
    #include
    #include

    EthernetServer server = EthernetServer(1000);

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

    uint8_t mac[6] = {0x00,0x01,0x02,0x03,0x04,0x05};
    IPAddress myIP(192,168,1,10);

    Ethernet.begin(mac,myIP);

    server.begin();
    }

    void loop()
    {
    size_t size;

    if (EthernetClient client = server.available())
    {
    if (client)
    {
    while((size = client.available()) > 0)
    {
    uint8_t* msg = (uint8_t*)malloc(size);
    size = client.read(msg,size);
    Serial.write(msg,size);
    client.write(msg,size);
    free(msg);
    }
    }
    }

    Reply
  4. Ricardo jardin

    Preciso de ajuda o meu não funciona enc28j60
    Não tenhovesquema de ligação e não sei se é meu roteador em qual porta ligo ou no pc
    Se montasse um passo a passo seria melhor

    Reply
  5. Kleyton

    Boa tarde amigos estou com um Shielder Ethernet que de vez em quando pisca led de COLISÃO está com frequência. O que pode ser? mudo IP carrega e vezes funciona outras não é assim que acontece.

    Quero por favor uma opinião de especialista como voces.

    Atenciosamente,

    Kleyton Campos

    Reply
  6. Geraldo

    Lenilson, progressos no seu projeto Arduino??

    Reply

Deixe uma resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

quatro + seis =