Acionando bomba d'água com registradores do Atmega328p

Eletrônica Arduino 17 de Novembro de 2019 às 14:03

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)
Esquema do acionamento de bomba d'água com transistor MOSFET e Arduino Uno (Atmega328p).

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.

Mini bomba d'água JT100 2.5V 6V para Arduino, NodeMCU e Raspberry Pi 3.

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!

Representação esquemática do transistor MOSFET de canal N e P.

É 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.

Conector jack P4 com fios para protoboard.

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.

Detalhe das ligações no protoboard.

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!

Projeto da bomba d'água com Atmega328p (Arduino Uno).

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); 
Registrador DDRD - Atmega328p.

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

    ...
}
Registrador PIND - Atmega328p.

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;
}
Registrador PORTD - Atmega328p.

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

  1. ATMEGA328P: 8-bit AVR Microcontroller with 32K Bytes In-System Programmable Flash - Datasheet Atmel.