Pages: [1]   Go Down
Author Topic: Manually start event, arduino repeat 10x in X amount time increments & then stop  (Read 2555 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Newbie
*
Karma: 1
Posts: 36
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

how would i go about coding this?  i was going to just use milli() in an if statement w/ the event code to start after the initial event and be X, then when X = ??ms (unsigned long), the event would re-occur again up to 10x at certain intervals and then stop, but it appears no matter where you put milli() it starts when the arduino boots even if the event is not triggered.

the timing is not critical, even +/- a few min would be sufficient.  just need to somehow start a timer or counter to have the event execute 9x additionally then stop.

but this timer can not always be running because the arduino will always be plugged in (so X may become larger than what an unsigned long can handle and i am not sure what happens in that case - does it lock up or restart?), so after the 10th execution, i need the timer to turn off until a manual reset.

thanks in advance,
bob
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 18
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hmm... I'm not sure I perfectly understand, but are you asking the following:
Given a certain time interval for all 10 operations, how do you execute the code in such a way that it spaces out the 10 over over this time interval?

If that is what you meant, I think there's an easy way to do it. (To be honest, I do not have an Arduino, but I do know C/C++/Java/AS3.0, so I think I'm covered for at least a little bit)

You could have your repeated function occur inside a for loop. The basic structure is...
Code:
for (int i = 0; i < x; i++)
{
//code here
}
The Arduino Reference for the for loop can be found here: http://arduino.cc/en/Reference/For

Basically, it assigns 0 to a new integer i. Then, as long as i < x (where x is some comparable type), the code form the body will execute and i will be incremented each time (until i >= x, that is, until i < x is false).

What you would need in this case it to split the time interval into 10 sections, and divide the time between them. It would be similar to the code below.

Code:
unsigned long totalTime = 1000;
unsigned short numRepeats = 10;

miniInterval = totalTime/numRepeats;

for (int i = 0; i < numRepeats; i++)
{
//code here
delay(miniInterval);
}

You can modify the values for the first two vvariables (totalTime and numRepeats). miniInterval is assigned difference in time need given the number of repeats (numRepeats) and the total time the operations should take (totalTime).

There is a small problem that it will go slightly past totalTime, every time, since the last operation is done "exactly" at totalTime (that is, the time that the loop is started plus totalTime).

If I was unclear, feel free to ask questions. If I've gone way track from what you've asked, please tell me.

I'll get back to you about overflowing longs and such; I gotta go eat some supper.

I do not guarantee the above code to work. I am not sure is delay() works in loops. I do not currently own an Arduino board or Arduino compatible board.
Logged

0
Offline Offline
Newbie
*
Karma: 1
Posts: 36
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

thank you very much for the assistance, it is actually easier than your fine cod.  i can set the interval manually so no math in that area is needed, i just need to figure out how to get a timer/counter going to actually time whatever i set as the timed amount so it is just for this 1 event and not a global timer/counter that continues when the unit is powered like milli().  then every time the timer/counter reaches the time i state, the event counter would be incremented until it hits 9 at which time it would stop completely.

again, thanks so much for the assistance,
bob
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 18
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Ahh, I think I see now. So you need a dedicated timer to start when you specify? And on each "tick" or completion of that timer, you increment some count until the count is 9 I suppose.

There's a few ways to do that. One does not necessarily involve a timer - if you can figure out a conversion for clock cycles per second to events per second it's really easy. I can't currently do it for you without knowing your oscillator frequency... though I could give you a formula if you wish? This approach basically increments a counting variable for each clock cycle (each run through "loop"), and incrementing your event counter when that is at a certain value corresponding to an amount of time. The trouble with this is that it doesn't really work in practice I think (other code taking up clock cycles).

I guess from here I have to ask another question. Do you expect your setup to time these in a sort of "sleep" mode? The reason I ask if because you mentioned something about millis only counting from the time that the system is running.

Assuming the Arduino board is always running, I'm sure there's a way. I can think of a cheap way to do it with millis (could be the most accurate?).
Could also be done with extra hardware (crystal dedicated to incrementing to a certain point, then pulsing on an interrupt on the Arduino). Actually, you could have a separate oscillator purely to pulse on an interrupt somehow (not sure if it's easily possible), and use the interrupt method to increment a counter. Since the oscillator (Crystal or resonator. A resonator should actually work fine, be cheaper, and more compact. They're not as realiable for time consistency, but if it does not matter for your application it is probably better)

Anyone else have some insight?
Logged

0
Offline Offline
Newbie
*
Karma: 1
Posts: 36
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

thanks for getting back to me smiley

