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);
    }
    
    

Log in to reply
 

Suggested Topics

  • 1
  • 3
  • 2
  • 2
  • 2
  • 1

25
Online

11.2k
Users

11.1k
Topics

112.5k
Posts