EEPROM - Armazenando dados na memória não volátil do Arduino

Armazenando dados de forma não volátil no Arduino - EEPROM

A necessidade de se armazenar informações é algo bastante recorrente no desenvolvimento de projetos embarcados. Sejam elas um conjunto de variáveis para configurar o seu sistema, ou até  mesmos dados que você queira visualizar após um intervalo de tempo, o armazenamento de informações é muito importante em praticamente todos os tipos de projetos. Porém nem sempre dispomos de um cartão SD, seja por limitações de custo ou até mesmo pinos de I/O, impossibilitando  assim que a utilização de um cartão SD resolvesse o problema. Sabendo disso, neste tutorial, você aprenderá como utilizar a memória EEPROM existente nos microcontroladores Atmega das placas Arduino para armazenar dados permanentemente.

[toc]

Memória EEPROM

A memória EEPROM ou Electrically-Erasable Programmable Read-Only Memory, consiste em um modelo de memória onde diferente da memória RAM, podemos manter dados armazenados após desligarmos o nosso equipamento. Desta forma, é possível salvar informações que podem ser necessárias para o funcionamento do sistema após o seu desligamento, como por exemplo:

  • Configurações
  • Dados de difícil obtenção
  • Dados  estáticos

A utilização de memórias EEPROM, possibilitam com que o desenvolvedor seja capaz de armazenar diversas informações do sistema para uso posterior. Porém, este tipo de  memória possui um ciclo muito pequeno de escritas, o que torna o seu uso viável apenas para o armazenamento de informações que serão pouco modificadas.

Memória eeprom i2c com encapsulamento dip.

O processo de leitura e escrita neste tipo  de memória pode ser feito de duas formas:

  • Paralelo: Cada byte é escrito de forma paralela na memória, sendo  este escrito com base no endereço definido no barramento. Mais rápida, porém gasta uma maior quantidade de pinos para I/O

  • Serial: Cada byte é escrito de forma serializada (normalmente utilizando o protocolo i2c) na memória eeprom. Mais lenta, porém gasta uma menor quantidade de pinos para I/O

Memória EEPROM no Arduino

Os microcontroladores ATmega possuem em sua arquitetura uma pequena memória eeprom, que pode ser utilizada como uma unidade de armazenamento. Cada microcontrolador possui uma de tamanho específico,  segmentada em 1 byte por endereço. A lista abaixo ilustra a quantidade de memória disponível para a microcontroladores utilizados em plataformas como Arduino Nano, Arduino Uno e Arduino Mega:

  • ATmega8,ATmega168 - 512 Bytes
  • ATmega326 - 1024 Bytes
  • ATmega1280, ATmega2560 - 4096 Bytes

Mãos à obra – Armazenando dados na memória EEPROM do Arduino

Neste projeto iremos apenas aprender a como manipular e realizar leituras e escritas na memória EEPROM do Arduino, desta forma iremos precisar apenas de um Arduino com algum dos microcontroladores citados acima.

Componentes Utilizados

Neste projeto iremos utilizar um Arduino Nano, porém praticamente todos os  microcontroladores ATmega dispõem de uma memória eeprom nativa.

Programando

- Bibliotecas

Como iremos apenas aprender como armazenar e ler dados da memória EEPROM do Arduíno, iremos utilizar apenas a biblioteca EEPROM.h que já é nativa da ide que pode ser importada ao seu código da seguinte forma:

#include <EEPROM.h>

- Código Utilizado

Agora que temos o nosso sistema montado, e as bibliotecas adicionadas ao projeto, podemos partir para o código. Observem o código a seguir que utilizaremos como base para o nosso manipulador de memória.

#include <EEPROM.h> // Biblioteca para acesso e manipulação da EEPROM
void setup()   
{
  Serial.begin(115200); // Inicialização da comunicação serial

  Serial.print("Espaco Disponivel em Bytes: "); // Mostra a quantidade  de memória da EEPROM do seu microcontrolador
  Serial.println(EEPROM.length()); // Mostra a quantidade de memória da EEPROM do seu microcontrolador
  escreveByte(0,254); // Escreve o valor 255 na posição 0 da memória  
  byte valor = leByte(0); // Lê o endereço 0 da memória ( onde escrevemos 255 )
  Serial.print("Byte Armazenado: "); // Mostra o Byte Armazenado
  Serial.println(valor); // Mostra o Byte Armazenado
  escreveInt(1,2,1200); // Escreve o valor 1200 na EEPROM ( por ser um int de 2 bytes precisamos utilizar 2 endereços para armazenar)
  Serial.print ("Inteiro Armazenado: "); // Mostra o inteiro Armazenado
  Serial.println(lerInt(1,2)); // Mostra o inteiro Armazenado
  escreveString(3,"Vida de Silício"); // Escreve a String Vida de Silício na EEPROM, começando no  endereço 3
  Serial.println("String Armazenada: "+leString(3)); // Mostra a String armazenada
}

void loop(){
  
}

byte leByte (int endereco1){
  return EEPROM.read(endereco1); // Realizamosa leitura de 1 byte  e retornamos
}

void escreveByte (int endereco1, byte valor){ // Escreve um byte na EEPROM no endereço especificado
  byte valorAtual = leByte(endereco1); // Lemos o byte que desejamos escrever
  if (valorAtual == valor){ // Se os valores forem iguais não  precisamos escrever ( economia de ciclos de escrita )
    return;
  }
  else { // Senão escrevemos o byte no endereço especificado na função
    EEPROM.write(endereco1,valor); // Escreve o byte no endereço especificado na função
  }
  
}



void escreveInt(int endereco1, int endereco2, int valor){ // Escreve um inteiro de 2 bytes na EEPROM
  int valorAtual = lerInt(endereco1,endereco2); // Lemos o valor inteiro da memória
  if (valorAtual == valor){ // Se o valor lido for igual ao que queremos escrever não é necessário escrever novamente
    return;
  }
  else{ // Caso contrário "quebramos nosso inteiro em 2 bytes e escrevemos cada byte em uma posição da memória
      byte primeiroByte = valor&0xff; //Executamos a operação AND de 255 com todo o valor, o que mantém apenas o primeiro byte
      byte segundoByte = (valor >> 8) &0xff; // Realizamos um deslocamento de 8 bits para a direita e novamente executamos um AND com o valor 255, o que retorna apenas o byte desejado
      EEPROM.write(endereco1,primeiroByte); // Copiamos o primeiro byte para o endereço 1
      EEPROM.write(endereco2,segundoByte); // Copiamos o segundo byte para o endereço 2
  }
}

int lerInt(int endereco1, int endereco2){ // Le o int armazenado em dois endereços de memória
  int valor = 0; // Inicializamos nosso retorno
  byte primeiroByte = EEPROM.read(endereco1); // Leitura do primeiro byte armazenado no endereço 1
  byte segundoByte = EEPROM.read(endereco2); // Leitura do segundo byte armazenado no endereço 2
  valor = (segundoByte << 8) + primeiroByte; // Deslocamos o segundo byte 8 vezes para a esquerda ( formando o byte mais significativo ) e realizamos a soma com o primeiro byte ( menos significativo )
  return valor; // Retornamos o valor da leitura

}

void escreveString(int enderecoBase, String mensagem){ // Salva a string nos endereços de forma sequencial
  if (mensagem.length()>EEPROM.length() || (enderecoBase+mensagem.length()) >EEPROM.length() ){ // verificamos se a string cabe na memória a partir do endereço desejado
    Serial.println ("A sua String não cabe na EEPROM"); // Caso não caiba mensagem de erro é mostrada
  }
  else{ // Caso seja possível armazenar 
    for (int i = 0; i<mensagem.length(); i++){ 
       EEPROM.write(enderecoBase,mensagem[i]); // Escrevemos cada byte da string de forma sequencial na memória
       enderecoBase++; // Deslocamos endereço base em uma posição a cada byte salvo
    }
    EEPROM.write(enderecoBase,'\0'); // Salvamos marcador de fim da string 
  }
}

String leString(int enderecoBase){
  String mensagem="";
  if (enderecoBase>EEPROM.length()){ // Se o endereço base for maior que o espaço de endereçamento da EEPROM retornamos uma string vazia
    return mensagem;
  }
  else { // Caso contrário, lemos byte a byte de cada endereço e montamos uma nova String
    char pos;
    do{
      pos = EEPROM.read(enderecoBase); // Leitura do byte com base na posição atual
      enderecoBase++; // A cada leitura incrementamos a posição a ser lida
      mensagem = mensagem + pos; // Montamos string de saídaa
    }
    while (pos != '\0'); // Fazemos isso até encontrar o marcador de fim de string
  }
  return mensagem; // Retorno da mensagem
}


Colocando pra funcionar

Se nada tiver sido modificado no código e sua EEPROM ainda possuir ciclos de escrita, a seguinte mensagem será apresentada no monitor serial:


Entendendo a Fundo

Software

- Incluindo bibliotecas necessárias

Para este sistema, iremos precisar apenas da biblioteca EEPROM.h que já é  nativa do Arduíno e será utilizada como interface entre a EEPROM e o nosso código, desta forma ela pode ser adicionada  da seguinte forma:

#include <EEPROM.h>

- Função Setup

Em nossa função setup, iremos basicamente escrever e ler as variáveis que desejamos armazenar na EEPROM, foram definidos um conjunto de 6 funções, sendo três para escrita e três para leitura de tipos de dados normalmente utilizados, sendo eles:

  • Int
  • Byte
  • String

Sendo assim, no setup iremos apenas utilizar estas funções, da seguinte forma:

- Função escreve byte

Escreve um valor em byte no endereço especificado, neste exemplo estamos escrevendo o valor 254 no endereço 0 da memória.

  escreveByte(0,254); // Escreve o valor 255 na posição 0 da memória

- Função lê byte

Realiza a leitura de um único byte no endereço especificado pelo usuário, neste exemplo estamos lendo o endereço 0.

byte valor = leByte(0);

- Função escreve int

Escreve um valor inteiro composto por 2 bytes, em duas posições quaisquer da eeprom, neste exemplo estamos escrevendo o valor 1200 utilizando os endereços 1 e 2.

escreveInt(1,2,1200);

- Função lê int

Realiza a leitura de dois endereços especificados pelo usuário, reconstruindo o valor inteiro que elas representam, neste exemplo estamos lendo os endereços 1 e 2 da memória.

Serial.println(lerInt(1,2));

- Função escreve string

Escreve uma determinada string de forma sequencial na EEPROM, neste exemplo estamos utilizando um total de 15 endereços (começando do endereço 3) para escrever a string "Vida de Silício" em nossa memória.

escreveString(3,"Vida de Silício");

- Função lê string

Dado um endereço base fornecido, esta função lê sequencialmente toda a string armazenada.

leString(3);

Entendendo cada função implementada

Cada função implementada possui um grau complexidade devido a realização de operações lógicas para quebra de bytes e armazenamento sequencial, desta forma iremos mostrar a forma como cada função é capaz de salvar e recuperar seus respectivos tipos de dados. Porém antes vamos entender um pouco a forma como a nossa memoria funciona.

Imagine a sua  memória como um um conjunto de blocos onde podemos armazenar valores em um intervalo de 0 até 255, e cada um desses intervalos está associado a um endereço, sendo assim, podemos imaginar a nossa memória da seguinte forma: Com essa estrutura de memória podemos salvar qualquer tipo de informação, desde  que o espaço seja suficientemente grande para armazenar todos os valores.

- Função escreveByte

A função escreveByte recebe como argumentos o endereço  e o valor a ser escrito naquela  posição, verificando apenas se o byte que desejamos escrever já não está lá, desta forma economizamos uma escrita que seria feita desnecessariamente, prologando assim a vida útil de nossa memória.

void escreveByte (int endereco1, byte valor){
  byte valorAtual = leByte(endereco1);
  if (valorAtual == valor){
    return;
  }
  else {
    EEPROM.write(endereco1,valor);
  }
}

Estruturalmente, podemos dizer que esta função executa a seguinte operação:

- Função leByte

Já a função leByte, basicamente realiza a leitura do endereço especificado em seu argumento, retornando assim o valor que está armazenado naquele endereço.

byte leByte (int endereco1){
  return EEPROM.read(endereco1);
}

Utilizando o nosso modelo de memória, podemos dizer que estamos realizando a seguinte operação:

- Função escreveInt

Nos microcontroladores ATmega, uma variável  do tipo int, é representada por um total de 2 bytes, sendo estes divididos entre mais significativos (HB) e menos significativos (LB), como a nossa memória permite apenas o armazenamento de 1 byte por endereço. Sabendo disso, é necessário que a nossa função seja capaz de "quebrar" o nosso  valor inteiro de 2 bytes, em duas variáveis de 1 byte cada, para que assim seja possível armazenar esta informação na memória. Para que isso seja feito, iremos utilizar dois tipos de operações lógicas existente em praticamente todas as arquiteturas de computadores, que são as operações rigth shift e and bitwise.

void escreveInt(int endereco1, int endereco2, int valor){
  int valorAtual = lerInt(endereco1,endereco2);
  if (valorAtual == valor){
    return;
  }
  else{
      byte primeiroByte = valor&0xff;
      byte segundoByte = (valor >> 8) &0xff;
      EEPROM.write(endereco1,primeiroByte);
      EEPROM.write(endereco2,segundoByte);
  }
}

 

Sabendo disso o algoritmo funciona da seguinte forma:

  1. Inicialmente verificamos se o valor que desejamos inserir é igual ao que está na memória ( se for economizamos duas escritas na memória )
  2. Caso não seja executamos a seguinte operação:
    1. Dado o nosso valor de exemplo 1001, serão executadas as seguintes operações:
    2.  Aplicamos uma operação AND bit a bit sob o valor que desejamos quebrar com o número 255, desta forma iremos preservar apenas os bits da primeira cadeia de byte que desejamos armazenar. A figura abaixo ilustra como o processo é feito e o resultado obtido através da operação realizada.
    3. Para o segundo byte, realizaremos o mesmo processo do passo 2, porém ao invés apenas aplicar a operação lógica AND, iremos antes deslocar os bits que estão na camada superior. Para que dessa forma, cheguem a posição dos bits menos significativos para a aplicação da  máscara.
    4.  Por fim, com os bytes separados, a  função salva cada um deles no endereço especificado como mostra a figura abaixo:

- Função leInt

O processo de leitura segue praticamente a lógica inversa do processo de escrita, onde iremos ler cada byte e montar o nosso valor da seguinte forma:

  1. Relizamos uma leitura do endereço de valor mais significativo, este  valor é deslocado 8 bits a esquerda para que volte a sua posição de bit mais significativo.
  2. Realizamos uma leitura do endereço de valor menos significativo, este valor é somado ao  valor deslocado para que volte a posição de bit menos significativo.
  3. Temos o nosso  valor montado novamente.

 

int lerInt(int endereco1, int endereco2){
  int valor = 0;
  byte primeiroByte = EEPROM.read(endereco1);
  byte segundoByte = EEPROM.read(endereco2);
  valor = (segundoByte << 8) + primeiroByte;
  return valor;
}

- Função escreveString

A função escreve string por sua vez, não utiliza de recursos de deslocamento de bits, devido ao fato de que cada caractere, é um único byte. Ou seja, uma string nada mais é do que um vetor de bytes alocados sequencialmente. Sabendo disso, o nosso algoritmo de salvar uma string na memória segue a seguinte lógica:

  1. Dado um endereço base, e o tamanho da string verificamos se é possível o armazenamento ou não.
    1. Caso não seja possível, o  valor não é salvo.
    2. Caso seja possível, a string é alocada sequencialmente na memória começando com o endereço base e terminando sempre com um ''\0''
void escreveString(int enderecoBase, String mensagem){
  if (mensagem.length()>EEPROM.length() || (enderecoBase+mensagem.length()) >EEPROM.length() ){
    Serial.println ("A sua String não cabe na EEPROM");
  }
  else{
    for (int i = 0; i<mensagem.length(); i++){
       EEPROM.write(enderecoBase,mensagem[i]);
       enderecoBase++;
    }
    EEPROM.write(enderecoBase,'\0');
  }
}

- Função leString

A função leString por sua vez, realiza praticamente o mesmo processo que a leitura, porém ao invés de armazenar os bytes como na função escreveString, ela utiliza a função read, para ler cada byte armazenado sequencialmente. Desta forma podemos dizer que o algoritmo funciona da seguinte forma:

  • Com base no endereço inicial, a função lê cada byte lido, até que o caractere de fim de texto '\0', seja encontrado. Quando encontrado uma string montada é retornada pela função.
