Manufactura industrial
Internet industrial de las cosas | Materiales industriales | Mantenimiento y reparación de equipos | Programación industrial |
home  MfgRobots >> Manufactura industrial >  >> Manufacturing Technology >> Proceso de manufactura

Controlador de riego inteligente

Componentes y suministros

Arduino Nano R3
× 1
Expansor IO
× 1
Paquete expansor IO
× 1

Aplicaciones y servicios en línea

Arduino IDE

Acerca de este proyecto

Cree un controlador de riego inteligente con Arduino

Riegue de forma inteligente su jardín con ciclos de agua dinámicos. Deje de regar su jardín si está lloviendo o ha llovido desde la última vez que lo riegue. Utilice el sensor de luz para detectar la hora del amanecer y ajustar automáticamente las horas de inicio del agua en consecuencia. Deje de regar su jardín si hace demasiado frío.

Lista de funciones

  • Sensor de temperatura exterior
  • Sensor de lluvia exterior
  • Sensor de luz exterior
  • Reloj en tiempo real con batería para programación semanal
  • Almacenamiento no volátil:nunca pierda el riego debido a la pérdida de energía
  • Detección de amanecer
  • El riego inteligente ahorra en su factura de agua
  • Riegue antes del amanecer para permitir un tiempo de remojo adecuado
  • Deje de regar cuando hace demasiado frío afuera
  • Reducir el crecimiento de hongos
  • Fácil control de horarios

Piezas necesarias para construir el controlador de riego inteligente

  • Expansor de IO
  • x2 1-Wire a I2C.
  • Unión de 1 cable
  • Conector óptico
  • Divisor
  • Arduino Nano.
  • Relé de 4 canales DC 5V.
  • Sensor de luz TSL2561.
  • Sensor de temperatura impermeable DS18B20.
  • Sensor de nivel de agua infrarrojo óptico.
  • DS3231 AT24C32 IIC Reloj de precisión en tiempo real.
  • Pantalla I2C SSD1306 OLED 128x64.
  • Caja de plástico transparente impermeable de 200x120x75 mm.
  • Caja de plástico transparente impermeable de 100x68x50 mm.
  • Prensaestopas de nailon impermeable ip68 pg7.
  • Prensaestopas de nailon impermeable ip68 pg11.
  • Conector de terminal de tornillo Keystone RJ11.
  • Cable RJ11 4C4P de 50 pies.
  • Cable RJ11 4C4P de 6 pies.
  • Cable de cabecera de 2,54 mm.
  • x2 Microinterruptor de botón pulsador momentáneo SPST de 2 pines
  • Fuente de alimentación con adaptador de pared de 12VDC 1A.

Diagrama de cableado

Pantalla OLED

Presione el botón Menú para mostrar el menú y continúe presionando el botón para recorrer todas las opciones del menú. El menú se eliminará automáticamente después de 30 segundos de inactividad. Presione el botón Seleccionar para realizar la función de menú deseada.

Entonces, ¿por qué utilizar el expansor IO?

  • Más sencillo de diseñar
  • Piezas disponibles en el mercado
  • No hay controlador de 1 cable para escribir
  • No hay controlador DS3231 RTC para escribir
  • Sin controlador EEPROM para escribir
  • Sin controlador de pantalla OLED para escribir
  • No hay fuentes de visualización para ocupar el espacio del código Arduino
  • Sin controlador de sensor de temperatura para escribir
  • No hay ningún secador de sensor de lluvia óptico para escribir
  • Ahorra espacio de código en Arduino; solo 12710 bytes (39%)
  • Solo tres días para escribir el código
  • Fácil de conectar con un cable telefónico RJ11 estándar
  • Sin problemas de longitud del cable del sensor
  • Más barato de construir que sistemas comerciales similares
  • Fácil de realizar cambios para adaptarse a los requisitos individuales
  • Fuente de alimentación única

Construya el sistema

Conecte el Arduino Nano al IO Expander y prográmelo con el siguiente código. El encabezado de 6 pines es el puerto de depuración en serie del software y no es necesario en la instalación final.

Asegúrese de cambiar la dirección definida ONEWIRE_TO_I2C_ROM1 y ONEWIRE-TO_I2C_ROM2 para que coincida con su dirección 1-Wire con I2C.

  / * IO Expander sketch optimizado 
*
* Sistema de riego v1.1
*
* /

#include
#include // Archivo ubicado \ Archivos de programa (x86) \ Arduino \ hardware \ tools \ avr \ avr \ include \ time.h
#include
#include
#include
#include "IOExpander.h"

#define FAHRENHEIT
# define INIT_BOARD "g5w1; g11w1; g11d0,75; g12w1; g12d0,75; rsf"
#define ONEWIRE_TO_I2C_ROM1 "i4scc"
#define ONEWIRE_TO_I2C_ROM_REf2 "ONEWIRE # "t6s0300"
#define RTC_SENSOR "s4te"
#define I2C_EEPROM "s4tf"
#define I2C_OLED "s4t10"
#define I2C_LIGHT "s3t9; sc0"
# define OPTICAL_SENSOR "g5a"
#define BUTTON1 "g11d"
#define BUTTON2 "g12d"

