-
1 HLW8032能耗采集數據
有效電壓、有效電流、有效功率、1°電所需脈沖、上電記錄的脈沖、已用電量
-
2 HLW8032的UART通訊接口
HLW8032 具有一個簡單的 UART 接口,采用異步串行通訊方式,允許用兩個單向引腳進行
數據通訊。UART 接口只需要一個低成本光電藕合器,就可以實現隔離通信。UART 接口以 4800
bps 的固定頻率工作,發送數據的間隔時間是 50mS,適合低速設計。
HLW8032 的 UART 使用兩個引腳,TX 引腳用於從 HLW8032 發送數據,數據以低位(LSB)優
先發送,RX 引腳用於來接收來自微控制器的數據。
-
3 數據的計算
-
4 串口數據處理代碼
.cpp部分

1 #include "HLW8032.h" 2 3 HLW8032::HLW8032() 4 { 5 } 6 7 void HLW8032::begin(HardwareSerial &SerialData, byte IO) //此處IO是供電使能 8 { 9 _IO = IO; 10 pinMode(_IO, OUTPUT); 11 digitalWrite(_IO, LOW); 12 delay(10); 13 SerialID = &SerialData; 14 SerialID->begin(4800, SERIAL_8E1); //指定4800波特率,偶校驗 符號為->指針調用 15 //while(SerialID->read()>= 0){} 16 digitalWrite(_IO, HIGH); 17 18 setVF(1.88); 19 setCF(1); 20 // VF = VolR1 / VolR2; //求電壓系數 21 // CF = 1.0 / (CurrentRF * 1000.0); //計算電流系數 22 } 23 24 //寫入電壓系數,輸入值為電壓值,計算后得到修正值 25 void HLW8032::setVF(float Data) 26 { 27 VF = Data; 28 } 29 30 //寫入電流系數 31 void HLW8032::setCF(float Data) 32 { 33 CF = Data; 34 } 35 36 void HLW8032::SerialReadLoop() 37 { 38 if (SerialID->available() > 0) //檢查串口是否有數據,並且緩沖區是否可用 39 { 40 delay(55); 41 SeriaDataLen = SerialID->available(); 42 43 if (SeriaDataLen != 24) 44 { 45 while (SerialID->read() >= 0) 46 { 47 } 48 return; 49 } 50 51 for (byte a = 0; a < SeriaDataLen; a++) //獲取所有字節數 52 { 53 SerialTemps[a] = SerialID->read(); 54 } 55 //Serial.println(SerialID->available()); 56 57 /*處理字節*/ 58 59 if (SerialTemps[1] != 0x5A) //標記識別,如果不是就拋棄 60 { 61 while (SerialID->read() >= 0) 62 { 63 } 64 return; 65 } 66 if (Checksum() == false) // 校驗測試,如果錯誤就拋棄 67 { 68 //Serial.println("crc error"); 69 return; 70 } 71 72 //如果通過了以上測試,則說明數據包應該沒問題,獲取其中的數據 73 SerialRead = 1; // 數據包完備標記 74 VolPar = ((uint32_t)SerialTemps[2] << 16) + ((uint32_t)SerialTemps[3] << 8) + SerialTemps[4]; //獲取電壓參數寄存器 75 if (bitRead(SerialTemps[20], 6) == 1) //如果電壓寄存器刷新,則取數據 76 { 77 VolData = ((uint32_t)SerialTemps[5] << 16) + ((uint32_t)SerialTemps[6] << 8) + SerialTemps[7]; //獲取電壓寄存器 78 } 79 CurrentPar = ((uint32_t)SerialTemps[8] << 16) + ((uint32_t)SerialTemps[9] << 8) + SerialTemps[10]; //電流參數 80 if (bitRead(SerialTemps[20], 5) == 1) //如果電流寄存器更新,則取數據 81 { 82 CurrentData = ((uint32_t)SerialTemps[11] << 16) + ((uint32_t)SerialTemps[12] << 8) + SerialTemps[13]; //電流 83 } 84 PowerPar = ((uint32_t)SerialTemps[14] << 16) + ((uint32_t)SerialTemps[15] << 8) + SerialTemps[16]; // 功率參數 85 if (bitRead(SerialTemps[20], 4) == 1) // 如果功率寄存器數據更新,則取數據 86 { 87 PowerData = ((uint32_t)SerialTemps[17] << 16) + ((uint32_t)SerialTemps[18] << 8) + SerialTemps[19]; //功率數據 88 } 89 PF = ((uint32_t)SerialTemps[21] << 8) + SerialTemps[22]; //脈沖數量寄存器 90 91 // 確認 PF進位寄存器是否進位,進位則添加1 92 if (bitRead(SerialTemps[20], 7) == 1) 93 { 94 PFData++; 95 } 96 Active_Volt = GetVol(); 97 Serial.print("Get_Vol: "); 98 Serial.printf("%.2f", Active_Volt); //電壓 99 Serial.println(" V"); 100 101 Active_Current = GetCurrent(); 102 Serial.print("Get_I: "); 103 Serial.printf("%.3f", Active_Current); //電流 104 Serial.println(" A"); 105 106 Active_Power = GetActivePower(); 107 Serial.print("GetActivePower: "); 108 Serial.printf("%.3f", Active_Power); //有效功率 109 Serial.println(" W"); 110 111 PF_One = GetPFOne(); 112 Serial.print("GetPFOne: "); 113 Serial.printf("%d", PF_One); //1°電脈沖數 114 Serial.println(""); 115 116 PF_All = GetPFAll(); 117 Serial.print("GetPFAll:"); 118 Serial.printf("%d", PF_All); //已記錄脈沖 119 Serial.println(""); 120 121 Used_KWh = GetKWh(); 122 Serial.print("GetKWh: "); 123 Serial.printf("%.5f", Used_KWh); 124 Serial.println(" KW/h"); 125 } 126 } 127 128 // 獲取電壓 129 float HLW8032::GetVol() 130 { 131 float Vol = GetVolAnalog() * VF; //求電壓有效值 132 return Vol; 133 } 134 135 //獲取電壓ADC值 136 float HLW8032::GetVolAnalog() 137 { 138 float FVolPar = VolPar; // float 計算 139 float Vol = FVolPar / VolData; 140 return Vol; //返回廠商修正過的ADC電壓值 141 } 142 143 //獲取有效電流 144 float HLW8032::GetCurrent() 145 { 146 float Current = GetCurrentAnalog() * CF; //計算有效電流 147 return Current; 148 } 149 150 //獲取電流廠商修正adc原始值 151 float HLW8032::GetCurrentAnalog() 152 { 153 float FCurrentPar = CurrentPar; 154 float Current = FCurrentPar / (float)CurrentData; 155 return Current; 156 //return CurrentData; 157 } 158 159 //計算有功功率 160 float HLW8032::GetActivePower() 161 { 162 float FPowerPar = PowerPar; 163 float FPowerData = PowerData; 164 //float Power = ((float)PowerPar/(float)PowerData) * VF * CF; // 求有功功率 165 float Power = FPowerPar / FPowerData * VF * CF; // 求有功功率 166 return Power; 167 } 168 169 //計算視在功率 170 float HLW8032::GetInspectingPower() 171 { 172 float vol = GetVol(); 173 float current = GetCurrent(); 174 return vol * current; 175 } 176 177 //計算功率因數 178 float HLW8032::GetPowerFactor() 179 { 180 float ActivePower = GetActivePower(); //獲取有功功率 181 float InspectingPower = GetInspectingPower(); //視在功率 182 return ActivePower / InspectingPower; 183 } 184 185 //獲取脈沖計數器值 186 uint16_t HLW8032::GetPF() 187 { 188 return PF; 189 } 190 191 //獲取總脈沖數 192 uint32_t HLW8032::GetPFAll() 193 { 194 return PFData * PF; 195 } 196 197 //1°電所需的脈沖數 198 uint32_t HLW8032::GetPFOne() 199 { 200 PFone = 3600000000000 / PowerPar / 1.88; 201 return PFone; 202 } 203 204 //獲取累積電量 205 float HLW8032::GetKWh() 206 { 207 // float InspectingPower = GetInspectingPower(); //視在功率 208 // uint32_t PFcnt = (1 / PowerPar) * (1 / InspectingPower) * 1000000000 * 3600; //一度電的脈沖數量 209 // float KWh = (PFData * PF) / PFcnt; //總脈沖除以1度電的脈沖量 210 // return KWh; 211 KWh = GetPFAll() / (float)PFone; //整型除法轉換成浮點型,否則為0.0000000000 212 return KWh; 213 } 214 215 //校驗測試 216 bool HLW8032::Checksum() 217 { 218 byte check = 0; 219 for (byte a = 2; a <= 22; a++) 220 { 221 check = check + SerialTemps[a]; 222 } 223 if (check == SerialTemps[23]) 224 { 225 //校驗通過 226 return true; 227 } 228 else 229 { 230 return false; //校驗不通過 231 } 232 }
.h部分

