Tuesday, March 31, 2015

Buttons, pushbuttons and debouncing story




     Today subject might look a trivial one but is not. At all. I will try to keep it as easy
to understand as possible without too much "behind the scene" theory.

     Contact bounce is a common problem with mechanical and electromecanical switches, relays, solenoids, etc.
  Switch contacts are usually made of springy metals. When the contacts strike together, their momentum and elasticity act together to cause them to bounce apart one or more times before making steady contact. The result is a rapidly pulsed electric current instead of a clean transition from zero to full current.

 But what happens during the bounce? Every bounce of every switch is different, a non deterministic function, a totally random event. Many produce only high speed hash till a solid one or zero appeared. Others can generate a serious pulse train of discernible logic levels that can give nightmares to the most sophisticated software debounce routine.

Ugly Bouncing Button - pulse train


   The effect is usually unimportant in power circuits, but causes problems in some analogue and logic circuits that respond fast enough to misinterpret the on‑off pulses as a data stream or change of the input logic level.

   They are many options and techniques that can solve this problem, some of them software based, some pure hardware. Few examples:

1. RC Filter Debouncing

   The RC filter slows down the signal transitions generated by the switch so the each button press gives one slow edge.  It is usually best to follow the RC filter stage with a Schmitt trigger buffer. Schmitt Trigger, which is simply an inverter equipped with hysteresis, further limits the switch bouncing.


RC Filter with Schmitt Trigger on output


2. Hardware - Dedicated Integrated Circuits

    Another way to debounce switches in hardware is to take advantage of application-specific integrated circuits.  Semiconductor manufacturers such as Maxim Integrated offer switch debouncers like the MAX6816 in very small packages, with built-in ESD protection. These parts cost a few dollars, depending on the purchasing volume. Digikey example : MAX6816. Although they are extremely easy to use, they are more expensive and offer less flexibility than a custom tailored solution.


3. Software routines, time delay 

   This is accomplished by inserting, depending of the pushbutton behaviour, a 20 to 50ms lockout delay in the function responding to port pin changes. The delay prevents the MCU from responding to the multiple switch transitions related to bouncing. The value should be choosen in such a way that is not affecting the true, real, switch transitions created by a true switch event. Maximum desired valid switching speed should also be determined for proper defining of the process.


   From my experience I think the best option is a combination of both Hardware and Software sides, so, what we will study it's a combined solution, a First order Low Pass Filter implemented in Hardware combined with Software Interrupt trigger routines on falling/rising edge. It's a simple setup and the results are great.

   Don't understand it wrong: it's no technique or solution for a piece of crap contact! What I have learned after some horror stories with switches and push buttons is that no matter the supplier, spend 5-10-15 minutes, take few from the batch, study their behavior and characterize them on the Oscilloscope! It's a truly life saver, no joke at all!


Let's continue with our choosen option.  

What we will need:
  •  CBDB Board
  •  USB adapter (take a look on Part 1 for details how to connect them together)
  •  RC Filter as described below 
  •  LED module
  •  Tested Push button

 For programming and uploading the driver and the software we will continue to use the LuaUploader as before.



 1. HARDWARE
 
First order RC Low pass filter

   One simple low-pass filter circuit consists of a resistor in series with a load, and a capacitor in parallel with the load. The capacitor exhibits reactance, and blocks low-frequency signals, forcing them through the load instead. At higher frequencies the reactance drops, and the capacitor effectively functions as a short circuit. The combination of resistance and capacitance gives the time constant of the filter:

   The break frequency, also called the turnover frequency or cutoff frequency (in hertz), is determined by the time constant:

or equivalently (in radians per second):

   This circuit may be understood by considering the time the capacitor needs to charge or discharge through the resistor:
  • At low frequencies, there is plenty of time for the capacitor to charge up to practically the same voltage as the input voltage.
  • At high frequencies, the capacitor only has time to charge up a small amount before the input switches direction. The output goes up and down only a small fraction of the amount the input goes up and down. At double the frequency, there's only time for it to charge up half the amount.

    Let's see on the Osciloscope how the value of the capacitor C can affect the rising time and what's the effect on the boucing event.
 
C = 10 nF

