Welcome to the exciting world of energy monitoring with Hexabitz! This project provides a simple and effective way to monitor your energy consumption using Hexabitz modules. With a little bit of customization, you can tailor this project to fit your specific needs and requirements. So why wait? Hexabitz Energy Meter, a single-phase energy meter that allows you to measure voltage, current, power, and power factor. With just a press of a button on the interface, you can view the measured values on a segment display.
⚡️ Introduction:🌟 In this project, we will be building an Energy Meter using the Hexabitz modules. This single-phase energy meter is designed to measure voltage, current, power, and power factor. The measured values are displayed on a segment display when the button is pressed on the interface.
🌟 Our energy meter is also equipped with a Mod-bus port as a serial communication interface, which is a common protocol in industrial systems. Investors can obtain all meter data not only through the display on the 7-segment, but also by connecting with it, as is the case with Schneider and Delta products, among others.
🌟 Key Features:
- Single-phase energy meter, 230VAC 50Hz
- Direct measurement up to 32A
- Display of active energy, voltage, current and cosφ
- Modbus RTU interface to query the data
- 6-digits display
- Easy to connect to Modbus Extension using existing template
- Ambient temperature: -20 … +55°C
🌟 The Hexabitz Energy Meter project aims to provide an efficient solution for measuring electrical parameters in a single-phase system. It utilizes the Hexabitz modular system, specifically AC Current and Voltage Sensor Module (H2AR3x), RS485 Serial Transceiver (H1DR1x) and 6 Digit Seven Segment Module (H3BR6x).
🌟 In this tutorial, We will take you through the steps that we followed to make this awesome project. We hope you will like it.
⚡️ Project Tools:We'll list the tools used in this project:
1-Hexabitz AC Current and Voltage Sensor Module (H2AR3):
H2AR3x is an AC current and voltage sensor module based on bidirectional current sense amplifiers INA199B2DCKT, INA199B1DCKT, Low-Drift, Low-Power, Dual-Output Vref and Vref/2 Voltage Reference REF2033AIDDCR and STM32F0 MCU.
2-CR8400 CurrentTransformer:
CR Magnetics CR8450-1000 is a wire lead current transformer.
3-RS485 Serial Transceiver (H1DR1x):
H1DR1x is an RS485 serial transceiver module based on Maxim Integrated MAX14840EASA+ transceiver and STM32F0 MCU.
- Easy-to-use and compact 3.3V RS485 half-duplex transceiver with high ESD protection for long-range wired serial communication and industrial applications.
- 120 Ohm DC termination resistor included on each module and enabled / disabled by a solder jumper/ zero-Ohm resistor
- 100 nF AC termination included on each module and bypassed by default with a solder jumper / zero-Ohm resistor.
- Use this module to connect to industrial equipment that supports RS485 interfaces such as PLCs, motor drives, and energy meters, among others.
- Can be configured in either one of these modes: UART-RS485 bridge, or Modbus RTU terminal, or Modbus ASCII terminal.
- Program advanced C code using our easy-to-use APIs and messaging system.
- Use separately or combine with other Hexabitz modules and external hardware.
4-6 Digit Seven Segment (H3BR6x):
H3BR6x is a 6 digit seven segment interface module based on STM32G0 MCU.
- Features 0.36 inches, 6 digits, RED, 8-segment display LED, common anode.
- Use this module as an output display device. Connect it to other Hexabitz modules to display information in text or decimal form.
5-Proto Board (H00R4x):
H00R4x is a through-hole proto board module with 100-mil plated hole pattern. Use this module to prototype any circuit you want and add it to your Hexabitz collection! The module features a 1-mm plated drill pattern with 100 mil spacing. Six arrays and six power ports are available to seamlessly integrate with Hexabitz ecosystem. Power ports are separate from each other, in case you need multiple voltage rails in your array.
Hardware Design Files(EAGLE).
6-STLINK-V3MODS Programmer (H40Rx):
H40Rx is a programmer module which contains STLINK-V3MODS stand-alone debugging and programming mini probe for STM32 micro-controllers (Hexabitz modules and other MCUs).
It supports the SWD (Serial Wire Debugging) interface for the communication with any STM32 micro-controller located on an application board.
It also provides bridge interfaces to several communication protocols, allowing for instance the programming of the target through boot-loader.
We prepare the project components and plan our array design by aligning modules side-by-side. Then we solder the modules together using Hexabitz Fixture.
We used a 100-mil PTH Proto Board (H00R4x) to build power circuit (AC/DC Converter).
The circuit of AC/DC Converter is very simple to build with few components. As you can see in the circuit diagram.
Check out this article for writing code with STM32CubeIDE.
Fixed topology file:
Inter-array communication in Hexabitz is done using a routing table stored in a special header (.h) file. This header file describes the number of modules and how they are connected to each other as well as other important information for the array; hence, it is called a topology header file. Currently, you need to make a topology file manually.
After creating the topology for the two modules (H2AR3x, H3BR6x) and determining their configurations, we add the topology for each module. See this link for help in creating a topology file. Then go to project.h and UN-comment the header.
H2AR3xFirmware main.c code:
Clone the latest firmware of the module and start coding!
Taking the advantage of Hexabitz Single Phase Power Analyzer project [8].
- First, we define our variables:
__IO uint8_t rx=0;
uint16_t p;
int i=0,temp=0,elapsed=0,status;
int R_p_s,R_p_h,q_s,q_h;// Active & reactive Energy
float volt,curr ,sum,sum_v,Ibuff[100]={0},Vbuff[100]={0},Pbuff[100]={0},buff[100]={0};
volatile float V,I;
float MaxV,Maxvp,MaxI,avi,avv,sumv,sumi;
float Rmsv,Rmsi, A_p,P_F,R_p,q,freq;
float R_Show1;
float R_Show2;
float theta1;
int i,j,indv,inda,theta,status;
uint8_t signv=0 , intr = 0;//0:+...1:-
uint8_t Data[24]={0};
uint32_t x;
uint8_t *send; uint8_t jata[4]={0};
volatile uint8_t Pressed =0;
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
uint16_t buffer[255]={0};
uint8_t bufferLength = 255;
- We define BOS variables. Using the keyword volatile in front of a variable definition tells the compiler that this variable might change outside the program.
- Second, in the
userTask
function we read the last value stored in the EEPROM, then we specify the parameter R_p_h to get the active power in hours, and the parameter R_p_s to get it in seconds.
status = EE_ReadVariable(_EE_MyVar, &p);
// read EEprom where the energy has been saved last time
R_p_h=p/3600;R_p_s=p%3600; // decomposition of total energy
- Define the button and link it to its callbacks in the UserTask function like this:
AddPortButton(MOMENTARY_NO, P1);
SetButtonEvents(1,1,0,0,0,0,0,0,0,0);
Check out this article for Port Buttons/Switches.
- The sensor module send the value of rx to the 7 seg module by a memory write API in for loop.
BOSMessaging.trace=NONE;
AddBOSvar(FMT_UINT8, (uint32_t)rx);
rx=1;// sleep 7-Seg
WriteRemote(2, (uint32_t)rx, 1, FMT_UINT8, 1);
HAL_Delay(800);
- Third, inside the
While(1)
loop, we take the real time from Hexabitz BOS functionBOS.time.seconds,
and do some startup initialization:
//Delay_ms(2000);
//IND_toggle();
GetTimeDate(); temp = BOS.time.seconds;
// due to elapsed seconds in initialization
HAL_Delay(2000);// update measurements every .... seconds
sumi=0;avi=0;avv=0;Rmsi=0;Rmsv=0;A_p=0;P_F=0;R_p=0;
MaxV=0;MaxI=0;sumv=0,sumi=0;indv=0;inda=0;Maxvp=0,freq=0;
- To obtain the voltage and current values, we used the following APIs programmed in the module's firmware, then we store them in buffers:
// get values sequentially not simultaneously ...!
for(i=0;i<100;i++)
{
SampleV(&volt);SampleA(&curr);
Vbuff[i]=volt;Ibuff[i]=curr;
StartMicroDelay(135);//135+65=200u, 200u*100= 20 ms.
}
for(i=0;i<100;i++) // calc average error for current
{avi=avi+Ibuff[i];} avi=avi/100;
for(i=0;i<100;i++) // Current online calibration
{Ibuff[i]=Ibuff[i]-avi;}
for(i=0;i<100;i++) // calc average error for volt
{avv=avv+Vbuff[i];} avv=avv/100;
for(i=0;i<100;i++) // Current online calibration
{Vbuff[i]=Vbuff[i]-avv;}
// catch max value with indicator
if(Vbuff[0] < 0) // wwe need peaks maxv+ and maxv-
{MaxV = Vbuff[0]*-1;signv=1;}
else {MaxV = Vbuff[0];signv=0;}
for(i=1;i<100;i++)
{
if(Vbuff[i] < 0)
{if(MaxV < -1*Vbuff[i] ) {MaxV=-1*Vbuff[i];signv=1;indv=i;}}
else
{if(MaxV < Vbuff[i] ) {MaxV=Vbuff[i];signv=0;indv=i;}}
}
if(signv==1) MaxV *= -1; MaxV=MaxV/1.414;
// frequency calculation
for(i=0;i<100;i++) // rectifier
{buff[i]=Vbuff[i];if(buff[i] < 0) buff[i]=-buff[i];}
Maxvp = buff[0];
for(i=1;i<50;i++)
{if(Maxvp < buff[i] ) {Maxvp=buff[i];indv=i;}}
Maxvp = buff[50];
for(i=50;i<100;i++)
{if(Maxvp < buff[i] ) {Maxvp=buff[i];inda=i;}}
// freq= 5000 /(indv-inda); no need to calc in case of phase absence
for(i=0;i<100;i++) {buff[i]=0;} // clean
// Real Power discrete time calculation
for(i=0;i<100;i++)
{Pbuff[i]=Ibuff[i]*Vbuff[i];// the acquired samples were sequential not simultaneous
sumi+=Pbuff[i];}R_p=sumi/100;// watt
if(R_p<0) R_p=-R_p;sumi=0;
// RMS discrete time calculation
for(i=0;i<100;i++)
{buff[i]=pow(Vbuff[i],2);sumv+=buff[i];} Rmsv=sqrt(sumv/100)*1.15; // we need here filter for stable values
if(Rmsv<MaxV) Rmsv=MaxV;
for(i=0;i<100;i++)
{buff[i]=pow(Ibuff[i],2);sumi+=buff[i];}Rmsi=sqrt(sumi/100); // we need here filter for stable values
// Apparent power = RMS Voltage x RMS current
// Power Factor = Real Power / Apparent Power
A_p=Rmsv*Rmsi; if(A_p<=0) A_p=0;
P_F=R_p/A_p; if (P_F< 0 | P_F>1) P_F=0;
theta=acos(P_F)*180/3.14159;
q=sqrt(pow(A_p,2)-pow(R_p,2));
IND_toggle();
GetTimeDate();elapsed=BOS.time.seconds-temp; if(elapsed<0) elapsed+=60;
R_p_s+=R_p*elapsed; // watt.s (cumulative sum)
if(R_p_s>3600) {R_p_h+=R_p_s/3600;R_p_s%=3600;}// watt.h (cumulative conversion)
q_s+=q*elapsed;
if(q_s>3600) {q_h+=q_s/3600;q_s%=3600;}// VAR.h (cumulative conversion)
p=R_p_s+(R_p_h*3600);
if (Rmsv>40) {status = EE_WriteVariable(_EE_MyVar,p);// no need to store energy in case of phase absence/failure
freq+= 1250 /(inda-indv);if((freq>60)|(freq<40)) freq=50;}
- We take advantage of BOS API
StartMicroDelay
to achieve the time of the signal, which is 20 ms for 100 sample.
- The obtained voltage and current values are uncertain due to grid harmonics, so we will perform some calibrations. First, we calculate the average error for current and voltage and perform an online calibration for the obtained values (median filter).
// get values sequentially not simultaneously ...!
for(i=0;i<100;i++)
{
SampleV(&volt);SampleA(&curr);
Vbuff[i]=volt;Ibuff[i]=curr;
StartMicroDelay(135);//135+65=200u, 200u*100= 20 ms.
}
for(i=0;i<100;i++) // calc average error for current
{avi=avi+Ibuff[i];} avi=avi/100;
for(i=0;i<100;i++) // Current online calibration
{Ibuff[i]=Ibuff[i]-avi;}
for(i=0;i<100;i++) // calc average error for volt
{avv=avv+Vbuff[i];} avv=avv/100;
for(i=0;i<100;i++) // Current online calibration
{Vbuff[i]=Vbuff[i]-avv;}
- Then the maximum peak amplitude of the voltage is determined, whether it was positive or negative, to calculate the values for frequency and RMS.
// catch max value with indicator
if(Vbuff[0] < 0) // wwe need peaks maxv+ and maxv-
{MaxV = Vbuff[0]*-1;signv=1;}
else {MaxV = Vbuff[0];signv=0;}
for(i=1;i<100;i++)
{
if(Vbuff[i] < 0)
{if(MaxV < -1*Vbuff[i] ) {MaxV=-1*Vbuff[i];signv=1;indv=i;}}
else
{if(MaxV < Vbuff[i] ) {MaxV=Vbuff[i];signv=0;indv=i;}}
}
if(signv==1) MaxV *= -1; MaxV=MaxV/1.414;
- Then we calculate the frequency in a digital way by implementing a rectifier that takes only positive values, and then detect peaks and store them in the parameter
indv
, the frequency is then calculated from the distance from pick to pick.
// frequency calculation
for(i=0;i<100;i++) // rectifier
{buff[i]=Vbuff[i];if(buff[i] < 0) buff[i]=-buff[i];}
Maxvp = buff[0];
for(i=1;i<50;i++)
{if(Maxvp < buff[i] ) {Maxvp=buff[i];indv=i;}}
Maxvp = buff[50];
for(i=50;i<100;i++)
{if(Maxvp < buff[i] ) {Maxvp=buff[i];inda=i;}}
// freq= 5000 /(indv-inda); no need to calc in case of phase absence
for(i=0;i<100;i++) {buff[i]=0;} // clean
// Real Power discrete time calculation
for(i=0;i<100;i++)
{Pbuff[i]=Ibuff[i]*Vbuff[i];// the acquired samples were sequential not simultaneous
sumi+=Pbuff[i];}R_p=sumi/100;// watt
if(R_p<0) R_p=-R_p;sumi=0;
- RMS current is calculated using the equations at [8], [9], substituting voltage samples, u(n), for current samples, i(n).
// RMS discrete time calculation
for(i=0;i<100;i++)
{buff[i]=pow(Vbuff[i],2);sumv+=buff[i];} Rmsv=sqrt(sumv/100)*1.15; // we need here filter for stable values
if(Rmsv<MaxV) Rmsv=MaxV;
for(i=0;i<100;i++)
{buff[i]=pow(Ibuff[i],2);sumi+=buff[i];}Rmsi=sqrt(sumi/100); // we need here filter for stable values
// Apparent power = RMS Voltage x RMS current
// Power Factor = Real Power / Apparent Power
A_p=Rmsv*Rmsi; if(A_p<=0) A_p=0;
P_F=R_p/A_p; if (P_F< 0 | P_F>1) P_F=0;
theta=acos(P_F)*180/3.14159;
q=sqrt(pow(A_p,2)-pow(R_p,2));
IND_toggle();
- Apparent Power and Power Factor:
Apparent power is calculated, as follows:
Apparent power = RMS Voltage x RMS current
and the power factor is calculated from the definition:
Power Factor = Real Power / Apparent Power
- Finally, we display the parameters:
To show a float value on the display when the button is pressed, we use CODE_H3BR6_SevenDis-playQuantities message. The parameter unit refers to the value unit (one character only).
if (Pressed == 1)
{
rx = 0;
WriteRemote(2, (uint32_t)rx, 1, FMT_UINT8, 1);
HAL_Delay(100);
rx = 0;
WriteRemote(2, (uint32_t)rx, 1, FMT_UINT8, 1);
HAL_Delay(100);
rx = 0;
WriteRemote(2, (uint32_t)rx, 1, FMT_UINT8, 1);
HAL_Delay(100);
for (int i = 0 ; i<3 ;i++)
{
memcpy(&messageParams[0], &Rmsv,4);
messageParams[4] = 0;
messageParams[5] = 'V';
messageParams[6] = 1;
SendMessageToModule(2,CODE_H3BR6_SevenDisplayQuantities,7);
HAL_Delay(1500);
memcpy(&messageParams[0], &Rmsi,4);
messageParams[4] = 2; /////// Resoulation
messageParams[5] = 'A'; ////// unit
messageParams[6] = 1; ////// Start SevSeg
SendMessageToModule(2,CODE_H3BR6_SevenDisplayQuantities,7);
HAL_Delay(1500);
if (R_p_h >0)
{
messageParams[0]='h';
messageParams[1]= 1;
SendMessageToModule(2, CODE_H3BR6_SevenDisplayLetter,2);
messageParams[0]='W';
messageParams[1]= 2;
SendMessageToModule(2, CODE_H3BR6_SevenDisplayLetter,2);
memcpy(&messageParams[0],&R_Show2, 4);
messageParams[4]= 0;
messageParams[5]= 3;
SendMessageToModule(2, CODE_H3BR6_SevenDisplayNumberF, 6);
// memcpy(&messageParams[0], &R_Show2,4);
// messageParams[4] = 0;
// messageParams[5] = 'w';
// messageParams[6] = 1;
// SendMessageToModule(2,CODE_H3BR6_SevenDisplayQuantities,7);
HAL_Delay(1500);
}
else
{
memcpy(&messageParams[0], &R_Show1,4);
messageParams[4] = 0;
messageParams[5] = 'j';
messageParams[6] = 0;
SendMessageToModule(2,CODE_H3BR6_SevenDisplayQuantities,7);
HAL_Delay(1500);
} //w.h
memcpy(&messageParams[0], &theta1,4);
messageParams[4] = 0;
messageParams[5] = 'd';
messageParams[6] = 1;
SendMessageToModule(2,CODE_H3BR6_SevenDisplayQuantities,7);
HAL_Delay(1500);
}
rx=1;// sleep 7-Seg
WriteRemote(2, (uint32_t)rx, 1, FMT_UINT8, 1);
HAL_Delay(800);
WriteRemote(2, (uint32_t)rx, 1, FMT_UINT8, 1);
HAL_Delay(800);
WriteRemote(2, (uint32_t)rx, 1, FMT_UINT8, 1);
HAL_Delay(800);
Pressed = 0;
}
3) Test the System 🧐🤩🙂☠️👀👨🔧⚡️💥💡🔌🔍Overall, this project provides a simple and effective way to monitor your energy consumption using Hexabitz modules. With a few modifications, you can customize the code to suit your specific needs and requirements.
⚡️ Future Work:The energy meter industry is constantly evolving, and with the advent of artificial intelligence and machine learning, there is a huge potential for further development. The use of these technologies can make our energy meter smarter and more efficient.
One such development could be the integration of machine learning algorithms that can predict which appliances are being used and when, based on patterns of energy usage. This would allow the meter to accurately predict when demand is likely to increase or decrease, and adjust the power supply accordingly.
Another potential development could be the use of artificial intelligence to identify faulty appliances and automatically switch them off to prevent damage to the electrical system. This would not only save energy but also reduce the risk of electrical fires.
In addition, the use of smart sensors could provide real-time data on energy usage, allowing consumers to monitor their energy consumption and make adjustments to reduce their carbon footprint.
Please feel free to leave a comment here if you have any questions or concerns regarding this project 😊
⚡️ References:[1]: https://hexabitz.com/product/ac-current-and-voltage-sensor-h2ar3/
[2]: https://hexabitz.com/product/stlink-v3mods-programmer-h40rx-2/
[3]: https://hexabitz.com/product/rs485-serial-transceiver-h1dr1x/
[4]: https://hexabitz.com/product/100-mil-pth-proto-board-h00r4x/
[5]: https://hexabitz.com/product/6-digit-seven-segment-h3br6x/
[6]: Wire Lead (crmagnetics.com)
[7]: Wiki – Hexabitz
[8]: https://www.hackster.io/ahmad-taskia/hexabitz-single-phase-power-analyser-8bf910
[9]: https://docs.openenergymonitor.org/electricity-monitoring/ac-power-theory/advanced-maths.html
Comments
Please log in or sign up to comment.