banner

Ir para o Forum

Medindo tensão AC True-RMS



Hoje vamos usar o STM32 Maple Mini para fazer uma leitura de AC, ou seja, pegar o valor RMS da rede elétrica. Isso é bastante útil para aqueles que querem monitorar a rede elétrica para a Internet das Coisas. Vamos, então, criar uma aplicação aproveitando a poder computacional do Maple Mini, aplicar um circuito eletrônico capaz de permitir a aquisição de um sinal 127Vac, bem como aplicar o cálculo da raiz do valor quadrático médio (RMS) sobre as amostras.



Demonstração

Na nossa montagem de hoje, nós temos o STM32, além do nosso circuito analógico para fazer a entrada do 110. Para evitar choques, isolamos o resistor que está entrando por 110.
O circuito é bastante sensível. Estou entrando com 110, mas reduzo 168 vezes usando o divisor de tensão e jogo para dentro do amplificador operacional, o qual tem várias funções.
Temos ainda alguns capacitores opcionais para filtragem da fonte. Caso sua fonte seja de boa qualidade, não precisa utilizá-los.
A entrada do AD é calculada através do osciloscópio, no qual você vê uma senóide, que não é a 110, mas é bem formada. Outra coisa é que a tensão na nossa rede elétrica não é 110, mas 127 volts. Mas, como estamos passando por um estabilizador, ele ajustará para 115V.
O valor exibido no monitor serial é o calculado em RMS, ou seja, o identificado pelo multímetro Fluke.




Recursos usados

·         jumpers
·         Um Maple Mini
·         Protoboard
·         Um amplificador LM386
·         Uma fonte simétrica (+5V e -5V)
·         Um trimpot multivoltas 10k (ou potenciômetro)
·         Quatro capacitores de 100nF poliester
·         3 resistores 10k
·         4 resistores470k
·         1 resistor 5k6
·         1 Diodo zener 1n4728A




Diagrama de blocos





Esquema

Este é um circuito que desenvolvi baseado nas especificações que acredito serem mais interessantes para esta medida, mas há vários outros exemplos na internet.




LM386 – Pinagem

O LM386 possui dois amplificadores para condicionamento ou amplificação de sinal.




AmpOp – Diferencial (subtrator)



 AmpOp – Somador Inversor




Maple Mini – Pinagem

Pinos marcados em:
Vermelho >> Tolerantes a 3V3
Verde   >> Tolerantes a 5V




Maple Mini – Pinagem – A/D utilizado na captura

Destaco aqui que o pino que eu utilizei é o D11 que, na nomenclatura da STMicroelectronics é o PA0.




Montagem

Para o nosso circuito, você precisará de uma fonte simétrica, como a que criamos para este projeto, ou, então, de duas fontes.




Gráfico com os dados obtidos




Cálculo do valor rms




Código-fonte – Definições e constantes

De início, definimos o pino de leitura como D11 e as várias constantes utilizadas nos cálculos.

#define leituraTensao D11 //AD CH0 no pino PA0

//valor teórico divisor de tensão  = 168.85714285714285714286
const float fatorDivisor = 168.40166345742404792461;

//valor teórico do ganho de amplificação = 1.0
const float fatorAmplificador = 1.0;

//Valor usado na multiplicação da leitura
const float fatorMultiplicacao = fatorDivisor * fatorAmplificador;

//Valor teórico da Tensão de alimentação Vcc = 3.3V
const float Vcc = 3.3;

//valor teórico do offset do amplificador = Vcc / 2.0;
const float offSet = 1.66;

//fator teórico da conversão do AD = 3.3 / 4095.0
const float fatorAD = Vcc / 4095.0;

const int amostras = 71429; //resulta em 1,027 segundos para cada atualização
//const int amostras = 35715; //resulta em 0,514 segundos para cada atualização



Código-fonte – Variáveis globais

Agora, definimos algumas variáveis globais.

float Vrms = 0.0; //armazena o valor rms da tensão
float Vmax = 0.0; //armazena o valor máximo detectado
float Vmin = 10000.0; //armazena o valor mínimo detectado
float Vmed = 0.0; //armazena o valor médio entre Vmáx e Vmín



Código-fonte – Setup()

Inicio a porta serial em 1Mbps. Ajustamos a porta do AD como entrada e aguardamos 5 segundos antes de iniciar a coleta de dados. O tempo de espera é opcional.

