写点什么

国产芯片 WiFi 物联网智能插座—电耗采集功能设计

发布于: 2021 年 03 月 01 日
国产芯片WiFi物联网智能插座—电耗采集功能设计

WiFi 物联网智能插座的电耗采集依托于合力为的 HLW8110 计量芯片实现,选取它的主要原因是精度不错,价格美丽,并且可以通过串口驱动,使用便捷。



1、硬件设计


HLW8110 是一款高精度的电能计量 IC,它采用 CMOS 制造工艺,主要用于单相计量应用。它能够测量线电压和电流,并能计算有功功率,视在功率和功率因素。该器件内部集成了二个∑-Δ型 ADC 和一个高精度的电能计量内核。输入通道支持灵活的 PGA 设置,因此 HLW8110 适合与不同类型的传感器使用,如电流互感器(CT)和低阻值分流器。


HLW8110 电能计量 IC 采用 3.3V 或 5.0V 电源供电,内置 3.579M 振荡器,可以通过 UART 口进行数据通讯,波特率为 9600bps。



HLW8110 的典型电路,外围电路简单,外围器件非常少,单路通道可用于检测负载设备的功率、电压、电流和用电量,通过 UART 或接口传输数据至 MCU,HLW8110 内部可以设置功率过载、电压过载和电流过载阀值,通过内部寄存器可以查询,并可以检测电压过零点。



官方测试,使用采样电阻或者互感器的理论数据误差如下所示:



在使用之前先简单设计一块 Demo 板进行调测,实物模块如下所示:



原理图、PCB 如下所示:



​2、软件设计


由于代码量较多,部分配置代码不再赘述,仅仅展示核心算法代码。


读取通道电流,实现代码如下所示:


