Mostrando entradas con la etiqueta Arduino. Mostrar todas las entradas
Mostrando entradas con la etiqueta Arduino. Mostrar todas las entradas

martes, 22 de agosto de 2017

Grabadora Laser

Buenas.

Siguiendo las indicaciones de esta página 3DPBurner, hace ya mas de un año que construí una unidad de esta máquina de grabado laser con la que podemos pasar fotos a madera en escala de grises. Esta fue la primera versión.



Paso a comentar mis impresiones y experiencias, que no van mas allá de la construcción, modificación y primeros trabajos pues realmente no la he usado mucho por dar prioridad a otros proyectos.

Lo primero es juntar el material y para esto hay que conocer varias palabras para poner en el buscador, como por ejemplo:

-"laser TTL". El módulo TTL permite que el laser no solo pueda estar encendido o apagado sino que encienda con diferentes intensidades, usadas para hacer los diferentes tonos de gris.
Yo instalé un laser Violeta (405nm) de 150 mW que compre por 28€ y actualmente por este precio podemos adquirir uno de 500mw con lo que podemos ir mas rápido para hacer el mismo trabajo.
Desconozco si con 500mW ya podemos cortar algún tipo de madera fina. Pero los 10W necesarios para grabar metal se alejan mucho de este precio. 

-"grbl shield" el escudo que conecta Arduino con los controladores de los motores paso a paso, el laser, la alimentación etc. No se si es barato (por lo que hace) o caro (por lo que es), compré varios a 1.05€ con envío gratis, ahora un poco más.
Aquí surgió el primer problema. Nada mas conectar, todo deja de funcionar, se funde el fusible del shield que habrá que sustituir por un trozo de cable.

- Para controlar los motores paso a paso podemos buscar "stepper driver" o mejor directamente "drv8825" (las búsquedas generales son siempre más caras). Muerte a los a4988, se duermen. Debo tener una quincena en los cajones sin usar, la diferencia entre unos y otros es de unos 20 centimos y los A4988 solo sirven para dejar trabajos a medias y perder material. Lo voy a decir abiertamente "te odio a4988"

- Motores paso a paso. Sabemos que la especificación NEMA17 de los motores paso a paso se refiere a sus dimensiones físicas, no a otras características como torque o voltaje. Como en muchos otros ámbitos lo mas usado suele ser lo mas barato y aunque podemos construir este tipo de maquina (que no carga un gran peso) con motores ridículos y os recomendaría buscar "17hs4401". Rondan los 34 € 5 unidades con terminales dupont para conectar directamente en el shield. Recuerdo también que me resistía a creer que cuando el fabricante especificaba que eran de 3 voltios pudiesen servir para 12 o 24 sin derretirse jajaja

- Piezas impresas. Si no tenéis impresora y conocéis a alguien que la tenga no creo que os cueste mucho el trabajo pues no es lo mismo imprimir versiones finales que imprimir piezas en desarrolo que hay que imprimir y reimprimir y...(estoy viendo en la estantería un mini-trípode para la reflex en el que gasté mas de un kilito de plástico, algún día lo subiré, pero por el momento lo que me consuela es que es una pieza única en el mundo... y cada vez que lo miro aún se me ocurre alguna pequeña modificación, no...no lo voy a decir abiertamente).
Por este motivo hice una pequeña donación y recibí un enlace con las últimas versiones de las piezas. aunque ahora están disponibles en thingverse en el siguiente enlace.

Ya funcionaba. Ya se movía!!!!

... pero no muy bien, demasiado ancho para solo un anclaje en el eje Y.

Era hora de sacar el afila lapices

Usar dos motores en el eje no resuelve el problema de dar la misma tensión a las los correas, solo aumenta costes, entonces habrá que mover dos correas con el mismo motor.



Nota: a principios de verano, con el aumento de las temperaturas  y debido a la tensión se rompieron estas piezas y las re-diseñé reforzandolas con un tornillo metálico. Este es el ENLACE a la versión de Thingverse pero con el ARCHIVO de  Blender podréis personalizar para la medida de vuestros rodamientos.

El siguiente paso era poner los finales de carrera, para poner a cero la máquina y poder reposicionarla sin mucho error. Y surgió el segundo problema. No encontraba los pines correcctos para conectarlos. La serigrafía del shield NO corresponde con el pinout del frimware que podemos consultar en este enlace. Solo hay que ver donde salen en la parte superiór. El reposicionamiento es asombrosamente preciso.

Antes de conectar los finales de carrera leí atentamente el modo de conexión pues hasta hace unos días, el único Arduino que me había cargado fue conectando mal los finales de carrera de una impresora. La reparación no fue muy cara ya que solo tuve que sustituir el regulador de tensión de la placa(1117).


Así paso algún que otro mes hasta que cayó en mis manos un trozo de goma eva. Es un material llamativo, atractivo... como muchos otros pero mi pequña "linternita" laser puede grabarlo e incluso cortarlo.


estas son unas pruevas a distintas velocidades, aunque dependen del color de la goma





La configuración final es mas grande para poder trabajar sobre láminas enteras de 600x400 mm y ademas rediseñe los soportes para poder utilizar dos tableros del mismo ancho. Es fácil ir a una gran superficie de bricolaje y pedir que corten uno pequeño a la mitad