C = 100 nF

     So, how big should be the capacitor C? It really depends on the specific application and also a lot on the quality of the pushbutton contacts but for a decent quality human pressed pushbutton a value between 10nF and 100nF might be the answer.



2. SOFTWARE

2.1 Init 

  stat="No key press"    -- initial status
  outpin=3                       -- Select output pin - GPIO0
  gpio.mode(outpin,gpio.OUTPUT)
  inpin=6                        -- Select input pin - GPIO12
  gpio.mode(inpin,gpio.INT,gpio.PULLUP)  -- attach interrupt to inpin, activate internal PULLUP



2.2 Trigger functions

   This 2 functions below are the interrupt callback functions used for push button status detection. A small delay added to "smooth" even more the readout from the pushbutton. Most of the time not necessary as the RC filter combined with the smart change of the trigger activation from falling/rising edge is enough. As this time we use the "Ugly Bouncing Button" (see picture above - worst case scenario) extra delay is added.

2.2.1 Trigger functions

  function pressed()
      print("Key Pressed!")                       -- print status
      st7032i:lcd_setCursor(1,1)               -- set cursor pos LCD
      st7032i:lcd_write("Key Pressed!") 
-- print status LCD
       stat = "ON"        
      gpio.write(outpin,gpio.HIGH)           -- Led ON - Motion detected
      tmr.delay(10)                                      -- time delay for switch debounce                     
      gpio.trig(inpin,"up",released)            -- change trigger on falling edge
      return stat
  end
 

  function released()
       print("Key Released!")
       st7032i:lcd_setCursor(1,1)
       st7032i:lcd_write("Key Released!")
       stat = "OFF"
       gpio.write(outpin,gpio.LOW)   -- Led OFF
       tmr.delay(10)
      gpio.trig(inpin,"down",pressed)  -- trigger on rising edge
      return stat
  end



For testing, just save the code on ESP as 'button_test.lua', restart ESP and run:

        -- INIT LCD
         require('st7032i') -- I suppose you have already uploaded st7032i module from previous articles
         sda, scl = 2, 1
         st7032i:init_i2c(sda, scl)
         st7032i:init_LCD()

         require('button_test')                                --call for new created button Module
         gpio.trig(inpin,"down",pressed)  -- trigger activated on rising edge


Repeatedly quick switching with RC filter in place
 




     As you can see from the test above, the First order Low Pass Filter combined with Interrupt Trigger on falling/rising edge technique gives a very clean response over a broad range of key pressing speed/pressure.



Wednesday, March 25, 2015

Mailbag Arrival !! New ESP8266 Adapter board



New goodies hit my MailBox, this time from Singapore :



   Let's see what's inside.
  • Short but nice documentation including, schematics, pinout, configuration:

   YES! It's a new breadboard adapter for ESP-07 or ESP-12 ESP8266 WiFi module, designed by
    Baoshi 
  • a box containing the module nice packed in antistatic bag.


  • Actual module zise vs. the printed A4 documentation
ESP Adapter Module Pinout

A closer look:

TOP
Bottom
Onboard 3.3V power regulator - AMS1117


ESP Adapter board modules are about16mm tall, easily occupies 6 rows (3 rows on each side) on a Breadboard:



Features

  • Easy breakout of all ESP07/12 pins
  • Custom designed pin headers take minimum real-estate on breadboard
  • Plug-n-play solution. No external pull-up / pull-down resistor necessary
  • One button reset/program mode selection (short press for reset, long press to enter program mode)
  • On-board 3.3v regulator with appropriate heatsink
  • On-board UART (UART0) connector with FTDI Basic compatible pinout for easy programming and debugging

All the shematics and related informations are released under CC-0 Licence and can be found on GitHub: https://github.com/baoshi/ESP-Breakout

