forked from Khaalidi/HLW8032
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathHLW8032.cpp
More file actions
227 lines (174 loc) · 4.93 KB
/
Copy pathHLW8032.cpp
File metadata and controls
227 lines (174 loc) · 4.93 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
/**
* HLW8032.c - source file for energy meter library
* @file HLW8032.c
* @author Habib Ullah
* @date 14-DEC-2024
* @version 1.0
*
* Modified by Cullen Sharp 2024
* Optimizing/Debugging by Derek Hernandez 2025
*
* This is a source file for a library to interact with a HLW8032 energy meter.
*/
#include "HLW8032.h"
HLW8032::HLW8032()
{
// Construction deferred
}
// Utils
void HLW8032::begin(HardwareSerial& SerialData)
{
SerialID = &SerialData;
SerialID->begin(4800,SERIAL_8E1);
_VCoeff = (UpstrR + DwstrR) / DwstrR;
_CCoeff = 1.0 / (ShuntR * 1000.0);
}
void HLW8032::SerialReadLoop()
{
if (SerialID->available()>0)
{
// The HLW8032 transmits data every 50ms
delay(56);
// Get the number of bytes available to read from serial
bytesInRXBuffer = SerialID->available();
// If there aren't enough bytes in the RX buffer
if (bytesInRXBuffer < TRANSMISSION_LENGTH)
{
// Empty the buffer
while(SerialID->read()>= 0){}
return;
}
// Read bytes into an
for (byte a = 0; a < TRANSMISSION_LENGTH; a++)
{
transmission[a] = SerialID->read();
}
// Read the Check Register
if(transmission[1] != 0x5A)
{
while(SerialID->read()>= 0){}
return;
}
if(Checksum() == false)
{
Serial.println("ERROR: (HLW8032): Checksum error");
return;
}
// Raise successful read flag
readSuccess = 1;
/*
HLW8032 transmits data in big endian byte ordering where
High byte -> middle byte -> low byte
To convert to the proper value we apply LSL (i.e. multiply by 2^x)
High byte is multiplied by 2^16 (LSL 16)
Middle byte is multiplied by 2^8 (LSL 8)
Low byte is left unchanged
*/
VoltageParam = ((uint32_t) transmission[2] <<16)
+ ((uint32_t) transmission[3] <<8)
+ transmission[4];
// Check if Voltage Register is done updating
if(bitRead(transmission[20], 6) == 1)
{
VoltageData = ((uint32_t) transmission[5] <<16)
+ ((uint32_t) transmission[6] <<8)
+ transmission[7];
}
CurrentParam = ((uint32_t) transmission[8] <<16)
+ ((uint32_t) transmission[9] <<8)
+ transmission[10];
// Check if Current Register is done updating
if(bitRead(transmission[20], 5) == 1)
{
CurrentData = ((uint32_t) transmission[11] <<16)
+ ((uint32_t) transmission[12] <<8)
+ transmission[13];
}
PowerParam = ((uint32_t) transmission[14] <<16)
+ ((uint32_t) transmission[15] <<8)
+ transmission[16];
// Check if Power Register is done updating
if(bitRead(transmission[20], 4) == 1)
{
PowerData = ((uint32_t) transmission[17] <<16)
+ ((uint32_t) transmission[18] <<8)
+ transmission[19];
}
PF = ((uint16_t) transmission[21] <<8)
+ transmission[22];
// PFdata refers to the number of times that PF has overflow'd
if(bitRead(transmission[20], 7) == 1)
{
PFData++;
}
}
}
bool HLW8032::Checksum()
{
byte check_sum = 0, a = 2;
for (;a <= TRANSMISSION_LENGTH-2; ++a) { check_sum += transmission[a]; }
byte check = transmission[23];
if (check_sum == check) { return true; }
return false;
}
//Check for division by zero, and return 0 if true
float checkDivisionOfZero(float denominator, float numerator)
{
if (denominator == 0){
Serial.println("WARNING: (HLW8032): Division by zero. Set to 0 to avoid errors");
return 0.0;
}
return numerator / denominator;
}
// Setters
void HLW8032::setVCoeff(float VCoeff) { _VCoeff = VCoeff; }
void HLW8032::setCCoeff(float CCoeff) { _CCoeff = CCoeff; }
// Getters
voltage_t HLW8032::GetEffVoltage()
{
float Vol = checkDivisionOfZero(VoltageParam , VoltageData) * _VCoeff;
return Vol;
}
voltage_t HLW8032::GetDividerVoltage()
{
float DividerVoltage = checkDivisionOfZero(VoltageParam , VoltageData);
return DividerVoltage;
}
current_t HLW8032::GetEffCurrent()
{
current_t Current = checkDivisionOfZero(CurrentParam, CurrentData) * _CCoeff;
return Current;
}
current_t HLW8032::GetShuntVoltage()
{
voltage_t ShuntVoltage = checkDivisionOfZero(CurrentParam, CurrentData);
return ShuntVoltage;
}
power_t HLW8032::GetActivePower()
{
power_t Power = checkDivisionOfZero(PowerParam,PowerData) * _VCoeff * _CCoeff;
return Power;
}
power_t HLW8032::GetApparentPower()
{
voltage_t SupplyVoltage = GetEffVoltage();
current_t LoadCurrent = GetEffCurrent();
return SupplyVoltage * LoadCurrent;
}
unitless_t HLW8032::GetPowerFactor()
{
power_t ActivePower = GetActivePower();
power_t ApparentPower = GetApparentPower();
return checkDivisionOfZero(ActivePower, ApparentPower);
}
uint16_t HLW8032::GetPF() { return PF; }
uint32_t HLW8032::GetPFAll() { return PFData * PF; }
energy_t HLW8032::GetKWh()
{
// Calculates the pulse count for one kWh
uint32_t PulseCount = checkDivisionOfZero(1,PowerParam)
* checkDivisionOfZero(1,(_VCoeff * _CCoeff))
* 1000000000 * 3600;
energy_t KWh =checkDivisionOfZero((PFData * PF) , PulseCount);
return KWh;
}