String leString(int enderecoBase){
  String mensagem="";
  if (enderecoBase>EEPROM.length()){
    return mensagem;
  }
  else {
    char pos;
    do{
      pos = EEPROM.read(enderecoBase);
      enderecoBase++;
      mensagem = mensagem + pos;
    }
    while (pos != '\0');
  }
  return mensagem;
}

Desafio

Agora que sabemos como manipular a memória EEPROM do nosso Arduino, tente adicionar esta funcionalidade a algum projeto que seja necessária a configuração de uma variável em tempo real.  Um exemplo de sistema desse tipo são os dataloggers, onde  precisamos configurar informações como tempo de leitura e configuração de sensores.

Considerações finais

Este tutorial, teve como objetivo mostrar como manipular a memória EEPROM, interna do seu Arduino, funcionando como uma pequena unidade de armazenamento para informações importantes. Espero que tenham gostado do conteúdo apresentado, sinta-se à vontade para nos dar sugestões, críticas ou elogios. Lembre-se de deixar suas dúvidas nos comentários abaixo.


Sensor de umidade do solo com Arduino - Higrômetro

Sensor de umidade do solo com Arduino - Higrômetro

Neste tutorial daremos o primeiro passo para desenvolver um sistema inteligente voltado para o monitoramento e controle das variáveis existentes em uma plantação. Começaremos aprendendo como usar o sensor de umidade do solo, também chamado de Higrômetro, em conjunto com um Arduino Nano.

[toc]

Sistemas automáticos na Agricultura

Plantas precisam de um solo de boa qualidade para crescerem de forma saudável e com qualidade, porém, existem vários tipos de situações ambientais que dificultam o seu crescimento, sendo algumas delas:

  • Irradiação solar excessiva;
  • Falta de nutrientes no solo;
  • Solo com baixa umidade;
  • Pragas;
  • Entre outros.

Todas as situações descritas anteriormente podem gerar prejuízo. Por este motivo, faz-se necessária a utilização de, sistemas automáticos os quais vêm sendo cada vez mais explorados que auxiliem o agricultor no monitoramento de seus cultivos visando obter uma eficiência cada vez maior e consequentemente a redução da ocorrência de situações indesejadas

Sensor umidade do solo - Higrômetro

Neste tutorial, iremos utilizar o sensor de umidade do solo, para aferir a condutividade do solo através de uma haste com dois eletrodos existentes no mesmo. O princípio de funcionamento deste circuito é bem simples, pois, resume-se ao fato de que, através da aplicação de uma determinada corrente X nos eletrodos citados, é possível estimar o quão úmido ou seco o solo estará em virtude da condutividade do solo em ambos os casos. Basicamente, quando o solo estiver úmido, teremos uma condutividade melhor devido a absorção da água e isso resultará em um fluxo maior de corrente entre os dois eletrodos. Entretanto se o solo estiver seco, teremos pouca ou até nenhuma corrente entre os eletrodos.

O sensor é composto basicamente duas hastes que ficaram presas ao solo que iremos monitorar e um circuito comparador que irá nos retornar o nível de condutividade do solo. Este circuito é composto por um total de 6 pinos, sendo dois destes utilizados para conectar a haste de metal ao circuito de comparação. As outras 4 entradas possuem as funções de alimentar o circuito e retornar o nível de umidade do solo.

A determinação do nível de umidade do solo pode ser feita de duas formas, sendo elas:

  • Um sinal digital que basicamente informa se o solo está seco ou não ( Menor precisão, porém não depende de um circuito ADC )
  • Um sinal analógico que pode ser utilizado para estimar o quão úmido o solo está ( Maior precisão, porém dependerá de um circuito ADC )
Sensor de umidade do solo com Arduino Higrômetro
Sensor de umidade do solo - Higrômetro

Especificações do dispositivo

  • Tensão de Operação: 3,3-5v
  • Sensibilidade ajustável via potenciômetro
  • Saída Digital TTL (D0) e Analógica(A0)
  • Led indicador de detecção de umidade

Mãos à Obra - Medindo a umidade do solo utilizando o Arduino - Higrômetro

Componentes utilizados

Montando o projeto

Nesta primeira parte do tutorial, iremos apenas conectar o sensor de umidade, desta forma,  iremos utilizar o seguinte esquema de ligação:

Mapa de ligação dos pinos

A montagem final do nosso sistema deve ser semelhante ao modelo abaixo

Sensor de umidade do solo com Arduino Higrômetro
Diagrama de montagem do sensor de umidade do solo - Higrômetro

Veja só como ficou o nosso sistema inicial.

Sensor de umidade do solo com Arduino Higrômetro
Montagem do circuito - sensor de umidade do solo - Higrômetro

Antes de ligar o seu circuito, verifique se todas as conexões foram feitas corretamente. Um curto circuito causado por uma ligação errada pode danificar todo o seu projeto.

Programando

Com a parte física do nosso projeto montada, iremos agora partir para a parte de codificação do sistema. Nesta primeira versão não iremos utilizar nenhuma biblioteca em especial, porém iremos utilizar funções para leitura de dados analógicos e também iremos construir o nosso sistema de leituras de uma forma um pouco diferente como pode ser visto no código abaixo:

/* Nome: Sistema de aferição de umidade de solo - Higrômetro
 * Feito por: Danilo Almeida
 * Data: 7/11/2017
 */
#define sensorUmidade A0 // Sensor de umidade de solo do módulo
unsigned long tempoAnterior = 0; // Variável utilizada para guardar o tempo anterior
unsigned long intervalo = 1000; // Intervalo de tempo em MS para cada leituraa
void setup() {
  Serial.begin(9600); // Inicialização da comunicação serial

}
void loop() {
  unsigned long tempoAtual = millis(); // Realizamos a leitura atual do tempo em que o nosso Arduino Nano está ligado
  if (tempoAtual-tempoAnterior > intervalo){ // Pequena lógica para realizar leituras temporizadas sem parar o microcontrolador
      tempoAnterior =tempoAtual; // Guardamos o tempo anterior como o ultimo intervalo de tempo lido
      int leitura = analogRead(sensorUmidade); // Leitura dos dados analógicos vindos do sensor de umidade de solo

      if (leitura<=1023 && leitura>=682){ // Se a leitura feita for um valor entre 1023 e 682 podemos definir que o solo está com uma baixa condutividade, logo a planta deve ser regada
        Serial.println("Nível de Umidade Baixo");
      }else{
        if (leitura<=681 && leitura>=341){ // Se a leitura feita for um valor entre 681 e 341 podemos definir que o solo está com um nível médio de umidade, logo dependendo da planta pode ou não ser vantajoso regar
        Serial.println("Nível de Umidade Médio");
        }
        else{
          if (leitura<=340 && leitura>=0){ // Se a leitura feita for um valor entre 0 e 340 podemos definir que o solo está com um nível aceitável de umidade, logo talvez não seja interessante regar neste momento
            Serial.println("Nível de Umidade Alto");
          }
        } 
      }
  }
}

Entendendo a Fundo

Software

- Definições e variáveis utilizadas no projeto

Inicialmente definimos todas as variáveis que iremos utilizar tanto para controlar as leituras que serão efetuadas quanto para realizar a leitura da entrada analógica do  sistema. Neste trecho de código definimos as variáveis  intervalo, tempoAnterior e criamos uma definição para o pino A0 do Arduino com o nome de sensorUmidade.

#define sensorUmidade A0 // Sensor de umidade de solo do módulo
unsigned long tempoAnterior = 0; // Variável utilizada para guardar o tempo anterior
unsigned long intervalo = 1000; // Intervalo de tempo em MS para cada leitura

- Função Setup - Inicialização da comunicação serial

Nesta primeira versão, iremos apenas verificar o nível de umidade do solo e com base nesta medição informar se o solo está úmido ou não. Para isso iremos utilizar a comunicação serial. Logo neste trecho de código basicamente inicializamos a comunicação serial do nosso Arduino.

void setup() {
  Serial.begin(9600); // Inicialização da comunicação serial

}

- Função Loop - Usando a função millis para contar o tempo

Nossa função loop tem como objetivo realizar o processo de leitura dentro de cada  intervalo de tempo definido na variável intervalo, porém diferente de como fazemos na maioria das implementações, não iremos utilizar o comando delay para sincronizar cada leitura realizada. Isso ocorre pois o comando  delay "congela" o microcontrolador o impedindo de executar outras ações, como por exemplo ler um outro sensor, ou receber dados da porta serial. Com isso neste projeto iremos utilizar a função millis para sincronizar as leituras e não "congelar"o microcontrolador, possibilitando assim com que ele faça outras tarefas enquanto aguarda o tempo de realizar uma nova leitura.