viernes, 30 de junio de 2017

iic scanner MY

Buenas, mira q me gusta juntar las cosas para comenzar un proyecto nuevo...

........................

Estos días estuve identificando las direcciones I2C de varios componentes y en un rato modifiqué el código "I2C Scanner" que se encuentra googleando. Mantiene la salida serie pero ademas muestra las direcciones en el lcd, por lo que no hace falta que este conectado al ordenador.

Si hay dos lcd con la misma dirección, se ven las notificaciones en las dos a la vez.

Usando la base que se muestra en las fotos para un Arduino Nano conecto el lcd en A4 y A5 y como tiene duplicados esos pines quedan los cables libres para el componente que queramos identificar.

enlace al CÓDIGO

También imprimí una pieza intentando economizar el gasto de plástico. La podéis descargar en Thingverse lista para impimir o descargar en formato Blender para modificar.

enlace a THINVERSE
enlace a BLENDER FILE




sábado, 17 de junio de 2017

Conunicación entre ESP8266 y Arduino

Buenas.

Hace algún tiempo había hecho una librería para comunicar ESP8266 con Arduino.

La idea era cargar un código tipo en Arduino y controlar todas sus funciones desde ESP: pinModes, reads y writes.

El primer error fue usar la comunicación por serie, la cual era muy inestable.
El segundo error fue pensar q solo podía cambiar el modo en que actúa un pin (entrada o salida) en el Setup.

Estos días estuve trabajando en la mejora.

Por una parte el bus IIC o I2C es estable porque las funciones de comunicación son interrupciones, el micro deja lo que esté haciendo para poder atenderlas. Me dio un poco de trabajo cubrir la necesidad de que los mensajes sean de una longitud determinada, conocida. Aparte de que trabaja con bytes (0-255) q hay que reconvertir a cadenas o enteros según se necesite.

Por otra parte, saber que puedo cambiar el "pinMode" durante la ejecución del programa, eliminó la necesidad de resetear Arduino para que la nueva configuración tenga efecto. Esto permite alcanzar la meta principal de tener un solo código tipo. Cargarlo solo una vez en Arduino. No es que cambie el cableado de un proyecto, sino que el proyecto y su cableado dependan de un solo código, el de ESP.

El bus IIC necesita un Master o Jefe, y ESP por su capacidad y velocidad es mejor que Arduino.
El bus IIC puede controlar varios Esclavos, cada uno con su dirección. Esto permite que un ESP pueda tener varios Arduinos a su servicio. Arduino es mejor en cuanto a numero de pines, (20 digitales en UNO, o 14 digitales y 6 entradas analógicas) y en rango de trabajo que va de 0 a 5v.

Por tanto, la única modificación que haremos al código tipo de Arduino, solo si usamos mas de un esclavo en cada Master, es dar una dirección única dentro del bus IIC.

Los códigos están disponibles en:

Github


y se aceptan dudas, comentarios y mejoras.

Anteriormente lo había enfocado como una librería, y aunque el coloreado de las funciones según se escriben facilita la lectura y corrección del código, últimamente prefiero trabajar teniendo las referencias en la misma pestaña,

El código Master1 es para un ESP con un solo esclavo.
El código Master2 es para un ESP con dos o mas esclavos.
También puede usarse un Arduino como Master. Para esto quitaríamos la única orden que hace que no compile: Wire.setClockStretchLimit(40000);.  Teniendo en cuenta ademas que SDA y SCL son fijos en Arduino, A4 y A5 en 328P (UNO, Nano, Micro) y 20 y 21 en Mega
.
El código Slave es para un Arduino Nano o Micro. También sirve para UNO teniendo en cuenta que no disponemos de las entradas analógicas 20 y 21
El código SlaveMEGA es para un Arduino Mega.  Aunque dos esclavos UNO suman 36 I/Os por menos dinero.

Como se explica en el .md el cableado es directo SDA-SDA y SCL-SCL, sin resistencias ni conversor de nivel.

En ESP-01 se debe especificar Wire.begin (0,2);.
En WemosD1 esta serigrafiado en la placa, Wire.begin (); actúa en D4 y D3.
En nodeMCU 1.0  Wire.begin ();, activa por defecto D1 y D2

Descripción de funcionamiento:

En el código de ejemplo vemos la manera sugerida de uso. Antes de actuar sobre un pin del Esclavo comprobamos su configuración
El esclavo guarda en eeprom la configuración previa aunque es redundante con la comprobación desde master por lo que se puede escoger entre los dos métodos.
Ademas de actuar sobre los pines podemos intercambiar valores de las variables nVar[i]. Para compartir floats podemos usar dos variables, una se ocuparía de la parte entera y reconstruiríamos los decimales con la otra.

En el código de ejemplo está activada la comunicación serie, que no es necesaria para el funcionamiento del código. Pero como veréis en el Monitor Serie cada vez que enviamos una orden, obtenemos un eco, lo que nos permite obtener un acuse de recibo.

ESP y Arduino se complementan. Si tenemos hardware incompatible con ESP podemos cargar sus librerias en Arduino y segur tomando las decisiones desde Master.

jueves, 13 de abril de 2017

ESP8266 RTC DS3231

Get Code