#define WATER_TIME_BEFORE_SUNRISE 60
#define SUNRISE_LUX 100
# define RAIN_DETECT_LEVEL 4.0
#define DO_NOT_WATER_TEMP 4.4444 // 40F

#define MAX_ZONES 4

#define HOUR_IN_DA Y 24L
#define MIN_IN_HOUR 60L
#define SEC_IN_MIN 60L
#define SEC_IN_HOUR (MIN_IN_HOUR * SEC_IN_MIN)
#define SEC_IN_DAY (HOUR_IN_DAY * SEC_IN_HORA)
#define
#define SEC_IN_WEEK (SEC_IN_DAY * DAYS_IN_WEEK)

#define SUN 0x01
#define LUN 0x02
#define TUE 0x04
#define WED 0x08
# define THR 0x10
#define VIE 0x20
#define SAT 0x40
#define TODOS LOS DÍAS (DOM | MON | MAR | MIÉ | THR | FRI | SAT)

#define SUNRISE 0x80

#define MENU_OPTIONS 9
#define MENU_TIME 30

#define OFF 0
#define ON 1

#define STATE_ON_OFF 0x01

// # define SERIAL_DEBUG

#ifdef SERIAL_DEBUG
SoftwareSerial swSerial (8,7 );
#endif

char weekday [] [4] ={"DOM", "LUN", "MAR", "MIE", "JUE", "VIE", " SAT "};

menú de caracteres [] [13] ={" Siguiente ",
" Agua ",
" Restablecer ",
" Reloj Min + " ,
"Minuto del reloj -",
"Hora del reloj +",
"Hora del reloj -",
"Salida del sol",
"ENCENDIDO / APAGADO"};

enumeración {
MENU_NEXT,
MENU_WATER,
MENU_RESET,
MENU_CLOCK_MIN_PLUS,
MENU_CLOCK_MIN_MINUS,
MENU_CLOCK_HOUR_PLUS,
MENU_CLOCK_HOUR_MINUS,
MENU_SUNRISE,
MENU_ON_OFF
};

typedef struct {
char description [16];
uint8_t relay;
} ZONE;

typedef struct {
uint8_t zone;
uint8_t days;
int8_t hour;
int8_t min;
uint8_t duration;
} SCHEDULE;

typedef struct {
time_t sunrise_time;
time_t last_water_time;
uint8_t water_schedule;
uint8_t water_duration;
uint8_t rain [MAX_ZONES];
uint8_t state;
uint8_t crc;
} NVRAM;

enumeración {
ZONE1,
ZONE2,
ZONE3,
ZONE4
};

enumeración {
RELAY1 =1,
RELAY2,
RELAY3,
RELAY4
};

ZONE zone [] ={
{"Front Right", RELAY1},
{"Front Left", RELAY2},
{"Bush", RELAY3},
{"Lado izquierdo", RELAY4},
};

HORARIO horario [] ={
{ZONE1, SUNRISE | TODOS LOS DÍAS, -1, 0, 4},
{ZONE2, TODOS LOS DÍAS, 6, 15, 5},
{ZONE3, TODOS LOS DÍAS, 6, 0, 10},
{ZONE4, TODOS LOS DÍAS , 6, 10, 6},
};

NVRAM nvram;
bool update_nvram =false;

uint8_t crc8 (uint8_t * datos, uint16_t length)
{
uint8_t crc =0;

while (length--) {
crc =_crc8_ccitt_update (crc, * data ++);
}
return crc;
}

int led =13;
bool init_oled =true;
bool update_oled =true;
bool init_board =true;

#ifdef FAHRENHEIT
#define C2F (temp) CelsiusToFahrenheit (temp)
float CelsiusToFahrenheit (float celsius)
{
return ((celsius * 9) / 5) + 32;
}
#else
#define C2F (temp) (temp)
#endif

void SerialPrint ( const char * str, float decimal, char error)
{
Serial.print (str);
if (error) Serial.print (F ("NA"));
else Serial.print (decimal, 1);
}

