接前一篇文章HLW8112芯片软件实现代码10二、寄存器介绍2. 详述上一回终于解析完了Init_HLW8112函数。本回开始讲解官方例程后续内容。其实一上来直接先讲了Init_HLW8112函数并不太好应该先讲解官方例程的主函数及整体流程。不过没关系现在来补上这一部分内容也不为迟晚。官方例程的主文件是2-参考代码-DC直流测量\stm32-codetest\USER\test.c该文件的完整内容如下#include sys.h #include usart.h #include delay.h #include led.h #include beep.h #include key.h #include timer.h #include HLW8110.h #include test.h extern unsigned char B_ReadData_HLW8110; int main(void) { //u8 key; // u16 t; // u16 len; // u16 times0; Stm32_Clock_Init(9); //系统时钟设置 //uart_init(72,115200); //72M,115200bps,串口1设置与PCB通讯 uart_init(36,115200); // PCLK1--不分频 36M delay_init(72); //延时初始化 LED_Init(); //初始化与LED连接的硬件接口 TIM3_Int_Init(4999,7199);//10Khz的计数频率计数5K次为500ms,定时为500ms #if HLW8110 uart2_init(18,9600); //36M最大36M9600偶校验串口2设置与8110通讯PCLK1--2分频18M Init_HLW8110(); B_ReadData_HLW8110 0; #endif #if HLW8112 Init_HLW8112(); B_ReadData_HLW8110 0; #endif while(1) { //每3HZ读取一次HLW8110芯片内的寄存器数据,每500ms读取一次数据 //读取数据的频率视 #if HLW8110 if ( B_ReadData_HLW8110 1 ) { Calculate_HLW8110_MeterData(); B_ReadData_HLW8110 0; } #endif #if HLW8112 if ( B_ReadData_HLW8110 1 ) { B_ReadData_HLW8110 0; HLW8112_Measure(); } #endif // LED0!LED0; // delay_ms(200); // if(USART_RX_STA0x8000) // { // lenUSART_RX_STA0x3FFF;//得到此次接收到的数据长度 // printf(\r\n您发送的消息为:\r\n\r\n); // for(t0;tlen;t) // { // USART1-DRUSART_RX_BUF[t]; // while((USART1-SR0X40)0);//等待发送结束 // } // printf(\r\n\r\n);//插入换行 // USART_RX_STA0; // }else // { // times; // if(times%50000) // { // printf(\r\n精英STM32F103开发板 串口实验\r\n); // printf(正点原子ALIENTEK\r\n\r\n); // } // if(times%2000)printf(请输入数据,以回车键结束\r\n); // if(times%300)LED0!LED0;//闪烁LED,提示系统正在运行. // delay_ms(10); // } } }可以看到test.c文件代码满打满算不到100行还是比较简单和易于理解的。下边笔者给出整理后的主函数main代码如下int main(void) { Stm32_Clock_Init(9); //系统时钟设置 //uart_init(72, 115200); //72M, 115200bps, 串口1设置与PCB通讯 uart_init(36, 115200); //PCLK1--不分频 36M delay_init(72); //延时初始化 LED_Init(); //初始化与LED连接的硬件接口 TIM3_Int_Init(4999, 7199); //10KHz的计数频率计数5K次为500ms定时为500ms #if HLW8110 uart2_init(18,9600); //36M最大36M9600偶校验串口2设置与8110通讯PCLK1--2分频18M Init_HLW8110(); B_ReadData_HLW8110 0; #endif #if HLW8112 Init_HLW8112(); B_ReadData_HLW8110 0; #endif while (1) { //每3HZ读取一次HLW8110芯片内的寄存器数据每500ms读取一次数据 //读取数据的频率视 #if HLW8110 if (B_ReadData_HLW8110 1) { Calculate_HLW8110_MeterData(); B_ReadData_HLW8110 0; } #endif #if HLW8112 if (B_ReadData_HLW8110 1) { B_ReadData_HLW8110 0; HLW8112_Measure(); } #endif } }进一步地忽略HLW8110的代码只看HLW8112的代码那么就是​int main(void) { Stm32_Clock_Init(9); //系统时钟设置 //uart_init(72, 115200); //72M, 115200bps, 串口1设置与PCB通讯 uart_init(36, 115200); //PCLK1--不分频 36M delay_init(72); //延时初始化 LED_Init(); //初始化与LED连接的硬件接口 TIM3_Int_Init(4999, 7199); //10KHz的计数频率计数5K次为500ms定时为500ms Init_HLW8112(); B_ReadData_HLW8110 0; while (1) { //每3HZ读取一次HLW8110芯片内的寄存器数据每500ms读取一次数据 //读取数据的频率视 if (B_ReadData_HLW8110 1) { B_ReadData_HLW8110 0; HLW8112_Measure(); } } }这就很清楚了做一些系统及外设的初始化包括Init_HLW8112()即HLW8112的初始化之后每隔500毫秒调用一次HLW8112_Measure()获取一次电量数据。初始化阶段的Init_HLW8112函数已经解析过了本回开始重点来看HLW8112_Measure函数。2HLW8112_Measure函数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); //插入换行 }HLW8112_Measure函数也很好理解就是依次调用Read_HLW8112_PA_I()、Read_HLW8112_U()、Read_HLW8112_PA()、Read_HLW8112_EA()等函数读取相关寄存器内容之后打印读到的各个数据。下边依次来看一下各个寄存器的具体内容1Read_HLW8112_PA_I()Read_HLW8112_PA_I函数也在HLW8112-SPI.c中代码如下/* * Function : void Read_HLW8112_PA_I(void) * Describe : 读取A通道电流 * Input : none * Output : none * Return : none * Record : 2018/05/09 */ void Read_HLW8112_PA_I(void) { //计算公式U16_AC_I (U32_RMSIA_RegData * U16_RMSIAC_RegData)/(A通道电流系数* 2^23 float a; unsigned long b; U32_RMSIA_RegData Read_HLW8112_RegData(REG_RMSIA_ADDR,3); //读取电流寄存器值 if (U32_RMSIA_RegData 0x800000) { b ~U32_RMSIA_RegData; a (float)b; } else { a (float)U32_RMSIA_RegData; } //a (float)U32_RMSIA_RegData; a a * U16_RMSIAC_RegData; a a / 0x800000; //电流计算出来的浮点数单位是mA比如5003.12 a a / 1; //DEMO板A通道电流系数 1 a a / 1000; //转换成整数5003表示电流5003mA a a * D_CAL_A_I; //直流测量需要校正D_CAL_A_I是校正系数默认是1 U32_AC_I a; }代码中U32_RMSIA_RegData是同文件中的全局变量保存的是A通道电流寄存器的值。unsigned long U32_RMSIA_RegData; //A通道电流寄存器值REG_RMSIA_ADDR宏在HLW8110.h中定义如下#define REG_RMSIA_ADDR 0x24REG_RMSIA_ADDR对应的是通道A电流有效值寄存器RmsIA。通道A电流有效值寄存器RmsIA的详情如下读取了通道A电流的有效值之后保存到U32_RMSIA_RegData变量中。接下来判断最高位Bit23是否为1。如果为1则说明是补码需要取绝对值如果为0则是正常值注意这里讲解的是直流测量交流测量另有计算方法。这一段对应上边代码中的以下部分if (U32_RMSIA_RegData 0x800000) { b ~U32_RMSIA_RegData; a (float)b; } else { a (float)U32_RMSIA_RegData; }接下来的一系列计算a a * U16_RMSIAC_RegData; a a / 0x800000; //电流计算出来的浮点数单位是mA比如5003.12 a a / 1; //DEMO板A通道电流系数 1 a a / 1000; //转换成整数5003表示电流5003mA a a * D_CAL_A_I; //直流测量需要校正D_CAL_A_I是校正系数默认是1就是按照芯片手册中的计算公式进行的计算代码中的第1行a a * U16_RMSIAC_RegData;相当于公式中的RmsIA * RmsIAC。代码中的第2行a a / 0x800000; //电流计算出来的浮点数单位是mA比如5003.12相当于公式中的RmsIA * RmsIAC / 2^23。代码中的第3行a a / 1; //DEMO板A通道电流系数 1相当于再除以K1。这里注意K1的值视具体的硬件电路确定。官方Demo板中的K1是1下图红色框中的电流通道采样电阻值自己的板子不一定是1了。代码中的第4行a a / 1000; //转换成整数5003表示电流5003mA是将mA转化为A因为使用上述公式计算出来的电流单位为mA。代码中的第5行a a * D_CAL_A_I; //直流测量需要校正D_CAL_A_I是校正系数默认是1是再通过A通道电流校正系数进行校正。一般该系数取1就好。下一回继续解析HLW8112_Measure函数中的其余函数。