From 4c30ff35499438b5ac1a2d0d912bcbdeb101ec27 Mon Sep 17 00:00:00 2001 From: rbaron Date: Sun, 14 Feb 2021 10:59:18 +0100 Subject: [PATCH] Adds a simple battery monitoring circuit and analog to digital measuring. --- .gitignore | 1 + README.md | 2 +- code/parasite/src/main.cpp | 25 ++++++++++++++++++++----- resources.md | 9 +++++++++ 4 files changed, 31 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index 945388b..73fe488 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ *.swp .vscode +.DS_Store diff --git a/README.md b/README.md index a673307..2b7d8b3 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,6 @@ A low power soil moisture sensor based on the nRF52840. # TODO -* Implement battery level monitoring * Figure out how to calibrate the ADC when running from different voltages, as the battery discharges * Experiment with different TX power / battery tradeoff. Since we'll be deepsleeping most of the time, maybe we can get away with a lot of TX power. * Implement deep sleep @@ -16,6 +15,7 @@ A low power soil moisture sensor based on the nRF52840. * Design new board using the nrf52 instead of esp32 # Done +* Implement battery level monitoring * Implement BLE advertising with moisture * Implement ADC for the parasitic capacitor; check out air/water range (using protoboard) * Simple PWM square wave generator diff --git a/code/parasite/src/main.cpp b/code/parasite/src/main.cpp index e4521e1..9a249c5 100644 --- a/code/parasite/src/main.cpp +++ b/code/parasite/src/main.cpp @@ -11,9 +11,14 @@ constexpr int kLED1Pin = 17; constexpr int kLED2Pin = 18; constexpr int kPWMPin = 19; constexpr int kSensAnalogPin = 4; // AIN2 +constexpr int kBattAnalogPin = 3; // AIN3 constexpr int kDischargeEnablePin = 16; constexpr double kPWMFrequency = 500000; +constexpr double kBattDividerR1 = 1470; +constexpr double kBattDividerR2 = 470; +constexpr double kBattDividerFactor = (kBattDividerR1 + kBattDividerR2) / kBattDividerR2; + const parasite::MACAddr kMACAddr = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06}; parasite::BLEAdvertiser advertiser(kMACAddr); @@ -40,17 +45,27 @@ void setup() { // Enable fast discharge cycle. digitalWrite(kDischargeEnablePin, HIGH); +} + +void loop() { + // With a gain of 1/2, we can read the range of [0, 1.2V]. + // I'm using a voltage divider with R1 = 1470, R2 470, so + // We can read 0 - ~5V. + // This seems to be working okay, but I need to investigate if making it + // stiffer (lower R1 and R2) work better. + analogOversampling(32); + analogReference(AR_INTERNAL_1_2); + int batt_val = analogRead(kBattAnalogPin); + double v_in = 1.2 * batt_val / (1<<10); + double batt_voltage = kBattDividerFactor * v_in; + Serial.printf("Batt val: %d, voltage: %f\n", batt_val, batt_voltage); // We setup the analog reference to be VDD. This allows us to cancel out // the effect of the battery discharge across time, since the RC circuit // also depends linearly on VDD. - // TODO(rbaron): empirically prove/disprove this. analogReference(AR_VDD4); -} - -void loop() { int sens_val = analogRead(kSensAnalogPin); - Serial.printf("Val: %d\n", sens_val); + // Serial.printf("Moisture val: %d\n", sens_val); digitalToggle(kLED1Pin); updateAdvertisingData(&advertiser, sens_val); delay(500); diff --git a/resources.md b/resources.md index 38a86dc..fdfedfa 100644 --- a/resources.md +++ b/resources.md @@ -139,6 +139,15 @@ I'm getting ~680 when in the air; ~65 while holding the sensor. The default reso # Battery monitoring * Good post on how to measure lipo batteries: [link](https://devzone.nordicsemi.com/nordic/nordic-blog/b/blog/posts/measuring-lithium-battery-voltage-with-nrf52#:~:text=To%20reduce%20the%20leakage%20current,of%2040%20us%2C%20see%20here.) +We have a choice of using different references when using the analog-to-digital converter. For measuing the peak of the RC charging circuit, it makes sense to use VCC as the reference, as the rise in the RC is proportional to VCC. +For battery monitoring, we need an absolute reference. Luckily, we can use the internal reference of 0.6V. To increase the range of values, we can combine this with a gain parameter. This is what the arduino-nrf5 does in [wiring_analog_nRF52.c](https://github.com/sandeepmistry/arduino-nRF5/blob/master/cores/nRF5/wiring_analog_nRF52.c#L92). +With a gain of 1/2, we could read the absolute range of [0, 1.2V]. Since we're interested in the max value of roughly 4.2 (fully charged LiPo, or alternatively 3.0V for a CR2032 coin cell), we can use a voltage divider with R1 = 1470 kOhm and R2 = 470kOhm. This would give us a range of [0, ~5V]. +This seems to be working okay, but I need to investigate if making it stiffer (lower R1 and R2) improves the accuracy. With higher resistor values, we minimize the quiescent current, but increase the source impedance. Even hooking up the oscilloscope changes the reading value. + +## Ideas for improvement: +* Decrease the impedance of the voltage divider, but somehow use a mcu-controlled switch so we don't pay the current price when the MCU is sleeping (which is most of the time). [This stackexchange answer](https://electronics.stackexchange.com/a/64491) mentions a similar approach +* Use even larger resistor values and attach a capacitor across R2, as suggested by [this answer](https://www.eevblog.com/forum/projects/battery-monitoring-voltage-divider/msg2524116/#msg2524116). We can reach nanoamps of current, which is negligible in this design. Question: does the capacitor self leak? If so, we'd need to be constantly pumping charges into it. How significant is this effect? If we do oversampling, the capacitor probably won't charge in time for multiple fast measurements. But the capacitor might act like a filter itself, negating the need for oversampling. + * [This post on jeelabs.org](https://jeelabs.org/wp-content/uploads/2013/05/16/measuring-the-battery-without-draining-it/) also does some experiments with a capacitor across R2. # BLE * BLE examples for platformio with nordicnrf52 platform: [link](https://github.com/platformio/platform-nordicnrf52/tree/master/examples)