Go Down

Topic: Starting and stopping a timer (Read 23767 times) previous topic - next topic

houdinihar

Hello everyone.

I have the YUN and have looked at several different examples of time and timer functions and libraries.
One that I thought might work is from the Simon Monk updated libary here: https://github.com/JChristensen/Timer
Here is this simple example from the download:

Code: [Select]
#include "Timer.h"

Timer t;
int pin = 13;

void setup()
{
  pinMode(pin, OUTPUT);
  t.pulse(pin, 10 * 1000, HIGH); // 10 seconds
  // t.pulse(pin, 10 * 60 * 1000, HIGH); // 10 minutes 
}

void loop()
{
  t.update();
}



For my own purpose I encapsulated the code into a  set of functions:

Code: [Select]
void onTimer (void)
{
  pinMode(pin, OUTPUT);   //pin 13 output- pin already defined earlier so I can turn on the LED
  digitalWrite(pin,LOW); //force to off
  t.pulse(pin, 2 * 60 * 1000, HIGH); // on for 2 minutes
Console.println("Timer turned on");
  Console.println();
}

void offTimer (void)
{
t.pulse(pin, 3 * 60 * 1000, LOW); // off for 3  minutes
  Console.println("Timer turned off");
  Console.println();
//essentially after this t.pulse() has finished, everything s/b reset and ready to be responded to in the main loop again.

}


I call the "onTimer" function from inside "void loop(void)" from an event driven "if" statement pending the meeting of certain criteria. When I run my sketch, I can successfully get to the "println" statement in the "onTimer" function just fine and my LED is lit up.

My problem is, after the time has elapsed, nothing changes. I mean the "onTimer" function, specifically the:
Code: [Select]
t.pulse(pin, 2 * 60 * 1000, HIGH);

does not automatically reset the pin to LOW.
Not mentioned on our site here:
http://playground.arduino.cc/code/timer
but present in the Timer.cpp file is this wording and I wonder if this may work;

Code: [Select]
/**
* This method will generate a pulse of startingValue, starting immediately and of
* length period. The pin will be left in the !startingValue state
*/
int8_t Timer::pulseImmediate(uint8_t pin, unsigned long period, uint8_t pulseValue)
{
int8_t id(oscillate(pin, period, pulseValue, 1));
// now fix the repeat count
if (id >= 0 && id < MAX_NUMBER_OF_EVENTS) {
_events[id].repeatCount = 1;
}
return id;
}


The key here as per the library is "The pin will be left in the !startingValue state". But actually, this code does not seem to reset the pin to its !startingValue state--if it did that would be great!!! I could code for that event and have it trigger something else. Maybe I did something wrong. always possible.

As it is though, I am wanting to get a total of 5 minutes per cycle using a software timer. Two minutes on and 3 minutes off. Also, it does not appear that any two statements can be combined into a single function thru this library. Each has to be alone and called separately.

Repeating essentially as above:
Another sticking point is actually responding to when a timer is finished (if indeed the pin is not set to the !startingValue state) and then doing the next code, function "void offTimer (void)" in this case. If this were merely a hardcoded external event control like it is for starting the first timer, it would be easier since some external event would trigger the "void offTimer (void)," but it isn't .

I didn't see any particular function in the  *.h or *.cpp files giving me that ability, although there is a "stop()" function that can stop a timer based on knowing its id. The problem still remains that the stop needs to be triggered by either the event finishing and notifying me, or some other timer/counter telling me it's done which must be based on my timer input length parameter (2 min, 3 min, etc), or a button click, etc;. Not only that, I wouldn't necessarily want to stop my timer until it was finished unless, I needed a panic button, but it could be useful.

So I suspect there must be something not really clear to me here. If anyone has a theory or actually knows of code that works and which would go on working  perpetually weeks or months at a time after loading my sketch, then I would love to see this. Please don't suggest delay()-its not practical in this situation.

Thanks for everyone's help here in our forums.
houdinihar

divedj

Hi houdinihar,

sorry, I don't have any experience with the libraries you are using. However, I am working a lot with timers and timings and I always managed to get it done like:

Code: [Select]

boolean programEnd = true;
unsigned long reference time = 0;

void setup() {
  // put your setup code here, to run once:

}

void loop()
 
  if(programmEnd) referenceTime = millis()/1000:
  if(call_timer(int start, int duration)) {
    //code to switch on led, motor etc;
    programmEnd = false;
  }
  if(call_timer(int start, int duration)) {
    //code to switch off led, notor etc.
    programmEnd = false;
  }
  if(call_timer == false) programmEnd = true;
}

boolean call_timer(int start, int duration){
  unsigned long time = millis()/1000;
  unsigned long startTime = referenceTime + start;
  unsigned long endTime = startTime + duration;
  if(time >= startTime && time <= endTime) return true;
}


The only thing you have to do is a little maths to fill in the numbers for int start and int duration in the function call
If you want to start the program without delay and you want to run it for lets say 3 minutes you would need to make the first function call as

call_timer(0, 180); // where the 0 represents 0 delay and 180 would represent 180 seconds for three minutes

the second function call would need to start with a 181 seconds delay to avoid over lapping and again we need the running time which we could make 2 minutes as example. The second function call would be:

call_timer(181, 120);

Hope it helped you a little

Regards
divedj

casemod

You could use an ISR as well. Set the timer overflow to whatever duration you want an off you go.

This gives you a maximum duration of about 4 seconds with a 16bit timer if I didn't miss anything.
For periods larger than this, increase a counter within the ISR and verify that the overflow count is within a given value. When the condition becomes true stop the timer or toggle the output or [insert your favorite here].
CircuitGuru
http://www.circuitguru.co.uk/

houdinihar

Hello divedj,

I will examine this code soon and put it to the test in a very simple sketch.
It was much simpler than my own. TY

Hi casemod, having only 4 sec would be no use in my timer. My timers will max out at 18 hours. Thanks

Quote
maximum duration of about 4 seconds with a 16bit timer

casemod

Hardware counter. Afterwords, use a software counter to serve that interrupt every 4 seconds. You can get 79h with a int or 545Years with a long.

For the second option use an atmel with ROM and not flash which the data retention is limited to about 45Years.
CircuitGuru
http://www.circuitguru.co.uk/

houdinihar

Hello you all.
I suspect a lot of people starting out with Arduino products, like me, have trouble timing certain events or the need to cause a certain even to occur.

After much searching, reading, and experimenting literally for hours, I have finally arrived at a solution that works for my situation and could possibly work for others who may be having trouble. I did away with an outside library that had its own unique qualifiers and stayed with the simple millis(); I have discovered that based on the complexity of the sketch and maybe streaming to the local web page, certain initial timing events can lag. I have no need for timing anything for a few seconds. Everything I need is from minutes to hours, so any initial lag is not critical to my application.

I welcome anyone to examine this code and make comments and suggest improvements to reduce code or other overhead.  Everything I use is either indirectly derived from the open source community or directly borrowed from it. The only uniqueness is to my personal needs. The data is generic enough to be easily modified, I believe, to fit a variety of situations.

My current board of use is an Arduino YUN and sketches are loaded wirelessly. My optically isolated quad channel relays (5v dc on controlling 110 volt 10 amp max AC) are directly connected and purchased from Ebay. Also, the fine print is important--when they say 5v, it must be 5 volts, because 3.3v will not trigger the device, although their LED is lit up with 3.3v.
I am expanding to Xbee communication in my next section of experimentation to offer myself the remote capabilities that I actually want--one must crawl before walking.
My sensor is a simple DHT11 using their library. All sensor streaming is done locally, but I will be adapting my code for Internet access soon. I also will use a DHT11 module in the near term and connect to a solder board with its own regulated power supply to alleviate data/power interruption because of loose wires at times on the breadboard. These are the basics in a nutshell.

Here is the abbreviated timer code of interest:

Code: [Select]

//Relay Data  --only need these 2 -this replaces HIGH -LOW for facility since these relays
//have LOW as normally on
#define RELAY_ON 0
#define RELAY_OFF 1

/* Declare variable pins- for me at this time*/
#define Relay_1 A1  //analog 1

static boolean pinOnA1 = false; //these pin choices are merely for easy id by me to keep up with what I'm doing
//and how my relays are connected

static unsigned long  offpinTimeA1 = 0; //variable to hold a large time value number


//more variables, declarations, definitions, and libraries here of course-left out for brevity

void setup(){
//other code here, including other initialization sequences

  //initalize pins so relays are inactive 
  digitalWrite(Relay_1, RELAY_OFF);   
  //add other relays as needed
 
  //set pins as outputs, 1 unique pin per relay
  pinMode(Relay_1, OUTPUT);
  //add other pins as needed

}


/*----Timer section   -sensor activated by temperature variable f, to control a fan
for my personal use, I wanted my fanRuntime to be 900000 millis, or 15 minutes on and 3 hours 45 minutes fanOfftime for a total time of 4 hour cycles to be repeated constantly during a 24 hour period
Time holding variables are all unsigned longs----*/

//pinOnA1 is assigned to pin A1 for this example only and initially set to "false"--could be another pin assignment
//my if statements again are geared for my own unique needs and will be changed by you.

void loop() {

      if (f > 75 && f < 95 && pinOnA1 == false && millis() - offpinTimeA1 > fanOfftime) 
   {   
    digitalWrite(Relay_1, RELAY_ON);  //force relay 1 to on
    pinOnA1 = true; //change pin state-- need to know pin state for setting On/Off (if) conditions       
    onpinTimeA1 = 0; //clear any old onpinTimeA1 value
    onpinTimeA1 = millis(); //current millis
   }
       
   //must force the relay off by using this if statement--I am using a set length of time--
   //could be setup to be purely sensor based as well if needed or desired

   if (pinOnA1 == true && millis() - onpinTimeA1 > fanRuntime) 
   {
      digitalWrite(Relay_1, RELAY_OFF);  //force to off             
      pinOnA1 = false;  //reset pin state to false for re-evaluation in the "if" statements
      offpinTimeA1 = 0; //clear any old offpinTimeA1 value     
      offpinTimeA1 = millis(); //current millis
    }

//add any other code as appropriate to your situation


}


Hopes this is beneficial to someone. Most of the code to run this simple timer is included. Some of the variables left out. You can use the pin 13 merely to evaluate the on/off state with the onboard LED. At least that way you can test various time lengths in milleseconds whether you have a real relay attached or not. You would substitute the digitalWrites this way:

Code: [Select]

//declare the:
int pin13 = 13;
//and
pinMode(pin13, OUTPUT);

digitalWrite(pin13, HIGH);  //for on and LOW for off
//place code in appropriate sections of the sketch
//comment out what you don't need.


Quick and dirty way without a relay in place. Or do an off board LED timer blinker without using the delay() function.

I appreciate everyone's help here and for those who have given us this open source code to help us on our way.
houdinihar

Go Up