Desde el punto de vista del software, establecer una conexión Ethernet con Arduino es muy sencillo. Para hacerlo se utiliza la librería Ethernet. Esta librería está diseñada para una Ethernet Shield que está basada en el integrado W5100, pero existen otras placas o módulos diferentes y/o que utilizan otros integrados, como el ENC28J60. Para simplificar su uso y aumentar la compatibilidad, otras librerías utilizan (casi) la misma API que la librería Ethernet, sólo habrá que sustituir la librería alternativa por la original o incluirla (cuando el nombre sea diferente) en su lugar aunque en el código se usen las mismas (o muy parecidas) funciones. En mi caso, utilizo la librería UIPEthernet de Norbert Truchsess siguiendo el mismo proceso que voy a describir en este texto.
1. Definir la conexión Ethernet
Tanto si se va a adoptar el papel de cliente como el de servidor, en primer lugar hay que definir la conexión con la función begin() a la que se le puede pasar como parámetro sólo la dirección MAC y esperar que un servidor DHCP en la red le asigne una dirección IP y el resto de la configuración o también es posible indicar (opcionalmente) más parámetros hasta definir la configuración completa:
- Dirección MAC (la que ya se ha citado)
- Dirección IP del shield o módulo
- Dirección IP del servidor DNS (sólo un servidor)
- Dirección IP de la puerta de enlace
- Máscara de red
Es recomendable indicar todos los parámetros, salvo que su deducción sea la habitual, para evitar que la configuración no sea correcto (por ejemplo, que la pasarela no sea la primera dirección de la red)
De lo anterior parece que queda claro que hay que usar bastantes veces datos que representen direcciones IP, por eso la librería incluye la clase IPAddress de la que instanciar objetos dirección IP. Los parámetros que la definen son los cuatro bytes de una dirección IPV4
La dirección MAC se define para esta librería como una matriz de 6 bytes. La dirección MAC es (se supone que es) un identificador único en el que los primeros bytes indican el fabricante y el modelo y los últimos al dispositivo en concreto. El integrado ENC28J60 no incluye una dirección MAC salvo que se opte por comprar además un integrado de dirección MAC de Microchip (o todo un bloque OUI de direcciones al IEEE si la tirada de dispositivos es lo bastante grande como para que merezca la pena). Cuando no se dispone de una dirección MAC se puede inventar una cuidando que no entre en conflicto con otras en la red en la que se encuentre el dispositivo.
Si la configuración se realiza con un servidor DHCP en lugar de «a mano», la función localIP() es útil para consultar la dirección que el servidor le ha asignado al módulo. Para renovar la dirección asignada (si el tiempo correspondiente hubiera expirado) la librería Ethernet proporciona la función maintain() que además informará devolviendo un código que corresponde con el estado de la renovación:
- La operación no ha tenido ningún efecto
-
Error al renovar (renew) la dirección IP
No se ha podido prolongar el uso de la dirección IP asignada en el mismo servidor - Dirección IP renovada correctamente
-
Error al reasignar (rebind) la dirección IP
No se ha podido prolongar el uso de la dirección IP asignada en ningún servidor - Dirección IP reasignada correctamente
Con la información vista hasta ahora ya se puede escribir un ejemplo de cómo se iniciaría una conexión Ethernet configurando la dirección IP por medio de un servidor DHCP en la red. En el siguiente código de ejemplo se trata de renovar la dirección IP cada cierto periodo de tiempo y se informa del resultado.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
//#include <UIPEthernet.h> // Librería Ethernet que usaré después con el módulo ENC28J60 #include <Ethernet.h> // Librería Ethernet estándar #define ESPERA_RENOVACION_IP 60000 // Un minuto unsigned long reloj; byte direccion_mac[]={0x12,0x34,0x56,0x78,0x9a,0xbc}; // Dirección MAC inventada byte estado_DHCP; void setup() { Serial.begin(9600); Ethernet.begin(direccion_mac); mostrar_direccion_ip(); reloj=millis()+ESPERA_RENOVACION_IP; } void loop() { if(millis()>reloj) // Tratar de renovar la IP cada ESPERA_RENOVACION_IP milisegundos { estado_DHCP=Ethernet.maintain(); switch(estado_DHCP) { case 0: Serial.println("Sin cambios"); break; case 1: Serial.println("Error al renovar la dirección IP"); break; case 2: Serial.println("Dirección IP renovada correctamente"); break; case 3: Serial.println("Error al reasignar la dirección IP"); break; case 4: Serial.println("Dirección IP reasignada correctamente"); break; default: Serial.println("Error desconocido"); } mostrar_direccion_ip(); reloj=millis()+ESPERA_RENOVACION_IP; } } void mostrar_direccion_ip() { Serial.print("Dirección IP actual ["); Serial.print(Ethernet.localIP()); // Mostrará la dirección IP asignada por el servidor DHCP Serial.println("]"); } |
En el ejemplo de abajo se asigna la dirección IP y el resto de la configuración manualmente utilizando objetos IPAddress para que resulte más cómodo leerlo y (en caso de código más complejo) evitar los errores que se podrían producir si se escribiera (mal) la dirección en cada uso.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
#include <UIPEthernet.h> // Librería Ethernet usada con el módulo ENC28J60 // #include <Ethernet.h> // Librería Ethernet estándar byte direccion_mac[]={0x12,0x34,0x56,0x78,0x9a,0xbc}; // Dirección MAC inventada IPAddress direccion_ip_fija(192,168,1,69); // Dirección IP elegida para el módulo IPAddress servidor_dns(87,216,170,85); // Servidor DNS OpenNIC (de Alejandro Bonet, http://opennic.alargador.org) IPAddress puerta_enlace(192,168,1,14); // Dirección IP del router IPAddress mascara_red(255,255,255,0); // Máscara de la red void setup() { Serial.begin(9600); while(!Serial){;} // He usado una placa Leonardo, me toca esperar a que el puerto serie esté operativo Ethernet.begin(direccion_mac,direccion_ip_fija,servidor_dns,puerta_enlace,mascara_red); Serial.print("Dirección IP asignada ["); Serial.print(Ethernet.localIP()); // Poco misterio, devolverá la dirección IP asignada manualmente Serial.println("]"); } void loop() { // Sólo es un ejemplo de configuración, no hace nada } |
2. Iniciar la conexión en modo cliente o servidor
Al iniciar una conexión en modo servidor, es el sistema microcontrolado que se está desarrollando el que queda a la escucha de las peticiones de otros sistemas. Para iniciar la conexión como servidor se utiliza EthernetServer() y se indica como parámetro el puerto en el que el servidor escuchará. EthernetServer() es el constructor de la clase Server, que soporta todas las operaciones Ethernet como servidor. Aunque lo más ortodoxo es realizar una llamada al constructor EthernetServer(), no es raro encontrar algunos ejemplos que usan directamente la clase Server o librerías alternativas para conexión Ethernet que eligen usar ese sistema de instanciado.
La conexuión como cliente es la que realiza las peticiones al sistema servidor que es el que las espera y las contesta según corresponda. Para inicar una conexión como cliente se utiliza EthernetClient() que es el constructor de la clase Client origen de todas las operaciones Ethernet como cliente.
A diferencia de lo que ocurre con el modo servidor, que se supone funcionando desde que se instancia la clase (aunque responderá a los clientes sólo si lo está realmente), se debe verificar que la conexión cliente está preparada antes de utilizarla. El objeto cliente que se crea al iniciar la conexión puede consultarse para verificar si está disponible. Por ejemplo, las operaciones de consulta pueden incluirse en una estructura if(EthernetClient) para ejecutarlas sólo cuando la conexión cliente esté disponible.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
#include <UIPEthernet.h> // Librería Ethernet usada con el módulo ENC28J60 // #include <Ethernet.h> // Librería Ethernet estándar byte direccion_mac[]={0x12,0x34,0x56,0x78,0x9a,0xbc}; // Dirección MAC inventada IPAddress direccion_ip_fija(192,168,1,69); // Dirección IP elegida para el módulo IPAddress servidor_dns(87,216,170,85); // Servidor OpenNIC (de Alejandro Bonet, http://opennic.alargador.org) IPAddress puerta_enlace(192,168,1,14); // Dirección IP del router IPAddress mascara_red(255,255,255,0); // Máscara de la red EthernetServer servidor=EthernetServer(80); // Puerto 80 (típico de un servidor HTTP) void setup() { Serial.begin(9600); while(!Serial){;} // He usado una placa Leonardo, hay que esperar a que el puerto serie esté operativo Ethernet.begin(direccion_mac,direccion_ip_fija,servidor_dns,puerta_enlace,mascara_red); servidor.begin(); Serial.println("Servidor HTTP iniciado"); } void loop() { // Sólo es un ejemplo de configuración, no hace nada productivo } |
3. Establecer una conexión como cliente
Como se ha dicho, una vez creada la conexión, es el cliente el que toma la iniciativa de realizar las consultas. El servidor estará esperando esa iniciativa y responderá como proceda. Es, por tanto, el cliente el que conecta al servidor, para hacerlo se utiliza connect() indicando como parámetros el servidor (la dirección IP o la URL) y el puerto en el que escucha.
Según el resultado de la operación, la función devolverá los valores
- ( ) Conexión establecida correctamente
- Estableciendo la conexión
- ( ) Ha pasado el tiempo de espera sin que se establezca la conexión
- ( ) No se ha encontrado el servidor o no responde correctamente
- ( ) La conexión se ha cortado antes de establecerse completamente
- ( ) La respuesta del servidor es incorrecta
Antes de empezar a realizar consultas es necesario verificar que la conexión está operativa con la función connected() que devolverá si ya está disponible o en caso contrario.
El ejemplo de abajo ilustra la conexión como cliente verificando cada 10 segundos si existe conexión con el servidor (no pretende ser nada productivo, sólo mostrar la sintaxis de las funciones) algo que, por cierto, no gustaría mucho a un servidor web en producción.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
#include <UIPEthernet.h> // Librería Ethernet usada con el módulo ENC28J60 // #include <Ethernet.h> // Librería Ethernet estándar #define INTERVALO_CONSULTA 10000 // Se comprueba cada 10 segundos si hay conexión #define LED_CONEXION 13 // Pin del LED que parpadea cuando hay conexión #define TIEMPO_PARPADEO 300 // Milisegundos entre encendido/apagado del LED que indica conexión byte direccion_mac[]={0x12,0x34,0x56,0x78,0x9a,0xbc}; // Dirección MAC inventada IPAddress direccion_ip_fija(192,168,1,69); // Dirección IP elegida para el módulo IPAddress servidor_dns(87,216,170,85); // Servidor OpenNIC (de Alejandro Bonet, http://opennic.alargador.org) IPAddress puerta_enlace(192,168,1,14); // Dirección IP del router IPAddress mascara_red(255,255,255,0); // Máscara de la red IPAddress ip_servidor_web(192,168,1,21); // Dirección IP del servidor web (en la intranet) //char url_servidor_web[]="sleepmanager.onironauta.es"; // URL poético para un gestor de sueño (en Internet) EthernetClient cliente=EthernetClient(); byte estado_conexion; boolean anteriormente_conectado; boolean estado_led_conexion; unsigned long cronometro_parpadeo; unsigned long cronometro_consulta; void conectar_ethernet() { estado_conexion=cliente.connect(ip_servidor_web,80); // Conexión desde la intranet //estado_conexion=cliente.connect(url_servidor_web,80); // Conexión desde Internet delay(100); // Un pequeño retraso para permitir que se active la conexión anteriormente_conectado=false; switch(estado_conexion) { case 1: Serial.println("Conexión con el servidor SleepManager establecida correctamente"); anteriormente_conectado=true; break; case -1: Serial.println("Ha pasado el tiempo de espera sin que se establezca la conexión"); break; case -2: Serial.println("No se ha encontrado el servidor o no responde correctamente"); break; case -3: Serial.println("La conexión se ha interrumpido antes de establecerse completamente"); break; case -4: Serial.println("La respuesta del servidor es incorrecta"); break; } } void setup() { pinMode(LED_CONEXION,OUTPUT); Serial.begin(9600); while(!Serial){;} // Esperar al puerto serie de la placa Leonardo Serial.println("Conectando con el servidor SleepManager..."); Ethernet.begin(direccion_mac,direccion_ip_fija,servidor_dns,puerta_enlace,mascara_red); conectar_ethernet(); estado_led_conexion=false; cronometro_parpadeo=0; cronometro_consulta=millis()+INTERVALO_CONSULTA; } void loop() { if(anteriormente_conectado&&millis()>cronometro_parpadeo) { estado_led_conexion=!estado_led_conexion; digitalWrite(LED_CONEXION,estado_led_conexion); cronometro_parpadeo=millis()+TIEMPO_PARPADEO; } if(millis()>cronometro_consulta) { if(!cliente.connected()) { conectar_ethernet(); } cronometro_consulta=millis()+INTERVALO_CONSULTA; } } |
4. Enviar datos
Igual que otras clases más conocidas, como ocurre con Serial, y con un uso equiparable, las clases Client y Server disponen de las funciones
-
Envía información usando el objeto cliente o servidor desde el que se invoque. El parámetro «dato» es un único byte o char mientras que «buffer» es una matriz de byte o char de la que se envía una cantidad igual a «longitud» Esta función es la que se utiliza para las operaciones binarias, frente a las dos siguientes que suelen reservarse para enviar texto.
-
Envía como cliente o servidor (según la clase desde la que se use) la información correspondiente a «dato» como texto. Si la información no está expresada como texto (por ejemplo es un número entero) puede utilizarse el parámetro opcional «base» con el que elegir la de la conversión que podrá ser una de las constantes BIN, OCT, DEC o HEX que indican, respectivamente las bases correspondientes a binario (base 2), octal (base 8), decimal (base 10) y hexadecimal (base 16)
-
El funcionamiento es idéntico a la anterior excepto por enviar, después de la información indicada expresamente por el parámetro «dato», un retorno de carro (el código 13 que se puede representar como \r) y un final de línea (el código 10, que se puede representar por \n) Frecuentemente se hace referencia a estos códigos, respectivamente, por las siglas CR (Carriage Return) y LF (Line Feed)
Las tres funciones anteriores devuelven el número de bytes que se han enviado, como ocurre también con las funciones equivalentes de la clase Serial; como se dijo arriba, el funcionamiento es equiparable.
5. Recibir datos
Igual que en el caso de las operaciones de envío de datos, las de recepción son equiparables a las de la ampliamente usada Serial. El protocolo de recepción también es similar: verificar si hay (suficientes) datos disponibles (available) y en tal caso leerlos
-
Devuelve el número de bytes que hay disponibles para ser leídos. Esta función está presente tanto en la clases Client como Server; en el primer caso informa del número de bytes que ha enviado el servidor en respuesta a una petición y que está disponible para que el cliente la lea (read), y en el segundo caso el (objeto) cliente que ha realizado una operación o false en caso de que no haya ninguno.
-
Sirve para leer la información que se ha recibido. Esta función sólo está disponible en la clase Client. Si la aplicación que se está desarollando cumple con el papel de servidor, para leer la información que ha llegado debe instanciarse un objeto cliente con la respuesta de la función available() comentada en el anterior apartado.
El siguiente ejemplo es un «servidor de mayúsculas» que escucha en el puerto 2000 y responde a las peticiones con lo que se haya enviado pasado a mayúsculas cuando sea posible. Puede probarse, por ejemplo con PuTTY o simplemente con Ciertamente no es algo muy práctico, su finalidad sólo es mostrar cómo obtener en el servidor los datos enviados al mismo por un cliente.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
#include <UIPEthernet.h> // Librería Ethernet usada con el módulo ENC28J60 //#include <Ethernet.h> // Librería Ethernet estándar byte direccion_mac[]={0x12,0x34,0x56,0x78,0x9a,0xbc}; // Dirección MAC inventada IPAddress direccion_ip_fija(192,168,1,69); // Dirección IP elegida para el módulo IPAddress servidor_dns(87,216,170,85); // Servidor OpenNIC (de Alejandro Bonet, http://opennic.alargador.org) IPAddress puerta_enlace(192,168,1,14); // Dirección IP del router IPAddress mascara_red(255,255,255,0); // Máscara de la red EthernetServer servidor=EthernetServer(2000); EthernetClient cliente; char texto_recibido; // Sólo para que se más fácil leer el programa usando varias líneas de código void setup() { Serial.begin(9600); while(!Serial){;} // Esperar al puerto serie de la placa Leonardo esté operativo Ethernet.begin(direccion_mac,direccion_ip_fija,servidor_dns,puerta_enlace,mascara_red); Serial.println("Iniciando el servidor de mayúsculas"); servidor.begin(); } void loop() { cliente=servidor.available(); // Si hay disponible alguna petición de un cliente leerla y devolverla en mayúsculas if(cliente) { texto_recibido=cliente.read(); if(texto_recibido>96&&texto_recibido<123) // Si se recibe una letra minúscula... { texto_recibido-=32; // ...convertirla a mayúsculas } // Si se tiene la seguridad de recibir texto se puede usar print en lugar de write servidor.write(texto_recibido); // Responder con lo recibido pasado a mayúsculas si procede } } |
6. Finalizar la conexión
Mientras que lo habitual es que una aplicación servidor funcione indefinidamente, las conexiones cliente se establece, realizan conexiones y terminan, lo que permite recuperar recursos y emplearlos en otras conexiones o dedicarlos a otros usos del programa. La función stop() de la clase Client se utiliza para terminar una conexión cliente y liberar los recursos que esté utilizando.
De cara al servidor, que el cliente termine la conexión cuando se ha enviado o recibido la información objeto de la consulta también le permite liberar recursos para destinarlos a otras conexiones o distintos fines. En definitiva, aunque parece algo menor, es conveniente terminar la conexión al terminar las operaciones del cliente.
Otra buena práctica al terminar una conexión cliente es vaciar el que utiliza la clase. Para hacerlo se dispone de la función flush() a la debería llamarse después de terminar la conexión cliente con stop()
Ejemplo de consulta HTTP GET
Para aclarar mejor todo lo anterior a continuación se incluye un ejemplo más completo de peticiones TCP usando el peticiones GET usando el protocolo HTTP. En el ejemplo se envían los los valores obtenidos por unos sensores analógicos conectados a una placa Arduino a un servidor web que los almacena en una base de datos.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
#include <UIPEthernet.h> // Librería Ethernet usada con el módulo ENC28J60 // #include <Ethernet.h> // Librería Ethernet estándar #define INTERVALO_CONSULTA 60000 // Enviar datos cada minuto #define INTERVALO_RECONEXION 10000 // Reintentar la conexión 10 segundos más tarde si no ha sido posible hacerlo cuado correspondía #define CANTIDAD_SENSORES 6 // Número de sensores analógicos empezando en A0 byte direccion_mac[]={0x12,0x34,0x56,0x78,0x9a,0xbc}; // Dirección MAC inventada IPAddress direccion_ip_fija(192,168,1,69); // Dirección IP elegida para el módulo IPAddress servidor_dns(87,216,170,85); // Servidor OpenNIC (de Alejandro Bonet, http://opennic.alargador.org) IPAddress puerta_enlace(192,168,1,14); // Dirección IP del router IPAddress mascara_red(255,255,255,0); // Máscara de la red //IPAddress ip_servidor_web(192,168,1,21); // Dirección IP del servidor web (en la intranet) char url_servidor_web[]="sleepmanager.onironauta.es"; // URL poético para un gestor de sueño (en Internet) EthernetClient cliente; byte estado_conexion; String texto_consulta; unsigned long cronometro_consulta; byte contador; void setup() { Serial.begin(9600); while(!Serial){;} // Esperar al puerto serie de la placa Leonardo Serial.println("Conectando con el servidor SleepManager..."); Ethernet.begin(direccion_mac,direccion_ip_fija,servidor_dns,puerta_enlace,mascara_red); cronometro_consulta=millis()+INTERVALO_CONSULTA; } void loop() { if(millis()>cronometro_consulta) { //estado_conexion=cliente.connect(ip_servidor_web,80); // Conexión desde la intranet estado_conexion=cliente.connect(url_servidor_web,80); // Conexión desde Internet while(estado_conexion==0) // esperar a que se establezca la conexión o se produzca un error { switch(estado_conexion) { case 1: Serial.println("Conexión con el servidor SleepManager establecida correctamente"); break; case -1: Serial.println("Ha pasado el tiempo de espera sin que se establezca la conexión"); break; case -2: Serial.println("No se ha encontrado el servidor o no responde correctamente"); break; case -3: Serial.println("La conexión se ha interrumpido antes de establecerse completamente"); break; case -4: Serial.println("La respuesta del servidor es incorrecta"); break; } } if(cliente.connected()) // Si ha sido posible conectar realizar la consulta { cronometro_consulta=millis()+INTERVALO_CONSULTA; texto_consulta="GET /pruebas/guardar_sensores_analogicos.php?origen=SleepManager"; for(contador=0;contador<CANTIDAD_SENSORES;contador++) { texto_consulta="&sensor_"+String(contador+1,DEC)+"="+String(analogRead(contador),DEC); delay(1); // Como tarda 100 μs en obtener el valor analógico, con 1 ms seguro le da tiempo } texto_consulta+=" HTTP/1.1\r\nHost: "+String(url_servidor_web)+"\r\nUser-Agent: sleep_inspector\r\n\r\n"; cliente.print(texto_consulta); cliente.flush(); cliente.stop(); } else // Si no ha sido posible conectar reintentarlo más tarde pero no tanto como si hubiera sido posible hacerlo { cronometro_consulta=millis()+INTERVALO_RECONEXION; } } } |
Marcelo Fabian
muy bien explicado todo, compartir siempre suma
Daniel
Muy buen trabajo, te felicito. Gracias por la información, saludos desde Argentina.
Gregorio
Enhorabuena Víctor, por tu claridad en la exposición. Muy buena, gracias.
Víctor Ventura
¡Gracias a ti, Gregorio, por visitar la web!
Rodrigo Andrés
Gracias victor por tu aporte, no sabes cuanto necesitaba de esta información.
Galileo
Muy bueno el informe. Estoy comenzando a utilizar esta librería. Tendrás un ejemplo de cómo leer desde el servidor en Arduino por ejemplo la acción de presionar un botón en el cliente (navegador web /HTML)? (por ejemplo encender un led conectado a la arduino presionando un botón de la página html que aparezca al ingresa en el navegador la IP de la Arduino). Gracias y éxitos!
Arnau
Buenas tardes,
Estoy haciendo un sistema de apertura de puertas con tarjetas NFC. Lo que estoy intentando hacer es que con el ID de cada NFC, lo envíe a un PHP, éste compruebe en un base de datos MySQL si puede acceder o no. Y retorne un 1 o 0 que lo reciba el Arduino. ¿Cómo puedo hacer esto?
Muchas gracias por adelantado.
Saludos
Víctor Ventura
Hola, Arnau.
El proceso que describes sería el que yo seguiría: mandar el id de puerta y llave al servidor, consultar en la base de datos si el par está autorizado y responder consecuentemente (sí/no)
Seguramente ya conoces la librería para hacer consultas HTTP con un módulo WiFi ESP8266 y Arduino que resuelve la parte de Arduino ¿Qué es lo que te da problemas, el acceso con PHP a la base de datos?
¿Has programado ya algo que no te funciona (conocerlo nos ayudaría a ayudarte) o no sabes cómo empezar?
Saludos.
Paul
Está mal escrito Ethernet.mantain() es Ethernet.maintain()
Víctor Ventura
¡ Corregido !
¡ Gracias, Paul !
Nacho
Muchas gracias Víctor por compartir. Quería hacerte una consulta. Tengo un DUE con ethershield y un nano con enc28j60. Ambos funcionan por separado ok como server web. Al nano le conecto un sensor de temperatura y el Due quiero que lo muestre en una pantalla. El DUE es el que espera como server web y el nano solo lee temp. Como hago para pasar la temperatura al DUE por top en lugar de por serial.
Muchas gracias
Víctor Ventura
Hola, Nacho.
Si la placa Arduino Due ya está haciendo de servidor web, lo único que tienes que hacer es preparar en ella una página que reciba los datos que le mande la placa Arduino Nano tal como se explica en el ejemplo de consulta HTTP GET.
Como en tu comentario hablas de pasar por TCP (espero que lo de «top» sea un error o no sé a qué te refieres) a lo mejor lo de «servidor web» es sólo una forma de hablar y te refieres a «servidor» genérico. En tal caso, tendrías que establecer una conexión como cliente con
connect
desde la placa Arduino Nano hasta la placa Arduino Due (que supongo que ya espera como servidor) enviar la información de la temperatura conwrite
o conprint
y recibirlos y procesarlos (presentarlos en la pantalla) en la placa Arduino Due conread
cuandoavailable
detecte que están disponibles.Todo eso está en el texto, así que a lo peor no entendido bien tu pregunta o el problema que se te plantea. No tengas problema en repreguntar con más información para tratar de ayudarte mejor si no es esto lo que preguntas.
Saludos.
Rafael
Hola, ante todo gracias por iluminar en esta gran oscuridad. Al fin alguien habla el idioma de los iniciados.
Fe de errata : En el apartado 3 linea 32-> falta punto y coma.
En linea 15-> EthernetServer cliente=EthernetClient(); es correcto?? no habis dicho que el constructor del cliente es EthrnetClient.
Critica constructiva :
Víctor Ventura
Hola, Rafael.
Gracias por avisar del error. Ya lo he corregido en el ejemplo para no confundir a los visitantes 🙂
En realidad es la clase (el tipo) lo que está mal, EthernetClient es el constructor pero de la clase EthernetClient no EthernetServer (como estaba inicialmente escrito en el ejemplo) Para colmo de lío (en las versiones antiguas) funcionaba por razones de herencia 🙁 Ahora está mucho más claro. Como siempre, lo mejor de la casa, los clientes.
¡Gracias por tu aportación!
Rafael
Hola de nuevo, me dejé la crítica constructiva.
Sería interesante, hacer mención de como se conecta el Hardware. Esta bien expresado el software pero no me quedó claro donde podía hacer la prueba, si directamente desde mi portatil o conectado al router. Al final pude realizer Ping conéxito desde la linea de commando MSDos conectando el modulo Ethernet y mi portatil al Router .
Felicidades por la página Web. Es sencilla, clara y plenamente interesante.
Muchas Gracias!!
Víctor Ventura
Hola, Rafael.
Puedes encontrar información sobre cómo conectar el módulo Ethernet ENC28J60 en mi artículo Conexión Ethernet con el integrado ENC28J60 de Microchip. He preferido separarlo en dos partes porque tiene lectores un poco diferentes y para no hacerlo demasiado largo (y aburrido)
Por supuesto, si no queda lo bastante claro, no tengas problema en volver a consultar; seguro que podemos explicarlo mejor.
¡Otra vez gracias por tus sugerencias! ¡Hasta pronto!
Miky
Hola Victor,
estoy en una situación un tanto rara, estoy utilizando un M-DUino 58 para fines industriales, el cual lleva un enc28J60 i actua como una genuino mega 2560
El tema són las librerias, he incluido la libreria tal y como comentas en el post pero el IDE de arduino me dice que tal librería queda invalidada he provado la Ethernet-h a ver si sonaba la flauta pero tampoco, puesto que usa otro shield de ethernet, alguna sugerencia?
La ide aes mandar a través de un programa de PC tramas UDP que recogerea el Arduino via Ethernet, luego recogerá unos bytes de dicha trama y los utilizará en sus funciones.
Víctor Ventura
Hola, Miky.
No conozco la placa que estás usando pero, si he entendido bien, debería «aparentar» ser un Arduino Mega 2560. Creo recordar que la librería funcionaba en Mega, pero no la he probado con el nuevo IDE. En cuanto tenga un momento le echo un vistazo por si algo de la nueva versión no fuera compatible. Si actualizo código que dependa de la librería también modificaré este artículo y te avisaré.
Un saludo.
Miky
El tema es que he conseguido hacer correr bien la libreria pero tengo un problema con el tema de configuraciones, tengo un programa que manda UDP frames al arduino, entonces ahi hay para modificar la ip y puerto del que envia y tambien para configurar la IP y puerto del que recibe. me gustaría entender que papel juegan cada uno.
mil Gracias Victor
Jorge leonardo
hola victor,
primero, felicitarte al fin alguien que da información clara del funcionamiento de esta shild
segundo estoy tratando de enviar un parametro que recojo de una alarma, y lo que quiero es enviarla a un servidor, solo que no por GET si no por socked, entiendo muy bien cuando explicas la diferencia entre servidor y cliente pero me enredo al querer enviar el dato al servidor, ya que tu ejemplo lee un dato del servidor con lo de las letras mayusculas, estoy usando la shild enc28j60 y un arduino uno me facilitarías mucho las cosas si me explicas como enviar el dato
Víctor Ventura
Hola, Jorge.
La forma de enviar un dato a un servidor es la que puedes ver en el apartado 4: usando
print
o usandowrite
según el dato sea texto o no. Esa función es independiente de que se utilice el protocolo HTTP (GET) o cualquier otro.Como no utilizas HTTP, en la conexión (ver apartado 3) debes indicar el puerto en el que el servidor escucha (segundo parámetro) después de la dirección IP que tiene asignada (primer parámetro).
El protocolo que utilice el servidor (no nos dices si es algo genérico o algo que has programado específicamente para este uso) será el que determine qué «forma» tienen los datos que envías (si se separan por comas, si se encierran entre paréntesis, si terminan en fin de línea…)
Espero que esto te sea útil. Gracias por participar en el blog.
Jorge leonardo
hola victor
tengo una duda en el apartado 3 la parte de codigo que tienes en el void loop() que funcion cumple como tal es necesaria para realizar la conexcion como cliente?o simplemente puedo enviar el dato aviertamente con las funciones que mencionas ?
Víctor Ventura
Hola, Jorge.
La parte de código de ejemplo que hay en
loop()
no es imprescindible para que el programa funcione. El primer bloque es para indicar si ha conectado y el segundo para volver a conectar si se pierde la conexión.Normalmente será en
loop()
donde se vayan enviando los datos conwrite()
y/oprint()
.Saludos.
IVO
Hola,
Estoy como tú desarrollando mis propias cosas de IoT. Gracias por tu escrito me ayudara a enteder mejor como fucniona mi ENC28J60 porque ahora no me esta registrando los datos en la base de datos en XAMPP. tienes un escrito similar para ESP8266? Saludos y Muchas gracias.
Francisco
Hola, buena tarde….
Disculpa, me podrías dar un ejemplo de como establecer comunicación entre el Arduino Uno con Ethernet Shiel W5100 y una placa RaspBerry Pi 3, necesito hacer que reciban y envíen datos entre ellos vía Ethernet sin usar un servidor web, eh intentado varias cosas pero asta hoy ninguna me a funcionado, te preguntaras por que no los conecto directamente por el puerto serie y es por la distancia que hay entre ellos, espero y me puedas ayudar, saludos y gracias…..