Manufaturação industrial
Internet das coisas industrial | Materiais industriais | Manutenção e reparo de equipamentos | Programação industrial |
home  MfgRobots >> Manufaturação industrial >  >> Manufacturing Technology >> Processo de manufatura

Controlador de irrigação inteligente

Componentes e suprimentos

Arduino Nano R3
× 1
Expansor IO
× 1
Pacote de expansão IO
× 1

Aplicativos e serviços online

Arduino IDE

Sobre este projeto





Crie um controlador de irrigação inteligente com Arduino


Irrigue seu quintal de forma inteligente com ciclos de água dinâmicos. Pare de regar o quintal se estiver chovendo ou tiver chovido desde a última rega. Use o sensor de luz para detectar a hora do nascer do sol e ajustar automaticamente os horários de início da água de acordo. Pare de molhar seu quintal se estiver muito frio.

Lista de recursos
  • Sensor de temperatura externa
  • Sensor externo de chuva
  • Sensor de luz externa
  • Relógio em tempo real com bateria para programação semanal
  • Armazenamento não volátil - nunca perca a irrigação devido à perda de energia
  • detecção do nascer do sol
  • A rega inteligente economiza na sua conta de água
  • Regar antes do nascer do sol para permitir um tempo de imersão adequado
  • Pare de regar quando estiver muito frio lá fora
  • Reduzir o crescimento de fungos
  • Fácil controle de programação





Peças necessárias para construir o controlador de irrigação inteligente

  • Expansor IO
  • x2 1 fio para I2C.
  • Junção de 1 fio
  • Conector óptico
  • Divisor
  • Arduino Nano.
  • Relé de 4 canais DC 5V.
  • Sensor de luz TSL2561.
  • Sensor de temperatura à prova d'água DS18B20.
  • Sensor infravermelho óptico de nível de água.
  • Relógio de tempo real de precisão DS3231 AT24C32 IIC.
  • Tela I2C SSD1306 OLED de 128x64.
  • Caixa de plástico transparente à prova d'água de 200x120x75mm.
  • Caixa de plástico transparente à prova d'água de 100x68x50mm.
  • ip68 pg7 prensa-cabo de nylon à prova d'água.
  • ip68 pg11 prensa-cabo de nylon à prova d'água.
  • Tomada de terminal de parafuso RJ11 Keystone.
  • Cabo RJ11 4C4P de 50 pés.
  • Cabo RJ11 4C4P de 6 pés.
  • Fio de plataforma de 2,54 mm.
  • x2 Microinterruptor de botão momentâneo de 2 pinos SPST
  • Fonte de alimentação do adaptador de parede 12VDC 1A.





Diagrama de fiação





Tela OLED


Pressione o botão Menu para exibir o menu e continue pressionando o botão para percorrer todas as opções do menu. O menu será removido automaticamente após 30 segundos de inatividade. Pressione o botão Selecionar para executar a função de menu desejada.





Então, por que usar o IO Expander?

  • Mais simples de projetar
  • Peças disponíveis no mercado
  • Nenhum driver 1-Wire para escrever
  • Nenhum driver DS3231 RTC para escrever
  • Nenhum driver EEPROM para escrever
  • Nenhum driver de exibição OLED para escrever
  • Nenhuma fonte de exibição para ocupar espaço de código Arduino
  • Nenhum driver de sensor de temperatura para escrever
  • Nenhum secador de sensor óptico de chuva para escrever
  • Economiza espaço de código no Arduino; apenas 12.710 bytes (39%)
  • Apenas três dias para escrever o código
  • Fácil de conectar usando o cabo telefônico RJ11 padrão
  • Sem problemas de comprimento do cabo do sensor
  • Mais barato de construir do que sistemas comerciais semelhantes
  • Fácil de fazer alterações para se adaptar aos requisitos individuais
  • Fonte de alimentação única





Construa o sistema


Conecte o Arduino Nano ao IO Expander e programe-o com o seguinte código. O cabeçalho de 6 pinos é a porta de depuração serial do software e não é necessário na instalação final.

Certifique-se de alterar o endereço definido ONEWIRE_TO_I2C_ROM1 e ONEWIRE-TO_I2C_ROM2 para corresponder ao endereço 1-Wire ao endereço I2C.
  / * Esboço do IO Expander otimizado 
*
* Sistema de irrigação v1.1
*
* /

#include
#include // Arquivo localizado \ Arquivos de programas (x86) \ Arduino \ hardware \ tools \ avr \ avr \ include \ time.h
#include
#include
#include
#include "IOExpander.h"

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

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

#define MAX_ZONES 4

