Need some direction.

Ok, so i have an led hooked up to a flow meter on my Arduino uno. The sensor in the flow meter is a dry contact switch that is operated by an internal turbine that magnetically closes it once per revolution. I would like the Arduino to read the flow meter and blink an led 10 times evenly distributed in the time it took for the previously recorded time interval. Multiplying the pulse from 1 to 10.

Im a novice and this probably is very advanced but out of necessity i need to figure out how to do this..
Is this possible? What would my sketch and circuit look like?

Need to know the details of the EXACT sensor you have.

You need to record millis() every time the sensor is triggered. Subtract the previous reading from the latest reading to get the number of milliseconds for a revolution. Then divide that number by 20 and use it as the time the LED is OFF and ON.

Look at the demo several things at a time for the general way to use millis().

The simplest way to record the pulses is probably with an interrupt routine that triggers every time pin 2 (which is interrupt 0) goes HIGH

attachInterrupt(0, pulseISR, RISING);
void pulseInterrupt() {
    newInterruptMillis = millis();
    newInterrupt = true;
}

...R

Unfortunately the part number on the sensor is warn off and Google has failed me in my findings. All i have found is that its a dry contact pulse. But if it helps i have it blinking an LED with the example sketch "Button".

If the turbine turns a magnet around its center and that turning field can be detected (not inside an iron or steel body) then a linear Hall sensor could detect the turn angle all the time.

The linear Hall detects field strength along one axis of the sensor. As the magnet turns, the field changes strength. At a steady turn rate, the output is a sine wave.

Other fields intruding would mess with that but even a grounded metal screen can shield against those.

The sensors are not expensive and quite sensitive. You could use one to investigate the flow meter.

You could probably use a coil wrapped around an iron nail though it might no be as sensitive.
Changing magnetic field (like from a turning or moving magnet or changing current in wire) will cause current to flow in conductors (like wire) at a distance, especially in wire loops and many times moreso in wire loops with iron cores.
That's how come we have motors, generators, radio, etc. Ain't science wunnerful?

mumbleelbmum:
Im a novice and this probably is very advanced but out of necessity i need to figure out how to do this..
Is this possible?

Of course it's possible, but it's totally crap if the flow rate can drop to zero for longer times.

mumbleelbmum:
I would like the Arduino to read the flow meter and blink an led 10 times evenly distributed in the time it took for the previously recorded time interval. Multiplying the pulse from 1 to 10.

Example:
If the flow rate is zero for an hour and then the turbine is starting with the first pulse, then you will have a time of one hour between two pulses.

If you then "blink an led 10 times evenly distributed in the time it took for the previously recorded time interval" you will have 10 blinks within the next hour.

I don't think that you really want what you described in words.
At least not, if the turbine is not "always on" with a reasonable pulse rate.

It averages 1 min per rotation and It will never fluctuate.

It will send a pulse signal to a chemical pump. In a "batch" setting (it will pump x amount of chemical per pulse received)

with the pulse being 1 min apart.... it will dump what its set at in the first 10 seconds.. letting untreated water pass wile the meter finishes its revolution..

my solution is to multiply the pulses from the flow meter and turn down the chemical output per pulse therefore allowing even distribution of chemical.

You can experiment and modify this sketch to suit your needs. It'll measure and print out pulse period and more:

// Flow Sensor Pulse Period Measurement

const byte pgenPin = 13;              // PGEN pin number (for testing)
const byte CLEAR = 12;                // CLEAR pin number
const byte sensorPin = 2;             // flowmeter pulse
const double pulseConstant = 7.5;     // pulse constants

double pgenFrequency = 7.5;           // (Hz), To test sketch with pgen, apply jumper from pin 13 to pin 2

long previousMillis = 0;
long pgenInterval = 1000000 / (pgenFrequency * 2);
byte pgenState = LOW;
long pgenPreviousMicros = 0;
long startTime;
byte sensorState;
byte sensorPrevious;
double pulsePeriod;
double pulseFrequency;
double flowRate;
double pulseVolume;
double totalVolume;

