Close

Arduino a WiFi shield

Arduino WiFi Shield

V tomto článku se zaměříme na použití Arduina s WiFi shieldem. Ten nám umožní připojit se k síti bez nutnosti připojování Ethernet kabelu.

Seznámení

Občas se hodí mít možnost s Arduinem komunikovat bezdrátově. Pro různé účely se hodí různé způsoby komunikace – někdy je vhodnější použít bluetooth, někdy potřebujeme větší dosah a šáhneme například po modulech nRF24L01+, a když jsme v dosahu nějaké WiFi sítě, můžeme použít

WiFi shield. Jedná se o výrobek z oficiální produkce Arduina, tudíž k němu (jako k většině oficiálních desek) existuje výborná dokumentace. Na začátek si představme základní vlastnosti shieldu.

  • WiFi shield se umí připojit k WiFi sítím se standardem 802.11b a 802.11g.
  • Může se připojit k sítím bez hesla a také k těm se zabezpečením WEP a WPA2 Personal.
  • Shield obsahuje slot na microSD kartu.
  • S Arduinem shield komunikuje přes SPI rozhraní (stejně jako Ethernet Shield).
  • SS pin WiFi shieldu je vyveden na pinu 10. SS pin SD slotu je připojen na pin 4.
  • WiFi a SD kartu není možné používat současně.
  • Na desce také nalezneme mini USB port pro update firmware shieldu.
  • Aby se mohl shield k síti připojit musí síť vysílat svoje SSID (nesmí být skryto).
  • Po zmáčknutí tlačítka RESET dojde k restartu Arduina i shieldu.
  • Při práci se shieldem je doporučeno nepoužívat pin 7. Je totiž využíván knihovnou pro ovládání shieldu.

Na desce nalezneme i několik LED diod.

Jméno Barva Funkce
L9 žlutá Je připojena na pin 9
LINK zelená Signalizuje připojení k WiFi
ERROR červená Signalizuje problém s komunikací
DATA modrá Signalizuje přenos dat
Rozložení pinů WiFi shieldu

Piny WiFi shieldu

Pokud používáme shield s Arduinem starším než Arduino UNO rev3, musíme propojit 3.3V s IOREF. Starší desky poznáme podle toho, že mají méně konektorů a pin IOREF shieldu zůstane nepřipojen. Pozor ale na to, abychom toto propojení nepoužili s novější deskou.

Propojení IOREF a 3.3V pro starší typy desek Arduino

Propojení pro starší desky

Pro ovládání slouží knihovna WiFi.h. Tu obsahuje Arduino IDE, tudíž ji nemusíme stahovat. Do kódu ji vložíme známým příkazem #include <WiFi.h>. Předtím, než se pustíme do programování shieldu, musíme ověřit, jestli je jeho firmware aktuální.

Zjištění verze firmware

Přestože je poslední verze firmware používaná už dlouhou dobu, může se stát, že narazíme na shield využívající starší verzi. Abychom zajistili správnou funkčnost, je vhodné firmware aktualizovat. Nejdříve ale musíme zjistit, jakou verzi vlastně máme. To provedeme pomocí jednoduchého kódu, který nám po sériové lince vypíše verzi firmware. S funkcemi se zatím zaobírat nemusíme, vše bude vysvětleno později.

#include <SPI.h>
#include <WiFi.h>

void setup() {
    Serial.begin(9600); 
    if (WiFi.status() == WL_NO_SHIELD) {
        Serial.println("WiFi shield je nepřipojen"); 
        while(true); //zacyklí program - ten dále nepokračuje
    } 
    Serial.print("Verze firmware: ");
    Serial.println(WiFi.firmwareVersion());
}

void loop() {}

Poznámka: Uvedený postup je použitelný pro Windows. Návod upgrade pro Mac a Linux naleznete zde.

Pokud verze firmware není 1.1.0 (nebo vyšší), je vhodné provést aktualizaci.

Aktualizace firmware

Před začátkem udpate musíme propojit dva piny, které umožní komunikaci s čipem AT32UC3 – mozkem procesoru. Jsou umístěny vedle microSD slotu. Procesor řídí chod čipu HDG104, který se stará o WiFi. Také bychom měli shield odpojit od Arduina.

