diff --git a/code/parasite/lib/parasite/parasite/adc.cpp b/code/parasite/lib/parasite/parasite/adc.cpp new file mode 100644 index 0000000..e1a4ad9 --- /dev/null +++ b/code/parasite/lib/parasite/parasite/adc.cpp @@ -0,0 +1,48 @@ +#include "parasite/adc.h" + +#include + +#include + +namespace parasite { +namespace { +// Resultion in bits. ADC read values will be mapped to [0, 2^reference]. +constexpr int kResolution = 10; + +/* + * Battery monitoring + */ +// Use the internal 0.6 reference with a gain of 1/2. +// This lets us read values in the range [0, 1.2V]. +constexpr eAnalogReference kBattADCReference = AR_INTERNAL_1_2; +constexpr double kMaxVoltage = 1.2; +// How many samples will be averaged out. +constexpr uint32_t kOversampling = 32; +// Voltage divider. +constexpr double kBattDividerR1 = 1470; +constexpr double kBattDividerR2 = 470; +constexpr double kBattDividerFactor = + (kBattDividerR1 + kBattDividerR2) / kBattDividerR2; +} // namespace + +double BatteryMonitor::Read() { + analogOversampling(kOversampling); + analogReference(kBattADCReference); + int batt_val = analogRead(pin_); + double v_in = kMaxVoltage * batt_val / (1 << kResolution); + return kBattDividerFactor * v_in; +} + +soil_reading_t SoilMonitor::Read() { + analogOversampling(kOversampling); + // Set up 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. + analogReference(AR_VDD4); + int raw = analogRead(pin_); + double percentage = + static_cast(raw - air_val_) / (water_val_ - air_val_); + return {raw, std::max(0.0, std::min(1.0, percentage))}; +} + +} // namespace parasite \ No newline at end of file diff --git a/code/parasite/lib/parasite/parasite/adc.h b/code/parasite/lib/parasite/parasite/adc.h new file mode 100644 index 0000000..df05c3e --- /dev/null +++ b/code/parasite/lib/parasite/parasite/adc.h @@ -0,0 +1,35 @@ +#ifndef _PARASITE_ADC_H_ +#define _PARASITE_ADC_H_ + +namespace parasite { + +class BatteryMonitor { + public: + explicit BatteryMonitor(int pin) : pin_(pin) {} + double Read(); + + private: + const int pin_; +}; + +struct soil_reading_t { + int raw; + double parcent; +}; + +class SoilMonitor { + public: + explicit SoilMonitor(int air_val, int water_val, int pin) + : air_val_(air_val), water_val_(water_val), pin_(pin) {} + + soil_reading_t Read(); + + private: + // Referencce values for estimating the soil moisture percentage. + const int air_val_, water_val_; + + // Pin the analog signal is connected to. + const int pin_; +}; +} // namespace parasite +#endif // _PARASITE_ADC_H_ \ No newline at end of file diff --git a/code/parasite/src/main.cpp b/code/parasite/src/main.cpp index 9a249c5..7ecffc9 100644 --- a/code/parasite/src/main.cpp +++ b/code/parasite/src/main.cpp @@ -1,8 +1,8 @@ #include #include -#include +#include "parasite/adc.h" #include "parasite/ble.h" #include "parasite/ble_advertisement_data.h" #include "parasite/pwm.h" @@ -10,22 +10,25 @@ constexpr int kLED1Pin = 17; constexpr int kLED2Pin = 18; constexpr int kPWMPin = 19; -constexpr int kSensAnalogPin = 4; // AIN2 +constexpr int kSoilAnalogPin = 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; +constexpr int kSoilMonitorAirVal = 680; +constexpr int kSoilMonitorWaterVal = 60; const parasite::MACAddr kMACAddr = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06}; parasite::BLEAdvertiser advertiser(kMACAddr); -void updateAdvertisingData(parasite::BLEAdvertiser *advertiser, - int moisture_level) { +parasite::BatteryMonitor batt_monitor(kBattAnalogPin); +parasite::SoilMonitor soil_monitor(kSoilMonitorAirVal, kSoilMonitorWaterVal, + kSoilAnalogPin); + +void updateAdvertisingData(parasite::BLEAdvertiser* advertiser, + const parasite::soil_reading_t& soil_reading) { parasite::BLEAdvertisementData data; - data.SetRawSoilMoisture(moisture_level); + + data.SetRawSoilMoisture(soil_reading.raw); advertiser->SetData(data); @@ -48,25 +51,16 @@ void setup() { } 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); + double batt_voltage = batt_monitor.Read(); + Serial.printf("Batt voltage: %f\n", batt_voltage); + + parasite::soil_reading_t soil_reading = soil_monitor.Read(); + Serial.printf("Moisture val: %d, %f%%\n", soil_reading.raw, + 100 * soil_reading.parcent); - // 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. - analogReference(AR_VDD4); - int sens_val = analogRead(kSensAnalogPin); - // Serial.printf("Moisture val: %d\n", sens_val); digitalToggle(kLED1Pin); - updateAdvertisingData(&advertiser, sens_val); + + updateAdvertisingData(&advertiser, soil_reading); + delay(500); } \ No newline at end of file