ESP Adapter Board Schematic

    One thing that definitely worth to mention is the clever way to combine RST and GPIO-0 pins signals to obtain the desired boot sequence modes during power on or reset with just one switch (SW1)

   How it works:

   During idle state, internal pull-up in the ESP8266 RESET pin turns on Q1. Q2 cut off so GPIO0 remains high due to GPIO0 internal pull-up. At the same time, C1 discharges from R2 and Q1. When user presses SW1, RESET goes low immediately. Meanwhile, Q1 turns off and 3.3V power charges C1 through R1 and R2. If user releases SW1 quickly and the voltage across C1 has not reached Q2′s threshold voltage, Q2 remains off and ESP8266 enters normal running mode. However if user holds SW1 long enough before releasing, Q2 will turn on, pull GPIO0 low. At the moment user releases SW1, RESET goes high but GPIO0 will be held low for a while due to C1 have to discharge through R2 and Q1. The choice of C1 and R2 are such that it keeps GPIO0 low long enough for ESP8266 to enter program mode."

SW1 Select circuit

  Different boot modes during power on or reset:

  Boot Mode   CH_PD   GPIO15   GPIO0
  Run firmware   High   Low   HiZ (Internal P-UP)
  Flash firmware   High   Low    Low


  Let's run a first test on it !

  Plug in the On-board UART (UART0) connector the USB adapter, 74880bps, 8N1, no handshake, choosing the right corresponding port. Be sure that is a 3V compatible one!! 5V logic levels might hurt badly your ESP8266 Module!

ESP8266 Module Boot message

It's Allive !! :)



 Let's burn some LUA flavour on it as explained previously for CBDB DevBoard and run some more tests.

NodeMcu Programming successful


For programming and uploading the software we will continue to use the LuaUploader as before:



Blinkie is BACK :)

And a short video showing the NodeMCU Firmware upload process and first run Blinkie test:







Monday, March 23, 2015

Display Time!! ST7032i - I2C LCD Display Driver



   One of the desired and also needed things in many projects is the availability of a local display to be able to directly see messages, values, results, etc. What we will need to be able to easy interface it with ESP8266 module is a 3V logic level compatible one and if it has genuine I2C interface even better for us as less data lines will be used and will keep our CBDB Dev Board I2C bus consistent.

   A most common type of available I2C displays are the ones based on ST7032/i chip. You can find them in many flavours, from very cheap eBay ones to very expensive industrial/mil grade ones. The one used in this project it's a good quality, high contrast/direct sunlight midrange one. Cannot say exactly the price as it's old stock and was ordered a time ago in big quantities, but somewhere around 8-9$. If is showing interest I can ask supplier for an updated price.


ST7032i I2C 2x16 COG LCD Display

    ST7032i is the I2C interface variant of the ST7032 dot-matrix liquid crystal display controller, can display alphanumeric, Japanese kana characters and symbols and it can be configured to drive a dot-matrix liquid crystal display under the control of a 4-bit, 8-bit or 3/4-line serial interface
microprocessor.

  FEATURES :

  •  5 x 8 dot matrix possible
  •  Low power operation support: 2.7 to 5.5V
  •  Range of LCD driver power: 3.0 to 7.0V
  •  4-bit, 8-bit, serial MPU or 400kbits/s fast
  •  I2C-bus interface - ST7032i
  •  80 x 8-bit display RAM (80 characters max.)
  •  10,240-bit character generator ROM for a total of 256 character fonts(max)
  •  64 x 8-bit character generator RAM(max)
  •  16-common x 80-segment and 1-common x
  •  80-segment ICON liquid crystal display driver
  •  16 x 5 –bit ICON RAM(max)
  •  Wide range of instruction functions: Display clear, cursor home, display on/off, cursor on/off,
     display character blink, cursor shift, display shift, double height font
  •  Automatic reset circuit that initializes the controller/driver after power on and external reset pin
  •  Internal oscillator(Frequency=540KHz) and external clock
  •  Built-in voltage booster and follower circuit (low power consumption )
  •  Com/Seg direction selectable
  •  Multi-selectable for CGRAM/CGROM size Instruction compatible to ST7066U and KS0066U
     and HD44780
  •  Available in COG type

   As you can see from the Features list above the ST7032 is suitable for low voltage supply (2.7V to 5.5V) and is perfectly suitable for any portable product which is driven by the battery and requires low power consumption. Exactly what we are looking for our 3V only ESP8266 module.

Please see ST7032 Datasheet for more details.


  PINOUT :

Default schematic for Vdd = 3V  usage


What we will need:
  • CBDB Board
  • USB adapter (take a look on Part 1 for details how to connect them together)
  • ST7032i LCD Module from above