#define HOUR_IN_DA A 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_HOUR)
#_define DAYS
#define SEC_IN_WEEK (SEC_IN_DAY * DAYS_IN_WEEK)

#define SUN 0x01
#define MON 0x02
#define TER 0x04
#define WED 0x08
# define THR 0x10
# define FRI 0x20
# define SAT 0x40
# define EVERYDAY (SUN | MON | TER | WED | THR | SEX | SAT)

#define NASCER DO SOL 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 dia da semana [] [4] ={"DOM", "SEG", "TER", "QUA", "QUI", "SEX", " SAT "};

menu char [] [13] ={" Próximo ",
" Água ",
" Reiniciar ",
" Relógio Min + " ,
"Clock Min -",
"Clock Hour +",
"Clock Hour -",
"Sunrise",
"ON / OFF"};

enum {
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
};

estrutura de typedef {
descrição do char [16];
relé uint8_t;
} ZONE;

typedef struct {
uint8_t zone;
uint8_t dias;
int8_t hora;
int8_t min;
uint8_t duration;
} CALENDÁRIO;

estrutura de typedef {
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;

enum {
ZONA1,
ZONA2,
ZONA3,
ZONA4
};

enum {
RELÉ1 =1,
RELÉ2,
RELÉ3,
RELAY4
};

Zona ZONE [] ={
{"Front Right", RELAY1},
{"Front Left", RELAY2},
{"Barramentos", RELÉ3},
{"Lado Esquerdo", RELÉ4},
};

AGENDAMENTO programação [] ={
{ZONA1, NASCER DO SOL | DIÁRIO, -1, 0, 4},
{ZONA2, DIÁRIO, 6, 15, 5},
{ZONA3, DIÁRIO, 6, 0, 10},
{ZONA4, DIÁRIO , 6, 10, 6},
};

NVRAM nvram;
bool update_nvram =false;

uint8_t crc8 (uint8_t * data, uint16_t comprimento)
{
uint8_t crc =0;

while (comprimento--) {
crc =_crc8_ccitt_update (crc, * dados ++);
}
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

vazio 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;

para (i =0; i if (agendar [i] .days &SUNRISE) {
clk_time =nvram.sunrise_time;
clk_time + =agendar [i] .hour * SEC_IN_HOUR;
clk_time + =agenda [i] .min * SEC_IN_MIN;
localtime_r (&clk_time, &clk);
}
else {
localtime_r (&last_time, &clk);
clk. tm_hour =agendar [i] .hour;
clk.tm_min =agendar [i] .min;
clk.tm_sec =0;
clk_time =mktime (&clk);
}
wday =clk.tm_wday;
while (clk_time <=last_time ||! (schedule [i] .days &(1 < {
clk_time + =SEC_IN_DAY;
if (++ wday> SATURDAY) wday =DOMINGO;
if (wday ==clk.tm_wday) break; // Verifique apenas uma 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 =agendar [start_schedule] .duration + 1;
update_nvram =true;
// Verifique se choveu
i =agendar [start_schedule] .zone;
if (i 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 =agendar [ 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, OUTPUT);
// delay (1000);
wdt_enable (WDTO_8S);
}

void loop () {
static tm rtc;
tm clk, sunrise_clk;
time_t rtc_time;
time_t clk_time;
time_t estático next_time;
estático uint8_t last_sec;
estático 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;
n longo;
bool botão1, botão2;
estático int8_t menu_select =-1;
estático 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 () pode alterar struct tm
rtc_time =mktime (&clk);
localtime_r (&rtc_time, &rtc); // Obter 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 Falha! ");
// 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 o último tempo de rega não inferior a uma semana
if (rtc_time - nvram.last_water_time> SEC_IN_WEEK) nvram.last_water_time =rtc_time - SEC_IN_WEEK;
// Verifique a hora do nascer do sol
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 }
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;
}
}
}

// Processa apenas uma vez a cada minuto
if (rtc.tm_min! =last_min)
{
// Solicita uma medição de temperatura de 1 fio. Leia mais tarde.
error_temp =! SerialCmdNoError (ONEWIRE_TEMPERATURE);
if (! Error_temp) SerialCmdDone ("tt");

error_light =! SerialCmdNoError ("ONEWIRE_TO_I2C_ROM2"; );
if (! error_light) {
SerialCmdDone (I2C_LIGHT); // Não 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 ();
}

// É o nascer do sol?
if (lux if (sunrise_counter> 0) sunrise_counter--;
else check_sunrise =true;
}
else {
if (sunrise_counter sunrise_counter ++;
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á chovendo?
if (rain <=RAIN_DETECT_LEVEL) {
para (i =0; i se (nvram.rain [i] <-1) nvram.rain [i] ++; }
update_nvram =true;
}

// Verificar programação
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 (water_time, water_schedule);
if (temp <=DO_NOT_WATER_TEMP || nvram.state &STATE_ON_OFF ==OFF)
nvram.water_duration =0;
}
}

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

last_min =rtc.tm_min;
update_oled =true;
}

// Botões de verificação
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;
break;
case MENU_CLOCK_MIN_MINUS:
clk_time - =SEC_IN_MIN;
break;
case MENU_CLOCK_HOUR_PLUS:
clk_time + =SEC_IN_HOUR;
pausa;
case MENU_CLOCK_HOUR_MINUS:
clk_time - =SEC_IN_HOUR;
break;
case 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 ("Chuva");
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 (dia da 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 =agendar [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");
}
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;
}
}

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

Nota: Se você usar a porta USB para programar o Arduino Nano, deverá desconectá-lo do IO Expander, pois ele também está usando a mesma porta serial única; em vez disso, se quiser depurar, use a porta ICSP para programar o ATmega328P. Para ativar a porta de depuração de software, descomente a definição SERIAL_DEBUG.

O divisor deve primeiro ser configurado para isolar a linha de dados do sensor infravermelho óptico da linha do sensor remoto de 1 fio. Solda em um resistor 0603 de zero ohm em R2.

Faça um orifício de 7/16 "no gabinete pequeno e um orifício de 11/16" no gabinete maior no lado direito para o PG7 e PG11. Use uma ferramenta dremel para aumentar ligeiramente os orifícios até que a sobreposta se ajuste bem. O PG7 alimentará os sensores remotos e o PG11 para os fios 12VDC, 24VAC, manifold e o fio dos sensores remotos RJ11.

Ligue o microinterruptor de botão momentâneo SPST e conecte-o ao terminal de parafuso RJ11. Use tubulação termorretrátil para isolar os contatos.

Conecte todos os fios e monte / alimente todas as peças no gabinete grande. Seu fio RJ11 de 50 pés para os sensores remotos deve apenas passar pela sobreposta PG11 sem ter que cortá-lo.

Faça um orifício de 9/16 "na parte superior da caixa pequena para o sensor infravermelho óptico de água. Use uma ferramenta dremel para aumentar ligeiramente o orifício até que o sensor se encaixe. A pequena caixa do sensor remoto é um encaixe apertado, mas se o conteúdo são colocados na orientação recomendada em que devem se encaixar. Fazer os fios RJ11 o mais curtos possível ajudará a amontoar tudo no gabinete menor. Depois de montado, é recomendado adicionar um pouco de cola marinha na arruela da porca da bucha antes de aparafusar a porca, para criar um selo melhor.

Instale o invólucro do sensor remoto do lado de fora e monte-o elevado ao lado leste da sua casa com o sensor de água infravermelho ótico e o sensor de luz apontando para o céu sem obstruções.

Faça orifícios de 1/4 "na parte superior central inferior do gabinete grande e monte os botões. Use uma ferramenta dremel para aumentar ligeiramente o orifício até que os botões se encaixem.

Teste o sistema e verifique se tudo está funcionando corretamente. Para testar o relé e os sensores, desconecte o Arduino do IO Expander e conecte-o diretamente ao seu computador para controlá-lo manualmente. Depois de verificar se tudo está funcionando, monte todas as peças no gabinete usando fita dupla-face e espuma de embalagem para proteger suas placas e aproveite os benefícios e a economia de seu Controlador de irrigação inteligente.





Vídeo em operação





Atualização 12/09/2019


Lançada a v1.1, que corrigia um problema de inicialização caso o sistema perdesse energia por vários dias.





Atualização 02/10/2019


Ao conectar o 1-Wire a I2C ao DS3231 e depois à tela OLED do SSD1306, você terá um total de três pullups diferentes nas linhas SDA e SCL, conforme mostrado na imagem abaixo circulada. Isso resultará efetivamente em um pullup de 4,7k / 3 =1,56k que pode ser muito forte e resultar em corrupções de tela aleatórias.

Uma vez que o DS3231 usa um pacote de resistores que é usado por outras linhas, remova os outros resistores pullup:
  • 1 fio para I2C R3 e R4.
  • SSD1306 OLED R6 e R7.

Código

  • Controlador de irrigação inteligente
Controlador de irrigação inteligente C / C ++
Use seu Arduino para regar seu quintal ou jardim de maneira inteligente.
 / * Esboço do IO Expander otimizado * * Sistema de irrigação v1.1 * * / # include  #include  // Arquivo localizado \ Programa Arquivos (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_ROM2 "i6s8f" #define ONEWIRE_TEMPERATURE "t6s0300" #define RTC_SENSOR "s4te" # definir I2C_EEPROM "s4tf" #define I2C_OLED "s4t10" #define I2C_LIGHT "s3t9; sc0" #define OPTICAL_SENSOR "g5a" #define BUTTON1 "g11d" #define BUTTON2 "g12d" #define_VEL_VEL_SENSOR_DEFINIR_AVE_INDA_ELEFINHA_ELEFINE_ELEFINER_ELEFINE_ELEFINER_60_60LEFATER_LISE 100_ELEFINE_ELEFINE_ELEFINE_ELEFINE_ELEFATER_LISE 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 * SEC_DAY * NOSSO) #define DAYS_IN_WEEK 7 # define SEC_IN_WEEK (SEC_IN_DAY * DAYS_IN_WEEK) #define SUN 0x01 # define MON 0x02 # define TUE 0x04 # define WED 0x08 # define THR 0x10 # define FRI 0x20 # define SAT 0x40 # define EVERYDAY (DOM 0x40 # define EVERYDAY | MON | TER | WED | THR | SEX | 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 weekday [] [4] ={"DOM", "SEG", "TER", "QUA", "QUI", "SEX", "SÁB"}; menu de caracteres [] [13] ={"Próximo", "Água", "Redefinir" , "Clock Min +", "Clock Min -", "Clock Hour +", "Clock Hour -", "Sunrise", "ON / OFF"}; enum {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 descrição [16]; relé uint8_t;} ZONA; typedef struct {uint8_t zona; uint8_t dias; int8_t hour; int8_t min; duração uint8_t;} CALENDÁRIO; 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; enum {ZONE1, ZONE2, ZONE3, ZONE4}; enum {RELAY1 =1, RELAY2, RELAY3, RELAY4}; ZONE zone [] ={{"Front Right", RELAY1}, {"Front Left" , RELAY2}, {"Bushes", RELAY3}, {"Left Side", RELAY4},}; AGENDAMENTO da programação [] ={{ZONE1, SUNRISE | DIÁRIO, -1, 0, 4}, {ZONA2, DIÁRIO, 6, 15, 5}, {ZONA3, DIÁRIO, 6, 0, 10}, {ZONA4, DIÁRIO, 6, 10, 6},}; NVRAM nvram; bool update_nvram =false; uint8_t crc8 (uint8_t * data, uint16_t comprimento) {uint8_t crc =0; while (comprimento--) {crc =_crc8_ccitt_update (crc, * dados ++); } 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 erro) {Serial.print (str); if (erro) 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; para (i =0; i  SÁBADO) wday =DOMINGO; if (wday ==clk.tm_wday) break; // Verifique apenas uma semana} if (clk_time  0) {if (nvram.rain [i]> nvram.water_duration) nvram.water_duration =0; senão nvram.water_duration - =nvram.rain [i]; nvram.rain [i] =0; }} void WaterScheduleTime (void) {uint8_t i; nvram.water_duration--; update_nvram =true; i =agendar [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); // delay (1000); wdt_enable (WDTO_8S);} void loop () {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; lux longo estático =0; temperatura de flutuação estática, chuva; estático uint8_t sunrise_counter =MIN_IN_HOUR; bool estático check_sunrise =false; uint8_t i; bool estático read_nvram =true; estático time_t water_time; static uint8_t water_schedule; uint8_t sz; uint8_t wday; long n; bool botão1, botão2; estático int8_t menu_select =-1; estático 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() 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); pausa; case MENU_WATER:StartScheduleTime(water_time, water_schedule); WaterScheduleTime(); pausa; case MENU_CLOCK_MIN_PLUS:clk_time +=SEC_IN_MIN; pausa; case MENU_CLOCK_MIN_MINUS:clk_time -=SEC_IN_MIN; pausa; case MENU_CLOCK_HOUR_PLUS:clk_time +=SEC_IN_HOUR; pausa; case MENU_CLOCK_HOUR_MINUS:clk_time -=SEC_IN_HOUR; pausa; case MENU_ON_OFF:nvram.state ^=STATE_ON_OFF; update_nvram =true; pausa; } 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

Processo de manufatura

  1. Projetando sistemas de agricultura inteligente de código aberto
  2. A placa do sensor inteligente acelera o desenvolvimento de IA de borda
  3. Controlador Smart Home de 433 MHz com Sensorflare e RaspberryPi
  4. Sensor de temperatura Raspberry Pi
  5. IoT celular:Lixeira inteligente
  6. Bartender inteligente
  7. Sensor de emoção / EEG
  8. Controlador de irrigação Win10 IOT com sensores de umidade
  9. Sensor ultra-sensível e resiliente para têxteis inteligentes
  10. Sensor ultrafino para lentes de contato inteligentes