Managing voltage drop from DC motor across ADS1115

General project help for Adafruit customers

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
Locked
User avatar
agz2007
 
Posts: 1
Joined: Sun Feb 05, 2023 12:30 am

Managing voltage drop from DC motor across ADS1115

Post by agz2007 »

Hello,
I am working on a project which includes an automated water sampling pump. One of my unresolved issues includes the ADS1115 and its behavior when the motor runs. When the motor runs, the battery charge percent I get from the ADS1115 drops by 80-90%. I've added a few capacitors to the circuit but that wasnt much help. I would like to get advice on how to stop the ADC from reading data while the motor is running. I tried to make an if statement that blocks the ADC from reading or analyzing data, but that doesnt work as the if statement is completely ignored. I am atttachng the schematic I am using, the bit of code which tries to control the ADC, and the full script. Help would be very much appreciated as I have been stuck on this issue since october.

Code: Select all

 if (!state == PumpState  || ReverseState || PurgeState) {
    ads.begin();
  adc0 = ads.readADC_SingleEnded(0);
  battVoltage = ads.computeVolts(adc0) * dividerRatio * calFactor;
  battVolt = battVoltage * 3.7;
  battmV = (battVolt * 1000) + 30;
  Val = battmV;
  //  int percent;
  percent =  multiMap(Val, in, out, 13);
 }

Code: Select all

#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 20, 4);
#include <Wire.h>
#include <OneWireNg.h>
#include <DallasTemperature.h>
#include <ezButton.h>
#include <Adafruit_ADS1X15.h>
#include <MultiMap.h>
#define ONE_WIRE_BUS 4
/***********************************GPRS/SMS STUFF ****************************************/

#define LED 2
#define SIGNAL_PIN 36 // ESP32 pin GIOP36 (ADC0) connected to sensor's signal pin



#define samplingRate2 3000UL // the time between sensor readouts

uint8_t type;
unsigned long counter = 0;
unsigned long counter2 = 0;
/**** BOOL VARIABLES FOR SMS ALERTS ****/
bool bat = false;
bool opened = false;
bool cold = false;


/**** FLOAT SWITCH ****/
const int  buttonPin = 33;
int buttonState = 0;         // current state of the button
int lastButtonState = 0;     // previous state of the button
const int FloatSwitchLED = 15;
const int ResetLED = 2;

int value = 0; // variable to store the sensor value
const int LeakLED = 19;



volatile int count; //This integer needs to be set as volatile to ensure it updates correctly during the interrupt process.

float tLimit = 30.0; //the amount of liquid in mL that the pump is supposed to collect during pump cycle
int Threshold;       //the threshold for amount of liquid collected before pump returns to OffState
bool ThresholdLimit = false; // flag for Threshold
/**********************************************************************************************************************************/

Adafruit_ADS1115 ads;
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
DeviceAddress insideThermometer;

unsigned long startMillis;                      // Keeps track of millis() when the pumping cycle starts.
unsigned long currentMillis;                    // millis() of the current loop.

// constants for Arduino IO-Pins with SELF-explaining names
const byte samplingBtnPin = 12;
const byte primeBtnPin    = 13;
const byte purgeBtnPin    = 14;
const byte resetBtnPin    = 32;
ezButton button1(12);  // create ezButton object that attach to pin 12;
ezButton button2(32);  // create ezButton object that attach to pin 12;
const byte DRV8876_IN1_PIN    = 26;
const byte DRV8876_IN2_PIN    = 27;

int flowPin = 25;    //This is the input pin on the Arduino, flow switch
float calibrationFactor = 107;                    //107 CAL FACTOR GOOD FOR 1000ML
float tempC;
float tempF;
int percent;

/**************************************************** Battery stuf **************************************************/
int R1 = 27, R2 = 10; // 10k and 27k ; the resistor ratio
float dividerRatio; // pre-calculate in setup
float calFactor = 1.01; // calibrate  if needed
int in[] = {
  10000, 12000, 12500, 12800, 12900, 13000, 13100, 13200, 13300, 13400, 13600, 14600, 14900
};                                                                                         // [13] IN holds the mV inputs
int out [] = {
  0, 9, 14, 17, 20, 30, 40, 70, 90, 99, 100, 110, 120
};                                                                                       // [13] OUT holds the percentage outputs
float bLimit = 20; // the lower limit of the percentage, if battery percent falls below 20, lowbatsMs is sent
int Val;  // holds input and output values for multimap
float vLimit = 32.0;
int adc0;
float battVoltage;
float battVolt;
int battmV;
/*********************************************************************************************************************/


volatile byte pulseCount;                       // counts the pulses of flow sensor
float flowRate;
unsigned int flowMilliLitres;                  //totaltotalMilliLitres used for the interrupts
unsigned long totalMilliLitres;
unsigned long oldTime;
unsigned long cloopTime;                      // to count pulses per second
unsigned long vol;                           //vol tracks total volume throughout loop


// constants for the states with SELF-explaining names
const byte OffState     = 0;
const byte PumpState    = 1;
const byte PausingState = 2;
const byte ReverseState = 3;
const byte RestState    = 4;
const byte FullState     = 5;
const byte PurgeState = 6;
byte state;

#define pressed HIGH
#define released LOW
#define closed HIGH
#define open LOW

// bool primeBtnPinHasBeenPressed = true;
bool purgeBtnPinHasBeenPressed = false;

void pulseCounter()
{
  // Increment the pulse counter
  pulseCount++;
}

void setup() {
  Serial.begin(115200);
  lcd.begin();
  button1.setDebounceTime(50); // set debounce time to 50 milliseconds
  button2.setDebounceTime(50); // set debounce time to 50 milliseconds
  Serial.println("ESP32 PUMP");
  pinMode(primeBtnPin, INPUT_PULLUP);    // pinMode(5, INPUT);
  pinMode(purgeBtnPin, INPUT_PULLUP);    // pinMode(6, INPUT);
  pinMode(samplingBtnPin, INPUT_PULLUP); // pinMode(7, INPUT);
  pinMode(resetBtnPin , INPUT_PULLUP);
  pinMode(FloatSwitchLED, OUTPUT);
  pinMode(ResetLED, OUTPUT);
  pinMode(DRV8876_IN1_PIN, OUTPUT); // pinMode(A0, OUTPUT);
  pinMode(DRV8876_IN2_PIN, OUTPUT); // pinMode(A1, OUTPUT);

  pinMode(flowPin, INPUT_PULLUP);
  digitalWrite(flowPin, LOW);


  pinMode(LeakLED, OUTPUT) ;

  Threshold         = 3400.0; //Threshold limit
  pulseCount        = 0;
  flowRate          = 0.0;
  flowMilliLitres   = 0.0;
  totalMilliLitres  = 0;
  vol               = 0;
  cloopTime = currentMillis;
  attachInterrupt(digitalPinToInterrupt(flowPin), pulseCounter, FALLING);

  dividerRatio = (R1 + R2) / R1;
  ads.setGain(GAIN_ONE);
//  ads.begin();
  /************************************************GRPS/SMS STUFF*************************************************/
//  adc0 = ads.readADC_SingleEnded(0);
//  battVoltage = ads.computeVolts(adc0) * dividerRatio * calFactor;
//  battVolt = battVoltage * 3.7;
//  battmV = (battVolt * 1000) + 30;
//  Val = battmV;
//  //  int percent;
//  percent =  multiMap(Val, in, out, 13);
  /************************************************GRPS/SMS STUFF end*********************************************/

  Serial.print("Locating devices...");
  sensors.begin();
  Serial.print("Found ");
  Serial.print(sensors.getDeviceCount(), DEC);
  Serial.println(" devices.");

  if (!sensors.getAddress(insideThermometer, 0)) Serial.println("Unable to find address for Device 0");

  //if (!oneWire.search(insideThermometer)) Serial.println("Unable to find address for insideThermometer");
  // show the addresses we found on the bus
  Serial.print("Device 0 Address: ");
  printAddress(insideThermometer);
  Serial.println();

  // set the resolution to 9 bit (Each Dallas/Maxim device is capable of several different resolutions)
  sensors.setResolution(insideThermometer, 9);

  Serial.print("Device 0 Resolution: ");





}

void loop() {
  button1.loop(); // MUST call the loop() function first
  button2.loop(); // MUST call the loop() function first
  int btn1State = button1.getState();
  int btn2State = button2.getState();
  //  if (digitalRead(primeBtnPin) == released) primeBtnPinHasBeenPressed = false;
  if (digitalRead(purgeBtnPin) == released) purgeBtnPinHasBeenPressed = true;



  currentMillis = millis();                   // Get the current value of millis().

  buttonState = digitalRead(buttonPin);

  if (digitalRead(samplingBtnPin) == released)
    if (state > OffState)                              // Are we already in a pumping cycle?
      state = OffState;
    else
      state = PumpState;




  //  delay(200);                         // Small delay to debounce the button.
  value = analogRead(SIGNAL_PIN); // read the analog value from sensor
//  adc0;
//  battVoltage;
//  battVolt;
//  battmV;
//  Val;
//  percent;
 if (!state == PumpState  || ReverseState || PurgeState) {
    ads.begin();
  adc0 = ads.readADC_SingleEnded(0);
  battVoltage = ads.computeVolts(adc0) * dividerRatio * calFactor;
  battVolt = battVoltage * 3.7;
  battmV = (battVolt * 1000) + 30;
  Val = battmV;
  //  int percent;
  percent =  multiMap(Val, in, out, 13);
 }
  sensors.requestTemperatures(); // Send the command to get temperatures
  //  Serial.println("DONE");
  printTemperature(insideThermometer); // Use a simple function to print out the data
  tempC = sensors.getTempCByIndex(0);
  tempF = (tempC * 1.8) + 32;
  lcd.setCursor(0, 3);
  lcd.print("B%");
  lcd.setCursor(3, 3);
  lcd.print(percent);
  lcd.setCursor(7, 3);
  lcd.print("TEMP:");
  lcd.setCursor(13, 3);
  lcd.print(tempF);



  if (percent < 100) { //if battery percent falls below 100, erase the third digit
    lcd.setCursor(5, 3);
    lcd.print(" ");
  }

  if (percent < 10) {
    lcd.setCursor(4, 3);  //if battery falls below 10 percent, erase second and third digit
    lcd.print("  ");
  }

  if (digitalRead(buttonPin) == HIGH) {
    digitalWrite(FloatSwitchLED, LOW);
  }
  else {
    digitalWrite(FloatSwitchLED, HIGH);
  }



  /*********************************  read sensor stats and print on serial monitor *************************/
  if (currentMillis - counter2 > samplingRate2) {
    Serial.println("-----------------------------------------------------------");
    Serial.print("Batt Volts: "); Serial.print(battVoltage, 3); Serial.print(" "); Serial.print("AIN0: "); Serial.print(adc0 ); Serial.print(" "); Serial.print(" BatVolt: "); Serial.println(battVolt, 3);
    Serial.print("Battery mV: "); Serial.print(battmV); Serial.print(" "); Serial.print("Battery level [%]: "); Serial.println(percent);
    Serial.println(sensors.getResolution(insideThermometer), DEC);
    Serial.print("Temp C: "); Serial.print(tempC); Serial.print(" "); Serial.print(" Temp F: "); Serial.println(DallasTemperature::toFahrenheit(tempC)); // Converts tempC to Fahrenheit
    Serial.print("FLOW ML: "); Serial.println(flowMilliLitres);
    if (ThresholdLimit == true) {
      Serial.print("THRESHOLD REACHED"); Serial.println(Threshold);
    } else
    {
      Serial.println("THRESHOLD NOT REACHED");
    }
    if (digitalRead(buttonPin) == HIGH) {
      Serial.println("FLOAT SWITCH OPEN!");
    }
    Serial.print("The water sensor value: ");
    Serial.println(value);

    Serial.println("-----------------------------------------------------------");

    counter2 = millis();
    currentMillis = millis();
  }

  /****** flow rate math ********/
  if (currentMillis >= (cloopTime + 1000))
  {
    cloopTime = currentMillis;
    if (pulseCount != 0) {
      flowRate =  (pulseCount / calibrationFactor);
      //oldTime = millis();
      flowMilliLitres = (flowRate / 60) * 1000;
      totalMilliLitres += flowMilliLitres;
      vol              += flowMilliLitres;
      Serial.print(flowRate); Serial.println(" :L/min");
      Serial.print(totalMilliLitres); Serial.println(" :mL");
      //      lcd.setCursor(0, 1);
      //      lcd.print(flowRate);
      //      lcd.setCursor(5, 1);
      //      lcd.print(":L/min");
      lcd.setCursor(0, 2);
      lcd.print(vol);
      lcd.setCursor(6, 2);
      lcd.print(": mL");
      pulseCount = 0;
    }
    else {
      Serial.print(flowRate); Serial.println(" :L/min");
      Serial.print(vol); Serial.println(" :mL");
      //      lcd.setCursor(0, 1);
      //      lcd.print(flowRate);
      //      lcd.setCursor(6, 1);
      //      lcd.print(":L/min");
      lcd.setCursor(0, 2);
      lcd.print(vol);
      lcd.setCursor(6, 2);
      lcd.print(": mL");
      flowRate = 0;

    }
  }
  ///////////Leak Detection/////////////
  if (value > 1) {
    digitalWrite(LeakLED, HIGH);
    delay(500);
    digitalWrite(LeakLED, LOW);
    delay(500);
    Serial.println("LEAK DETECTED!");
  }
  else {
    digitalWrite(LeakLED, LOW);
  }
  /////////////////////////////////////

  switch (state)                        // Check which state we are in.
  {
    case OffState:
      //    manualMode();
      if (digitalRead(primeBtnPin) == pressed) {

        pumpOff();
      }
      else {
        manualMode();
        break;
      }

      if (purgeBtnPinHasBeenPressed = true) {
        state = PurgeState;
      }
      else {
        break;
      }

      if (digitalRead(resetBtnPin) == released) {  // keep this button in OffState case so that if accidently pressed it wont hurt anything
        resetData();
        digitalWrite(ResetLED, HIGH);
      }
      else {
        digitalWrite(ResetLED, LOW);
        break;
      }

      startMillis = currentMillis;      // Keep resetting the start time of the pumping sequence.
      pumpOff();
      break;

    case PurgeState:
      if (digitalRead(purgeBtnPin) == pressed)
        state = OffState;
      else
        manualPurge();
      break;

    case PumpState:
      if (totalMilliLitres > vLimit || currentMillis - startMillis > 60000)        /// did we collect XmL? if not, go to next stage after X millis
        state = PausingState;
      else

        PumpForward();



      break;

    case PausingState:
      if (currentMillis - startMillis > 63000)   // Have we been in this state too long?
        state = ReverseState;
      else
        pumpOff();
      Serial.println("PAUSE!");
      lcd.setCursor(0, 0);
      lcd.print("PAUSED! ");

      break;

    case ReverseState:
      if (currentMillis - startMillis > 123000) // Have we been in this state too long?
        state = RestState;//state++;
      else
        PumpReverse();

      break;

    case RestState:
      if (currentMillis - startMillis > 900000)  // has it been X minutes?
      {

        state = FullState;
        startMillis = currentMillis;            // Reset the start time of the pumping sequence.
        totalMilliLitres = 0;                  //reset totalMilliLitres so it can start counting up from 0 again

      }
      else
        pumpOff();
      Serial.println("REST!");
      lcd.setCursor(0, 0);
      lcd.print("RESTING!");

      break;

    case FullState:
      if (ThresholdLimit == true) { //||  (digitalRead(buttonPin) == HIGH))
        state = OffState;
      }

      else {
        Serial.println(state);
        state = PumpState;
      }
      break;
  }
  /***************************SMS ALERTS***************************************************/
  if (buttonState == HIGH && lastButtonState == LOW || vol > 3100 && vol - flowMilliLitres <= 3100) {
    opened = false;
    ThresholdLimit = true;
    lastButtonState = buttonState;

    pumpOff();
    lcd.setCursor(0, 0);
    lcd.print("FULL          ");
  }


  if (tempF < tLimit && cold == false) {

    cold = true;
  }
  else if (tempF > tLimit + 2.0 && cold == true) {
    cold = false;
  }
  if (percent < bLimit && bat == false) {

    bat = true;
  }
  /***************************SMS ALERTS END***************************************************/
  /**************************** DATA POST TO DWEET *********************************************/

}

void Full() {
  lcd.setCursor (0, 0);
  lcd.print("FULL");
  digitalWrite(DRV8876_IN1_PIN, LOW);
  digitalWrite(DRV8876_IN2_PIN, LOW);
}



void manualMode() {
  digitalWrite(DRV8876_IN1_PIN, HIGH);  // comment is obsolete code epxlains ITSELF Turn on the pump (forward).
  digitalWrite(DRV8876_IN2_PIN, LOW);
  //  Serial.println("PUMPING!");
  lcd.setCursor(0, 0);
  lcd.print("PUMPING!");
}

void manualPurge() {
  digitalWrite(DRV8876_IN1_PIN, LOW);  // comment is obsolete code epxlains ITSELF Turn on the pump (forward).
  digitalWrite(DRV8876_IN2_PIN, HIGH);
  //  Serial.println("PUMPING!");
  lcd.setCursor(0, 0);
  lcd.print("PURGING!");
}



// senseful SUB-unit of code with a SELF-explaining name
void PumpForward() {
  digitalWrite(DRV8876_IN1_PIN, HIGH);  // comment is obsolete code epxlains ITSELF Turn on the pump (forward).
  digitalWrite(DRV8876_IN2_PIN, LOW);
  //  Serial.println("PUMPING!");
  lcd.setCursor(0, 0);
  lcd.print("PUMPING!");
}