Estos días quería actualizar el programador de riego para usarlo con ESP y lo primero que necesitaba era trabajar con un RTC.

Con las busquedas en google lo primero que me quedó claro es que ESP puede usar la hora de internet. Lo segundo fue que aunque quieras usar un rtc, ESP puede usar la hora de internet, y sigue...

Os dejo este código en el que esp se conecta a una wifi y publica una pagina web desde la que podemos cambiar fecha y hora y saber la temperatura del 3231.

Al principio refrescaba la pagina cada segundo. El problema surgió cuando en ese tiempo no era capaz de escoger una nueva hora en el cuadro para introducirla y al refrescarse la pagina tenia que empezar de nuevo. Imposible.

Como comento en el video, encontre esta entrada: http://www.esp8266.com/viewtopic.php?f=8&t=4307&start=8 en la que el Sr. katz se preguntaba y se respondía. Usé el código de la página 3 como base.

Mediante xml actualizamos partes de la página sin interferir con la selección de una nueva fecha u hora.

Al leer más sobre xml vi que también se podría hacer mediante json, cuya principal ventaja, para mi,
es el uso de arrays. Desafortunadamente, la librería para implementar el uso de json, impide el uso de delay. Aunque no es necesario en este código, si me dio errores de compilación mas adelante. Por eso volví al uso de xml.

miércoles, 21 de octubre de 2015

Programador de Riego v2 328P




Programador de riego V2 328P:

  • 4 sectores
  • 4 arranques por sector
  • tiempo mínimo de riego 1 minuto, máximo 99 minutos
  • control manual
  • puesta en hora de reloj
  • porcentaje de tiempo de riego para ajustar programación sin cambiarla
  • guarda los datos en la memoria EEPROM y recupera la programación después de de reiniciarse
Presupuesto y componentes:
  • Arduino Pro-Mini (2€)
  • Joystick (1€)
  • RTC DS1307 (1€)
  • Módulo de 4 Relés (3€)
  • LCD1602 (2€)
  • Cables (1€)
  • Transformador USB (1€)
  • Transformador 24vac (12€)
  • Caja electrica (6€)
Total 29 €

jueves, 15 de octubre de 2015

Joystick LCD Menu Arduino

Os dejo aquí una plantilla de código para comenzar a trabajar, Es un sistema de menús en Arduino que utiliza un joystick como dispositivo de entrada.



Las características de este código son:

- La pantalla no parpadea, solo se refresca cuando mandemos.
- La estructura de menús no utiliza librerías especificas, todo está en el código.
- Con el botón del joystick entramos en modo edición para ingresar valores, cambiar estados, etc.
- El joystick tiene un retardo en la lectura para evitar lecturas falsas basado en el ejemplo "debounce" que viene con la IDE Arduino. Ademas, pasado ese tiempo, cada pulsación cuenta como una sola.

Cosillas que se quedaron en el tintero:

- Utilizo la última versión de la librería LiquidCristal_I2C. La primera comprobación que hay que hacer si no se muestran caracteres es regular el potenciómetro que esta detrás del LCD, en su circuito controlador. Si esto no resulta, para saber la dirección I2C de nuestra pantalla, cargamos en Arduino un código que encontraremos facilmente "googleando" "I2C scanner", que nos dará las direcciones de los dispositivos conectados al bus sda/scl.

Veo erratas en el código de abajo y dejo un enlace para que podáis descargarlo.


/*  
    LCD Menu & Joytick por JMLoureiro77

    http://jmloureiro77.blogspot.com.es

  328P Flash 5300 (17%) RAM 409(19%)

 - LCD SIN parpadeo
 - Sistema de menus SIN libreria
 - Joystick una pulsacion con retardo
 - editMode para introducir valores en Menu 1 

CC-BY 3.0 */

//---------------------------------------------------
// 1. Librerias
//---------------------------------------------------

#include "Wire.h"
#include "LiquidCrystal_I2C.h" 

//----------------------------------------------------
// 2. Pines
//----------------------------------------------------
#define xPin     A1   
#define yPin     A0   
#define kPin      7   
//SDA            A4
//SCL            A5

//----------------------------------------------------
// 3. Variables y Comandos
//----------------------------------------------------
int tCount1;
bool refresh;//lcd clear On/Off
//leerJoystick
int joyRead;
int joyPos; // lectura de 
int lastJoyPos;
long lastDebounceTime = 0; 
long debounceDelay = 100;               //user define
//Control Joystick
bool PQCP;
bool editMode;
//sistema de menus
int mNivel1;  
int mNivel2;  
//editmode
byte n[19];
int lastN;
int lcdX;
//int lcdY;
bool exiT;
//----------------------------------------------------
// 4. Objetos
//----------------------------------------------------
LiquidCrystal_I2C lcd(0x27,16,2); 

//====================================================
// SETUP
//====================================================
void setup() {
//----------------------------------------------------
// S1. Pines
//----------------------------------------------------
  pinMode(xPin, INPUT);
  pinMode(yPin, INPUT);
  pinMode(kPin, INPUT_PULLUP);
//----------------------------------------------------
// S2. Objetos
//----------------------------------------------------
  lcd.init();
  lcd.backlight(); 
}