O processo de sincronizar a leitura de forma não bloqueante é feito de uma maneira bem simples:

  1. Inicialmente armazenamos o tempo atual ( que é retornado pela função millis ).
      unsigned long tempoAtual = millis(); // Realizamos a leitura atual do tempo em que o nosso Arduino Nano está ligado
    
  2. Com o tempo atual do microcontrolador armazenado, iremos agora realizar uma operação de subtração entre o tempo atual lido e o último tempo que armazenamos.
    if (tempoAtual-tempoAnterior > intervalo)
  3. Se a subtração entre o tempo atual do microcontrolador e o último tempo armazenado for maior que o intervalo de tempo para cada leitura, significa que já  é hora de realizar a leitura desejada, porém antes devo atualizar o meu tempo anterior já que realizei uma leitura.
    tempoAnterior =tempoAtual; // Guardamos o tempo anterior como o ultimo intervalo de tempo lido
    
  4.  Recomeçamos o processo no passo 1

- Leitura do nosso medidor de umidade de solo

Agora iremos realizar a leitura do nosso sensor de umidade de solo através da porta A0, esta leitura é feita através da função analogRead como mostra o código abaixo:

      int leitura = analogRead(sensorUmidade); // Leitura dos dados analógicos vindos do sensor de umidade

Esta função basicamente retorna um valor numérico entre 0 e 1023, que representa o valor tem Volts lido do sensor de umidade. O valor está entre 0 e 1023 devido a resolução do circuito ADC que já vem integrado ao Arduíno, se você precisar de uma resolução maior, pode também utilizar circuitos ADC's dedicados.

- Tomada de decisão baseada no valor medido pelo sensor de umidade

Já por fim ( porém não menos importante ), iremos mostrar através da porta serial, em qual intervalo de valores a sua leitura está contida. Para isso, basicamente dividimos o valor da resolução máxima do circuito ADC do Arduino 1024 valores por três, o que resulta em três estados chamados: umidade baixa, umidade média, umidade alta.

      if (leitura<=1023 && leitura>=682){ // Se a leitura feita for um valor entre 1023 e 682 podemos definir que o solo está com uma baixa condutividade, logo a planta deve ser regada
        Serial.println("Nível de Umidade Baixo");
      }else{
        if (leitura<=681 && leitura>=341){ // Se a leitura feita for um valor entre 681 e 341 podemos definir que o solo está com um nível médio de umidade, logo dependendo da planta pode ou não ser vantajoso regar
        Serial.println("Nível de Umidade Médio");
        }
        else{
          if (leitura<=340 && leitura>=0){ // Se a leitura feita for um valor entre 0 e 340 podemos definir que o solo está com um nível aceitável de umidade, logo talvez não seja interessante regar neste momento
            Serial.println("Nível de Umidade Alto");
          }
        } 
      }

Desafio

Agora que temos o nosso projeto montado e funcionando tente melhorar um pouco o nível de medição do sistema. Divida o valor máximo do conversor ADC por um valor maior que três e crie mais ifs para que você seja capaz de identificar melhor o nível de umidade do solo.

Considerações Finais

Este tutorial teve como objetivo apresentar e ilustrar o funcionamento do sensor de umidade do solo, que por sua vez, tem uma aplicação bastante interessante e importante que é identificar em qual momento uma planta deve ser regada, para que dessa forma ela tenha uma qualidade de vida melhor e seja capaz de produzir e aumentar a qualidade de sua produção. Como dito anteriormente, este projeto será uma série onde iremos construir um sistema de monitoramento em tempo real do solo e do ambiente onde nossa plantação está. Espero que tenham gostado do conteúdo apresentado, sinta-se à vontade para nos dar sugestões, críticas ou elogios. Lembre-se de deixar suas dúvidas nos comentários abaixo.


SCT-013 - Sensor de Corrente Alternada com Arduino

SCT-013 - Sensor de Corrente Alternada com Arduino

Neste tutorial ensinaremos a você como medir corrente alternada e estipular a potência instantânea de um circuito utilizando o Sensor de corrente alternada não invasivo SCT-013 juntamente com Arduino. Para este projeto, iremos medir a corrente e a potência de um ferro de solda.

Esse tutorial é dividido em três partes.

  1. Introdução: Nessa parte você conhecerá um pouco mais o sensor SCT013
  2. Mãos à obra: Aqui você aprenderá a usar o Sensor de corrente SCT-013 na prática
  3. Entendendo a fundo: Por fim você entenderá como funciona o software e hardware usado na experiência da parte 2

[toc]

Sensor de corrente não invasivo SCT-013

O sensor de corrente SCT-013 é muito versátil e tem como principal vantagem o fato de não precisar de contato elétrico com o circuito para medir a corrente elétrica alternada. Ou seja, não precisamos abrir o circuito para ligá-lo em série com a carga, basta apenas "abraçar" um dos fios ligados ao equipamento a ser monitorado.

SCT013 sensor de corrente ac
Sensor de corrente SCT013

Um pouco de física

Para fazer a medição da corrente sem a necessidade de contato elétrico com o circuito esse sensor de corrente alternada utiliza as propriedades magnéticas da corrente elétrica.

- Lei de Ampère

A Lei de Ampère diz que todo condutor por onde flui uma corrente elétrica induz ao seu redor um campo magnético proporcional à corrente.

Linhas de campo geradas pela corrente elétrica
Linhas de campo geradas pela corrente elétrica

- Corrente Alternada

A corrente alternada tem uma peculiaridade de se comportar como uma senoide, sendo assim sua intensidade varia ao longo do tempo indo do máximo positivo ao máximo negativo. Esse comportamento oscilatório tem uma frequência que pode ser de 50Hz ou de 60Hz conforme o país ou região. No Brasil é adotado a frequência de 60Hz, ou seja: a corrente elétrica varia entre positivo e negativo 60 vezes em 1 segundo.

Corrente Alternada
Corrente Alternada

Como o campo magnético é proporcional ao valor de corrente, o campo magnético gerado ao redor do condutor percorrido por uma corrente alternada irá variar ao logo do tempo conforme a variação da mesma.

- Lei de Faraday - lei da indução eletromagnética

A lei de Faraday diz que um campo magnético que varia ao longo do tempo induz em uma espira uma força eletromotriz que gera um corrente elétrica proporcional a intensidade do campo magnético.

Lei de Faraday
Lei de Faraday

Na figura acima podemos entender essa lei na prática. Veja que ao aproximar o imã das espiras estamos variando o campo magnético e está sendo indicado uma tensão no voltímetro (força eletromotriz) chegando quase a 20V. Depois, ao afastar o imã temos a tensão indo quase a 20V no sentido contrário.

- Resumo

  1. Lei de Ampère: Um condutor percorrido por uma corrente induz a formação de um campo magnético ao seu redor de valor proporcional à corrente;
  2. Corrente Alternada: A corrente alternada varia ao longo do tempo gerando um campo magnético também variante ao longo do tempo;
  3. Lei da indução de Faraday: Um campo magnético variante no tempo induz numa espira uma tensão, e por consequência um corrente elétrica, proporcional à intensidade do campo magnético

Levando em conta essas três propriedades, podemos montar um transformador de corrente.

Transformadores de corrente

Existe uma grande gama de sensores de corrente que usam essas propriedades magnéticas. Esse sensores são conhecidos com TC (Transformador de Corrente), que em inglês é CT (Current Transformer).

Um transformador de corrente, nada mais é que um conjunto de espiras que são colocadas ao redor de um condutor ao qual queremos medir a corrente. O transformador de corrente (TC) terá em seus polos uma corrente alternada induzida Is, que é proporcional a corrente alternada Ic que percorre o condutor ao qual pretendemos medir a corrente elétrica.

 Esquema para exemplificar o SCT-013
Esquema para exemplificar o SCT-013

A corrente induzida no TC também será inversamente proporcional ao número de espiras de sua bobina.

Esse sensores são divididos em 2 modelos: Os split-core (núcleo dividido) e os solid-core (núcleo sólido).

Solid-core CT - Transformador de núcleo sólido ou núcleo anel - Não possui possibilidade de abertura
Split-core CT - Transformador de corrente de núcleo dividido - Permite a abertura

Transformador de corrente SCT-013

SCT é a sigla para Split-core Current Transformer, ou seja, Transformador de corrente de núcleo dividido. Para fazer fazer a medição da corrente elétrica o SCT-013 possui uma bobina interna em sua estrutura, como podemos ver na figura abaixo.

