Hexabitz Energy Meter

The Hexabitz Energy Meter is a single-phase energy meter designed to measure voltage, current, power, energy and power factor.

ExpertFull instructions provided10 hours539
Hexabitz Energy Meter

Things used in this project

Hardware components

4-Pin USB-Serial Prototype Cable
Hexabitz 4-Pin USB-Serial Prototype Cable
×1
STLINK-V3MODS Programmer (H40Rx)
Hexabitz STLINK-V3MODS Programmer (H40Rx)
×1
6 Digit Seven Segment (H3BR6x)
Hexabitz 6 Digit Seven Segment (H3BR6x)
×1
AC Current and Voltage Sensor (H2AR3)
Hexabitz AC Current and Voltage Sensor (H2AR3)
×1
100-mil PTH Proto Board (H00R4x)
Hexabitz 100-mil PTH Proto Board (H00R4x)
×1
RS485 Serial Transceiver (H1DR1x)
Hexabitz RS485 Serial Transceiver (H1DR1x)
×1
Capacitor 100 µF
Capacitor 100 µF
×1
Capacitor 100 nF
Capacitor 100 nF
×1
Capacitor 22 µF
Capacitor 22 µF
×1
Electrolytic Capacitor, 2.2 µF
Electrolytic Capacitor, 2.2 µF
×1
SMBJ7.0A Diode
×1
AC/DC-On-board Converter Module
×1

Software apps and online services

STM32CUBEPROG
STMicroelectronics STM32CUBEPROG
STMicroelectronics STM32CubeIDE

Hand tools and fabrication machines

Solder Wire, Lead Free
Solder Wire, Lead Free
5V / 8W Portable USB Soldering Iron
Hexabitz 5V / 8W Portable USB Soldering Iron
4-Port USB 2.0 Hub with Individual Power Switches
Hexabitz 4-Port USB 2.0 Hub with Individual Power Switches
3D Printer (generic)
3D Printer (generic)
Wire Stripper, Automatic
Wire Stripper, Automatic
Premium Female/Female Jumper Wires, 40 x 3" (75mm)
Premium Female/Female Jumper Wires, 40 x 3" (75mm)

Story

Read more

Custom parts and enclosures

6 Digit Seven Segment (H3BR6x) module code

AC Current and Voltage Sensor (H2AR3x) code

Schematics

CR8400 CurrentTransformer Datasheet

AC Current and Voltage Sensor (H2AR3x) module factsheet

AC Current and Voltage Sensor (H2AR3x) Schematic

H1DR10 Schematics

RS485 Serial Transceiver (H1DR1x) Factsheet

6 Digit Seven Segment (H3BR6x) module factsheet

Code

topology.h

C Header File
/*
 BitzOS (BOS) V0.2.7 - Copyright (C) 2017-2022 Hexabitz
 All rights reserved

 File Name     : topology.h
 Description   : Array topology definition.

 */

/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __topology_H
#define __topology_H
#ifdef __cplusplus
 extern "C" {
#endif

/* Includes ------------------------------------------------------------------*/
#include "stm32G0xx_hal.h"

#define __N	2					// Number of array modules

// Array modules
#define _mod1	1<<3
#define _mod2	2<<3

// Topology
static uint16_t array[__N ][7] ={
	{_H2AR3, 0, _mod2 | P3, 0, 0, 0, 0}, 						 // Module 1
	{_H3BR6, 0, 0, _mod1 | P2, 0, 0, 0},					     // Module 2
};

// Configurations for duplex serial ports
#if ( _module == 1 )
	#define	H2AR3	1
	#define	_P1pol_normal	1
	#define	_P2pol_normal	1
	#define	_P3pol_normal	1
	#define	_P4pol_normal	1
	#define	_P5pol_normal	1
	#define	_P6pol_normal	1
#endif

#if ( _module == 2 )
	#define	H3BR6	1
	#define	_P1pol_normal	1
	#define	_P2pol_normal	1
	#define	_P3pol_reversed	1
	#define	_P4pol_normal	1
	#define	_P5pol_normal	1
	#define	_P6pol_normal	1

#endif

#ifdef __cplusplus
}
#endif
#endif /*__ topology_H */

/************************ (C) COPYRIGHT HEXABITZ *****END OF FILE****/

AC Current and Voltage Sensor (H2AR3x) main code

C/C++
/*
 BitzOS (BOS) V0.2.7 - Copyright (C) 2017-2022 Hexabitz
 All rights reserved

 File Name     : main.c
 Description   : Main program body.
 */
/* Includes ------------------------------------------------------------------*/
#include "BOS.h"

__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
//int Rmsv=209;Rmsi=2;A_p=418;R_p=410;P_F,theta;

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[20]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20};
uint8_t Data[24]={0};
uint32_t x;
uint8_t *send; uint8_t jata[4]={0};

volatile uint8_t Pressed =0;

//uint8_t signi=0;//0:+...1:-
/* Private variables ---------------------------------------------------------*/

/* Private function prototypes -----------------------------------------------*/
//char buffer[50]={0};

uint16_t buffer[255]={0};
uint8_t bufferLength = 255;

/* Main function ------------------------------------------------------------*/

int main(void){

	Module_Init();		//Initialize Module &  BitzOS

	//Don't place your code here.
	for(;;){}
}

/*-----------------------------------------------------------*/

/* User Task */
void UserTask(void *argument){
	AddPortButton(MOMENTARY_NO, P1);
	SetButtonEvents(1,1,0,0,0,0,0,0,0,0);
	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
	SwapUartPins(&huart3, REVERSED);

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

	rx=1;// sleep 7-Seg
	WriteRemote(2, (uint32_t)rx, 1, FMT_UINT8, 1);
	HAL_Delay(800);

	rx=1;// sleep 7-Seg
	WriteRemote(2, (uint32_t)rx, 1, FMT_UINT8, 1);
	HAL_Delay(800);


	while(1)
	{
		//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;

		// 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;}
		// first packet has been sent to EMS interface board successfully.
		//		Rmsi=5.68;/*0x238*/Rmsv=0xDC;P_F=0.85;//0x55
		//		//current_MBS = Rmsi*100;
		//		R_p_s=8800;/*0x2260*/q_s=350;/*0x15E*/q=160.88;/*0x3ED8*/
		//		Rmsi*=100;x=(uint16_t)Rmsi;
		//		Data[0]= Rmsv;
		//		/*Data[1]=x>>24;Data[2]=x>>16;Data[3]=x>>8;Data[4]=x;*/
		//		memcpy(&Data[1],&x,2);
		//		//memcpy(&Data[1],&current_MBS,2);               //Data[1]= (uint8_t)(Rmsi*100>>8);
		//		Data[3]=P_F*100;
		//		memcpy(&Data[4],&R_p_s,2);
		//		memcpy(&Data[6],&q_s,2);
		//        q*=100;x=(uint16_t)q;
		//        memcpy(&Data[8],&x,2);freq=49;
		//        Data[10]=freq;
		R_Show1 = R_p_s;
		R_Show2 = R_p_h;
		theta1 = theta;

		/*=========================Send the analysis Package To 7Seg Module================ */
		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;
		}

		// second dynamic packet to be tested with EMS interface board: it was ok
		//Rmsi=5.68;/*0x238*/Rmsv=0xDC;P_F=0.85;//0x55
		//current_MBS = Rmsi*100;
		//R_p_s=8800;/*0x2260*/q_s=350;/*0x15E*/q=160.88;/*0x3ED8*/
		/*Rmsi*=100;x=(uint16_t)Rmsi;Data[0]= Rmsv;memcpy(&Data[1],&x,2);Data[3]=P_F*100;
		memcpy(&Data[4],&R_p_s,2);memcpy(&Data[6],&q_s,2);q*=100;x=(uint16_t)q;
		memcpy(&Data[8],&x,2);Data[10]=freq;
		HAL_UART_Transmit_IT(GetUart(P3), (uint8_t *)Data, 20);*/

		//================new modification for JASON file==============================//
//		Data[0]= Rmsv;Data[1]= 0;// LSByte then MSByte of Rmsv
//		Rmsi*=1000;x=(uint32_t)Rmsi;
//		Data[2]=x;Data[3]=x>>8;Data[4]=x>>16;Data[5]=x>>24;
//		P_F*=1000;x=(uint32_t)P_F;
//		Data[6]=x;Data[7]=x>>8;Data[8]=x>>16;Data[9]=x>>24;
//		Data[10]=R_p_h;Data[11]=R_p_h>>8;
//		Data[12]=q_h;Data[13]=q_h>>8;
//		Data[14]=freq;Data[15]=0;// LSByte then MSByte of freq
//		HAL_UART_Transmit_IT(GetUart(P3), (uint8_t *)Data, 20);
		// JASON MOD 2572023:
		Data[0]= (uint8_t)Rmsv;Data[1]= 0;Data[2]= 0;Data[3]= 0;// LSByte then MSByte of Rmsv
		Rmsi*=1000;x=(uint32_t)Rmsi;
		send=(uint8_t *)&Rmsi;
		memcpy(&Data[4],send,sizeof(float));
		//Data[4]=x;Data[5]=x>>8;Data[6]=x>>16;Data[7]=x>>24;
		P_F*=1000;x=(uint32_t)P_F;
		send=(uint8_t *)&P_F;
		memcpy(&Data[8],send,sizeof(float));
	//	Data[8]=x;Data[9]=x>>8;Data[10]=x>>16;Data[11]=x>>24;
		//Data[8]=(uint8_t)P_F;Data[9]=(uint8_t)P_F>>8;Data[10]=(uint8_t)P_F>>16;Data[11]=(uint8_t)P_F>>24;
		Data[12]=R_p_h;Data[13]=R_p_h>>8;Data[14]= 0;Data[15]= 0;
		Data[16]=q_h;Data[17]=q_h>>8;Data[18]= 0;Data[19]= 0;
		Data[20]=freq;Data[21]=0;Data[22]= 0;Data[23]= 0;// LSByte then MSByte of freq
		HAL_UART_Transmit_IT(GetUart(P3), (uint8_t *)Data, 24);

		/* Send the analysis Package */
		/*sprintf(buffer,"\n\n\rIrms: %.3f A\n\rVrms: %.2f V\n\rS   : %f VA\n\rP   : %f W\n\rQ   : %f VAR\n\rCOS : %.2f\n\rTheta: %d deg\n\r"
		"Active Energy cumulative:\n\r %d W.sec %d W.hour\n\rReactive Energy cumulative:\n\r %d VAR.sec %d VAR.hour\n\rfreq: %f Hz\n\n\r>",Rmsi,Rmsv,A_p,R_p,q,P_F,theta,R_p_s,R_p_h,q_s,q_h,freq);
		writePxMutex(P1, (uint8_t*)buffer, bufferLength, 0xffff, 0xffff);*/
	}
}
/*-----------------------------------------------------------*/
void buttonClickedCallback(uint8_t port)
{
	Pressed = 1;
}