CBDB DevBoard with ST7032i I2C LCD on Expansion port

For programming and uploading the driver and the software we will continue to use the LuaUploader as before.

Driver implementation:

1. Init I2C interface:

      address = 0x3E
      id = 0

      init_i2c = function (self, sda, scl)
        i2c.setup(self.id, sda, scl, i2c.SLOW)
     end


 
2. Init LCD

    Necessary setup steps for proper initialising the LCD Display :


Init LCD Steps

     init_LCD = function (self)
        self:lcd_command(0x38);      --
function set  basic
        tmr.delay(300);
        self:lcd_command(0x39);  
   -- function set extended
        tmr.delay(300);
        self:lcd_command(0x14);     
-- internal OCS frequency adjustment
        tmr.delay(300);
        self:lcd_command(0x69);      --
contrast set low nible
         tmr.delay(300);
        self:lcd_command(0x54);      --
contrast set high nible / icon / power
         tmr.delay(300);
        self:lcd_command(0x6f);       -- 
follower control
         tmr.delay(200000);
        self:lcd_command(0x0c);      --  display on
        tmr.delay(300);
        self:lcd_command(0x01);      -- clear display
        tmr.delay(350000);
        self:lcd_command(0x06);      -- entry mode set
        tmr.delay(300);
        self:lcd_command(0x02);      -- home
        tmr.delay(1000000);
     end 


3. I/O Basic and LCD Instruction functions:


  3.1 - Send I2C data :

     send_i2c = function(self, value, mode)
         i2c.start(self.id)
         i2c.address(self.id, self.address, i2c.TRANSMITTER)
         i2c.write(self.id, mode)
         i2c.write(self.id, value)      
         i2c.stop(self.id)  
     end


  3.2 - LCD Command

     lcd_command = function(self, value)
        self:send_i2c(value, 0x00)
     end




  3.3 -  LCD Write

     lcd_write = function(self, value)
        self:send_i2c(value, 0x40)
     end


  3.4 -  LCD Clear

     lcd_clear = function(self)
        self:lcd_command(0x01)
        tmr.delay(350000)
     end

  

 3.5 -  LCD SetCursor

     lcd_setCursor = function(self, col, row)
        row_offsets = { 0x00, 0x40, 0x14, 0x54 }
        if ( row > 2 ) then
           row = 2-1   
        end
        self:lcd_command(bit.bor(0x80,(col + row_offsets[row])))
        tmr.delay(300)
     end




For testing, just save the code on ESP as 'st7032i.lua', restart ESP and run:

     require('st7032i')                                --call for new created ST7032i Module Driver
     sda, scl = 2, 1                                    -- declare your I2C pinout
     st7032i:init_i2c(sda, scl)                   -- init I2C Bus
     st7032i:init_LCD()                            -- init LCD. See Datasheet for Reg Values calculation

    -- first test "Hello World!"

     st7032i:lcd_clear()                            -- Clear LCD Instruction
     st7032i:lcd_setCursor(0,1)               -- Set Cursor position(col, row) 
LCD Instruction

     st7032i:lcd_write("Hello World!")   -- Print String "Hello World" at set location

      -- second test - 2 lines print           
      st7032i:lcd_setCursor(2,1)               -- Set Cursor position(col, row)  LCD Instruction
      st7032i:lcd_write("First Line")        -- Print String "" at set location
       st7032i:lcd_setCursor(2,2)              -- Set Cursor position(col, row)  LCD Instruction
      st7032i:lcd_write("Second Line")     -- Print String "" at set location



Run "Hello World!" test

Hello World!
2 lines test



  For printing also our live data values on LCD we will need an additional function to convert data in ascii character codes:

  3.6 -  LCD Print Value

     lcd_print = function(self,col,row,val)
        for i=1,string.len(val),1 do
          self:lcd_setCursor(col+i-1,row)
          self:lcd_write(string.sub(val,i,i))
          tmr.wdclr()
        end
     end

 