Konfigurační piny WiFi shieldu

Konfigurační piny

Firmware obou čipů můžeme nahrát přes USB. K tomu ale budeme potřebovat speciální software, který se jmenuje FLIP. Je to oficiální software od Atmel a dá se stáhnout přímo z jeho stránek. Po stažení vhodné verze spustíme instalaci a bez jakékoliv nutnosti konfigurace jej nainstalujeme. Z Githubu stáhneme nejnovější verzi firmware. Zde nás budou zajímat soubory wifi_dnld.elf a wifiHD.elf, které stáhneme.

Poté spustíme příkazový řádek a přepneme se do složky, kde je nainstalovaný soubor FLIP (většinou C:\Program Files (x86)\Atmel\Flip X.X.X\bin). Pozor! Může být nutné spouštět příkazový řádek s právy správce. V příkazovém řádku se do požadované složky přesuneme pomocí příkazu cd následovaným absolutní adresou, například tedy:

cd C:\Program Files (x86)\Atmel\Flip 3.4.7\bin
Příkazový řádek Windows. Cesta k programu Flip.

Příkazový řádek

Pomocí mini USB připojíme shield k počítači. Ve většině případů nedojde k automatické instalaci ovladačů a my je tedy budeme muset nainstalovat ručně. To provedeme tak, že otevřeme Ovládací panely a v nich s právy administrátora spustíme Správce zařízení. Pokud nedošlo ke správné instalaci driverů uvidíme zde podobnou položku, jaká je na obrázku.

Neznámé zařízení Windows

Neznámé zařízení

Pravým tlačítkem na něj klikneme a vybereme možnost Aktualizovat software ovladače, poté zvolíme Vyhledat ovladač v počítači a v následující nabídce otevřeme složku s nainstalovaným programem FLIP (např. C:\Program Files (x86)\Atmel\Flip X.X.X). Kliknutím na tlačítko další program nalezne potřebné ovladače a nainstaluje je. Nyní už je vše připraveno pro instalaci nového firmware. Postupně nahrajeme oba stažené soubory, oba pomocí příkazu níže. V příkladu jsou oba soubory uložené ve složce C:\Users\uzivatel\Downloads.

batchisp.exe -device AT32UC3A1256 -hardware usb -operation erase f memory flash blankcheck loadbuffer C:\cesta\k\souboru program verify start reset 0

Začneme souborem wifi_dnld.elf.

batchisp.exe -device AT32UC3A1256 -hardware usb -operation erase f memory flash blankcheck loadbuffer C:\Users\uzivatel\Downloads\wifi_dnld.elf program verify start reset 0

Po úspěšném uploadu shield restartujeme, a poté nahrajeme i soubor wifiHD.elf.

batchisp.exe -device AT32UC3A1256 -hardware usb -operation erase f memory flash blankcheck loadbuffer C:\Users\uzivatel\Downloads\wifiHD.elf program verify start reset 0

Tím je proces instalace aktuálního software u konce. Dva konektory, které jsme předtím spojili, teď rozpojíme a odpojíme shield od USB. Aktuální firmware by měl mít verzi 1.1.0 (nebo vyšší).

Údaje potřebné pro připojení k WiFi

Pro připojení k otevřené síti nechráněné heslem stačí vědět její SSID (název).

Pro sítě se zabezpečením WEP je potřeba znát SSID, klíč (key) a index klíče (key index). Klíč je heslo v hexadecimální podobě. Většinou se získává převedením řetězce do hexadecimální reprezentace, nebo přímo zadáním tohoto řetězce (záleží na nastavení WiFi přístupového bodu).

Ukázka nastavení wep klíče

Ukázka nastavení wep klíče

U sítí WPA2 Personal nám stačí SSID a heslo.

Přehled funkcí pro práci s WiFi

V následujícím přehledu si ukážeme funkce a objekty, které jsou potřeba při práci s WiFi shieldem. Některé funkce knihovny WiFi jsou velmi podobné těm, se kterými jsme se setkali při práci s Ethernet shieldem a některé jsou dokonce stejné.

Třída WiFi

Název Zápis Funkce
WiFi.begin() WiFi.begin(ssid);
WiFi.begin(ssid, pass);
WiFi.begin(ssid, keyIndex, key);
Tato funkce spustí komunikaci s WiFi přístupovým bodem. Může mít tyto parametry:SSID – název sítěpass – heslo WPA2 sítěkey – klíč WEP sítě

