Exemples | Referència | Plaques | Recursos CITCEA | |
Projectes | Programació | Perifèrics | Inici |
En aquest cas tindrem el nostre microcontrolador actuant com un punt d'accés a la xarxa. Qualsevol dispositiu Wi-Fi veurà el nostre microcontrolador a la llista de xarxes Wi-Fi disponibles i, si sap la contrasenya, s'hi podrà connectar.Un cop connectat al punt d'accés, l'usuari podrà posar l'adreça IP corresponent a la placa i rebrà una pàgina web amb la que podrà encendre i apagar un LED connectat a la pota 7, tal com mostra la figura següent:
Si no teniu cap LED disponible podeu emprar el LED de la placa, que està a la pota 6.
La pàgina que veurà l'usuari tindrà el següent contingut (vegeu les etiquetes del llenguatge html).
<!DOCTYPE HTML> <meta charset='UTF-8'> <html> <h1>El LED està apagat</h1> <p></p> <button type='button' onClick=location.href='/?LED=1'>Encén</button> <p></p> <button type='button' onClick=location.href='/?LED=0'>Apaga</button> </html>
Que ens donarà una pàgina similar a aquesta:
El programa configura el punt d'accés i espera que algun usuari s'hi connecti. Quan ho fa li envia la pàgina html en la que l'estat del LED es personalitza segons com estigui en aquell moment. Quan es prem un botó es torna a carregar la pàgina afegint el paràmetre corresponent. A continuació hi ha les tres versions possibles de l'adreça: consulta, encendre i apagar (vegeu les comandes http). Podeu consultar també les funcions de la biblioteca WiFiNINA que fem servir.
192.168.4.1/ 192.168.4.1/?LED=0 192.168.4.1/?LED=1
El programa que fem servir per provar-ho és el següent:
// Aquest programa està parcialment basat en els exemples de la pàgina // https://www.arduino.cc/en/Tutorial/LibraryExamples#wifi1010 #include <SPI.h> // Carreguem la biblioteca SPI #include <WiFiNINA.h> // Carreguem la biblioteca WiFiNINA #define LED 7 // pota on hem connectat el LED
const char idXarxa[] = "acces-ESP32"; // Nom del punt d'accés const char contrasenya[] = "etseib00"; // Contrasenya de connexió bool estat = LOW; // Variable que recorda l'estat del LED bool enviar = false; int status = WL_IDLE_STATUS; // Estat de la connexió WiFiServer server(80); // Creem un objecte de comunicació amb el port 80 // El port 80 és el de defecte per a http
void setup() { // Inicialització Serial.begin(9600); // Monitor sèrie while (!Serial) { ; // Esperem que estigui connectat } // Aquest while s'ha de suprimir a la versió definitiva pinMode(LED, OUTPUT); // La pota del LED és sortida digitalWrite(LED, LOW); // Comencem amb el LED apagat if (WiFi.status() == WL_NO_MODULE) { Serial.println("No s'ha trobat el dispositiu Wi-Fi"); while (true); // Bloquegem el programa } Serial.print("Creant el punt d'accés: "); Serial.println(idXarxa); status = WiFi.beginAP(idXarxa, contrasenya); if (status != WL_AP_LISTENING) { Serial.println("No s'ha pogut crear el punt d'accés"); while (true); // Bloquegem el programa } delay(10000); // Esperem deu segons server.begin(); // Posem en marxa el servidor Serial.print("SSID de la xarxa: "); Serial.println(WiFi.SSID()); IPAddress ip = WiFi.localIP(); Serial.print("Adreça IP: "); Serial.println(ip); Serial.print("Posa l'adreça http://"); Serial.print(ip); Serial.println("/ al teu navegador"); }
void loop() { // Programa que es repeteix indefinidament if (status != WiFi.status()) { // Mirem si ha canviat l'estat de la connexió status = WiFi.status(); if (status == WL_AP_CONNECTED) { Serial.println("Dispositiu connectat al punt d'accés"); } else { Serial.println("El dispositiu s'ha desconnectat del punt d'accés"); } } WiFiClient client = server.available(); // Mirem si hi ha clients if (client) { // Si hi ha un client... Serial.println("Nou client"); String peticio = ""; // Aquí guardarem una línia de la petició del client while (client.connected()) { // Mentre el client estigui connectat if (client.available()) { // Si hi ha dades disponibles char c = client.read(); // Llegim un byte Serial.write(c); if (c == '\n') { // Mirem si és un salt de línia // Si hem rebut una línia buida vol dir que tenim dos salts de línia seguits // vol dir que ha acabat la petició del client i enviem la resposta: if (peticio.length() == 0) { enviar = true; // Llestos per enviar la resposta break; // Sortim del while } else { // Si hem rebut un salt de línia // Ha acabat una línia de la petició, anem a veure si és la que ens interessa // Rebrem un munt de línies però només hem d'analitzar la que comença per GET if (peticio.indexOf("GET") != -1) { // Si no ho troba torna -1 // Ara cal comprovar si s'ha demanat una acció sobre el LED if (peticio.indexOf("LED=1") != -1) { // Si no ho troba torna -1 estat = HIGH; // Si ho troba encendrem el LED digitalWrite(LED, estat); // Enviem el nou estat al LED } if (peticio.indexOf("LED=0") != -1){ estat = LOW; // Si ho troba apagarem el LED digitalWrite(LED, estat); // Enviem el nou estat al LED } } peticio = ""; // Comencem línia amb una línia buida } } else if (c != '\r') { // Si el caràcter no és un retorn peticio += c; // Afegim el caràcter rebut } } } if (enviar) { // Resposta al client client.println("HTTP/1.1 200 OK"); client.println(); // Imprescindible línia en blanc client.println("<!DOCTYPE HTML>"); client.println("<meta charset='UTF-8'>"); client.println("<html>"); // En el títol l'estat del LED client.print("<h1>El LED està "); if(estat == HIGH) { client.print("encès"); } else { client.print("apagat"); } client.println("</h1>"); // Botons per canviar l'estat del LED client.println("<p></p>"); client.println("<p></p>"); client.println("<button type='button' onClick=location.href='/?LED=1'>Encén</button>"); client.println("<p></p>"); client.println("<p></p>"); client.println("<button type='button' onClick=location.href='/?LED=0'>Apaga</button>"); client.println("</html>"); delay(1); enviar = false; } client.stop(); // Tanquem la connexió Serial.println("Fi de la connexió amb el client"); } }
En aquest programa hi ha la condició que el monitor sèrie estigui obert per a que el programa comenci a funcionar. Això ens permet seguir tot el procés encara que triguem a obrir el monitor sèrie. Quan el microcontrolador hagi de funcionar de manera independent de l'ordinador caldrà eliminar les línies següents per evitar aquest bloqueig.
while (!Serial) { ; // Esperem que l'usuari obri el monitor sèrie }
Per provar-ho, podem agafar un dispositiu mòbil i cercar les xarxes Wi-Fi. Ens hem de connectar a la xarxa acces-ESP32. Probablement ens avisarà que la xarxa no ens dóna connexió a internet. Si fem servir habitualment el Wi-Fi pot passar que es torni a connectar a la nostra xarxa habitual (i, per tant, no ens poguem connectar al microcontrolador). Per tant, serà convenient desactivar l'opció de tornar-se a connectar automàticament a la nostra xarxa habitual. Un cop connectats a la xarxa acces-ESP8266 podem obrir un navegador i demanar-li la pàgina 192.168.4.1. Llavors ens hauria de mostrar la pàgina que em vist més amunt i picant els botons podem encendre i apagar el LED.
En aquest exemple hem posat un botó per encendre i un altre per apagar. També podíem haver posat un únic botó que segons l'estat del LED ens permetés passar-lo a l'estat contrari. Això es pot fer que l'acció del botó i el text que porta escrit siguin diferents segons l'estat del LED.
El nostre programa de prova escriu unes quantes coses al monitor sèrie (instruccions Serial.print i Serial.println). Quan ja tinguem clar que el programa funciona, les podem eliminar i probablement anirà una mica més ràpid.
Si ens fixem en el que s'escriu al monitor sèrie, veurem que una petició típica pot ser la següent:
GET /?LED=1 HTTP/1.1 Host: 192.168.4.1 Connection: keep-alive Upgrade-Insecure-Requests: 1 Save-Data: on User-Agent: Mozilla/5.0 (Linux; Android 8.0.0; SM-J330F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8 Referer: http://192.168.4.1/?LED=0 Accept-Encoding: gzip, deflate Accept-Language: ca-ES,ca;q=0.9 GET /favicon.ico HTTP/1.1 Host: 192.168.4.1 Connection: keep-alive User-Agent: Mozilla/5.0 (Linux; Android 8.0.0; SM-J330F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36 Save-Data: on Accept: image/webp,image/apng,image/*,*/*;q=0.8 Referer: http://192.168.4.1/?LED=1 Accept-Encoding: gzip, deflate Accept-Language: ca-ES,ca;q=0.9
I aquí veiem unes quantes coses que hem de tenir en compte. La primera és que quan l'usuari fa la petició d'una pàgina resulta que molts navegadors fan dues peticions. La primera és la petició de l'usuari i la segona és la descàrrega de la imatge que actua com a icona del lloc web (favicon.ico). En principi, aquesta segona petició no ens interessa.
A més, en la pròpia petició tenim dues vegades el text que ens interessa (LED=) una quan ens indica la petició de l'usuari
GET /?LED=1 HTTP/1.1
i una altra on ens diu quin enllaç ha picat l'usuari per arribar a aquesta petició.
Referer: http://192.168.4.1/?LED=0
Només ens interessa la primera, la que comença per GET, per això hem comprovat si hi començava abans de processar la línia.
Aquesta obra d'Oriol Boix està llicenciada sota una llicència no importada Reconeixement-NoComercial-SenseObraDerivada 3.0.