For testing, just save again the code on ESP as 'st7032i.lua', restart ESP and run:

     require('st7032i')                                --call for new created ST7032i Module Driver
     sda, scl = 2, 1                                    -- declare your I2C pinout
     st7032i:init_i2c(sda, scl)                   -- init I2C Bus
     st7032i:init_LCD()                            -- init LCD. See Datasheet for Reg Values calculation

     st7032i:lcd_clear()                            -- Clear LCD Instruction
     st7032i:lcd_setCursor(0,1)               -- Set Cursor position(col, row) 
LCD Instruction

     st7032i:lcd_write("Hello World!")    -- Print String "Hello World" at set location


     value=12.739                                     -- our value to print
     st7032i:lcd_print(0,2,value)              -- LCD Print(col, row, value) function call



Print data value on LCD
Test Video : 




 



Wednesday, March 18, 2015

Internal ADC - ESP8266

----------------------------------  UPDATE  --------------------------------------

For a ADC Input Frontend with Auto-range capabilities in the 0-40V Input range take a look also at the new ADC Input related article

---------------------------------  UPADTE  ----------------------------------------

Added also a new example for a 0-5V input range with Voltage divider and LSB calculation, "the easy way": ESP8266 internal ADC 2 - the easy way example


 ---------------------------------------------------------------------------------------


    After talking in the previous article about DAC (Digital to analog conversion) let's take a look also to the ADC (Analog to Digital Conversion) process story.

   What is the purpose of an ADC ?
    The ADC translates an analog input signal to a digital output value representing the size of the input relative to a reference.

   One of the good news about is that ESP8266 has an ADC inside and at least ESP-07, ESP-12, Olimex MOD-WIFI-ESP8266-DEV modules have the ADC Pin available.



ESP8266 - ESP-07 Module

Olimex MOD-WIFI-ESP8266-DEV

   Some not so good news about ESP8266 internal ADC, at least until now:
  •   Documentation available it's at a very poor level. More like a leaflet combined with a marketing presentation. If you were able to find anything more than this one please feel free to share.  
  •  Only one ADC, one analog input pin, resolution probably determined by the ESP8266 community as been a 10 Bit one thru trial and error or some internal data leakage and has a not so clear range from 0 to about 1V. No other technical specifications. None. Engineering fun :)
  •  Should I ask about the voltage reference? :)

    So, the legitimate Question arrived: it is any good for anything or just a fancy added function for marketing purposes ? Well...will see below

    The first simple application that has come in my mind was to use the new builded Li-ion Battery Module to power up ESP8266 module and in the same time to read the Li-ion Cell voltage thru a long period of time. A voltage logger for the Li-ion Cell if you want. 10 Bits resolution must be enough for the purpose of the experiment, to see some trending data for the Li-ion Cell.


What we will need:


General considerations :

     As maximum voltage input is expected to be 1V only and because our Li-ion Cell fully charged voltage goes up to 4.2-4.3V it's obviously that we need to find a way to "translate" the voltage domain between 0-4.3V to 0-1V. They are many different techniques available for doing that but the easiest one and the one that we will use here is the Resistive Voltage Divider (RVD).

    A RVD (also known as a potential divider) is a passive linear circuit that produces an output voltage (Vout) that is a fraction of its input voltage (Vin). Voltage division is the result of distributing the input voltage among the components of the divider.

  We will use for our project the simpler example of a voltage divider: two resistors connected in series, with the input voltage applied across the resistor pair and the output voltage emerging from the connection between them.

Voltage divider schematic and Vout formula

The result:
Voltage divider


  Few observations about:
  • use high quality resistors, 1% or less with as small as possible ppm/C. In this case were used metal film resistors, 1%, 50ppm/C. Try to avoid carbon ones.
  • avoid long wires that can produce itself a voltage drop due to internal resistance. For a quick explanation and calculation take a look here and for PCB traces here
  • yes, I know, pedants might say breadboard is not a good idea for something like that but believe me, in this case, for a quick test, will make no difference. It's a 10 Bit ADC and we are doing trending measurement.

  Let's find out what resistor values we will need for our RVD:
  • Vinmax = 4.3 V
  • Voutmax = VADCin_max = 1V
  •  Vout=Vin*R2/(R1+R2)
   From the resistor ratio calculation choosed values are: R1=33K and R2=10k. You can choose also other values as long as you keep accurate the ratio between, better go upper that that. 330k and 100k should give the same result for example.


Software implementation

For programming CBDB Board and uploading the driver and the software we will continue to use the LuaUploader as before. 


We will implement 3 different type of ADC Read functions,  to see if any notable difference:

 1. READ_ADC function: 

       function readADC()                 -- simple read adc function
           ad = 0
          ad=ad+adc.read(0)*4/978   -- calibrate it based on your voltage divider AND Vref!
          print(ad)
         return ad
     end



 2. READ_AVG ADC function: 

      function readADC_avg()                 -- read 10 consecutive values and calculate average.
           ad1 = 0
           i=0
           while (i<10) do
                ad1=ad1+adc.read(0)*4/978 --calibrate based on your voltage divider AND Vref!
                --print(ad1)
                i=i+1
           end
           ad1 = ad1/10
           print(ad1)
           return ad1
      end



 2. READ_ DCM function:

    As probably Read_ADC() and Read_AVG() are pretty straigh forward things I will not insist on them. Read_DCM() function it's a little bit special, as is using a special technique called oversampling and decimation. 

    The theory behind oversampling and decimation is rather complex, but using the method is fairly easy. The technique requires a higher amount of samples. These extra samples can be achieved by oversampling the signal. For each additional bit of resolution, n, the signal must be oversampled four times. To get the best possible representation of a analog input signal, it is necessary to oversample the signal this much, because a larger amount of samples will give a better representation of the input signal, when averaged.

   That means that in our case if we want to increase resolution from 10 to 12 bit we will need to take 16 samples.

    Another requirement to make this method work properly is that the signal-component of interest should not vary during a conversion. However another criteria for a successful enhancement of the resolution is that the input signal has to vary when sampled. This may look like a contradiction, but in this case variation means just a few LSB. The variation should be seen as the noise-component of the signal. When oversampling a signal, there should be noise present to satisfy this demand of small variations in the signal.

   As a conclusion from other ADC related work, IF Read_ADC() will give us very good and accurate results Read_DCM() will go bad and vice-versa. 

     function readADC_dcm()
         ad2 = 0
         i=0
         while (i<16) do
               ad2=ad2+adc.read(0)
               --print(ad2)
               i=i+1
          end
          ad2 = bit.rshift(ad2, 2)
          ad2= ad2*0.001020880 -- 12Bit step value-calibrate based on your voltage divider AND Vref!
          print(ad2)
          return ad2
     end


Some first time run results:




Not bad at all!


Adding a Web interface it's an easy task :

srv=net.createServer(net.TCP)
  srv:listen(80,
     function(conn)
           conn:on("receive",function(conn,payload)
            --print(payload)
           conn:send("HTTP/1.1 200 OK\n\n")
           conn:send("<META HTTP-EQUIV=\"REFRESH\" CONTENT=\"5\">")
           conn:send("<html><title>LOG Server - ESP8266</title><body>")
           conn:send("<h1>Data Logger Server - ESP8266</h1><BR>")
           conn:send("Voltage    :<B><font color=red size=4>"..string.format("%g",ad)..

                            " V</font></b><br>")
           conn:send("Voltage AVG:<B><font color=red size=4>"..string.format("%g",ad1)..

                            " V</font></b><br>")
           conn:send("Voltage DCM:<B><font color=red size=4>"..string.format("%g",ad2)..

                            " V</font></b><br>")
           conn:send("<BR><BR><BR>Node.HEAP     : <b>" .. node.heap() .. "</b><BR>")
           conn:send("IP ADDR    :<b>".. wifi.sta.getip() .. "</b><BR>")
           conn:send("TMR.NOW    :<b>" .. tmr.now() .. "</b><BR<BR><BR>")
           conn:send("</html></body>")
           conn:on("sent",function(conn) conn:close() end)
           conn = nil    
      end)
end)


Test Video:


 

Monday, March 16, 2015

Mailbag arrival! New Battery solution for ESP8266 Modules!

================== W A R N I N G ! ! =================
Li-Ion batteries are very dangerous if not handled properly.
Use them only with proper protection circuits and chargers.
DO NOT OVER CHARGE / BURN / OPEN Li-Ion Bats
     Using any of the informations available on esp8266-projects.com
 is on your own risk !!
