ACS37800 library for Arduino
Loading...
Searching...
No Matches
ACS37800.h
Go to the documentation of this file.
1// Copyright (C) Pololu Corporation. See LICENSE.txt for details.
2
10
11#pragma once
12
13#include <Arduino.h>
14#include <Wire.h>
15
17{
18public:
23 ACS37800(uint8_t address = 0x60, TwoWire * bus = &Wire)
24 : bus(bus), address(address) {}
25
33 void setBus(TwoWire * bus)
34 {
35 this->bus = bus;
36 }
37
40 TwoWire * getBus()
41 {
42 return this->bus;
43 }
44
49 void setAddress(uint8_t address)
50 {
51 this->address = address;
52 }
53
55 uint8_t getAddress()
56 {
57 return address;
58 }
59
62 uint8_t getLastError()
63 {
64 return lastError;
65 }
66
74 void setBoardPololu(uint8_t rsense_kohm)
75 {
76 icodesMult = 17873;
77 icodesShift = 14;
78 switch (rsense_kohm)
79 {
80 case 1:
81 vcodesMult = 18623;
82 vcodesShift = 9;
83 pinstantMult = 1299;
84 pinstantShift = 0;
85 break;
86 case 2:
87 vcodesMult = 18627;
88 vcodesShift = 10;
89 pinstantMult = 10395;
90 pinstantShift = 4;
91 break;
92 default:
93 case 4:
94 vcodesMult = 18637;
95 vcodesShift = 11;
96 pinstantMult = 325;
97 pinstantShift = 0;
98 break;
99 }
100 }
101
120 void setBoardParameters(uint8_t isense_range, uint32_t riso, uint32_t rsense)
121 {
122 calculateApproximation(riso + rsense, 110 * rsense,
123 vcodesMult, vcodesShift);
124 calculateApproximation(2 * isense_range, 55,
125 icodesMult, icodesShift);
126 calculateApproximation(
127 (uint64_t)isense_range * (riso + rsense) * 5, rsense * 462,
128 pinstantMult, pinstantShift);
129 }
130
136 {
137 writeReg(0x2F, 0x4F70656E); // write ACCESS_CODE
138 }
139
148 void setSampleCount(uint16_t count)
149 {
151 if (getLastError()) { return; }
152
153 uint32_t reg = readReg(0x1F);
154 if (getLastError()) { return; }
155
156 if (count > 1023) { count = 1023; }
157
158 // Clear N and BYPASS_N_EN, then set them if necessary.
159 reg &= 0xFE003FFF;
160 if (count) { reg |= ((uint32_t)1 << 24) | ((uint32_t)count << 14); }
161
162 writeReg(0x1F, reg);
163 }
164
169 {
170 uint32_t reg = readReg(0x20);
171 uint16_t vrms = (uint16_t)reg;
172 uint16_t irms = (uint16_t)(reg >> 16);
173 rmsVoltageMillivolts = (int32_t)vrms * vcodesMult >> vcodesShift >> 1;
174 rmsCurrentMilliamps = (int32_t)irms * icodesMult >> icodesShift >> 1;
175 }
176
181 {
182 uint32_t reg = readReg(0x21);
183 int16_t pactive = (int16_t)reg;
184 uint16_t pimag = (uint16_t)(reg >> 16);
185 activePowerMilliwatts = (int32_t)pactive * pinstantMult >> pinstantShift;
186 reactivePowerMilliwatts = (int32_t)pimag * pinstantMult >> pinstantShift >> 1;
187 }
188
191 {
192 // Note: maybe this function should also store the power factor and
193 // other things in register 0x22.
194 uint32_t reg = readReg(0x22);
195 uint16_t papparent = (uint16_t)reg;
196 apparentPowerMilliwatts = (int32_t)papparent * pinstantMult >> pinstantShift >> 1;
197 return apparentPowerMilliwatts;
198 }
199
204 {
205 uint32_t reg = readReg(0x2A);
206 int16_t vcodes = (int16_t)reg;
207 int16_t icodes = (int16_t)(reg >> 16);
208 instVoltageMillivolts = (int32_t)vcodes * vcodesMult >> vcodesShift;
209 instCurrentMilliamps = (int32_t)icodes * icodesMult >> icodesShift;
210 }
211
215 {
216 int16_t pinstant = (int16_t)readReg(0x2C);
217 instPowerMilliwatts = (int32_t)pinstant * pinstantMult >> pinstantShift;
218 return instPowerMilliwatts;
219 }
220
227 {
229 return rmsVoltageMillivolts;
230 }
231
238 {
240 return rmsCurrentMilliamps;
241 }
242
249 {
251 return activePowerMilliwatts;
252 }
253
260 {
262 return reactivePowerMilliwatts;
263 }
264
271 {
273 return instVoltageMillivolts;
274 }
275
282 {
284 return instCurrentMilliamps;
285 }
286
294 void writeEepromI2CAddress(uint8_t address)
295 {
297 if (getLastError()) { return; }
298 uint32_t reg = readReg(0x0F);
299 if (getLastError()) { return; }
300 reg = (reg & ~(uint32_t)0x3FC) | (1 << 9) | ((address & 0x7F) << 2);
301 writeReg(0x0F, reg);
302 }
303
305 uint32_t readReg(uint8_t reg)
306 {
307 bus->beginTransmission(address);
308 bus->write(reg);
309 lastError = bus->endTransmission();
310 if (getLastError()) { return 0; }
311
312 uint8_t byteCount = bus->requestFrom(address, (uint8_t)4);
313 if (byteCount != 4)
314 {
315 lastError = 50;
316 return 0;
317 }
318
319 uint32_t value = bus->read();
320 value |= (uint32_t)bus->read() << 8;
321 value |= (uint32_t)bus->read() << 16;
322 value |= (uint32_t)bus->read() << 24;
323 return value;
324 }
325
327 void writeReg(uint8_t reg, uint32_t value)
328 {
329 bus->beginTransmission(address);
330 bus->write(reg);
331 bus->write(value & 0xFF);
332 bus->write(value >> 8 & 0xFF);
333 bus->write(value >> 16 & 0xFF);
334 bus->write(value >> 24 & 0xFF);
335 lastError = bus->endTransmission();
336 }
337
338 uint16_t vcodesMult = 1, icodesMult = 1, pinstantMult = 1;
339 uint8_t vcodesShift = 0, icodesShift = 0, pinstantShift = 0;
340
341 int32_t instVoltageMillivolts;
342 int32_t instCurrentMilliamps;
343 int32_t instPowerMilliwatts;
344
345 int32_t rmsVoltageMillivolts;
346 int32_t rmsCurrentMilliamps;
347 int32_t activePowerMilliwatts;
348 int32_t reactivePowerMilliwatts;
349 int32_t apparentPowerMilliwatts;
350
351private:
352
353 // Calculates an approximation for (x * numerator / denominator), where
354 // x is an int16_t or uint16_t, of the form ((int32_t)x * mult >> shift).
355 static void calculateApproximation(
356 uint64_t numerator, uint64_t denominator,
357 uint16_t & outputMult, uint8_t & outputShift)
358 {
359 float k = (float)numerator / denominator;
360 uint16_t mult = 0;
361 uint8_t shift = 0;
362 for (uint8_t shift_candidate = 0; shift_candidate < 32; shift_candidate++)
363 {
364 uint32_t mult_candidate = round(k * ((uint32_t)1 << shift_candidate));
365 if (mult_candidate > 0x7FFF) { break; }
366 mult = mult_candidate;
367 shift = shift_candidate;
368 }
369 while ((mult & 1) == 0)
370 {
371 mult >>= 1;
372 shift--;
373 }
374 outputMult = mult;
375 outputShift = shift;
376 }
377
378 TwoWire * bus;
379 uint8_t address;
380
381 uint8_t lastError = 0;
382};
int32_t readRMSVoltageMillivolts()
Definition ACS37800.h:226
uint8_t getAddress()
Returns the 7-bit I2C address that this object is configured to use.
Definition ACS37800.h:55
int32_t readInstCurrentMilliamps()
Definition ACS37800.h:281
void readActiveAndReactivePower()
Definition ACS37800.h:180
int32_t readApparentPowerMilliwatts()
Reads the apparent power from the sensor and returns it in mW.
Definition ACS37800.h:190
void setAddress(uint8_t address)
Definition ACS37800.h:49
int32_t readReactivePowerMilliwatts()
Definition ACS37800.h:259
void writeReg(uint8_t reg, uint32_t value)
Writes to a sensor register.
Definition ACS37800.h:327
void setBoardParameters(uint8_t isense_range, uint32_t riso, uint32_t rsense)
Definition ACS37800.h:120
void readInstVoltageAndCurrent()
Definition ACS37800.h:203
TwoWire * getBus()
Definition ACS37800.h:40
int32_t readInstVoltageMillivolts()
Definition ACS37800.h:270
void readRMSVoltageAndCurrent()
Definition ACS37800.h:168
void writeEepromI2CAddress(uint8_t address)
Definition ACS37800.h:294
int32_t readInstPowerMilliwatts()
Definition ACS37800.h:214
void setSampleCount(uint16_t count)
Definition ACS37800.h:148
ACS37800(uint8_t address=0x60, TwoWire *bus=&Wire)
Definition ACS37800.h:23
uint8_t getLastError()
Definition ACS37800.h:62
void enableWriteAccess()
Definition ACS37800.h:135
int32_t readRMSCurrentMilliamps()
Definition ACS37800.h:237
void setBus(TwoWire *bus)
Definition ACS37800.h:33
void setBoardPololu(uint8_t rsense_kohm)
Definition ACS37800.h:74
uint32_t readReg(uint8_t reg)
Reads a sensor register and returns its value.
Definition ACS37800.h:305
int32_t readActivePowerMilliwatts()
Definition ACS37800.h:248