void resetData() {
  currentMillis = millis();
  startMillis = currentMillis;
  cloopTime = currentMillis;
  totalMilliLitres = 0;
  flowRate = 0;
  vol = 0;
  flowMilliLitres = 0;
  ThresholdLimit = false;
  Serial.println("Data Reset");
  lcd.setCursor(0, 2);
  lcd.print(vol);
  lcd.setCursor(1, 2);
  lcd.print("    ");
  pulseCount = 0;
}
// senseful SUB-unit of code with a SELF-explaining name
void PumpReverse() {
  digitalWrite(DRV8876_IN1_PIN, LOW);  // comment is obsolete code epxlains ITSELF Reverse the pump.
  digitalWrite(DRV8876_IN2_PIN, HIGH);
  Serial.println("PURGING!");
  lcd.setCursor(0, 0);
  lcd.print("PURGING!");
}


// senseful SUB-unit of code with a SELF-explaining name
void pumpOff()
{
  digitalWrite(DRV8876_IN1_PIN, LOW);
  digitalWrite(DRV8876_IN2_PIN, LOW);
  lcd.setCursor(0, 0);
  lcd.print("PUMP OFF");
}

void printTemperature(DeviceAddress deviceAddress)
{
  // method 1 - slower
  //Serial.print("Temp C: ");
  //Serial.print(sensors.getTempC(deviceAddress));
  //Serial.print(" Temp F: ");
  //Serial.print(sensors.getTempF(deviceAddress)); // Makes a second call to getTempC and then converts to Fahrenheit

  // method 2 - faster
  float tempC = sensors.getTempC(deviceAddress);
  if (tempC == DEVICE_DISCONNECTED_C)
  {
    Serial.println("Error: Could not read temperature data");
    return;
  }

}

// function to print a device address
void printAddress(DeviceAddress deviceAddress)
{
  for (uint8_t i = 0; i < 8; i++)
  {
    if (deviceAddress[i] < 16) Serial.print("0");
    Serial.print(deviceAddress[i], HEX);
  }
}

[/size]
Attachments
whopper jr.PNG
whopper jr.PNG (310.14 KiB) Viewed 113 times

User avatar
adafruit_support_bill
 
Posts: 88092
Joined: Sat Feb 07, 2009 10:11 am

Re: Managing voltage drop from DC motor across ADS1115

Post by adafruit_support_bill »

Code: Select all

if (!state == PumpState  || ReverseState || PurgeState) 
That won't work because the motor will never be in all three states simultaneously.

What you need is:

Code: Select all

if ((state != PumpState) && (state != ReverseState) && (state != PurgeState))
Also: ads.begin() should only need to be called once in setup();

User avatar
sj_remington
 
Posts: 997
Joined: Mon Jul 27, 2020 4:51 pm

Re: Managing voltage drop from DC motor across ADS1115

Post by sj_remington »

The ADS1115 must share a common ground with the rest of the circuitry, and that is not clear from the non-standard schematic.

You should clearly indicate common ground connections using the ground symbol, rather than running what appear to be several different, unconnected ground connections.

Locked
Please be positive and constructive with your questions and comments.

Return to “General Project help”