HLW8112芯片软件实现代码(14)
接前一篇文章HLW8112芯片软件实现代码13二、寄存器介绍2. 详述2HLW8112_Measure函数上一回继续讲解HLW8112_Measure函数讲解了第3段代码。本回继续往下进行解析。为了便于理解和回顾再次贴出HLW8112_Measure函数代码在HARDWARE\HLW8112-SPI\HLW8112-SPI.c中如下/* * Function : void HLW8012_Measure(void); * Describe : * Input : none * Output : none * Return : none * Record : 2018/05/10 */ void HLW8112_Measure(void) { Read_HLW8112_PA_I(); Read_HLW8112_U(); Read_HLW8112_PA(); Read_HLW8112_EA(); Read_HLW8112_PB_I(); Read_HLW8112_PB(); Read_HLW8112_EB(); Read_HLW8112_DC_Offset(); printf(直流参数测量-SPI\r\n); printf(A通道电能参数\r\n); printf(U32_AC_V %f\r\n, U32_AC_V); //电压 printf(U32_AC_I %f\r\n, U32_AC_I); //A通道电流 printf(U32_AC_P %f\r\n, U32_AC_P); //A通道功率 printf(U32_AC_E %f\r\n, U32_AC_E); //A通道电量 printf(B通道电能参数\r\n); printf(U32_AC_V %f\r\n, U32_AC_V); //电压 printf(U32_AC_I_B %f\r\n, U32_AC_I_B); //B通道电流 printf(U32_AC_P_B %f\r\n, U32_AC_P_B); //B通道功率 printf(U32_AC_E_B %f\r\n, U32_AC_E_B); //B通道电量 printf(\r\n\r\n); //插入换行 printf(寄存器数值\r\n); printf(U16_RMSIA_Offset %x\r\n, U16_RMSIA_Offset); printf(U16_RMSIB_Offset %x\r\n, U16_RMSIB_Offset); printf(U16_PAOS_Offset %x\r\n, U16_PAOS_Offset); printf(U16_PBOS_Offset %x\r\n, U16_PBOS_Offset); printf(U32_RMSIA_RegData %x\r\n, U32_RMSIA_RegData); printf(U32_RMSIB_RegData %x\r\n, U32_RMSIB_RegData); printf(U32_RMSU_RegData %x\r\n, U32_RMSU_RegData); printf(U32_POWERPA_RegData %x\r\n, U32_POWERPA_RegData); printf(U32_POWERPB_RegData %x\r\n, U32_POWERPB_RegData); printf(\r\n\r\n); //插入换行 }4Read_HLW8112_EA函数Read_HLW8112_EA函数也在HLW8112-SPI.c中代码如下/* * Function : void void Read_HLW8112_EA(void) * Describe : 读取A通道有功电量 * Input : none * Output : none * Return : none * Record : 2018/05/09 */ void Read_HLW8112_EA(void) { //因为掉电数据不保存所以系统上电后应读出存在EEPROM内的电量数据总电量 EEPROM内电量数据此次计算的电量 //功率计算公式 (U32_ENERGY_PA_RegData * U16_EnergyAC_RegData * HFConst) / (电流系数*电压系数*2^29*2^12)HFConst(默认值1000H 2^12) float a; U32_ENERGY_PA_RegData Read_HLW8112_RegData(REG_ENERGY_PA_ADDR, 3); //读取电量寄存器值 a (float)U32_ENERGY_PA_RegData; a a * U16_EnergyAC_RegData; a a / 0x20000000; a a / 1; //DEMO板的电流系数 1 a a / 1; // DEMO板的电压系数 1 a a * D_CAL_A_E; //直流测量需要校正D_CAL_A_E是校正系数默认是1 U32_AC_E a; //电量单位是0.001KWH比如算出来是2.002表示2.002KWH if (U32_AC_E 1) //每读到0.001度电就清零 { U32_AC_BACKUP_E U32_AC_E; //IO_HLW8112_SDI LOW; HLW8112_WriteREG_EN(); //打开写8112 Reg //清零REG_ENERGY_PA_ADDR寄存器 IO_HLW8112_CS LOW; HLW8112_SPI_WriteReg(REG_EMUCON2_ADDR); HLW8112_SPI_WriteByte(0x03); //电量寄存器读后清零 HLW8112_SPI_WriteByte(0xff); IO_HLW8112_CS HIGH; U32_ENERGY_PA_RegData Read_HLW8112_RegData(REG_ENERGY_PA_ADDR, 3); //读后清零 U32_ENERGY_PA_RegData Read_HLW8112_RegData(REG_ENERGY_PA_ADDR, 3); //读后清零 U32_AC_E 0; //每读到0.001度电就清零然后再设置读后不清零 IO_HLW8112_CS LOW; HLW8112_SPI_WriteReg(REG_EMUCON2_ADDR); HLW8112_SPI_WriteByte(0x0b); //电量寄存器B读后不清零 HLW8112_SPI_WriteByte(0xff); IO_HLW8112_CS HIGH; HLW8112_WriteREG_DIS(); //关闭写8112 Reg } }代码中U32_ENERGY_PA_RegData 是同文件中的全局变量 保存的是A通道有功电能寄存器的值。unsigned long U32_ENERGY_PA_RegData; //A通道有功电能量寄存器值REG_ENERGY_PA_ADDR宏也在HLW8110.h中定义如下#define REG_ENERGY_PA_ADDR 0x28REG_ENERGY_PA_ADDR对应的是通道A有功电能寄存器Energy_PA。通道A有功电能寄存器Energy_PA的详情如下读取了通道A有功电能值之后保存到U32_ENERGY_PA_RegData变量中。这里注意对于电能来说就没有补码一说了。接下来的一系列计算a a * U16_EnergyAC_RegData; a a / 0x20000000; a a / 1; //DEMO板的电流系数 1 a a / 1; // DEMO板的电压系数 1 a a * D_CAL_A_E; //直流测量需要校正D_CAL_A_E是校正系数默认是1就是按照芯片手册中的计算公式进行的计算代码中的第1行a a * U16_EnergyAC_RegData;相当于公式中的EnergyPA * EnergyPAC。代码中的第2行a a / 0x20000000;相当于公式中的EnergyPA * EnergyPAC / 2^29。代码中的第3行a a / 1; //DEMO板的电流系数 1相当于公式中的EnergyPA * EnergyPAC / (2^29 * K1)。K1的值前文书讲过了视具体的情况而定对于官方Demo来说是1。代码中的第4行a a / 1; // DEMO板的电压系数 1相当于公式中的EnergyPA * EnergyPAC / (2^29 * K1 * K2)。K2的值前文书讲过了视具体的情况而定对于官方Demo来说是1。代码中的第5行a a * D_CAL_A_E; //直流测量需要校正D_CAL_A_E是校正系数默认是1是再通过功率校正系数进行校正。一般该系数取1就好。看到这有人包括笔者自己会问了上边公式中还有2项没计算进来啊其实HFconst的值是在寄存中设置的参见手册以下内容可见由于代码中并未对HFConst寄存进行设置因此HFconst的默认值就是1000h即4096。因此两相抵消了。如果不是默认值1000h则需要考虑这两个因素了。接下来来到以下代码片段U32_AC_E a; //电量单位是0.001KWH比如算出来是2.002表示2.002KWH if (U32_AC_E 1) //每读到0.001度电就清零 { U32_AC_BACKUP_E U32_AC_E; //IO_HLW8112_SDI LOW; HLW8112_WriteREG_EN(); //打开写8112 Reg //清零REG_ENERGY_PA_ADDR寄存器 IO_HLW8112_CS LOW; HLW8112_SPI_WriteReg(REG_EMUCON2_ADDR); HLW8112_SPI_WriteByte(0x03); //电量寄存器读后清零 HLW8112_SPI_WriteByte(0xff); IO_HLW8112_CS HIGH; U32_ENERGY_PA_RegData Read_HLW8112_RegData(REG_ENERGY_PA_ADDR, 3); //读后清零 U32_ENERGY_PA_RegData Read_HLW8112_RegData(REG_ENERGY_PA_ADDR, 3); //读后清零 U32_AC_E 0; //每读到0.001度电就清零然后再设置读后不清零 IO_HLW8112_CS LOW; HLW8112_SPI_WriteReg(REG_EMUCON2_ADDR); HLW8112_SPI_WriteByte(0x0b); //电量寄存器B读后不清零 HLW8112_SPI_WriteByte(0xff); IO_HLW8112_CS HIGH; HLW8112_WriteREG_DIS(); //关闭写8112 Reg }这段代码的注释感觉有问题。手册中讲的是电量计算出的单位是KW*h度而注释中说的是0.001KWH。应该还是以手册为准才对。那么这段代码的意思是就是当电能大于1度的时候就设置EMUCON2计量控制寄存器2让EPA_CA和EPB_CB都在读后清零。然后读取电能寄存器使得电量寄存器A和B都清零。然后再设置电能寄存器B在读后不清零而电能寄存器A在读后清零。其实这里注释也不对按照代码来理解应该是一开始初始化时设置的是电量寄存器A和B读后都不清零一旦读到了1度电后就将电量寄存器A的累计值保存在U32_AC_BACKUP_E中之后每次读都清零。而B通道则读后不清零。笔者不理解为何不能直接设置两个都到A和B的电能寄存器直接都设置成读后也不清零。这一点留待后续验证吧。下一回继续解析HLW8112_Measure函数中的后续函数。