Você já pensou em construir seu próprio sistema de irrigação com Arduino para seu jardim e ficar despreocupado com suas plantas?
Atualmente, diversas pessoas têm o hábito de criar plantas em seus apartamentos e casas. Porém, um dos grandes problemas é o esquecimento ou falta de tempo para cuidar e oferecer água necessária para mantê-las vivas. Além disso, quanto maior a quantidade, maior é o tempo consumido para cuidar de toda a área de plantação.
Agora, imagine… Como seria se você tivesse um sistema para realizar a irrigação por você? É exatamente isso que queremos ensinar nesse artigo. Além disso, sugerimos que você leia até o final, pois caso você não leia, perderá a oportunidade de:
- Aprender a aplicar memórias EEPROM para armazenar dados de processos;
- Aplicar a reutilização de funções em seus projetos;
- Aprender a utilização do Relógio de Tempo Real para contabilizar o tempo;
- Aprender a utilizar o módulo Display TM1637 em projetos que envolvem apresentação de valores;
- Criar sistema de iluminação para indicar etapas de processos;
- Aprender como integrar diversos dispositivos e criar um projeto mais complexo.
Portanto, se você se importa em aprender os recursos acima e acredita que são importantes para seus futuros projetos, vamos dar início à apresentação passo a passo do sistema de irrigação com Arduino.
Desenvolvimento do Sistema de Irrigação com Arduino
Primeiramente, para construção desse projeto necessitamos montar o seguinte esquema eletrônico, que é apresentado abaixo.
Além disso, todos os itens para esse projeto podem ser encontrados a seguir:
Lista de itens do projeto
- Arduino Nano;
- Display TM1637;
- 4 x Botões 6x6x5 mm;
- Jumpers;
- Relé de 1 Canal – 220V/10A;
- 1 Mini Bomba Submersa – 5V;
De acordo com o circuito da Figura 1, o projeto funcionará da seguinte forma.
Primeiramente, temos 4 botões no sistema. Esses 4 botões serão utilizados para configuração das horas do relógio e dos horários de ligação e desligamento da bomba de irrigação.
Ou seja, por meio dos botões 2 e 3, o usuário irá configurar, respectivamente, as horas e minutos do relógio do sistema. Já os botões 1 e 4 possuem outra finalidade.
O botão 1 será utilizado para o usuário entrar no modo de ajuste do horário de ligar e desligar a bomba de irrigação. Em seguida, será acionado o LED Amarelo, para indicar que o usuário deve ajustar a hora de ligação. Nessa etapa, o usuário deve utilizar os botões 2 e 3 para ajustar as horas e minutos de ligação da carga.
Posteriormente, o usuário deve pressionar o botão 4, a fim de indicar que finalizou o ajuste e deseja ajustar a hora de desligar o sistema de irrigação.
Durante esta etapa, o LED Amarelo será desligado e o LED Vermelho será ligado em seguida. Ele indicará que o usuário irá ajustar o horário de desligamento.
Portanto, o usuário realizará o processo anterior e finalizará pressionando o botão número 4. Após isto, o sistema irá comparar as horas atuais com as horas ajustadas e realizar o acionamento e desligamento do relé nas horas ajustadas pelo usuário.
Agora, apresentaremos o desenvolvimento da lógica de controle do sistema.
Desenvolvimento da Lógica de Controle
Inicialmente, apresentamos a lógica completa que foi desenvolvida para o projeto.
<code>#include <TM1637Display.h> #include <DS1307.h> #include <Wire.h> #include <EEPROM.h> TM1637Display display(2, 3); bool BotaoHora = 0, BotaoMinuto = 0; bool EstadoBotaoHoraAnt = 0, EstadoBotaoMinutoAnt = 0; int valorfinal; int DataTime[7]; byte segto = 0x80, hora = 0, minuto = 0, AlarmeHora = 0, AlarmeMinuto = 0; byte HoraLig = 0, MinLig = 0, HoraDesl = 0, MinDesl = 0; void ConfigAlarme(); #define HORALIG 0 #define MINLIG 1 #define HORADESL 2 #define MINDESL 3 #define LEDDESL 4 #define LEDACIONA 5 #define Carga 7 #define Alarme 8 #define Enter 9 #define PinoHora 10 #define PinoMinuto 12 void setup() { display.setBrightness(0x0f); DS1307.begin(); pinMode(Enter, INPUT); pinMode(Alarme, INPUT); pinMode(PinoHora, INPUT); pinMode(PinoMinuto, INPUT); pinMode(LEDDESL, OUTPUT); pinMode(LEDACIONA, OUTPUT); pinMode(Carga, OUTPUT); digitalWrite(Carga, HIGH); HoraDesl = EEPROM.read(HORADESL); MinDesl = EEPROM.read(MINDESL); HoraLig = EEPROM.read(HORALIG); MinLig = EEPROM.read(MINLIG); } void loop() { DS1307.getDate(DataTime); hora = DataTime[4]; minuto = DataTime[5]; display.showNumberDecEx((hora * 100) + minuto, 0x40, 1, 4, 0); // dispaying value of hour and minutes on display BotaoHora = digitalRead(PinoHora); BotaoMinuto = digitalRead(PinoMinuto); if (BotaoHora == 1 && EstadoBotaoHoraAnt == 0) { hora++; DS1307.setDate(0, 0, 0, 0, hora, minuto, 0); //Ano, Mes, Data do Mes, Dia da Semana, hora, minuto, segundo EstadoBotaoHoraAnt = 1; if (hora > 23) { hora = 0; } } if (BotaoHora == 0 && EstadoBotaoHoraAnt == 1) { EstadoBotaoHoraAnt = 0; } if (BotaoMinuto == 1 && EstadoBotaoMinutoAnt == 0) { minuto++; DS1307.setDate(0, 0, 0, 0, hora, minuto, 0); //Ano, Mes, Data do Mes, Dia da Semana, hora, minuto, segundo EstadoBotaoMinutoAnt = 1; if (minuto > 59) { minuto = 0; } } if (BotaoMinuto == 0 && EstadoBotaoMinutoAnt == 1) { EstadoBotaoMinutoAnt = 0; } bool BotaoAlarme = digitalRead(Alarme); if(BotaoAlarme == 1) { digitalWrite(LEDDESL, LOW); digitalWrite(LEDACIONA, HIGH); ConfigAlarme(HORALIG, MINLIG); delay(1500); digitalWrite(LEDACIONA, LOW); digitalWrite(LEDDESL, HIGH); ConfigAlarme(HORADESL, MINDESL); digitalWrite(LEDDESL, LOW); HoraLig = EEPROM.read(HORALIG); MinLig = EEPROM.read(MINLIG); HoraDesl = EEPROM.read(HORADESL); MinDesl = EEPROM.read(MINDESL); } if((hora == HoraLig) && (minuto == MinLig)) { digitalWrite(Carga, LOW); } if((hora == HoraDesl) && (minuto == MinDesl)) { digitalWrite(Carga, HIGH); } } void ConfigAlarme(byte hora, byte minuto) { bool BotaoEnter = 0; delay(1000); do { BotaoHora = digitalRead(PinoHora); BotaoMinuto = digitalRead(PinoMinuto); if (BotaoHora == 1 && EstadoBotaoHoraAnt == 0) { AlarmeHora++; EstadoBotaoHoraAnt = 1; if (AlarmeHora > 23) { AlarmeHora = 0; } } if (BotaoHora == 0 && EstadoBotaoHoraAnt == 1) { EstadoBotaoHoraAnt = 0; } if (BotaoMinuto == 1 && EstadoBotaoMinutoAnt == 0) { AlarmeMinuto++; EstadoBotaoMinutoAnt = 1; if (AlarmeMinuto > 59) { AlarmeMinuto = 0; } } if (BotaoMinuto == 0 && EstadoBotaoMinutoAnt == 1) { EstadoBotaoMinutoAnt = 0; } BotaoEnter = digitalRead(Enter); display.showNumberDecEx((AlarmeHora * 100) + AlarmeMinuto, 0x40, 1, 4, 0); // dispaying value of hour and minutes on display }while(BotaoEnter == 0); EEPROM.write(hora, AlarmeHora); EEPROM.write(minuto, AlarmeMinuto); delay(1000); }</code>
Primeiramente, foram declaradas as bibliotecas do Display TM1637, Relógio de Tempo Real, I2C e Memória EEPROM, conforme apresentado abaixo.
<code>#include <TM1637Display.h> #include <DS1307.h> #include <Wire.h> #include <EEPROM.h></code>
Posteriormente, foi realizada a definição dos pinos de comunicação de dados do display TM1637. Em seguida, todas as variáveis foram declaradas e inicializadas.
<code>TM1637Display display(2, 3); bool BotaoHora = 0, BotaoMinuto = 0; bool EstadoBotaoHoraAnt = 0, EstadoBotaoMinutoAnt = 0; int valorfinal; int DataTime[7]; byte segto = 0x80, hora = 0, minuto = 0, AlarmeHora = 0, AlarmeMinuto = 0; byte HoraLig = 0, MinLig = 0, HoraDesl = 0, MinDesl = 0;</code>
Logo depois, a fim de facilitar o uso e manipulação dos pinos durante a programação, foram definidos nomes para cada valor de pino do Arduino. As definições são apresentadas a seguir.
<code>void ConfigAlarme(); #define HORALIG 0 #define MINLIG 1 #define HORADESL 2 #define MINDESL 3 #define LEDDESL 4 #define LEDACIONA 5 #define Carga 7 #define Alarme 8 #define Enter 9 #define PinoHora 10 #define PinoMinuto 12</code>
Após essa etapa, apresentaremos a configuração e inicialização dos dispositivos utilizados no projeto do sistema de irrigação com Arduino.
Configuração e Inicialização dos Dispositivos do Sistema de Irrigação com Arduino
Primeiramente, apresentamos a função void setup. Nela serão realizadas todas as configurações de pinos e inicialização dos dispositivos eletrônicos do projeto.
<code>void setup() { display.setBrightness(0x0f); DS1307.begin(); pinMode(Enter, INPUT); pinMode(Alarme, INPUT); pinMode(PinoHora, INPUT); pinMode(PinoMinuto, INPUT); pinMode(LEDDESL, OUTPUT); pinMode(LEDACIONA, OUTPUT); pinMode(Carga, OUTPUT); digitalWrite(Carga, HIGH); HoraDesl = EEPROM.read(HORADESL); MinDesl = EEPROM.read(MINDESL); HoraLig = EEPROM.read(HORALIG); MinLig = EEPROM.read(MINLIG); }</code>
Inicialmente, definimos o brilho do display em seu valor máximo e inicializamos o relógio de tempo real, conforme apresentado a seguir.
<code>display.setBrightness(0x0f); DS1307.begin();</code>
Posteriormente, definimos os pinos como entradas e saídas digitais e acionamos o pino do relé para mantê-lo desativado.
<code> pinMode(Enter, INPUT); pinMode(Alarme, INPUT); pinMode(PinoHora, INPUT); pinMode(PinoMinuto, INPUT); pinMode(LEDDESL, OUTPUT); pinMode(LEDACIONA, OUTPUT); pinMode(Carga, OUTPUT); digitalWrite(Carga, HIGH);</code>
Finalmente, foi realizada a leitura dos valores de horas de acionamento e desligamento da carga, que foram salvos na memória EEPROM.
<code> HoraDesl = EEPROM.read(HORADESL); MinDesl = EEPROM.read(MINDESL); HoraLig = EEPROM.read(HORALIG); MinLig = EEPROM.read(MINLIG);</code>
Leitura do valor das Horas de Irrigação
Conforme apresentado nas linhas de código acima, é necessário ler as horas de acionamento da carga na memória EEPROM.
Portanto, por meio desse processo, o sistema sempre carregará as horas de acionamento e desligamento no processo de inicialização do CHIP.
Agora, apresentaremos a estrutura da lógica principal de controle do sistema.
Lógica Principal de Controle do Sistema de Irrigação com Arduino
A princípio, apresentamos a lógica de programação será apresentada logo abaixo.
<code>void loop() { DS1307.getDate(DataTime); hora = DataTime[4]; minuto = DataTime[5]; display.showNumberDecEx((hora * 100) + minuto, 0x40, 1, 4, 0); //Apresenta o valor da Hora e Minuto no Display BotaoHora = digitalRead(PinoHora); BotaoMinuto = digitalRead(PinoMinuto); if (BotaoHora == 1 && EstadoBotaoHoraAnt == 0) { hora++; DS1307.setDate(0, 0, 0, 0, hora, minuto, 0); //Ano, Mes, Data do Mes, Dia da Semana, hora, minuto, segundo EstadoBotaoHoraAnt = 1; if (hora > 23) { hora = 0; } } if (BotaoHora == 0 && EstadoBotaoHoraAnt == 1) { EstadoBotaoHoraAnt = 0; } if (BotaoMinuto == 1 && EstadoBotaoMinutoAnt == 0) { minuto++; DS1307.setDate(0, 0, 0, 0, hora, minuto, 0); //Ano, Mes, Data do Mes, Dia da Semana, hora, minuto, segundo EstadoBotaoMinutoAnt = 1; if (minuto > 59) { minuto = 0; } } if (BotaoMinuto == 0 && EstadoBotaoMinutoAnt == 1) { EstadoBotaoMinutoAnt = 0; } bool BotaoAlarme = digitalRead(Alarme); if(BotaoAlarme == 1) { digitalWrite(LEDDESL, LOW); digitalWrite(LEDACIONA, HIGH); ConfigAlarme(HORALIG, MINLIG); delay(1500); digitalWrite(LEDACIONA, LOW); digitalWrite(LEDDESL, HIGH); ConfigAlarme(HORADESL, MINDESL); digitalWrite(LEDDESL, LOW); HoraLig = EEPROM.read(HORALIG); MinLig = EEPROM.read(MINLIG); HoraDesl = EEPROM.read(HORADESL); MinDesl = EEPROM.read(MINDESL); } if((hora == HoraLig) && (minuto == MinLig)) { digitalWrite(Carga, LOW); } if((hora == HoraDesl) && (minuto == MinDesl)) { digitalWrite(Carga, HIGH); } }</code>
Primeiramente, realizamos a aquisição de data e hora do RTC e armazenamos os valores no vetor DataTime. Posteriormente, os valores das horas são armazenados nas variáveis hora e minuto, conforme apresentado abaixo.
<code>DS1307.getDate(DataTime); hora = DataTime[4]; minuto = DataTime[5];</code>
Dessa forma, o valor da hora é apresentado na tela do display a partir da função apresentada a seguir.
<code>display.showNumberDecEx((hora * 100) + minuto, 0x40, 1, 4, 0); //Apresenta o valor da Hora e Minuto no Display</code>
As horas são apresentadas conforme mostra a Figura 2.
Posteriormente, é realizada a leitura dos pinos digitais dos botões de ajuste das Horas e Minutos. O código é apresentado a seguir.
<code> BotaoHora = digitalRead(PinoHora); BotaoMinuto = digitalRead(PinoMinuto);</code>
Portanto, quando o botão de hora é pressionado, o sistema irá incrementar a variável hora e executará a função de ajuste de data e hora logo em seguida.
<code>DS1307.setDate(0, 0, 0, 0, hora, minuto, 0); //Ano, Mes, Data do Mes, Dia da Semana, hora, minuto, segundo</code>
Assim, através dessa função, o sistema irá incrementar e configurar a hora toda vez que o botão for pressionado. Analogamente, esse processo é semelhante para o botão de ajuste dos minutos.
Além disso, temos a leitura do botão de ajuste das horas acionamento e desligamento, conforme apresentado a seguir.
<code>bool BotaoAlarme = digitalRead(Alarme);</code>
Toda vez que esse botão é pressionado, por conseguinte, será executada a seguinte condição.
<code> if(BotaoAlarme == 1) { digitalWrite(LEDDESL, LOW); digitalWrite(LEDACIONA, HIGH); ConfigAlarme(HORALIG, MINLIG); delay(1500); digitalWrite(LEDACIONA, LOW); digitalWrite(LEDDESL, HIGH); ConfigAlarme(HORADESL, MINDESL); digitalWrite(LEDDESL, LOW); HoraLig = EEPROM.read(HORALIG); MinLig = EEPROM.read(MINLIG); HoraDesl = EEPROM.read(HORADESL); MinDesl = EEPROM.read(MINDESL); }</code>
Primeiramente, é acionado o LED Amarelo a fim de sinalizar o ajuste da hora de acionamento da carga. Isto pode ser visto na Figura 3.
Além disso, a função ConfigAlarme é chamada, conforme apresentada a seguir.
<code>digitalWrite(LEDDESL, LOW); digitalWrite(LEDACIONA, HIGH); ConfigAlarme(HORALIG, MINLIG); delay(1500);</code>
A função ConfigAlarme é fundamental na configuração do horário de acionamento e desligamento da carga.
A seguir, apresentaremos sua estrutura e discutiremos a importância da criação de funções na programação.
Função de Configuração de Acionamento do Sistema de Irrigação com Arduino
Em primeiro lugar, a função ConfigAlarme apresenta a seguinte estrutura, que é apresentada no código abaixo.
<code>void ConfigAlarme(byte hora, byte minuto) { bool BotaoEnter = 0; delay(1000); do { BotaoHora = digitalRead(PinoHora); BotaoMinuto = digitalRead(PinoMinuto); if (BotaoHora == 1 && EstadoBotaoHoraAnt == 0) { AlarmeHora++; EstadoBotaoHoraAnt = 1; if (AlarmeHora > 23) { AlarmeHora = 0; } } if (BotaoHora == 0 && EstadoBotaoHoraAnt == 1) { EstadoBotaoHoraAnt = 0; } if (BotaoMinuto == 1 && EstadoBotaoMinutoAnt == 0) { AlarmeMinuto++; EstadoBotaoMinutoAnt = 1; if (AlarmeMinuto > 59) { AlarmeMinuto = 0; } } if (BotaoMinuto == 0 && EstadoBotaoMinutoAnt == 1) { EstadoBotaoMinutoAnt = 0; } BotaoEnter = digitalRead(Enter); display.showNumberDecEx((AlarmeHora * 100) + AlarmeMinuto, 0x40, 1, 4, 0); // dispaying value of hour and minutes on display }while(BotaoEnter == 0); EEPROM.write(hora, AlarmeHora); EEPROM.write(minuto, AlarmeMinuto); delay(1000); }</code>
Inicialmente, conforme é possível observar, a função possui a entrada de dois parâmetros: byte hora e byte minuto. Desse modo, esses dois parâmetros são referentes aos endereços da memória EEPROM, que utilizaremos para armazenar a hora e minuto de acionamento ou desligamento da carga.
Em seguida, no início do laço do while realizamos a leitura dos botões de ajuste da hora e minuto de acionamento da carga. Conforme é possível observar, os mesmos botões de ajuste de horas do relógio foram utilizados para ajustar o tempo de acionamento e desligamento da carga.
Portanto, esse processo é útil para criar botões com múltiplas funções e reduzir a quantidade de botões no projeto.
Posteriormente, caso o usuário pressione o botão de horas, o sistema irá incrementar a variável AlarmeHora até um valor máximo de 23h. Em seguida, é apresentada a porção de código descrita acima.
<code>if (BotaoHora == 1 && EstadoBotaoHoraAnt == 0) { AlarmeHora++; EstadoBotaoHoraAnt = 1; if (AlarmeHora > 23) { AlarmeHora = 0; } } if (BotaoHora == 0 && EstadoBotaoHoraAnt == 1) { EstadoBotaoHoraAnt = 0; }</code>
Analogamente, temos esse mesmo processo para o botão de ajuste dos minutos. Dessa forma, continuamente o sistema irá ler os valores ajustados e apresentar no display, conforme apresentado no código abaixo.
<code>display.showNumberDecEx((AlarmeHora * 100) + AlarmeMinuto, 0x40, 1, 4, 0);</code>
Finalmente, após o ajuste das horas e minutos de acionamento, o usuário deve pressionar o botão F, a fim de finalizar o processo de ajuste.
Em seguida, os valores de ajuste das horas e minutos serão salvos nas posições de hora e minuto que foram passadas como parâmetro no início da função. Isto é apresentado a seguir.
<code>EEPROM.write(hora, AlarmeHora); EEPROM.write(minuto, AlarmeMinuto); delay(1000);</code>
Dessa forma, esses valores são salvos para garantir que após um desligamento do sistema, eles possam ser lidos e carregados da memória na reinicialização do dispositivo.
De volta à função Loop
Posteriormente, o sistema desligará o LED Amarelo e ligará o LED Vermelho para indicar que devemos configurar a hora de desligamento.
Analogamente, o processo se repete. Portanto, implementamos funções sempre que blocos de códigos se repetem e necessitamos reutilizá-los em outros pontos de código.
Finalmente, os valores ajustados serão lidos e armazenados nas variáveis, conforme apresentado a seguir.
<code> HoraLig = EEPROM.read(HORALIG); MinLig = EEPROM.read(MINLIG); HoraDesl = EEPROM.read(HORADESL); MinDesl = EEPROM.read(MINDESL);</code>
Desse modo, esses valores serão utilizados para que o sistema compare continuamente a hora atual com os valores ajustados pelo usuário. Isto é apresentado a seguir.
<code>if((hora == HoraLig) && (minuto == MinLig)) { digitalWrite(Carga, LOW); } if((hora == HoraDesl) && (minuto == MinDesl)) { digitalWrite(Carga, HIGH); }</code>
Portanto, por meio das condições acima, o sistema irá ligar o relé para acionar a mini bomba quando a hora e minuto forem iguais a HoraLig e MinLig.
Dessa forma, o sistema irá fornecer água do reservatório para a planta, conforme apresentado na Figura 4.
Em seguida, realizará o desligamento da carga quando a hora e minuto forem iguais a HoraDesl e MinDesl, respectivamente.
Conclusão sobre o Sistema de Irrigação com Arduino
Conforme foi apresentado, o sistema apresenta-se útil para o desenvolvimento de projetos que necessitam de baixos recursos de interface homem-máquina e realizar automações de acionamento baseado no tempo.
Além disso, por meio desse sistema o usuário poderá aplicá-lo para qualquer tipo de carga que necessite ser acionada em um tempo específico. Dessa forma, é possível criar um sistema universal de acionamento temporizado.
Logo, por meio desse sistema é possível aplicá-lo em diversas áreas e, inclusive, realizar melhorias como: Implementar um sensor de umidade, a fim de não irrigar o solo quando estiver molhado.
Portanto, sugerimos a leitura do nosso artigo “Sensor de Umidade Capacitivo com Arduino”, para que você aprenda e implemente novas melhorias a esse projeto.
Agradecemos sua leitura e deixamos o convite para conhecer nosso blog Autocore Robótica.