Skip to content
  • 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. Better battery reporting
  • Getting Started
  • Controller
  • Build
  • Hardware
  • Download/API
  • Forum
  • Store

Better battery reporting

Scheduled Pinned Locked Moved Development
4 Posts 3 Posters 1.3k Views 3 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.
  • ? Offline
    ? Offline
    A Former User
    wrote on last edited by A Former User
    #1

    Hello,
    A modification I implemented starting from the "battery sensor" sketch, in order to improve battery % reporting; wrapped up in a small library. Please be kind with my code, I'm merely a hobbyist.
    Why:
    1- LiPo cells can't get under 3.3v without damage risk, AA cells are leak proof down to 0.7v, I wanted my battery reporting to implement this: LiPo: 100% = 4.15v, 0% = 3.3v // AA: 100% = 1.5v, 0% = 0.8v
    2 - Voltage divider precision relies on resistors accuracy, I wanted a way to "calibrate" my divider in order to get proper battery reporting
    3 - For fun :-)
    Please note that the voltage divider is not the same for LiPo and AA battery (explained in cpp's comments)

    Feel free to copy, paste, modify, criticize!

    Test sketch

    #include <BatteryManager.h>
    
    const int BatteryType = 1; // 1 for 1S LiPo, 2 for 2xAA
    const uint8_t BatterySensorPin = A0;
    const float VoltageDividerCalibration = 1; // default 1, can be calibrated by measurement
    
    BatteryManager bms;
    
    void setup() {
      // put your setup code here, to run once:
      Serial.begin(115200);
      bms.begin(BatteryType, BatterySensorPin,VoltageDividerCalibration);
    }
    
    void loop() {
      // put your main code here, to run repeatedly:
      Serial.print("Voltage: ");
      Serial.println(bms.reportVoltage());
      Serial.print("Percent: ");
      Serial.println(bms.reportPercent());
      delay(3000);
    }
    

    header:

    /*
    * Battery Manager
    */
    
    #ifndef BatteryManager_h
    #define BatteryManager_h
    
    #include <Arduino.h>
    
    class BatteryManager {
    	public:
            BatteryManager();
                    void begin(int BatteryType, uint8_t SensePin, float Compensation);
    		int reportPercent();
    		float reportVoltage();
    	private:
    		int _BatteryType; //1 for 1S LiPO, 2 for 2x AA
    		uint8_t _SensePin;
                    float _Compensation;
    		float Battery_Min_V;
    		float Battery_Max_V;
    		float Battery_Sense_Pin_Resolution;
    };
    #endif
    

    cpp

    #include <Arduino.h>
    #include <BatteryManager.h>
    
    BatteryManager::BatteryManager() { }
    
    void BatteryManager::begin(int BatteryType, uint8_t SensePin, float Compensation)
    {
        _SensePin = SensePin;
        _Compensation = Compensation;
        pinMode(_SensePin, INPUT);
        // Battery use the 1.1 V internal reference
        #if defined(__AVR_ATmega2560__)
            analogReference(INTERNAL1V1);
        #else
            analogReference(INTERNAL);
        #endif
        int firstRead = analogRead(_SensePin);
        // check battery type and feed related variables
        if (BatteryType == 1) {
                /* LiPo voltage need to be measured up to 4.2V hence using internal ADC ref of 1.1V,
                *  divider across battery needs to be 1M, 330K, 
                *  which allows a range of 0 to ((1e6+330e3)/330e3)*1.1 = 4.433 Volts
                *  resolution: 4.4333/1023 = Volts per bit = 0.004333659
                *  sense point can be bypassed with 0.1 uF cap to reduce noise at that point
                *  LiPo is full @ 4.2V and risks damage below 3.3v
                *  => LiPo usable range is 3.3 to 4.2 volts so the goal is to report
                *  100% @ 4.2 volts
                *  0% @ 3.3 volts
                */
                Battery_Min_V = 3.3;
                Battery_Max_V = 4.15;
                Battery_Sense_Pin_Resolution = 4.333659; //mv per bit
        }
         if (BatteryType == 2) {
                /* 2 x AA Alkaline voltage need to be measured up to 3V hence using internal ADC ref of 1.1V,
                *  divider across battery needs to be 1M, 470K, 
                *  which allows a range of 0 to ((1e6+470e3)/470e3)*1.1 = 3.44 Volts
                *  resolution: 3.44/1023 = Volts per bit = 0.003363075
                *  sense point can be bypassed with 0.1 uF cap to reduce noise at that point
                *  AA is normally leak proof down to 0.7V, I add an extra 0.1V to avoid any issue
                *  => AA usable range is 1.5 to 0.8 volts so the goal is to report
                *  100% @ 2x1.5 = 3 volts
                *  0% @ 2x0.8 = 1.6 volts
                */
                Battery_Min_V = 1.6;
                Battery_Max_V = 3;
                Battery_Sense_Pin_Resolution = 3.363075; //mv per bit
        }
    }
    
    int BatteryManager::reportPercent() {
        // get the battery Voltage
        int sensorValue = analogRead(_SensePin);
        Serial.println(sensorValue);
    	float batteryV  = sensorValue * Battery_Sense_Pin_Resolution * _Compensation / 1000;
    	// map to 0 -- 100 according to boundaries
    	// need to multiply voltages by 10 as map function processes long variables
    	return map(10*batteryV,10*Battery_Min_V, 10*Battery_Max_V, 0, 100);;
    }
    
    float BatteryManager::reportVoltage() {
        // get the battery Voltage
        int sensorValue = analogRead(_SensePin);
        Serial.println(sensorValue);
    	return sensorValue * Battery_Sense_Pin_Resolution * _Compensation / 1000;
    }
    
    Michiel van der WulpM 1 Reply Last reply
    0
    • ? A Former User

      Hello,
      A modification I implemented starting from the "battery sensor" sketch, in order to improve battery % reporting; wrapped up in a small library. Please be kind with my code, I'm merely a hobbyist.
      Why:
      1- LiPo cells can't get under 3.3v without damage risk, AA cells are leak proof down to 0.7v, I wanted my battery reporting to implement this: LiPo: 100% = 4.15v, 0% = 3.3v // AA: 100% = 1.5v, 0% = 0.8v
      2 - Voltage divider precision relies on resistors accuracy, I wanted a way to "calibrate" my divider in order to get proper battery reporting
      3 - For fun :-)
      Please note that the voltage divider is not the same for LiPo and AA battery (explained in cpp's comments)

      Feel free to copy, paste, modify, criticize!

      Test sketch

      #include <BatteryManager.h>
      
      const int BatteryType = 1; // 1 for 1S LiPo, 2 for 2xAA
      const uint8_t BatterySensorPin = A0;
      const float VoltageDividerCalibration = 1; // default 1, can be calibrated by measurement
      
      BatteryManager bms;
      
      void setup() {
        // put your setup code here, to run once:
        Serial.begin(115200);
        bms.begin(BatteryType, BatterySensorPin,VoltageDividerCalibration);
      }
      
      void loop() {
        // put your main code here, to run repeatedly:
        Serial.print("Voltage: ");
        Serial.println(bms.reportVoltage());
        Serial.print("Percent: ");
        Serial.println(bms.reportPercent());
        delay(3000);
      }
      

      header:

      /*
      * Battery Manager
      */
      
      #ifndef BatteryManager_h
      #define BatteryManager_h
      
      #include <Arduino.h>
      
      class BatteryManager {
      	public:
              BatteryManager();
                      void begin(int BatteryType, uint8_t SensePin, float Compensation);
      		int reportPercent();
      		float reportVoltage();
      	private:
      		int _BatteryType; //1 for 1S LiPO, 2 for 2x AA
      		uint8_t _SensePin;
                      float _Compensation;
      		float Battery_Min_V;
      		float Battery_Max_V;
      		float Battery_Sense_Pin_Resolution;
      };
      #endif
      

      cpp

      #include <Arduino.h>
      #include <BatteryManager.h>
      
      BatteryManager::BatteryManager() { }
      
      void BatteryManager::begin(int BatteryType, uint8_t SensePin, float Compensation)
      {
          _SensePin = SensePin;
          _Compensation = Compensation;
          pinMode(_SensePin, INPUT);
          // Battery use the 1.1 V internal reference
          #if defined(__AVR_ATmega2560__)
              analogReference(INTERNAL1V1);
          #else
              analogReference(INTERNAL);
          #endif
          int firstRead = analogRead(_SensePin);
          // check battery type and feed related variables
          if (BatteryType == 1) {
                  /* LiPo voltage need to be measured up to 4.2V hence using internal ADC ref of 1.1V,
                  *  divider across battery needs to be 1M, 330K, 
                  *  which allows a range of 0 to ((1e6+330e3)/330e3)*1.1 = 4.433 Volts
                  *  resolution: 4.4333/1023 = Volts per bit = 0.004333659
                  *  sense point can be bypassed with 0.1 uF cap to reduce noise at that point
                  *  LiPo is full @ 4.2V and risks damage below 3.3v
                  *  => LiPo usable range is 3.3 to 4.2 volts so the goal is to report
                  *  100% @ 4.2 volts
                  *  0% @ 3.3 volts
                  */
                  Battery_Min_V = 3.3;
                  Battery_Max_V = 4.15;
                  Battery_Sense_Pin_Resolution = 4.333659; //mv per bit
          }
           if (BatteryType == 2) {
                  /* 2 x AA Alkaline voltage need to be measured up to 3V hence using internal ADC ref of 1.1V,
                  *  divider across battery needs to be 1M, 470K, 
                  *  which allows a range of 0 to ((1e6+470e3)/470e3)*1.1 = 3.44 Volts
                  *  resolution: 3.44/1023 = Volts per bit = 0.003363075
                  *  sense point can be bypassed with 0.1 uF cap to reduce noise at that point
                  *  AA is normally leak proof down to 0.7V, I add an extra 0.1V to avoid any issue
                  *  => AA usable range is 1.5 to 0.8 volts so the goal is to report
                  *  100% @ 2x1.5 = 3 volts
                  *  0% @ 2x0.8 = 1.6 volts
                  */
                  Battery_Min_V = 1.6;
                  Battery_Max_V = 3;
                  Battery_Sense_Pin_Resolution = 3.363075; //mv per bit
          }
      }
      
      int BatteryManager::reportPercent() {
          // get the battery Voltage
          int sensorValue = analogRead(_SensePin);
          Serial.println(sensorValue);
      	float batteryV  = sensorValue * Battery_Sense_Pin_Resolution * _Compensation / 1000;
      	// map to 0 -- 100 according to boundaries
      	// need to multiply voltages by 10 as map function processes long variables
      	return map(10*batteryV,10*Battery_Min_V, 10*Battery_Max_V, 0, 100);;
      }
      
      float BatteryManager::reportVoltage() {
          // get the battery Voltage
          int sensorValue = analogRead(_SensePin);
          Serial.println(sensorValue);
      	return sensorValue * Battery_Sense_Pin_Resolution * _Compensation / 1000;
      }
      
      Michiel van der WulpM Offline
      Michiel van der WulpM Offline
      Michiel van der Wulp
      wrote on last edited by
      #2

      @thierryd Nice idea.

      Two remarks:

      You write in the cpp file:

      if (BatteryType == 2) {
      /* LiPo voltage ...

      You probably mean here "AA voltage"

      The AA batteries you talk about are Alkaline (not rechargeable)?
      The values are different for NiMH rechargeable (which I always use).

      1 Reply Last reply
      0
      • ? Offline
        ? Offline
        A Former User
        wrote on last edited by A Former User
        #3

        Thank you for your answer, indeed there's a mistake in the comment, I'll edit that right away!
        Yes for AA i mean Alkaline, I implemented the "battery type" feature even if I'm not yet using it, as I currently only power my gadget with LiPo cells. But as it is explained well enough (I hope), anybody can add his battery type in the code! I guess for NiMH boundaries would be 0.9v to 1.3v

        1 Reply Last reply
        0
        • skywatchS Offline
          skywatchS Offline
          skywatch
          wrote on last edited by
          #4

          I chose a different approach to this problem (but only with 1 power supply).

          That was to replace the resistor pair of 1M0 and 470K with 9M1 and 0.5M preset (trimmer). This reduces the current flow by about 90%+ and by adjusting the preset I can 'calibrate' it to 100%. Changing batteries doesn't seem to require retweeking if the same type are used.

          I even did a little sketch to load to the arduino to calibrate the battery reading before loading the main sketch.

          So far it is working well for me.

          1 Reply Last reply
          0
          Reply
          • Reply as topic
          Log in to reply
          • Oldest to Newest
          • Newest to Oldest
          • Most Votes


          14

          Online

          11.7k

          Users

          11.2k

          Topics

          113.0k

          Posts


          Copyright 2019 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
          • OpenHardware.io
          • Categories
          • Recent
          • Tags
          • Popular