Sunday, June 15, 2014

Problema con delay en Arduino Nano

Trabajando últimamente con Arduino Nano y queriendo de alguna forma "explotar" a fondo sus características, me crucé un problema particular. Mi objetivo era hacer andar un display lcd de 16x2 junto con 5 sensores DHT11. El problema más clásico que sufrí fue que la aplicación se quedaba en cierto punto y no avanzaba. Haciendo diversas pruebas, llegué a que el problema se encontraba en la clásica función de Arduino delay. Esta función se encarga de pausar el controlador por X milisegundos y se suele utilizar imperativamente en ocasiones como la lectura de sensores, para que no se realicen lecturas continuamente ya que puede llegar a leerse información basura. Investigando un poco, encontré que esta función no es muy recomendable utilizar en este tipo de micro-controladores.

Era necesario encontrar una forma alternativa de "esperar" o detener el micro-procesador unos cuantos milisegundos en distintos puntos del programa. Esta es la solución para aquellos que se encuentren con este tipo de problemas:
Supongamos que estabamos utilzando delay(1000), es decir, espera de 1 segundo. Esto puede ser reemplazado por lo siguiente:

unsigned long Timer=millis();

while (!(millis()-Timer>=1000UL)){
}

La variable Timer toma los milisegundos actuales del programa. Luego se realizará la comparación de dicho valor con los milisegundos futuros y no se avanzará en la ejecución del programa hasta que haya una diferencia de 1000 entre ambos valores. UL indica que la variable es unsigned long, para tener compatibilidad de tipos.

Saludos y nos vemos pronto.


Monday, April 7, 2014

Configurar Etherner Shield ENC28J60 con Arduino MEGA 2560



Después de tanto buscar en inet como lograr hacer funcionar mi Ethernet Shield ENC28J60, logré encontrar la solución y la posteo acá porque sé que a alguien le servirá en algún futuro cercano. Para los que tengan dudas si su Shield es el adecuado, trabajé con el HanRun HR911105A 09/48, pero seguramente sirva para otros modelos. Acá una foto para más claridad:
Las conexiones con Arduino Mega 2560 son las siguientes:
GND -> GND
3.3 -> Vcc
SO -> Pin 50
SI -> Pin 51
SCK -> Pin 52
CS -> Pin 53
Los otros cuatro pines (INT, RESET, WOL, CLKOUT) quedan sin conectar.

La librería que se usará es la EtherCard, que la pueden bajar aquí: https://github.com/jcw/ethercard
Esta librería funciona sin problemas para placas Arduino UNO y quizás para algunas más, pero existe un pequeño inconveniente con las placas MEGA. En las placas Arduino MEGA, está mal configurado el pin CS, lo que genera que si se utiliza la librería con los ejemplos que trae, no vaya a funcionar jamás. Para arreglar dicho inconveniente, el método ether.begin que inicializa al Shield debe recibir un parámetro extra indicando la modificación del pin CS. Los encabezados deberían quedar de la siguiente forma:

...
  if (ether.begin(sizeof Ethernet::buffer, mymac, 53) == 0)
    Serial.println( "Failed to access Ethernet controller");
...

Normalmente, dicho seteo suele estar en la función setup del Arduino. Lo que se hizo fue agregar un parámetro más al final del llamado a la función begin, que indica a que pin debe conectarse CS.

Finalmente, para verificar que el Arduino trabaja correctamente, pueden cargar el siguiente código:

#include <EtherCard.h>

// ethernet interface mac address, must be unique on the LAN
static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31  };
static byte myip[] = { 192,168,2,188 };

byte Ethernet::buffer[500]; 
BufferFiller bfill;                   

void setup () {
  if (ether.begin(sizeof Ethernet::buffer, mymac, 53) == 0)
    Serial.println( "Failed to access Ethernet controller");
  ether.staticSetup(myip);
}

static word homePage() {
  bfill = ether.tcpOffset();        
  bfill.emit_p(PSTR(                  
"<!DOCTYPE html>"
"<html>"
    "<head>"
    "<style>"
    "body {"
    "font-size:100%;"
    "font-family:arial;"
    "}"
    "</style>"
    "</head>"
    "<body>"
        "<div >Hello World!</div>"
    "</body>"
"</html>"
    ));
  return bfill.position();
}

void loop () {
  word len = ether.packetReceive();
  word pos = ether.packetLoop(len);
  
  if (pos)  // check if valid tcp data is received
    ether.httpServerReply(homePage()); // send web page data
}

En mi caso, conecté la salida del Ethernet Shield a mi router y desde mi computadora, ingresando la IP indicada en el código, correspondiente al Arduino, logré entrar y ver la respuesta HTML. Es posible incluso pasar parámetros a la función emit_p y referenciarlos desde el HTML de la siguiente forma:

  bfill.emit_p(PSTR( 
"<!DOCTYPE html>"
"<html>"
    "<head>"
    "<style>"
    "body {"
    "font-size:100%;"
    "font-family:arial;"
    "}"
    "</style>"
    "</head>"
    "<body>"
        "<div >$D $D</div>"
    "</body>"
"</html>"
    ), "Hello ", "World!");  

Al final de la función se puede pasar una lista (no importa la cantidad) de elementos. En el HTML, mediante $D se tomará al elemento correspondiente al número de aparición de $D. En este caso, el primer $D toma el valor "Hello " y el segundo el valor "World!".

Dejo la fuente que me permitió llegar a solucionar este problema, que es básicamente todo lo que dejé aquí: http://en.code-bude.net/2013/06/22/how-to-use-enc28j60-ethernet-shield-with-arduino-mega-2560/
Saludos!