Adds a simple battery monitoring circuit and analog to digital measuring.
This commit is contained in:
parent
6c4b57f2b0
commit
4c30ff3549
4 changed files with 31 additions and 6 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -1,2 +1,3 @@
|
||||||
*.swp
|
*.swp
|
||||||
.vscode
|
.vscode
|
||||||
|
.DS_Store
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@
|
||||||
A low power soil moisture sensor based on the nRF52840.
|
A low power soil moisture sensor based on the nRF52840.
|
||||||
|
|
||||||
# TODO
|
# TODO
|
||||||
* Implement battery level monitoring
|
|
||||||
* Figure out how to calibrate the ADC when running from different voltages, as the battery discharges
|
* 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.
|
* 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
|
* 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
|
* Design new board using the nrf52 instead of esp32
|
||||||
|
|
||||||
# Done
|
# Done
|
||||||
|
* Implement battery level monitoring
|
||||||
* Implement BLE advertising with moisture
|
* Implement BLE advertising with moisture
|
||||||
* Implement ADC for the parasitic capacitor; check out air/water range (using protoboard)
|
* Implement ADC for the parasitic capacitor; check out air/water range (using protoboard)
|
||||||
* Simple PWM square wave generator
|
* Simple PWM square wave generator
|
||||||
|
|
|
||||||
|
|
@ -11,9 +11,14 @@ constexpr int kLED1Pin = 17;
|
||||||
constexpr int kLED2Pin = 18;
|
constexpr int kLED2Pin = 18;
|
||||||
constexpr int kPWMPin = 19;
|
constexpr int kPWMPin = 19;
|
||||||
constexpr int kSensAnalogPin = 4; // AIN2
|
constexpr int kSensAnalogPin = 4; // AIN2
|
||||||
|
constexpr int kBattAnalogPin = 3; // AIN3
|
||||||
constexpr int kDischargeEnablePin = 16;
|
constexpr int kDischargeEnablePin = 16;
|
||||||
constexpr double kPWMFrequency = 500000;
|
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};
|
const parasite::MACAddr kMACAddr = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06};
|
||||||
parasite::BLEAdvertiser advertiser(kMACAddr);
|
parasite::BLEAdvertiser advertiser(kMACAddr);
|
||||||
|
|
||||||
|
|
@ -40,17 +45,27 @@ void setup() {
|
||||||
|
|
||||||
// Enable fast discharge cycle.
|
// Enable fast discharge cycle.
|
||||||
digitalWrite(kDischargeEnablePin, HIGH);
|
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
|
// 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
|
// the effect of the battery discharge across time, since the RC circuit
|
||||||
// also depends linearly on VDD.
|
// also depends linearly on VDD.
|
||||||
// TODO(rbaron): empirically prove/disprove this.
|
|
||||||
analogReference(AR_VDD4);
|
analogReference(AR_VDD4);
|
||||||
}
|
|
||||||
|
|
||||||
void loop() {
|
|
||||||
int sens_val = analogRead(kSensAnalogPin);
|
int sens_val = analogRead(kSensAnalogPin);
|
||||||
Serial.printf("Val: %d\n", sens_val);
|
// Serial.printf("Moisture val: %d\n", sens_val);
|
||||||
digitalToggle(kLED1Pin);
|
digitalToggle(kLED1Pin);
|
||||||
updateAdvertisingData(&advertiser, sens_val);
|
updateAdvertisingData(&advertiser, sens_val);
|
||||||
delay(500);
|
delay(500);
|
||||||
|
|
|
||||||
|
|
@ -139,6 +139,15 @@ I'm getting ~680 when in the air; ~65 while holding the sensor. The default reso
|
||||||
|
|
||||||
# Battery monitoring
|
# 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.)
|
* 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
|
||||||
* BLE examples for platformio with nordicnrf52 platform: [link](https://github.com/platformio/platform-nordicnrf52/tree/master/examples)
|
* BLE examples for platformio with nordicnrf52 platform: [link](https://github.com/platformio/platform-nordicnrf52/tree/master/examples)
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue