DEV Community

lee
lee

Posted on

Integrating 3.7 V Li-ion Battery Monitoring into Your Embedded Firmware

Li-ion batteries have become the standard for powering embedded devices. Whether you're building an IoT sensor node, a wearable device, or a mobile robot, there's a good chance you're using a 3.7 V lithium ion battery to keep things running.

But powering your project is only half the job. You also need to monitor your battery’s health, voltage, and behavior to ensure reliability and user safety.

If you're sourcing batteries from a trusted lithium battery manufacturer, such as Ufine Battery, you'll likely receive stable, high-quality cells. But it’s still up to you as a firmware developer to implement solid battery monitoring in your code.

3.7V Li-ion battery

This post will walk you through:

  • Why 3.7 V battery monitoring matters
  • How to read voltage levels safely
  • Code examples (for STM32 and Arduino)
  • How Ufine’s custom battery packs simplify integration

🔋 Why Monitor Your Battery?

Even the best battery will degrade over time. Voltage drops, internal resistance rises, and performance can become unstable—especially under load. By monitoring battery behavior, your firmware can:

  • Alert users before shutdown
  • Prevent deep discharge (which damages Li-ion cells)
  • Log battery health over time
  • Extend your device’s usable life

If your project goes into production, battery monitoring isn’t optional—it’s essential.

🔌 Basic Battery Monitoring Circuit

At its simplest, voltage monitoring involves connecting the battery’s positive terminal through a voltage divider to an analog input pin.

Example Circuit (For a 3.7 V Battery):

Battery + ----[R1]----+----[R2]---- GND  
                      |  
                  Analog Pin
Enter fullscreen mode Exit fullscreen mode

Choose R1 and R2 so the analog voltage doesn’t exceed your microcontroller’s ADC reference voltage (typically 3.3V or 5V).

Tip: Use resistors in the range of 10k–100k to limit current draw. For better precision, add a capacitor (~0.1μF) across R2.

📟 Firmware: Reading Battery Voltage (STM32 & Arduino)

Here’s a sample implementation for STM32 (HAL-based):

float read_battery_voltage() {
    uint32_t raw = HAL_ADC_GetValue(&hadc1);
    float v_ref = 3.3;
    float adc_max = 4095.0;
    float voltage = (raw / adc_max) * v_ref;

    // Adjust based on your resistor divider ratio
    float divider_ratio = (R1 + R2) / R2;
    return voltage * divider_ratio;
}
Enter fullscreen mode Exit fullscreen mode

And a simple version for Arduino:

float readBatteryVoltage() {
  int raw = analogRead(A0);
  float vRef = 5.0;
  float voltage = (raw / 1023.0) * vRef;

  // Assume R1 = 100k, R2 = 100k => ratio = 2
  return voltage * 2.0;
}
Enter fullscreen mode Exit fullscreen mode

Don’t forget to calibrate your readings if your board has VREF inconsistencies.

⚠️ Safety Logic: Cutoff and Warning Thresholds

Typical 3.7 V Li-ion discharge range:

  • Full: 4.2 V
  • Nominal: 3.7 V
  • Low: ~3.2 V
  • Critical (shutdown): ~3.0 V
  • Dangerous: < 2.8 V (avoid)

Add warning levels in firmware:

if (voltage < 3.3 && voltage > 3.0) {
    // Show warning
} else if (voltage <= 3.0) {
    // Trigger shutdown
}
Enter fullscreen mode Exit fullscreen mode

Avoid deep discharge! Repeated drops below 3.0 V can permanently damage the cell.

📦 Ufine Battery: Designed for Embedded Flexibility

Not all batteries are created equal. Some are generic, lacking any kind of identification or protection. Others—like those from Ufine Battery—are made with embedded developers in mind.

Here’s why Ufine batteries integrate well with firmware-based monitoring:

  • Rich selection of cell types: 18650, pouch, LiFePO4, thin-film, high/low temp, high C-rate
  • OEM/ODM support: They offer custom packs with your preferred connector, protection board, and labeling
  • Low MOQ (1 unit!): Great for early-stage development
  • Fast support & shipping: So you don’t wait weeks just to try out a pack
  • 1-year warranty: More confidence during testing and rollout

If you need a special voltage range or pinout, Ufine can build it for you—and provide full specs for firmware tuning.

🧠 Advanced Features to Consider

If you’re building a production device, consider adding:

1. Coulomb Counting

Use a current sensor (like INA219 or MAX17043) to estimate capacity (mAh used). Some chips even offer fuel gauge output.

2. Temperature Monitoring

Li-ion cells don’t like extreme temperatures. Add a thermistor near the battery and adjust charge/discharge rates if needed.

3. EEPROM Logging

Log voltage over time to analyze health trends. If your microcontroller supports EEPROM or external flash, store snapshots daily or hourly.

4. Protection Board (BMS) Communication

If you’re working with smart battery packs, you may be able to read state-of-charge (SOC), temperature, and error flags over I2C or SMBus.

🧪 Testing Tips

  • Simulate low battery: Use a lab power supply to dial voltage down during testing.
  • Test under load: Batteries sag under real usage. Don’t rely on idle voltage only.
  • Add brownout detection: Some MCUs have internal BOD circuitry to help with graceful shutdowns.

🚀 Final Thoughts

Monitoring 3.7 V Li-ion batteries in firmware is more than just a nice-to-have—it’s a core requirement for reliable embedded systems. With a simple analog input and good code logic, you can protect your device and users from battery issues.

And if you're still choosing a supplier, go for a lithium battery manufacturer that gets embedded engineering. Ufine Battery may not be the biggest, but they deliver the kind of customized, firmware-friendly cells that makers and startups need.

Need a pack with an odd shape? High C-rate? Extreme temp rating? No problem—Ufine will build it, label it, and ship it fast.

🛠 If you're using battery monitoring in your firmware, what techniques have worked best for you? Feel free to share thoughts, examples, or GitHub links in the comments.

Let’s build smarter—and safer—battery-powered devices.

Top comments (1)

Some comments may only be visible to logged-in visitors. Sign in to view all comments.