keyIndex – WEP síť může mít až čtyři klíče pro připojení, tímto jí sdělujete, jaký z těchto čtyř hodláte použítFunkce navíc vrací dvě různé hodnoty odpovídající konstantám:

WL_CONNECTED – když se připojení k síti podařilo

WL_IDLE_STATUS – když se připojení nepodařilo, ale shield funguje

WiFi.disconnect() WiFi.disconnect() Odpojí shield od sítě, ke které je právě připojen.
WiFi.status() WiFi.status(); Zjistí stav shieldu a připojení k síti. Vrací hodnoty odpovídající konstantám:WL_NO_SHIELD – WiFi shield není připojen k ArduinuWL_IDLE_STATUS – Shield je připojen, ale nepodařilo se připojitWL_NO_SSID_AVAIL – SSID není dostupná

WL_SCAN_COMPLETED – Hledání sítí dokončeno

WL_CONNECTED – Připojeno k síti

WL_CONNECT_FAILED – Připojování selhalo

WL_CONNECTION_LOST – Ztráta spojení

WL_DISCONNECTED – Odpojeno

WiFi.config() WiFi.config(ip);
WiFi.config(ip, dns);
WiFi.config(ip, dns, gateway);
WiFi.config(ip, dns, gateway, subnet);
Umožňuje změnu IP adresy, adresu DNS, gateway a subnet. Používejte, pokud víte, co děláte. Parametry funkce: ip, dns, gateway a subnet.
WiFi.setDNS() WiFi.setDNS(dns_server1);
WiFi.setDNS(dns_server1, dns_server2);
Umožňuje nastavení DNS serveru. Funkce má parametry: dns_server1 – primární DNS serverdns_server2 – sekundární DNS serverOpět doporučuji používat jen tehdy, když víte, co nastavujete.
WiFi.scanNetworks() WiFi.scanNetworks(); Vrátí počet nalezených WiFi sítí. Tato funkce musí být volána, mají-li poté být bez problému použity funkce .SSID().
WiFi.SSID() WiFi.SSID();
WiFi.SSID(wifiAccessPoint);
Při volání funkce bez parametru vrátí SSID sítě, ke které je shield aktuálně připojen. Parametr wifiAccessPoint je číslo sítě, které jí bylo přiděleno funkcí .scanNetworks(). V případě volání s parametrem vrátí SSID vybrané sítě.
WiFi.BSSID() WiFi.BSSID(bssid); Funkce vrátí MAC adresu přístupového bodu, ke kterému je shield připojen. Má jediný parametr:bssid – je pole, do kterého se uloží adresa, musí tedy být předem nadefinované a musí mít 6 prvků (byte bssid[6];)
WiFi.RSSI() WiFi.RSSI();
WiFi.RSSI(wifiAccessPoint);
Funkce funguje stejně jako .SSID(), pouze vrací sílu signálů sítě v dBm (decibel-miliwatt).
WiFi.encryptionType() WiFi.encryptionType();
WiFi.encryptionType(wifiAccessPoint);
Stejné jako .SSID(), vrací typ zabezpečení.
WiFi.macAddress() WiFi.macAddress(mac); Vrátí MAC adresu shieldu. Parametr mac funguje stejně jako bssid u funkce .BSSID()
WiFi.getSocket() WiFi.getSocket(); Vrátí první přijatý socket.
WiFi.localIP() WiFi.localIP(); Vrátí aktuální IP adresu shieldu. Vrácená IP je datového typu IPAdress.
WiFi.subnetMask() WiFi.subnetMask(); Vrátí subnet WiFi sítě. Je datového typu IPAdress.
WiFi.gatewayIP() WiFi.gatewayIP(); Vrátí gateway sítě. Vrácená data jsou také datového typu IPAdress.

Třída WiFiServer

Třída, která obsahuje informace o serveru a funkce pro práci s ním.