Bobina do Sensor de corrente não invasivo SCT-013
Bobina do Sensor de corrente não invasivo SCT013

Podemos ver essa bobina com mais detalhes na foto a seguir

Dentro do Sensor de corrente SCT-013
Dentro do Sensor de corrente SCT013

O circuito é bem simples:

Circuito interno do SCT-013
Circuito interno do SCT-013

- Os Modelos de SCT-013

Com base nesse princípio de funcionamento, foram criados diferentes tipos de sensores não-invasivos, como pode ser observado em seu datasheet, com o objetivo de atenderem os mais diversos cenários, de forma que não exista um "melhor", mas sim o mais recomendado para a aplicação recorrente.

Tabela com os diferentes modelos do sensor de corrente não-invasivo

As duas principais diferenças são a Corrente eficaz máxima a ser medida (Input current) -  e o Tipo de saída do sensor (Output type).

É possível observar que somente o modelo SCT-013-000 apresenta uma variação de corrente em sua saída de 0-50mA, já os outros modelos apresentam uma variação tensão de 0-1V, onde por meio destas variações é possível mensurar a corrente elétrica.

Para sabermos qual será a taxa variação tanto de corrente quanto de tensão basta dividirmos o valor máximo  da saída pelo valor máximo a ser medido. Abaixo temos alguns exemplos deste cálculo:

  • SCT-013-000:
    • 0,05 / 100 = 0,5mA. A cada um Ampere a mais ou a menos, sua saída será de 0,5mA para mais ou a menos;
  • SCT-013-005:
    • 1 / 5 = 0,2V. A cada um Ampere a mais ou a menos, sua saída será de 0,2V para mais ou a menos;
  • SCT-013-050:
    • 1 / 50 = 0,02V. A cada um Ampere a mais ou a menos, sua saída será de 0,02V para mais ou a menos.

- SCT-013-000 - 100A / 0-50mA

Para esse tutorial usaremos o SCT-013-000. Ele poder medir valores de 0 até 100A de corrente alternada. Em sua saída teremos valores entre 0 a 50mA proporcionais ao valor de corrente percorrido no condutor principal.

Como nosso Arduino só lê valores de tensão, iremos precisar montar um circuito auxiliar para que essa corrente percorra um resistor e assim possamos converter os valores de correntes gerado pelo sensor em valores de tensão. Explicaremos o passo a passo de como dimensionar esse circuito no tópico Entendendo o Hardware.


Mãos à Obra - Monitorando a corrente AC com o Sensor de corrente SCT-013

Componentes necessários

Serão necessários os seguintes componentes para a execução deste projeto:

Utilizaremos o SCT-013 100A e o Arduino Uno, além de um aparelho que terá sua corrente elétrica medida, no nosso caso, um ferro de solda. Você poderá medir a corrente elétrica de outros dispositivos.

O resistor de 330Ω foi dimensionado por meio de uma sequência de cálculos com o propósito de aumentar a precisão das medidas deste sensor de corrente. Os cálculos poderão ser visto na sessão "Entendendo o SCT-013".

*Caso o seu SCT-013 seja de outro modelo ao invés de 100A, o passo a passo será diferente.

sct013 sensor de corrente

Montando o projeto

Esse sensor de corrente normalmente vem com um plugue P2 do tipo macho em sua ponta. Para esse tutorial nós removemos ele e conectamos os dois fios presentes no interior do cabo diretamente na protoboard. Caso você não queira remover o plugue P2, recomendamos que você adquira um plugue P2 do tipo fêmea para poder utilizar esse sensor de corrente.

Com os componentes em mãos, montaremos o seguinte circuito na protoboard:

Após realizar esta montagem, é necessário conectar o SCT-013 ao condutor por onde a corrente elétrica a ser medida passará.

AVISO: Não conecte este sensor de corrente de acordo com a imagem abaixo, pois não será possível medir a corrente elétrica. A explicação do por quê será feita mais abaixo.

Como a corrente elétrica produz campo magnético conforme seu sentido e o sentido da corrente em um fio é o oposto ao sentido do outro fio, os campos magnéticos produzido pelos dois acabam se anulando. Se não há campo magnético, não há indução magnética no transformador do sensor de corrente, fazendo com que não circule a corrente Is necessária para a medição da corrente Ic consumida. Por esse motivo não podemos conectar este sensor aos dois fios de alimentação.

Com isso finalizamos o hardware do nosso projeto. Agora, bora programar!

Programando

- Bibliotecas necessária

É necessário baixar a biblioteca EmonLib (download). Após baixar, descompacte e mova para a pasta libraries da IDE do Arduino. A EmonLib será utilizada para nos auxiliar a calcular o valor da corrente elétrica consumida.

- Código utilizado

Para sabermos quantos Amperes estão passando pelo condutor, basta realizar a seguinte programação:

#include "EmonLib.h"

EnergyMonitor SCT013;

int pinSCT = A0;   //Pino analógico conectado ao SCT-013

int tensao = 127;
int potencia;

void setup()
{
    SCT013.current(pinSCT, 6.0606);

    Serial.begin(9600);
}

void loop()
{
    double Irms = SCT013.calcIrms(1480);   // Calcula o valor da Corrente
    
    potencia = Irms * tensao;          // Calcula o valor da Potencia Instantanea    

    Serial.print("Corrente = ");
    Serial.print(Irms);
    Serial.println(" A");
    
    Serial.print("Potencia = ");
    Serial.print(potencia);
    Serial.println(" W");
   
    delay(500);

    Serial.print(".");
    delay(500);
    Serial.print(".");
    delay(500);
    Serial.println(".");
    delay(500);
}

Após compilar e enviar o código ao Arduino, os valores de corrente elétrica e potência instantânea serão mostrados no Monitor Serial da IDE do Arduino, e serão atualizados a cada 2 segundos.

Colocando para funcionar

Código compilado e circuito montado! Veja abaixo o resultado.

Circuito montado na prática
Circuito montado na prática
Monitor Serial aberto

Entendendo a fundo

Software

– Incluindo as bibliotecas a serem utilizadas no projeto

Inicialmente, observe que foi necessário incluir uma biblioteca no código para que o mesmo pudesse funcionar corretamente. A biblioteca EmonLib.h é a responsável por realizar os cálculos para encontrar o valor eficaz da corrente a ser medida, baseando-se nas amostras colhidas no pinSCT.

#include "EmonLib.h"

– Declarando o objeto SCT013

Em seguida, cria-se um objeto que será utilizado posteriormente para representar o sensor de corrente SCT-013 no código.

Lembre-se: SCT013 é apenas um nome, sendo assim, é importante ressaltar que este objeto poderia ser chamado por qualquer outro nome, como por exemplo, sensorSCT.

EnergyMonitor SCT013;

– Definindo as configurações iniciais

Declaramos pinSCT = A0 para poder facilitar e tornar intuitivo o uso da porta analógica do arduino.

int pinSCT = A0;    //Pino analógico conectado ao SCT-013

Declaramos duas variáveis, uma chamada Tensao, e atribuímos o valor de 127, que equivale a tensão da rede aqui no nosso estado, e outra chamada Potencia, que será utilizada para reservar o resultado da multiplicação da tensão e da corrente.

int tensao = 127;
int potencia;

No void setup(), chamamos a função SCT013.current(pinSCT, 6.0606) da biblioteca EmonLib, para que seja realizado o cálculo do valor eficaz da corrente, onde ele se baseará nas amostras lidas do pinSCT, e é empregado um valor de calibração de 6.0606 que ensinaremos como encontra-lo mais abaixo.

SCT013.current(pinSCT, 6.0606);

Habilitamos também a comunicação serial entre o arduino e o computador por meio do comando Serial.begin(9600).

Serial.begin(9600);

Caso você tenha dúvidas sobre como utilizar a comunicação serial do arduino, recomendamos que veja o tutorial Comunicação Serial Arduino (clique aqui), presente no portal.

– Aquisição do valor de corrente

Na função void loop(), utiliza-se primeiramente a função SCT013.calcIrms() para atribuir o valor de corrente à variável Irms. O valor entre parênteses representa o número de amostras que a função irá ler do pinSCT.

    double Irms = SCT013.calcIrms(1480);

Veja que SCT013 é o nome que definimos para o objeto. Para usar uma função ligada a esse objeto, colocamos seu nome seguido de ponto e o nome da função. Ex: nomeobjeto.calcIrms().

