meta data de esta página
Diferencias
Muestra las diferencias entre dos versiones de la página.
Próxima revisión | Revisión previa | ||
electronica:arduino:valvula [2016/08/21 21:19] – creado lc | electronica:arduino:valvula [2023/01/18 14:36] (actual) – editor externo 127.0.0.1 | ||
---|---|---|---|
Línea 1: | Línea 1: | ||
+ | {{tag> | ||
===== 5. Electroválvulas ===== | ===== 5. Electroválvulas ===== | ||
En nuestro anterior proyecto teníamos un pequeño motor para regar independientemente de una toma de agua. Ahora lo vamos a modificar para conectarlo a una o varias tomas de agua y que sean unas electroválvulas las que al abrir o cerrar, dejen pasar el agua de la toma para regar nuestro huerto. | En nuestro anterior proyecto teníamos un pequeño motor para regar independientemente de una toma de agua. Ahora lo vamos a modificar para conectarlo a una o varias tomas de agua y que sean unas electroválvulas las que al abrir o cerrar, dejen pasar el agua de la toma para regar nuestro huerto. | ||
+ | |||
+ | El esquema es idéntico al anterior, sólo necesitamos sustituir el motor por una placa de relés, que nos permita encender y apagar las electroválvulas que funcionan a 12 V . | ||
+ | |||
+ | < | ||
+ | |||
+ | En mi caso he comprado la siguiente placa de cuatro relés que permiten un máximo de 10A a 30VDC o 10 A a 250VAC.{{ : | ||
+ | |||
+ | El esquema quedaría de la siguiente forma: | ||
+ | {{ : | ||
+ | |||
+ | Y modificamos el código : | ||
+ | <sxh javascript> | ||
+ | //// wiki.intrusos.info | ||
+ | // modificación del código de http:// | ||
+ | // riego v1.6 se cambia el motor por un relé de 4 salidas conectadas a electrválvulas | ||
+ | |||
+ | |||
+ | // | ||
+ | #include " | ||
+ | #define DHTPIN 2 // Pin del Arduino al cual esta conectado el pin 2 del sensor | ||
+ | // Descomentar segun el tipo de sensor DHT usado | ||
+ | #define DHTTYPE DHT11 // DHT 11 | ||
+ | DHT dht(DHTPIN, DHTTYPE);// Inicializa el sensor | ||
+ | |||
+ | // | ||
+ | #include < | ||
+ | // Inicializa el objeto LCD con los pines de la interfaz | ||
+ | LiquidCrystal lcd(8, 9, 4, 5, 6, 7); | ||
+ | |||
+ | // | ||
+ | byte pinRele1 = 10; | ||
+ | byte pinRele2 = 11; | ||
+ | byte pinRele3 = 12; | ||
+ | byte pinRele4 = 13; | ||
+ | |||
+ | |||
+ | |||
+ | |||
+ | // Pines analógicos | ||
+ | byte pinSensorHumedad = 1; | ||
+ | |||
+ | // definición teclado | ||
+ | int lcd_key | ||
+ | int adc_key_in | ||
+ | #define btnRIGHT | ||
+ | #define btnUP 1 | ||
+ | #define btnDOWN | ||
+ | #define btnLEFT | ||
+ | #define btnSELECT 4 | ||
+ | #define btnNONE | ||
+ | |||
+ | // Constantes para los posibles modos de funcionamiento | ||
+ | byte MODO_TIEMPO_HUMEDAD = 0; | ||
+ | byte MODO_SOLO_TIEMPO = 1; | ||
+ | byte MODO_SOLO_HUMEDAD = 2; | ||
+ | |||
+ | |||
+ | int modoElegido = 0; // Modo de funcionamiento | ||
+ | |||
+ | int umbralHumedad = 0; // Umbral de humedad seleccionado para empezar a regar | ||
+ | |||
+ | int diasTemporizacion = 0; | ||
+ | int horasTemporizacion = 0; | ||
+ | int minutosTemporizacion = 0; | ||
+ | |||
+ | int duracionRiego = 0; // Duración del riego en segundos una vez alcanzado el evento de activación | ||
+ | |||
+ | String linea1; | ||
+ | String linea2; | ||
+ | |||
+ | int humedadMinima = 0; // Lectura mínima por defecto para el sensor de humedad (se ajusta dinámicamente) | ||
+ | int humedadMaxima = 100; // Lectura máxima por defecto para el sensor de humedad (se ajusta dinámicamente) | ||
+ | |||
+ | int lecturasHumedad[10]; | ||
+ | int indiceLecturasHumedad = 0; // Indice para saber que valor toca rellenar del array previo | ||
+ | boolean mediaLista = false; // Indicador de que ya están rellenos los 10 valores del array | ||
+ | int mediaHumedad = 0; // Media de las últimas 10 lecturas de humedad | ||
+ | int riegos = 0; // Numero de riegos realizados | ||
+ | int limiteRiegos = 10; // Limite de seguridad del número de riegos | ||
+ | |||
+ | int read_LCD_buttons(); | ||
+ | |||
+ | int read_LCD_buttons() | ||
+ | { adc_key_in = analogRead(0); | ||
+ | if (adc_key_in > 900) return btnNONE; | ||
+ | if (adc_key_in < 50) | ||
+ | if (adc_key_in < 200) return btnUP; | ||
+ | if (adc_key_in < 400) return btnDOWN; | ||
+ | if (adc_key_in < 600) return btnLEFT; | ||
+ | if (adc_key_in < 800) return btnSELECT; | ||
+ | return btnNONE; | ||
+ | } | ||
+ | |||
+ | |||
+ | // | ||
+ | void setup() | ||
+ | { | ||
+ | |||
+ | // Inicializa el número de columnas y filas del LCD | ||
+ | lcd.begin(16, | ||
+ | |||
+ | // Inicializamos los reles | ||
+ | pinMode(pinRele1, | ||
+ | pinMode(pinRele2, | ||
+ | pinMode(pinRele3, | ||
+ | pinMode(pinRele4, | ||
+ | |||
+ | //Asegurar nivel ALTO en cada entrada de rele | ||
+ | // los reles se activan con nivel BAJO (0) | ||
+ | digitalWrite (pinRele1, RELAY_OFF); | ||
+ | digitalWrite (pinRele2, RELAY_OFF); | ||
+ | digitalWrite (pinRele3, RELAY_OFF); | ||
+ | digitalWrite (pinRele4, RELAY_OFF); | ||
+ | |||
+ | // Activa el led rojo y muestra la pregunta sobre el modo en el que va a funcionar | ||
+ | mostrarPregunta(modoElegido); | ||
+ | |||
+ | // Pregunta por el modo de funcionamiento: | ||
+ | boolean respuesta = false; | ||
+ | while (!respuesta) | ||
+ | { | ||
+ | lcd_key = read_LCD_buttons(); | ||
+ | delay(200); | ||
+ | if ( lcd_key == btnDOWN) | ||
+ | { | ||
+ | modoElegido--; | ||
+ | if (modoElegido == -1) modoElegido = 2; | ||
+ | mostrarPregunta(modoElegido); | ||
+ | } | ||
+ | else if ( lcd_key == btnUP) | ||
+ | { | ||
+ | modoElegido++; | ||
+ | if (modoElegido == 3) modoElegido = 0; | ||
+ | mostrarPregunta(modoElegido); | ||
+ | } | ||
+ | else if ( lcd_key == btnSELECT) | ||
+ | { | ||
+ | respuesta = true; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | |||
+ | // Si el modo elegido incluye riego por tiempo, pregunta cada cuantos días, horas y minutos | ||
+ | if (modoElegido == MODO_TIEMPO_HUMEDAD || modoElegido == MODO_SOLO_TIEMPO) | ||
+ | { | ||
+ | // No permite elegir un tiempo cero | ||
+ | while (diasTemporizacion + horasTemporizacion + minutosTemporizacion == 0) | ||
+ | { | ||
+ | diasTemporizacion = preguntarValor(" | ||
+ | horasTemporizacion = preguntarValor(" | ||
+ | minutosTemporizacion = preguntarValor(" | ||
+ | } | ||
+ | |||
+ | // Muestra un resumen del tiempo elegido | ||
+ | linea1 = " | ||
+ | linea2 = " | ||
+ | mostrarTexto(); | ||
+ | delay(1000); | ||
+ | } | ||
+ | |||
+ | // Si el modo elegido incluye riego por sensor de humedad, pregunta cual es el umbral de humedad para regar | ||
+ | if (modoElegido == MODO_TIEMPO_HUMEDAD || modoElegido == MODO_SOLO_HUMEDAD) | ||
+ | { | ||
+ | umbralHumedad = preguntarValor(" | ||
+ | } | ||
+ | |||
+ | // Pregunta cuantos segundos deberá durar el riego cuando se active | ||
+ | duracionRiego = preguntarValor(" | ||
+ | |||
+ | } | ||
+ | |||
+ | |||
+ | void loop() | ||
+ | { | ||
+ | // inicializa las variables de tiempo para el riego por temporización | ||
+ | int diasPendientes = diasTemporizacion; | ||
+ | int horasPendientes = horasTemporizacion; | ||
+ | int minutosPendientes = minutosTemporizacion; | ||
+ | int segundosPendientes = 0; | ||
+ | |||
+ | if (modoElegido == MODO_TIEMPO_HUMEDAD) | ||
+ | { | ||
+ | // Continua el bucle hasta que el tiempo llegue a cero | ||
+ | while ((diasPendientes + horasPendientes + minutosPendientes + segundosPendientes) > 0) | ||
+ | { | ||
+ | // Espera un segundo y decrementa las variables el equivalente a un segundo | ||
+ | delay(987); | ||
+ | segundosPendientes--; | ||
+ | if (segundosPendientes == -1) | ||
+ | { | ||
+ | segundosPendientes = 59; | ||
+ | minutosPendientes--; | ||
+ | } | ||
+ | if (minutosPendientes == -1) | ||
+ | { | ||
+ | minutosPendientes = 59; | ||
+ | horasPendientes--; | ||
+ | } | ||
+ | if (horasPendientes == -1) | ||
+ | { | ||
+ | horasPendientes = 23; | ||
+ | diasPendientes--; | ||
+ | } | ||
+ | |||
+ | // Actualiza la variable con la humedad actual | ||
+ | leerHumedad(); | ||
+ | |||
+ | // Actualiza el display con el tiempo hasta el siguiente riego y la humedad actual | ||
+ | linea1 = str(diasPendientes) + ":" | ||
+ | linea2 = " | ||
+ | mostrarTexto(); | ||
+ | |||
+ | // Si la media de humedad de las últimas 10 lecturas está lista y es inferior al umbral configurado, | ||
+ | if ((mediaHumedad < umbralHumedad) && mediaLista) | ||
+ | { | ||
+ | regar(); | ||
+ | // Reinicia la media de humedad para que le tiempo a la tierra a empaparse | ||
+ | indiceLecturasHumedad = 0; | ||
+ | mediaLista = false; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | // Activa lo bomba de riego durante el tiempo configurado | ||
+ | regar(); | ||
+ | } | ||
+ | else if (modoElegido == MODO_SOLO_TIEMPO) | ||
+ | { | ||
+ | // Continua el bucle hasta que el tiempo llegue a cero | ||
+ | while ((diasPendientes + horasPendientes + minutosPendientes + segundosPendientes) > 0) | ||
+ | { | ||
+ | delay(990); | ||
+ | segundosPendientes--; | ||
+ | if (segundosPendientes == -1) | ||
+ | { | ||
+ | segundosPendientes = 59; | ||
+ | minutosPendientes--; | ||
+ | } | ||
+ | if (minutosPendientes == -1) | ||
+ | { | ||
+ | minutosPendientes = 59; | ||
+ | horasPendientes--; | ||
+ | } | ||
+ | if (horasPendientes == -1) | ||
+ | { | ||
+ | horasPendientes = 23; | ||
+ | diasPendientes--; | ||
+ | } | ||
+ | |||
+ | // Actualiza el display con el tiempo hasta el siguiente riego | ||
+ | linea1 = " | ||
+ | linea2 = str(diasPendientes) + ":" | ||
+ | mostrarTexto(); | ||
+ | } | ||
+ | |||
+ | // Activa lo bomba de riego durante el tiempo configurado | ||
+ | regar(); | ||
+ | } | ||
+ | else if (modoElegido == MODO_SOLO_HUMEDAD) | ||
+ | { | ||
+ | while (true) | ||
+ | { | ||
+ | delay(1000); | ||
+ | |||
+ | // Actualiza la variable con la humedad actual | ||
+ | leerHumedad(); | ||
+ | |||
+ | // Actualiza el display con la humedad actual y el número de riegos efectuados hasta el momento | ||
+ | linea1 = " | ||
+ | linea2 = " | ||
+ | mostrarTexto(); | ||
+ | |||
+ | // Si la media de humedad de las últimas 10 lecturas está lista y es inferior al umbral configurado, | ||
+ | if ((mediaHumedad < umbralHumedad) && mediaLista) | ||
+ | { | ||
+ | regar(); | ||
+ | // Reinicia la media de humedad para que le tiempo a la tierra a empaparse | ||
+ | indiceLecturasHumedad = 0; | ||
+ | mediaLista = false; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | |||
+ | // Pregunta el modo de funcionamiento con la última opción elegida | ||
+ | void mostrarPregunta(byte modo) | ||
+ | { | ||
+ | lcd.clear(); | ||
+ | lcd.print(" | ||
+ | lcd.setCursor(0, | ||
+ | if (modo == MODO_TIEMPO_HUMEDAD) lcd.print(" | ||
+ | else if (modo == MODO_SOLO_TIEMPO) lcd.print(" | ||
+ | else if (modo == MODO_SOLO_HUMEDAD) lcd.print(" | ||
+ | } | ||
+ | |||
+ | // Muestra el texto configurado en el display | ||
+ | void mostrarTexto() | ||
+ | { | ||
+ | lcd.clear(); | ||
+ | lcd.print(linea1); | ||
+ | lcd.setCursor(0, | ||
+ | lcd.print(linea2); | ||
+ | } | ||
+ | |||
+ | |||
+ | // Muestra una pregunta y recoge un valor numérico | ||
+ | int preguntarValor(String texto, int inicial, int maximo) | ||
+ | { | ||
+ | linea1 = texto; | ||
+ | linea2 = str(inicial); | ||
+ | mostrarTexto(); | ||
+ | boolean respuesta = false; | ||
+ | int valor = inicial; | ||
+ | while (!respuesta) | ||
+ | { | ||
+ | lcd_key = read_LCD_buttons(); | ||
+ | delay(200); //para evitar lecturas seguidas | ||
+ | if ( lcd_key == btnDOWN) | ||
+ | { valor--; | ||
+ | if (valor == -1) valor = maximo; | ||
+ | linea2 = str(valor); | ||
+ | mostrarTexto(); | ||
+ | } | ||
+ | |||
+ | else if ( lcd_key == btnUP) | ||
+ | { | ||
+ | valor++; | ||
+ | if (valor > maximo) valor = 0; | ||
+ | linea2 = str(valor); | ||
+ | mostrarTexto(); | ||
+ | } | ||
+ | |||
+ | else if ( lcd_key == btnSELECT) | ||
+ | { | ||
+ | respuesta = true; | ||
+ | } | ||
+ | } | ||
+ | return valor; | ||
+ | } | ||
+ | |||
+ | // Devuelve una cadena numérica de al menos 2 caractes, rellenando con un cero por la izquierda si hace falta | ||
+ | String str(int valor) | ||
+ | { | ||
+ | if (valor < 10) return " | ||
+ | else return (String(valor)); | ||
+ | } | ||
+ | |||
+ | |||
+ | // Actualiza la variable con la media de humedad de las últimas 10 lecturas | ||
+ | void leerHumedad() | ||
+ | { | ||
+ | lecturasHumedad[indiceLecturasHumedad] = analogRead(pinSensorHumedad); | ||
+ | lecturasHumedad[indiceLecturasHumedad] = map (lecturasHumedad[indiceLecturasHumedad], | ||
+ | indiceLecturasHumedad++; | ||
+ | if (indiceLecturasHumedad > 9) | ||
+ | { | ||
+ | indiceLecturasHumedad = 0; | ||
+ | mediaLista = true; | ||
+ | } | ||
+ | |||
+ | mediaHumedad = 0; | ||
+ | for (int i = 0; i < 10; i++) mediaHumedad += lecturasHumedad[i]; | ||
+ | mediaHumedad /= 10; | ||
+ | if (mediaHumedad > humedadMaxima) humedadMaxima = mediaHumedad; | ||
+ | if (mediaHumedad < humedadMinima) humedadMinima = mediaHumedad; | ||
+ | mediaHumedad -= humedadMinima; | ||
+ | |||
+ | mediaHumedad = (double)((double)mediaHumedad / (double)(humedadMaxima - humedadMinima)) * 100; | ||
+ | if (mediaHumedad == 100) mediaHumedad = 99; | ||
+ | } | ||
+ | |||
+ | |||
+ | // Activa lo bomba de riego durante el tiempo configurado | ||
+ | void regar() | ||
+ | { | ||
+ | if (riegos == limiteRiegos) | ||
+ | { | ||
+ | linea1 = " - BLOQUEADO - "; | ||
+ | linea2 = " | ||
+ | mostrarTexto(); | ||
+ | while (true) { | ||
+ | delay(999999); | ||
+ | } | ||
+ | } | ||
+ | int riegoPendiente = duracionRiego; | ||
+ | digitalWrite(pinRele1, | ||
+ | digitalWrite(pinRele2, | ||
+ | digitalWrite(pinRele3, | ||
+ | digitalWrite(pinRele4, | ||
+ | while (riegoPendiente > 0) | ||
+ | { | ||
+ | linea1 = " -- REGANDO -- "; | ||
+ | linea2 = " | ||
+ | mostrarTexto(); | ||
+ | delay(990); | ||
+ | riegoPendiente--; | ||
+ | } | ||
+ | digitalWrite(pinRele1, | ||
+ | digitalWrite(pinRele2, | ||
+ | digitalWrite(pinRele3, | ||
+ | digitalWrite(pinRele4, | ||
+ | riegos++; | ||
+ | } | ||
+ | </ | ||
+ | ==== Referencias ==== | ||
+ | * http:// |