查看: 264|回复: 0

[参赛项目] 创客造|国产芯片WiFi物联网智能插座—电耗采集功能设计

[复制链接]
WiFi物联网智能插座的电耗采集依托于合力为的HLW8110计量芯片实现,选取它的主要原因是精度不错,价格美丽,并且可以通过串口驱动,使用便捷。
WedJanuary-202101204396..png
1、硬件设计
HLW8110是一款高精度的电能计量 IC,它采用 CMOS 制造工艺,主要用于单相计量应用。它能够测量线电压和电流,并能计算有功功率,视在功率和功率因素。该器件内部集成了二个∑-Δ型 ADC 和一个高精度的电能计量内核。输入通道支持灵活的 PGA 设置,因此 HLW8110 适合与不同类型的传感器使用,如电流互感器(CT)和低阻值分流器。
HLW8110 电能计量 IC 采用 3.3V 或 5.0V 电源供电,内置 3.579M 振荡器,可以通过 UART 口进行数据通讯,波特率为 9600bps。
WedJanuary-202101208138..png
HLW8110的典型电路,外围电路简单,外围器件非常少,单路通道可用于检测负载设备的功率、电压、电流和用电量,通过 UART 或接口传输数据至 MCU,HLW8110 内部可以设置功率过载、电压过载和电流过载阀值,通过内部寄存器可以查询,并可以检测电压过零点。
WedJanuary-202101206427..png
官方测试,使用采样电阻或者互感器的理论数据误差如下所示:
WedJanuary-202101209308..png
在使用之前先简单设计一块Demo板进行调测,实物模块如下所示:
WedJanuary-202101206670..png
原理图、PCB如下所示:

WedJanuary-202101201700..png
2、软件设计

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

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

  1. void Read_HLW8110_IA(void)
  2. {        
  3.         float a;
  4.         
  5.         Uart_Read_HLW8110_Reg(REG_RMSIA_ADDR,3);
  6.                 delay_ms(10);
  7.         if ( u8_RxBuf[u8_RX_Length-1] == HLW8110_checkSum_Read(u8_RX_Length) )
  8.         {
  9.                 U32_RMSIA_RegData = (unsigned long)(u8_RxBuf[0]<<16) + (unsigned long)(u8_RxBuf[1]<<8) + (unsigned long)(u8_RxBuf[2]);
  10.                 printf("A通道电流寄存器:%lx\n " ,U32_RMSIA_RegData);
  11.         }
  12.         else
  13.         {
  14.                 printf("A通道电流寄存器读取出错\r\n");
  15.                 B_Read_Error = 1;
  16.         }
  17.         
  18.         
  19.         //A通道电流PGA = 16,电压通道PGA = 1;电流采样电阻1mR,电压采样电阻1M
  20.   //计算公式,U16_AC_I = (U32_RMSIA_RegData * U16_RMSIAC_RegData)/(电流系数* 2^23)
  21.         if ((U32_RMSIA_RegData & 0x800000) == 0x800000)
  22.          {
  23.                         F_AC_I = 0;
  24.          }
  25.          else
  26.          {
  27.                 a = (float)U32_RMSIA_RegData;
  28.                 a = a * U16_RMSIAC_RegData;
  29.                 a  = a/0x800000;                     //电流计算出来的浮点数单位是mA,比如5003.12
  30.                 a = a/1;                                                                  // 1 = 电流系数
  31.                 a = a/1000;              //a= 5003ma,a/1000 = 5.003A,单位转换成A
  32.                 a = a * D_CAL_A_I;                                //D_CAL_A_I是校正系数,默认是1
  33.                 F_AC_I = a;
  34.          }
  35. }
复制代码

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

  1. void Read_HLW8110_U(void)
  2. {
  3.         float a;
  4.         
  5.         Uart_Read_HLW8110_Reg(REG_RMSU_ADDR,3);
  6.                 delay_ms(10);
  7.         if ( u8_RxBuf[u8_RX_Length-1] == HLW8110_checkSum_Read(u8_RX_Length) )
  8.         {
  9.                 U32_RMSU_RegData = (unsigned long)(u8_RxBuf[0]<<16) + (unsigned long)(u8_RxBuf[1]<<8) + (unsigned long)(u8_RxBuf[2]);
  10.                 printf("电压通道寄存器:%lx\n " ,U32_RMSU_RegData);
  11.         }
  12.         else
  13.         {
  14.                 printf("电压通道寄存器读取出错\r\n");
  15.                 B_Read_Error = 1;
  16.         }
  17.         
  18.                 //电压
  19.         //计算:U16_AC_V = (U32_RMSU_RegData * U16_RMSUC_RegData)/2^23
  20.         
  21.          if ((U32_RMSU_RegData &0x800000) == 0x800000)
  22.          {
  23.                         F_AC_V = 0;
  24.          }
  25.   else
  26.         {
  27.   a =  (float)U32_RMSU_RegData;
  28.   a = a*U16_RMSUC_RegData;  
  29.   a = a/0x400000;      
  30.   a = a/1;                                                  // 1 = 电压系数
  31.   a = a/100;                                    //计算出a = 22083.12mV,a/100表示220.8312V,电压转换成V
  32.   a = a*D_CAL_U;                                //D_CAL_U是校正系数,默认是1,               
  33.   F_AC_V = a;
  34.         }
  35. }