- Cálculo da potência instantânea

Por meio da multiplicação da corrente Irms pela tensão estipulada, conseguimos descobrir a potência do dispositivo.

    potencia = Irms * tensao;

Em seguida imprimimos o valor de corrente e da potência no monitor serial:

    Serial.print("Corrente = ");
    Serial.print(Irms);
    Serial.println(" A");

    Serial.print("Potencia = ");
    Serial.print(potencia);
    Serial.println(" W");

Esperamos um tempo para a próxima medição.

    delay(500);
    Serial.print(".");
    delay(500);
    Serial.print(".");
    delay(500);
    Serial.println(".");
    delay(500);

Hardware

- Corrente gerada pelo sensor

O sensor é calibrado para medir a corrente alternada máxima de 100A AC. Esse valor de 100A é o valor RMS, que também é chamado de valor eficaz. O valor RMS é igual ao máximo valor que a corrente pode alcançar (corrente de pico) dividido pela raiz quadrada de dois. 

sensor de corrente SCT013

Então, temos que a corrente de pico máxima medida é de 141.4A:

i (medido) = √2 * i (rms) = 1,414 * 100A = 141,4 A

Sabendo que para uma corrente de 100A no primário, ele produz 50mA no secundário, é só jogarmos na fórmula de relação de transformação. O resultado será:

N1 / N2 = I2 / I1

  • I1 = corrente no primário (corrente a ser medida);
  • I2 = corrente no secundário;
  • N1 = número de votas do primário (no caso deste sensor, N1 será igual a 1);
  • N2 = número de voltas do secundário.

N2 = 2000 espiras.

A corrente na saída do sensor é inversamente proporcional ao número de voltas (aqui é 2000):

i (sensor) = i (medido) / numero_de_espiras = 141,4A / 2000 = 0,0707A

Teremos na saída do sensor o sinal da corrente induzida semelhante ao da figura a seguir:

Sinal na saída do sensor de corrente SCT para um valor de corrente eficaz máxima de 100A
Sinal na saída do SCT013 para um valor de corrente eficaz  de 100A

- Transformando corrente em tensão - Calculando a resistência de carga

O Arduino UNO só realiza, em seus pinos de entrada analógica, a leitura de níveis de tensão (entre 0V a 5V). Dessa forma, precisamos converter o sinal de corrente alternada do SCT-013 para um valor de tensão que seja legível para o Arduino.

O primeiro passo é adicionar um resistor de carga entre os polos do sensor de corrente:

Sensor sct013 esquema de ligação

Como a corrente alterna em torno de zero, vamos escolher um resistor que de na saída um valor máximo de tensão de 2,5V.

R(carga) = U(sensor)/I(sensor) = 2,5V / 0,0707A = 35,4Ω

 

O resistor de carga ideal é de 35,4Ω para uma corrente de até 100A, nesse caso usariamos um resistor de 33Ω. Dessa forma teremos o seguinte sinal de tensão sobre o resistor de carga:

Sinal de tensão sobre o resistor de 33
Sinal de tensão sobre o resistor de carga de 33Ω para uma corrente eficaz de 100A

OBS: Para nosso projeto, não iremos medir valores maiores que 10A. Dessa forma, podemos considerar que nossa corrente máxima é 10 vezes menor. Logo:

i (sensor) = i (medido) / numero_de_espiras = 14,14A / 2000 = 0,00707A

R(carga) = U(sensor)/I(sensor) = 2,5V / 0,00707A = 354Ω

Portanto, para nosso projeto adotamos o resistor de 330Ω.

Ou seja, você pode calcular o resistor ideal para a faixa de operação que você precisa. Se for 100A, você pode adotar o de 33Ω, se for de 10A você pode usar um resistor de 330Ω. Para outros valores, basta você calcular.

Seguiremos essa explicação considerando a faixa de operação de 100A, que é o máximo para nosso sensor.

- Convertendo sinal de tensão AC para DC

Agora temos um sinal de tensão alternada variando entre 2,5V positivo e 2,5V negativo. O Arduino não pode medir tensão negativa, então precisamos somar 2,5 V ao sinal para que ele varie entre 0V a 5V.

O primeiro passo para isso é montar um divisor de tensão usando a alimentação de 5V que a placa Arduino fornece.  Assim, consideramos R1 e R2 iguais a 10kΩ, e com isso, a tensão sobre eles será igual, pois os 5V provenientes do Arduino se dividirá igualmente entre eles.

Circuito divisor de tensão
Circuito divisor de tensão

Em seguida adicionamos um capacitor entre o GND e a saída de 2,5V no meio do divisor de tensão:

Circuito de offset

Esse circuito funcionará como uma bateria de 2,5V adicionando essa tensão à fonte AC. Este valor de tensão que acrescentamos a forma de onda é chamado de offset.

Forma de onda da tensão no resistor de carga

 

Forma de onda com offset

Veja como vai fica nosso circuito:

Sensor sct013 esquema de ligação completo

Na figura a seguir mostramos o circuito com seus respectivos sinais:

Como explicado, o circuito de offset funciona como uma fonte tensão de 2,5V DC, somando essa tensão à senoide do SCT-013. O circuito poderia ser ilustrado como a figura a seguir:

- Calibrando o software

Agora que sabemos o sensor carga, modificamos a função SCT013.current onde definimos o pino de entrada e o valor de calibração.

SCT013.current(pinSCT, Valor_de_Calibracao);

Este valor é de calibração, destinado justamente para caso queiramos mudar o valor do resistor de carga. Para descobrir ele, basta dividir o número total de voltas (espiras) do secundário pelo valor do resistor de carga dimensionado:

  • Valor_de_Calibração = 2000 / 33
  • Valor_de_Calibração = 60,606

Dessa forma, teremos:

SCT013.current(pinSCT, 60,606);

obs: Para nosso projeto prático nosso resistor escolhido foi de 330Ω devido ao fato de trabalharmos com uma faixa de operação de 10A. Dessa forma o valor de calibração usado no projeto prático foi de 6,0606.

Valor_de_Calibração = 2000 / 330 = 6,0606

Mudando o range de medição

Calculamos até aqui o valor de uma resistência de carga e valor de calibração do software que possibilita nosso software medir valores de corrente eficazes de até 100A, que é o máximo valor de projeto do sensor. Só que conforme a aplicação, nunca chegaremos a correntes tão altas. Por isso, podemos calibrar nosso software e circuito para ler valores de máxima corrente distintos, desde que estejam dentro do permitido para esse sensor.

Talvez você tenha percebido inclusive que o valor de resistência encontrado em nossos cálculos (33Ω) foi 10 vezes menor que o usada em nossa experiencia (330Ω). Para nosso projeto adotamos uma corrente máxima de 10A, visto que a maiorias dos eletrodomésticos consomem correntes menores que esse valor.

Para calcular a resistência de carga adequada basta repetirmos os seguintes passos:

- Passo 1 - Escolher a corrente rms máxima que será medida pelo circuito

imax (rms) = 10A

- Passo 2 - Converter esta corrente para o valor de pico:

i (medido) = √2 * imax (rms) = 1,414 * 10A = 14,14 A

- Passo 3 - Descobrir o número total de espiras da bobina do secundário:

Sabendo que para uma corrente de 100A no primário, ele produz 50mA no secundário, é só jogarmos na fórmula de relação de transformação. O resultado será:

N1 / N2 = I2 / I1

  • I1 = corrente no primário (corrente a ser medida);
  • I2 = corrente no secundário;
  • N1 = número de votas do primário (no caso deste sensor, N1 será igual a 1);
  • N2 = número de voltas do secundário.

N2 = 2000 espiras.

- Passo 4 - Calcular a corrente de pico máxima do secundário do SCT-013:

i (sensor) = i (medido) / numero_de_espiras = 14,14A / 2000 = 0,00707A

- Passo 5 - Dimensionar o resistor de carga:

R(carga) = U(sensor)/I(sensor) = 2,5V / 0,00707A = 354Ω

Para o projeto, arredondamos este valor para 330Ω, que é um valor comercial de resistor.

R(carga) = 330Ω

- Passo 6 - Colocando o valor de calibração no software:

Agora que sabemos o sensor carga, modificamos a função SCT013.current onde definimos o pino de entrada e o valor de calibração.

SCT013.current(pinSCT, Valor_de_Calibracao);

Este valor é de calibração, destinado justamente para caso queiramos mudar o valor do resistor de carga. Para descobrir ele, basta dividir o número total de voltas (espiras) do secundário pelo valor do resistor de carga dimensionado:

Valor_de_Calibração = N2 / R(carga)

Valor_de_Calibração = 2000 / 330

Valor_de_Calibração = 06,0606

Dessa forma, teremos:

SCT013.current(pinSCT, 6.0606);

 

Pronto, agora você sabe como adaptar o hardware para o seu projeto.


Desafio

Desenvolva um projeto em que seja possível medir a potência requisitada por um determinado equipamento. Para isto, utilize o sensor de corrente SCT-013 (tratado com detalhes neste material) em conjunto com, por exemplo, o sensor de tensão GBK P8.

Considerações finais

Esperamos que este tutorial tenha esclarecido algumas dúvidas sobre os procedimentos necessários para realizar monitoramento das correntes elétricas utilizadas nos acionamentos dos seus equipamentos. Obrigado pela atenção e continue buscando conhecimento no portal do Vida de Silício.


Usando Transistor no Arduino

Usando Transistor no Arduino

Porquê usar transistores?

Os microcontroladores, tais como Atmega, PIC e MSP, são dispositivos lógicos. Eles  são usados com o intuito de ser a inteligencia do circuito. Dessa forma, esses componentes não são produzidos para suportar grandes correntes. O Arduino UNO, por exemplo, que usa o Atmega328, suporta um máximo de 40mA em suas portas I/O e fornece uma tensão de 5V.

 O Arduino UNO suporta um máximo de 40mA em suas portas I/O

Para muitas aplicações isso não é o suficiente. Segue alguns exemplos:

  • Motores DC;
  • Fitas de LED;
  • Relé;
  • Ou qualquer componente que precise de mais de 5V ou 40mA.

A solução pode parecer complicada mas é simples, o nome dela é Transistores.

Alguns modelos de transistores

Nesse Post iremos focar nos transistores BJT (junção bipolar), tentarei ser o mais prático possível, pensando em alguém que não saiba nada de eletrônica. Caso queira saber mais sobre transistores, existe bastante material na internet explicando os vários tipos e suas propriedades de forma mais detalhada.

Um Pouco de História!

Uma das invenções mais importantes do Milênio, os transistores possibilitaram uma revolução tecnológica inimaginável. Agora mesmo, usando o seu computador ou qualquer aparelho eletrônico você está colhendo os frutos dessa invenção.

Antes dos transistores, os computadores funcionavam a partir do uso de válvulas termoiônicas,  elas até que funcionavam bem, porém ocupavam muito espaço fazendo com que computadores ocupassem espaços muito grandes. Dessa forma, se viu a necessidade de descobrir uma forma de utilizar um substituto menor.

Em 1947, nos Laboratórios da Bell Telephone, os pesquisadores John Bardeen e Walter Houser Brattain inventaram o primeiro transistor feito de germânio. Em 23 de Dezembro de 1948, foi demonstrado para o mundo por John Bardeen, Walter Houser Brattain e William Bradford Shockley, que ganharam o Nobel de Física em 1956.

Primeiro Transistor

Hoje, o material semicondutor mais usado na fabricação de transistores é o silício. O silício é preferível porque possibilita o funcionamento a temperaturas mais elevadas (175 ºC, quando comparado com os ~75ºC dos transistores de germânio) e também porque apresenta correntes de fuga menores. Com a evolução tecnológica existe a necessidade de diminuir cada vez mais o tamanho dos transistores para que se diminua o tamanho dos equipamentos e que se aumente a capacidade de processamento. Uma das novas tecnologias é o chamado transistor 3D que tem dimensões nanométricas.


Como funcionam?

Imagine uma válvula hidráulica,  a do seu chuveiro por exemplo, ela tem a função de controlar o fluxo de água que sairá pelo chuveiro, correto? Podemos ter a válvula totalmente fechada, totalmente aberta ou em uma abertura especifica, limitando a corrente de água.

Válvula Hidráulica

Nessa válvula temos:

  • Uma entrada, onde entra a corrente de água;
  • Uma saída, nesse caso vai para o chuveiro
  • Um elemento de controle de fluxo, no caso o volante da válvula.

O transistor é muito semelhante, porém tratamos de uma corrente de elétrons. O transistor atua como uma válvula. No transistor NPN, temos:

  • Uma entrada, chamada coletor, por onde entra a corrente de elétrons;
  • Uma saída, chamada emissor, por onde sai a corrente de elétrons;
  • E um entrada de controle, chamada base, que no caso é controlada a partir de uma corrente de controle.
Transistor NPN

Como assim, corrente de controle?

Quando trabalhando no estado Ativo, o transistor aumenta ou reduz o fluxo de corrente entre o coletor e o emissor conforme à corrente de base aumenta ou reduz. Dessa forma, existe uma relação entre corrente do emissor e coletor com a corrente de base. Ela é:

Icoletor ≅ Iemissor ≅ Ibase.hfe

Repare que a corrente de emissor e coletor são aproximadamente iguais (em breve explicaremos porque)  e que as duas são proporcionais a corrente de base.

Mas quem é esse hfe?

O hfe, também conhecido como β (beta), é o coeficiente de ganho de corrente. Ele relaciona a corrente de base com a corrente de coletor e emissor.  Todo transistor tem o seu valor, esse pode ser consultado na folha de dados do componente (datasheet). Esse valor costuma ser na ordem de centenas. Assim, a corrente de base é muito pequena, em relação às correntes de coletor e de base.

Contudo, a corrente de base tem que fluir para algum lugar. No caso do transistor NPN, ela se junta a corrente de coletor, fluindo em direção ao emissor. Logo, no transistor NPN:

Iemissor =  Icoletor + Ibase =  Ibase.hfe + Ibase

Iemissor =   Ibase.(hfe + 1)  ≅ Ibase.hfe

Icoletor ≅ Iemissor

Como hfe >> 1 (muito maior que 1), podemos aproximar o termo (hfe+1) para hfe e assim considerar que as correntes de emissor e coletor são aproximadamente iguais, cometendo um erro inferior a 3% em transistores típicos.

Fluxo de corrente nos transistor NPN

Mas o que acontece se a corrente de base for muito grande?

O transistor entrará em um estado de Saturação. Chega um instante em que a corrente de base é tão grande que a corrente de coletor não consegue ser proporcional a ela. Nesse instante, o transistor libera o máximo de corrente de coletor que pode. É como um registro totalmente aberto.

Icoletor < Ibase . hfe

(Condição de Saturação)

E como restringir toda a corrente?

Quando nenhuma corrente flui entre coletor (c) e emissor (e), pode­se dizer que o transistor está em corte. Para que possamos entrar nesse estado, algumas condições são necessárias No transistor NPN, as condições são:

  • Vb < Vc,  Tensão de coletor maior que tensão de base;
  • Vb ­- Ve < 0.7, Tensão de base deve ser 0,7V maior que tensão de Emissor.

Observe que caso o emissor tenha uma tensão de 0V e colocarmos uma tensão de 0V na base, é o suficiente para que o transistor não conduza. Já que a tensão de base não será 0,7V maior que a tensão de emissor.

Será que entendi?

O transistor possui  3 estados de operação, são eles:

  • Ativo,  Icoletor ≅ Iemissor ≅ Ibase.hfe;
  • Corte, Icoletor ≅ Iemissor ≅ 0;
  • Saturado, Icoletor < Ibase.hfe (deixa toda a corrente fluir).

Para o transistor NPN funcionar em estado ativo é necessário que:

  • Vb < Vc, Tensão de coletor maior que tensão de base;
  • Vb ­- Ve < 0.7, Tensão de base 0,7V maior que tensão de Emissor;

Transistor PNP

Além do transistor NPN, existe também o PNP. Os dois possuem configurações internas diferentes que mudam um pouco o funcionamento deles.

  • No transistor NPN a corrente flui do coletor para o emissor, e a corrente de base entra somando junto a contente de emissor, fluindo da base para o emissor.
  • No transistor PNP a corrente flui do emissor para o coletor e a corrente de base flui do emissor para a base.

Veja a imagem a seguir:

Além disso, os parâmetros para que não entre em Corte mudam. Para o transistor PNP funcionar, precisamos que:

  • Tensão de Base seja maior que tensão de Coletor;
  • Tensão de Emissor 0,7V maior que tensão de Base;

Observe que a corrente de base continua sendo muito pequena, considerando Icoletor ≅ Iemissor.

Qual transistor usar?