//====================================================
// LOOP
//====================================================
void loop() {
  controlJoystick();
  menu();
/*  if (millis()%50==0){
    tCount1++;}
  if (tCount1>1000){tCount1=0;}*/
}

//====================================================
// Menu
//====================================================
void menu(){
  switch (mNivel1){
    case 0:
      menu0();//pantalla de inicio
    break;
    case 1:
        if(mNivel2==1){menu11();
        }else if (mNivel2==2){menu12();
        }else if (mNivel2==3){menu13();}
        else{menu1();}
    break;
    case 2:
      menu2();
        if(mNivel2==1){menu21();
        }else if (mNivel2==2){menu22();
        }else if (mNivel2==3){menu23();}
        else{menu2();}
    break;
    case 3:
      menu3(); //
    break;
  }//switch
}
//----------------------------------------------------
// Pantalla de inicio
//----------------------------------------------------
void menu0(){
  if (refresh){lcd.clear();refresh=0;}
  leeJoystick();
  lcd.setCursor(0,0);
  lcd.print("Pantalla Inicio");
}
//----------------------------------------------------
// Menu 1
//----------------------------------------------------
void menu1(){
  if (refresh){lcd.clear();refresh=0;}
  lcd.setCursor(0,0);
  lcd.print("Menu 1");
  lcd.setCursor(0,1);
//++++++++++++++++++++
  while(editMode){
    controlJoystick();
    lcd.setCursor(lcdX,1);
    if(n[lcdX]!=lastN){
      lcd.print(n[lcdX]);
      lastN=n[lcdX];
    }
  }
}
//-------------------------------------------------1.1
void menu11(){
  if (refresh){lcd.clear();refresh=0;}
  lcd.setCursor(0,0);
  lcd.print("Menu 1.1");
}
//-------------------------------------------------1.2
void menu12(){
  if (refresh){lcd.clear();refresh=0;}
  lcd.setCursor(0,0);
  lcd.print("Menu 1.2");
}
//-------------------------------------------------1.3
void menu13(){
  if (refresh){lcd.clear();refresh=0;}
  lcd.setCursor(0,0);
  lcd.print("Menu 1.3");
}
//----------------------------------------------------
// Menu 2
//----------------------------------------------------
void menu2(){
  if (refresh){lcd.clear();refresh=0;}
  lcd.setCursor(0,0);
  lcd.print("Menu 2");
}
//-------------------------------------------------2.1
void menu21(){
  if (refresh){lcd.clear();refresh=0;}
  lcd.setCursor(0,0);
  lcd.print("Menu 2.1");
}
//-------------------------------------------------2.2
void menu22(){
  if (refresh){lcd.clear();refresh=0;}
  lcd.setCursor(0,0);
  lcd.print("Menu 2.2");
}
//-------------------------------------------------2.3
void menu23(){
  if (refresh){lcd.clear();refresh=0;}
  lcd.setCursor(0,0);
  lcd.print("Menu 2.3");
}
//----------------------------------------------------
// Menu 3
//----------------------------------------------------
void menu3(){
  if (refresh){lcd.clear();refresh=0;}
  lcd.setCursor(0,0);
  lcd.print("Menu 3");
  switch (mNivel2){
    case 0:
      return;
    case 1:
      menu31();
    break;
    case 2:
      menu32();
    break;
    case 3:
      menu33();
    break;
    default:
    break;
  }//switch
}
//-------------------------------------------------3.1
void menu31(){
  if (refresh){lcd.clear();refresh=0;}
  lcd.setCursor(0,0);
  lcd.print("Menu 3.1");
}
//-------------------------------------------------3.2
void menu32(){
  if (refresh){lcd.clear();refresh=0;}
  lcd.setCursor(0,0);
  lcd.print("Menu 3.2");
}
//-------------------------------------------------3.3
void menu33(){
  if (refresh){lcd.clear();refresh=0;}
  lcd.setCursor(0,0);
  lcd.print("Menu 3.3");
}
//====================================================
// Control Joystic
//====================================================
void controlJoystick(){
  leeJoystick();
  if(PQCP) {
    PQCP=0;
    if (joyPos==5){editMode=!editMode;}
    switch (editMode){
       case 1: 
          lcd.blink();
          if (joyPos==4&&n[lcdX]<9 arriba="" if="" joypos="=3&&n[lcdX]" lcdx="" n="" refresh="0;}">0){n[lcdX]--;   //abajo
              refresh=0;} 
          if (joyPos==1&&lcdX<19 derecha="" if="" joypos="=2&&lcdX" lcdx="" refresh="0;}">0){lcdX--;         //izq
           refresh=0;}
        break;
        case 0:
          lcd.noBlink();
          if (mNivel1<3 abajo="" if="" joypos="=3){mNivel1++;" mnivel1="" mnivel2="0;}" refresh="1;">0&&joyPos==4){mNivel1--;    //arriba
            mNivel2=0;
            refresh=1;}
          if (mNivel2<3 derecha="" if="" joypos="=1){mNivel2++;" mnivel2="" refresh="1;}">0&&joyPos==2){mNivel2--;    //izq
           refresh=1;}
        }//!edit
  }//PQCP
}
int leeJoystick(){
  int x = analogRead(xPin);
  int y = analogRead(yPin);
  int k = digitalRead(kPin);
    if(x>900){joyRead=1;        //x+
    }else if(x<100 else="" if="" joyread="2;" x-="" y="">900){joyRead=3;  //y+
    }else if(y<100 -="" else="" if="" joyread="" k="" lastdebouncetime="" lastjoypos="" millis="" y-=""> debounceDelay)&&(joyRead!=joyPos)){
    joyPos=joyRead;
    if(!PQCP){PQCP=1;}
    }
  lastJoyPos=joyRead;
}