复制代码

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

  1. void Read_HLW8110_PA(void)
  2. {
  3.         float a;
  4.         float b;
  5.         
  6.         Uart_Read_HLW8110_Reg(REG_POWER_PA_ADDR,4);
  7.                 delay_ms(10);
  8.         if ( u8_RxBuf[u8_RX_Length-1] == HLW8110_checkSum_Read(u8_RX_Length) )
  9.         {
  10.                 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]);
  11.                 printf("A通道功率寄存器:%lx\n " ,U32_POWERPA_RegData);
  12.         }
  13.         else
  14.         {
  15.                 printf("A通道功率寄存器读取出错\r\n");
  16.                 B_Read_Error = 1;
  17.         }
  18.         
  19.         
  20.          if (U32_POWERPA_RegData > 0x80000000)
  21.    {
  22.      b = ~U32_POWERPA_RegData;
  23.      a = (float)b;
  24.    }
  25.    else
  26.      a =  (float)U32_POWERPA_RegData;
  27.      
  28.    
  29.         //功率需要分正功和负功
  30.   //计算,U16_AC_P = (U32_POWERPA_RegData * U16_PowerPAC_RegData)/(2^31*电压系数*电流系数)
  31.         //单位为W,比如算出来5000.123,表示5000.123W
  32.         
  33.     a = a*U16_PowerPAC_RegData;
  34.     a = a/0x80000000;            
  35.     a = a/1;                                                                                  // 1 = 电流系数
  36.     a = a/1;                                                                                  // 1 = 电压系数
  37.     a = a * D_CAL_A_P;                                                //D_CAL_A_P是校正系数,默认是1
  38.     F_AC_P = a;                                                                        //单位为W,比如算出来5000.123,表示5000.123W
  39. }
复制代码

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

  1. void Read_HLW8110_EA(void)
  2. {
  3.         float a;
  4.         Uart_Read_HLW8110_Reg(REG_ENERGY_PA_ADDR,3);
  5.         delay_ms(10);
  6.         
  7.         if ( u8_RxBuf[u8_RX_Length-1] == HLW8110_checkSum_Read(u8_RX_Length) )
  8.         {
  9.                 U32_ENERGY_PA_RegData = (unsigned long)(u8_RxBuf[0]<<16) + (unsigned long)(u8_RxBuf[1]<<8) + (unsigned long)(u8_RxBuf[2]);
  10.                 printf("A通道有功电量寄存器:%lx\n " ,U32_ENERGY_PA_RegData);
  11.         }
  12.         else
  13.         {
  14.                 printf("A通道有功电量寄存器读取出错\r\n");
  15.                 B_Read_Error = 1;
  16.         }
  17.         
  18.         Uart_Read_HLW8110_Reg(REG_HFCONST_ADDR,2);
  19.         delay_ms(10);
  20.         if ( u8_RxBuf[u8_RX_Length-1] == HLW8110_checkSum_Read(u8_RX_Length) )
  21.         {
  22.                 U16_HFConst_RegData = (unsigned int)(u8_RxBuf[0]<<8) + (unsigned int)(u8_RxBuf[1]);
  23.                 printf("HFCONST常数 = :%d\n " ,U16_HFConst_RegData);
  24.         }
  25.         else
  26.         {
  27.                 printf("HFCONST常数寄存器读取出错\r\n");
  28.                 B_Read_Error = 1;
  29.         }
  30.         //电量计算,电量 = (U32_ENERGY_PA_RegData * U16_EnergyAC_RegData * HFCONST) /(K1*K2 * 2^29 * 4096)
  31.         //HFCONST:默认值是0x1000, HFCONST/(2^29 * 4096) = 0x20000000
  32.         a =  (float)U32_ENERGY_PA_RegData;        
  33.   a = a*U16_EnergyAC_RegData;
  34.   a = a/0x20000000;             //电量单位是0.001KWH,比如算出来是2.002,表示2.002KWH   
  35.    a = a/1;                                                                                  // 1 = 电流系数
  36.    a = a/1;                                                                                  // 1 = 电压系数
  37.    a = a * D_CAL_A_E;                             //D_CAL_A_E是校正系数,默认是1
  38.   F_AC_E = a;
  39.         F_AC_BACKUP_E = F_AC_E;        
  40. }
复制代码

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

  1. void Read_HLW8110_LineFreq(void)
  2. {
  3.         float a;
  4.         unsigned long b;
  5.         Uart_Read_HLW8110_Reg(REG_UFREQ_ADDR,2);
  6.         delay_ms(10);
  7.         if ( u8_RxBuf[u8_RX_Length-1] == HLW8110_checkSum_Read(u8_RX_Length) )
  8.         {
  9.                 b = (unsigned long)(u8_RxBuf[0]<<8) + (unsigned long)(u8_RxBuf[1]);
  10.                 printf("A通道线性频率寄存器:%ld\n " ,b);
  11.         }
  12.         else
  13.         {
  14.                 printf("A通道线性频率寄存器读取出错\r\n");
  15.                 B_Read_Error = 1;
  16.         }
  17.         a = (float)b;
  18.         a = 3579545/(8*a);   
  19.         F_AC_LINE_Freq = a;
  20. }
复制代码

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

  1. void Read_HLW8110_PF(void)
  2. {
  3.   float a;
  4.   unsigned long b;
  5.         
  6. //测量A通道的功率因素,需要发送EA+5A命令
  7. //测量B通道的功率因素,需要发送EA+A5命令        
  8.         
  9.         Uart_Read_HLW8110_Reg(REG_PF_ADDR,3);
  10.         delay_ms(10);
  11.         if ( u8_RxBuf[u8_RX_Length-1] == HLW8110_checkSum_Read(u8_RX_Length) )
  12.         {
  13.                 b = (unsigned long)(u8_RxBuf[0]<<16) + (unsigned long)(u8_RxBuf[1]<<8) + (unsigned long)(u8_RxBuf[2]);
  14.                 printf("A通道功率因素寄存器:%ld\n " ,b);
  15.         }
  16.         else
  17.         {
  18.                 printf("读取A通道功率因素寄存器出错\r\n");
  19.                 B_Read_Error = 1;
  20.         }
  21.   if (b>0x800000)       //为负,容性负载
  22.   {
  23.       a = (float)(0xffffff-b + 1)/0x7fffff;
  24.   }
  25.   else
  26.   {
  27.       a = (float)b/0x7fffff;
  28.   }
  29.   
  30.   if (F_AC_P < 0.3) // 小于0.3W,空载或小功率,PF不准
  31.           a = 0;
  32. //功率因素*100,最大为100,最小负100
  33.   F_AC_PF = a;
  34. }
复制代码

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

  1. <blockquote>void Read_HLW8110_Angle(void)
  2. {
  3.         float a;        
  4.         unsigned long b;
  5.         Uart_Read_HLW8110_Reg(REG_ANGLE_ADDR,2);
  6.         delay_ms(10);
  7.         if ( u8_RxBuf[u8_RX_Length-1] == HLW8110_checkSum_Read(u8_RX_Length) )
  8.         {
  9.                 b =(unsigned long)(u8_RxBuf[0]<<8) + (unsigned long)(u8_RxBuf[1]);
  10.                 printf("A通道线相角寄存器:%ld\n " ,b);
  11.         }
  12.         else
  13.         {
  14.                 printf("A通道线相角寄存器出错\r\n");
  15.                 B_Read_Error = 1;
  16.         }
  17.         
  18.         if ( F_AC_PF < 55)        //线性频率50HZ
  19.         {
  20.                 a = b;
  21.                 a = a * 0.0805;
  22.                 F_Angle = a;
  23.         }
  24.         else
  25.         {
  26.                 //线性频率60HZ
  27.                 a = b;
  28.                 a = a * 0.0965;
  29.                 F_Angle = a;
  30.         }
  31.         
  32.         
  33.                 if (F_AC_P < 0.5)                //功率小于0.5时,说明没有负载,相角为0
  34.         {
  35.                 F_Angle = 0;
  36.         }
  37.         
  38.         if (F_Angle < 90)
  39.         {
  40.                 a = F_Angle;
  41.                 printf("电流超前电压:%f\n " ,a);
  42.         }
  43.         else if (F_Angle < 180)
  44.         {
  45.                 a = 180-F_Angle;
  46.                 printf("电流滞后电压:%f\n " ,a);        
  47.         }
  48.         else if (F_Angle < 360)
  49.         {
  50.                 a = 360 - F_Angle;
  51.                 printf("电流滞后电压:%f\n " ,a);        
  52.         }
  53.         else
  54.         {
  55.                         a = F_Angle -360;
  56.                         printf("电流超前电压:%f\n " ,a);        
  57.         }
  58. }
复制代码

高级模式
B Color Image Link Quote Code Smilies |上传

本版积分规则

为本项目制作心愿单
购买心愿单
心愿单 编辑
[[wsData.name]]

硬件清单

  • [[d.name]]
btnicon
我也要做!
点击进入购买页面
上海智位机器人股份有限公司 沪ICP备09038501号-4

© 2013-2021 Comsenz Inc. Powered by Discuz! X3.4 Licensed

mail