天天看點

國産晶片WiFi物聯網智能插座—電耗采集功能設計

目錄

1、硬體設計

2、軟體設計

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

國産晶片WiFi物聯網智能插座—電耗采集功能設計

HLW8110是一款高精度的電能計量 IC,它采用 CMOS 制造技術,主要用于單相計量應用。它能夠測量線電壓和電流,并能計算有功功率,視在功率和功率因素。該器件内部內建了二個∑-Δ型 ADC 和一個高精度的電能計量核心。輸入通道支援靈活的 PGA 設定,是以 HLW8110 适合與不同類型的傳感器使用,如電流互感器(CT)和低阻值分流器。

HLW8110 電能計量 IC 采用 3.3V 或 5.0V 電源供電,内置 3.579M 振蕩器,可以通過 UART 口進行資料通訊,波特率為 9600bps。

國産晶片WiFi物聯網智能插座—電耗采集功能設計
HLW8110的典型電路,外圍電路簡單,外圍器件非常少,單路通道可用于檢測負載裝置的功率、電壓、電流和用電量,通過 UART 或接口傳輸資料至 MCU,HLW8110 内部可以設定功率過載、電壓過載和電流過載閥值,通過内部寄存器可以查詢,并可以檢測電壓過零點。
國産晶片WiFi物聯網智能插座—電耗采集功能設計
官方測試,使用采樣電阻或者互感器的理論資料誤差如下所示:
國産晶片WiFi物聯網智能插座—電耗采集功能設計
在使用之前先簡單設計一塊Demo闆進行調測,實物子產品如下所示:
國産晶片WiFi物聯網智能插座—電耗采集功能設計
原理圖、PCB如下所示:
國産晶片WiFi物聯網智能插座—電耗采集功能設計

由于代碼量較多,部配置設定置代碼不再贅述,僅僅展示核心算法代碼。

讀取通道電流,實作代碼如下所示:

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

繼續閱讀