Programador de Riego v2 MEGA


Cosillas que se quedaron en el tintero:

- Aunque no se monte ESP-01 u otra versión de ESP8266, el programador funciona igual.

- Uso de memorias. Tal como está en el vídeo, el código ocupa un 38% de RAM y un 30% de FLASH, esto implica que se puede llegar a 20 sectores y mas arranques diarios.

- ESP, como punto de acceso añade capacidades interesantes. Imaginemos por ejemplo un jardinero, con un programador de este tipo en cada jardín en el que trabaja. Si todos tienen la misma configuración, SSID y contraseña, en cuanto llegase al jardín podría controlar el riego ahorrándose algún que otro paseo.

- Souliss y la APP Souliss se pueden encontrar en http://souliss.net/ y en Google Play Store

jueves, 21 de agosto de 2014

Programador de Riego Arduino V 1.0 SD Backup

Descripción:
Programador de riego Arduino V1.0 http://jmloureiro77.blogspot.com
  - 7 sectores mas arranque de bomba
  - 4 arranques diarios por sector, un minuto de tiempo mínimo de riego
  - Programable mediante arcivos de texto en SD
  - Consulta de programa sobre web/ip
  - Control manual sobre web/ip

Componentes:
  - Arduino Mega
  - RTCDS1307
  - Modulo 8 Relés
  - Transformador con salida USB (alimenta Arduino) y derivación para alimentar reles
  - Trasnformador 24V AC para activar electroválvulas estandar
  - telefono mobil para consulta de programación y control manual



Instrucciones:
  S1.txt, S2.txt, S7.txt en raiz SD segun el siguiente formato:
  Nombre del sector  //primera linea
  S  // Segunda linea "S" o "N"- S(para sector exterior afectado por la desconexion manual), N (Sector de invernadero, patio interior, etc noafectado por desconexion manual) // no implementado en esta version
  1  // Tercera linea tiempo de riego en minutos, para > 1 hora, pex 61-120
  09:00 // Hora del primer arranque diario
  10:00 // si no se una el segundo,... dejar en blanco. no usar 00:00 pues arrancaria a las 12 PM
  18:00
  19:00

  insertar tarjeta y resetear arduino


(CC BY 3.0 ES)
  Usted es libre de:
    Compartir — copiar y redistribuir el material en cualquier medio o formato
    Adaptar — remezclar, transformar y crear a partir del material
    para cualquier finalidad, incluso comercial.
    El licenciador no puede revocar estas libertades mientras cumpla con los términos de la licencia.
 
  Bajo las condiciones siguientes:
    Reconocimiento — You must give appropriate credit, provide a link to the license, and indicate if changes were made. You may do so in any reasonable manner, but not in any way that suggests the licensor endorses you or your use.

Gracias a:
  http://www.extremadura-web.es/Blog/2013/01/16/leer-linea-fichero-sd-en-arduino/

Problemas solventados.
- Como dar alimentación externa a modulo de relés.
- Como cambiar MAC para que no coincida con otro Arduino en la red
- Estructura de control con varios If. Antes daba problemas con el control de la bomba.

Futuras mejoras: (Acepto Ayuda)
- Como fijar la hora del rtc desde la pagina web.
- Instalación de LCD 1602 y menú
- Conseguir implementar un "Rain delay" aka desconexión manual

Problemas no resueltos.
 En casa todo OK.
Cuando lo instalo en la ubicación definitiva, en otra wifi, donde hay otro Arduino conectado al router y publicando otra web, este no publica la página web. A veces carga el principio de la pagina pero no mas.
Riega y sigue la programación pero no muestra la web.
En el código, los dos tienen distinta ip y mac, cambie también el puerto, y lo abrí en el router com"patata"trend.
Despues de abrir el puerto, la luz del router dejo de parpadear y se mantiene fija.
Sigo Buscando...



domingo, 27 de julio de 2014

Programador de riego Arduino SD backup V0.7


