A class to Measure the Battery
-
Hi all, for the sake of beginners like myself and to get advice on it, here is the code i have done to measure the battery of my sensors
based on @sundberg84 here: EasyNewbie-PCB-for-MySensors and articles i've read here
Please provide advice on how to manage switching analogReference()
Here is the class definition:
class MyBM { public: MyBM(); MyBM(const float _VMIN, const float _VMAX); void setup(void); void MeasureBattery(void); //The battery calculations private: void burnreadings(void); float VBAT_PER_BITS; float VMIN; // Vmin (radio Min Volt)=1.9V (564v) float VMAX; // Vmax = (2xAA bat)=3.0V (892v) int batteryPcnt = 0; // Calc value for battery % int batLoop = 0; // Loop to help calc average int batArray[3]; // Array to store value for average calc. unsigned int BATTERY_SENSE_PIN = A0; // select the input pin for the battery sense point int sValue; float Vbat; };
You can change the values in the constructor MyBM() ; by default it is the resistors 1M and 470k for EasyPCB.
Following advice found on stackoverflow, i make 8 readings in burnreadings() when switching from analogReference(INTERNAL) to analogReference(DEFAULT) back & forth
MyBM::MyBM() { this->VMIN= 2.0 ; // Vmin (radio Min Volt)=1.9V (564v) this->VMAX= 3.3; // Vmax = (2xAA bat)=3.0V (892v) this->VBAT_PER_BITS= (1470/470)*(1.1/1024); } MyBM::MyBM(const float _VMIN, const float _VMAX) { MyBM(); this->VMIN= _VMIN; this->VMAX= _VMAX; } void MyBM::burnreadings(void) { for (int i = 0; i < 8; i++) { analogRead(BATTERY_SENSE_PIN); } } void MyBM::setup(void) { //========================= // BATTERY MEASURER //DEFAULT: the default analog reference of 5 volts (on 5V Arduino boards) or 3.3 volts (on 3.3V Arduino boards) //INTERNAL: an built-in reference, equal to 1.1 volts on the ATmega168 or ATmega328 and 2.56 volts on the ATmega8 (not available on the Arduino Mega) //EXTERNAL: the voltage applied to the AREF pin (0 to 5V only) is used as the reference. analogReference(INTERNAL); // set the ADC reference to 1.1V burnreadings(); // make 8 readings but don't use them delay(10); // idle some time //Battery inital calc DPR("With Battery VMax (100%) = "); DPR(VMAX); DPR("volts and Vmin (0%) = "); DPR(VMIN); DPRLN(" volts"); DPR("Battery Percent 25%/50%/75% calculates to: "); DPR(((VMAX - VMIN) / 4) + VMIN); DPR("/"); DPR(((VMAX - VMIN) / 2) + VMIN); DPR("/"); DPRLN(VMAX - ((VMAX - VMIN) / 4)); sValue = analogRead(BATTERY_SENSE_PIN); DPR("Batterysens :"); DPRLN(sValue); Vbat = sValue * VBAT_PER_BITS; batteryPcnt = static_cast<int>(((Vbat - VMIN) / (VMAX - VMIN)) * 100.); DPR("Current battery are measured to (please confirm!): "); DPR(batteryPcnt); DPR(" % - Or "); DPRLN(Vbat); DPRLN(" Volts"); analogReference(DEFAULT); // set the ADC reference back to internal burnreadings(); // make 8 readings but don't use them delay(10); // idle again //========================= } void MyBM::MeasureBattery() { analogReference(INTERNAL); // set the ADC reference to 1.1V burnreadings(); // make 8 readings but don't use them delay(10); // idle some time // Battery monitoring reading sValue = analogRead(BATTERY_SENSE_PIN); DPR("Batterysens :"); DPRLN(sValue); //delay(500); // Calculate the battery in % Vbat = sValue * VBAT_PER_BITS; batteryPcnt = static_cast<int>(((Vbat - VMIN) / (VMAX - VMIN)) * 100.); DPR("Battery percent: "); DPR(batteryPcnt); DPR(" %"); DPR("Battery Voltage: "); DPR(Vbat); DPRLN(" Volts"); // Add it to array so we get an average of 3 (3x20min) batArray[batLoop] = batteryPcnt; if (batLoop > 2) { batteryPcnt = (batArray[0] + batArray[1] + batArray[2]); batteryPcnt = batteryPcnt / 3; if (batteryPcnt > 100) { batteryPcnt = 100; } DPR("Battery Average (Send): "); DPR(batteryPcnt); DPRLN(" %"); sendBatteryLevel(batteryPcnt); batLoop = 0; } else { batLoop++; } analogReference(DEFAULT); // set the ADC reference back to internal burnreadings(); // make 8 readings but don't use them delay(10); // idle again }
Here is how i use it with a sensor that manages both interrupts and a sensor-specific timeout
// sdj is an object representing the sensor MyBM bm; void setup() { sdj.setup(); bm.setup(); } void loop() { if (tripped==0) { the_switch= sdj.get(); } else if (tripped==MY_WAKE_UP_BY_TIMER) { if (sdj.wait_next()) { // timeout needs to do something for the sensor sdj.resetCode(); } else { // timeout , nothing occured for sensor bm.MeasureBattery(); } } // Sleep until something happens with the sensor or timeout tripped= sdj.sleep(WAIT_LOOP); }