Fluxo de corrente nos transistor NPN (esquerda) e PNP(direita)

Para selecionar um transistor, é importante verificar os níveis de corrente, tensão e dissipação de potência em que ele irá trabalhar. Isso é feito na etapa de projeto, utilizando teoria de circuitos ou (quando possível) simulando o comportamento do circuito em softwares específicos. Então, deve-­se escolher um dispositivo com capacidade de suportar tais correntes, tensões. Para isso existem duas abordagens principais. A mais comum e simples, é utilizar dispositivos de projetos parecidos (amplamente disponíveis na internet) pois já foram testados por outras pessoas. A abordagem ideal porém mais trabalhosa é consultar a folha de dados (datasheet) dos transistores. Nos datasheets é possível descobrir a SOA (Safety Operation Area) ou 'área de operação segura' dos transistores e assim poder confiar no seu funcionamento correto e na sua durabilidade.

O que devemos verificar:

  • Pol: polarização; negativa quer dizer NPN e positiva significa PNP.
  • VCEO: tensão entre coletor e emissor com a base aberta.
  • VCER: tensão entre coletor e emissor com resistor no emissor.
  • IC: corrente máxima do coletor.
  • PTOT: é a máxima potência que o transistor pode dissipar (Corrente Máxima de coletor vezes Tensão máxima entre coletor e base)
  • hFE: ganho (beta).
  • Encapsulamento: a maneira como o fabricante encapsulou o transistor, nos fornece a identificação dos terminais.

Como usar transistores no Arduino?

Veremos agora como usar um transistor NPN junto ao Arduino. Existem varias configurações de circuitos usando transistores, mas vamos nos ater a uma das mais simples. Ela é apresentada na figura a seguir. Nesse caso, estamos controlando um LED através do Arduino com o auxilio do transistor:

Exemplo de configuração de um transistor NPN com um Arduino

Saída Arduino

A saída do Arduino será:

  • 5V, quando em nível lógico alto;
  • 0V, quando em nível lógico baixo.

Para que o LED acenda, precisamos que quando a saída do Arduino estiver em nível lógico alto, o transistor conduza (Estado Ativo ou Saturado) e que quando estiver em nível lógico baixo, não conduza (Estado de Corte).

Relembrando

O transistor possui  3 estados de operação, são eles:

  • Ativo,  Icoletor ≅ Iemissor ≅ Ibase.hfe;
  • Corte, Icoletor ≅ Iemissor ≅ 0;
  • Saturado, Icoletor < Ibase.hfe (deixa toda a corrente fuir).

Para o transistor NPN conduza precisamos que:

  • Vb < Vc, Tensão de coletor maior que tensão de base;
  • Vb ­- Ve < 0.7, Tensão de base 0,7V maior que tensão de Emissor;

Transistor em Corte

Como o emissor está conectado ao GND, sua tensão é de 0V. Assim, quando a saída do Arduino estiver em 0V não atenderá um dos requisitos para que o transistor conduza (Tensão de Emissor 0,7V maior que tensão de Base) . Dessa forma o transistor entrará em estado de Corte.

Transistor Conduzindo

Quando o Arduino estiver com 5V em sua saída, sendo a tensão de coletor maior que a tensão de base, teremos o transistor na região ativa ou saturada. Para garantimos que quando em região ativa teremos a corrente de coletor suficiente para acionar o LED precisamos dimensionar os resistores de base(R2) e de coletor(R1) corretamente.

22222
Saída do Arduino em nível lógico alto

Resistor R1

O resistor R1 tem função de limitar a corrente de coletor. Para acionar um LED, precisamos de uma corrente de pelo menos 10mA. Para uma tensão de 9V um resistor de 150Ohm atende muito bem, veja os cálculos a seguir.

Aplicando a 1ª lei de Ohm considerando uma queda de tensão de 2,5V no LED e desconsiderando a queda de tensão no transistor, temos:

Icoletor-máx = (Vfonte - Queda de tensão no componente) /R = (9-2,5)V/150 Ohm = 43mA

O que é suficiente para alimentar o LED.

Resistor R2 - O mais importante

O resistor R2 tem a função de limitar a corrente de base. Sendo ela responsável por controlar a corrente que irá fluir do coletor para o emissor, temos que escolhe-la com cuidado para garantir a mínima corrente no coletor que conseguirá acender o LED.

Aplicando a 1ª lei de Ohm temos que a corrente de base é:

Ibase =  (5-0,7)/R2 = 4,3/R2-max

Mas precisamos que a corrente de coletor seja pelo menos de 10mA, para isso temos que:

Icoletor-min ≅ Iemissor-min ≅ 10mA = 0,01A = Ibase.hfe

0,01A = Ibase-min.hfe

Considerando que estamos usando o transistor BC547A, temos que seu hfe = 110(Consultado na Folha de Dados - datasheet), dessa forma:

0,01A = Ibase.110

Ibase-min=0,01/110 = 0,00009= 0,09mA

Logo:

Ibase-min= 0,00009 = 4,3/R2

R2-max =  4,3/0,00009 =52,2KOhm

Dessa forma, devemos usar um resistor menor que o calculado. Vamos adotar 4,7KOhm. Com esse resistor, teremos:

Ibase=4,3/4,7KOhm=0,9mA

Icoletor'=Ibase.hfe

Icoletor'=0,9mA.110=99mA

Como:  Ibase.hfe > Icoletor   ->  99mA > 43mA,  então:

Transistor  Saturado

Resumo dos cálculos

Requisito

Icoletor > 10mA  -> Corrente de coletor deve ser maior que 10mA quando o transistor estiver conduzindo para que o LED acenda.

Componentes

  • Fonte externa de 9V;
  • Transistor BC547A -> hfe=110;
  • R1 -> resistor que limitará a corrente de coletor, definindo a corrente máxima;
  • R2->  resistor que define a corrente de base que por sua vez define a máxima corrente de coletor.

Especificações

  • R1=150 Ohm, Limita a corrente de coletor em 43mA
  • R2 < 52,2 kOhm, adotamos R2=4,7 kOhm para corrente de base mínima de 0,09mA, logo a corrente de coletor mínima é 10mA

O que você precisa saber?

Ao projetar um circuito usando o transistor NPN, devemos:

  • Escolher qual transistor usar a partir das tensões e correntes máximas;
  • Dimensionar os resistores R1 e R2.

Para dimensionar R1, que é o resistor responsável por limitar a corrente de coletor, precisamos saber:

  • Qual a tensão da fonte;
  • Qual a queda de tensão no componente;
  • Qual a corrente necessária para que o componente controlado funcione corretamente (Icoletor-min).

Formula para calculo do R1:

Icoletor-min =(Vfonte - Queda de tensão no componente) /R1-max

R1 não deve ser muito menor que R1-max.

Para dimensionar R2, que é responsável por controlar a corrente de coletor através da corrente de base (Icoletor max = Ibase.hfe), precisamos saber:

  • Qual a corrente necessária para que o componente controlado funcione corretamente (Icoletor-min);
  • hfe do transistor escolhido.

Formula para calculo do R2:

Ibase = 4,3/R2-max

Ibase = Icoletor/hfe

obs.: É importante dimensionar bem esse resistor para que não se restrinja demais a corrente de coletor do transistor. O ideal, para esse tipo de aplicação, é trabalharmos com o transistor saturado (Icoletor < Ibase.hfe). Para isso, geralmente escolhemos um resistor bem menor que o R2 calculado.

DICAS

Para esse tipo de aplicação, na maioria dos casos, podemos adotar:

  • R1 = 150 Ohm;
  • R2 = 1 kOhm a 4,7 kOhm
  • Fonte externa até 12V para o BC547A
Circuito Transistor NPN

No lugar do LED podemos colocar um relé ou outro componente que consuma até 100mA, caso esteja usando o BC547A

Costumo usar na maioria das vezes os seguintes transistores NPN:

  • BC547A (Tensão de coletor máx =45V; Corrente de coletor máx = 100mA ; hfe=110)
  • BD137 (Tensão de coletor máx =60V; Corrente de coletor máx =1,5A ; Corrente de Base máx = 500mA; hfe=40)
  • TIP122 (Tensão de coletor máx =100V; Corrente de coletor máx = 5A ; Corrente de Base máx = 120mA; hfe= 1000)

Fechamento

Esperamos que tenham gostado, deixe seu comentário com duvidas, sugestões ou com a foto ou vídeo de seu projeto!! Compartilhe à vontade.

 

Apostila Arduino Básico