├── README.md └── src ├── ADE7758.h └── ADE7758.cpp /README.md: -------------------------------------------------------------------------------- 1 | ADE7758 2 | ======= 3 | THIS IS NOT FOR BEGINNERS. RISKS of ELECTRICUTION, DAMAGE TO ELECTRONIC DEVICES ATTACHED INCLUDING LAPTOPS are POSSIBLE. 4 | USE at your OWN RISK. 5 | 6 | Arduino Library for ADE7758 7 | 8 | This Library is not a complete ADE7758 library. I just implemented only the functions I used in a certain project. 9 | 10 | Library files are ADE7758Lib.h and ADE7758Lib.cpp. To include the library in your projects, you can #include "ADE7758Lib.h" in you project provided you put the files in your project folder. The library uses SPI at mode1 (CPOL=0 - clock idle is low,CPHA=1- data is read at falling edge of clock). The library results are uncalibrated. What I did to calibrate is to sample on different voltage levels and current levels measured from multimeter and perform a linear regression. Well, an equation given 2 points sometimes is enough. I sampled at 110V, 220V, 230V. I also sampled with different current loads. You can add a calibration function using the methods discussed in the datasheet. 11 | 12 | An Example ino file is included that uses the methods included in the source code. 13 | 14 | You can implement other functions by filling up the empty functions I left in the .cpp file. Just read the datasheet for the algorithm. 15 | 16 | for SCHEMATIC: 17 | 18 | Use at your own RISK. This circuit has been tested by Computer and Electrical Engineering Majors in one of the 230V RMS line-to-line phase of a 3-Phase 60Hz source. This circuit works even if your feed 3 single-phase input as long as you connect the neutral line to the VN. 19 | 20 | Jumpers JP1,2 and 3 are for when you decide to use two-watt meter method (tested). Remove jumpers when you want to use 3 watt-meter method. NEVER TOUCH the board(even the ground plane) when the power is on! 21 | 22 | On each branch in VAP, VBP and VCP, I added a series 1M resistor and a pull down 1K resistor after the 1M. This is a voltage divider to divide the line voltage to LineV*1K/(1K+1M) or approximately LineV/1000 so a 110V line to ground will appear as 110mV in the VAP of the IC. 23 | 24 | For two-watt meter method (please read about this), JP1,2 and 3 is shorted. Connect line Voltage A to VAP header. Line voltage B to VAP in the header connect Line Voltage C to VN header (no need to connect anything to VCP header). Therefore, what you read in AV register is the VAC voltage and BV register is the VBC. In two-watt meter method, you only need two line voltages and the currents running to these lines to solve the over-all power. So connect your current sensor to IA and IB only. 25 | NOTE: Current Sensor you should use is a current transformer. Add a low resistance high power resistor between the two pins of the CT as shunt so that you can read voltage. The current channels in the IC reads voltage. Compensate for the ratio in the program, the resistor and voltage to current conversion based on the resistor (I=V/R) in your program. 26 | Advantage: no need for neutral ground. Disadvantage: some information are not available. 27 | 28 | For three watt meter method just remove tha short in JP1,2 and 3. Connect voltage A, B, C and Neutral lines to VAP,VBP,VCP and VN respectively. connect all line currents to each corresponding current input header. 29 | 30 | Also notice that the ADE is isolated from the SPI header using high speed opto-isolators so that there is less risk of damaging your Arduino and PC. 31 | 32 | Connect to arduino SPI pins you used the SPI header in the schematic. In PCB layout, use separate ground planes for AC and MCU DC sides. THE AC side has AC components, Analog DC and digital DC(DC side of the ADE7758). Use the same ground plane for AC and Analog DC. SO a total of 3 Ground planes. Connect the Analog ground to DC side of the ADE7758 by at a single point. (Read about mixed signal routing). 33 | -------------------------------------------------------------------------------- /src/ADE7758.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef ADE7758_H 3 | #define ADE7758_H 4 | 5 | 6 | 7 | 8 | // Class Atributes 9 | #define AFECS 10 // Chip Select ADE7758 - It is the pin to which the AFE is connected, then I add 8 to make it compatible with digitalwrite 10 | #define WRITE 0x80 // WRITE bit BT7 to write to registers 11 | #define CLKIN 10000000 // ADE7758 frec, 10.000000MHz 12 | #define PERIODO 50 // It is actually frequency, it is used to calculate the amount of Cycles it accumulates for energy. 13 | #define PHASE_A 0 14 | #define PHASE_B 1 15 | #define PHASE_C 2 16 | 17 | 18 | 19 | 20 | //Register address 21 | 22 | //------Name--------Address---------Length 23 | #define AWATTHR 0x01 //---------16 24 | #define BWATTHR 0x02 //---------16 25 | #define CWATTHR 0x03 //---------16 26 | 27 | #define AVARHR 0x04 //---------16 28 | #define BVARHR 0x05 //---------16 29 | #define CVARHR 0x06 //---------16 30 | 31 | #define AVAHR 0x07 //---------16 32 | #define BVAHR 0x08 //---------16 33 | #define CVAHR 0x09 //---------16 34 | 35 | #define AIRMS 0x0A //---------24 36 | #define BIRMS 0x0B //---------24 37 | #define CIRMS 0x0C //---------24 38 | 39 | #define AVRMS 0x0D //---------24 40 | #define BVRMS 0x0E //---------24 41 | #define CVRMS 0x0F //---------24 42 | 43 | #define FREQ 0x10 //---------12 44 | #define TEMP 0x11 //---------8 45 | #define WFORM 0x12 //---------24 46 | #define OPMODE 0x13 //---------8 47 | #define MMODE 0x14 //---------8 48 | #define WAVMODE 0x15 //---------8 49 | #define COMPMODE 0x16 //---------8 50 | #define LCYCMODE 0x17 //---------8 51 | #define MASK 0x18 //---------24 52 | #define STATUS 0x19 //---------24 53 | #define RSTATUS 0x1A //---------24 54 | #define ZXTOUT 0x1B //---------16 55 | #define LINECYC 0x1C //---------16 56 | #define SAGCYC 0x1D //---------8 57 | #define SAGLVL 0x1E //---------8 58 | #define VPINTLVL 0x1F //---------8 59 | #define IPINTLVL 0x20 //---------8 60 | #define VPEAK 0x21 //---------8 61 | #define IPEAK 0x22 //---------8 62 | #define GAIN 0x23 //---------8 63 | #define AVRMSGAIN 0x24 //---------12 64 | #define BVRMSGAIN 0x25 //---------12 65 | #define CVRMSGAIN 0x26 //---------12 66 | #define AIGAIN 0x27 //---------12 67 | #define BIGAIN 0x28 //---------12 68 | #define CIGAIN 0x29 //---------12 69 | #define AWG 0x2A //---------12 70 | #define BWG 0x2B //---------12 71 | #define CWG 0x2C //---------12 72 | #define AVARG 0x2D //---------12 73 | #define BVARG 0x2E //---------12 74 | #define CVARG 0x2F //---------12 75 | #define AVAG 0x30 //---------12 76 | #define BVAG 0X31 //---------12 77 | #define CVAG 0x32 //---------12 78 | #define AVRMSOS 0x33 //---------12 79 | #define BVRMSOS 0X34 //---------12 80 | #define CVRMSOS 0X35 //---------12 81 | #define AIRMSOS 0X36 //---------12 82 | #define BIRMSOS 0X37 //---------12 83 | #define CIRMSOS 0X38 //---------12 84 | #define AWATTOS 0X39 //---------12 85 | #define BWATTOS 0X3A //---------12 86 | #define CWATTOS 0X3B //---------12 87 | #define AVAROS 0X3C //---------12 88 | #define BVAROS 0X3D //---------12 89 | #define CVAROS 0X3E //---------12 90 | #define APHCAL 0X3F //---------7 91 | #define BPHCAL 0X40 //---------7 92 | #define CPHCAL 0X41 //---------7 93 | #define WDIV 0X42 //---------8 94 | #define VARDIV 0X43 //---------8 95 | #define VADIV 0X44 //---------8 96 | #define APCFNUM 0X45 //---------16 97 | #define APCFDEN 0X46 //---------12 98 | #define VARCFNUM 0X47 //---------16 99 | #define VARCFDEN 0X48 //---------12 100 | 101 | #define CHKSUM 0X7E //---------8 102 | #define VERSION 0x7f //---------8 103 | 104 | 105 | //bits 106 | 107 | /** 108 | OPERATIONAL MODE REGISTER (0x13) 109 | The general configuration of the ADE7758 is defined by writing to the OPMODE register. 110 | Table 18 summarizes the functionality of each bit in the OPMODE register. 111 | 112 | Bit Location Bit Mnemonic Default Value Description 113 | 0 DISHPF 0 The HPFs in all current channel inputs are disabled when this bit is set. 114 | 1 DISLPF 0 The LPFs after the watt and VAR multipliers are disabled when this bit is set. 115 | 2 DISCF 1 The frequency outputs APCF and VARCF are disabled when this bit is set. 116 | 3 to 5 DISMOD 0 By setting these bits, ADE7758’s ADCs can be turned off. In normal operation, these bits should be left at Logic 0. 117 | DISMOD[2:0] Description 118 | 0 0 0 Normal operation. 119 | 1 0 0 Redirect the voltage inputs to the signal paths for the current channels and the current inputs to the signal paths for the voltage channels. 120 | 0 0 1 Switch off only the current channel ADCs. 121 | 1 0 1 Switch off current channel ADCs and redirect the current input signals to the voltage channel signal paths. 122 | 0 1 0 Switch off only the voltage channel ADCs. 123 | 1 1 0 Switch off voltage channel ADCs and redirect the voltage input signals to the current channel signal paths. 124 | 0 1 1 Put the ADE7758 in sleep mode. 125 | 1 1 1 Put the ADE7758 in power-down mode (reduces AIDD to 1 mA typ). 126 | 6 SWRST 0 Software Chip Reset. A data transfer to the ADE7758 should not take place for at least 18 μs after a software reset. 127 | 7 RESERVED 0 This should be left at 0. 128 | 129 | */ 130 | 131 | #define DISHPF 0x01 132 | #define DISLPF 0x02 133 | #define DISCF 0x04 134 | #define SWRST 0x40 135 | 136 | /** 137 | MEASUREMENT MODE REGISTER (0x14) 138 | The configuration of the PERIOD and peak measurements made by the ADE7758 is defined by writing to the MMODE register. 139 | Table 19 summarizes the functionality of each bit in the MMODE register. 140 | 141 | Bit Location Bit Mnemonic Default Value Description 142 | 0 to 1 FREQSEL 0 These bits are used to select the source of the measurement of the voltage line frequency. 143 | FREQSEL1 FREQSEL0 Source 144 | 0 0 Phase A 145 | 0 1 Phase B 146 | 1 0 Phase C 147 | 1 1 Reserved 148 | 2 to 4 PEAKSEL 7 These bits select the phases used for the voltage and current peak registers. 149 | Setting Bit 2 switches the IPEAK and VPEAK registers to hold the absolute values 150 | of the largest current and voltage waveform (over a fixed number of half-line cycles) 151 | from Phase A. The number of half-line cycles is determined by the content of the 152 | LINECYC register. At the end of the LINECYC number of half-line cycles, the content 153 | of the registers is replaced with the new peak values. Similarly, setting Bit 3 turns 154 | on the peak detection for Phase B, and Bit 4 for Phase C. Note that if more than one 155 | bit is set, the VPEAK and IPEAK registers can hold values from two different phases, that is, 156 | the voltage and current peak are independently processed (see the Peak Current Detection section). 157 | 5 to 7 PKIRQSEL 7 These bits select the phases used for the peak interrupt detection. 158 | Setting Bit 5 switches on the monitoring of the absolute current and voltage waveform to Phase A. 159 | Similarly, setting Bit 6 turns on the waveform detection for Phase B, and Bit 7 for Phase C. 160 | Note that more than one bit can be set for detection on multiple phases. 161 | If the absolute values of the voltage or current waveform samples in the selected phases exceeds 162 | the preset level specified in the VPINTLVL or IPINTLVL registers the corresponding bit(s) in the 163 | STATUS registers are set (see the Peak Current Detection section). 164 | 165 | */ 166 | 167 | #define FREQSEL0 0x01 168 | #define FREQSEL1 0x02 169 | 170 | 171 | /** 172 | WAVEFORM MODE REGISTER (0x15) 173 | The waveform sampling mode of the ADE7758 is defined by writing to the WAVMODE register. 174 | Table 20 summarizes the functionality of each bit in the WAVMODE register. 175 | 176 | Bit Location Bit Mnemonic Default Value Description 177 | 0 to 1 PHSEL 0 These bits are used to select the phase of the waveform sample. 178 | PHSEL[1:0] Source 179 | 0 0 Phase A 180 | 0 1 Phase B 181 | 1 0 Phase C 182 | 1 1 Reserved 183 | 2 to 4 WAVSEL 0 These bits are used to select the type of waveform. 184 | WAVSEL[2:0] Source 185 | 0 0 0 Current 186 | 0 0 1 Voltage 187 | 0 1 0 Active Power Multiplier Output 188 | 0 1 1 Reactive Power Multiplier Output 189 | 1 0 0 VA Multiplier Output 190 | -Others- Reserved 191 | 5 to 6 DTRT 0 These bits are used to select the data rate. 192 | DTRT[1:0] Update Rate 193 | 0 0 26.04 kSPS (CLKIN/3/128) 194 | 0 1 13.02 kSPS (CLKIN/3/256) 195 | 1 0 6.51 kSPS (CLKIN/3/512) 196 | 1 1 3.25 kSPS (CLKIN/3/1024) 197 | 7 VACF 0 Setting this bit to Logic 1 switches the VARCF output pin to an output 198 | frequency that is proportional to the total apparent power (VA). 199 | In the default state, Logic 0, the VARCF pin outputs a frequency proportional 200 | to the total reactive power (VAR). 201 | */ 202 | 203 | 204 | 205 | /** 206 | COMPUTATIONAL MODE REGISTER (0x16) 207 | The computational method of the ADE7758 is defined by writing to the COMPMODE register. 208 | 209 | Bit Location Bit Mnemonic Default Value Description 210 | 0 to 1 CONSEL 0 These bits are used to select the input to the energy accumulation registers. 211 | CONSEL[1:0] = 11 is reserved. IA, IB, and IC are IA, IB, and IC phase shifted by –90°, respectively. 212 | Registers CONSEL[1, 0] = 00 CONSEL[1, 0] = 01 CONSEL[1, 0] = 10 213 | AWATTHR VA × IA VA × (IA – IB) VA × (IA–IB) 214 | BWATTHR VB × IB 0 0 215 | CWATTHR VC × IC VC × (IC – IB) VC × IC 216 | 217 | AVARHR VA × IA VA × (IA – IB) VA × (IA–IB) 218 | BVARHR VB × IB 0 0 219 | CVARHR VC × IC VC × (IC – IB) VC × IC 220 | 221 | AVAHR VARMS × IARMS VARMS × IARMS VARMS × ARMS 222 | BVAHR VBRMS × IBRMS (VARMS + VCRMS)/2 × IBRMS VARMS × IBRMS 223 | CVAHR VCRMS × ICRMS VCRMS × ICRMS VCRMS × ICRMS 224 | 225 | 2 to 4 TERMSEL 7 These bits are used to select the phases to be included in the APCF and VARCF pulse outputs. 226 | Setting Bit 2 selects Phase A (the inputs to AWATTHR and AVARHR registers) to be included. 227 | Bit 3 and Bit 4 are for Phase B and Phase C, respectively. 228 | Setting all three bits enables the sum of all three phases to be included in the frequency outputs 229 | (see the Active Power Frequency Output and the Reactive Power Frequency Output sections). 230 | 231 | 5 ABS 0 Setting this bit places the APCF output pin in absolute only mode. 232 | Namely, the APCF output frequency is proportional to the sum of the absolute values of the watt-hour 233 | accumulation registers (AWATTHR, BWATTHR, and CWATTHR). 234 | Note that this bit only affects the APCF pin and has no effect on the content of the corresponding 235 | registers. 236 | 237 | 6 SAVAR 0 Setting this bit places the VARCF output pin in the signed adjusted mode. 238 | Namely, the VARCF output frequency is proportional to the sign-adjusted sum of the VAR-hour accumulation 239 | registers (AVARHR, BVARHR, and CVARHR). 240 | The sign of the VAR is determined from the sign of the watt calculation from the corresponding phase, 241 | that is, the sign of the VAR is flipped if the sign of the watt is negative, and if the watt is positive, 242 | there is no change to the sign of the VAR. 243 | Note that this bit only affects the VARCF pin and has no effect on the content of the corresponding 244 | registers. 245 | 246 | 7 NOLOAD 0 Setting this bit activates the no-load threshold in the ADE7758. 247 | */ 248 | 249 | 250 | /** 251 | LINE CYCLE ACCUMULATION MODE REGISTER (0x17) 252 | The functionalities involved the line-cycle accumulation mode in the ADE7758 are defined by writing to the LCYCMODE register. 253 | 254 | Bit Location Bit Mnemonic Default Value Description 255 | 256 | 0 LWATT 0 Setting this bit places the watt-hour accumulation registers 257 | (AWATTHR, BWATTHR, and CWATTHR registers) into line-cycle accumulation mode. 258 | 1 LVAR 0 Setting this bit places the VAR-hour accumulation registers (AVARHR, BVARHR, and CVARHR registers) 259 | into line-cycle accumulation mode. 260 | 2 LVA 0 Setting this bit places the VA-hour accumulation registers (AVAHR, BVAHR, and CVAHR registers) 261 | into line-cycle accumulation mode. 262 | 3 to 5 ZXSEL 7 These bits select the phases used for counting the number of zero crossings in the line-cycle 263 | accumulation mode. Bit 3, Bit 4, and Bit 5 select Phase A, Phase B, and Phase C, respectively. 264 | More than one phase can be selected for the zero-crossing detection, 265 | and the accumulation time is shortened accordingly. 266 | 6 RSTREAD 1 Setting this bit enables the read-with-reset for all the WATTHR, VARHR, and VAHR registers for all three 267 | phases, that is, a read to those registers resets the registers to 0 after the content of the registers 268 | have been read. This bit should be set to Logic 0 when the LWATT, LVAR, or LVA bits are set to Logic 1. 269 | 7 FREQSEL 0 Setting this bit causes the FREQ (0x10) register to display the period, instead of the frequency of the 270 | line input. 271 | */ 272 | 273 | 274 | #define LWATT 0x01 275 | #define LVAR 0x02 276 | #define LVA 0x04 277 | #define ZXSEL_A 0x08 278 | #define ZXSEL_B 0x10 279 | #define ZXSEL_C 0x20 280 | #define RSTREAD 0x40 281 | #define FREQSEL 0x80 282 | 283 | 284 | 285 | /** INTERRUPT MASK REGISTER (0x18) 286 | When an interrupt event occurs in the ADE7758, the IRQ logic output goes active low if the mask bit for this event is Logic 1 in the MASK register. 287 | The IRQ logic output is reset to its default collector open state when the RSTATUS register is read. 288 | describes the function of each bit in the interrupt mask register. 289 | **/ 290 | 291 | // The next table summarizes the function of each bit for 292 | // the Interrupt Enable Register 293 | 294 | /* Bit Mask // Bit Location / Description 295 | #define AEHF 0x0001 // bit 0 - Enables an interrupt when there is a change in Bit 14 of any one of the three WATTHR registers, that is, the WATTHR register is half full. 296 | #define REHF 0x0002 // bit 1 - Enables an interrupt when there is a change in Bit 14 of any one of the three VARHR registers, that is, the VARHR register is half full. 297 | #define VAEHF 0x0004 // bit 2 - Enables an interrupt when there is a 0 to 1 transition in the MSB of any one of the three VAHR registers, that is, the VAHR register is half full. 298 | #define SAGA 0x0008 // bit 3 - Enables an interrupt when there is a SAG on the line voltage of the Phase A. 299 | #define SAGB 0x0010 // bit 4 - Enables an interrupt when there is a SAG on the line voltage of the Phase B. 300 | #define SAGC 0x0020 // bit 5 - Enables an interrupt when there is a SAG on the line voltage of the Phase C. 301 | #define ZXTOA 0x0040 // bit 6 - Enables an interrupt when there is a zero-crossing timeout detection on Phase A. 302 | #define ZXTOB 0x0080 // bit 7 - Enables an interrupt when there is a zero-crossing timeout detection on Phase B. 303 | #define ZXTOC 0x0100 // bit 8 - Enables an interrupt when there is a zero-crossing timeout detection on Phase C. 304 | #define ZXA 0x0200 // bit 9 - Enables an interrupt when there is a zero crossing in the voltage channel of Phase A 305 | #define ZXB 0x0400 // bit 10 - Enables an interrupt when there is a zero crossing in the voltage channel of Phase B 306 | #define ZXC 0x0800 // bit 11 - Enables an interrupt when there is a zero crossing in the voltage channel of Phase C 307 | #define LENERGY 0x1000 // bit 12 - Enables an interrupt when the energy accumulations over LINECYC are finished. 308 | //RESERVED 0x2000 // bit 13 - RESERVED 309 | #define PKV 0x4000 // bit 14 - Enables an interrupt when the voltage input selected in the MMODE register is above the value in the VPINTLVL register. 310 | #define PKI 0x8000 // bit 15 - Enables an interrupt when the current input selected in the MMODE register is above the value in the IPINTLVL register. 311 | #define WFSM 0x010000 // bit 16 - Enables an interrupt when data is present in the WAVEMODE register. 312 | #define REVPAP 0x020000 // bit 17 - Enables an interrupt when there is a sign change in the watt calculation among any one of the phases specified by the TERMSEL bits in the COMPMODE register. 313 | #define REVPRP 0x040000 // bit 18 - Enables an interrupt when there is a sign change in the VAR calculation among any one of the phases specified by the TERMSEL bits in the COMPMODE register. 314 | #define SEQERR 0x080000 // bit 19 - Enables an interrupt when the zero crossing from Phase A is followed not by the zero crossing of Phase C but with that of Phase B. 315 | */ 316 | /** INTERRUPT STATUS REGISTER (0x19)/RESET INTERRUPT STATUS REGISTER (0x1A) 317 | The interrupt status register is used to determine the source of an interrupt event. 318 | When an interrupt event occurs in the ADE7758, the corresponding flag in the interrupt status register is set. 319 | The IRQ pin goes active low if the corresponding bit in the interrupt mask register is set. 320 | When the MCU services the interrupt, it must first carry out a read from the interrupt status register to determine the source of the interrupt. 321 | All the interrupts in the interrupt status register stay at their logic high state after an event occurs. 322 | The state of the interrupt bit in the interrupt status register is reset to its default value once the reset interrupt status register is read. 323 | **/ 324 | 325 | // The next table summarizes the function of each bit for 326 | // the Interrupt Status Register, the Reset Interrupt Status Register. 327 | 328 | // Bit Mask // Bit Location / Description 329 | #define AEHF 0x0001 // bit 0 - Indicates that an interrupt was caused by a change in Bit 14 among any one of the three WATTHR registers, that is, the WATTHR register is half full. 330 | #define REHF 0x0002 // bit 1 - Indicates that an interrupt was caused by a change in Bit 14 among any one of the three VARHR registers, that is, the VARHR register is half full. 331 | #define VAEHF 0x0004 // bit 2 - Indicates that an interrupt was caused by a 0 to 1 transition in Bit 15 among any one of the three VAHR registers, that is, the VAHR register is half full. 332 | #define SAGA 0x0008 // bit 3 - Indicates that an interrupt was caused by a SAG on the line voltage of the Phase A. 333 | #define SAGB 0x0010 // bit 4 - Indicates that an interrupt was caused by a SAG on the line voltage of the Phase B. 334 | #define SAGC 0x0020 // bit 5 - Indicates that an interrupt was caused by a SAG on the line voltage of the Phase C. 335 | #define ZXTOA 0x0040 // bit 6 - Indicates that an interrupt was caused by a missing zero crossing on the line voltage of the Phase A. 336 | #define ZXTOB 0x0080 // bit 7 - Indicates that an interrupt was caused by a missing zero crossing on the line voltage of the Phase B. 337 | #define ZXTOC 0x0100 // bit 8 - Indicates that an interrupt was caused by a missing zero crossing on the line voltage of the Phase C 338 | #define ZXA 0x0200 // bit 9 - Indicates a detection of a rising edge zero crossing in the voltage channel of Phase A. 339 | #define ZXB 0x0400 // bit 10 - Indicates a detection of a rising edge zero crossing in the voltage channel of Phase B 340 | #define ZXC 0x0800 // bit 11 - Indicates a detection of a rising edge zero crossing in the voltage channel of Phase C 341 | #define LENERGY 0x1000 // bit 12 - In line energy accumulation, indicates the end of an integration over an integer number of half- line cycles (LINECYC). See the Calibration section. 342 | #define RESET 0x2000 // bit 13 - Indicates that the 5 V power supply is below 4 V. Enables a software reset of the ADE7758 and sets the registers back to their default values. This bit in the STATUS or RSTATUS register is logic high for only one clock cycle after a reset event. 343 | #define PKV 0x4000 // bit 14 - Indicates that an interrupt was caused when the selected voltage input is above the value in the VPINTLVL register. 344 | #define PKI 0x8000 // bit 15 - Indicates that an interrupt was caused when the selected current input is above the value in the IPINTLVL register. 345 | #define WFSM 0x010000 // bit 16 - Indicates that new data is present in the waveform register. 346 | #define REVPAP 0x020000 // bit 17 - Indicates that an interrupt was caused by a sign change in the watt calculation among any one of the phases specified by the TERMSEL bits in the COMPMODE register. 347 | #define REVPRP 0x040000 // bit 18 - Indicates that an interrupt was caused by a sign change in the VAR calculation among any one of the phases specified by the TERMSEL bits in the COMPMODE register. 348 | #define SEQERR 0x080000 // bit 19 - Indicates that an interrupt was caused by a zero crossing from Phase A followed not by the zero crossing of Phase C but by that of Phase B. 349 | 350 | 351 | 352 | 353 | //constants 354 | #define GAIN_1 0x00 355 | #define GAIN_2 0x01 356 | #define GAIN_4 0x02 357 | #define INTEGRATOR_ON 1 358 | #define INTEGRATOR_OFF 0 359 | #define FULLSCALESELECT_0_5V 0x00 360 | #define FULLSCALESELECT_0_25V 0x01 361 | #define FULLSCALESELECT_0_125V 0x02 362 | 363 | 364 | 365 | class ADE7758 { 366 | public: 367 | 368 | ADE7758(); 369 | void Init(void); 370 | 371 | void setOpMode(char m); 372 | int getOpMode(); 373 | void setMMode(char m); 374 | int getMMode(); 375 | void setWavMode(char m); 376 | int getWavMode(); 377 | void setCompMode(char m); 378 | int getCompMode(); 379 | void setLcycMode(char m); 380 | int getLcycMode(); 381 | void gainSetup(char integrator, char scale, char PGA2, char PGA1); 382 | void setupDivs(unsigned char Watt_div,unsigned char VAR_div,unsigned char VA_div); 383 | long getMaskInterrupts(void); 384 | void setMaskInterrupts(unsigned long m); 385 | unsigned long getStatus(void); 386 | unsigned long resetStatus(void); 387 | long getIRMS(char); 388 | long getVRMS(char); 389 | long getVrms(char); 390 | float irms(char ); 391 | 392 | int GetFrequency(char phase); 393 | void setLineCyc(int d); 394 | 395 | //==========apparent power gain register========== 396 | int getAVAGainregister(); 397 | int getBVAGainregister(); 398 | int getCVAGainregister(); 399 | void setAVAGainregister(int o); 400 | void setBVAGainregister(int o); 401 | void setCVAGainregister(int o); 402 | 403 | //======= active power offset calibration=========== 404 | int getAWATTOS(); 405 | int getBWATTOS(); 406 | int getCWATTOS(); 407 | void setAWATTOS(int o); 408 | void setBWATTOS(int o); 409 | void setCWATTOS(int o); 410 | //========================phase offsets============= 411 | int getAPHCAL(); 412 | int getBPHCAL(); 413 | int getCPHCAL(); 414 | void setAPHCAL(char m); 415 | void setBPHCAL(char m); 416 | void setCPHCAL(char m); 417 | //=========================current offset========= 418 | int getACurrentOffset(); 419 | int getBCurrentOffset(); 420 | int getCCurrentOffset(); 421 | 422 | void setACurrentOffset(int o); 423 | void setBCurrentOffset(int o); 424 | void setCCurrentOffset(int o); 425 | int getAVoltageOffset(); 426 | int getBVoltageOffset(); 427 | int getCVoltageOffset(); 428 | void setAVoltageOffset(int o); 429 | void setBVoltageOffset(int o); 430 | void setCVoltageOffset(int o); 431 | void setZeroCrossingTimeout(int d); 432 | int getZeroCrossingTimeout(); 433 | char setPotLine(char Phase, int Ciclos); 434 | int getWatt(char); 435 | int getVar(char); 436 | int getVa(char); 437 | unsigned char getVersion(void); 438 | 439 | 440 | 441 | 442 | unsigned char spiRead8(unsigned char address); 443 | unsigned int spiRead16(unsigned char address); 444 | unsigned long spiRead24(unsigned char address); 445 | 446 | void spiWrite24(unsigned char address, unsigned long value); 447 | void spiWrite16(unsigned char address,unsigned int value); 448 | void spiWrite8(unsigned char address,unsigned int value); 449 | 450 | private: //private methods 451 | void enableChip(bool enable); 452 | 453 | 454 | }; 455 | 456 | #endif 457 | -------------------------------------------------------------------------------- /src/ADE7758.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "ADE7758.h" 5 | 6 | 7 | 8 | ADE7758::ADE7758() { 9 | 10 | } 11 | 12 | void ADE7758::Init(void) { 13 | pinMode(AFECS,OUTPUT); 14 | digitalWrite(AFECS, LOW);//enabled by default 15 | // SPI Init 16 | SPI.setDataMode(SPI_MODE2); 17 | SPI.setClockDivider(SPI_CLOCK_DIV32); 18 | SPI.setBitOrder(MSBFIRST); 19 | SPI.begin(); 20 | delay(10); 21 | 22 | 23 | } 24 | 25 | 26 | /***************************** 27 | * 28 | * private functions 29 | * 30 | *****************************/ 31 | 32 | /** === enableChip === 33 | * Enable chip, setting low ChipSelect pin (AFECS) 34 | * @param none 35 | * 36 | */ 37 | void ADE7758::enableChip(bool enable) { 38 | digitalWrite(AFECS, enable ? 0 : 1); 39 | if (enable) 40 | delayMicroseconds(50); // 50 microseconds to power up. 41 | } 42 | 43 | 44 | /** === read8 === 45 | * Read 8 bits from the device at specified register 46 | * @param char containing register direction 47 | * @return char with contents of register 48 | * 49 | */ 50 | unsigned char ADE7758::spiRead8(unsigned char address){ 51 | unsigned char RegValue0=0; 52 | 53 | enableChip(true); 54 | SPI.transfer(address); 55 | RegValue0 = SPI.transfer(0x00); 56 | enableChip(false); 57 | 58 | return (RegValue0); 59 | } 60 | 61 | 62 | /** === read16 === 63 | * Read 16 bits from the device at specified register 64 | * @param char containing register direction 65 | * @return int with contents of register 66 | * 67 | */ 68 | unsigned int ADE7758::spiRead16(unsigned char address){ 69 | unsigned int _16BitValue=0; 70 | unsigned char ReadValue,RegValue1,RegValue2; 71 | 72 | enableChip(true); 73 | delayMicroseconds(50); 74 | SPI.transfer(address); 75 | delayMicroseconds(50); 76 | RegValue1 = SPI.transfer(0x00); 77 | delayMicroseconds(50); 78 | RegValue2 = SPI.transfer(0x00); 79 | delayMicroseconds(50); 80 | enableChip(false); 81 | _16BitValue = RegValue1; 82 | _16BitValue <<= 8; 83 | _16BitValue |= RegValue2; 84 | return(_16BitValue); 85 | } 86 | 87 | 88 | /** === read24 === 89 | * Read 24 bits from the device at specified register 90 | * @param: char containing register direction 91 | * @return: char with contents of register 92 | * 93 | */ 94 | unsigned long ADE7758::spiRead24(unsigned char address){ 95 | long _24bitValue = 0; 96 | unsigned char RegValue0,RegValue1,RegValue2; 97 | 98 | enableChip(true); 99 | delayMicroseconds(50); 100 | SPI.transfer(address); 101 | delayMicroseconds(50); 102 | RegValue0 = SPI.transfer(0x00); 103 | delayMicroseconds(50); 104 | RegValue1 = SPI.transfer(0x00); 105 | delayMicroseconds(50); 106 | RegValue2 = SPI.transfer(0x00); 107 | delayMicroseconds(50); 108 | enableChip(false); 109 | 110 | _24bitValue = RegValue0 ; 111 | _24bitValue <<= 16; 112 | _24bitValue |= (((unsigned int)RegValue1) << 8); 113 | _24bitValue |= RegValue2; 114 | return (_24bitValue); 115 | } 116 | 117 | 118 | 119 | /** === write8 120 | * Write 8 bits to the device at specified register 121 | * @param reg char containing register direction 122 | * @param data char, 8 bits of data to send 123 | * 124 | */ 125 | void ADE7758::spiWrite8(unsigned char address,unsigned int value){ 126 | unsigned char a1; 127 | address |= WRITE; 128 | a1 = (unsigned char)value; 129 | 130 | enableChip(true); 131 | delayMicroseconds(50); 132 | SPI.transfer((unsigned char)address); //register selection 133 | delayMicroseconds(50); 134 | SPI.transfer((unsigned char)a1); 135 | delayMicroseconds(50); 136 | enableChip(false); 137 | } 138 | 139 | 140 | /** === write16 === 141 | * Write 16 bits to the device at specified register 142 | * @param reg: char containing register direction 143 | * @param data: int, 16 bits of data to send 144 | * 145 | */ 146 | void ADE7758::spiWrite16(unsigned char address,unsigned int value){ 147 | unsigned char a1,a2; 148 | a1 = value >> 8; 149 | a2 = (unsigned char)value; 150 | 151 | address |= WRITE; 152 | enableChip(true); 153 | delayMicroseconds(50); 154 | SPI.transfer((unsigned char)address); 155 | delayMicroseconds(50); 156 | SPI.transfer(a1); 157 | delayMicroseconds(50); 158 | SPI.transfer(a2); 159 | delayMicroseconds(50); 160 | enableChip(false); 161 | } 162 | 163 | void ADE7758::spiWrite24(unsigned char address, unsigned long value){ 164 | 165 | unsigned char a1,a2,a3; 166 | a1 = value >> 16; 167 | a2 = value >> 8; 168 | a3 = (unsigned char)value; 169 | address |= WRITE; 170 | 171 | enableChip(true); 172 | delayMicroseconds(50); 173 | SPI.transfer((unsigned char)address); 174 | delayMicroseconds(50); 175 | SPI.transfer(a1); 176 | delayMicroseconds(50); 177 | SPI.transfer(a2); 178 | delayMicroseconds(50); 179 | SPI.transfer(a3); 180 | delayMicroseconds(50); 181 | enableChip(false); 182 | } 183 | 184 | 185 | 186 | /** 187 | * In general: 188 | * @params: void 189 | * @return: register content (measure) of the proper type depending on register width 190 | */ 191 | unsigned char ADE7758::getVersion(){ 192 | return spiRead8(VERSION); 193 | } 194 | 195 | /** === setOpMode / getOpMode === 196 | OPERATIONAL MODE REGISTER (0x13) 197 | The general configuration of the ADE7758 is defined by writing to the OPMODE register. 198 | Table 18 summarizes the functionality of each bit in the OPMODE register. 199 | 200 | Bit Location Bit Mnemonic Default Value Description 201 | 0 DISHPF 0 The HPFs in all current channel inputs are disabled when this bit is set. 202 | 1 DISLPF 0 The LPFs after the watt and VAR multipliers are disabled when this bit is set. 203 | 2 DISCF 1 The frequency outputs APCF and VARCF are disabled when this bit is set. 204 | 3 to 5 DISMOD 0 By setting these bits, ADE7758’s ADCs can be turned off. In normal operation, these bits should be left at Logic 0. 205 | DISMOD[2:0] Description 206 | 0 0 0 Normal operation. 207 | 1 0 0 Redirect the voltage inputs to the signal paths for the current channels and the current inputs to the signal paths for the voltage channels. 208 | 0 0 1 Switch off only the current channel ADCs. 209 | 1 0 1 Switch off current channel ADCs and redirect the current input signals to the voltage channel signal paths. 210 | 0 1 0 Switch off only the voltage channel ADCs. 211 | 1 1 0 Switch off voltage channel ADCs and redirect the voltage input signals to the current channel signal paths. 212 | 0 1 1 Put the ADE7758 in sleep mode. 213 | 1 1 1 Put the ADE7758 in power-down mode (reduces AIDD to 1 mA typ). 214 | 6 SWRST 0 Software Chip Reset. A data transfer to the ADE7758 should not take place for at least 18 μs after a software reset. 215 | 7 RESERVED 0 This should be left at 0. 216 | 217 | */ 218 | 219 | void ADE7758::setOpMode(char m){ 220 | spiWrite8(OPMODE, m); 221 | } 222 | int ADE7758::getOpMode(){ 223 | return spiRead8(OPMODE); 224 | } 225 | 226 | /** === setMMode / getMMode === 227 | MEASUREMENT MODE REGISTER (0x14) 228 | The configuration of the PERIOD and peak measurements made by the ADE7758 is defined by writing to the MMODE register. 229 | Table 19 summarizes the functionality of each bit in the MMODE register. 230 | 231 | Bit Location Bit Mnemonic Default Value Description 232 | 0 to 1 FREQSEL 0 These bits are used to select the source of the measurement of the voltage line frequency. 233 | FREQSEL1 FREQSEL0 Source 234 | 0 0 Phase A 235 | 0 1 Phase B 236 | 1 0 Phase C 237 | 1 1 Reserved 238 | 2 to 4 PEAKSEL 7 These bits select the phases used for the voltage and current peak registers. 239 | Setting Bit 2 switches the IPEAK and VPEAK registers to hold the absolute values 240 | of the largest current and voltage waveform (over a fixed number of half-line cycles) 241 | from Phase A. The number of half-line cycles is determined by the content of the 242 | LINECYC register. At the end of the LINECYC number of half-line cycles, the content 243 | of the registers is replaced with the new peak values. Similarly, setting Bit 3 turns 244 | on the peak detection for Phase B, and Bit 4 for Phase C. Note that if more than one 245 | bit is set, the VPEAK and IPEAK registers can hold values from two different phases, that is, 246 | the voltage and current peak are independently processed (see the Peak Current Detection section). 247 | 5 to 7 PKIRQSEL 7 These bits select the phases used for the peak interrupt detection. 248 | Setting Bit 5 switches on the monitoring of the absolute current and voltage waveform to Phase A. 249 | Similarly, setting Bit 6 turns on the waveform detection for Phase B, and Bit 7 for Phase C. 250 | Note that more than one bit can be set for detection on multiple phases. 251 | If the absolute values of the voltage or current waveform samples in the selected phases exceeds 252 | the preset level specified in the VPINTLVL or IPINTLVL registers the corresponding bit(s) in the 253 | STATUS registers are set (see the Peak Current Detection section). 254 | 255 | */ 256 | 257 | void ADE7758::setMMode(char m){ 258 | spiWrite8(MMODE, m); 259 | } 260 | int ADE7758::getMMode(){ 261 | return spiRead8(MMODE); 262 | } 263 | 264 | 265 | /** === setWavMode / getWavMode === 266 | WAVEFORM MODE REGISTER (0x15) 267 | The waveform sampling mode of the ADE7758 is defined by writing to the WAVMODE register. 268 | Table 20 summarizes the functionality of each bit in the WAVMODE register. 269 | 270 | Bit Location Bit Mnemonic Default Value Description 271 | 0 to 1 PHSEL 0 These bits are used to select the phase of the waveform sample. 272 | PHSEL[1:0] Source 273 | 0 0 Phase A 274 | 0 1 Phase B 275 | 1 0 Phase C 276 | 1 1 Reserved 277 | 2 to 4 WAVSEL 0 These bits are used to select the type of waveform. 278 | WAVSEL[2:0] Source 279 | 0 0 0 Current 280 | 0 0 1 Voltage 281 | 0 1 0 Active Power Multiplier Output 282 | 0 1 1 Reactive Power Multiplier Output 283 | 1 0 0 VA Multiplier Output 284 | -Others- Reserved 285 | 5 to 6 DTRT 0 These bits are used to select the data rate. 286 | DTRT[1:0] Update Rate 287 | 0 0 26.04 kSPS (CLKIN/3/128) 288 | 0 1 13.02 kSPS (CLKIN/3/256) 289 | 1 0 6.51 kSPS (CLKIN/3/512) 290 | 1 1 3.25 kSPS (CLKIN/3/1024) 291 | 7 VACF 0 Setting this bit to Logic 1 switches the VARCF output pin to an output 292 | frequency that is proportional to the total apparent power (VA). 293 | In the default state, Logic 0, the VARCF pin outputs a frequency proportional 294 | to the total reactive power (VAR). 295 | */ 296 | 297 | void ADE7758::setWavMode(char m){ 298 | spiWrite8(WAVMODE, m); 299 | } 300 | int ADE7758::getWavMode(){ 301 | return spiRead8(WAVMODE); 302 | } 303 | 304 | 305 | 306 | /** === setCompMode / getCompMode === 307 | 308 | COMPUTATIONAL MODE REGISTER (0x16) 309 | The computational method of the ADE7758 is defined by writing to the COMPMODE register. 310 | 311 | Bit Location Bit Mnemonic Default Value Description 312 | 0 to 1 CONSEL 0 These bits are used to select the input to the energy accumulation registers. 313 | CONSEL[1:0] = 11 is reserved. IA, IB, and IC are IA, IB, and IC phase shifted by –90°, respectively. 314 | Registers CONSEL[1, 0] = 00 CONSEL[1, 0] = 01 CONSEL[1, 0] = 10 315 | AWATTHR VA × IA VA × (IA – IB) VA × (IA–IB) 316 | BWATTHR VB × IB 0 0 317 | CWATTHR VC × IC VC × (IC – IB) VC × IC 318 | 319 | AVARHR VA × IA VA × (IA – IB) VA × (IA–IB) 320 | BVARHR VB × IB 0 0 321 | CVARHR VC × IC VC × (IC – IB) VC × IC 322 | 323 | AVAHR VARMS × IARMS VARMS × IARMS VARMS × ARMS 324 | BVAHR VBRMS × IBRMS (VARMS + VCRMS)/2 × IBRMS VARMS × IBRMS 325 | CVAHR VCRMS × ICRMS VCRMS × ICRMS VCRMS × ICRMS 326 | 327 | 2 to 4 TERMSEL 7 These bits are used to select the phases to be included in the APCF and VARCF pulse outputs. 328 | Setting Bit 2 selects Phase A (the inputs to AWATTHR and AVARHR registers) to be included. 329 | Bit 3 and Bit 4 are for Phase B and Phase C, respectively. 330 | Setting all three bits enables the sum of all three phases to be included in the frequency outputs 331 | (see the Active Power Frequency Output and the Reactive Power Frequency Output sections). 332 | 333 | 5 ABS 0 Setting this bit places the APCF output pin in absolute only mode. 334 | Namely, the APCF output frequency is proportional to the sum of the absolute values of the watt-hour 335 | accumulation registers (AWATTHR, BWATTHR, and CWATTHR). 336 | Note that this bit only affects the APCF pin and has no effect on the content of the corresponding 337 | registers. 338 | 339 | 6 SAVAR 0 Setting this bit places the VARCF output pin in the signed adjusted mode. 340 | Namely, the VARCF output frequency is proportional to the sign-adjusted sum of the VAR-hour accumulation 341 | registers (AVARHR, BVARHR, and CVARHR). 342 | The sign of the VAR is determined from the sign of the watt calculation from the corresponding phase, 343 | that is, the sign of the VAR is flipped if the sign of the watt is negative, and if the watt is positive, 344 | there is no change to the sign of the VAR. 345 | Note that this bit only affects the VARCF pin and has no effect on the content of the corresponding 346 | registers. 347 | 348 | 7 NOLOAD 0 Setting this bit activates the no-load threshold in the ADE7758. 349 | */ 350 | 351 | void ADE7758::setCompMode(char m){ 352 | spiWrite8(COMPMODE, m); 353 | } 354 | int ADE7758::getCompMode(){ 355 | return spiRead8(COMPMODE); 356 | } 357 | 358 | /** === setLcycMode / getLcycMode === 359 | 360 | LINE CYCLE ACCUMULATION MODE REGISTER (0x17) 361 | The functionalities involved the line-cycle accumulation mode in the ADE7758 are defined by writing to the LCYCMODE register. 362 | 363 | Bit Location Bit Mnemonic Default Value Description 364 | 365 | 0 LWATT 0 Setting this bit places the watt-hour accumulation registers 366 | (AWATTHR, BWATTHR, and CWATTHR registers) into line-cycle accumulation mode. 367 | 1 LVAR 0 Setting this bit places the VAR-hour accumulation registers (AVARHR, BVARHR, and CVARHR registers) 368 | into line-cycle accumulation mode. 369 | 2 LVA 0 Setting this bit places the VA-hour accumulation registers (AVAHR, BVAHR, and CVAHR registers) 370 | into line-cycle accumulation mode. 371 | 3 to 5 ZXSEL 7 These bits select the phases used for counting the number of zero crossings in the line-cycle 372 | accumulation mode. Bit 3, Bit 4, and Bit 5 select Phase A, Phase B, and Phase C, respectively. 373 | More than one phase can be selected for the zero-crossing detection, 374 | and the accumulation time is shortened accordingly. 375 | 6 RSTREAD 1 Setting this bit enables the read-with-reset for all the WATTHR, VARHR, and VAHR registers for all three 376 | phases, that is, a read to those registers resets the registers to 0 after the content of the registers 377 | have been read. This bit should be set to Logic 0 when the LWATT, LVAR, or LVA bits are set to Logic 1. 378 | 7 FREQSEL 0 Setting this bit causes the FREQ (0x10) register to display the period, instead of the frequency of the 379 | line input. 380 | */ 381 | 382 | void ADE7758::setLcycMode(char m){ 383 | spiWrite8(LCYCMODE, m); 384 | } 385 | int ADE7758::getLcycMode(){ 386 | return spiRead8(LCYCMODE); 387 | } 388 | 389 | /** === gainSetup === 390 | GAIN REGISTER (0x23) 391 | The PGA configuration of the ADE7758 is defined by writing to the GAIN register. 392 | Table 18 summarizes the functionality of each bit in the GAIN register. 393 | 394 | Bit Location Bit Mnemonic Default Value Description 395 | 0 to 1 PGA1 0 Current GAIN 396 | PGA1[1:0] Description 397 | 0 0 x1 398 | 0 1 x2 399 | 1 0 x4 400 | 1 1 RESERVED 401 | 2 ---- RESERVED Reserved. 402 | 3 to 4 SCALE 0 Current input full-scale select 403 | SCALE[1:0] Description 404 | 0 0 0.5v 405 | 0 1 0.25v 406 | 1 0 0.125v 407 | 1 1 Reserved 408 | 5 to 6 PGA2 0 Voltage GAIN 409 | PGA2[1:0] Description 410 | 0 0 x1 411 | 0 1 x2 412 | 1 0 x4 413 | 1 1 RESERVED 414 | 7 INTEGRATOR 0 This bit enables the integrator on the current chanel when set. 415 | */ 416 | 417 | void ADE7758::gainSetup(char integrator, char scale, char PGA2, char PGA1){ 418 | char pgas = (integrator<<7) | (PGA2<<5) | (scale<<3) | (PGA1); 419 | spiWrite8(GAIN,pgas);//write GAIN register, format is |3 bits PGA2 gain|2 bits full scale|3 bits PGA1 gain 420 | } 421 | 422 | void ADE7758::setupDivs(unsigned char Watt_div,unsigned char VAR_div,unsigned char VA_div){ 423 | spiWrite8(WDIV,Watt_div); 424 | spiWrite8(VARDIV,VAR_div); 425 | spiWrite8(VADIV,VA_div); 426 | } 427 | 428 | /** === getMaskInterrupts / setMaskInterrupts 429 | MASK REGISTER (0x18) 430 | When an interrupt event occurs in the ADE7758, the IRQ logic output goes active low if the mask bit for this event is Logic 1 in the MASK register. 431 | The IRQ logic output is reset to its default collector open state when the RSTATUS register is read. 432 | describes the function of each bit in the interrupt mask register. 433 | 434 | Bit Location Interrupt Flag Default Value Description 435 | 0 AEHF 0 Enables an interrupt when there is a change in Bit 14 of any one of the three WATTHR registers, 436 | that is, the WATTHR register is half full. 437 | 1 REHF 0 Enables an interrupt when there is a change in Bit 14 of any one of the three VARHR registers, 438 | that is, the VARHR register is half full. 439 | 2 VAEHF 0 Enables an interrupt when there is a 0 to 1 transition in the MSB of any one of the three VAHR 440 | registers, that is, the VAHR register is half full. 441 | 3 SAGA 0 Enables an interrupt when there is a SAG on the line voltage of the Phase A. 442 | 4 SAGB 0 Enables an interrupt when there is a SAG on the line voltage of the Phase B. 443 | 5 SAGC 0 Enables an interrupt when there is a SAG on the line voltage of the Phase C. 444 | 6 ZXTOA 0 Enables an interrupt when there is a zero-crossing timeout detection on Phase A. 445 | 7 ZXTOB 0 Enables an interrupt when there is a zero-crossing timeout detection on Phase B. 446 | 8 ZXTOC 0 Enables an interrupt when there is a zero-crossing timeout detection on Phase C. 447 | 9 ZXA 0 Enables an interrupt when there is a zero crossing in the voltage channel of Phase A 448 | (see the Zero-Crossing Detection section). 449 | 10 ZXB 0 Enables an interrupt when there is a zero crossing in the voltage channel of Phase B 450 | (see the Zero-Crossing Detection section). 451 | 11 ZXC 0 Enables an interrupt when there is a zero crossing in the voltage channel of Phase C 452 | (see the Zero-Crossing Detection section). 453 | 12 LENERGY 0 Enables an interrupt when the energy accumulations over LINECYC are finished. 454 | 13 RESERVED 0 Reserved. 455 | 14 PKV 0 Enables an interrupt when the voltage input selected in the MMODE register is above 456 | the value in the VPINTLVL register. 457 | 15 PKI 0 Enables an interrupt when the current input selected in the MMODE register is above the 458 | value in the IPINTLVL register. 459 | 16 WFSM 0 Enables an interrupt when data is present in the WAVEMODE register. 460 | 17 REVPAP 0 Enables an interrupt when there is a sign change in the watt calculation among any one of 461 | the phases specified by the TERMSEL bits in the COMPMODE register. 462 | 18 REVPRP 0 Enables an interrupt when there is a sign change in the VAR calculation among any one of 463 | the phases specified by the TERMSEL bits in the COMPMODE register. 464 | 19 SEQERR 0 Enables an interrupt when the zero crossing from Phase A is followed not by the zero crossing 465 | of Phase C but with that of Phase B. 466 | */ 467 | long ADE7758::getMaskInterrupts(void){ 468 | return spiRead24(MASK); 469 | } 470 | void ADE7758::setMaskInterrupts(unsigned long m){ 471 | return spiWrite24(MASK, m); 472 | } 473 | /** getStatus / resetStatus 474 | INTERRUPT STATUS REGISTER (0x19)/RESET INTERRUPT STATUS REGISTER (0x1A) 475 | The interrupt status register is used to determine the source of an interrupt event. 476 | When an interrupt event occurs in the ADE7758, the corresponding flag in the interrupt status register is set. 477 | The IRQ pin goes active low if the corresponding bit in the interrupt mask register is set. 478 | When the MCU services the interrupt, it must first carry out a read from the interrupt status register to determine the source of the interrupt. 479 | All the interrupts in the interrupt status register stay at their logic high state after an event occurs. 480 | The state of the interrupt bit in the interrupt status register is reset to its default value once the reset interrupt status register is read. 481 | 482 | Bit Location Interrupt Flag Default Value Event Description 483 | 0 AEHF 0 Indicates that an interrupt was caused by a change in Bit 14 among any one of the three 484 | WATTHR registers, that is, the WATTHR register is half full. 485 | 1 REHF 0 Indicates that an interrupt was caused by a change in Bit 14 among any one of the three 486 | VARHR registers, that is, the VARHR register is half full. 487 | 2 VAEHF 0 Indicates that an interrupt was caused by a 0 to 1 transition in Bit 15 among any one of the three 488 | VAHR registers, that is, the VAHR register is half full. 489 | 3 SAGA 0 Indicates that an interrupt was caused by a SAG on the line voltage of the Phase A. 490 | 4 SAGB 0 Indicates that an interrupt was caused by a SAG on the line voltage of the Phase B. 491 | 5 SAGC 0 Indicates that an interrupt was caused by a SAG on the line voltage of the Phase C. 492 | 6 ZXTOA 0 Indicates that an interrupt was caused by a missing zero crossing on the line voltage of the Phase A. 493 | 7 ZXTOB 0 Indicates that an interrupt was caused by a missing zero crossing on the line voltage of the Phase B. 494 | 8 ZXTOC 0 Indicates that an interrupt was caused by a missing zero crossing on the line voltage of the Phase C. 495 | 9 ZXA 0 Indicates a detection of a rising edge zero crossing in the voltage channel of Phase A. 496 | 10 ZXB 0 Indicates a detection of a rising edge zero crossing in the voltage channel of Phase B. 497 | 11 ZXC 0 Indicates a detection of a rising edge zero crossing in the voltage channel of Phase C. 498 | 12 LENERGY 0 In line energy accumulation, indicates the end of an integration over an integer number of 499 | half- line cycles (LINECYC). See the Calibration section. 500 | 13 RESET 1 Indicates that the 5 V power supply is below 4 V. Enables a software reset of the ADE7758 501 | and sets the registers back to their default values. This bit in the STATUS or RSTATUS register 502 | is logic high for only one clock cycle after a reset event. 503 | 14 PKV 0 Indicates that an interrupt was caused when the selected voltage input is above the value in the 504 | VPINTLVL register. 505 | 15 PKI 0 Indicates that an interrupt was caused when the selected current input is above the value 506 | in the IPINTLVL register. 507 | 16 WFSM 0 Indicates that new data is present in the waveform register. 508 | 17 REVPAP 0 Indicates that an interrupt was caused by a sign change in the watt calculation among any 509 | one of the phases specified by the TERMSEL bits in the COMPMODE register. 510 | 18 REVPRP 0 Indicates that an interrupt was caused by a sign change in the VAR calculation among any 511 | one of the phases specified by the TERMSEL bits in the COMPMODE register. 512 | 19 SEQERR 0 Indicates that an interrupt was caused by a zero crossing from Phase A 513 | followed not by the zero crossing of Phase C but by that of Phase B. 514 | */ 515 | 516 | unsigned long ADE7758::getStatus(void){ 517 | return spiRead24(STATUS); 518 | } 519 | 520 | unsigned long ADE7758::resetStatus(void){ 521 | return spiRead24(RSTATUS); 522 | } 523 | 524 | /** === getAIRMS === 525 | * Phase A Current RMS Value 526 | * To minimize noise, synchronize the reading of the rms register with the zero crossing 527 | * of the voltage input and take the average of a number of readings. 528 | * @param none 529 | * @return long with the data (24 bits unsigned). 530 | */ 531 | long ADE7758::getIRMS(char phase){ 532 | long lastupdate = 0; 533 | char t_of = 0; 534 | resetStatus(); // Clear all interrupts 535 | lastupdate = millis(); 536 | while(!(getStatus() & ZXA)) // wait Zero-Crossing 537 | { // wait for the selected interrupt to occur 538 | if ( ( millis() - lastupdate ) > 20) 539 | { 540 | t_of = 1; 541 | break; 542 | } 543 | } 544 | if (t_of){ 545 | return 0; 546 | }else{ 547 | return spiRead24(AIRMS + phase); 548 | } 549 | } 550 | 551 | /** === getAVRMS === 552 | * Phase A RMS Value (Voltage Channel). 553 | * To minimize noise, synchronize the reading of the rms register with the zero crossing 554 | * of the voltage input and take the average of a number of readings. 555 | * @param none 556 | * @return long with the data (24 bits unsigned). 557 | */ 558 | 559 | long ADE7758::getVRMS(char phase){ 560 | long lastupdate = 0; 561 | char t_of = 0; 562 | resetStatus(); // Clear all interrupts 563 | lastupdate = millis(); 564 | while(!(getStatus() & ZXA)) // wait Zero-Crossing 565 | { // wait for the selected interrupt to occur 566 | if ((millis() - lastupdate) > 20) 567 | { 568 | break; 569 | } 570 | } 571 | if(t_of){ 572 | return 0; 573 | }else{ 574 | return spiRead24(AVRMS + phase); 575 | } 576 | } 577 | 578 | 579 | /** === vrms === 580 | * Returns the mean of last 20 readings of RMS voltage. Also supress first reading to avoid 581 | * corrupted data. 582 | * To minimize noise, synchronize the reading of the rms register with the zero crossing 583 | * of the voltage input and take the average of a number of readings. 584 | * @param none 585 | * @return long with RMS voltage value 586 | */ 587 | long ADE7758::getVrms(char phase){ 588 | byte i=0; 589 | long v=0; 590 | if(getVRMS(phase)){ //Ignore first reading to avoid garbage 591 | for(i=0;i<5;++i){ 592 | v+=getVRMS(phase); 593 | } 594 | return (v/5); 595 | }else{ 596 | return 0; 597 | } 598 | } 599 | 600 | 601 | /** === irms === 602 | * Returns the mean of last 20 readings of RMS current. Also supress first reading to avoid 603 | * corrupted data. 604 | * To minimize noise, synchronize the reading of the rms register with the zero crossing 605 | * of the voltage input and take the average of a number of readings. 606 | * @param none 607 | * @return long with RMS current value in hundreds of [mA], ie. 6709=67[mA] 608 | */ 609 | float ADE7758::irms(char phase){ 610 | char n=0; 611 | long i=0; 612 | if(getIRMS(phase)){//Ignore first reading to avoid garbage 613 | for(n=0;n<5;++n){ 614 | i+=getIRMS(phase); 615 | } 616 | float j = (float)i; 617 | j = (j/5); 618 | return j; // i multipied by slope 619 | }else{ 620 | return 0; 621 | } 622 | } 623 | 624 | 625 | /** === getFreq === 626 | * Period of the Phase selected in MMode. 627 | * @param none 628 | * @return int with the data (12 bits unsigned). 629 | */ 630 | 631 | 632 | int ADE7758::GetFrequency(char phase){ 633 | uint8_t mmode; 634 | mmode = spiRead8(MMODE); 635 | spiWrite8(MMODE,(mmode&0x11111100 )| phase); 636 | delay(10); 637 | return spiRead16(FREQ); 638 | } 639 | /** setLineCyc configura el numero de ciclos necesarios para las acumulaciones. 640 | **/ 641 | void ADE7758::setLineCyc(int d){ 642 | spiWrite16(LINECYC,d); 643 | } 644 | /** === setCurrentOffset / getCurrentOffset === 645 | * @param none 646 | * @return int with the data (12 bits 2-complement signed). 647 | */ 648 | 649 | //=================================================Apparent power gain register==================================== 650 | int ADE7758::getAVAGainregister(){ 651 | return ((spiRead16(AVAG))<<4)>>4; 652 | } 653 | int ADE7758::getBVAGainregister(){ 654 | return ((spiRead16(BVAG))<<4)>>4; 655 | } 656 | int ADE7758::getCVAGainregister(){ 657 | return ((spiRead16(CVAG))<<4)>>4; 658 | } 659 | void ADE7758::setAVAGainregister(int o){ 660 | spiWrite16(AVAG, o); 661 | } 662 | void ADE7758::setBVAGainregister(int o){ 663 | spiWrite16(BVAG, o); 664 | } 665 | void ADE7758::setCVAGainregister(int o){ 666 | spiWrite16(CVAG, o); 667 | } 668 | //========================active power offset calibration during when no power is cconsumed============================ 669 | int ADE7758::getAWATTOS(){ 670 | return ((spiRead16(AWATTOS))<<4)>>4; 671 | } 672 | int ADE7758::getBWATTOS(){ 673 | return ((spiRead16(BWATTOS))<<4)>>4; 674 | } 675 | int ADE7758::getCWATTOS(){ 676 | return ((spiRead16(CWATTOS))<<4)>>4; 677 | } 678 | void ADE7758::setAWATTOS(int o){ 679 | spiWrite16(AWATTOS, o); 680 | } 681 | void ADE7758::setBWATTOS(int o){ 682 | spiWrite16(BWATTOS, o); 683 | } 684 | void ADE7758::setCWATTOS(int o){ 685 | spiWrite16(CWATTOS, o); 686 | } 687 | 688 | //========================PHASE CALIBRATIO REGISTERS=================== 689 | 690 | 691 | void ADE7758::setAPHCAL(char m){ 692 | spiWrite8(APHCAL, m); 693 | } 694 | int ADE7758::getAPHCAL(){ 695 | return ((spiRead8(APHCAL))<<1)>>1; 696 | } 697 | 698 | void ADE7758::setBPHCAL(char m){ 699 | spiWrite8(BPHCAL, m); 700 | } 701 | int ADE7758::getBPHCAL(){ 702 | return ((spiRead8(BPHCAL))<<1)>>1; 703 | } 704 | 705 | void ADE7758::setCPHCAL(char m){ 706 | spiWrite8(CPHCAL, m); 707 | } 708 | int ADE7758::getCPHCAL(){ 709 | return ((spiRead8(CPHCAL))<<1)>>1; 710 | } 711 | //===================================================current offset========================== 712 | int ADE7758::getACurrentOffset(){ 713 | return ((spiRead16(AIRMSOS))<<4)>>4; 714 | } 715 | int ADE7758::getBCurrentOffset(){ 716 | return ((spiRead16(BIRMSOS))<<4)>>4; 717 | } 718 | int ADE7758::getCCurrentOffset(){ 719 | return ((spiRead16(CIRMSOS))<<4)>>4; 720 | } 721 | void ADE7758::setACurrentOffset(int o){ 722 | spiWrite16(AIRMSOS, o); 723 | } 724 | void ADE7758::setBCurrentOffset(int o){ 725 | spiWrite16(BIRMSOS, o); 726 | } 727 | void ADE7758::setCCurrentOffset(int o){ 728 | spiWrite16(CIRMSOS, o); 729 | } 730 | /** === setVoltageOffset / getVoltageOffset === 731 | * @param none 732 | * @return int with the data (12 bits 2-complement signed). 733 | */ 734 | int ADE7758::getAVoltageOffset(){ 735 | return ((spiRead16(AVRMSOS))<<4)>>4; 736 | } 737 | int ADE7758::getBVoltageOffset(){ 738 | return ((spiRead16(BVRMSOS))<<4)>>4; 739 | } 740 | int ADE7758::getCVoltageOffset(){ 741 | return ((spiRead16(CVRMSOS))<<4)>>4; 742 | } 743 | void ADE7758::setAVoltageOffset(int o){ 744 | spiWrite16(AVRMSOS, o); 745 | } 746 | void ADE7758::setBVoltageOffset(int o){ 747 | spiWrite16(BVRMSOS, o); 748 | } 749 | void ADE7758::setCVoltageOffset(int o){ 750 | spiWrite16(CVRMSOS, o); 751 | } 752 | 753 | 754 | /** === setZeroCrossingTimeout / getZeroCrossingTimeout === 755 | * Zero-Crossing Timeout. If no zero crossings are detected 756 | * on Channel 2 within a time period specified by this 12-bit register, 757 | * the interrupt request line (IRQ) is activated 758 | * @param none 759 | * @return int with the data (12 bits unsigned). 760 | */ 761 | void ADE7758::setZeroCrossingTimeout(int d){ 762 | spiWrite16(ZXTOUT,d); 763 | } 764 | int ADE7758::getZeroCrossingTimeout(){ 765 | return spiRead16(ZXTOUT); 766 | } 767 | /** === setPotLine(Phase) === 768 | Setea las condiciones para Line accumulation en la phase seleccionada. 769 | Luego espera la interrupccion y devuelve el numero de phase cuando ocurre. 770 | Si no ocurre por mas de 1,5 segundos devuelve un 0. 771 | **/ 772 | char ADE7758::setPotLine(char Phase, int Ciclos){ 773 | long lastupdate = 0; 774 | char m = 0; 775 | char temp = 0; 776 | switch (Phase){ 777 | case PHASE_A: m = (LWATT | LVAR | LVA | ZXSEL_A); 778 | break; 779 | case PHASE_B: m = (LWATT | LVAR | LVA | ZXSEL_B); 780 | break; 781 | case PHASE_C: m = (LWATT | LVAR | LVA | ZXSEL_C); 782 | break; 783 | } 784 | setLcycMode(0); 785 | setLcycMode(m); 786 | resetStatus(); 787 | setLineCyc(Ciclos); 788 | lastupdate = millis(); 789 | while(!(getStatus() & LENERGY)) // wait to terminar de acumular 790 | { // wait for the selected interrupt to occur 791 | if ((millis() - lastupdate) > (Ciclos*15)) 792 | { 793 | temp = 1; 794 | break; 795 | } 796 | } 797 | if(temp){ 798 | return 0; 799 | }else{ 800 | return Phase; 801 | } 802 | } 803 | /** === getWatt(phase) / getVar(phase) / getVa(phase) === 804 | Devuelve los valores de la potencia requerida de la fase seleccionada. 805 | Utilizar antes setPotLine(phase) para generar los valores. 806 | **/ 807 | int ADE7758::getWatt(char Phase){ 808 | return spiRead16(AWATTHR + Phase ); 809 | 810 | } 811 | int ADE7758::getVar(char Phase){ 812 | int temp = 0; 813 | temp = spiRead16(AVARHR + Phase); 814 | 815 | return temp; 816 | } 817 | int ADE7758::getVa(char Phase){ 818 | int temp = 0; 819 | temp = spiRead16(AVAHR + Phase); 820 | 821 | return temp; 822 | } 823 | --------------------------------------------------------------------------------