time_t NextScheduleTime (time_t last_time, uint8_t * next_schedule)
{
time_t next_time =-1;
time_t clk_time;
uint8_t i;
tm clk;
uint8_t wday;

for (i =0; i if (schedule [i] .days &SUNRISE) {
clk_time =nvram.sunrise_time;
clk_time + =schedule [i] .hour * SEC_IN_HOUR;
clk_time + =programar [i] .min * SEC_IN_MIN;
localtime_r (&clk_time, &clk);
}
else {
localtime_r (&last_time, &clk);
clk. tm_hour =horario [i] .hora;
clk.tm_min =horario [i] .min;
clk.tm_sec =0;
clk_time =mktime (&clk);
}
wday =clk.tm_wday;
while (clk_time <=last_time ||! (horario [i] .days &(1 < {
clk_time + =SEC_IN_DAY;
if (++ wday> SATURDAY) wday =DOMINGO;
if (wday ==clk.tm_wday) break; // Solo verifique una semana
}
if (clk_time next_time =clk_time;
* next_schedule =i;
}
}
return next_time;
}

void StartScheduleTime (time_t start_time, uint8_t start_schedule)
{
uint8_t i;

nvram. last_water_time =start_time;
nvram.water_schedule =start_schedule;
nvram.water_duration =schedule [start_schedule] .duration + 1;
update_nvram =true;
// Compruebe si llovió
i =schedule [start_schedule] .zone;
if (i 0) {
if (nvram.rain [i]> nvram.water_duration) nvram .water_duration =0;
más nvram.water_duration - =nvram.rain [i];
nvram.rain [i] =0;
}
}

void WaterScheduleTime (void)
{
uint8_t i;

nvram.water_duration--;
update_nvram =true;
i =horario [ nvram.water_schedule] .zone;
if (i Serial.print ("r");
Serial.print (zona [i] .relay);
if (nvram.water_duration> 0) Serial.println ("o");
else Serial.println ("f");
SerialReadUntilDone ();
}
}

void setup () {
Serial.begin (115200);
#ifdef SERIAL_DEBUG
swSerial.begin (115200);
#endif
pinMode (led, SALIDA);
// retardo (1000);
wdt_enable (WDTO_8S);
}

bucle vacío () {
static tm rtc;
tm clk, sunrise_clk;
time_t rtc_time;
time_t clk_time;
static time_t next_time;
static uint8_t last_sec;
static uint8_t last_min;
bool error_rtc;
bool error_light;
bool error_temp;
static long lux =0;
static float temp, rain;
static uint8_t sunrise_counter =MIN_IN_HOUR;
static bool check_sunrise =false;
uint8_t i;
static bool read_nvram =true;
static time_t water_time;
static uint8_t water_schedule;
uint8_t sz;
uint8_t wday;
long n;
bool button1, button2;
static int8_t menu_select =-1;
static time_t menu_time =0;

Serial.println ();
if (SerialReadUntilDone ()) {
if (init_board) {
SerialCmdDone (INIT_BOARD);
init_board =false;
}

if (init_oled) {
if (SerialCmdNoError (ONEWIRE_TO_I2C_ROM1)) {
SerialCmdDone (I2C_OLED "; si; sc; sd");
init_oled =false;
}
}

if (SerialCmdDone (RTC_SENSOR)) {
error_rtc =! SerialReadTime (&rtc);
if (! error_rtc) {
clk =rtc; // mktime () puede cambiar la estructura tm
rtc_time =mktime (&clk);
localtime_r (&rtc_time, &rtc); // Obtener wday.
}

if (read_nvram) {
if (SerialCmdNoError (I2C_EEPROM)) {
SerialReadEEPROM ((uint8_t *) &nvram, 0, sizeof (nvram));
if (nvram.crc! =crc8 ((uint8_t *) &nvram, sizeof (nvram) -sizeof (uint8_t))) {
//swSerial.println("CRC8 Failure! ");
// Inicializar nvram
memset (&nvram, 0, sizeof (nvram));
clk =rtc;
clk.tm_hour =6;
clk .tm_min =0;
clk.tm_sec =0;
nvram.sunrise_time =mktime (&clk);
if (nvram.sunrise_time update_nvram =true;
}
// Verifique la última hora de riego no menos de una semana
if (rtc_time - nvram.last_water_time> SEC_IN_WEEK) nvram.last_water_time =rtc_time - SEC_IN_WEEK;
// Verifica la hora del amanecer
if (rtc_time> nvram.sunrise_time) {
localtime_r (&nvram.sunrise_time, &sunrise_clk);
clk =rtc;
clk.tm_hour =sunrise_clk.tm_hour;
clk.tm_min =amanecer_clk.tm_min;
clk.tm_sec =amanecer_clk.tm_sec;
nvram.sunrise_time =mktime (&clk);
if (nvram.sunrise_time }
if (nvram.water_duration) {
nvram. water_duration ++;
water_time =nvram.last_water_time;
}
else {
clk_time =(nvram.last_water_time)? nvram.last_water_time:rtc_time;
water_time =NextScheduleTime (clk_time, &water_schedule);
}
read_nvram =false;
}
}
}

// Procese solo una vez por minuto
if (rtc.tm_min! =last_min)
{
// Solicite una medición de temperatura de 1 cable. Léalo más tarde.
error_temp =! SerialCmdNoError (ONEWIRE_TEMPERATURE);
if (! Error_temp) SerialCmdDone ("tt");

error_light =! SerialCmdNoError (ONEWIRE_TO_I2C_o0 "; );
if (! error_light) {
SerialCmdDone (I2C_LIGHT); // No use overdrive
SerialCmd ("sr");
SerialReadInt (&lux);
SerialReadUntilDone ();
}

if (SerialCmd (OPTICAL_SENSOR)) {
SerialReadFloat (&rain);
SerialReadUntilDone ();
}

error_temp =! SerialCmdNoError (ONEWIRE_TEMPERATURE);
if (! error_temp) {
SerialCmd ("tr");
SerialReadFloat (&temp);
SerialReadUntilDone ();
}

// ¿Está amaneciendo?
if (lux if (sunrise_counter> 0) sunrise_counter--;
else check_sunrise =true;
}
else {
if (amanecer_contador amanecer_contador ++;
if (check_sunrise &&sunrise_counter ==MIN_IN_HOUR) {
nvram.sunrise_time =rtc_time + (SEC_IN_DAY - SEC_IN_HOUR);
check_sunrise =false;
update_nvram =true;
}
}
}

// ¿Está lloviendo?
if (rain <=RAIN_DETECT_LEVEL) {
para (i =0; i if (nvram.rain [i] <-1) nvram.rain [i] ++; }
update_nvram =true;
}

// Verifique el horario
if (menu_select ==-1 &&! nvram.water_duration) {
while (water_time + (schedule [water_schedule] .duration * SEC_IN_MIN) water_time =NextScheduleTime (water_time, &water_schedule);
}
if (water_time <=rtc_time) {
StartScheduleTime (tiempo_del_agua, programa_del_agua);
if (temp <=DO_NOT_WATER_TEMP || nvram.state &STATE_ON_OFF ==OFF)
nvram.water_duration =0;
}
}

// ¿Necesitamos regar?
if (nvram.water_duration) {
WaterScheduleTime ();
if (! nvram.water_duration)
water_time =NextScheduleTime (water_time, &water_schedule);
}

last_min =rtc.tm_min;
update_oled =true;
}

// Comprobar botones
button1 =SerialReadButton (BUTTON1);
if (button1 ) {
if (menu_select ==-1) menu_select =0;
else {
if (++ menu_select> =MENU_OPTIONS)
menu_select =0;
}
menu_time =rtc_time;
update_oled =true;
}
if (menu_select> =0) {
button2 =SerialReadButton (BUTTON2);
if ( button2) {
clk_time =rtc_time;
switch (menu_select) {
case MENU_NEXT:
case MENU_RESET:
if (nvram.water_duration) {
nvram .water_duration =1;
WaterScheduleTime ();
}
water_time =NextScheduleTime ((menu_select ==MENU_NEXT) ? water_time:rtc_time, &water_schedule);
break;
case MENU_WATER:
StartScheduleTime (water_time, water_schedule);
WaterScheduleTime ();
break;
case MENU_CLOCK_MIN_PLUS:
clk_time + =SEC_IN_MIN;
descanso;
caso MENU_CLOCK_MIN_MINUS:
clk_time - =SEC_IN_MIN;
descanso;
caso MENU_CLOCK_HOUR_PLUS:
clk_time + =SEC_IN_HOUR;
descanso;
caso MENU_CLOCK_HOUR_MINUS:
clk_time - =SEC_IN_HOUR;
descanso;
caso MENU_ON_OFF:
nvram.state ^ =STATE_ON_OFF;
update_nvram =true;
break;
}
if (clk_time! =rtc_time) {
if (SerialCmdDone (RTC_SENSOR)) {
localtime_r ( &clk_time, &clk);
SerialWriteTime (&clk);
rtc_time =clk_time;
}
}
menu_time =rtc_time;
update_oled =true;
}
}
if (menu_select> =0 &&rtc_time - menu_time> MENU_TIME) {
menu_select =-1;
update_oled =true;
}

if (update_oled) {
if (S erialCmdNoError (ONEWIRE_TO_I2C_ROM1)) {
Serial.print ("st10; so1; sc; sf0; sa0; sd0,0, \" ");
if (nvram.water_duration) Serial.print (nvram. water_duration);
else {
if ((nvram.state &STATE_ON_OFF) ==OFF) Serial.print ("OFF");
else if (rain <=RAIN_DETECT_LEVEL) Serial.print ("Lluvia");
else if (temp <=DO_NOT_WATER_TEMP) Serial.print ("Cold");
else Serial.print ("v1.1");
}
Serial.print ("\"; sf2; sa1; sd75,0, \ "");
if (menu_select ==7) {// Amanecer
clk_time =nvram.sunrise_time;
localtime_r (&clk_time, &clk);
}
else clk =rtc;
Serial.print (clk.tm_hour - ((clk.tm_hour> 12)? 12:0));
Serial.print (":");
if (clk.tm_min <10) Serial.print ("0");
Serial.print (clk.tm_min);
Serial.println ("\" ");
SerialReadUntilDone ();

Serial.print (" sf1; sa0; sd79,8, \ "");
Serial .print ((clk.tm_hour> 12)? "PM":"AM");
Serial.print ("\"; sf0; sa1; sd127,1, \ "");
Serial .print (día de la semana [clk.tm_wday]);
Serial.print ("\"; sd127,13, \ "");
Serial.print (clk.tm_mon + 1);
Serial.print ("/");
Serial.print (clk.tm_mday);
Serial.println ("\" ");
SerialReadUntilDone ();

Serial.print (" sf0; sa0; sd1 , 36, \ "");
i =schedule [water_schedule] .zone;
if (i localtime_r (&water_time , &clk);
if (water_time - rtc_time> SEC_IN_DAY) {
Serial.print ("\"; sa1; sd126,36, \ "");
Serial.print (clk. tm_mon + 1);
Serial.print ("/");
Serial.print (clk.tm_mday);
Serial.print ("");
Serial.print (clk.tm_hour - ((clk.tm_hour> 12)? 12:0));
Serial.print (":");
if (clk.tm_min <10) Serial.print (" 0 ");
Serial.print (clk.tm_min);
Serial.print (" ");
}
else {
Serial.print (" \ "; sf1; sa1; sd111,30, \" ");
Serial.print (clk.tm_hour - ((clk.tm_hour> 12)? 12:0));
Serial.print ( ":");
if (clk.tm_min <10) Serial.print ("0");
Serial.print (clk.tm_min);
Seria l.print ("\"; sf0; sd126,36, \ "");
}
Serial.print ((clk.tm_hour> 12)? "PM":"AM");
if (nvram.water_duration) Serial.print ("\"; so2; sc0,29,128,19 ");
Serial.println ();
SerialReadUntilDone ();

if (menu_select ==-1) {
//Serial.print ("\"; sa0; sd0,52, \ "");
//Serial.print(rain);
SerialPrint ("\"; so1; sa2; sd63,52, \ "", C2F (temp), error_temp);
if (! error_temp) Serial.print ("\", 248, \ ""
#ifdef FAHRENHEIT
"F"
#else
"C"
#endif
);
Serial.print (" / ");
Serial.print (lux);
}
else {
Serial.print (" \ "; so0; sc0,51,128,14; sf0; sa2; sd63,52, \ "");
if (menu_select ==MENU_ON_OFF) {
Serial.print ((nvram.state &STATE_ON_OFF)? "OFF":"ON");
}
más Serial.print (menú [menu_select]);
}
Serial.println ("\"; sd ");
SerialReadUntilDone ();
update_oled =false;
}
else init_oled =true;
}

if (update_nvram) {
if (SerialCmdNoError (I2C_EEPROM)) {
nvram.crc =crc8 ((uint8_t *) &nvram, sizeof (nvram) -sizeof (uint8_t));
//swSerial.println(nvram.crc , HEX);
SerialWriteEEPROM ((uint8_t *) &nvram, 0, sizeof (nvram));
update_nvram =false;
}
}

delay (50);
}
else {
digitalWrite (led, HIGH);
delay (500);
digitalWrite (led, LOW);
delay (500);
init_board =true;
init_oled =true;
}
wdt_reset ();
}

Nota: Si usa el puerto USB para programar el Arduino Nano, debe desconectarlo del IO Expander, ya que también está usando el mismo puerto serie único, en cambio, si desea depurar, use el puerto ICSP para programar el ATmega328P. Para habilitar el puerto de depuración del software, elimine el comentario de la definición SERIAL_DEBUG.

El divisor debe configurarse primero para aislar la línea de datos del sensor de infrarrojos óptico de la línea del sensor remoto de 1 cable. Suelde en un resistor 0603 de cero ohmios en R2.

Taladre un orificio de 7/16 "en el gabinete pequeño y un orificio de 11/16" en el gabinete más grande en el lado derecho para el PG7 y el PG11. Utilice una herramienta dremel para agrandar ligeramente los orificios hasta que el casquillo encaje perfectamente. El PG7 alimentará los sensores remotos y el PG11 para los cables del colector de 12VDC, 24VAC, y el cable de los sensores remotos RJ11.

Conecte el microinterruptor de botón momentáneo SPST y conéctelo al terminal de tornillo RJ11. Utilice tubos termorretráctiles para aislar los contactos.

Conecte todos los cables y ensamble / alimente todas las partes en el gabinete grande. Su cable RJ11 de 50 pies para los sensores remotos debe pasar a través del casquillo PG11 sin tener que cortarlo.

Taladre un orificio de 9/16 "en la parte superior del gabinete pequeño para el sensor de agua infrarrojo óptico. Utilice una herramienta dremel para agrandar el orificio un poco hasta que el sensor encaje. El gabinete del sensor remoto pequeño encaja bien, pero si el contenido están colocados en la orientación recomendada, debería encajar. Hacer los cables RJ11 lo más cortos posible ayudará a meterlo todo en el gabinete más pequeño. Una vez ensamblado, se recomienda agregar un poco de pegamento marino en la arandela de la tuerca del prensaestopas antes de atornillar la tuerca, para crear un mejor sello.

Instale el gabinete del sensor remoto en el exterior y móntelo elevado en el lado este de su casa con el sensor de agua infrarrojo óptico y el sensor de luz apuntando hacia el cielo sin obstrucciones.

Taladre orificios de 1/4 "en la parte superior media inferior del gabinete grande y monte los botones. Utilice una herramienta dremel para agrandar el orificio ligeramente hasta que los botones encajen.

Pruebe el sistema y asegúrese de que todo funcione correctamente. Para probar el relé y los sensores, desconecte el Arduino del expansor IO y conéctelo directamente a su computadora para controlarlo manualmente. Una vez que haya verificado que todo está funcionando, ensamble todas las piezas en el gabinete con cinta adhesiva de doble cara y espuma de embalaje para asegurar sus tablas, y disfrute de los beneficios y ahorros de su controlador de riego inteligente.

Video en funcionamiento

Actualización 12/09/2019

Lanzamiento v1.1 que solucionó un problema de inicio si el sistema se quedaba sin energía durante varios días.

Actualización 2/10/2019

Cuando conecte el 1-Wire a I2C al DS3231 y luego a la pantalla OLED SSD1306, tendrá un total de tres pullups diferentes en las líneas SDA y SCL como se muestra en la imagen a continuación en un círculo. Esto dará como resultado un pullup de 4.7k / 3 =1.56k que puede ser demasiado fuerte y provocar daños en la pantalla aleatoria.

Dado que el DS3231 utiliza un paquete de resistencias que utilizan otras líneas, elimine las otras resistencias pullup:

  • 1 cable a I2C R3 y R4.
  • SSD1306 OLED R6 y R7.

Código

  • Controlador de riego inteligente
Controlador de riego inteligente C / C ++
Use su Arduino para regar inteligentemente su patio o jardín.
 / * IO Expander sketch optimizado * * Irrigation System v1.1 * * / # include  #include  // Archivo ubicado \ Programa Archivos (x86) \ Arduino \ hardware \ tools \ avr \ avr \ include \ time.h # include  #include  #include  #include "IOExpander. h "#define FAHRENHEIT # define INIT_BOARD" g5w1; g11w1; g11d0,75; g12w1; g12d0,75; rsf "#define ONEWIRE_TO_I2C_ROM1" i4scc "#define ONEWIRE_TO_EWI2COR8" s define I2C_EEPROM "s4tf" #define I2C_OLED "s4t10" #define I2C_LIGHT "s3t9; sc0" #define OPTICAL_SENSOR "g5a" #define BUTTON1 "g11d" #define BUTTON2 "g12EFE" #definir_definir_definir define DO_NOT_WATER_TEMP 4.4444 // 40F # define MAX_ZONES 4 # define HOUR_IN_DAY 24L # define MIN_IN_HOUR 60L # define SEC_IN_MIN 60L # define SEC_IN_HOUR (MIN_IN_HOUR * SEC_IN_MIN) #define SEC_IN_DAY (HOUR_IN_DAY * NUESTRO) #define DAYS_IN_WEEK 7 # define SEC_IN_WEEK (SEC_IN_DAY * DAYS_IN_WEEK) #define SUN 0x01 # define LUN 0x02 # define TUE 0x04 # define WED 0x08 # define THR 0x10 # define VIE 0x20 # define SUNYDAY # define SUN MON | MAR | MIÉ | THR | FRI | SAT) #define SUNRISE 0x80 # define MENU_OPTIONS 9 # define MENU_TIME 30 # define OFF 0 # define ON 1 # define STATE_ON_OFF 0x01 // # define SERIAL_DEBUG # ifdef SERIAL_DEBUGSoftwareSerial swSerial (8,7); # endifchar día de la semana [] [4] ={"DOM", "LUN", "MAR", "MIÉ", "JUE", "VIE", "SÁB"}; menú de caracteres [] [13] ={"Siguiente", "Agua", "Restablecer" , "Clock Min +", "Clock Min -", "Clock Hour +", "Clock Hour -", "Sunrise", "ON / OFF"}; enumeración {MENU_NEXT, MENU_WATER, MENU_RESET, MENU_CLOCK_MIN_PLUS, MENU_CLOCK_MIN_MINUS, MENU_CLOCK_HOUR_PLUS, MENU_CLOCK_HOUR_MINUS, MENU_SUNRISE, MENU_ON_OFF}; typedef struct {char descripción [16]; uint8_t relé;} ZONE; typedef struct {uint8_t zone; uint8_t días; int8_t hora; int8_t min; uint8_t duración;} HORARIO; typedef struct {time_t sunrise_time; time_t last_water_time; uint8_t water_schedule; uint8_t water_duration; uint8_t lluvia [MAX_ZONES]; estado uint8_t; uint8_t crc;} NVRAM; enumeración {ZONE1, ZONE2, ZONE3, ZONE4}; enumeración {RELAY1 =1, RELAY2, RELAY3, RELAY4}; ZONE zone [] ={{"Front Right", RELAY1}, {"Front Left" , RELÉ2}, {"Arbustos", RELÉ3}, {"Lado izquierdo", RELÉ4},}; HORARIO horario [] ={{ZONA1, SALIDA DEL SOL | TODOS LOS DÍAS, -1, 0, 4}, {ZONA2, TODOS LOS DÍAS, 6, 15, 5}, {ZONA3, TODOS LOS DÍAS, 6, 0, 10}, {ZONA4, TODOS LOS DÍAS, 6, 10, 6},}; NVRAM nvram; bool update_nvram =false; uint8_t crc8 (uint8_t * datos, uint16_t longitud) {uint8_t crc =0; while (longitud--) {crc =_crc8_ccitt_update (crc, * data ++); } return crc;} int led =13; bool init_oled =true; bool update_oled =true; bool init_board =true; #ifdef FAHRENHEIT # define C2F (temp) CelsiusToFahrenheit (temp) float CelsiusToFahrenheit (float celsius) {return ((celsius * 9) / 5) + 32;} # else # define C2F (temp) (temp) #endifvoid SerialPrint (const char * str, float decimal, char error) {Serial.print (str); if (error) Serial.print (F ("NA")); else Serial.print (decimal, 1);} time_t NextScheduleTime (time_t last_time, uint8_t * next_schedule) {time_t next_time =-1; time_t clk_time; uint8_t i; tm clk; uint8_t wday; for (i =0; i  SÁBADO) wday =DOMINGO; if (wday ==clk.tm_wday) romper; // Marque solo una semana} if (clk_time  0) {if (nvram.rain [i]> nvram.water_duration) nvram.water_duration =0; else nvram.water_duration - =nvram.rain [i]; nvram.rain [i] =0; }} void WaterScheduleTime (void) {uint8_t i; nvram.water_duration--; update_nvram =true; i =horario [nvram.water_schedule] .zone; if (i  0) Serial.println ("o"); else Serial.println ("f"); SerialReadUntilDone (); }} void setup () {Serial.begin (115200); # ifdef SERIAL_DEBUG swSerial.begin (115200); # endif pinMode (led, OUTPUT); // retraso (1000); wdt_enable (WDTO_8S);} bucle vacío () {tm rtc estático; tm clk, sunrise_clk; time_t rtc_time; time_t clk_time; static time_t next_time; static uint8_t last_sec; static uint8_t last_min; bool error_rtc; bool error_light; bool error_temp; lux largo estático =0; temperatura de flotación estática, lluvia; estático uint8_t sunrise_counter =MIN_IN_HOUR; static bool check_sunrise =false; uint8_t i; static bool read_nvram =true; static time_t water_time; static uint8_t water_schedule; uint8_t sz; uint8_t wday; largo n; bool button1, button2; static int8_t menu_select =-1; tiempo_estático_tiempo_menú =0; Serial.println (); if (SerialReadUntilDone ()) {if (init_board) {SerialCmdDone (INIT_BOARD); init_board =falso; } if (init_oled) {if (SerialCmdNoError (ONEWIRE_TO_I2C_ROM1)) {SerialCmdDone (I2C_OLED "; si; sc; sd"); init_oled =falso; }} if (SerialCmdDone (RTC_SENSOR)) {error_rtc =! SerialReadTime (&rtc); if (!error_rtc) { clk =rtc; // mktime() can change struct tm rtc_time =mktime(&clk); localtime_r(&rtc_time, &rtc); // Get wday. } if (read_nvram) { if (SerialCmdNoError(I2C_EEPROM)) { SerialReadEEPROM((uint8_t*)&nvram, 0, sizeof(nvram)); if (nvram.crc !=crc8((uint8_t*)&nvram, sizeof(nvram)-sizeof(uint8_t))) { //swSerial.println("CRC8 Failure!"); // Initialize nvram memset(&nvram, 0, sizeof(nvram)); clk =rtc; clk.tm_hour =6; clk.tm_min =0; clk.tm_sec =0; nvram.sunrise_time =mktime(&clk); if (nvram.sunrise_time  SEC_IN_WEEK) nvram.last_water_time =rtc_time - SEC_IN_WEEK; // Check sunrise time if (rtc_time> nvram.sunrise_time) { localtime_r(&nvram.sunrise_time, &sunrise_clk); clk =rtc; clk.tm_hour =sunrise_clk.tm_hour; clk.tm_min =sunrise_clk.tm_min; clk.tm_sec =sunrise_clk.tm_sec; nvram.sunrise_time =mktime(&clk); if (nvram.sunrise_time  0) sunrise_counter--; else check_sunrise =true; } else { if (sunrise_counter =MENU_OPTIONS) menu_select =0; } menu_time =rtc_time; update_oled =true; } if (menu_select>=0) { button2 =SerialReadButton(BUTTON2); if (button2) { clk_time =rtc_time; switch(menu_select) { case MENU_NEXT:case MENU_RESET:if (nvram.water_duration) { nvram.water_duration =1; WaterScheduleTime(); } water_time =NextScheduleTime((menu_select ==MENU_NEXT) ? water_time :rtc_time, &water_schedule); descanso; case MENU_WATER:StartScheduleTime(water_time, water_schedule); WaterScheduleTime(); descanso; case MENU_CLOCK_MIN_PLUS:clk_time +=SEC_IN_MIN; descanso; case MENU_CLOCK_MIN_MINUS:clk_time -=SEC_IN_MIN; descanso; case MENU_CLOCK_HOUR_PLUS:clk_time +=SEC_IN_HOUR; descanso; case MENU_CLOCK_HOUR_MINUS:clk_time -=SEC_IN_HOUR; descanso; case MENU_ON_OFF:nvram.state ^=STATE_ON_OFF; update_nvram =true; descanso; } if (clk_time !=rtc_time) { if (SerialCmdDone(RTC_SENSOR)) { localtime_r(&clk_time, &clk); SerialWriteTime(&clk); rtc_time =clk_time; } } menu_time =rtc_time; update_oled =true; } } if (menu_select>=0 &&rtc_time - menu_time> MENU_TIME) { menu_select =-1; update_oled =true; } if (update_oled) { if (SerialCmdNoError(ONEWIRE_TO_I2C_ROM1)) { Serial.print("st10;so1;sc;sf0;sa0;sd0,0,\""); if (nvram.water_duration) Serial.print(nvram.water_duration); else { if ((nvram.state &STATE_ON_OFF) ==OFF) Serial.print("OFF"); else if (rain <=RAIN_DETECT_LEVEL) Serial.print("Rain"); else if (temp <=DO_NOT_WATER_TEMP) Serial.print("Cold"); else Serial.print("v1.1"); } Serial.print("\";sf2;sa1;sd75,0,\""); if (menu_select ==7) { // Sunrise clk_time =nvram.sunrise_time; localtime_r(&clk_time, &clk); } else clk =rtc; Serial.print(clk.tm_hour-((clk.tm_hour>12)?12:0)); Serial.print(":"); if (clk.tm_min <10) Serial.print("0"); Serial.print(clk.tm_min); Serial.println("\""); SerialReadUntilDone(); Serial.print("sf1;sa0;sd79,8,\""); Serial.print((clk.tm_hour>12)?"PM":"AM"); Serial.print("\";sf0;sa1;sd127,1,\""); Serial.print(weekday[clk.tm_wday]); Serial.print("\";sd127,13,\""); Serial.print(clk.tm_mon+1); Serial.print("/"); Serial.print(clk.tm_mday); Serial.println("\""); SerialReadUntilDone(); Serial.print("sf0;sa0;sd1,36,\""); i =schedule[water_schedule].zone; if (i  SEC_IN_DAY) { Serial.print("\";sa1;sd126,36,\""); Serial.print(clk.tm_mon+1); Serial.print("/"); Serial.print(clk.tm_mday); Serial.print(" "); Serial.print(clk.tm_hour-((clk.tm_hour>12)?12:0)); Serial.print(":"); if (clk.tm_min <10) Serial.print("0"); Serial.print(clk.tm_min); Serial.print(" "); } else { Serial.print("\";sf1;sa1;sd111,30,\""); Serial.print(clk.tm_hour-((clk.tm_hour>12)?12:0)); Serial.print(":"); if (clk.tm_min <10) Serial.print("0"); Serial.print(clk.tm_min); Serial.print("\";sf0;sd126,36,\""); } Serial.print((clk.tm_hour>12)?"PM":"AM"); if (nvram.water_duration) Serial.print("\";so2;sc0,29,128,19"); Serial.println (); SerialReadUntilDone(); if (menu_select ==-1) { //Serial.print("\";sa0;sd0,52,\""); //Serial.print(rain); SerialPrint("\";so1;sa2;sd63,52,\"", C2F(temp), error_temp); if (!error_temp) Serial.print("\",248,\"" #ifdef FAHRENHEIT "F" #else "C" #endif ); Serial.print(" / "); Serial.print(lux); } else { Serial.print("\";so0;sc0,51,128,14;sf0;sa2;sd63,52,\""); if (menu_select ==MENU_ON_OFF) { Serial.print((nvram.state &STATE_ON_OFF) ? "OFF" :"ON"); } else Serial.print(menu[menu_select]); } Serial.println("\";sd"); SerialReadUntilDone(); update_oled =false; } else init_oled =true; } if (update_nvram) { if (SerialCmdNoError(I2C_EEPROM)) { nvram.crc =crc8((uint8_t*)&nvram, sizeof(nvram)-sizeof(uint8_t)); //swSerial.println(nvram.crc, HEX); SerialWriteEEPROM((uint8_t*)&nvram, 0, sizeof(nvram)); update_nvram =false; } } delay(50); } else { digitalWrite(led, HIGH); delay(500); digitalWrite(led, LOW); delay(500); init_board =true; init_oled =true; } wdt_reset();}

Esquemas

Intelligently water your yard or garden

Proceso de manufactura

  1. Diseño de sistemas agrícolas inteligentes de código abierto
  2. La placa del sensor inteligente acelera el desarrollo de la IA de borde
  3. 433MHz Smart Home Controller con Sensorflare y RaspberryPi
  4. Sensor de temperatura Raspberry Pi
  5. IoT celular:cubo de basura inteligente
  6. Smart Bartender
  7. Sensor de emoción / EEG
  8. Controlador de riego IOT Win10 con sensores de humedad
  9. Sensor ultrasensible y resistente para textiles inteligentes
  10. Sensor ultrafino para lentes de contacto inteligentes
  11. La mecatrónica inteligente ayuda a la producción de sensores en Sensata Technologies