Název Zápis Funkce
Server() WiFiServer server(port); Vytvoří WiFi server, který naslouchá událostem na zadaném portu.
server.begin() server.begin() Zahájí naslouchání serveru na nastaveném portu.
server.available() server.available(); Vrátí informace o klientovi připojeném k vytvořenému serveru. Vrácená data jsou datového typu WiFiClient.
server.write() server.write(data); Pošle data všem klientům připojeným k serveru. Parametr data může být datového typu byte nebo char.
server.print() server.print(data);
server.print(data, BASE);
Pošle data všem připojeným klientům v podobě ASCII.data – informace k vypsáníBASE – v jaké soustavě se mají vypsat čísla (BIN, DEC, OCT, HEX)
server.println() server.println(data);
server.println(data, BASE);
Stejné jako .print(), pouze na konec přidá zalomení řádku.

Třída WiFiClient

Obsahuje informace o klientovi a funkce pro jeho obsluhu.

Název Zápis Funkce
WiFiClient() WiFiClient client; Vytvoří proměnnou typu WiFiClient sloužící pro obsluhu a práci s klientem.
client.connected() client.connected(); Funkce vrací true, pokud jsou k dispozici nějaká data odeslaná klientem. V opačném případě vrací false.
client.connect() client.connect(ip, port);
client.connect(URL, port);
Připojí se k zadanému serveru. Ten může být zvolen pomocí ip adresy, nebo URL. Parametr port specifikuje port, přes který se k serveru připojujeme. Funkce vrací true/false podle úspěšnosti operace.
client.write() client.write(data); Pošle data serveru, ke kterému je připojen.
client.print() client.print(data);
client.print(data, BASE);
Pošle data serveru jako ASCII.
client.println() client.println(data);
client.print(data, BASE);
Pošle serveru data jako ASCII se zalomením řádku na konci.
client.available() client.available(); Vrátí počet bytů, které jsou dostupné ke čtení ze serveru.
client.read() client.read(); Vrátí následující přijatý byte. Pokud žádný není, vrátí -1.
client.flush() client.flush(); Smaže všechny přijaté byty čekající na přečtení.
client.stop() client.stop(); Odpojí klienta od serveru.

Příklady

Tímto jsme si představili funkce používané pro obsluhu WiFi shieldu. Nyní si můžeme předvést několik ukázek. Ty vycházejí z oficiálních příkladů z dokumentace.

Připojení k síti

Následující příkladu ukazuje, jak se připojit k síti se zabezpečením WEP. Jednoduchou úpravou parametrů u WiFi.begin() se ale dá příklad modifikovat i pro WEP2 síť a také síť bez zabezpečení.

#include <WiFi.h>

char ssid[] = "SSID_site";      	//SSID sítě
char key[] = "klic_site";       	//klíč sítě
int keyIndex = 0;         			//číslo klíče
int status = WL_IDLE_STATUS;		//pomocná proměnná uchovávající stav připojení

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

    //zkontroluje, jestli je shield připojen 
    if (WiFi.status() == WL_NO_SHIELD) {
        Serial.println("WiFi shield neni pripojen"); 
        while(true); //zacyklí program, nic se nebude dít dál
    } 

    //pripoji se k síti
    while ( status != WL_CONNECTED) { 
        Serial.print("Pripojuji se k SSID: ");
        Serial.println(ssid);
        status = WiFi.begin(ssid, keyIndex, key);
        delay(10000);
    }

    Serial.print("Jste pripojen");
    printCurrentNet();
    printWifiData();
}

void loop(){
    //každých 10 sekund zkontrolujeme WiFi síť
    delay(10000);
    printCurrentNet();
}

void printWifiData() {
    //funkce pro výpis IP a MAC shieldu
    IPAddress ip = WiFi.localIP();
    Serial.print("IP adresa: ");
    Serial.println(ip);
    Serial.println(ip);

    byte mac[6];  
    WiFi.macAddress(mac);
    Serial.print("MAC adresa: ");
    Serial.print(mac[5],HEX);
    Serial.print(":");
    Serial.print(mac[4],HEX);
    Serial.print(":");
    Serial.print(mac[3],HEX);
    Serial.print(":");
    Serial.print(mac[2],HEX);
    Serial.print(":");
    Serial.print(mac[1],HEX);
    Serial.print(":");
   Serial.println(mac[0],HEX);
}

