NEWBIE: Pulse counting problem

Hi folks, never played with Arduino before so trying my best.

My project is to make a solenoid pump driver that counts a pre-determined number pulses on Pin2 and then opens a solenoid driven by Pin13 for a specific duration and repeats.

Basically

X = number of pulses to count before activating pump Y = fixed delay between opening and closing solenoid (milliseconds)

• Define X • Count X pulses • Set Pin13 output high • Delay Y milliseconds • Set Pin13 output low • Loop

So far I have set up the hardware which works fine - I have tested the solenoid by messing with the Blink Sketch timings.

This is as far as I've got with the coding - it uploads but it doesn't work. I have connected a switch from +5v pin to the input of Pin2 to test input manually but eventually the pulse input rate will be between 30 - 500Hz

// this constant won't change: const int IP1 = 2; // the pin that the pulse is attached to const int SOLENOID = 13; // the pin that the LED is attached to const int X = 10; // X is the no of pulses to count before firing solenoid const int Y = 50; // Y is the fixed delay between open and close of solenoid

// Variables will change: int PulseCounter = 0; // counter for the number of pulses int PulseState = 0; // current state of the pulse pin int lastPulseState = 0; // previous state of the pulse pin

void setup() { // initialize the pulse pin as a input: pinMode(IP1, INPUT); // initialize the solenoid as an output: pinMode(SOLENOID, OUTPUT); // initialize serial communication: }

void loop() { // read the pulse input pin: PulseState = digitalRead(IP1);

// compare the PulseState to its previous state if (PulseState != lastPulseState) { // if the state has changed, increment the counter if (PulseState == HIGH) { // if the current state is HIGH then the pulse // went from LOW to HIGH: PulseCounter++; } else { // if the current state is LOW then the pulse // went from HIGH to LOW: } } // save the current state as the last state, //for next time through the loop lastPulseState = PulseState;

// turns on the solenoid every X pulses // delays by Y milliseconds // turns off the solenoid // resets the pulse counter to zero if (PulseCounter == X) { digitalWrite(SOLENOID, HIGH); delay (Y); digitalWrite(SOLENOID, LOW); int PulseCounter = 0; } else { digitalWrite(SOLENOID, LOW); }

}

I have two questions:

1. What am I missing to get this current sketch to work (with USB connection the solenoid randomly fires - do I need to define a pull-down resistor on Pin2? 2. Is there a simpler/faster/more efficient method of pulse counting than the state change routine above?

Eventually I plan for X (number of pulses to be counted) to be defined as a result of calculation based on different inputs, but for the moment I am so naive with coding that a constant integer will do just for testing purposes.

do I need to define a pull-down resistor on Pin2?

Unless there is an external resistor, yes. Note that having the internal pullup resistor enable means that LOW is pressed and HIGH is released.

it uploads but it doesn’t work.

No, this is wrong. It works. If it does not do what you expect, that is not the same as not working.

Is there a simpler/faster/more efficient method of pulse counting than the state change routine above?

Simpler? No.
Faster? Yes, using an interrupt handler. But this is faster only in the sense that the change is known immediately. Taking action based on the number of pulses won’t be any faster.
More efficient? You need to define what you mean by efficient.

    int PulseCounter = 0;

Having local variables with the same name as global variables is definitely the way to drive yourself crazy.

I recommend that you post your code within a code block.

Your code here

so we can read it more easily.

I suspect you can think up more meaningful variable names for 'X' and 'Y' to indicate what they're used for. Good choice of variable and function names can make all the difference to understanding what the program does, and spotting where something is being used incorrectly.

Aha! - found the code button

Right sorry for asking dumb questions but we all have to start somewhere.

// this constant won't change:
const int  IP1 = 2;    // the pin that the pulse is attached to
const int SOLENOID = 13;       // the pin that the LED is attached to
const int X = 10;       // X is the no of pulses to count before firing solenoid
const int Y = 50;       // Y is the fixed delay between open and close of solenoid

// Variables will change:
int PulseCounter = 0;   // counter for the number of pulses
int PulseState = 0;         // current state of the pulse pin
int lastPulseState = 0;     // previous state of the pulse pin

void setup() {
  
  pinMode(IP1, INPUT); // initialize the pulse pin as a input:
  pinMode(SOLENOID, OUTPUT); // initialize the solenoid as an output:
  digitalWrite(IP1, LOW); // turn on pull-down resistor on the input
}


void loop() {
  // read the pulse input pin:
  PulseState = digitalRead(IP1);

  // compare the PulseState to its previous state
  if (PulseState != lastPulseState) {
    // if the state has changed, increment the counter
    if (PulseState == HIGH) {
      // if the current state is HIGH then the pulse
      // went from LOW to HIGH:
      PulseCounter++;
    } 
    else {
      // if the current state is LOW then the pulse
      // went from HIGH to LOW:
    }
  }
  // save the current state as the last state, 
  //for next time through the loop
  lastPulseState = PulseState;

  
  // turns on the solenoid every X pulses 
  // delays by Y milliseconds
  // turns off the solenoid
  // resets the pulse counter to zero
  if (PulseCounter == X) {
    digitalWrite(SOLENOID, HIGH);
    delay (Y);
    digitalWrite(SOLENOID, LOW);
    int PulseCounter = 0;   
  } else {
   digitalWrite(SOLENOID, LOW);
  }
  
}

Right hopefully the line

digitalWrite(IP1, LOW); // turn on pull-down resistor on the input

should sort out the input. Is that right?

But how do I sort out resetting the counter to zero after the solenoid operation if int PulseCounter = 0; is no good?

Note that I have used X and Y because I have a long equation to include later and thought it would be easier to read with short symbols on one line.

Right sorry for asking dumb questions but we all have to start somewhere.

I didn't see any dumb questions.

Right hopefully the line Code:

digitalWrite(IP1, LOW); // turn on pull-down resistor on the input

should sort out the input. Is that right?

No. The Arduino does not have internal pull-down resistors. It only has pullup resistors. Those are activated by writing HIGH to the INPUT pin.

But how do I sort out resetting the counter to zero after the solenoid operation if Code:

int PulseCounter = 0;

is no good?

The int keyword there is defining a new variable. Is that really what you want to be doing?

PaulS:

Right hopefully the line Code:

digitalWrite(IP1, LOW); // turn on pull-down resistor on the input

should sort out the input. Is that right?

No. The Arduino does not have internal pull-down resistors. It only has pullup resistors. Those are activated by writing HIGH to the INPUT pin.

OK - I will change it to pull-up and wire the switch back to ground. It shouldn't affect the operation of my test rig as long as the pin rests in a stable state between button pushes. Is that right?

PaulS:

But how do I sort out resetting the counter to zero after the solenoid operation if Code:

int PulseCounter = 0;

is no good?

The int keyword there is defining a new variable. Is that really what you want to be doing?

No, I just want to reset Pulsecounter to Zero but I don't know how to do it, so I am asking for some help. I've read a lot on Arduino over 3 nights or so but it's hard to take it all in when you have no background in computing. what might seem obvious to some is not to a novice.

No, I just want to reset Pulsecounter to Zero but I don't know how to do it, so I am asking for some help.

PulseCounter = 0;

Thanks Phil - I thought it might be something simple :cold_sweat:

I seem to have it doing something now - my switch connection was faulty so simply making a manual ground connection to pin2 now puts the Pin13 LED on occasionally. I assume it will not measure counts correctly like that because it will need to be 'debounced'. Is that right?

PaulS:

Is there a simpler/faster/more efficient method of pulse counting than the state change routine above?

Simpler? No. Faster? Yes, using an interrupt handler. But this is faster only in the sense that the change is known immediately. Taking action based on the number of pulses won't be any faster. More efficient? You need to define what you mean by efficient.

I don't think there is really a need for interrupts, but I wondered if it was possible to use PulseIn to monitor the input pin count rather than the change state routine in order to keep the code shorter.

If the current method works then it should suffice for the moment.

Hello,

When powering-on the Arduino, I believe that specifically in the Uno version, the digital pin 13 flashes a little bit. This also happens whenever you press the reset button.

Please correct me if somehow you managed to disable this behavior.

If that pin is connected to the solenoid, it will trigger the solenoid a couple of times very quickly, thus turning the pump on and off. Depending on the kind of pump it is (powerful or not), this will probably be a good way of damaging it.

About the debouncing, it will depend on the source of the pulses. If they come from a button that is pressed mechanically, then yes, it's usually recommended.

footswitch: Hello,

When powering-on the Arduino, I believe that specifically in the Uno version, the digital pin 13 flashes a little bit. This also happens whenever you press the reset button.

Please correct me if somehow you managed to disable this behavior.

If that pin is connected to the solenoid, it will trigger the solenoid a couple of times very quickly, thus turning the pump on and off. Depending on the kind of pump it is (powerful or not), this will probably be a good way of damaging it.

You are right - I did notice that in testing, but for the purposes of my application that is actually quite handy as it will prime the system. I haven't tested any of the other digital pins (I chose this one because the LED is a useful way of monitoring pump activity), do you know if they exhibit the same erratic start-up pulses or is that exclusive to Pin13?

Another question for the software gurus if I may:

For the purposes of testing I have predefined the number of pulses to count (Xpulses) as a constant integer, however I actually want Xpulses to be defined at the start of each loop by calculation based on the readings taken from two analogue pins:

TPSV = Analogue Throttle Position Sensor input (0 – 1023) 1023 = 5V PotV = Voltage input from preset (0 – 1023) 1023 = 5V Xfactor = a digital input that sets a multiplication factor

Now I have an equation that I came up with to calculate Xpulses, which is:

Xpulses = (PotV – (TPSV/5 * PotV/1023)) *Xfactor

Now that equation is written as I (a sort of human) would understand it with the brackets indicating which calculations to do first. The question is: will Sketch understand it as it is, or is there some other way I need to input it, maybe by calculating the result of each part in turn and then using those results to finally give me a result for Xpulses?

My second question is how to handle decimal points if the result is not a whole number? For my purposes I need the result to be rounded up to the nearest whole number (since it will be impossible to count half a pulse). How do I do that chaps?

Mr_Stickman: do you know if they exhibit the same erratic start-up pulses or is that exclusive to Pin13?

Only pin 13 flashes during startup. Mind you it's not erratic, it's consistent.

Mr_Stickman: Now that equation is written as I (a sort of human) would understand it with the brackets indicating which calculations to do first. The question is: will Sketch understand it as it is, or is there some other way I need to input it, maybe by calculating the result of each part in turn and then using those results to finally give me a result for Xpulses?

That is exactly how the compiler works too. The code would look almost exactly as you have written your formula, assuming PotV and TPSV are variable holding your analogue input values. If you have an equation with several expressions in it, you can put parenthesis around the expressions you want evaluated first. If you don't specify it like this the compiler will use some standard rules about which operators take precedence over each other, and calculate them in that order. In my opinion it is bad practice to relay on operator precedence because it makes it non-obvious what the order of evaluation is.

It is also perfectly valid to divide the equation up into a sequence of simpler equations, and this can make the code clearer if the equation is very complicated, but it also makes the code longer. If you can look at the equation and understand it clearly, then in my opinion there's no reason to break it down any further. Your example code looks perfectly straight forward to me, but you haven't explicitly stated the precedence between the * and / operations:

Xpulses = (PotV – (TPSV/5 * PotV/1023)) *Xfactor

Could be:

Xpulses = (PotV – ((TPSV/5) * (PotV/1023))) *Xfactor

or:

Xpulses = (PotV – (TPSV/((5 * PotV)/1023))) *Xfactor

or any other combination. Probably the first one is what you intended, but best to make it explicit.

Also, when performing calculations like this, you need to consider the type and range of the results of each expression. If you are using integer variables, they will only hold whole numbers. So if you intermediate results produce any fractional values, these will be discarded and the results rounded to the nearest round number. This is a common problem when scaling values by multiply and dividing. In general, when using integer arithmetic you are best advised to arrange the formula so that you do the multiplications first. But you also need to be aware that the integer data types can only hold values within a specific range. If your multiplication produces values too big for the type you're using to hold them, you'll get a condition known as overflow. In this case the result will be garbage. To avoid this, you need to work out the maximum possible value of each intermediate result, and make sure you that the type you use to do the calculation can can hold that value.

As an aside, I doubt that your original formula is correct since it doesn't seem to do anything meaningful with PotV and TPSV.

PeterH: As an aside, I doubt that your original formula is correct since it doesn't seem to do anything meaningful with PotV and TPSV.

Thanks for the reassurance on Sketch's handling of the equation.

The idea for the formula is that PotV presets a number of pulses to count, but that TPSV has up to 20% potential reduction of that result. (hence the 1/5 division and multiplication by PotV/PotV-max). I've done a few rough calculations and the results seem to make sense.

I.e if PotV is 500 (of 1023max) and TPSV is 500 (of 1023max) - roughly mid point so approx 10% reduction and X factor is 1

Xpulses = (PotV – (TPSV/5 * PotV/PotV-max)) * Xfactor

Xpulses = (500 - (500/5 * 500/1023)) * Xfactor

Xpulses = (500 - (100 * 0.49)) * 1

Xpulses = (500 - 49) * 1

Xpulses = 451

Similarly if TPSV was at maximum (1023) then the result would be (500 - (100 * 1)) = 400 so the 20% reduction I was looking for.

Will this formula work though given that PotV/PotV-max will always be a fraction or will I end up with overflows? How do I need to define PotV at the start?

There is an assumption in your example that is wrong.

500/1023 = 0.49

Dividing one int by another int produces an integer result. The division you show would produce either 0 or 1, depending on the value of PotV (almost always 0, unless PotV is 1023).

You'll need to type PotV as a float, or cast it to a float in the equation.

PaulS: You'll need to type PotV as a float, or cast it to a float in the equation.

OK - I don't know what that means or how it works but I'll try to look it up. If you have any links to practical examples of how that might work then please fire away :~

OK I’ve had a little read but not much the wiser. The reference I found said that some people go out of their way to avoid floating point maths because it is much slower to process, and that they multiply by 100 (and presumably divide by 100 later) to keep the calcs within integer maths.

In theory can I do the same, and if I do what happens to fractions behind the decimal point?

e.g. in my previous example:

Xpulses = (PotV – (TPSV/5 * PotV/PotV-max)) * Xfactor

can I change it to:

Xpulses = (PotV – ((TPSV/5 * (100*PotV)/PotV-max)/100)) * Xfactor

Xpulses = (500 - ((500/5 * 50000/1023)/100) * Xfactor

Xpulses = (500 - ((100 * 50000/1023)/100) * Xfactor

Xpulses = (500 - ((100 * 49)/100) * Xfactor // am I right to assume that 50,000/1023 will round up to 49?

Xpulses = (500 - 49) * Xfactor

Would that work?

I guess I have the same problem with small values of TPSV <5 which will also come to a result with a values less than 1

am I right to assume that 50,000/1023 will round up to 49?

No. Integer division results in truncation, not rounding.

The reference I found said that some people go out of their way to avoid floating point maths because it is much slower to process, and that they multiply by 100 (and presumably divide by 100 later) to keep the calcs within integer maths.

How often are you planning to perform this calculation? 30,000 times a second is a reason to avoid floating point arithmetic. Once a week is not.

PaulS:

am I right to assume that 50,000/1023 will round up to 49?

No. Integer division results in truncation, not rounding.

Truncation will do for my needs. Precision accuracy is not important for this job, but reliability is vital so if the maths are easier to work simply and reliably without fractions then surely that is better?

PaulS:

The reference I found said that some people go out of their way to avoid floating point maths because it is much slower to process, and that they multiply by 100 (and presumably divide by 100 later) to keep the calcs within integer maths.

How often are you planning to perform this calculation? 30,000 times a second is a reason to avoid floating point arithmetic. Once a week is not.

Is not understanding floating point maths a good enough reason to avoid it? :)

In which case, will the idea of multiply by 100 and divide by 100 work ok?