First of, don’t use mere numbers for pins, please stick with the D0, D1, A0, … convention (Arduino “compatibility” or not).
Next I don’t see where you ever reset pulses after you have watered once.
If you call attachInterrupt() in Water() then you might want to detachInterrupt() once you are done - or you only attachInterrupt() once in the constructor.
If you have a switch or button you should use INPUT_PULLUP instead of INPUT (unless you got an external pull-up).
Your Water() routines are very long running, so they should have a Particle.process() inside their while() loops and you are not allowed to call such long running functions from within your button interrupt handler.
Rather only set a flag in the ISR and call your Water() functions from loop() depending on the state of that flag.
Also consider making your Water() functions non-blocking as currently you’ll first work valve1 and only after that’s finished valve2 but this could be done in parallel.
I’d even put the limit check inside the ISRs, so that you just say go and the ISR cares about the stopping.
I guess that’s enough for the start, before going into attaching class methods to an interrupt.
The link you posted there was not leading to peekay123’s latest code - that’s just a few posts down (and some things have changed since too ;-))
it’s basic millis() timer… a drop-in I use in my projects, tried and tested.
Anyways, it isn’t germane to the example or to what OP is concerned about here… just a way of updating the currentTime, so one can see if the device is updating the cloud in real time.
great job editing though, you really aligned those statements nicely.
I am also interested what that can be. It looks like anonymous function in other languages, but from the description it should run, not just declare. Can you please explain what C trickery is behind that?
So that's where I am supposed to get confused? I think I mighta went a few lines early
Major thanks to you @ScruffR and @BulldogLowell for your INPUT!! There is a lot here I am unfamiliar with and I am generating all sorts of questions.
First, about my code:
I tried using D at one point and was griefed by the compiler so I abandoned it, I will figure out what I did wrong and put it back into practice
You're right, its not there. I had tried putting it in several places, I figured the most logical place would be in the Water() function just before the while() statement. I think I was told I didn't have it defined in that scope. I tried moving it around and if it was defined where I moved the 'reseter' it wasn't defined in the pulser() or Water() functions.
I think you are pointing out a concern that crossed my mind. Does looping digitalWrite() to the valvePin use up all the processor? And does Particle.process() avoid this? Will I be able to have it hold the valve open without thinking about it until it is time to close? I will research Particle.process()
@BulldogLowell, you created a class for the flowmeter and didn't use one for the valves, Why is this? I didn't mention earlier that I will be adding more valves, having them classed would be nice for that, is there any reason other than there are only two?
This is my first micro controller project, my first C++ and also my first Particle project, I was just gonna get everything working with a button then move to a web controller. At the projects end I will be able to specify a volume per valve and have it all go with one button push.
You mentioned that you wanted multiple solenoid valves to access the same flow meter, so I created a FlowMeter object with methods that can affect the multiple solenoids (but one at a time). Building a Valve class seems overkill to me. They have only a pin and a state, and that is nicely dealt with with existing functions. Each valve is controlled by the same ISR callback and that function is "attached" to the FlowMeter object. Because the interrupts are driving the valves, we need not hold in a Water function like your code suggested (I couldn't really see where you were going with your class and methods, but admittedly didn't spend much time with it).
If you used several solenoid valves with several FlowMeters, I may have approached it differently. Actually, if I programmed this from the start, I may not have used a class unless I planned on blowing this up to something bigger.
You can easily add a pushbutton switch to initiate the watering sequence, it is rather trivial. You bought a Particle, so I went right to the Particle.function() to initiate the sequencing of the valves. It seemed like a natural next step for you; starting the watering over the internet.
If that wasn't declared there it would not have been declared one line down where you used it for your while(pulses < waterLimit) either
It's not what you have in your while() but it's the while() itself which keeps the code from doing the cloud house keeping which would happen each way round loop() otherwise. But this is what Particle.process() does then instead to keep the cloud connection alive.
Once you set a pin HIGH or LOW it will remain in this state until you tell the pin to do otherwise.
Eventually my system will involve many branches, sensors, flowmeters, valves, pumps, and Photons. I am trying to put together a simple prototype. Anything that's not too complicated and I can scale later would be nice to get out of the way. I am still making sense of everything you have going on in your script, it certainly seems much more robust than what I had. I will get it straight and see if I can make it work
I have been looking at some of these Particle functions and it seems it may even be easier to use them than a button, diving straight into web controlling seems to make sense.
You use this to set interrupt handler to a method of a class. You pass method and instance of class (this). It is in docs, but bit buried in.
! negates a boolean, so in case of int it means volume == 0 (because non zero _volume in boolean context as in if() translates to true, ! negating it) && is boolean "and", meaning both conditions must be true. Basic boolean operators.
Enum is basically set of named values, yes. You could use just numbers for state, but enum makes code easier to understand and less likely to make an mistake.
This might be simplifying things:
The this pointer is a C++ construct that's provided to each object to have some way of accessing itself.
Since each object (meaning its non-static members) can live all over the place (and can even move once instatiated) in RAM you need to keep track of it by means of this pointer.
But the member functions will always be "static". So you need to provide the location of the static function (that's the ampersand & for) but also need to let the code know where to find the non-static members when the system calls that function as ISR.
the & operator passes the function "by address" allowing the attachInterrupt() to call a class member function, which is explained here in the particle docs: