Você está na página 1de 47

Por Fernando Koyanagi

Intenção dessa aula

1. Disponibilizar um circuito de captura de


tensão e corrente aplicados em uma carga.
Demonstração
SEJA MEMBRO

+
Links onde
comprei os
componentes

https://bit.ly/2VM1ZdQ

Em www.fernandok.com
4
SEJA MEMBRO

5
SEJA MEMBRO

6
forum.fernandok.com
Instagram
fernandok_oficial

Telegram
fernandok_oficial

8
Materias utilizados
• Módulo ESP32 WROOM 32
• Resistores de 10k 1% e 82k
• Capacitores de 0,22nF, 4n7 e 47nF
• Capacitor de 1000uF / 25V
• Led
• Sensor de tensão AC ZMPT101B
• Sensor de corrente ACS758LCB-050B
• Multímetro
• Osciloscópio
• Plugue NBR14136
• Tomada NBR14136
• Pcb universal
• Variac
• 5 Cargas resistivas de 150W
• Aplicativo datalogger SerialFK
Circuito
Circuito – Rede AC e sensores
Abaixo vemos a interligação dos sensores à rede AC a ser monitorada:

• O sensor de tensão é conectado em


paralelo com a carga.

• O sensor de corrente é conectado em série


com a carga.

• Um interruptor é adicionado ao circuito


para permitir o controle da alimentação da
carga.

• Um led indicador também é incluindo,


indicando quando o a carga está
energizada.
Circuito – Rede AC e sensores
Mais detalhes sobre o sensor de tensão baseado no Trafo ZMPT101B:

• No esquema podemos observar que o ZMPT101B age como um isolador


entre a rede e o circuito de medição.

• O sinal detectado é da tensão induzida sobre o resisto R1, capturada por um


amplificador de diferença com ganho 10.

• O sinal resultante é aplicado em um divisor de tensão formado pelo trimpot


R12 e em seguida, aplicado em uma outra etapa amplificadora de mesmo
tipo e ganho.

Vcc (5V)
Sinal
Rede AC GND da alimentação e
127V do sinal
Circuito – Rede AC e sensores
Detalhes sobre o sensor de corrente baseado no ACS758LCB-050B:

• O sinal resultante do sensor ACS758 pode ser obtido diretamente, passando


apenas por um filtro passa-baixas formado por R1 e C1, bastando para isso
conectar o ADC na saída OUT1.

• Mas também pode ser obtido passando por um amp-op seguidor de tensão,
formado por U2.

Sinal após o seguidor de tensão


Corrente AC (entrada) Sinal direto do ACS758
Corrente AC (saída) GND
5V
Circuito – Filtros dos ADCs
Para garantir um sinal mais livre de ruídos nas entradas dos ADC e com níveis de tensão adequados aos 3V3 limite
dos ADC, o sinais de cada sensor foram aplicados:

• Primeiro a um divisor de tensão formado por dois


resistores de 10k / 1%, fazendo com que as tensões
máximas de 5V das saídas sejam reduzidas a 2,5V. Não só
adequado ao limites como também, dentro da faixa de
maior linearidade dos ADCs do ESP32, o que resultará em
ajustes de curva mais simples.

• Em seguida, esses sinais, provenientes dos divisores de


tensão passam por dois filtros passa-baixas sobrepostos,
para frequências de 10 e 100x a frequência da rede AC
(600Hz e 6kHz).

• Um jumper foi adicionado ao filtro de 600Hz do sensor de


tensão para desativação opcional, caso os ruídos sejam o
objeto de estudo.
Circuito – ESP32 e fonte
Depois de passar pelos divisores e filtros, os sinais são aplicados a suas respectivas entradas ADC no ESP32 (pinos 32
e 33 para o sinal de tensão e de corrente respectivamente).
Vemos também um detalhe dos capacitores da fonte de alimentação de 5V, que deve ser de boa qualidade, estável,
livre de ruídos e com potência suficiente para manter o circuito.
Calibração – Sensor de tensão - offset
Para efetuar a calibração do sensor de tensão, temos que recordar que sua saída
mantem um offset de metade da tensão da alimentação, neste caso 5V÷2 = 2,5V.
Esses 2,5V passam em seguida por um divisor de tensão de resistores iguais, logo,
senso novamente dividido por 2. Assim, quando uma tensão de 0VAC estiver na
entrada do sensor de tensão, devemos esperar uma tensão de 1,25V aplicada ao
ADC de tensão.
Essa tensão de offset produzirá um código de offset no ADC. Para determina-la,
basta ler o valor do ADC com 0VAC aplicados no sensor.

A figura ao lado mostra uma parte dos dados capturados e o valor médio obtido
para o código de offset do sensor de tensão.

Esse valor será importante para a conversão dos valores em valores de tensão e
será utilizada como uma constante no código-fonte de captura.

//valores de offset de cada sensor (determinados estatisticamente através de capturas)


const float offsetVAC = 1383.328;
Calibração – Sensor de corrente - offset
Da mesma forma que o sensor de tensão, a saída do sensor de corrente também
apresenta um offset de metade da tensão de alimentação, que por sua vez
também é aplicado a um divisor de tensão de resistores iguais, resultando
também em um código de offset do ADC do sensor de corrente. Mas não podemos
utilizar o mesmo valor obtido no sensor de tensão devido a variações entre os
componentes dos dois circuito.

Mas podemos determina-la da mesma forma, como mostrado ao lado:

Da mesma forma, vamos utilizar futuramente este valor nos cálculos de conversão
dos códigos do ADC em valores de tensão.

//valores de offset de cada sensor (determinados estatisticamente através de capturas)


const float offsetVAC = 1383.328;
const float offsetIAC = 1395.393991;
Calibração – Sensor de tensão – valores instantâneos
Uma vez determinado o offset, podemos então aplicar uma tensão senoidal conhecida e através dela, comparar os códigos obtidos.

Aplicamos neste exemplo uma tensão senoidal de 137Vrms. Essa produzirá picos de +193,7V e -193,7V.

Capturando os códigos gerados e comparando os valores máximos e mínimos obtidos (descartando os picos causados por ruídos eventuais), podemos
obter uma relação direta entre o código do ADC e os valores instantâneos, como mostrado na figura abaixo:

Usamos a função da reta de regressão como função de


conversão:

Seus coeficiente angular e linear (A e B) são utilizados no


código fonte.

//coeficientes das regressões lineares.


//Usados para a conversão dos códigos
const float coefA_VAC = 0.2546;
const float coefB_VAC = 0.3807;

Serial.print((float(tensao) - offsetVAC)*coefA_VAC - coefB_VAC);


Calibração – Sensor de corrente – valores instantâneos
O mesmo princípio pode ser aplicado ao sensor de corrente. Nele, aplicamos uma corrente senoidal de 4,924Arms, que produzirá picos de +6,964A e -
6,964A.

Capturando os códigos gerados e comparando os valores máximos e mínimos obtidos (descartando os picos causados por ruídos eventuais), podemos
obter uma relação direta entre o código do ADC e os valores instantâneos, como mostrado na figura abaixo:

Usamos a função da reta de regressão como função de


conversão:

Seus coeficiente angular e linear (A e B) são utilizados no


código fonte.

//coeficientes das regressões lineares.


//Usados para a conversão dos códigos
const float coefA_IAC = 0.117;
const float coefB_IAC = 0.1299;

Serial.print((float(corrente) - offsetIAC)*coefA_IAC - coefB_IAC);


Calibração – Observação!
Nestes métodos de calibração mostrados acima, as retas de regressão usadas nas conversões foram obtidas usando apenas três pontos. Fizemos desta
forma aqui simplesmente para simplificar a aplicação e por conhecermos a priori o comportamento e o grau de linearidade dos sensores de tensão e
corrente e dos circuitos acessórios.

Mesmo assim, todos as medidas obtidas com estes sensores posteriormente, foram verificadas diversas vezes e por processos diferentes após a
calibração, descartando os possíveis desvios para além das limitações dos próprios sensores.

Em aplicações mais exigentes, mesmo conhecendo os sensores, utilize uma metodologia estatística mais robusta para garantir a determinação correta
dos parâmetros de conversão.
Calibração – Sensor de tensão – valores RMS
Para calibração dos valores RMS de tensão, utilizamos um variac para criar diversas tensões AC na entrada do sensor de tensão.

Já os códigos usados na regressão, são o resultado do algoritmo de cálculo da raíz quadrada média (root mean square ou RMS) dos códigos obtidos em
um certo número de períodos da onda AC, capturados.

Utilizando os pares tensão e código do ADC obtidos, podemos então encontrar uma reta de conversão, como mostrado abaixo.

Definimos para a regressão o valor de 0V para o código 0 do ADC.

Usamos a função da reta de regressão como função de


conversão:

Seus coeficiente angular e linear (A e B) são utilizados no


código fonte.

//coeficientes das regressões lineares.


//Usados para a conversão dos códigos
const float coefA_VAC = 0.2652;
const float coefB_VAC = 0.0;

acumuladorTensao = acumuladorTensao * coefA_VAC + coefB_VAC;


//Conversão em volts
Calibração – Sensor de corrente – valores RMS
Para calibração dos valores RMS de corrente, utilizamos um 5 cargas resistivas de 150W, para variar a corrente na entrada do sensor, introduzindo-as
sequencialmente em paralelo.

Já os códigos usados na regressão, são o resultado do algoritmo de cálculo da raiz quadrada média (root mean square ou RMS) dos códigos obtidos em
um certo número de períodos da onda AC, capturados, assim como foi feito com os códigos para cálculo da tensão RMS.

Utilizando os pares corrente e código do ADC obtidos, podemos então encontrar uma reta de conversão, como mostrado abaixo.

Definimos para a regressão o valor de 0A para o código 0 do ADC.

Usamos a função da reta de regressão como função de


conversão:

Seus coeficiente angular e linear (A e B) são utilizados no


código fonte.

//coeficientes das regressões lineares.


//Usados para a conversão dos códigos
const float coefA_IAC = 0.1191;
const float coefB_IAC = 0.0;

acumuladorCorrente = acumuladorCorrente * coefA_IAC + coefB_IAC;


//Conversão em ampères
Código-fonte
Códigos-Fonte: Cálculo do valor RMS
Para calcular o valor RMS (Root Mean Square), também conhecido como valor eficaz, para uma
coleção de medidas discretas, podemos usar a expressão;

Para realizar esta operação, vamos dividi-la em etapas;

1. Primeiro, vamos acumular o valor do quadrado de cada medida, bastando para isso, multiplicar cada medida realizada por ela
mesma e, em seguida, adicioná-la a uma variável acumuladora.

2. Depois de todas as medidas serem realizadas, dividimos o resultado do acumulador pelo número de medidas.

3. Aplicamos então a raiz quadrada neste último valor. O resultado é então o valor RMS da coleção de medidas
Códigos-Fonte: Declarações e setup()
/* Seleção do MODO de operação:
0 - Transmite os valores brutos dos ADCs
1 - Transmite os valores instantâneos de tensão e corrente, em volts e ampères
2 - Transmite os valores RMS de tensão e corrente, em volts e ampères
*/

#define MODO 0

//Pinos de entrada utilizados


const uint8_t pinAdcTensao = 32;
const uint8_t pinAdcCorrente = 33;

//Caracter separador dos dados


const char separador = '\t';

//valores de offset de cada sensor (determinados estatisticamente através de capturas)


const float offsetVAC = 1383.328;
const float offsetIAC = 1395.393991;

void setup()
{
Serial.begin(1000000); //Iniciando a comunicação serial
}
Códigos-Fonte: loop no MODO 0
void loop()
{

#if MODO == 0
//Envio direto dos códigos do ADC sem nenhum tratamento

//Variáveis
int32_t tensao = 0;
int32_t corrente = 0;

//Captura
tensao = analogRead(pinAdcTensao);
corrente = analogRead(pinAdcCorrente);

//Transmissão
//Serial.print(micros());
//Serial.print(separador);
Serial.print(tensao);
Serial.print(separador);
Serial.print(corrente);
Serial.println();
#endif
Códigos-Fonte: loop no MODO 1
#if MODO == 1
//Envio dos códigos convertidos em tensão e corrente instantâneos

//coeficientes das regressões lineares. Usados para a conversão dos códigos


const float coefA_VAC = 0.2546;
const float coefB_VAC = 0.3807;
const float coefA_IAC = 0.117;
const float coefB_IAC = 0.1299;

//Variáveis
int32_t tensao = 0;
int32_t corrente = 0;

//Captura
tensao = analogRead(pinAdcTensao);
corrente = analogRead(pinAdcCorrente);

//Transmissão
//Serial.print(micros());
//Serial.print(separador);
Serial.print((float(tensao) - offsetVAC)*coefA_VAC + coefB_VAC);
Serial.print(separador);
Serial.print((float(corrente) - offsetIAC)*coefA_IAC + coefB_IAC);
Serial.println();
#endif
Códigos-Fonte: loop no MODO 2
#if MODO == 2
//Envio dos códigos convertidos da tensão e corrente RMS

//coeficientes das regressões lineares. Usados para a conversão dos códigos


const float coefA_VAC = 0.2652;
const float coefB_VAC = 0.0;
const float coefA_IAC = 0.1191;
const float coefB_IAC = 0.0;

//Período mínimo de captura de 16,7ms para garantir que ao menos um ciclo seja capturado
const int32_t duracaoDaAmostragem = (int32_t)((1000.0 / 60.0) * 6.0); //6 ciclos de 1000ms/60 (60Hz)

//Variáveis
int32_t tensao = 0;
int32_t corrente = 0;
uint32_t qtdDeAmostras = 0;
float acumuladorTensao = 0.0;
float acumuladorCorrente = 0.0;

//Captura
unsigned long inicio = millis();
do
{
tensao = analogRead(pinAdcTensao) - offsetVAC;
corrente = analogRead(pinAdcCorrente) - offsetIAC;

acumuladorTensao = acumuladorTensao + (tensao * tensao); //Soma dos quadrados


acumuladorCorrente = acumuladorCorrente + (corrente * corrente);//Soma dos quadrados

qtdDeAmostras++;
} while ((millis() - inicio) < duracaoDaAmostragem);
Códigos-Fonte: loop no MODO 2
//Cálculo dos valores RMS
acumuladorTensao = acumuladorTensao / float(qtdDeAmostras); //Média dos quadrados
acumuladorCorrente = acumuladorCorrente / float(qtdDeAmostras); //Média dos quadrados

acumuladorTensao = sqrt(acumuladorTensao); //RMS da captura


acumuladorCorrente = sqrt(acumuladorCorrente); //RMS da captura

acumuladorTensao = acumuladorTensao * coefA_VAC + coefB_VAC; //Conversão em volts


acumuladorCorrente = acumuladorCorrente * coefA_IAC + coefB_IAC; //Conversão em ampères

//Transmissão
//Serial.print(micros());
//Serial.print(separador);
Serial.print(acumuladorTensao);
Serial.print(separador);
Serial.print(acumuladorCorrente);
Serial.println();
#endif
}
Serial FK
Serial FK – Enviando a Tensão e Corrente AC RMS
Vamos utilizar agora o dispositivo para enviar as medidas de tensão e corrente AC RMS para o software Serial FK, onde podemos
acompanhar seu comportamento através de indicadores, gravar logs e observar graficamente as variações.

Para isso, vamos introduzir mais um modo de operação do programa, o MODO 3. Nele, vamos apenas alterar as informações enviadas
para o formato de recepção do Serial FK, incluindo o nome das variáveis e enviando também o instante da captura para registro no log,
se necessário.

//Transmissão O MODO 3 de operação é idêntico ao MODO 2, a não ser pela mudança


Serial.print("t"); nas informações enviadas.
Serial.print(separador); O Serial FK espera que as informações cheguem no formato:
Serial.print(micros()); <NOME DA VARIÁVEL>
Serial.print(separador); <CARACTER DE TABULAÇÃO>
<VALOR>
Serial.print("Vac"); <CARACTER DE TABULAÇÃO>
<NOME DA SEGUNDA VARIÁVEL>
Serial.print(separador); <CARACTER DE TABULAÇÃO>
Serial.print(acumuladorTensao); <VALOR>
<CARACTER DE TABULAÇÃO>
Serial.print(separador); . . .
<CARACTER DE NOVA LINHA>
Serial.print("Iac");
Serial.print(separador); Vamos mudar também o Baud Rate para 115200, no setup().
Serial.println(acumuladorCorrente);
#endif Serial.begin(115200); //Iniciando a comunicação serial
Serial FK – Enviando a Tensão e Corrente AC RMS
No circuito de teste, vamos utilizar 5 cargas de 150W, as mesmas utilizadas durante a calibração. Também conectaremos dois
multímetros, um como amperímetro e outro como voltímetro, somente para controle.

Serial FK

USB Cargas em paralelo

Fonte AC
Medidor de tensão
e corrente AC
V
AC

A AC
Serial FK – Enviando a Tensão e Corrente AC RMS
Foto do barramento AC com as cargas e os multímetros de controle de tensão e corrente. Ao lado o medidor montado.
Serial FK – Enviando a Tensão e Corrente AC RMS
Abaixo mais detalhes do software Serial FK.

Widgets
Tensão

Corrente
Complemento – Conexão do Display
Abaixo, a tabela de conexão entre o ESP32 e o Display.

Display ESP32
Vcc (verde para LED) 3V3
GND GND
CS GPIO15
RST GPIO4
DC GPIO2
SDI GPIO23
SCK GPIO18
Complemento – Conexão do Display
Abaixo, a tabela de conexão entre o ESP32 e o Display.
Complemento – Biblioteca
• Biblioteca TFT_eSPI
1. Vá em Sketch -> Incluir Biblioteca -> Gerenciar bibliotecas
2. Pesquise por tft_espi
3. Selecione e instale a biblioteca TFT_eSPI distribuída por Bodmer
Complemento – Biblioteca
• Configuração da biblioteca TFT_eSPI

Precisamos configurar o arquivo User_Setup.h para utilizá-lo com o display escolhido e os pinos do
ESP32. Para isso, localize-o no local de instalação da biblioteca, como mostrado no exemplo abaixo.
Complemento – Biblioteca
• Configuração da biblioteca TFT_eSPI: Arquivo User_Setup.h

Verifique se o driver correto está selecionado e se os pinos estão ajustados corretamente. Confira
também as velocidades para comunicação SPI.
Código
com
display
Códigos-Fonte: Declarações
#include <SPI.h> //Para a comunicação SPI com o display
#include <TFT_eSPI.h> // Biblioteca de controle do display

//Cria o objeto que representa o display


TFT_eSPI tft = TFT_eSPI();

//Pinos de entrada utilizados


const uint8_t pinAdcTensao = 32;
const uint8_t pinAdcCorrente = 33;

//Caracter separador dos dados


const char separador = '\t';

//valores de offset de cada sensor (determinados estatisticamente através de capturas)


const float offsetVAC = 1383.328;
const float offsetIAC = 1395.393991;

//Variáveis Globais
float ultimaTensao = 0; //Usada para apagar o valor de tensão no display
float ultimaCorrente = 0; //Usada para apagar o valor de corrente no display
Códigos-Fonte: Setup()

void setup()
{
Serial.begin(115200); //Iniciando a comunicação serial
tft.init(); //inicia o display
tft.setRotation(1); //Ajusta a rotação do display
tft.fillScreen(0x0); //pinta a tela de preto
//tft.setTextFont(7); //Ajusta o tamanho da fonte
}
Códigos-Fonte: Loop() – Variáveis e constantes

void loop()
{
//coeficientes das regressões lineares. Usados para a conversão dos códigos
const float coefA_VAC = 0.2652;
const float coefB_VAC = 0.0;
const float coefA_IAC = 0.1191;
const float coefB_IAC = 0.0;

//Período mínimo de captura de 16,7ms para garantir que ao menos um ciclo seja capturado
const int32_t duracaoDaAmostragem = (int32_t)((1000.0 / 60.0) * 100.0); //100 ciclos de 1000ms/60 (60Hz)

//Variáveis
int32_t tensao = 0;
int32_t corrente = 0;
uint32_t qtdDeAmostras = 0;
float acumuladorTensao = 0.0;
float acumuladorCorrente = 0.0;

Passamos a capturar 100 ciclos neste exemplo.


Códigos-Fonte: Loop() – Captura e cálculo do RMS
//Captura
unsigned long inicio = millis();
do
{
tensao = analogRead(pinAdcTensao) - offsetVAC;
corrente = analogRead(pinAdcCorrente) - offsetIAC;

acumuladorTensao = acumuladorTensao + (tensao * tensao); //Soma dos quadrados


acumuladorCorrente = acumuladorCorrente + (corrente * corrente);//Soma dos quadrados

qtdDeAmostras++;
} while ((millis() - inicio) < duracaoDaAmostragem);

//Cálculo dos valores RMS


acumuladorTensao = acumuladorTensao / float(qtdDeAmostras); //Média dos quadrados
acumuladorCorrente = acumuladorCorrente / float(qtdDeAmostras); //Média dos quadrados

acumuladorTensao = sqrt(acumuladorTensao); //RMS da captura


acumuladorCorrente = sqrt(acumuladorCorrente); //RMS da captura

acumuladorTensao = acumuladorTensao * coefA_VAC + coefB_VAC; //Conversão em volts


acumuladorCorrente = acumuladorCorrente * coefA_IAC + coefB_IAC; //Conversão em ampères
Códigos-Fonte: Loop() – Impressão no display
//Imprime na tela
//Imprime a barra de título
tft.setCursor(0, 0, 2);
tft.setTextColor(TFT_WHITE, TFT_BLUE); tft.setTextSize(3);
tft.println("Medidas");
tft.print("de tensao e corrente");

//Apaga o valor anterior


tft.setTextSize(1);
tft.setCursor(120, 120, 7);
tft.setTextColor(TFT_BLACK);
tft.print(ultimaTensao, 1);
tft.setCursor(120, 240, 7);
tft.print(ultimaCorrente, 1);

//Imprime o novo valor


tft.setCursor(120, 120, 7);
tft.setTextColor(TFT_YELLOW);
tft.print(acumuladorTensao, 1);
tft.setCursor(120, 240, 7);
tft.print(acumuladorCorrente, 1);

//Imprime a unidades
tft.setTextSize(2);
tft.setCursor(270, 120, 4);
tft.print("V");
tft.setCursor(270, 240, 4);
tft.print("A");

ultimaTensao = acumuladorTensao;
ultimaCorrente = acumuladorCorrente;
}
Captura: Display indicando valores
Em www.fernandok.com
Download arquivo PDF e INO

47

Você também pode gostar