/*
Programador de riego V.07 http://jmloureiro77.blogspot.com
  - 3 sectores con desconexion manual y arranque de bomba
  - 4 arranques diarios por sector, un minuto de tiempo mínimo de riego
  - Programable mediante arcivos de texto en SD

Componentes:
  - Arduino UNO
  - RTCDS1307
  - Modulo SD & SD card
  - 4 Relés
  - Transformador con salida USB (alimenta Arduino)
  - Trasnformador 24V AC para activar electroválvulas estandar
  - Divisor resistivo pullDown e interruptor manual 1k ohm

Instrucciones:
  S1.txt, S2.txt, S3.txt en raiz SD segun el siguiente formato:
S  // Primera linea - "S" o "N"- S(para sector exterior afectado por la desconexion manual), N (Sector de invernadero, patio interior, etc noafectado por desconexion manual)
1  //segunda linea  - tiempo de riego en minutos, para > 1 hora, pex 61-120
09:00 // Hora delprimer arranque diario
10:00 // si no se una el segundo,... dejar en blanco. no usar 00:00 pues arrancaria a las 12 PM
18:00
19:00

insertar tarjeta y resetear arduino


(CC BY 3.0 ES)
  Usted es libre de:
    Compartir — copiar y redistribuir el material en cualquier medio o formato
    Adaptar — remezclar, transformar y crear a partir del material
    para cualquier finalidad, incluso comercial.
    El licenciador no puede revocar estas libertades mientras cumpla con los términos de la licencia.
 
  Bajo las condiciones siguientes:
    Reconocimiento — You must give appropriate credit, provide a link to the license, and indicate if changes were made. You may do so in any reasonable manner, but not in any way that suggests the licensor endorses you or your use.

Gracias a:
  http://www.extremadura-web.es/Blog/2013/01/16/leer-linea-fichero-sd-en-arduino/


 * SD card attached to SPI bus as follows:
 ** MOSI - pin 11
 ** MISO - pin 12
 ** CLK - pin 13
 ** CS - pin 4

 */

#include xSPI.hx
#include xWire.hx
#include xSD.hx
#include "RTClib.h"
RTC_DS1307 RTC;

// Pines
int PinDescoM = A1; // entrada del divisor resistivo en pullDown del interruptor de desconexion manual para sectores afectados por lluvia
                    //devolvera un valor > 700 si el interruptor manual de lluvia está activado
int DescoM = 0; //0=todos sectores activados 1= desactiva sectores exteriores

int PinPump = 5; //pin para rele que activa bomba conectado Normalmente Abierto
int PinS1 = 6;   //pin para sector de riego 1
int PinS2 = 7;
int PinS3 = 8;

File myFile;

//Variables Sector 1
String ext1;
String t1; //recupera de fichero
int t1d;  //covierte a decimal
  //Variables sector UNO para Hora de arranque UNO *ver en void setup
String h11; //ex recupera 13:22
String h11h; // selecciona 13
int h11hd;  //pasa a decimal
String h11m; //selecciona 22
int h11md;  //pasa a decimal
int h11d;  //13*60+22

String h12;
String h12h;
int h12hd;
String h12m;
int h12md;
int h12d;

String h13;
String h13h;
int h13hd;
String h13m;
int h13md;
int h13d;

String h14;
String h14h;
int h14hd;
String h14m;
int h14md;
int h14d;

//Variables Sector 2
String ext2;
String t2; //recupera de fichero
int t2d;  //covierte a decimal
  //Variables sector UNO para Hora de arranque UNO *ver en void setup
String h21; //ex recupera 13:22
String h21h; // selecciona 13
int h21hd;  //pasa a decimal
String h21m; //selecciona 22
int h21md;  //pasa a decimal
int h21d;  //13*60+22

String h22;
String h22h;
int h22hd;
String h22m;
int h22md;
int h22d;

String h23;
String h23h;
int h23hd;
String h23m;
int h23md;
int h23d;

String h24;
String h24h;
int h24hd;
String h24m;
int h24md;
int h24d;

//Variables Sector 3
String ext3;
String t3; //recupera de fichero
int t3d;  //covierte a decimal
  //Variables sector UNO para Hora de arranque UNO *ver en void setup
String h31; //ex recupera 13:22
String h31h; // selecciona 13
int h31hd;  //pasa a decimal
String h31m; //selecciona 22
int h31md;  //pasa a decimal
int h31d;  //13*60+22

String h32;
String h32h;
int h32hd;
String h32m;
int h32md;
int h32d;

String h33;
String h33h;
int h33hd;
String h33m;
int h33md;
int h33d;

String h34;
String h34h;
int h34hd;
String h34m;
int h34md;
int h34d;

int HoraAc = 0; //variable para almacenar hora actual