1 #ifndef HLW8032_h 2 #define HLW8032_h 3 4 #if ARDUINO >= 100 5 #include "Arduino.h" 6 #else 7 #include "WProgram.h" 8 #endif 9 10 class HLW8032 11 { 12 public: 13 HLW8032(); 14 void begin(HardwareSerial &SerialData, byte IO); 15 void setVF(float Data); //寫入電壓系數 16 void setCF(float Data); //寫入電流系數 17 void SerialReadLoop(); //串口循環業務 獲取數據,並且解碼數據 18 float GetVol(); // 獲取電壓 19 float GetVolAnalog(); // 獲取電壓原始ADC值 20 float GetCurrent(); //獲取電流 21 float GetCurrentAnalog(); //獲取電流原始ADC值 22 float GetActivePower(); //獲取有功功率 23 float GetInspectingPower(); //獲取視在功率 24 float GetPowerFactor(); //獲取功率因數 25 uint16_t GetPF(); //獲取電脈沖計數器 26 uint32_t GetPFAll(); //獲取總脈沖數 27 uint32_t GetPFOne(); //獲取總脈沖數 28 float GetKWh(); // 獲取累積電量 29 30 byte SerialTemps[25]; //串口緩沖區 31 byte SeriaDataLen = 0; //數據長度計數器 32 bool SerialRead = 0; //串口數據OK標記 33 34 uint32_t VolPar; //電壓參數 35 uint32_t CurrentPar; //電流參數 36 uint32_t PowerPar; //功率參數 37 uint32_t CurrentData; //電流數據 38 float VF; //電壓系數 39 float CF; //電流系數 40 int PFone; //1°電用的脈沖數(一定要另外算的,不可調用函數) 41 float KWh; //已用電量(一定要另外算的,不可調用函數) 42 43 float Active_Volt; //存有效電壓 44 float Active_Current; //存有效電流 45 float Active_Power; //存有效功率 46 uint32_t PF_One; //存1°電需要的脈沖數 47 uint32_t PF_All; //上電開始記錄的脈沖數 48 float Used_KWh; //存已使用的電量 49 50 private: 51 bool Checksum(); //校驗函數 52 53 byte _IO; 54 HardwareSerial *SerialID; 55 uint8_t SysStatus; //系統狀態寄存器 56 57 uint32_t VolData; //電壓數據 58 59 uint32_t PowerData; //功率數據 60 uint16_t PF; //脈沖計數器 61 uint32_t PFData = 1; //脈沖溢出計數器 62 uint32_t VolR1 = 1880000; //電壓電阻1 470K*4 1880K 63 uint32_t VolR2 = 1000; //電壓電阻2 1K 64 float CurrentRF = 0.1; // 電流采樣電阻 0.1 歐姆 65 }; 66 67 #endif
-
5 串口打印(此部分已在HLW8032.cpp里面)
PS:各種數據我都已經存儲,需要哪個就直接調用
1 float Active_Volt; //存有效電壓 2 float Active_Current; //存有效電流 3 float Active_Power; //存有效功率 4 uint32_t PF_One; //存1°電需要的脈沖數 5 uint32_t PF_All; //上電開始記錄的脈沖數 6 float Used_KWh; //存已使用的電量