void setup() {
  Serial.begin(115200);
  Serial.print("");
  pinMode(pgenPin, OUTPUT);
  pinMode(CLEAR, INPUT_PULLUP);
  pinMode(sensorPin, INPUT_PULLUP);            // recommend using "INPUT" and 4.7K external pull up resistor
  pulseVolume = 1.0 / (pulseConstant * 60);
  clr(); // initialize arrays
}

void loop()
{
  // run pulse generator for input testing
  pgen();

  // check if CLEAR push button is pressed
  if (digitalRead (CLEAR) == LOW) {
    clr();
  }
  sensorState = digitalRead(sensorPin);                     // read the inputs

  if (sensorState == 1 & sensorPrevious == 0) {             // if rising
    pulsePeriod = (micros() - startTime) / 1000000.0;       // test duration (sec)
    pulseFrequency = 1 / pulsePeriod;                       // input frequency (Hz)
    flowRate = pulseFrequency / pulseConstant;              // flow rate
    totalVolume = totalVolume + pulseVolume;                // totalized volume

    if (millis() - previousMillis > 1000) {                  // update timing (milliseconds)
      Serial.print(pulsePeriod, 6); Serial.print(" sec, ");
      Serial.print(pulseFrequency, 3); Serial.print(" Hz, ");
      Serial.print(flowRate, 3); Serial.print(" L/min, ");
      Serial.print(totalVolume, 6); Serial.print(" L");
      Serial.println();
      previousMillis = millis();
    }
    startTime = micros();
  }
  sensorPrevious = sensorState;
}


// functions -----------------------------------------------------

void pgen() {
  // check to see if it's time to pulse the PGEN; that is, if the
  // difference between the current time and last time you pulsed
  // the PGEN is bigger than the interval to changed its output state.
  unsigned long pgenCurrentMicros = micros();

  if (pgenCurrentMicros - pgenPreviousMicros > pgenInterval) {
    // save the last time you pulsed the PGEN
    pgenPreviousMicros = pgenCurrentMicros;

    // if the PGEN output is off turn it on and vice-versa:
    if (pgenState == LOW)
      pgenState = HIGH;
    else
      pgenState = LOW;

    digitalWrite(pgenPin, pgenState);
  }
}

void clr() {
  startTime = micros();
  sensorState = 0;
  sensorPrevious = 1;
  pulsePeriod = 0;
  pulseFrequency = 0;
  flowRate = 0;
  totalVolume = 0;
}

You could use the pulse timing, divide by 10 and use this value to create a pulse output with 0.1 "pulse weight".

mumbleelbmum:
It averages 1 min per rotation and It will never fluctuate.

So your input is the time difference between two rotation pulses.

Let's say this is 59 seconds = 59000 milliseconds.

Your output is a LED which cycles ten times as often, so the settings for the LED output would be:
LED cycle time = 5900 milliseconds
LED on time = 2950 milliseconds
So the LED is on for 2.95s and off for 2.95s

When the next pulse arrives after 59100 milliseconds, you just change the output settings for the LED:
LED cycle time = 5910 milliseconds
LED on time = 2955 milliseconds
So the LED is on for 2.955s and off for 2.955s after the next pulse

mumbleelbmum:
It will send a pulse signal to a chemical pump

So maybe a duty cycle of 50% may be too long? Do you want to create shorter pulses with a fixed HIGH time?

The total cycle can start after the first inital two pulses have been received. When you get an average of 1 pulse per minute, it may take from 1 minute up to 2 minutes, before the Arduino is able to calculate the output cycle settings. Any thoughts what the Arduino should do before he had seen the first two pulses? No LED output? LED always on? LED blinking at a high rate?

if you read the position of the turbine directly, you won't need the pulses and guesswork calculations.

Yes shorter pulses with a fixed High time but still relative to the flow meter output..
No led before the first 2 pulses and it would need to stop after 5 min or so after no input from flow meter...As to not waste chemical. Correction on the pump setting... its a setting called "pulse" pumps relative to an external input.

