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 |
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.
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.
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
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.
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).
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. 2: Propojení pro starší desky]
V případě jakýchkoliv dotazů či nejasností se na mě neváhejte obrátit v komentářích.