Skip to content
  • MySensors
  • OpenHardware.io
  • Categories
  • Recent
  • Tags
  • Popular
Skins
  • Light
  • Brite
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Brand Logo
  1. Home
  2. Development
  3. A class to Measure the Battery

A class to Measure the Battery

Scheduled Pinned Locked Moved Development
1 Posts 1 Posters 184 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • H Offline
    H Offline
    hlehoux
    wrote on last edited by hlehoux
    #1

    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);
    }
    
    
    1 Reply Last reply
    1

    Hello! It looks like you're interested in this conversation, but you don't have an account yet.

    Getting fed up of having to scroll through the same posts each visit? When you register for an account, you'll always come back to exactly where you were before, and choose to be notified of new replies (either via email, or push notification). You'll also be able to save bookmarks and upvote posts to show your appreciation to other community members.

    With your input, this post could be even better 💗

    Register Login
    Reply
    • Reply as topic
    Log in to reply
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes


    20

    Online

    12.0k

    Users

    11.2k

    Topics

    113.4k

    Posts


    Copyright 2025 TBD   |   Forum Guidelines   |   Privacy Policy   |   Terms of Service
    • Login

    • Don't have an account? Register

    • Login or register to search.
    • First post
      Last post
    0
    • MySensors
    • OpenHardware.io
    • Categories
    • Recent
    • Tags
    • Popular