目錄
1、硬體設計
2、軟體設計
WiFi物聯網智能插座的電耗采集依托于合力為的HLW8110計量晶片實作,選取它的主要原因是精度不錯,價格美麗,并且可以通過序列槽驅動,使用便捷。

HLW8110是一款高精度的電能計量 IC,它采用 CMOS 制造技術,主要用于單相計量應用。它能夠測量線電壓和電流,并能計算有功功率,視在功率和功率因素。該器件内部內建了二個∑-Δ型 ADC 和一個高精度的電能計量核心。輸入通道支援靈活的 PGA 設定,是以 HLW8110 适合與不同類型的傳感器使用,如電流互感器(CT)和低阻值分流器。
HLW8110 電能計量 IC 采用 3.3V 或 5.0V 電源供電,内置 3.579M 振蕩器,可以通過 UART 口進行資料通訊,波特率為 9600bps。
由于代碼量較多,部配置設定置代碼不再贅述,僅僅展示核心算法代碼。
讀取通道電流,實作代碼如下所示:
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);
}
}