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.
  • TmasterT Offline
    TmasterT Offline
    Tmaster
    wrote on last edited by Tmaster
    #1

    Hello. like i told on other topics , i'm finishing my first "mysensor" conected to vera lite ,battery powered (2xtermistor+light sensor) that i will present later on forum soon as its working. its all working except battery percentage.
    Second the example i follow,it says:

     // 1M, 470K divider across battery and using internal ADC ref of 1.1V
       // Sense point is bypassed with 0.1 uF cap to reduce noise at that point
       // ((1e6+470e3)/470e3)*1.1 = Vmax = 3.44 Volts
       // 3.44/1023 = Volts per bit = 0.003363075
       float batteryV  = sensorValue * 0.003363075;
       int batteryPcnt = sensorValue / 10;
    

    this is part of "mysensor battery sensor example"

    Its a simple voltage divider and calculation of volt per bit and after that send percentage to my vera.
    BUT i'm using li-ion batteries , 3.6v cell, 2 cell=7.2v or +-8.2v on full charge.
    AND there comes my problem.
    Where this calculation make reference to what is 100%(8.2v) and what is 0%(6.4v)?
    it only will say 0% its a flat ...Dead...li-ion cell:/

    Thank you

    i'm a arduino fan .Even sometimes don't undestanding how to use it :P

    1 Reply Last reply
    0
    • mfalkviddM Offline
      mfalkviddM Offline
      mfalkvidd
      Mod
      wrote on last edited by mfalkvidd
      #2

      The reference tells the chip what should be regarded as maximum. So if you set 1.1V as reference, any voltage above 1.1V will result in a reading of 1023.

      You either need to adjust your voltage divider so the "middle" point is at 1.1V or below (with 8.2V you could use something like 1Mohm + 120kohm), or use a different method (like the "secret" method). You could also switch to using the "standard" reference (of 5V) and your 1M+470k voltage divider.

      Edit: The "secret" (stupid name!) method required that you don't use a voltage regulator, so it is not applicable in your case. Go for 1M+120k voltage divider or use the standard reference.

      1 Reply Last reply
      1
      • TmasterT Offline
        TmasterT Offline
        Tmaster
        wrote on last edited by Tmaster
        #3

        Ok. I use vreg. Its waste less battery than stepup modules(second i read) .
        But what about Set the 0% .0 will be aa flat cell,right?

        I already use reference as default(3.3v on my promini)

        i'm a arduino fan .Even sometimes don't undestanding how to use it :P

        1 Reply Last reply
        0
        • m26872M Offline
          m26872M Offline
          m26872
          Hardware Contributor
          wrote on last edited by m26872
          #4

          I've successfully used these calculations, resistors and voltage levels for different number of AAs in series with the 1.1V ref.

          Internal_ref=1.1V, res=10bit=2^10-1=1023, 2AA: Vin/Vbat=470e3/(1e6+470e3), 4AA: Vin/Vbat=1e6/(1e6+5e6), 3AA: Vin/Vbat=680e3/(2.5e6+680e3)
          
          Vlim = 1.1*Vbat/Vin = 6.6 V (Set to Vmax ?)
          Volts per bit = Vlim/1023 = 0.006452
          Vmin = 4.3V (Min input voltage to regulator according to datasheet. (?) )
          Vmax = 6.6V (Known or desired voltage of full batteries. If not, set to Vlim.)
          Vpercent = 100*(Vbat-Vmin)/(Vmax-Vmin)
          

          So if you use the 3.3V Arduino Pro Mini through its internal vreg, I'd set the Vmin (0%) ~1V above 3.3V i.e. 4.3V, by default. If your stuff supplied by this vreg-out is capable of going below 3.3V you could lower your Vmin, but then you have to use the 1.1V ref.
          Else, when using "high" voltages like in your case it's hard to optimize the resistors and then better to also use a higher reference, like 3.3 och 5V Vcc.

          I'd suggest you to use the 3.3V (default) reference and standard voltage divider (1M+470k). The calculation are then

          Vlim = 3.3*(1e6+470e3)/470e3 = 10.32 V
          Volts per bit = Vlim/1023 = 0.010089224434
          Vmin = 4.3V (Min input voltage to regulator)
          Vmax = 8.2V (+ some margin)
          Vpercent = 100*(Vbat-Vmin)/(Vmax-Vmin)
          

          And of course in your code, there will be something like...

          float batteryV  = sensorValue * 0.010089224434;
          int batteryPcnt = static_cast<int>(((batteryV-VMIN)/(VMAX-VMIN))*100);
          
          1 Reply Last reply
          3
          • TmasterT Offline
            TmasterT Offline
            Tmaster
            wrote on last edited by Tmaster
            #5
             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.

            i'm a arduino fan .Even sometimes don't undestanding how to use it :P

            m26872M 1 Reply Last reply
            0
            • m26872M Offline
              m26872M Offline
              m26872
              Hardware Contributor
              wrote on last edited by
              #6

              :thumbsup:

              Some people prefer to use the 'map()' function instead. It does the same job.

              1 Reply Last reply
              0
              • TmasterT Offline
                TmasterT Offline
                Tmaster
                wrote on last edited by Tmaster
                #7

                one more function that i din't know:P

                long map(long x, long in_min, long in_max, long out_min, long out_max)
                {
                  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
                }
                

                For now it will stay with voltage regulator and 7,2v (2 cells battery), but in case I want save even more battery I can use only 1 cell (3.7v) and connect it directly to vcc on my 8mhz pro mini and remove led and 3.3v regulator.

                My question is , atmel326p handle up to 5v directly on Vcc,even my 8mhz one, but what happens to my analog reference ,if i set analog reference( default ), as it is right now, and my battery fluctuate between 4.2V and 3.2V when start discharge? Reference will fluctuate as well and affect my battery measure ,right? how they handle that problem?

                i'm a arduino fan .Even sometimes don't undestanding how to use it :P

                m26872M 1 Reply Last reply
                0
                • TmasterT Tmaster

                  one more function that i din't know:P

                  long map(long x, long in_min, long in_max, long out_min, long out_max)
                  {
                    return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
                  }
                  

                  For now it will stay with voltage regulator and 7,2v (2 cells battery), but in case I want save even more battery I can use only 1 cell (3.7v) and connect it directly to vcc on my 8mhz pro mini and remove led and 3.3v regulator.

                  My question is , atmel326p handle up to 5v directly on Vcc,even my 8mhz one, but what happens to my analog reference ,if i set analog reference( default ), as it is right now, and my battery fluctuate between 4.2V and 3.2V when start discharge? Reference will fluctuate as well and affect my battery measure ,right? how they handle that problem?

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

                  @Tmaster
                  Whenever you connect your battery straight to Vcc, I can't see any reason not use the internal voltage monitoring method (as @mfalkvidd linked to above).

                  Last I heard was that 3.7V ment a high risk to kill the nRF radio module. You might want to look up how people have handled that before you proceed.

                  1 Reply Last reply
                  0
                  • TmasterT Offline
                    TmasterT Offline
                    Tmaster
                    wrote on last edited by
                    #9

                    ah! i was so focus on arduino that i forgot the radio. but i know about 3.3 v from nrf24.
                    When its powered by transformer ,i use 5v arduinos and this module for the nrf24. is v reg :
                    http://www.ebay.com/itm/New-Sale-Socket-Adapter-Module-Board-for-8PIN-NRF24L01-Wireless-Module-/191353332066?hash=item2c8d8c2162:g:QnUAAOxyBotTX0mW

                    i'm a arduino fan .Even sometimes don't undestanding how to use it :P

                    1 Reply Last reply
                    0
                    • 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


                                          6

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