hahaha Im in over my head!

What better way to learn than head first :smiley:

mumbleelbmum:
What better way to learn than head first :smiley:

I'd say: Learning programming is best done by programming.

So I have the code ready:

#define INPUTMODE INPUT_PULLUP    // INPUT or INPUT_PULLUP
#define BOUNCETIME 50             // bouncing time in milliseconds

byte buttonPins[]={2};// pin numbers of all buttons
#define NUMBUTTONS (sizeof(buttonPins))

#define LED 13
long ledOnTime, ledCycleTime;
boolean ledIsOn;
unsigned long lastPulseTime, lastLEDcycleStart;


byte buttonState[NUMBUTTONS];  // array holds the actual HIGH/LOW states
byte buttonChange[NUMBUTTONS]; // array holds the state changes when button is pressed or released
enum{UNCHANGED,BUTTONUP,BUTTONDOWN};

void input(){
// read the input state and state changes of all buttons
  static unsigned long lastButtonTime; // time stamp for remembering the time when the button states were last read
  memset(buttonChange,0,sizeof(buttonChange)); // reset all old state changes
  if (millis()-lastButtonTime<BOUNCETIME) return;  // within bounce time: leave the function
  lastButtonTime=millis(); // remember the current time
  for (int i=0;i<NUMBUTTONS;i++) 
  {
    byte curState=digitalRead(buttonPins[i]);        // current button state
    if (INPUTMODE==INPUT_PULLUP) curState=!curState; // logic is inverted with INPUT_PULLUP
    if (curState!=buttonState[i])                    // state change detected
    {
      if (curState==HIGH) buttonChange[i]=BUTTONDOWN;
      else buttonChange[i]=BUTTONUP;
    }
    buttonState[i]=curState;  // save the current button state
  }
}

void debugCycleTime()
{
  Serial.print("Cycle time: ");
  Serial.print(ledCycleTime);
  Serial.print("   on time: ");
  Serial.print(ledOnTime);
  Serial.println();
}



void processing()
{
  long nowMillis=millis();
  if (buttonChange[0]==BUTTONDOWN)
  { // new pulse detected, recalculate the new ledCycleTime and ledOnTime
    ledCycleTime= (nowMillis-lastPulseTime)/10;
    ledOnTime=ledCycleTime/5;
    lastPulseTime=nowMillis;
    debugCycleTime();
  }
  if (nowMillis-lastLEDcycleStart>=ledCycleTime)
  {
    lastLEDcycleStart+=ledCycleTime;
  }
  if (nowMillis-lastLEDcycleStart<ledOnTime)
    ledIsOn=true;
  else   
    ledIsOn=false;
}

void output()
{
  if (ledIsOn)
    digitalWrite(LED,HIGH);
  else
    digitalWrite(LED,LOW);
}



void setup() {                
  Serial.begin(9600);
  for (int i=0;i<NUMBUTTONS;i++)
  {
    pinMode(buttonPins[i],INPUTMODE);
  }
  pinMode(LED, OUTPUT);     
  Serial.println("Waiting for first pulse...");
  do
  {
    input();
  } while (buttonChange[0]!=BUTTONDOWN);
  lastPulseTime=millis();
  Serial.println("Waiting for second pulse...");
  do
  {
    input();
  } while (buttonChange[0]!=BUTTONDOWN);
  long nowMillis=millis();
  ledCycleTime= (nowMillis-lastPulseTime)/10;
  ledOnTime=ledCycleTime/5;
  lastPulseTime=nowMillis;
  lastLEDcycleStart=nowMillis;
  Serial.println("System up and running!");
  debugCycleTime();
}

void loop() {
  input();
  processing();
  output();
}

The "input()" function is a little bit complicated for reading just a single input, normally this function is what I use for reading multiple buttons. As your signal is very slow, I've set the possible bouncetime to a relatively high value of 50 milliseconds for debouncing.

On the other side the output function is very short, also the loop() function.

mumbleelbmum:
No led before the first 2 pulses

OK, so you will see just two debug messages on Serial "Waiting for first pulse..." before the first pulse and ""Waiting for second pulse..." before the loop() function starts running.

mumbleelbmum:
Yes shorter pulses with a fixed High time but still relative to the flow meter output..

The current duty cycle is now set to 20% of the cycle time, by calculating:
ledOnTime=ledCycleTime/5;

If you need a fixed "on" time for the pulse generation, you can set it instead.

mumbleelbmum:
and it would need to stop after 5 min or so after no input from flow meter...As to not waste chemical.

Implementing a "timeout" to stop the whole thing would be up to you. It's not included in my code.

Perhaps have a look.

You can test the code opening the Serial monitor and simulate your input pulses with a wire betwen GND and the input pin-2. The LED on pin-13 then starts pulsing 10 times as quickly as you simulate pulses.

That is Excellent! very awesome! Ill keep messing with it. Thank you! :smiley:

jurs:
I'd say: Learning programming is best done by programming.

So I have the code ready:

#define INPUTMODE INPUT_PULLUP    // INPUT or INPUT_PULLUP

#define BOUNCETIME 50            // bouncing time in milliseconds

byte buttonPins[]={2};// pin numbers of all buttons
#define NUMBUTTONS (sizeof(buttonPins))

#define LED 13
long ledOnTime, ledCycleTime;
boolean ledIsOn;
unsigned long lastPulseTime, lastLEDcycleStart;

byte buttonState[NUMBUTTONS];  // array holds the actual HIGH/LOW states
byte buttonChange[NUMBUTTONS]; // array holds the state changes when button is pressed or released
enum{UNCHANGED,BUTTONUP,BUTTONDOWN};

void input(){
// read the input state and state changes of all buttons
  static unsigned long lastButtonTime; // time stamp for remembering the time when the button states were last read
  memset(buttonChange,0,sizeof(buttonChange)); // reset all old state changes
  if (millis()-lastButtonTime<BOUNCETIME) return;  // within bounce time: leave the function
  lastButtonTime=millis(); // remember the current time
  for (int i=0;i<NUMBUTTONS;i++)
  {
    byte curState=digitalRead(buttonPins[i]);        // current button state
    if (INPUTMODE==INPUT_PULLUP) curState=!curState; // logic is inverted with INPUT_PULLUP
    if (curState!=buttonState[i])                    // state change detected
    {
      if (curState==HIGH) buttonChange[i]=BUTTONDOWN;
      else buttonChange[i]=BUTTONUP;
    }
    buttonState[i]=curState;  // save the current button state
  }
}

void debugCycleTime()
{
  Serial.print("Cycle time: ");
  Serial.print(ledCycleTime);
  Serial.print("  on time: ");
  Serial.print(ledOnTime);
  Serial.println();
}

void processing()
{
  long nowMillis=millis();
  if (buttonChange[0]==BUTTONDOWN)
  { // new pulse detected, recalculate the new ledCycleTime and ledOnTime
    ledCycleTime= (nowMillis-lastPulseTime)/10;
    ledOnTime=ledCycleTime/5;
    lastPulseTime=nowMillis;
    debugCycleTime();
  }
  if (nowMillis-lastLEDcycleStart>=ledCycleTime)
  {
    lastLEDcycleStart+=ledCycleTime;
  }
  if (nowMillis-lastLEDcycleStart<ledOnTime)
    ledIsOn=true;
  else 
    ledIsOn=false;
}

void output()
{
  if (ledIsOn)
    digitalWrite(LED,HIGH);
  else
    digitalWrite(LED,LOW);
}

void setup() {               
  Serial.begin(9600);
  for (int i=0;i<NUMBUTTONS;i++)
  {
    pinMode(buttonPins[i],INPUTMODE);
  }
  pinMode(LED, OUTPUT);   
  Serial.println("Waiting for first pulse...");
  do
  {
    input();
  } while (buttonChange[0]!=BUTTONDOWN);
  lastPulseTime=millis();
  Serial.println("Waiting for second pulse...");
  do
  {
    input();
  } while (buttonChange[0]!=BUTTONDOWN);
  long nowMillis=millis();
  ledCycleTime= (nowMillis-lastPulseTime)/10;
  ledOnTime=ledCycleTime/5;
  lastPulseTime=nowMillis;
  lastLEDcycleStart=nowMillis;
  Serial.println("System up and running!");
  debugCycleTime();
}

void loop() {
  input();
  processing();
  output();
}




The "input()" function is a little bit complicated for reading just a single input, normally this function is what I use for reading multiple buttons. As your signal is very slow, I've set the possible bouncetime to a relatively high value of 50 milliseconds for debouncing.

On the other side the output function is very short, also the loop() function.

OK, so you will see just two debug messages on Serial "Waiting for first pulse..." before the first pulse and ""Waiting for second pulse..." before the loop() function starts running.

The current duty cycle is now set to 20% of the cycle time, by calculating:
ledOnTime=ledCycleTime/5;

If you need a fixed "on" time for the pulse generation, you can set it instead.

Implementing a "timeout" to stop the whole thing would be up to you. It's not included in my code.

Perhaps have a look.

You can test the code opening the Serial monitor and simulate your input pulses with a wire betwen GND and the input pin-2. The LED on pin-13 then starts pulsing 10 times as quickly as you simulate pulses.

So what about adding an LCD-keypad shield to control the pulse Rate and view data?

mumbleelbmum:
So what about adding an LCD-keypad shield to control the pulse Rate and view data?

Adding a LCD keypad shield for displaying current values is easy with minor changes.

If you want to show data which is not currently provided in a global variable, you'd have to create a variable for it. I.e. for the duration of the last rotation of the turbine, if you want to show that.

You just need to know what values you want to show, then change the "output()" function to print the values on LCD, i.e. with a one second update rate.

The "pulse rate" cannot be controlled by you, as the "pulse rate" is solely dependent on the turbine rotation. That's how you wanted the processing logic: Generated pulse rate = 10 times the pulse rate of the turbine. What could be adjustable would be the "duty cycle" of the generated pulses. The duty cycle of the generated pulses is currently set to 20% with this line of code:

ledOnTime=ledCycleTime/5;

But this could be adjustable.

The easiest solution for adjusting the duty cycle of generated pulses would be an potentiometer attached to the Arduino.

Jeez - why have you two Threads about this project ?

I put a lot of effort into a reply in your other Thread and it looks like I was just wasting my time.

...R

Robin2:
Jeez - why have you two Threads about this project ?

I think, meanwhile and if counted all together, he has started THREE threads on the same topic.

1st thread: Need some direction. - Project Guidance - Arduino Forum**
(That's this one, where I posted the code for him that he now carries from one thread to the other)

2nd thread: Need help with wiring. - Project Guidance - Arduino Forum**

3rd thread: pulse multiplier NEED WISDOM!! - Project Guidance - Arduino Forum**

Perhaps he is getting paid by the number of new threads he opens in this forum?
:money_mouth_face:

P.S.: If you'd see a code where the loop function looks like that:

void loop() {
  input();
  processing();
  output();
}

it will most likely be a code initiated by me. As it seems, I'm the one and only Arduino programmer in the whole world until now, who is propagating a strictly IPO programming model (Input-Processing-Output) for writing Arduino sketches, using that same piece of code as the loop() logic.

Okay, so ive done a good job of making this very confusing for everyone and for that i apologize.
Im a beginner.... i understand that there is a right and wrong way to use this forum and i don't mean to waste time. i will do better at this.

mumbleelbmum:
Okay, so ive done a good job of making this very confusing for everyone and for that i apologize.
Im a beginner.... i understand that there is a right and wrong way to use this forum and i don't mean to waste time. i will do better at this.

@jurs is WRONG.
I believe there are FOUR Threads - he missed this one 298938

This is crazy nonsense.

I am not going to make any attempt to help until @mumbleelbum gets the moderators to lock all but one of these Threads or (preferably) gets them all merged in to one. Just click the "report to moderator" link.

...R