the arduino will be powered the whole time, no sleep mode.

exactly, i just need to make sure it executes the 10x and then stop, just for example say every 10mins or basically any time for that matter.  timing is not critical at all.  if i want it to go every 10mins, and it executes every 11min i would be a happy camper, 12mins, still a happy camper - as you can tell it is not very time critical smiley

i know the atmega328 has multiple timers in them, i just do not know how to access them thus my reason for the millis() thought...
Logged

0
Offline Offline
Newbie
*
Karma: 1
Posts: 36
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Camalaio, i think i may have found what i am looking for - http://www.arduino.cc/playground/Code/SimpleTimer

my searchfu must have been way off earlier  smiley-eek-blue

does anybody know what type of qualification is necessary to code up in the 'playground' - has it been tested by the community?  is there a way to use a timer from inside a loop that is part of the arduino code?  that has been very thoroughly tested?
« Last Edit: February 16, 2011, 12:22:50 am by bob4432 » Logged

0
Offline Offline
Newbie
*
Karma: 1
Posts: 36
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

so i could just put my event in here if using the simple timer:

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.

Code:
void repeatMeqTenTimes() {
    // put my code here
}

timerId = timer.setTimer(1000, repeatMeTenTimes, 10);

seems like a nice setup....anybody see anything wrong w/ doing this this way?
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 18
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Will the system be doing anything during those breaks?

If not, then I know at least one of the following three should work: Note: I do not know if the compiler supports recursive functions (for (2)). Also, delay() apparently is a hog, so almost nothing else will go on.
1) You can do something similar to the for loop using delay() as I first pointed out. Or use delay() somehow.
2) Eliminate the loop, but still use delay() inside a recursive function. This is the basic setup.
Code:
//----First way. Uses external counter.----
int ticker = 0; //this is your counter for counting up to 10 times.
void tick()
{
delay(60000); //wait for 1 minute
ticker++; // just incrementing the count after the wait
if (ticker > 9)
{
// What to do once the 10 times are complete.
}
else
{
tick(); // Calls the function again, effectively acting like a loop. Will still cancel on ticker>9, because the condition is there with each call.
}
}

//----Second way. Same idea, but different..----
int ticker = 0; //this is your counter for counting up to 10 times.
void tick()
{
delay(60000); //wait for 1 minute
ticker++; // just incrementing the count after the wait
if (ticker <= 9) // different condition. Basically just saying that if the counter isn't at 9 yet, keep ticking.
{
tick();
}
}

//----Third way. Uses recursion with passed parameters.----
void tick(unsigned int ticker)
{
delay(60000); //wait for 1 minute
if (ticker <= 9)
{
ticker++;
tick(ticker); //recursively passes the increasing value.
}
}

//----Final way. Same as 3, but more compacted----
void tick(unsigned int ticker)
{
delay(60000); //wait for 1 minute
if (ticker <= 9)
tick(ticker++); //recursively passes the increasing value.
}
3) Use millis(). Record what millis() is when you start, then use delay() or something while looping to to check if currentMillis (that is, call millis()) >= startMillis+miniInterval (where miniInterval is the time between each event in milliseconds)

If other things are going on during the time interval, OR if you are trying to save power, then a hardware implementation will work better. As said, the basic idea is to oscillate on an interrupt pin. You'd have it set up similar to the following: Note: Use http://arduino.cc/en/Reference/AttachInterrupt for reference on interrupts.
Code:
unsigned long miniCounter = 0;
unsigned long threshold = 960000000; // will allow miniCounter to go up to a full minute
// the above comes from (crystal speed in Hz) * (desired number of seconds)
// I assumed 16MHz (16000000Hz) and 60 seconds.
unsigned int wholeConter = 0;
void tick()
{
miniCounter++;
if (miniCounter >= threshold)
{
miniCounter = 0;
wholeCounter++;
}
}

void setup()
{
attachInterrupt(0, tick, CHANGE);
/*----Parameters
* 0 The interrupt number. Not the pin number. Use Google on the Arduino Interrupt reference to see which pin corresponds to which interrupt. 0 is pin2.
* tick Name of the function to run when the interrupt pin experience the third parameter. Must have no parameters. Must not return a value (must be declared as void)
* CHANGE
Tells to run the function (tick) when the value on the interrupt (0, or pin2) changes. That is, goes from LOW to HIGH, or HIGH to LOW.
*/----
}
That provides just the basic layout for what you could do.

Now, about those other timers in the 328. Those might be for PWM (Pulse-width modulation, if you're not familar with it. You might want to look it up if you're not, but don't get scared of it. analogWrite() makes PWM extremely easy).
If they are used for PWM only, then I don't think you would have access to them.

Though that gives me an idea. analogWrite() to an interrupt pin. Should oscillate fairly nice at 50% duty cycle! (gives equal time for HIGH and LOW output, or "true" and "false" for the CHANGE interrupt to happen). Of course though, I would not think it a great idea to hook a PWM pin directly to another Arduino pin...


As a little note, don't worry about using millis(). It will run for 49.71 days according to my calculations (assuming it returns an unsigned long int). This matches the Arduino reference, which states that it overflows after 50 days. Link here: http://arduino.cc/en/Reference/Millis

Might want to bookmark the Reference page if you haven't. It's nice to have around if you've forgotton some basic functions, or if you need parameters/functionality clarified. That would be at http://arduino.cc/en/Reference/HomePage

I hope this helps smiley keep in mind I'm not exactly an Arduino programmer though.



Just saw your new replies. Looks perfect on a quick look. I'll check back if I see anything worth noting... but otherwise it looks good to use! Nice find.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 18
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

After looking at it, it is basically the option 3 that I mentioned. So it will probably hog the system (I think? Can anybody confirm this?).
I don't necessarily love the implementation, but it works fine for your use I think. You should theoretically only have an error of +-10ms.

Lesson: Search libraries well, and in multiple ways before asking? But asking is still good and encourages learning!

Just make sure you have the source files, and you place...
Code:
#include <SimpleTimer.h>
...at the beginning of your code.

And make sure you rememer to put the code it gives you into SimpleTimer.h and SimpleTimer.cpp !

Logged

0
Offline Offline
Newbie
*
Karma: 1
Posts: 36
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

thanks for all the assistance smiley  i just got the simple timer code saved as a .h, .cpp and .pde to try out its example overnight while i also investigate the code you have supplied.

my issue w/ millis() is that the plan is to have the device on for a loooong time, long enough to exceed the size of the unsigned long data type - again, this is assuming, the programming is ok, so i need to really look over any code that i create or use to make sure i don't fill up a data type.  i also need to figure out what happens if a data type fills up - does the arduino lock up?

i think i need to make a post about uptime for an arduino..... smiley   smiley-sad-blue
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 18
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Was going to say... consider hardware limitations of running so long too!

Software:-------
About overflows. Imagine a Base-10 number (that, is, it has 10 unique symbols, starting from 0. So, 0 through 9, inclusive). That is our "normal" number system, known as decimal.
Let's call each single "place" a "bit". Assume I have a 2-"bit" number.
If I have 98, and add one, I get 99.
If 1 is added to 99, we get 100. Since this is only a 2-"bit" number, the leftmost symbol is effectively dropped.
This leaves 00, or simply 0.

Binary, or Base-2, (two unique symbols: 0 and 1) works similarily (unsigned values only). Once you reach the limit, then add one (as the internal counter would do), it would overflow and reset to 0. No errors happen just by an overflow, however, it can cause mathematical issues if you grabbed a value right before the overflow and compared it with the timer later. That is only one example of where an overflow can cause a problem.
Signed datatypes overflow in a slightly different way. Once they reach the maximum and one is added, they go down to their most negative value. For example, with a signed 8-bit integer, 127+1 would yield -128. (I have a hard time remembering if the odd number or the even one is the max... I might be wrong, but the idea is the same)

To deal with the overflow, you'll have to probably make something similar in functionality to SimpleTimer. I can help you with that if needed. Actually, I'll first check if SimpleTimer has accounted for overflow if I have time.

You may want to look into using the EEPROM for storage. It's on the reference page I linked to, I believe. This may help depending on your implementation (and serves as a more reliable source in the case that the SRAM messes up some data)

Hardware:-------
Do you have power back-ups? In case your power source fails (whether it be from an electrical provider or power supply), you'll want to have a back-up plan of some sort.
If it applies, consider: excess heat, ventilation, dust conditons, humidity, and fluctuations in these.
Logged

0
Offline Offline
Newbie
*
Karma: 1
Posts: 36
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

thanks for the info again.  exactly how you explained the overflow is exactly how the timer example code handled it - didn't stop just kept on counting but backwards.  it does go upto 9:06:07 then -9:-06:-08 and then -9:-06:07, etc.  for my uses i will not need any where near that time frame smiley.  i just need to set it up and get my code working correctly with it and it should perform its first execution that will run through the event 1x, then that should start the timer counter and i will have it execute 9 more times at a determined amount of time.

as far as hardware, everything you have brought up i have taken into account, and i appreciate the thoughts/suggestions.
Logged

Pages: [1]   Go Up
Jump to: