ENC28J60 NANO SHIELD czyli wygodny sposób na podłączenie Arduino do sieci!

Wraz z biegiem lat płytki Arduino są wykorzystywane do coraz bardziej zaawansowanych projektów i nie dzieje się to za sprawą samych płytek, ale w dużym stopniu dzięki modułom oraz układom kompatybilnych z procesorami 8-bitowymi. Dzisiaj pod lupę weźmiemy shield, czyli nakładkę na płytkę Arduino Nano, shield ten jest wyposażony w układ ENC28J60 który zajmuje się przetwarzaniem danych które mogą trafić do sieci, dobrze wykorzystany stanie się kombajnem sieciowym który do wszystkich użytkowników docelowej sieci może dostarczać dane z czujników lub zbierać i wykonywać polecania userów. 

Podłączenie modułu do płytki i sieci

Podłączenie shielda do Arduino jest niezwykle proste ponieważ musimy nałożyć piny shielda na piny od naszej płytki uruchomieniowej, warto sprawdzić które piny są opisane na shieldzie i Arduino i podłączyć shielda zgodnie z nimi. Na zdjęciu poniżej zaprezentowane jest prawidłowe podłączenie modułu do płytki.

Biblioteki i niezbędne materiały

Do uruchomienia modułu i rozpoczęcia udanej współpracy z płytką przyda nam się biblioteka, my skorzystamy z biblioteki EtherCard, oprócz EtherCard w sieci możemy znaleźć jeszcze kilka bibliotek, jednak ta moim zdaniem jest najłatwiejsza w obsłudze,  a funkcje które oferuje w zupełności wystarczą do większości zadań. Bibliotekę pobieramy z linka umieszczonego na dole artykułu. Pakiet musimy oczywiście zaimplementować w IDE. Programowanie płytki rozpoczniemy od wgrania zmienionego na nasze potrzeby przykładu backSoon, program ma za zadanie podłączyć się do sieci i postawić prostą witrynę która będzie wyświetlała tekst. Cały program który musimy wprowadzić jest przedstawiony poniżej.

#include <EtherCard.h>
#define STATIC 1
#if STATIC
static byte myip[] = { 192,168,1,200 };//adres IP, możemy go dowolnie definiować
static byte gwip[] = { 192,168,1,1 };//adres bra,y domyslnej, w naszym przypadku routera
#endif
static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 }; //indywidualny adres mac płytki

byte Ethernet::buffer[500]; // tcp/ip send and receive buffer

const char page[] PROGMEM =
"HTTP/1.0 503 Service Unavailable\r\n"
"Content-Type: text/html\r\n"
"Retry-After: 600\r\n"
"\r\n"
"<html>"
  "<head><title>"
    "Witaj na twojej pierwszej stronie"
  "</title></head>"
  "<body>"
    "<h3>Na bazie tej strony możemy stworzyć witryne w sieci lokalnej</h3>"
    "<h2>Wprowadzenie tekstu jest bardzo latwe, wystarczy znac podstawy HTML</h2>"
  "</body>"
"</html>"
;//tutaj definujemy jaka strona zostanie wyswietlona

void setup(){
  Serial.begin(57600);
  Serial.println("\n[backSoon]");
  if (ether.begin(sizeof Ethernet::buffer, mymac, SS) == 0)
    Serial.println( "Failed to access Ethernet controller");
#if STATIC
  ether.staticSetup(myip, gwip);
#else
  if (!ether.dhcpSetup())
    Serial.println("DHCP failed");
#endif
  ether.printIp("IP:  ", ether.myip);
  ether.printIp("GW:  ", ether.gwip);
  ether.printIp("DNS: ", ether.dnsip);
}
void loop(){
  if (ether.packetLoop(ether.packetReceive())) {
    memcpy_P(ether.tcpOffset(), page, sizeof page);
    ether.httpServerReply(sizeof page - 1);
  }
}

Większość elementów w kodzie zostało wyjaśnionych za pomocą komentarzy kodu źródłowego, jednak warto skupić się nie na samym programie co na aspektach sieciowych, bo właśnie to może być bardziej niezrozumiałe dla osób które na co dzień nie mają kontaktu z chociażby konfigurowaniem sieci komputerowych. Adres  IP jest to numer identyfikacyjny urządzenia w sieci i służy do prawidłowej komunikacji pomiędzy innymi urządzeniami. Każde urządzenie w sieci powinno mieć indywidualny adres IP, tak aby przesyłanie pakiety nie kolidowały ze sobą, my użyliśmy adresu 192.168.1.200, tak aby nabrać bezpiecznego dystansu do innych urządzeń w sieci, jeśli jednak do sieci mamy podłączone jedno urządzenie to moduł Ethernet może mieć IP 192.168.1.3. Tutaj może zrodzić się pytanie, skoro w sieci są tylko dwa urządzenia, dlaczego nie nadamy modułowi Ethernet adresu 192.168.1.2? Z jednej bardzo prostej przyczyny, adres 192.168.1.1 jest adresem bramy domyślnej i przypisany jest do routera i ten właśnie adres bramy domyślnej oznaczony jest w programie jako “gwip”. Ostatnim elementem jest adres MAC oznaczony jako “mymac”, adres MAC jest indywidualnym adresem urządzenia, podobnie jak w przypadku IP dwa te same adresy MAC w sieci mogą spowodować kolidowanie pakietów. O ile mamy w sieci tylko jeden moduł Ethernet to nie mamy czym się przejmować, jednak gdy podłączymy do sieci dwa lub więcej urządzeń adresy należy zmodyfikować aby różniły się chociażby jednym znakiem.

Gdy wgramy powyższy program do naszego Arduino warto włączyć Serial Monitor, wyświetli nam wprowadzone przez nas dane, należy też zmienić prędkość transferu danych w Serial Monitorze z 9600 bodów na 57600 bodów. Po wgraniu programu i włączeniu Serial Monitora powinien ukazać nam się taki widok.

Gdy jesteśmy pewni, że moduł jest skonfigurowany według podanych przez nas adresów musimy wpiąć kabel zakończony wtyczką RJ45 do naszego modułu, a drugą wtyczkę do wolnego gniazda RJ45 w routerze. Po podłączeniu należy odczekać kilka sekund, po tym czasie wracamy do komputera i w pasku przeglądarki wpisujemy adres ip naszego modułu, następnie klikamy enter, naszym oczom powinna ukazać się strona wyglądająca jak ta poniżej.

Urozmaicenie programu o wyświetlanie odczytu z czujnika DS18B20

Aby przetestować szybkość działania programu do pinu 4 podłączymy czujnik temperatury DS18B20, dzięki czemu będziemy mogli sprawdzić jak sprawuje się wyświetlanie danych z czujników. Czujnik podłączamy do pinu 4, warto pamiętać aby zmostkować pin danych i VCC rezystorem podciągającym 4,7 KOHM. Układ należy zbudować według zdjęcia poniżej.

Po zbudowaniu układu możemy przejść do części programowej, niezbędna będzie nam biblioteka OneWire oraz DallasTemperature(link na dole artykułu) do obsługi czujnika DS18B20 oraz pakiet bibliotek ETHER_28J60 do łatwiejszej obsługi czujników na naszej stronie. Dlaczego używamy dwóch różnych bibliotek? Z prostej przyczyny, nie ma sensu utrudniać sobie pracy, EtherCard jest dużo lepszy do zastosowań typowo sieciowych, jednak ETHER_28J60 jest o wiele wygodniejszym narzędziem do wypisywania danych różnego typu na stronie, kod jest też lżejszy i łatwiejszy do zrozumienia. Gdy mamy zainstalowany nowy pakiet bibliotek możemy przejść do pisania programu który powinien wyglądać jak ten poniżej.

#include "etherShield.h"
#include "ETHER_28J60.h"
#include <OneWire.h>
#include <DallasTemperature.h>
#define ONE_WIRE_BUS 4 //definiujemy podłączenie czujnika DS18B20
OneWire oneWire(ONE_WIRE_BUS); //uruchamiamy magistrale OneWire
static uint8_t mac[6] = {0x74, 0x69, 0x69, 0x2D, 0x30, 0x31}; //adres MAC                                                      
static uint8_t ip[4] = {192, 168, 1, 200}; //adres bramy domyslnej
static uint16_t port = 80; //port danych, dla HTML wartosc powinna wynosic 80
ETHER_28J60 e;
DallasTemperature sensors(&oneWire); //przypisujemy czujnik DS18B20 do OneWire
void setup()
{ 
  sensors.begin();
  e.setup(mac, ip, port);
}

void loop()
{
  sensors.requestTemperatures(); //pobieramy dane o temperaturze z DS18B20
  float temp = sensors.getTempCByIndex(0); // tworzymy zmienne dla wartości z czujnika
  if (e.serviceRequest())
  {
    e.print("<H3>Oto twoj pierwszy sieciowy czujnik temperatury!</H3><br/>");
    e.print("Temperatura wynosi ");
    e.print(temp);
    e.print(" *C");
    e.respond();
  }
  delay(100);
}

Po wgraniu programu powinien ukazać nam się taki widok.

Znamy już podstawy działania tego modułu, jak widać zastosowanie Arduino w sieci nie jest tak trudne jak mogłoby się wydawać, swoją drogą układ ENC28J60 uchodzi za najtrudniejszy do zaprogramowania i przystosowania do prawidłowego działania, ponieważ nie jest oficjalnie wspierany przez Arduino, jednak trochę praktyki i zastosowanie odpowiednich bibliotek daje w pełni pożądane efekty! 

Produkty użyte w poradniku:

Biblioteki użyte w poradniku: