Introduction: Measuring True-RMS AC Voltage

About: Do you like technology? Follow my channel on Youtube and my Blog. In them I put videos every week of microcontrollers, arduinos, networks, among other subjects.

Today, we will use the STM32 Maple Mini to do an AC reading. In our example, we’ll get the RMS value of the power grid. This is very useful for those who want to monitor the electrical network for the Internet of Things. We will then create an application using the computational power of the Maple Mini, apply an electronic circuit capable of allowing the acquisition of a 127Vac signal, as well as apply the root mean square (RMS) calculation on the samples.

Step 1: Demonstration

In our assembly today, we have the STM32, in addition to our analog circuit to make the input of 110. To avoid shocks, isolate the resistor that is entering by 110.

The circuit is quite sensitive. I'm getting in with 110, but I reduce it 168 times using the voltage divider and put it into the operational amplifier, which has several functions.

We also have some optional capacitors for source filtering. If your source is of good quality, you do not need to use them.

The AD input is calculated through the oscilloscope, in which you see a sinusoid, which is not 110 (but it is well formed). Another thing is that the voltage in our electrical network is not 110 (it’s actually 127 volts). But as we are undergoing a stabilizer, it will adjust to 115V.

The value displayed on the serial monitor is what is calculated in RMS, that is, the one identified by the Fluke Meter.

Step 2: Resources Used

• Jumpers

• A Maple Mini

• Protoboard

• An LM386 amplifier

• A symmetrical source (+ 5V and -5V)

• A 10k multi-turn trimpot (or potentiometer)

• Four capacitors of 100nF polyester

• Three 10k resistors

• Four 470k resistors

• One 5k6 resistor

• One 1n4728A zener diode

Step 3: Block Diagram

Step 4: Scheme

This is a circuit I developed based on the specs I believe are the best for this measurement, but there are several other examples that can be found on the internet.

Step 5: LM386 - Pinning

The LM386 has two amplifiers for conditioning or signal amplification.

Step 6: AmpOp - Differential (subtractor)

Step 7: AmpOp - Inverter Adder

Step 8: Maple Mini - Pinage

Pins marked on:

Red >> 3V3 Tolerant

Green >> 5V Tolerant

Step 9: Maple Mini - Pinning - a / D Used in Capturing

I emphasize here that the pin that I used is the D11 that (in the nomenclature of the STMicroelectronics) is the PA0.

Step 10: Assembly

For our circuit, you will need a symmetric source, like the one we created for this project. Otherwise, you’ll need two sources.

Step 11: Graph With the Data Obtained

Step 12: Calculating the RMS Value

Step 13: Source Code

Source code - Definitions and constants

At first, we defined the pin reading as D11, as well as the various constants used in the calculations.

#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

Source code - Global variables

Now, we define some global variables.

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

Source Code - Setup ()

Start the serial port at 1Mbps. We adjusted the AD port as input and waited 5 seconds before starting to collect data. Standby time is optional.

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

Source Code - Loop () - Starts the data collection variables

In the Loop, we have the variable for iteration. Here, we also store the readings of AD in 0.0 and restart the variable VRMS also in 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

Source Code - Captures and executes the individual calculations for each sample

At this stage, if i is smaller than the sample, we start a sampling cycle until i reaches the number of samples. We run analogRead to read the analog port and calculate the sum of the squares of the read voltages. Finally, we increment the iterator.

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 }

Source code - General calculations of the samples and identification of maximum, minimum, and average

We apply the multiplication fact to determine the actual value of the voltages. We detect whether the value is maximum or minimum, and we calculate the average of the current maximum and minimum values.

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

Source Code - Output Options

We have three options for "plotting" the output value. We have output formatted to the Arduino IDE serial plotter, like CSV or 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); */ }

Step 14: Files

Download the files: