Help Correcting Code in IR Sensor Counting a Perastaltic Pump

Hope to hit in the right section for help.
I am starting to use Arduino in projects as hobbies and toys with my kids.

Project: Counting Perastolic Pump rotation with IR Sensor as counter to report volume output in “mL” on LCD. (reason is IR acts as a fail safe if the pump does not run, then no transfer of liquid.)

Action: Pressed the button to start the PPumps timed action and the IR will count the arm rotations, presenting the count on a (16x2) LCD, as Volume in “ml”.

All is working on the UNO independently, the code I posted is really pieced together from other found/googled codes and instructional.

Issue:

  1. IR will count when pump in not on, but will not count while pump is running, even though the light on sensor is blinking. (Got to be in my code.) Once pump is cuts off, it would count the last few rotations as it slows down.

  2. Not to have the count to start till after the button is pressed and stop after the pump run time stops. (Reason: IR position could have the pump arm stop in front of the sensor showing a HIGH constant value.)

Equipment:

  • UNO
  • 5V Perastaltic Pump
  • ir sensor fc-51
  • LCD (16x2)
// include the library code:
#include <LiquidCrystal.h>


#define HALF4WIRE 8


// CHANGE THIS TO "true/false" IN ORDER TO CHANGE MODES
bool TESTMODE = true;


// initialize the library by associating any needed LCD interface pin
// with the arduino pin number it is connected to
const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 6;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

//set pin for the pulse counter
byte sensorPin = 2;
byte buttonPresses = 0;
byte lastPressCount = 0;

// program variable
int loopCount = 0;

//define the input/output pins
//pump/relay pins
#define PUMP_1_PIN 7


//pushbutton pins
#define BUTTON_1_PIN 8


//Time for pumping stations to turn on in milliseconds
#define PUMP_1_TIME 30000


//setup() runs once
void setup() {

  
  // initialize serial communication for debugging
  Serial.begin(9600);

   // set up the LCD's number of columns and rows:
  lcd.begin(16, 2);   
  lcd.clear();
  lcd.print("initializing...");
  delay(500);
  lcd.clear();
  
  //pin connected to button
  pinMode(sensorPin, INPUT);
//setup output pins for relays/pumping stations
pinMode(PUMP_1_PIN, OUTPUT);
//setup input pins for buttons
pinMode(BUTTON_1_PIN, INPUT);
}

//loop() runs indefinitely
  
void loop() {
  // put your main code here, to run repeatedly:
    // Turn off the display:
  //lcd.noDisplay();
  lcd.display();
  interrupts();

  switch(TESTMODE) {
    

    //OPERATION FOR TEST MODE
    case true:
      while (loopCount != 1){ //do this only once - the first loop through
        lcd.print("Ready: Press Go"); //LCD output
        loopCount = 1;
      }
      // COUNT THE NUMBER OF BUTTON PUSHES
      if (digitalRead(sensorPin) == LOW){
        buttonPresses++;
        delay(250); //debounce signal so that we only trigger one count per press
        }

      lastPressCount = buttonPresses;

      }

      //Display the number of button presses
      Serial.println(lastPressCount);
      lcd.setCursor(0,2);
      lcd.print("Vol.(ml):");
      lcd.setCursor(13,2);
      lcd.print(lastPressCount);
//check pushbutton on pin BUTTON_1_PIN to see if it is HIGH (it has been pressed)
if(digitalRead(BUTTON_1_PIN) == HIGH)
{
digitalWrite(PUMP_1_PIN, HIGH); //turn pump 1 on
delay(PUMP_1_TIME); //wait PUMP_1_TIME milliseconds
digitalWrite(PUMP_1_PIN, LOW); //turn pump 1 off
}

   }

#define PUMP_1_TIME 30000


delay(PUMP_1_TIME); //wait PUMP_1_TIME milliseconds

Nothing is going to happen during that delay(). The processor, for all practical purposes, is dead. Your encoder is not being read.

You will need to use millis() for timing. If the speed of the motor is high and you miss pulses by polling you may need to resort to using an interrupt to read the sensor (encoder).

A couple of tutorials that may help
beginner's guide to millis()
several things at a time

OP image (I won't call it a schematic):


How to post images.

What is that transistor? Part number?

Thanks groundFungus,

I am reading through the forum post now.

the waiting the pump time 1 millsec, is basically turning the pump on and off through the allotted time. Basically pulsing the motor to turn and between that time using IR to read. Would that be enough time to get a read from the IR sensor?

Would switching the IR Sensor from a digital read on pin2 to an analog signal make a difference?

No not a good schematic, but hope to get the build across.

The transistor is PNP222A and a Rectifier Diode 1n4001, (not sure why all the build have a diode I copied the projects that would fit.)

The code, as is, turns the pump on for 30 seconds and during that time does nothing else. It cannot read the IR sensor nor can it read the switch.

The way to do it is to turn the pump on and at that time, record, in a variable, the value of millis(). Then each time through loop() check the recorded millis() against the current value of millis() and after 30000 milliseconds has elapsed, turn the pump off. Only read and count pulses from the IR sensor while the motor is running. Use NO delay()s.

If I may make a couple of suggestions on the hardware side.
It is more common practice to wire a switch from an input to ground and enable the internal pullup resistor. The switch will read LOW when pressed and HIGH when not pressed. Put a 0.1uF cap across the switch to debounce the switch in hardware.

The transistor needs a base resistor to limit the current into the base of the transistor to protect the output from excess current draw. Suggest 180 to 220 Ohms. The schematic has 180 to 470 but I would stay on the low side (180-220).

Running a motor from the Uno 5V regulator can cause problems. Motors are noisy, electrically and the regulator can not supply a lot of current. It would be better, if possible, to use an external supply for the motor. The diode is there to absorb the high reverse voltage that is generated when the motor is turned off. When the motor is running a magnetic field is developed around the motor. When the motor turns off, the field collapses and generates the high reverse voltage. Without the diode that high reverse voltage can (and will) kill the transistor. 1N4001 is probably OK though I would use a 1N4007 because it has a higher reverse voltage capability. A 0.1uF cap across the motor (in parallel with the diode) will help to filter out high frequency noise from the motor power.

Here is a sketch that does close to what you want, I think. It illustrates how to use millis() for timing and the state change detection method for sensing transitions for the sensor and button outputs. Note that the button is wired like the schematic in the previous post (active low). I changed some variable names to make their use more clear. Hope this, along with the linked tutorials, will give you some ideas. Questions welcome.

#include <LiquidCrystal.h>

const unsigned long PUMP_ON_TIME = 5000; // set this for the run time that you want.

const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 6;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

//set pin for the pulse counter
const byte sensorPin = 2;
byte pulseCount = 0; // changed the names to

//pushbutton
const byte buttonPin = 8;

// pump
const byte pumpPin = 7;
boolean pumpRunFlag = false;
boolean pumpRunning = false;
unsigned long pumpTimer = 0;

void setup()
{
   Serial.begin(115200);
   pinMode(buttonPin, INPUT_PULLUP);
   pinMode(sensorPin, INPUT_PULLUP); // adjust for your sensor
   pinMode(pumpPin, OUTPUT);
   digitalWrite(pumpPin, LOW);

   lcd.begin(16, 2);
   lcd.clear();
   lcd.print("initializing...");
   delay(1000);
   lcd.clear();
}

void loop()
{
   checkButton();
   runPump();
   readSensor();
}

void checkButton()
{
   static boolean lastButtonState = HIGH;
   boolean buttonState = digitalRead(buttonPin);
   if (buttonState != lastButtonState)
   {
      if (buttonState == LOW)
      {
         pumpRunFlag = true;
      }
      lastButtonState = buttonState;
   }
}

void runPump()
{
   if (pumpRunFlag == true && pumpRunning == false)
   {
      pumpTimer = millis();  // record pump start time
      pumpRunning = true;
      digitalWrite(pumpPin, HIGH); // turn on pump
      lcd.setCursor(0, 0);
      lcd.print("running         ");
   }
   else if (pumpRunFlag == true && pumpRunning == true)
   {
      if (millis() - pumpTimer >= PUMP_ON_TIME)  
      {
         digitalWrite(pumpPin, LOW); // turn pump off
         pumpRunning = false; // reset flags
         pumpRunFlag = false;
         lcd.setCursor(0, 0);
         lcd.print("pulseCount ");
         lcd.setCursor(11, 0);
         lcd.print("   ");
         lcd.setCursor(11, 0);
         lcd.print(pulseCount);
      }
   }
}

void readSensor()
{
   if (pumpRunning == true) // only count pulses when pump running
   {
      static boolean lastSensorState = HIGH;
      boolean sensorState = digitalRead(sensorPin);
      if (sensorState != lastSensorState)
      {
         if (sensorState == LOW)
         {
            pulseCount++;
         }
         lastSensorState = sensorState;
      }
   }
}