void printCurrentNet() {
    //odešle SSID sítě
    Serial.print("SSID: ");
    Serial.println(WiFi.SSID());

    //odešle MAC adresu přístupového bodu
    byte bssid[6];
    WiFi.BSSID(bssid);    
    Serial.print("BSSID: ");
    Serial.print(bssid[5],HEX);
    Serial.print(":");
    Serial.print(bssid[4],HEX);
    Serial.print(":");
    Serial.print(bssid[3],HEX);
    Serial.print(":");
    Serial.print(bssid[2],HEX);
    Serial.print(":");
    Serial.print(bssid[1],HEX);
    Serial.print(":");
    Serial.println(bssid[0],HEX);

    //odešle sílu signálu
    long rssi = WiFi.RSSI();
    Serial.print("Sila signalu:");
    Serial.println(rssi);

    //odešle typ zabezpečení
    byte encryption = WiFi.encryptionType();
    Serial.print("Typ zabezpeceni:");
    Serial.println(encryption,HEX);
    Serial.println();
}

Interakce se serverem

Pomocí dvou odkazů (zapni a vypni) budeme ovládat LED diodu připojenou na pin 9. Pomocí sériové linky nám Arduino vypíše, na jakou IP adresu se máme připojit. V příkladu se používá HTTP request. Práci s ním jsme si popsali v příkladu s Ethernet shieldem.

#include <SPI.h>
#include <WiFi.h>

char ssid[] = "SSID_site";  
char pass[] = "heslo_site";    

int status = WL_IDLE_STATUS;
WiFiServer server(80);

void setup() {
    Serial.begin(9600);  
    pinMode(9, OUTPUT);  

    if (WiFi.status() == WL_NO_SHIELD) {
        Serial.println("Shield nepripojen"); 
        while(true); 
    } 

    while ( status != WL_CONNECTED) { 
        Serial.print("Pripojuji k SSID: ");
        Serial.println(ssid);

        status = WiFi.begin(ssid, pass);
        delay(10000);
    } 
    server.begin();    
    printWifiStatus();    
}

void loop() {
	//čeká na připojení klienta
    WiFiClient client = server.available(); 

    if(client){  //když naleznem klienta
        String currentLine = "";         
        while (client.connected()){       
            if (client.available()){    
                char c = client.read();        
                Serial.write(c);     
				//pokud najde znak zalomení řádku (ukončuje request od klienta)
                if (c == '\n'){                 
                    if (currentLine.length() == 0) {   
                        client.println("HTTP/1.1 200 OK");
                        client.println("Content-type:text/html");
                        client.println();             
						//hlavička je oddělena znakem nového řádku 
  
                        //zde začíná HTML kód stránky
                        client.print("<a href=\"/H\">ZAPNI</a><br>");
                        client.print("<a href=\"/L\">VYPNI</a><br>");
  
                        client.println(); //dalším prázdným řádkem končí HTML část
                        break;         
                    } 
                    else{
                        currentLine = "";
                    }
                }     
		else if (c != '\r') {    
		    currentLine += c;
		}

		//kontroluje, jestli request končí na H, nebo L
		if (currentLine.endsWith("GET /H")) {
		    digitalWrite(9, HIGH);            //zapne LED
		}
		if (currentLine.endsWith("GET /L")) {
		    digitalWrite(9, LOW);             //vypne LED
		}
	    }
	}
        client.stop();
        Serial.println("client disonnected");
    }
}

void printWifiStatus() {
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());

  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);

  long rssi = WiFi.RSSI();
  Serial.print("signal strength (RSSI):");
  Serial.print(rssi);
  Serial.println(" dBm");
  
  Serial.print("http://");
  Serial.println(ip);
}

Tyto základní příklady, společně se znalostmi zmíněnými ve článku o Ethernet shieldu, slouží jako odrazový můstek pro další tvorbu.

Zdroje obrázků

[Obr. 1: Piny shieldu]

[Obr. 2: Propojení pro starší desky]

[Obr. 3: Konfigurační piny]

V případě jakýchkoliv dotazů či nejasností se na mě neváhejte obrátit v komentářích.

Zbyšek Voda

One Comment on “Arduino a WiFi shield

Tomáš Jurman
22.8.2015 at 21:26

Díky za super tutoriál. Těším se, jak vyzkouším.

Napsat komentář