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

举报
不脱发的程序猿 发表于 2021/03/10 00:58:52 2021/03/10
【摘要】 目录 1、硬件设计 2、软件设计 WiFi物联网智能插座的电耗采集依托于合力为的HLW8110计量芯片实现,选取它的主要原因是精度不错,价格美丽,并且可以通过串口驱动,使用便捷。 1、硬件设计 HLW8110是一款高精度的电能计量 IC,它采用 CMOS 制造工艺,主要用于单相计量应用。它能够测量线电压和电流,并能计算有功功率,视在功率和功率因素。该器件内部集...

目录

1、硬件设计

2、软件设计


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、软件设计

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

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


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

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


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

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


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

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


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

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


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

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


  
  1. 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. if ( F_AC_PF < 55) //线性频率50HZ
  18. {
  19. a = b;
  20. a = a * 0.0805;
  21. F_Angle = a;
  22. }
  23. else
  24. {
  25. //线性频率60HZ
  26. a = b;
  27. a = a * 0.0965;
  28. F_Angle = a;
  29. }
  30. if (F_AC_P < 0.5) //功率小于0.5时,说明没有负载,相角为0
  31. {
  32. F_Angle = 0;
  33. }
  34. if (F_Angle < 90)
  35. {
  36. a = F_Angle;
  37. printf("电流超前电压:%f\n " ,a);
  38. }
  39. else if (F_Angle < 180)
  40. {
  41. a = 180-F_Angle;
  42. printf("电流滞后电压:%f\n " ,a);
  43. }
  44. else if (F_Angle < 360)
  45. {
  46. a = 360 - F_Angle;
  47. printf("电流滞后电压:%f\n " ,a);
  48. }
  49. else
  50. {
  51. a = F_Angle -360;
  52. printf("电流超前电压:%f\n " ,a);
  53. }
  54. }

 

文章来源: handsome-man.blog.csdn.net,作者:不脱发的程序猿,版权归原作者所有,如需转载,请联系作者。

原文链接:handsome-man.blog.csdn.net/article/details/112849689

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。