Seattle, WA
Offline
Newbie
Karma: 0
Posts: 45
|
 |
« on: December 19, 2012, 06:26:24 pm » |
Disclaimer: I'm pretty new to all this. Hi, I'd like to make a time of day based event, such on a certain hour (or several), something happens. Down the road maybe an RTC makes sense, but it would be cool to make one from scratch. Here's what I got so far (Thanks to guix to help me get started) unsigned long time_old; unsigned long time_new; int hours = 0;
void setup() { time_old = millis(); }
void loop() { time_new = millis(); if(time_new - time_old >= (60 * 60 * 1000UL )) { hours++; }
if(hours == 4) { //do something }
if(hours>= 24) { time_old = time_new; } } Will this work? Will this keep time at all accurately? Will it not if I use delay() in my "do something" section? Also, if I power cycle the Uno at noon, would it reset the clock?
|
|
|
|
|
Logged
|
|
|
|
|
California
Offline
Edison Member
Karma: 41
Posts: 1869
|
 |
« Reply #1 on: December 19, 2012, 06:29:48 pm » |
Will this work? Will this keep time at all accurately?/ Depends on how you define "accurately" Will it not if I use delay() in my "do something" section?
Not likely, but it depends on how you are using delay and how you are using the time.
|
|
|
|
|
Logged
|
|
|
|
|
Virginia, USA
Offline
Jr. Member
Karma: 0
Posts: 90
|
 |
« Reply #2 on: December 19, 2012, 06:34:55 pm » |
Here is a time library on the playground. I have not used this but it may be what you are looking for. http://playground.arduino.cc/Code/Time
|
|
|
|
|
Logged
|
|
|
|
|
Seattle, WA
Offline
Newbie
Karma: 0
Posts: 45
|
 |
« Reply #3 on: December 19, 2012, 06:36:01 pm » |
Hmm, a minute per day accurate maybe? So, I reduced the counter so I could debug... doesn't seem to work. I'd expect every 10 seconds for hours to increment, then print to serial, etc. every 10 seconds, but what happens is after 10 seconds, it prints 1 to 24 really fast, then nothing. Any ideas? Thanks unsigned long time_old; unsigned long time_new; int hours = 0;
void setup() { time_old = millis(); Serial.begin(9600); }
void loop() { time_new = millis(); if(time_new - time_old >= (10 * 1000UL )) //shortened for debug { hours++; Serial.println(hours); } if(hours == 4) { //do something } if(hours>= 24) { time_old = time_new; } } Edit: adding " hours = 0;" to the last IF makes the same thing repeat every 10 seconds, not 240 
|
|
|
|
|
Logged
|
|
|
|
|
Manchester (England England)
Offline
Brattain Member
Karma: 277
Posts: 25506
Solder is electric glue
|
 |
« Reply #4 on: December 19, 2012, 06:37:01 pm » |
Also, if I power cycle the Uno at noon, would it reset the clock Everything gets reset in a power cycle. If it is not exactly at noon then hours will not match real time.
|
|
|
|
|
Logged
|
|
|
|
|
Seattle, WA
Offline
Newbie
Karma: 0
Posts: 45
|
 |
« Reply #5 on: December 19, 2012, 06:41:54 pm » |
Ok, got it, needed to reset time_old each ~hour. if(time_new - time_old >= (1 * 1000UL )) //shortened for debug { hours++; time_old = time_new; //new line Serial.println(hours); }
|
|
|
|
|
Logged
|
|
|
|
|
0
Offline
Tesla Member
Karma: 71
Posts: 6624
Arduino rocks
|
 |
« Reply #6 on: December 19, 2012, 06:44:49 pm » |
Will this work? Will this keep time at all accurately? Will it not if I use delay() in my "do something" section?
With the standard Uno, no it won't be accurate enough for a clock, since the Uno uses a ceramic resonator rather than a quartz crystal as its time base. It is possible to resolder a quartz crystal and caps in place of the resonator, but it is a pretty fiddly job. The Duemilanova (previous standard version of Arduino) used a quartz crystal, but alas the Uno doesn't. Calling delay() has little effect on your code if the delays are short - the checks for the hour will be held up but the time accounting will still work.
|
|
|
|
|
Logged
|
|
|
|
|
Seattle, WA
Offline
Newbie
Karma: 0
Posts: 45
|
 |
« Reply #7 on: December 19, 2012, 06:49:59 pm » |
won't be accurate enough for a clock, since the Uno uses a ceramic resonator rather than a quartz crystal as its time base.... .....the checks for the hour will be held up but the time accounting will still work.
Cool, this will be enough to get me going and maybe later I can get a real RTC. Is there not a Arduino model currently being produced with a quartz? Thanks!
|
|
|
|
|
Logged
|
|
|
|
|
Offline
Edison Member
Karma: 114
Posts: 2205
|
 |
« Reply #8 on: December 19, 2012, 07:39:45 pm » |
Will this keep time at all accurately? It will drift, by the duration of the main loop. The best is through an interrupt. If you have to use millis(), this is what I would do: #define PR_1s 1000ul //duration of 1 second, in ms #define PR_1m (60 * PR_1s) //duration of 1 minute #define PR_1h (60 * PR_1m) //duration of 1 hour #define PR_ERROR 0 //error term
#define PR PR_1m //duration set to 1 minute
void loop(void) { static time = millis(); //reset current time if (millis() - time >= PR) {//desired time has elapsed time += PR + PR_ERROR; //update time, with error correction //do something } }
The code is self-contained and allows you to correct for timing errors. Its accuracy is only determined by the crystal.
|
|
|
|
|
Logged
|
|
|
|
|
Global Moderator
Boston area, metrowest
Offline
Brattain Member
Karma: 248
Posts: 16535
Available for Design & Build services
|
 |
« Reply #9 on: December 19, 2012, 07:47:40 pm » |
|
|
|
|
|
Logged
|
|
|
|
|
Offline
Edison Member
Karma: 114
Posts: 2205
|
 |
« Reply #10 on: December 19, 2012, 07:58:02 pm » |
I would change it slightly: #define PR_1s 1000ul //duration of 1 second, in ms #define PR_1m (60 * PR_1s) //duration of 1 minute #define PR_1h (60 * PR_1m) //duration of 1 hour #define PR_ERROR 0 //error term
#define PR PR_1m //duration set to 1 minute
unsigned char rtc_tick(void) { static unsigned long time = millis(); //reset current time if (millis() - time >= PR) {//desired time has elapsed time += PR + PR_ERROR; //update time, with error correction return 1; //return a tick } else return 0; } Whenever the duration defined by PR has passed, rtc_tick() returns 1, making time counting quite easy.
|
|
|
|
|
Logged
|
|
|
|
|
SE USA
Offline
Faraday Member
Karma: 33
Posts: 3623
@ssh0le
|
 |
« Reply #11 on: December 19, 2012, 08:04:28 pm » |
On the other hand, a DS1307 & crystal are pretty inexpensive
they are expensive in terms of memory, everyone uses the wire library to control the things, which directly states "I am going to eat your ram!" just to return a string you could write on a band-aid
|
|
|
|
|
Logged
|
http://arduino.cc/forum/index.php?action=unread;boards=2,3,4,5,67,6,7,8,9,10,11,66,12,13,15,14,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,86,87,89,1;ALL
|
|
|
|
Netherlands
Offline
Tesla Member
Karma: 90
Posts: 9401
In theory there is no difference between theory and practice, however in practice there are many...
|
 |
« Reply #12 on: December 20, 2012, 12:45:03 pm » |
@dhenry nice implementation !
minor point, I would use uint8_t instead of unsigned char as return type to indicate it is really an int. Or boolean true / false? ==> in short it depends.
|
|
|
|
|
Logged
|
|
|
|
|
Pittsburgh, PA, USA
Offline
Faraday Member
Karma: 31
Posts: 2931
I only know some basic electricity....
|
 |
« Reply #13 on: December 20, 2012, 01:38:36 pm » |
It's the other $40 I spend to justify shipping that gets me....
|
|
|
|
|
Logged
|
Examples can be found at Learning in the Main Site and at the Playground
|
|
|
|
|
|
|