/* BL0937 Copyright (C) 2016-2018 by Xose Pérez This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef BL0937_h #define BL0937_h #include // Internal voltage reference value #define V_REF 1.218 // The factor of a 1mOhm resistor // as per recomended circuit in datasheet // A 1mOhm resistor allows a ~30A max measurement #define R_CURRENT 0.001 // This is the factor of a voltage divider of 1MOhm upstream and 1kOhm downstream // as per recomended circuit in datasheet #define R_VOLTAGE 1000 // Frequency of the BL0937 internal clock #define F_OSC 2000000 // Minimum delay between selecting a mode and reading a sample #define READING_INTERVAL 3000 // Maximum pulse with in microseconds // If longer than this pulse width is reset to 0 // This value is purely experimental. // Higher values allow for a better precission but reduce sampling rate // and response speed to change // Lower values increase sampling rate but reduce precission // Values below 0.5s are not recommended since current and voltage output // will have no time to stabilise #define PULSE_TIMEOUT 5000000 // Define ICACHE_RAM_ATTR for AVR platforms #if defined(ARDUINO_ARCH_AVR) #define ICACHE_RAM_ATTR #endif // CF1 mode typedef enum { MODE_CURRENT, MODE_VOLTAGE } bl0937_mode_t; class BL0937 { public: void cf_interrupt(); void cf1_interrupt(); void begin( unsigned char cf_pin, unsigned char cf1_pin, unsigned char sel_pin, unsigned char currentWhen = HIGH, bool use_interrupts = true, unsigned long pulse_timeout = PULSE_TIMEOUT); void setMode(bl0937_mode_t mode); bl0937_mode_t getMode(); bl0937_mode_t toggleMode(); double getCurrent(); unsigned int getVoltage(); unsigned int getActivePower(); unsigned int getApparentPower(); double getPowerFactor(); unsigned int getReactivePower(); unsigned long getEnergy(); //in Ws void resetEnergy(); void setResistors(double current, double voltage_upstream, double voltage_downstream); void expectedCurrent(double current); void expectedVoltage(unsigned int current); void expectedActivePower(unsigned int power); double getCurrentMultiplier() { return _current_multiplier; }; double getVoltageMultiplier() { return _voltage_multiplier; }; double getPowerMultiplier() { return _power_multiplier; }; void setCurrentMultiplier(double current_multiplier) { _current_multiplier = current_multiplier; }; void setVoltageMultiplier(double voltage_multiplier) { _voltage_multiplier = voltage_multiplier; }; void setPowerMultiplier(double power_multiplier) { _power_multiplier = power_multiplier; }; void resetMultipliers(); private: unsigned char _cf_pin; unsigned char _cf1_pin; unsigned char _sel_pin; double _current_resistor = R_CURRENT; double _voltage_resistor = R_VOLTAGE; double _current_multiplier; // Unit: us/A double _voltage_multiplier; // Unit: us/V double _power_multiplier; // Unit: us/W unsigned long _pulse_timeout = PULSE_TIMEOUT; //Unit: us volatile unsigned long _voltage_pulse_width = 0; //Unit: us volatile unsigned long _current_pulse_width = 0; //Unit: us volatile unsigned long _power_pulse_width = 0; //Unit: us volatile unsigned long _pulse_count = 0; double _current = 0; unsigned int _voltage = 0; unsigned int _power = 0; unsigned char _current_mode = HIGH; volatile unsigned char _mode; bool _use_interrupts = true; volatile unsigned long _last_cf_interrupt = 0; volatile unsigned long _last_cf1_interrupt = 0; volatile unsigned long _first_cf1_interrupt = 0; void _checkCFSignal(); void _checkCF1Signal(); void _calculateDefaultMultipliers(); }; #endif