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. Battery sensor measure for li-ion cells?

Battery sensor measure for li-ion cells?

Scheduled Pinned Locked Moved Development
20 Posts 5 Posters 9.6k Views 4 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.
  • L Offline
    L Offline
    LastSamurai
    Hardware Contributor
    wrote on last edited by LastSamurai
    #10

    Great information here! I was building my own method for getting battery percentage for my 2AA battery powered node and tried to understand the calculations. Here is my piece of code. What do you guys think? Everything's right?

    // define values for the battery measurement
    #define R1 = 1e6;
    #define R2 = 470e3;
    #define VMIN = 1.8;
    #define VMAX = 3;
    #define ADC_PRECISION = 1023;
    
    int getBatteryPercentage() {
    
      // read analog pin value
      int inputValue = analogRead(BATTERY_SENSE_PIN);
      
      // calculate the max possible value and therefore the range and steps
      float voltageDividerFactor = (R1 + R2) / R2;
      float maxValue = voltageDividerFactor * VMAX;
      float voltsPerBit = maxValue / ADC_PRECISION;
    
      float batteryVoltage = voltsPerBit * inputValue;
      //int batteryPercentage = ((batteryVoltage-VMIN)/(VMAX-VMIN))*100;
      int batteryPercentage = map(batteryVoltage, 0, maxValue, 0, 100);
    
      return batteryPercentage;
    }
    

    The 2 lines for the batteryPercentage should do exactly the same. Prefer the 2nd one though, it's more readable for me.

    m26872M 1 Reply Last reply
    0
    • L LastSamurai

      Great information here! I was building my own method for getting battery percentage for my 2AA battery powered node and tried to understand the calculations. Here is my piece of code. What do you guys think? Everything's right?

      // define values for the battery measurement
      #define R1 = 1e6;
      #define R2 = 470e3;
      #define VMIN = 1.8;
      #define VMAX = 3;
      #define ADC_PRECISION = 1023;
      
      int getBatteryPercentage() {
      
        // read analog pin value
        int inputValue = analogRead(BATTERY_SENSE_PIN);
        
        // calculate the max possible value and therefore the range and steps
        float voltageDividerFactor = (R1 + R2) / R2;
        float maxValue = voltageDividerFactor * VMAX;
        float voltsPerBit = maxValue / ADC_PRECISION;
      
        float batteryVoltage = voltsPerBit * inputValue;
        //int batteryPercentage = ((batteryVoltage-VMIN)/(VMAX-VMIN))*100;
        int batteryPercentage = map(batteryVoltage, 0, maxValue, 0, 100);
      
        return batteryPercentage;
      }
      

      The 2 lines for the batteryPercentage should do exactly the same. Prefer the 2nd one though, it's more readable for me.

      m26872M Offline
      m26872M Offline
      m26872
      Hardware Contributor
      wrote on last edited by
      #11

      @LastSamurai
      About this line:

      float maxValue = voltageDividerFactor * VMAX;
      

      You should use your Adc reference voltage here, not VMAX. If it's a 2AA node you probably use 1.1V internal ref.

      1 Reply Last reply
      0
      • L Offline
        L Offline
        LastSamurai
        Hardware Contributor
        wrote on last edited by LastSamurai
        #12

        Thanks! I updated the code (had some errors in the define statements and now got this:

        #include <SPI.h>
        #include <MySensor.h>  
        #include <DHT.h>  
        
        #define CHILD_ID_HUM 0
        #define CHILD_ID_TEMP 1
        #define HUMIDITY_SENSOR_DIGITAL_PIN 3
        
        // define values for the battery measurement
        #define R1 1e6
        #define R2 470e3
        #define VMIN 1.8
        #define VMAX 3
        #define ADC_PRECISION 1023
        #define VREF 1.1
        
        MySensor gw;
        DHT dht;
        unsigned long SLEEP_TIME = 300000; // Sleep time between reads (in milliseconds)
        float lastTemp;
        float lastHum;
        boolean metric = true; 
        MyMessage msgHum(CHILD_ID_HUM, V_HUM);
        MyMessage msgTemp(CHILD_ID_TEMP, V_TEMP);
        int oldBatteryPcnt = 0;
        int BATTERY_SENSE_PIN = A0;
        
        
        void setup()  
        { 
             // use the 1.1 V internal reference
          #if defined(__AVR_ATmega2560__)
             analogReference(INTERNAL1V1);
          #else
             analogReference(INTERNAL);
          #endif
        
          gw.begin();
          dht.setup(HUMIDITY_SENSOR_DIGITAL_PIN); 
        
          // Send the Sketch Version Information to the Gateway
          gw.sendSketchInfo("Humidity", "1.0");
        
          // Register all sensors to gw (they will be created as child devices)
          gw.present(CHILD_ID_HUM, S_HUM);
          gw.present(CHILD_ID_TEMP, S_TEMP);
          
          metric = gw.getConfig().isMetric;
        }
        
        void loop()      
        {  
           int batteryPcnt = getBatteryPercentage();
        
           Serial.print("Battery percent: ");
           Serial.print(batteryPcnt);
           Serial.println(" %");
        
           if (oldBatteryPcnt != batteryPcnt) {
             // Power up radio after sleep
             gw.sendBatteryLevel(batteryPcnt);
             oldBatteryPcnt = batteryPcnt;
           }
          
          // totally random test values
          gw.send(msgTemp.set(42, 1));
          gw.send(msgHum.set(42, 1));
        
          gw.sleep(SLEEP_TIME); //sleep a bit
        }
        
        int getBatteryPercentage() {
        
          // read analog pin value
          int inputValue = analogRead(BATTERY_SENSE_PIN);
          
          // calculate the max possible value and therefore the range and steps
          float voltageDividerFactor = (R1 + R2) / R2;
          float maxValue = voltageDividerFactor * VREF;
          float voltsPerBit = maxValue / ADC_PRECISION;
        
          float batteryVoltage = voltsPerBit * inputValue;
          float batteryPercentage = ((batteryVoltage-VMIN)/(VMAX-VMIN))*100;
          //int batteryPercentage = map(batteryVoltage, 0, maxValue, 0, 100);
        
          return batteryPercentage;
        }
        

        I am using 2 1.5V aa batteries, but somehow I get a percentage of 136%. Whats wrong there?
        Using the map part instead I get 100%, so some values is way to big somehow.

        m26872M 1 Reply Last reply
        0
        • L LastSamurai

          Thanks! I updated the code (had some errors in the define statements and now got this:

          #include <SPI.h>
          #include <MySensor.h>  
          #include <DHT.h>  
          
          #define CHILD_ID_HUM 0
          #define CHILD_ID_TEMP 1
          #define HUMIDITY_SENSOR_DIGITAL_PIN 3
          
          // define values for the battery measurement
          #define R1 1e6
          #define R2 470e3
          #define VMIN 1.8
          #define VMAX 3
          #define ADC_PRECISION 1023
          #define VREF 1.1
          
          MySensor gw;
          DHT dht;
          unsigned long SLEEP_TIME = 300000; // Sleep time between reads (in milliseconds)
          float lastTemp;
          float lastHum;
          boolean metric = true; 
          MyMessage msgHum(CHILD_ID_HUM, V_HUM);
          MyMessage msgTemp(CHILD_ID_TEMP, V_TEMP);
          int oldBatteryPcnt = 0;
          int BATTERY_SENSE_PIN = A0;
          
          
          void setup()  
          { 
               // use the 1.1 V internal reference
            #if defined(__AVR_ATmega2560__)
               analogReference(INTERNAL1V1);
            #else
               analogReference(INTERNAL);
            #endif
          
            gw.begin();
            dht.setup(HUMIDITY_SENSOR_DIGITAL_PIN); 
          
            // Send the Sketch Version Information to the Gateway
            gw.sendSketchInfo("Humidity", "1.0");
          
            // Register all sensors to gw (they will be created as child devices)
            gw.present(CHILD_ID_HUM, S_HUM);
            gw.present(CHILD_ID_TEMP, S_TEMP);
            
            metric = gw.getConfig().isMetric;
          }
          
          void loop()      
          {  
             int batteryPcnt = getBatteryPercentage();
          
             Serial.print("Battery percent: ");
             Serial.print(batteryPcnt);
             Serial.println(" %");
          
             if (oldBatteryPcnt != batteryPcnt) {
               // Power up radio after sleep
               gw.sendBatteryLevel(batteryPcnt);
               oldBatteryPcnt = batteryPcnt;
             }
            
            // totally random test values
            gw.send(msgTemp.set(42, 1));
            gw.send(msgHum.set(42, 1));
          
            gw.sleep(SLEEP_TIME); //sleep a bit
          }
          
          int getBatteryPercentage() {
          
            // read analog pin value
            int inputValue = analogRead(BATTERY_SENSE_PIN);
            
            // calculate the max possible value and therefore the range and steps
            float voltageDividerFactor = (R1 + R2) / R2;
            float maxValue = voltageDividerFactor * VREF;
            float voltsPerBit = maxValue / ADC_PRECISION;
          
            float batteryVoltage = voltsPerBit * inputValue;
            float batteryPercentage = ((batteryVoltage-VMIN)/(VMAX-VMIN))*100;
            //int batteryPercentage = map(batteryVoltage, 0, maxValue, 0, 100);
          
            return batteryPercentage;
          }
          

          I am using 2 1.5V aa batteries, but somehow I get a percentage of 136%. Whats wrong there?
          Using the map part instead I get 100%, so some values is way to big somehow.

          m26872M Offline
          m26872M Offline
          m26872
          Hardware Contributor
          wrote on last edited by m26872
          #13

          @LastSamurai
          If I were you I would:
          a. Measure battery voltage to know what to expect.
          b. Debug by printing out the raw sensor value 'inputValue'. (0 or 1023 likely means a hw issue).
          c. Change VMAX to 3.2, 3.3 or maxValue.
          d. Change the line

            float batteryPercentage = ((batteryVoltage-VMIN)/(VMAX-VMIN))*100;
          

          to

            int batteryPercentage = static_cast<int>(((batteryVoltage-VMIN)/(VMAX-VMIN))*100);
          
          1 Reply Last reply
          0
          • L Offline
            L Offline
            LastSamurai
            Hardware Contributor
            wrote on last edited by
            #14

            Ok I added the change, removed everything but the battery/voltage code and tried it out. Using a serial to usb adapter I got the right values.
            Then I readded the network and sleep stuff and suddenly I am getting these 136% percent again. Any idea why? Could sleeping or the network somehow interfere with the measurements?

            AWIA 1 Reply Last reply
            0
            • L LastSamurai

              Ok I added the change, removed everything but the battery/voltage code and tried it out. Using a serial to usb adapter I got the right values.
              Then I readded the network and sleep stuff and suddenly I am getting these 136% percent again. Any idea why? Could sleeping or the network somehow interfere with the measurements?

              AWIA Offline
              AWIA Offline
              AWI
              Hero Member
              wrote on last edited by
              #15

              @LastSamurai Everything is related to VMAX in your case. Have you measured the actual voltage of the batteries..? The type of battery used can explain the 136% upload-24c946fc-3ac4-4897-9bc2-b8203650a0ac

              Using the calculation below you will never get an above 100% reading ;)

              int batteryPcnt = constrain(map(batteryVoltage, VccMin, VccMax, 0, 100),0,100); // and map to the 0-100% range
              
              1 Reply Last reply
              0
              • L Offline
                L Offline
                LastSamurai
                Hardware Contributor
                wrote on last edited by LastSamurai
                #16

                The actual voltage was about 2.7-2.8V. So my values should be right?! I will do some more testing soon.

                Are you sure about constrain and map? I am pretty sure the map call already maps the values to 0..100. So no constrain needed.

                Is it possible that

                #define VMAX 3
                // has to be
                #define VMAX 3.0
                
                m26872M 1 Reply Last reply
                0
                • L LastSamurai

                  The actual voltage was about 2.7-2.8V. So my values should be right?! I will do some more testing soon.

                  Are you sure about constrain and map? I am pretty sure the map call already maps the values to 0..100. So no constrain needed.

                  Is it possible that

                  #define VMAX 3
                  // has to be
                  #define VMAX 3.0
                  
                  m26872M Offline
                  m26872M Offline
                  m26872
                  Hardware Contributor
                  wrote on last edited by
                  #17

                  @LastSamurai
                  I think you should note what the map() reference says about constrain and integer math. Try to use mV instead.

                  1 Reply Last reply
                  0
                  • L Offline
                    L Offline
                    LastSamurai
                    Hardware Contributor
                    wrote on last edited by
                    #18

                    @m26872 Thanks! For me thats strange behaviour but it seems you guys are absolutely right!
                    What do you mean mV? Using VMAX 3000 instead of 3?

                    m26872M 1 Reply Last reply
                    0
                    • L LastSamurai

                      @m26872 Thanks! For me thats strange behaviour but it seems you guys are absolutely right!
                      What do you mean mV? Using VMAX 3000 instead of 3?

                      m26872M Offline
                      m26872M Offline
                      m26872
                      Hardware Contributor
                      wrote on last edited by
                      #19

                      @LastSamurai
                      As input to map(), yes. And that goes for Vbat and Vmin as well of course.

                      1 Reply Last reply
                      0
                      • TmasterT Tmaster
                         Vpercent = 100 x (Vbat-Vmin) / (Vmax-Vmin)    ! ! ! ! ! ! ! ! ! 
                        

                        THAT IS THE WINNER CALCULATION!! is just that what i'm locking for :) but i coldn't reach by my self

                        Thank you very much.

                        m26872M Offline
                        m26872M Offline
                        m26872
                        Hardware Contributor
                        wrote on last edited by
                        #20

                        @Tmaster
                        I'd like to add a few things about the settings a Vmin and Vmax.

                        If you get a Vbat value outside of [Vmin Vmax] the calculation would give a negative result. Since it's then sent as an uint8_t, it'll not be easy read or meaningful. Due to this it's sometimes a good advice to make the interval wider, use a constraint or handle the exceptions.

                        Vmin 4.3V is a conservative limit. The APM internal vreg (ldo?) is probably working a lot lower depending on the load. You have to find out yourself.

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


                        22

                        Online

                        11.7k

                        Users

                        11.2k

                        Topics

                        113.1k

                        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