void Read_HLW8110_IA(void){		float a;		Uart_Read_HLW8110_Reg(REG_RMSIA_ADDR,3);		delay_ms(10);	if ( u8_RxBuf[u8_RX_Length-1] == HLW8110_checkSum_Read(u8_RX_Length) )	{		U32_RMSIA_RegData = (unsigned long)(u8_RxBuf[0]<<16) + (unsigned long)(u8_RxBuf[1]<<8) + (unsigned long)(u8_RxBuf[2]); 		printf("A通道电流寄存器:%lx\n " ,U32_RMSIA_RegData);	}	else	{		printf("A通道电流寄存器读取出错\r\n");		B_Read_Error = 1;	}			//A通道电流PGA = 16,电压通道PGA = 1;电流采样电阻1mR,电压采样电阻1M  //计算公式,U16_AC_I = (U32_RMSIA_RegData * U16_RMSIAC_RegData)/(电流系数* 2^23)	if ((U32_RMSIA_RegData & 0x800000) == 0x800000)	 {			F_AC_I = 0;	 }	 else	 {		a = (float)U32_RMSIA_RegData;		a = a * U16_RMSIAC_RegData;		a  = a/0x800000;                     //电流计算出来的浮点数单位是mA,比如5003.12 		a = a/1;  								// 1 = 电流系数		a = a/1000;              //a= 5003ma,a/1000 = 5.003A,单位转换成A		a = a * D_CAL_A_I;				//D_CAL_A_I是校正系数,默认是1		F_AC_I = a;	 }}
复制代码


读取通道电压,实现代码如下所示:


void Read_HLW8110_U(void){	float a;		Uart_Read_HLW8110_Reg(REG_RMSU_ADDR,3);		delay_ms(10);	if ( u8_RxBuf[u8_RX_Length-1] == HLW8110_checkSum_Read(u8_RX_Length) )	{		U32_RMSU_RegData = (unsigned long)(u8_RxBuf[0]<<16) + (unsigned long)(u8_RxBuf[1]<<8) + (unsigned long)(u8_RxBuf[2]);		printf("电压通道寄存器:%lx\n " ,U32_RMSU_RegData);	}	else	{		printf("电压通道寄存器读取出错\r\n");		B_Read_Error = 1;	}			//电压	//计算:U16_AC_V = (U32_RMSU_RegData * U16_RMSUC_RegData)/2^23		 if ((U32_RMSU_RegData &0x800000) == 0x800000)	 {			F_AC_V = 0;	 }  else	{  a =  (float)U32_RMSU_RegData;  a = a*U16_RMSUC_RegData;    a = a/0x400000;         a = a/1;  						// 1 = 电压系数  a = a/100;    				//计算出a = 22083.12mV,a/100表示220.8312V,电压转换成V  a = a*D_CAL_U;				//D_CAL_U是校正系数,默认是1,		  F_AC_V = a;	}}
复制代码


读取通道功率,实现代码如下所示:


void Read_HLW8110_PA(void){	float a;	float b;		Uart_Read_HLW8110_Reg(REG_POWER_PA_ADDR,4);		delay_ms(10);	if ( u8_RxBuf[u8_RX_Length-1] == HLW8110_checkSum_Read(u8_RX_Length) )	{		U32_POWERPA_RegData = (unsigned long)(u8_RxBuf[0]<<24) + (unsigned long)(u8_RxBuf[1]<<16) + (unsigned long)(u8_RxBuf[2]<<8) + (unsigned long)(u8_RxBuf[3]);		printf("A通道功率寄存器:%lx\n " ,U32_POWERPA_RegData);	}	else	{		printf("A通道功率寄存器读取出错\r\n");		B_Read_Error = 1;	}			 if (U32_POWERPA_RegData > 0x80000000)   {     b = ~U32_POWERPA_RegData;     a = (float)b;   }   else     a =  (float)U32_POWERPA_RegData;        	//功率需要分正功和负功  //计算,U16_AC_P = (U32_POWERPA_RegData * U16_PowerPAC_RegData)/(2^31*电压系数*电流系数)	//单位为W,比如算出来5000.123,表示5000.123W	    a = a*U16_PowerPAC_RegData;    a = a/0x80000000;                 a = a/1;  										// 1 = 电流系数    a = a/1;  										// 1 = 电压系数    a = a * D_CAL_A_P;						//D_CAL_A_P是校正系数,默认是1    F_AC_P = a;									//单位为W,比如算出来5000.123,表示5000.123W}
复制代码


读取通道有功电量,实现代码如下所示:


void Read_HLW8110_EA(void){	float a;	Uart_Read_HLW8110_Reg(REG_ENERGY_PA_ADDR,3); 	delay_ms(10);		if ( u8_RxBuf[u8_RX_Length-1] == HLW8110_checkSum_Read(u8_RX_Length) )	{		U32_ENERGY_PA_RegData = (unsigned long)(u8_RxBuf[0]<<16) + (unsigned long)(u8_RxBuf[1]<<8) + (unsigned long)(u8_RxBuf[2]);		printf("A通道有功电量寄存器:%lx\n " ,U32_ENERGY_PA_RegData);	}	else	{		printf("A通道有功电量寄存器读取出错\r\n");		B_Read_Error = 1;	}		Uart_Read_HLW8110_Reg(REG_HFCONST_ADDR,2); 	delay_ms(10);	if ( u8_RxBuf[u8_RX_Length-1] == HLW8110_checkSum_Read(u8_RX_Length) )	{		U16_HFConst_RegData = (unsigned int)(u8_RxBuf[0]<<8) + (unsigned int)(u8_RxBuf[1]);		printf("HFCONST常数 = :%d\n " ,U16_HFConst_RegData);	}	else	{		printf("HFCONST常数寄存器读取出错\r\n");		B_Read_Error = 1;	} 	//电量计算,电量 = (U32_ENERGY_PA_RegData * U16_EnergyAC_RegData * HFCONST) /(K1*K2 * 2^29 * 4096)	//HFCONST:默认值是0x1000, HFCONST/(2^29 * 4096) = 0x20000000	a =  (float)U32_ENERGY_PA_RegData;	  a = a*U16_EnergyAC_RegData;  a = a/0x20000000;             //电量单位是0.001KWH,比如算出来是2.002,表示2.002KWH       a = a/1;  										// 1 = 电流系数   a = a/1;  										// 1 = 电压系数   a = a * D_CAL_A_E;     			//D_CAL_A_E是校正系数,默认是1  F_AC_E = a;	F_AC_BACKUP_E = F_AC_E;	}
复制代码


读取通道的线性频率,实现代码如下所示:


void Read_HLW8110_LineFreq(void){	float a;	unsigned long b;	Uart_Read_HLW8110_Reg(REG_UFREQ_ADDR,2);	delay_ms(10);	if ( u8_RxBuf[u8_RX_Length-1] == HLW8110_checkSum_Read(u8_RX_Length) )	{		b = (unsigned long)(u8_RxBuf[0]<<8) + (unsigned long)(u8_RxBuf[1]);		printf("A通道线性频率寄存器:%ld\n " ,b);	}	else	{		printf("A通道线性频率寄存器读取出错\r\n");		B_Read_Error = 1;	}	a = (float)b;	a = 3579545/(8*a);    	F_AC_LINE_Freq = a;}
复制代码


读取通道功率因素,实现代码如下所示:


void Read_HLW8110_PF(void){  float a;  unsigned long b;	//测量A通道的功率因素,需要发送EA+5A命令//测量B通道的功率因素,需要发送EA+A5命令			Uart_Read_HLW8110_Reg(REG_PF_ADDR,3);	delay_ms(10);	if ( u8_RxBuf[u8_RX_Length-1] == HLW8110_checkSum_Read(u8_RX_Length) )	{		b = (unsigned long)(u8_RxBuf[0]<<16) + (unsigned long)(u8_RxBuf[1]<<8) + (unsigned long)(u8_RxBuf[2]);		printf("A通道功率因素寄存器:%ld\n " ,b);	}	else	{		printf("读取A通道功率因素寄存器出错\r\n");		B_Read_Error = 1;	}   if (b>0x800000)       //为负,容性负载  {      a = (float)(0xffffff-b + 1)/0x7fffff;  }  else  {      a = (float)b/0x7fffff;  }    if (F_AC_P < 0.3) // 小于0.3W,空载或小功率,PF不准	  a = 0;  //功率因素*100,最大为100,最小负100  F_AC_PF = a;}
复制代码


读取通道相位角,实现代码如下所示:


void Read_HLW8110_Angle(void){	float a;		unsigned long b;	Uart_Read_HLW8110_Reg(REG_ANGLE_ADDR,2);	delay_ms(10);	if ( u8_RxBuf[u8_RX_Length-1] == HLW8110_checkSum_Read(u8_RX_Length) )	{		b =(unsigned long)(u8_RxBuf[0]<<8) + (unsigned long)(u8_RxBuf[1]);		printf("A通道线相角寄存器:%ld\n " ,b);	}	else	{		printf("A通道线相角寄存器出错\r\n");		B_Read_Error = 1;	}		if ( F_AC_PF < 55)	//线性频率50HZ	{		a = b;		a = a * 0.0805;		F_Angle = a;	}	else	{		//线性频率60HZ		a = b;		a = a * 0.0965;		F_Angle = a;	}				if (F_AC_P < 0.5)		//功率小于0.5时,说明没有负载,相角为0	{		F_Angle = 0;	}		if (F_Angle < 90)	{		a = F_Angle;		printf("电流超前电压:%f\n " ,a);	}	else if (F_Angle < 180)	{		a = 180-F_Angle;		printf("电流滞后电压:%f\n " ,a);		}	else if (F_Angle < 360)	{		a = 360 - F_Angle;		printf("电流滞后电压:%f\n " ,a);		}	else	{			a = F_Angle -360;			printf("电流超前电压:%f\n " ,a);		}}
复制代码


发布于: 2021 年 03 月 01 日阅读数: 14
用户头像

【研究方向】物联网、嵌入式、AI、Python 2018.02.09 加入

【公众号】美男子玩编程

评论

发布
暂无评论
国产芯片WiFi物联网智能插座—电耗采集功能设计