===============================================


   Finally Arrived! This was a long awaited one. Postal service at it's best :)

   I was asked for a more compact and easy to recharge battery pack solution for the ESP8266 Modules and with the new items arrived in the MailBox, here it is:


ESP8266 Battery Module

What we will need:
  • LGDB318650 - Rechargeable 3,7V/2600mAh Li-ion Cell 
  • 18650 Cell holder
  • Li-ion Charger/Monitor with protection
  • Asorted wires - choose your desired color but red/black, blue/white standard coding with be better :)

Li-ion Cell and holder
   As the LGDS318650 Li-ion Cells does not have any internal protection been bare ones - usual find in laptops battery packs - we will need to use a charger/monitor with some sort of protection mechanism.

Forget the Ni-Mh abuse if you want to run your Li-ion cells properly and safely for a long lifespan.  Li-ion Cells shouldn't be charged/discharged/drained more than the recommended values to prolong its life and even to avoid a nasty explosion or fire!


The module from the picture below it's covering decently all the required needs:
  • USB compatible constant-current/constant-voltage charger - linear
  • Monitor for overcharge/overdischarge and/or overcurrent
  • High speed MOSFET Switching protection mechanism
 
Li-ion Cell Charger/Monitor with protection


   It is based on TP4056 1A Standalone Linear Li-lon Battery Charger with Thermal Regulation chip

   The TP4056 is a complete constant-current/constant-voltage linear charger for single cell
lithium-ion batteries. Its SOP package and low external component count make the TP4056
ideally suited for portable applications. Furthermore, the TP4056 can work within USB and wall
adapter.

   No blocking diode is required due to the internal PMOSFET architecture and have prevent to
negative Charge Current Circuit. Thermal feedback regulates the charge current to limit the die
temperature during high power operation or high ambient temperature. The charge voltage is
fixed at 4.2V, and the charge current can be programmed externally with a single resistor. The
TP4056 automatically terminates the charge cycle when the charge current drops to 1/10th the
programmed value after the final float voltage is reached.

    TP4056 Other features include current monitor, under voltage lockout, automatic recharge and
two status pin to indicate charge termination and the presence of an input voltage.
 
TP4056 - SO8 package

  
 FEATURES:

  •  Programmable Charge Current Up to  1000mA 
  • No MOSFET, Sense Resistor or Blocking  Diode Required
  • Complete Linear Charger in SOP-8 Package for Single Cell Lithium-Ion Batteries
  • Constant-Current/Constant-Voltage
  • Charges Single Cell Li-Ion Batteries Directly from USB Port
  • Preset 4.2V Charge Voltage with 1.5% Accuracy
  • Automatic Recharge
  • Two Charge Status Output Pins
  • C/10 Charge Termination
  • 2.9V Trickle Charge Threshold (TP4056) 
  • Soft-Start Limits Inrush Current
   For more details please see TP4056 Datasheet

   TP4056 is accompanied with DW01-G battery protection IC.

   DW01-G is designed to protect lithium-ion/polymer battery from damage or degrading the lifetime due to overcharge,overdischarge, and/or overcurrent for one-cell lithium-ion/polymer battery powered systems, such as cellular phones.

Protection circuit - DW01-G + Mosfet switch
   DW01-G has an accuracy of ±50mV overcharging detection voltage that ensures safe and full utilization charging. Also the very low standby current drains little current from the cell while in storage.

FEATURES:
  • Reduction in Board Size due to Miniature SOT-23-6 Package
  • Ultra-Low Quiescent Current at 3μA (Vcc=3.9V)
  • Ultra-Low Power-Down Current at 0.1μA (Vcc=2.0V)
  • Precision Overcharge Protection Voltage 4.25V ± 50mV
  • Load Detection Function during Overcharge Mode
  • Two Detection Levels for Overcurrent Protection
  • Delay times are generated by internal circuits. No external capacitors required
  Battery Protection Swithing is done with 8205A Mosfet. The ML8205A uses advanced trench technology to provide excellent RDS(ON), low gate charge and operation with gate voltages as low as 2.5V. This device is suitable for use as a Battery protection or in other Switching application.

We will use this battery solution setup in the future for our battery powered projects.

Stay tuned for more about soon!