Já pensou em implementar uma bomba d'água em um jardim com o seu projeto de automação residencial (Domótica), e não sabe por onde começar? É simples, com este artigo você irá aprender como ligar corretamente uma mini bomba d'água submersa utilizando um Atmega328p ou placa de desenvolvimento Arduino Uno de uma forma diferente, vamos desenvolver o firmware na linguagem C/C++ e acessando os registradores internos do microcontrolador. Se você não possui experiência, não se preocupe, o código em "linguagem Arduino" está disponível no fim deste artigo para a utilização na IDE oficial do Arduino.
No Tec Dicas já foram publicados artigos de como os registradores do Atmega328p funcionam internamente e na programação em C/C++, como também já implementamos um sensor de presença PIR com LED e módulo relé utilizando a mesma metodologia. É de extrema importância a leitura desses artigos para o entendimento dos registradores e ferramentas utilizadas para gravação, programação e ambiente de desenvolvimento do código.
Materiais e montagem
Para montar este projeto completo siga a lista de materiais necessários abaixo, depois leia atentamente os passos e explicações de cada tópico apresentado em seguida.
- 1 Arduino Uno ou Standalone Atmega328p com conexão ICSP
- 1 Gravador AVR USBasp
- 1 Mini Bomba d'água JT100
- 1 Mangueira de silicone (normal ou atóxica)
- 1 Recipiente com água
- 1 Protoboard
- 1 Fonte fixa 5V (LM7805 e capacitores)
- 1 Transistor MOSFET de potência IRFZ44N
- 1 Resistor de 15KΩ
- 1 Chave táctil
- 1 Diodo 1N4007
- Fios jumpers
- 1 Bateria de 6-7V com conector P4 2.1mm (Opcional)
- 1 Conector Jack P4 2.1mm com fios (Opcional)
- 1 Fonte de bancada ajustável (Opcional)
- 1 Conector adaptador ICSP de 6-10 pinos (Opcional)
A bomba d'água
A mini bomba d'água que foi utilizada para este artigo é do tipo submersa, possui vedação de seu circuito elétrico com proteção IP68. É compatível nas principais plataformas de desenvolvimento embarcado, como Arduino, NodeMCU e Raspberry Pi 3, pois suporta tensões entre 2.5V à 6V, e corrente máxima de 200mA. Sua elevação máxima é de 1 metro, impulsionando a água até 1,5 litro por minuto.
Para utilizar a bomba d'água é necessário um recipiente com água limpa, uma mangueira de silicone que encaixe no diâmetro de saída da bomba (aprox. 5mm). Os fios da bomba (vermelho e preto) são ligados no 5V e no dreno do transistor MOSFET.
Atenção: Se a aplicação com a bomba d'água for destinada ao consumo humano ou animal, utilize a mangueira de silicone atóxica para bebedouros.
Motor DC e transistor MOSFET
A estrutura elétrica de uma bomba d'água possui um motor DC para realizar o impulsionamento da água, e como já estudamos no artigo Controle de velocidade com driver MOSFET para motor DC, vimos que não podemos realizar as conexões do motor diretamente nas portas do Atmega328p, pois o motor é uma carga indutiva muito grande em que o sistema de proteção das portas do microcontrolador não suportam, além disso enfrentamos o fenômeno da indutância que tende ao infinito, e existem motores que são alimentados com tensões superiores que 5V.
Para resolver esses problemas e proteger as portas do microcontrolador, é utilizado uma chave eletrônica para acionar cargas maiores, chamada de transistor. Nesta aplicação foi utilizado o transistor de efeito de campo, ou MOSFET, seus conceitos e funcionamento estão presentes no artigo mencionado anteriormente.
Se preferir, você pode optar por um módulo de relé 5V - 10A para Arduino, onde um relé também é uma chave, porém eletromecânica. Ou ainda, Faça o seu módulo de relé compatível com qualquer plataforma de desenvolvimento embarcado agora!
É de extrema importância separar as tensões, onde uma fonte fixa de 5V foi adicionada ao circuito dedicando-se à bomba d'água e ao transistor, possuindo um regulador de tensão LM7805, um capacitor de poliéster de 100nF e um eletrolítico de 470uF. Na montagem realizada para este artigo, foi implementado um conector Jack P4 de painel com fios de protoboard, e uma bateria de 7V. O Arduino pode ser alimentado por esta bateria quando não está conectado na USB do computador, para isso conecte um fio na entrada do regulador (positivo da bateria) para o pino Vin da placa Arduino. Lembre-se de retirar esta conexão quando for utilizar o gravador ou alimentação USB.
Chave táctil, Atmega328p e resistor pull-up interno
Utilizamos uma chave táctil para controlar o acionamento da bomba d'água, sua ligação é feita com o mínimo de componentes possíveis, e isso é possível utilizando o resistor de pull-up interno do Atmega328p. Estes resistores estão disponíveis na maioria dos modelos de microcontroladores AVR, sendo úteis para sensores simples e botões/chave táctil.
Mas o que é resistor de pull-up e pull-down? Os resistores de pull-down e pull-up externos são utilizados normalmente em portas digitais de entrada que flutuam seus valores, sendo necessário "forçar" ou garantir algum estado. Um resistor de pull-down garante o estado de LOW/0V em portas digitais, já o resistor de pull-up garante o estado de HIGH/5V. O valor da resistência pode variar entre 4,7KΩ e 10KΩ. A aplicação destas configurações de resistores dependem da necessidade de projeto.
Programando o Atmega328p
Abra o Atmel Studio 7 e crie um projeto com o nome de "BombaDAgua" e selecione o microcontrolador Atmega328p.
Copie e cole este código abaixo, compile e grave o código utilizando o gravador USBasp, em Tools/AVRDude USBasp.
Atenção: Ao enviar firmwares via ICSP, retire o cabo Vin na placa Arduino.
/*
* BotaoBounce.cpp
*
* Created: 03/10/2019 14:48:09
* Author : tecdicas
*/
#define F_CPU 16000000UL // Cristal de 16MHz
#include <avr/io.h>
#include "util/delay.h"
bool valor1;
bool valor2;
bool estado_botao;
int main(void)
{
// Configura o PD3 como INPUT (Botão)
DDRD &= ~(1 << DDD3);
// Habilita o resistor de pull-up interno em PD3
PORTD = (1 << PORTD3);
// Configura o PD4 como OUTPUT (Gate MOSFET)
DDRD |= (1 << DDD4);
// Leitura inicial armazenada em estado_botao
estado_botao = (PIND & (1 << PIND3));
while (1)
{
// Leitura do botão armazenada em valor1
valor1 = (PIND & (1 << PIND3));
_delay_ms(10);
// Segunda leitura do botão armazenada em valor2
valor2 = (PIND & (1 << PIND3));
// Comparação para uma leitura aceitável sem drepidação mecânica
if (valor1 == valor2)
{
// Se o valor lido for diferente do estado do botão inicial
if (valor1 != estado_botao)
{
// Se o botão NÃO estiver pressionado..
if (valor1 == true)
{
// Desliga a bomba
PORTD &= ~(1 << PORTD4);
}
else
{
// Se não, liga
PORTD |= (1 << PORTD4);
}
}
// O estado_botao é igual ao valor1
estado_botao = valor1;
}
}
}
Se a compilação for bem sucedida..
Build succeeded.
========== Build: 1 succeeded or up-to-date, 0 failed, 0 skipped ==========
E se a gravação for bem sucedida..
avrdude.exe: AVR device initialized and ready to accept instructions
Reading | ################################################## | 100% 0.00s
avrdude.exe: Device signature = 0x1e950f
avrdude.exe: NOTE: FLASH memory has been specified, an erase cycle will be performed
To disable this feature, specify the -D option.
avrdude.exe: erasing chip
avrdude.exe: reading input file "D:\Projetos\AtmelStudio\BombaDAgua\BombaDAgua\Debug\BombaDAgua.hex"
avrdude.exe: writing flash (248 bytes):
Writing | ################################################## | 100% 0.11s
avrdude.exe: 248 bytes of flash written
avrdude.exe: verifying flash memory against D:\Projetos\AtmelStudio\BombaDAgua\BombaDAgua\Debug\BombaDAgua.hex:
avrdude.exe: load data flash data from input file D:\Projetos\AtmelStudio\BombaDAgua\BombaDAgua\Debug\BombaDAgua.hex:
avrdude.exe: input file D:\Projetos\AtmelStudio\BombaDAgua\BombaDAgua\Debug\BombaDAgua.hex contains 248 bytes
avrdude.exe: reading on-chip flash data:
Reading | ################################################## | 100% 0.08s
avrdude.exe: verifying ...
avrdude.exe: 248 bytes of flash verified
avrdude.exe: safemode: Fuses OK
avrdude.exe done. Thank you.
Retirando o conector ICSP da placa Arduino, e colocando o fio no pino Vin novamente, ligue a bateria com conector P4 no jack P4. Posicionando a mangueira dentro do recipiente, clique na tecla táctil com debounce para ligar a bomba d'água e veja o resultado!
Analisando o código
Vamos analisar a forma em que os registradores foram utilizados na programação em C/C++.
Direções das portas e resistor de pull-up
Dentro da estrutura int main(void) configuramos inicialmente a porta PD3 como INPUT, utilizando o registrador DDRD, onde o terceiro bit é setado como 0/falso utilizando a técnica de bitwise NAND. O resistor de pull-up interno do microcontrolador é "ativado" na programação utilizando o registrador PORTD, onde a porta PD3 é setada como HIGH.
A porta PD4 é configurada como OUTPUT utilizando também o registrador DDRD, onde o quarto bit é setado como 1/verdadeiro com o bitwise OR.
// Configura o PD3 como INPUT (Botão)
DDRD &= ~(1 << DDD3);
// Habilita o resistor de pull-up interno em PD3
PORTD = (1 << PORTD3);
// Configura o PD4 como OUTPUT (Gate MOSFET)
DDRD |= (1 << DDD4);
O código equivalente utilizando a "linguagem Arduino" seria:
pinMode(3, INPUT_PULLUP);
pinMode(4, OUTPUT);
Leituras da porta INPUT para debounce
O efeito "trepidação mecânica" ou Bounce, é extremamente comum em chaves físicas utilizadas em sistemas digitais. Este efeito pode variar os níveis de HIGH/LOW com o clique mecânico do botão, prejudicando a exatidão do sinal, para resolver este problema é aplicado um Debounce, que pode ser em forma de hardware ou firmware.
Neste código é realizado três leituras na porta de INPUT para debounce, onde estes valores são armazenados em três variáveis do tipo bool "valor1", "valor2" e "estado_botao". O registrador PIND é utilizado para esta operação de leitura do botão, onde setamos o terceiro bit PIND3 como 1/verdadeiro.
int main(void)
{
...
// Leitura inicial armazenada em estado_botao
estado_botao = (PIND & (1 << PIND3));
}
while(1)
{
// Leitura do botão armazenada em valor1
valor1 = (PIND & (1 << PIND3));
_delay_ms(10);
// Segunda leitura do botão armazenada em valor2
valor2 = (PIND & (1 << PIND3));
...
}
O código equivalente utilizando a "linguagem Arduino" seria:
void setup()
{
...
estado_botao = digitalRead(3);
}
void loop()
{
valor1 = digitalRead(3);
delay(10);
valor2 = digitalRead(3);
...
}
Verificação dos valores com debounce e estado da porta OUTPUT
Depois das leituras da porta PD3, os valores são comparados para obter um estado real da porta (Debounce), e depois é verificado se o valor inicial do botão foi modificado para ligar e desligar a bomba d'água (Gate MOSFET) na porta PD4.
Utilizando o resistor pull-up interno, a lógica de on/off é invertida, pois o resistor está garantindo 5V ou HIGH na porta. Então se o valor com debounce estiver em HIGH ou true, desliga a bomba utilizando o registrador PORTD com a lógica bitwise NAND, se não, liga a bomba com o registrador PORTD com a lógica bitwise OR. Depois o último valor com debounce é armazenado na variável estado_botao.
// Comparação para uma leitura aceitável sem drepidação mecânica
if (valor1 == valor2)
{
// Se o valor lido for diferente do estado do botão inicial
if (valor1 != estado_botao)
{
// Se o botão NÃO estiver pressionado..
if (valor1 == true)
{
// Desliga a bomba
PORTD &= ~(1 << PORTD4);
}
else
{
// Se não, liga
PORTD |= (1 << PORTD4);
}
}
// O estado_botao é igual ao valor1
estado_botao = valor1;
}
O código equivalente utilizando a "linguagem Arduino" seria:
if (valor1 == valor2)
{
if (valor1 != estado_botao)
{
if (valor1 == HIGH)
{
digitalWrite(led, LOW);
}
else
{
digitalWrite(led, HIGH);
}
}
estado_botao = valor1;
}
Código completo para Arduino Uno
Se você utilizou um Arduino Uno para realizar os procedimentos desse artigo, e deseja voltar as configurações originais da placa Arduino, como o bootloader, leia o item Voltando as configurações originais do Arduino Uno.
bool valor1;
bool valor2;
bool estado_botao;
void setup()
{
pinMode(3, INPUT_PULLUP);
pinMode(4, OUTPUT);
estado_botao = digitalRead(3);
}
void loop()
{
valor1 = digitalRead(3);
delay(10);
valor2 = digitalRead(3);
if (valor1 == valor2)
{
if (valor1 != estado_botao)
{
if (valor1 == HIGH)
{
digitalWrite(4, LOW);
}
else
{
digitalWrite(4, HIGH);
}
}
estado_botao = valor1;
}
}
Referência