Protocolos
de comunicación: SPI
SPI es un protocolo serial síncrono
que
se utiliza para comunicar un microcontrolador con
otro y con periféricos a distancias cortas. Para hacer
una conexion SPI
siempre habrá un dispositivo maestro (usualmente un microcontrolador) que
controlará uno o varios periféricos (esclavos), se utilizan por lo generar 3 lineas de
conexión y una de selección que son:
* SO o MISO (Master In Slave Out). La linea que utiliza el esclavo para enviar datos al maestro
* SI o MOSI (Master Out Slave In). Datos del maestro al esclavo.
* SCK (Serial clock). Pulsos de reloj para sincronizar la comunicación
* CS o Select. Se usa por el master para habilitar o deshabilitar un determinado periférico
Los microcontroladores atmel incluyen las 4 lineas para usar protocolo SPI las cuales obviamente están presentes en los pines del arduino, para el arduino uno se deben usar: Pin digital 10 para CS, Pin digital 11 para SI, Pin digital 12 para SO y Pin digital 13 para SCK, en el caso del arduino mega se usaría los sig. pines: 50 (MISO), 51 (MOSI), 52 (SCK), and 53 (CS).
La alimentación del módulo puede es a 3.3 los cuales son suministrados por el arduino
* SO o MISO (Master In Slave Out). La linea que utiliza el esclavo para enviar datos al maestro
* SI o MOSI (Master Out Slave In). Datos del maestro al esclavo.
* SCK (Serial clock). Pulsos de reloj para sincronizar la comunicación
* CS o Select. Se usa por el master para habilitar o deshabilitar un determinado periférico
Los microcontroladores atmel incluyen las 4 lineas para usar protocolo SPI las cuales obviamente están presentes en los pines del arduino, para el arduino uno se deben usar: Pin digital 10 para CS, Pin digital 11 para SI, Pin digital 12 para SO y Pin digital 13 para SCK, en el caso del arduino mega se usaría los sig. pines: 50 (MISO), 51 (MOSI), 52 (SCK), and 53 (CS).
La alimentación del módulo puede es a 3.3 los cuales son suministrados por el arduino
Protocolos
de comunicación: HTTP
Hypertext
Transfer Protocol o
HTTP (en español protocolo de transferencia de hipertexto) es el protocolo
usado en cada transacción de la Web.
Es un
protocolo orientado a transacciones y sigue el esquema petición-respuesta entre
un cliente y un servidor.
Al cliente
que efectúa la petición (un navegador web o un spider) se lo conoce como "user agent"
(agente del usuario). Y a la información transmitida se la llama recurso y se la identifica
mediante un localizador uniforme de recursos (URL). Los recursos pueden ser
archivos, el resultado de la ejecución de un programa, una consulta a una base
de datos, en
este caso en particular la respuesta será la lectura de un sensor o el
resultado de la ejecución de un proceso en Arduino, etc.
El
módulo ENC28J60 y su librería desarrollada para el arduino lo
convierten en un pequeño servidor WEB capaz de responder a interacciones del
usuario desde cualquier navegador.
Librería
ENC28J60
El
módulo que usaremos está basado en un chip ENC28J60 de Microchip que
interactúa con Arduino y le permite la comunicación de datos mediante un puerto Ethernet.
Se
integra el controlador de la MAC address, un
buffer de 8 KB de transmisión/recepción de de paquetes de doble puerto y una
FIFO circular que se gestionan a nivel de hardware, además
permite la
programación de retransmisión de datos en caso de colisión.
La
librería de funciones fue desarrollada por Jean-Claude Wippler del
sitio http://jeelabs.org y liberada con licencia creative commons como
software libre,
a
partir de ahí ha sido utilizada por diferentes fabricantes para soportar
diferentes productos basados en el mismo controlador.
Antes de iniciar la operación de
nuestro módulo debemos llevara acabo la configuración de los parámetros para
comunicación en la red ethernet, datos como:
Dirección IP
Máscara de red
Puerta de enlace
Tamaño del buffer de datos.
Las principales funciones incluidas
en la librería son:
ether.begin :
Crea un objeto para interactuar con el controlador
ether.packetReceive(); Devuelve la cantidad de paquetes pendientes de recibir que estan
almacenados en el buffer.
ether.packetLoop(len); Da
entrada todos los paquetes almacenados en el buffer, len es
la cantidad de paquetes que se van a recibir;
ether.httpServerReply(homePage()); Responde al cliente que realizo la petición, homePage es
una variable que apunta a un string o
cadena de texto con formato HTML con una respuesta válida para el cliente.
El siguiente programa controla el encendido y apagado de un led mediante una pagina web que se accede desde la direccion ip del modulo enc-28j60 conectado al arduino, el diagrama de conexion del modulo con el arduino es el que ya vimos en la primera parte de este tutorial mas un led conectado en el pin digital 2 que sera el que controlemos via red:
// Arduino demo sketch for testing ethernet
// 2012-09-20 lmdiaz@tecnotinker.com
// This sketch is derived from RF12eth.pde:
// May 2010, Andras Tucsni, http://opensource.org/licenses/mit-license.php
#include <EtherCard.h>
#define DEBUG 0 // set to 1 to display free RAM on web page
#define SERIAL 0 // set to 1 to show incoming requests on serial port
// buffer for an outgoing data packet
static char outCount = -1;
// configuration, as stored in EEPROM
struct Config {
byte band;
byte group;
byte collect;
word refresh;
byte valid; // keep this as last byte
} config;
#define NUM_MESSAGES 10 // Number of messages saved in history
#define MESSAGE_TRUNC 15 // Truncate message payload to reduce memory use
static BufferFiller bfill; // used as cursor while filling the buffer
static byte history_rcvd[NUM_MESSAGES][MESSAGE_TRUNC+1]; //history record
static byte history_len[NUM_MESSAGES]; // # of RF12 messages+header in history
static byte next_msg; // pointer to next rf12rcvd line
static word msgs_rcvd; // total number of lines received modulo 10,000
byte ledstatus = 0;
byte Ethernet::buffer[1000]; // tcp/ip send and receive buffer
// ethernet interface mac address
static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 };
// ethernet interface ip address
static byte myip[] = { 192,168,1,188 };
// gateway ip address
static byte gwip[] = { 192,168,1,1 };
#if DEBUG
static int freeRam () {
extern int __heap_start, *__brkval;
int v;
return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
}
#endif
void setup(){
#if SERIAL
Serial.begin(57600);
Serial.println("\n[etherNode]");
#endif
if (ether.begin(sizeof Ethernet::buffer, mymac) == 0)
Serial.println( "Failed to access Ethernet controller");
ether.staticSetup(myip, gwip);
#if SERIAL
ether.printIp("IP: ", ether.myip);
#endif
}
char okHeader[] PROGMEM =
"HTTP/1.0 200 OK\r\n"
"Content-Type: text/html\r\n"
"Pragma: no-cache\r\n"
;
static void homePage(BufferFiller& buf, byte led) {
buf.emit_p(PSTR("$F\r\n"
"<meta http-equiv='refresh' content='$D'/>"
"<title>Controlar un led desde internet</title>"
"<body><p>Estatus del led: $D</br>"
"<a href='a'>Apagar</a> </br>"
"<a href='e'>Encender</a><br></p>"), okHeader, 1, led);
// Cronometrar el tiempo de ejecucion del programa
long t = millis() / 1000;
word h = t / 3600;
byte m = (t / 60) % 60;
byte s = t % 60;
buf.emit_p(PSTR(
"Tiempo corriendo $D$D:$D$D:$D$D</body>"), h/10, h%10, m/10, m%10, s/10, s%10);
#if DEBUG
buf.emit_p(PSTR(" ($D bytes free)"), freeRam());
#endif
}
void loop(){
word len = ether.packetReceive();
word pos = ether.packetLoop(len);
// check if valid tcp data is received
if (pos) {
bfill = ether.tcpOffset();
char* data = (char *) Ethernet::buffer + pos;
#if SERIAL
Serial.println(data);
#endif
// Pagina sin solicitud
if (strncmp("GET / ", data, 6) == 0) {
homePage(bfill, ledstatus);
}
else if (strncmp("GET /a", data, 6) == 0) {
// Recibimos el parametro a (apagar)
homePage(bfill, ledstatus);//configPage(data, bfill);
if(ledstatus == HIGH) {
digitalWrite(2, LOW);
ledstatus = LOW;
}
}
else if (strncmp("GET /e", data, 6) == 0) {
// Recibimos el parametro e (encender)
homePage(bfill, ledstatus);
if(ledstatus == LOW) {
digitalWrite(2, HIGH);
ledstatus = HIGH;
}
}
else
bfill.emit_p(PSTR(
"HTTP/1.0 401 Invalido\r\n"
"Content-Type: text/html\r\n"
"\r\n"
"<h1>401 Unauthorized</h1>"));
ether.httpServerReply(bfill.position()); // send web page data
}
}