6 Digit Seven Segment (H3BR6x) module main code

C/C++
/*
 BitzOS (BOS) V0.2.9 - Copyright (C) 2017-2023 Hexabitz
 All rights reserved

 File Name     : main.c
 Description   : Main program body.
 */
/* Includes ------------------------------------------------------------------*/
#include "BOS.h"

/* Private variables ---------------------------------------------------------*/
extern TIM_HandleTypeDef htim6;
/* Private function prototypes -----------------------------------------------*/
__IO uint8_t rx=0;
/* Main function ------------------------------------------------------------*/

int main(void){

	Module_Init();		//Initialize Module &  BitzOS

	//Don't place your code here.
	for(;;){}
}

/*-----------------------------------------------------------*/

/* User Task */
void UserTask(void *argument){
	BOSMessaging.trace=NONE;
	AddBOSvar(FMT_UINT8, (uint32_t)rx);
	// put your code here, to run repeatedly.
	while(1){

		if(rx == 128)
		{
			SevenDisplayOff();
			ClearIndicator(Ind1);
			ClearIndicator(Ind2);
			HAL_Delay(500);
			HAL_TIM_Base_Stop_IT(&htim6);
			HAL_SuspendTick();
			HAL_PWR_EnterSLEEPMode(PWR_LOWPOWERREGULATOR_ON,PWR_SLEEPENTRY_WFI);
			HAL_ResumeTick();
			HAL_Delay(20);
			HAL_TIM_Base_Start_IT(&htim6);

		}
		else
		{
			HAL_ResumeTick();
			HAL_Delay(500);
			HAL_TIM_Base_Start_IT(&htim6);
			SetIndicator(Ind1);
		}

	}
}

void HAL_GPIO_EXTI_Rising_Callback(uint16_t GPIO_Pin)
{
	if(GPIO_Pin == GPIO_PIN_3) // If The INT Source Is EXTI Line9 (A9 Pin)
	{
		SetIndicator(Ind2);
		rx = 0;
	}
}
/*-----------------------------------------------------------*/

AC Current and Voltage Sensor (H2AR3x) Firmware

6 Digit Seven Segment (H3BR6x) module Firmware

RS485 Serial Transceiver (H1DR1x) Firmware

Credits

Mahmoud Mardnly
12 projects • 19 followers
Embedded System Engineer
Contact
Aula 💡🕊️
60 projects • 224 followers
Electronic Engineering
Contact
Abdulrhman_Battiekh
0 projects • 1 follower
Contact
Ahmad TASKIA
12 projects • 11 followers
MPhil. Bsc. ELECTRONICS Engineering
Contact
Bakry Rihawi
3 projects • 9 followers
Contact

Comments

Please log in or sign up to comment.