void setup() {
  Serial.begin(1000000); //inicia a porta serial em 1Mbps
  pinMode(leituraTensao, INPUT); //ajusta a porta do AD como entrada
  delay(5000); //aguarda 5s antes de iniciar a coleta. (opcional)
}


Código-fonte – Loop() – Inicia as variáveis  de coleta de dados

No Loop, temos a variável para iteração. Ainda aqui, armazenamos as leituras do AD em 0.0 e reiniciamos a variável Vrms também em 0.0.

void loop() {
  int i = 0; //variável para iteração
  float leitura = 0.0; //armazena as leituras do AD
  Vrms = 0.0; //reinicia a variável Vrms



Código-fonte – Captura e executa os cálculos individuais de cada amostra

Nesta fase, se i for menor que a amostra, iniciamos um ciclo de amostragem até que o i alcance o número de amostras. Executamos analogRead para leitura da porta analógica e calculamos a soma dos quadrados das tensões lidas. Por fim, incrementamos o iterador.

while (i < amostras) { //inicia um ciclo de amostragem até que i alcance o número de amostras
    leitura = analogRead(leituraTensao); //lê a porta analógica
    //Serial.println(leitura); //Descomente se quiser ver o sinal bruto do AD
    Vrms = Vrms + pow(((leitura * fatorAD) - offSet), 2.0); //calcula a soma dos quadrados das tensões lidas
    i++; //incrementa o iterador
  }


Código-fonte – Cálculos gerais das amostras e identificação de máximo, mínimo e média

Aplicamos o fator de multiplicação para determina o valor real das tensões. Detectamos se o valor é máximo ou mínimo e calculamos a média dos valores máximo e mínimo atuais.

 //Aplicando fator de multiplicação para determinar o valor real das tensões
  Vrms = (sqrt(Vrms / amostras)) * fatorMultiplicacao;

  //detecta se é um valor é máximo
  if (Vrms > Vmax) {
    Vmax = Vrms;
  }
  //detecta se é um valor mínimo
  if (Vrms < Vmin) {
    Vmin = Vrms;
  }
  //calcula a média dos valores máximo e mínimo atuais
  Vmed = (Vmax + Vmin) / 2.0;
  


Código-fonte – Opções de saída

Temos três opções para “plottar” o valor de saída.  Temos a saída formatada para plotter serial IDE Arduino, como CSV ou como Jason.

 //saída formatada para plotter serial IDE Arduino
  Serial.print(Vrms, 3);
  Serial.print(",");
  Serial.print(Vmax, 3);
  Serial.print(",");
  Serial.print(Vmin, 3);
  Serial.print(",");
  Serial.println(Vmed, 3);

  /*
    //saída formatada como json
    Serial.print("{\"instante(ms)\":");
    Serial.print(millis());
    Serial.print(",");
    Serial.print("\"Vrms(V)\":");
    Serial.print(Vrms, 3);
    Serial.print(",");
    Serial.print("\"Vmax(V)\":");
    Serial.print(Vmax, 3);
    Serial.print(",");
    Serial.print("\"Vmin(V)\":");
    Serial.print(Vmin, 3);
    Serial.print(",");
    Serial.print("\"Vmed(V)\":");
    Serial.print(Vmed, 3);
    Serial.println("}");
  */

  /*
    //saída formatada como CSV
    Serial.print(millis());
    Serial.print(",");
    Serial.print(Vrms, 3);
    Serial.print(",");
    Serial.print(Vmax, 3);
    Serial.print(",");
    Serial.print(Vmin, 3);
    Serial.print(",");
    Serial.println(Vmed, 3);
  */
}



Faça o download dos arquivos:




2 comentários:

  1. Boa noite Fernando, desculpe está perguntando aqui, mas estou com uma dúvida com a placa protoneer cnc. Como eu faço para os motores ficarem alimentados, mantendo a cnc travada no lugar quando não estiver usinando, tem algum jump a ser colocado como na cnc shild do arduíno?

    ResponderExcluir
  2. Obrigado Fernando!

    Tinha pedido justamente isso em um dos seus vídeos passados em que comentou sobre o assunto!

    Abs, Paulo.

    ResponderExcluir

Tecnologia do Blogger.