void setup()
{
 // Open serial communications and wait for port to open:
  Serial.begin(9600); //activada durante pruebas
  Wire.begin();
  RTC.begin();
  //cuando quitamos el comentario(//) de la linea siguiente, se ajusta la hora y la fecha con la del ordenador
  //RTC.adjust(DateTime(__DATE__, __TIME__));
   pinMode(10, OUTPUT);
   pinMode(PinPump, OUTPUT);
   digitalWrite(PinPump,HIGH); //para que rele empiece apagado
   pinMode(PinS1, OUTPUT);
   digitalWrite(PinS1,HIGH); //para que rele empiece apagado

   while (!Serial) {
    ; // wait for serial port to connect. Needed for Leonardo only
  }


  Serial.print("Initializing SD card...");
  // On the Ethernet Shield, CS is pin 4. It's set as an output by default.
  // Note that even if it's not used as the CS pin, the hardware SS pin
  // (10 on most Arduino boards, 53 on the Mega) must be left as an output
  // or the SD library functions will not work.
 
 
  if (!SD.begin(4)) {
    Serial.println("initialization failed!");
    return;
  }
  Serial.println("initialization done.");

  // open the file. note that only one file can be open at a time,
  // so you have to close this one before opening another.
  myFile = SD.open("S1.txt", FILE_WRITE);

  // if the file opened okay, write to it:
  if (myFile) {
    //Serial.print("Writing to test.txt...");
    //myFile.println("testing 1, 2, 3.");
    // close the file:
    //myFile.close();
    Serial.println("done.");
  } else {
    // if the file didn't open, print an error:
    Serial.println("error opening test.txt");
  }

  // re-open the file for reading:
  myFile = SD.open("S1.txt");
  if (myFile) {
    Serial.println("S1.txt:");
 
    // read from the file until there's nothing else in it:
    while (myFile.available()) {
        Serial.write(myFile.read());
    }
    // close the file:
    myFile.close();
  } else {
    // if the file didn't open, print an error:
    Serial.println("error opening test.txt");
  }


//Serial.println();
char Ruta[7] = {'S', '1', '.', 't', 'x', 't', '\0'};

//Leemos linea de archivo en la SD
String Lin = ReadFile(0,Ruta);
ext1 = Lin;
Lin = ReadFile(1,Ruta);
t1 = Lin; //tiempo de riego sector 1
t1d = t1.toInt();
Lin = ReadFile(2,Ruta);
h11 = Lin; //hora arranque 1
h11h= h11.substring(0,2); //el primero no cuenta
h11hd = h11h.toInt();
h11m= h11.substring(3,5);
h11md = h11m.toInt();

Lin = ReadFile(3,Ruta);
h12 = Lin;
h12h= h12.substring(0,2);
h12hd = h12h.toInt();
h12m= h12.substring(3,5);
h12md = h12m.toInt();

Lin = ReadFile(4,Ruta);
h13 = Lin;
h13h= h13.substring(0,2);
h13hd = h13h.toInt();
h13m= h13.substring(3,5);
h13md = h13m.toInt();

Lin = ReadFile(5,Ruta);
h14 = Lin;
h14h= h14.substring(0,2);
h14hd = h14h.toInt();
h14m= h14.substring(3,5);
h14md = h14m.toInt();

//Sector 2
char RutaS2[7] = {'S', '2', '.', 't', 'x', 't', '\0'};

//Leemos linea de archivo en la SD
Lin = ReadFile(0,RutaS2);
ext2 = Lin;
Lin = ReadFile(1,RutaS2);
t2 = Lin; //tiempo de riego sector 1
t2d = t2.toInt();
Lin = ReadFile(2,RutaS2);
h21 = Lin; //hora arranque 1
h21h= h21.substring(0,2); //el primero no cuenta
h21hd = h21h.toInt();
h21m= h21.substring(3,5);
h21md = h21m.toInt();

Lin = ReadFile(3,RutaS2);
h22 = Lin;
h22h= h22.substring(0,2);
h22hd = h22h.toInt();
h22m= h22.substring(3,5);
h22md = h22m.toInt();

Lin = ReadFile(4,RutaS2);
h23 = Lin;
h23h= h23.substring(0,2);
h23hd = h23h.toInt();
h23m= h23.substring(3,5);
h23md = h23m.toInt();

Lin = ReadFile(5,RutaS2);
h24 = Lin;
h24h= h24.substring(0,2);
h24hd = h24h.toInt();
h24m= h24.substring(3,5);
h24md = h24m.toInt();

//Sector 3
char RutaS3[7] = {'S', '3', '.', 't', 'x', 't', '\0'};

//Leemos linea de archivo en la SD
Lin = ReadFile(0,RutaS3);
ext3 = Lin;
Lin = ReadFile(1,RutaS3);
t3 = Lin; //tiempo de riego sector 1
t3d = t3.toInt();
Lin = ReadFile(2,RutaS3);
h31 = Lin; //hora arranque 1
h31h= h31.substring(0,2); //el primero no cuenta
h31hd = h31h.toInt();
h31m= h31.substring(3,5);
h31md = h31m.toInt();

Lin = ReadFile(3,RutaS3);
h32 = Lin;
h32h= h32.substring(0,2);
h32hd = h32h.toInt();
h32m= h32.substring(3,5);
h32md = h32m.toInt();

Lin = ReadFile(4,RutaS3);
h33 = Lin;
h33h= h33.substring(0,2);
h33hd = h33h.toInt();
h33m= h33.substring(3,5);
h33md = h33m.toInt();

Lin = ReadFile(5,RutaS3);
h34 = Lin;
h34h= h34.substring(0,2);
h34hd = h34h.toInt();
h34m= h34.substring(3,5);
h34md = h34m.toInt();

}

void loop()
{
  if (PinDescoM > 500)  { //esta parte del codigo imposivilita controlar el parametro por web, la desconexion de los sectores exteriores se hace fisicamente
    DescoM = 1;
  }
  else {
    DescoM = 0;
  }
 DateTime now = RTC.now();
 HoraAc = now.hour()*60 + now.minute(); //pasamos la hora actual a minuto del dia

 h11d = ((h11hd * 60)+ h11md); //pasamos a minuto del dia la hora de arranque
 h12d = ((h12hd * 60)+ h12md);
 h13d = ((h13hd * 60)+ h13md);
 h14d = ((h14hd * 60)+ h14md);

 h21d = ((h21hd * 60)+ h21md); //pasamos a minuto del dia la hora de arranque
 h22d = ((h22hd * 60)+ h22md);
 h23d = ((h23hd * 60)+ h23md);
 h24d = ((h24hd * 60)+ h24md);

 h31d = ((h31hd * 60)+ h31md); //pasamos a minuto del dia la hora de arranque
 h32d = ((h32hd * 60)+ h32md);
 h33d = ((h33hd * 60)+ h33md);
 h34d = ((h34hd * 60)+ h34md);

//Control Sector 1
if (DescoM == 1 && ext1 == "S") {
  }
else {
  if (HoraAc >= h11d && HoraAc < (h11d+t1d)) { //Arranque 1
    digitalWrite(PinPump,LOW); //low es encendido y no preguntes. encendemos bomba
    digitalWrite(PinS1,LOW); //abrimos electrovalbula
  }
  else {
    digitalWrite(PinPump,HIGH);
    digitalWrite(PinS1,HIGH);
  }
  if (HoraAc >= h12d && HoraAc < (h12d+t1d)) { //Arranque 2
    digitalWrite(PinPump,LOW);
    digitalWrite(PinS1,LOW);
  }
  else {
    digitalWrite(PinPump,HIGH);
    digitalWrite(PinS1,HIGH);
  }
  if (HoraAc >= h13d && HoraAc < (h13d+t1d)) { //Arranque 3
    digitalWrite(PinPump,LOW);
    digitalWrite(PinS1,LOW);
  }
  else {
    digitalWrite(PinPump,HIGH);
    digitalWrite(PinS1,HIGH);
  }
  if (HoraAc >= h14d && HoraAc < (h14d+t1d)) { //Arranque 4
    digitalWrite(PinPump,LOW);
    digitalWrite(PinS1,LOW);
  }
  else {
    digitalWrite(PinPump,HIGH);
    digitalWrite(PinS1,HIGH);
  }
}
//Control Sector 2
if (DescoM == 1 && ext2 == "S") {
  }
else {
  if (HoraAc >= h21d && HoraAc < (h21d+t2d)) { //Arranque 1
    digitalWrite(PinPump,LOW); //low es encendido y no preguntes. encendemos bomba
    digitalWrite(PinS2,LOW); //abrimos electrovalbula
  }
  else {
    digitalWrite(PinPump,HIGH);
    digitalWrite(PinS2,HIGH);
  }
  if (HoraAc >= h22d && HoraAc < (h22d+t2d)) { //Arranque 2
    digitalWrite(PinPump,LOW);
    digitalWrite(PinS2,LOW);
  }
  else {
    digitalWrite(PinPump,HIGH);
    digitalWrite(PinS2,HIGH);
  }
  if (HoraAc >= h23d && HoraAc < (h23d+t2d)) { //Arranque 3
    digitalWrite(PinPump,LOW);
    digitalWrite(PinS2,LOW);
  }
  else {
    digitalWrite(PinPump,HIGH);
    digitalWrite(PinS2,HIGH);
  }
  if (HoraAc >= h24d && HoraAc < (h24d+t2d)) { //Arranque 4
    digitalWrite(PinPump,LOW);
    digitalWrite(PinS2,LOW);
  }
  else {
    digitalWrite(PinPump,HIGH);
    digitalWrite(PinS2,HIGH);
  }
}
//Control Sector 1
if (DescoM == 1 && ext3 == "S") {
  }
else {
  if (HoraAc >= h31d && HoraAc < (h31d+t3d)) { //Arranque 1
    digitalWrite(PinPump,LOW); // encendemos bomba
    digitalWrite(PinS3,LOW); //abrimos electrovalbula
  }
  else {
    digitalWrite(PinPump,HIGH);
    digitalWrite(PinS3,HIGH);
  }
  if (HoraAc >= h32d && HoraAc < (h32d+t3d)) { //Arranque 2
    digitalWrite(PinPump,LOW);
    digitalWrite(PinS3,LOW);
  }
  else {
    digitalWrite(PinPump,HIGH);
    digitalWrite(PinS3,HIGH);
  }
  if (HoraAc >= h33d && HoraAc < (h33d+t3d)) { //Arranque 3
    digitalWrite(PinPump,LOW);
    digitalWrite(PinS3,LOW);
  }
  else {
    digitalWrite(PinPump,HIGH);
    digitalWrite(PinS3,HIGH);
  }
  if (HoraAc >= h34d && HoraAc < (h34d+t3d)) { //Arranque 4
    digitalWrite(PinPump,LOW);
    digitalWrite(PinS3,LOW);
  }
  else {
    digitalWrite(PinPump,HIGH);
    digitalWrite(PinS3,HIGH);
  }
}
}


//Funcion para leer linea de un archivo de la sd http://www.extremadura-web.es/Blog/2013/01/16/leer-linea-fichero-sd-en-arduino/
//Primer parametro numero de linea
//Segundo Parametro ruta del fichero
String ReadFile(int Linea,char Ruta[]){
  int Lin=0;
  String Resultado;
  File myFile;
  byte Bin;
  myFile = SD.open(Ruta);;
  if (myFile) {
  while (myFile.available()) {
  Bin=myFile.read();
  if (Bin==13){Lin++;myFile.read();}
  else
  {
  if (Lin==Linea){Resultado=Resultado+(char(Bin));}
  if (Lin>Linea){myFile.close();return Resultado;}
  }
  }
  myFile.close();return Resultado;
  }
}