Using timer.setTimer() function vs. timer.setInterval()

All -

This particular issue was discussed earlier and was shown as “SOLVED” - however I wanted to approach it from a new angle. It was originally posted as “Reading a tipping bucket rain gauge”.

I posted this earlier today … and it was classified as “SOLVED”, so I am reposting it as a new topic. Sorry for the confusion.

The project I am creating reads the revolutions of a water wheel over a period of time. It uses a Hall sensor and monitors the High/Low state of a digital pin on an MKR1000 board. There are two “timers” being used, one using “timer.set Interval” to call the action of a second timer which uses the “timer.setTimer” function to run every 100 millis and repeats 100 times. The second timer finishes its 100 cycles and returns to the first timer which then should send the data to the Blynk cloud. The program compiles just fine, however the revolution counter variable which is increased in the second timer function (setTimer) does not return its value to the calling function (set.Interval).

In the original “Tipping Bucket” topic …

The comment from Pavel is the same logic I am considering.

I am considering using the timer.setTimer" function from the SimpleTimer library because it allows me to set the timer to repeat every “d” millis for “n” times.

I am including the code snippet from Arduino.

int setTimer(long d, timer_callback f, int n)

Call function f every d milliseconds for n times. The callback function must be declared as void f(). After f has been called the specified number of times, the interval is deleted, therefore the value timerId is no longer valid.

void repeatMeFiveTimes() {
// do something
}

timerId = timer.setTimer(1000, repeatMeFiveTimes, 5);

So my first question is:
Does the Blynk Timer support “timer.setTimer”? I know it supports “timer.setInterval”, because most every timer has that function to create the delay in transferring data.

And if so … I am perplexed that the global variables I have in the sketch do not maintain their values when I exit the set.Timer function.

Second question - Does the “timer.setTimer” function clear the variables that have been modified within that function when it ends its “repeat cycles”? They are definitely global variables called in the beginning of the sketch outside of any function including setup(().

Finally -

I saw that the last comment from the old topic was to use an Interrupt …
I just though that the second timer using a combination of set.Interval and set.Timer function would be an easier approach.

Environment -
Mac oS Sierra 10.12.6
Arduino 1.8.3
Blank 2.10.1
MKR1000 Board

Thanks for any comments or suggestions.

Jim

This was done on purpose:

A) Because it had been solved, just not marked as such way back then.

B) So as not to keep old topics from dragging on… After a long time (4-6+ months), sometimes creating a NEW topic is the way to go :+1:

BlynkTimer is just an integrated form of SimpleTimer (with a few improvements like 16 instances instead of only 10)… so anything the original did, BlynkTimer should do as well; And the exact same way, including int setTimer(long d, timer_callback f, int n)

https://playground.arduino.cc/Code/SimpleTimer#Functions

PS, being integrated, the one difference is that you don’t need to declare a library in order to use it… otherwise everything else is the same.

PPS, remember, sometime a timer will work without it needing to be “named”, other times it requires being “named” aka assigned a timer ID.

Thank you Gunner for the reply -

Yes, I assumed that the Blynk timer was a modification of the SimpleTimer, and the functions would work the same … just had not seen anyone using that setTimer option.

I am including the snippet of code that relates to this issue. Perhaps I am just missing something, but the global variables that are modified within the timer.setTimer() function are not being passed back to the calling function

    //************************************************************************************
    // Function to count revolutions of the water wheel to test for water flow
    // caused by bad pump, or low water conditions
    void flowSensorData()
    {
      // reset the global variables that will be used to check for change in pinStatus (high/low)
      int currentPinStatus = 0;
      int priorPinStatus = 0;
      int revCounter = 0;

      // Call the setTimer function that will check for changes in pinStatus
      // This timer has an interval of 100 milliseconds, and a set time of 100 repititions
      timer.setTimer(100, waterFlowPinStatus, 100);

      // Program returns to this point for error checking and passing data back to the main program

      Serial.println (" Program returns to this point after timer event has stopped ");
      Serial.print (" Revolution Counter from subroutine ");
      Serial.println (revCounter);

      // check for warning notification based on number of revolutions
      if (revCounter <= 1)
      {
          // Send notification and email for warning   
        led1.off();
        led3.on();
      }
      else
      {
        led1.on();
        led3.off();
      }

      // send data to Blynk
      Blynk.virtualWrite(V6, revCounter);

      // Print data for error checking
      Serial.print (" Revolution counter passed to Blynk ");
      Serial.print (revCounter);
      Serial.println (" ");
      Serial.println (" ");

    }



    // ***************************************************************************
    // This is a subroutine that is called within the flowSensorData function
    // It uses a timer with the setTimer option
    // which allows me to run this a specified number of times at specified intervals
    // Currently I have it set to run 100 times with a 100 millisecond interval
    // There is no need to clear the revolution counter, because it will be reset in the calling function

    void waterFlowPinStatus()

    {
      currentPinStatus = digitalRead(waterSensorPin);
      Serial.print ("Current PinStatus ");
      Serial.println (currentPinStatus);
      Serial.print ("Prior Pin Status ");
      Serial.println (priorPinStatus);

      if (currentPinStatus != priorPinStatus)
      {
        // a rotation has occurred, increase revolution counter by one
        revCounter++;
      }

      // reassign current pin status to the prior pin status

      priorPinStatus = currentPinStatus;

      Serial.print (" Rev Counter passed to calling function ");
      Serial.print (revCounter);
      Serial.println (" ");

    }

The code complies and runs, however the revolution counter is not reset to zero and it is not sent to Blynk … or at least it is not showing those actions on the serial monitor.

Suggestions?

Jim

I have edited your post to make your code readable. Please hit the edit button to see how it was done if this is not explanatory enough:

```cpp
Insert code here
```

void flowSensorData()
    {
      // reset the global variables that will be used to check for change in pinStatus (high/low)
      int currentPinStatus = 0;
      int priorPinStatus = 0;
      ....


void waterFlowPinStatus()

    {
      currentPinStatus = digitalRead(waterSensorPin);
      Serial.print ("Current PinStatus ");
      Serial.println (currentPinStatus);
      Serial.print ("Prior Pin Status ");
      Serial.println (priorPinStatus);

      if (currentPinStatus != priorPinStatus)
      {
        // a rotation has occurred, increase revolution counter by one
        revCounter++;
      }
     ....

You are declaring the variables inside the function itself, making them only avalible inside it, while it runs.
Then you try to use something that does not exist inside another function.

Atleast from this snippet you wrote.

Declare them globally and modify locally

 int currentPinStatus = 0;
 int priorPinStatus = 0;

void flowSensorData()
    {
      // reset the global variables that will be used to check for change in pinStatus (high/low)
      currentPinStatus = 0;
      priorPinStatus = 0;
     ....
1 Like

Thank you for your reply Fettkeewl -

I think I understand what you mean by “editing” my post … you removed many of the comment lines just to make the code a little more compact. I do not see an “edit” button however …

That is not really critical … just to be clear however, I do use the “preformatted text” formatting tool when I paste code into my topics.

Back to the issue … Yes, I understand that global variables are to be declared outside of the function. All of my variables are declared in the beginning of the sketch, outside of any function including the setup(). I did remove the “int” prefix when resetting the variables just in case that caused some confusion and perhaps declared the variables again within the function. That has no effect.

Somehow the revCounter variable within the second timer which is called by the first timer.setInterval is the issue. I can change the sketch to not reset the revCounter variable in the calling function and the value is passed correctly. However that does not give me a proper count for the time frame I am checking … it just continues to increase and is not reset to “0”.

I think that when the “timer.setTimer” function finishes its cycles … it still goes back to the calling function and resets the variables before the data is sent to Blynk. I can’t think of a way to set them back to zero when calling the first “timer.setInterval” function and not have them reevaluated before the data is sent to Blynk.

The question is … can you think of another way to count the revolutions for a fixed period of time within a function that is called by a timer.setInterval(). I cannot use “delay”, and a simple count down variable goes so quickly at the speed of the processor. The other thought I had was to use a millis counter within the “while” loop to slow down the reading of the pin status on the MKR1000 processor.

See the prior post for the code …

No one would be editing your comments or anything like that without good reason… however we do “edit” the code postings for better visuals.

Unfortunately the </> formatted text button doesn’t always work for C++ code. The correct way, as shown in the Welcome Topic… that many unfortunately skip over, is to paste your sketch, but then place three backticks and the letters cpp at the beginning and three more backticks at the end of the code, this way it shows up proper.

You could use millis(), or another type timer with incremental counters, boolean logic, etc.

https://www.arduino.cc/en/Reference/Increment

Lots of different ways, however there is no reason using a timer should reset or disable your global variables… I have also used setTimeout() and setTimer() without any issues for non blocking delays and counting applications.

More time would have to be spent following your code line by line to be sure it is not something else. But if you really think it is the timer issue, then consider asking over at the source for further clarification:

Here is an example I have for a relay (door latch) and flashing indicator

//===== LATCH(Relay Sim) & LED PULSE - BLYNK Functions =====
BLYNK_WRITE(V40)  // Virtual button on V40 to activate Relay_LED pulses
{
  RLY_LED = param.asInt();
  if (RLY_LED == 1 && Flag == 0){
    Flag = 1;  // Keeps from allowing button press more then once while relay activated
    digitalWrite(30, HIGH); // Activate Relay
    timer.setTimeout(2000L, Relay2OFF);  // Deactivare Relay after 2 seconds
    timer.setTimer(2000L, LedON, 5);  // Pulse LED routine (LedON/LedOFF) 5 times
  }  // END if
}  // END Blynk Function

void Relay2OFF()
{
  digitalWrite(30, LOW);
  Flag = 0;  // reset flag after relay disables
}  // END Relay2OFF Function

void LedON()
{
  digitalWrite(31, HIGH);  // Turn on LED
  timer.setTimeout(1000L, LedOFF);  // Run OFFLED routine once in 1 second
}  // END LedON Function

void LedOFF()
{
  digitalWrite(31, LOW);  // Turn off LED
}  // END LedOFF Function

Thank you for the clarification. I will be more careful in the future.

I also found my error in resetting the revolution counter. It was simply being reset at the top of the code block, rather than after sending the digital.Write command to Blynk.

Thank you for the help. If you would like me to share my final code, I would be happy. The timer.setTimer function does seem to be a good method of calling a timer with a repeating option.

Regards -

Jim

That would be great… it is always nice to have more code examples for others to see and learn from. :+1:

Gunner -

Thank you for sharing the code snippet … I will study it more carefully and see what I can learn from it.

Because I am new to some of the code techniques, I do have a question. Can you explain the “pram.asInt( )” declaration. I do not understand the use of parameters in creating variables. Or is this only for virtual buttons within Blynk?

Thanks for your patience.

Yes, I believe it is a Blynk creation… It is the Virtual Pin data type part of their creation…

Gunner -

I have not posted code for examples before. Would you like the entire sketch, or just the snippet concerning the timer.setTime( )?

I have no problem with sharing the entire code. Probably a couple hundred lines?
And where do you think I should post it? In the examples? Or just attached to this topic? Do you want an overview of the project included?

Regards -

Jim

If it is a completeish project that you think will encourage, help, or simply entertain others, then create a new topic and choose the “Projects made with Blynk” title… Post the entire thing there. And an overview would be beneficial in that case.

Or if you feel the snippet will be clear enough by itself you can simply post it here. Or do both :slight_smile:

Hello, the only approach in such cases when you want to monitor real time event is to use interrupt. This way you can count amount of pulses in particular period of time, without a danger of losing one. Otherwise if you use pooling method no matter how fast your function will run you are going to miss those pulses.

Conker -

Thank you for your input. If I understand your logic, I would create an interrupt using AttachInterupt( ) and some sort of a timer / milliseconds() counter to run that interrupt for a given period of time … then pass that pulse count to a global variable that would be sent to Blank. After the given time period, I would issue a DetachInterupt( ) command to stop counting pulses. Is that what you are thinking?

In my particular case, the revolutions of the water wheel are rather slow … perhaps 50 rpm, so if I miss one pulse or two by using the timer.setTimer( ) function it is not a major concern. And the simplicity of allowing the timer to act as my start and stop for monitoring the revolutions makes the code much simpler.

I can see that this would not work for high speed counters, or random events that require monitoring for changes in state.

Just my thoughts at this point. Perhaps if I was more comfortable using interrupts I would look at it differently.

Regards -

Jim

Not exactly, you have function which is set on Timer to execute every second. It would take the ammount of pulses that happened during this second and calculate water flow. Interrupt runs all the time and the only thing it does is to increase some kind of timer by 1 on rising edge.

volatile uint16_t count = 0; //It’s increased by interrupt hence you need volatile

void periodicFunctionToExecuteEverySecond(void) {
//Do some calculations like count * 60 would be rpm
//Zero the counter count = 0;
}

void interruptHandler(void) {
count++;
}

OK - I think I understand.

Let me work on a snippet of code and I will reply after testing to see if I have it correct.

It still has to be posted to Blynk which would take place outside of the interrupt, correct?

What I am finding is that the various functions I am calling to check “temperature” or “revolutions” or “power status” are all posting the results to Blynk at the time the functions finish. I think perhaps a wiser choice would be to consolidate the digitalWrite( ) commands to its own timer and all the global variables would be refreshed on Blynk at the same time? That is the same logic I am using to refresh the LCD screen on my device. Any thoughts on that? Or should I post that as a new topic?

Jim