How to make an Arduino clock - without using external oscillators or clock chips:

(more of my projects on our research website - click the arduino logo top of home page)

You will need:

An Arduino board (just about any flavor will work fine) and software
1 Jumper Wire

(Wiring Example Updated Below...)

I'm an Electrical Engineer of 20+ years and just discovered the Arduino platform a few months ago.  Needless to say I fell in love with it and am now hooked on projects.  For Christmas this year, I wanted to make some very heart-felt, one-of-a-kind gifts for my parents.  For my Mother, it was definately a 'one-of' clock design.  I was not concerned with keeping up with daylight savings time or leap years - simply accurately keep the day of week and time.  

How to generate the clock pulses in a unique but accurate manner though?  Sure I could use a fancy embedded clock IC or the common 32,768 crystal oscillator, but I wanted something different than the rest.  I started using a 555 timer to output a steady 100Hz square wave.  This worked pretty well but I was losing about 1 second per hour.  No problem - I just wrote an algorithm to correct the missing second in software.  I was happy.  Then I discovered that although the Arduino's internal timer was not totally reliable for time keeping, the analog PWM outputs did have a very steady square wave of 490Hz.  The duty cycle is determined by the value written to the analog pin.  (i.e. - 0 is zero volts, 127 is a 50% duty cycle, 255 is a logic high/5V).

I decided to try the PWM analog output wired directly to the interrupt pin  2 and it worked great!  Plus, it kept up perfectly with my computer's real time clock to the second without need for software compensation.  I've been running it for days now and it continues to perform just as I had hoped....all with one wire and some code.

The finished gift will have Eagle CAD custom PCB's for the power supply and logic, housed in a plexiglass enclosure.  The entire theme is ice blue LED lighting to simulate an analog clock.  While the enclosure has a white on blue LCD displaying the day, time, and room temperature, a serial cable connects from the project box to the actual clock.  Using a 12 bit decade counter, a servo, and lots of blue LED's I am lighting the appropriate hour segments on a custom-designed analog clock face printed on plexiglass.  The servo is mounted in the center of the clock face and has an armature attached with an LED mounted to light up the minutes behind the glass.  (each minute the servo turns 6 degrees, lighting up the appropriate minute).  I hope to have it finished soon and will make a video of the final product....I hope she loves it !!

Simple Arduino wiring diagram and demo code to make your own clock using this method.  Also a link to Circuit Lab demonstrating how to use the 555 timer @ 100Hz method if you so choose.

Code and links below...

555 Timer Oscillator Circuit (if you wish to try this method)

Clock Demo Code:

/*  Simple internal clock demo: by Joseph Unik aka Relic1974
    Uses analog PWM output of 490Hz with a 50% duty cycle to
    keep very accurate time ;).  Connect an LED to pin 13 to
    watch seconds blink.  Connect a jumper from Analog pin 0
    to Digital Pin 2 (interrupt 0). Minutes output to serial
    monitor.  http://www.planetxresearch.com 'Arduino' logo
    for more projects and tricks...
    (Feel free to use this code to expand into a fully-functional
    clock or other project under Creative Commons ;)

int clockInt = 0;            // digital pin 2 is now interrupt 0
int masterClock = 0;         // counts rising edge clock signals
int seconds = 0;             // variable
int minutes = 0;             // variable
int ledPin = 13;

void setup()
  attachInterrupt(clockInt, clockCounter, RISING);
      //  clockInt is our interrupt, clockCounter function is called when
      //  invoked on a RISING clock edge
  pinMode(ledPin, OUTPUT);
  analogWrite(0, 127);   // this starts our PWM 'clock' with a 50% duty cycle

void clockCounter()      // called by interrupt
  masterClock ++;        // with each clock rise add 1 to masterclock count
  if(masterClock == 489) // 490Hz reached     
    seconds ++;          // after one 490Hz cycle add 1 second ;)
    masterClock = 0;     // Reset after 1 second is reached
    tone(13, 100, 500);  // using tone to pulse LED without delay call ;)

void loop()
  if(seconds == 60)      // NOW GETTING IN TO REAL TIME KEEPING
    minutes ++;          // increment minutes by 1
    seconds = 0;         // reset the seconds variable
    Serial.print("Minutes = ");

Demo of my project in the works here


I tried to use this clock with a project I'm working on. The only differance I really noticed was that I'm running an UNO and that I'm running at 9600 baud. I'm very new at this so I may have done something else wrong that I don't even realize but anyway the end result is that my clock gains about 17 seconds every hour. Any suggestions? I'm working on getting my code transfered to this PC so I can post it but in the mean time was wondering if my baud rate would have any effect.
OK, some differences were found that I forgot to mention (my fault) between different arduino boards. &nbsp;I have only tried this with success with the mega2560 and the ATMega328-based Nano v3.0.&nbsp;<br> <br> On the mega2560, which is the board that I developed my uber clock upon, a few of the first analog pins DO have PWM output ability. &nbsp;For that board, my interrupt routine was counting only the RISING clock signals @ 490hz. &nbsp;When I ported the code to the nano, I realized that it did not have the same PWM on analog 0 as the mega did. &nbsp;So I kept the same interrupt pin (D2, int 0) and moved the masterClock pulses to D3 on the nano.&nbsp;<br> <br> Then another issue appeared. &nbsp;When counting RISING clock edges @ 490hz on the nano, my clock was almost double speed! &nbsp; So I changed the interrupt to look for CHANGE in clock signal instead of RISING and changed the frequency (number of clock CHANGES) to 979, or 0 thru 979 which = 980. &nbsp;I had to change the frequency not because the PWM signal was 980hz on the nano, but because I was now counting any CHANGE in PWM signal. &nbsp;So either a low to high OR &nbsp;a high to low clock edge would invoke the interrupt. &nbsp;WHY this worked I still am puzzled about.&nbsp;<br> <br> Your serial port baud rate should not affect the clock at all btw.<br> <br> Here's some example code (just the basics) of what I did differently when using the nano. &nbsp; The same might apply to your UNO board.<br> <br> In setup try this instead:<br> <br> attachInterrupt(0, clockCounter, CHANGE); &nbsp; // Still using interrupt 0 pin D2<br> analogReference(DEFAULT);<br> <br> analogWrite(3, 127);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // PWM clock heartbeat !!! &nbsp;(or any other PWM pin)<br> <br> <br> Then try this instead for your interrupt / masterClock function:<br> <br> void clockCounter()&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // called by interrupt<br> {<br> &nbsp; masterClock ++;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // with each clock rise add 1 to masterclock count<br> &nbsp; if(masterClock &gt;= 979)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br> &nbsp; {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br> &nbsp;&nbsp;&nbsp; seconds ++;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // also add one second<br> &nbsp;&nbsp;&nbsp; masterClock = 0;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Reset after 1 second is reached<br> &nbsp;&nbsp;&nbsp; ledpinstate = !ledpinstate;<br> &nbsp; }<br> &nbsp;<br> &nbsp; digitalWrite(ledPin, ledpinstate);<br> <br> }<br> <br> <br> This got the nano keeping EXACT time with my PC's real time clock, which is very hard to believe, but I have the results to prove it !&nbsp;<br> <br> Here is another thing to try IF you have an oscilloscope (don't have mine yet). &nbsp;Perfrom the same analogWrite(pin, 127) on any PWM pin and note the frequency. &nbsp;It SHOULD be 490hz on all boards but I could be wrong. &nbsp;So, say the UNO's PWM freq is a bit different ... then you would need to adjust your clock pulse counts to match.<br> <br> I hope this helps, and feel free to contact again if more assistance is needed. &nbsp;I also have many other projects, from beginner to advanced, on my website at this URL -&nbsp;http://www.planetxresearch.org/#!__arduino<br> <br> I'll be adding a guide in the next day or two on getting results with the infamouse JY-MCU cheap bluetooth breakout board. &nbsp;I finally have code for the radio that is reliable, allows for board programming with AT commands, and also provides 2-way communication.<br> <br>
<p>Your PWM is powered from the exact same clock that drives your timers, since the PWM signals are generated by the timers. Using the timers you will achieve the exact same accuracy as using the PWM - just without the need of an external wire...</p><p>This fact might be hidden behind the shell of the Arduino programming environment, but it becomes clear if you look into the details on how PWM works on an ATmega microcontroller...</p>
<p>People, really. There is no need for this method. Just use the timer interrupt. It is exactly the same, if not better. *Facepalm*</p>
<p>Ahan ahan just use the internal interrupt based on a timer to accomplish the same, and I am not an electrical engineer but mechanical... This intractable should be deleted.</p>
<p>I don't really see the point of this. The PWM is directly divided out of the main system clock. You can just program the interrupt registers to do the exact same thing without having to touch hardware.</p>
you can use the millis() function instead and obtain similar results... <br>here's the code- <br> <br> <br> <br>unsigned long lastTick=0; <br>unsigned int sec=1; <br>unsigned int minute=0; <br>unsigned int hour=0; <br> <br>void setup() <br>{ <br> Serial.begin(9600); <br>} <br> <br>void loop() <br>{ <br> <br> <br>if (millis() - lastTick &gt;= 1000) { <br> <br> <br>Serial.print(hour,DEC); <br>Serial.print(&quot; : &quot;); <br>Serial.print(minute,DEC); <br>Serial.print(&quot; : &quot;); <br>Serial.print(sec,DEC); <br>Serial.println(); <br> <br>sec++; <br>if (sec==60) <br>{minute++; <br>sec=0; <br>} <br>if(minute==60) <br>{ hour++; <br>minute=0; <br>} <br>lastTick = millis(); <br>} <br> <br>} <br>
<p>Does this code cater for Rollover? otherwise you can have glitches every 50days, when Millis - resets? Thats the great trick with using this PWM...</p>
<p>I discovered that my Arduino nano is actually producing 490.03Hz. So that means that every 2592 seconds, I need to skip 1 second to keep the clock accurate. Still, not bad at all for not using an RTC.</p>
<p>Very interesting idea! I have a question though... Based on the Atmel documentation, it looks like the PWM timers are 'divided down' from the main CPU clock speed. (e.g., &quot;The clock source for the [PWM] timer is prepared &ndash; the PLL [timer hardware] is started <em>and locked to the system clock</em>&quot;, <a href="http://www.atmel.com/Images/doc2542.pdf" rel="nofollow">http://www.atmel.com/Images/doc2542.pdf </a> ) </p><p>This means that if the main CPU clock drifts (which as sadly we all know it does), then the exact timing of the PWM timers will drift proportionately. This would explain why some people are seeing different exact speeds of their PWM output: it's no more frequency-controlled than the main CPU speed, and people are having to make small adjustments and compensations for their particular device and environment. </p><p>So basically my question is this: do you have a link for any documentation showing where the timebase of the ATmega PWM timers comes from, whether divided from CPU clock or otherwise? Thanks! I'm very interested in how we can improve the stability and accuracy of Arduino clocks, and this is a clever idea to pursue!</p>
<p>hello </p><p>i just tried your method but im not sure it works </p><p>mi timmer was very fast or very slow , i do not know why </p><p>any suggestion ?</p>
<p>Don't you lose time as soon as you power it off?</p>
I'm also a 20+yr Electrical &amp; Embedded Software Engineer who loves Arduino, and I'm working on using one for a simple project at work. I needed a reasonably accurate periodic interrupt timer, so I did something similar to what you did, but instead of using PWM output command (which only works on certain pins and at a fixed rate), I used the tone() command on Digital pin 4 and wired it to Digital pin 3.<br> <br> I use attachInterrupt() for interrupt#1 (on pin#3). The tone() command can be of whatever frequency that I need - there's no need to be locked into the 490Hz interrupts. Note that the tone() command has a lower limit of about 31 Hz on my board&nbsp; from what I've read. I've been using a tone() of 8000Hz successfully on an Arduino Uno board. I don't know what the upper limit is, but it will depend on how much code is in the interrupt service routine and the crystal.
Brian, has the tone command been keeping time properly for you since your post?
I may be a little late to the party, but my curiosity was stroked by the mechanical side of your project. I am very intreged by your armature with the LED. Could you explain how you went about that? Also I thought servos were not accurate enough for something like a clock. I mean accuracy as far as being off a fraction of a degree after so many movements. Seems like you would have to have some method of checking it's position to ensure accuracy?
The servo I used only turns 180 degrees. The servo's 'data' line does communicate back to the arduino to report it's position in degrees. One minute on the clock equated to 6 degrees on the servo. The armature attached to the servo has 2 LED's, one at each end. This allow me to use the servo as a 360 degree minute hand on the clock.<br><br>When the armature reaches 31 minues past the hour, it returns to it's zero degree start position and the other LED lights up. This allows the servo to again go through it's 0 - 180 degree cycle and thus the 'illusion' that the minute hand is now moving from 31 minutes to the top of the hour. Then the whole process repeats again.<br><br>For this project the servo position was amazingly accurate enough. If I had required smaller increments in movement, like 1 - 3 degrees then it would not have worked out so great. But the 6 degrees of movement every minute was accurate enough to land the LED on the correct minute marker on the face of the clock.<br><br>So to sum it up, as long as you have the armature well calibrated/adjusted when assembling it, the movement should remain accurate due to the servo's communication with the arduino. The finished clock is still keeping accurate time without the need for adjustments after over 6 months of continuous operation.<br><br>Good luck with your project !
That's awesome. I admire your out-of-the-box thinking. I wasn't aware that servos had an output to relate their position. Could the same be accomplished with a stepper motor? Seems like that would be the way to go due to the full rotational ability of a stepper. Stepper would be more quite as well right? Ah, but maybe the probl there would be finding a stepper that rotates in 6 degree intervals, if such even exists? And I guess getting power to the LED, with it being able to keep rotating and not reset, would be an issue as well. Sorry just thinking out loud. Thanks for the quick reply. I am really looking forward to your thought on all this.
LoL, I was going to suggest using a stepper motor for very precise movement. To use one, I would think that some experimentation would be required to determine how many steps 6 degrees of rotation would be. You could write a simple test sketch and manually pusle the stepper motor until it reached 6 degrees from starting point. Use an int variable to track it's number of steps, as the stepper will NOT communicate it's position back to the arduino like a servo would.<br><br>As far as powering the led, with only 180 degrees of movement powering the led wasn't too hard to do. I used a thin strip of vero proto board and those high quality dupont colored cables, along with some very carefull wire routing. For 360 degrees of movement, I would attempt trying a similar setup. However instead of allowing the stepper to continue in a clockwise motion infinately, I would use the variable that is tracking the number of steps/pulses to 'rewind' the stepper (H bridge could reverse the polarity) and return it to it's starting position that way. otherwise your LED wires will just end up twisting round and about.<br><br>Any other advice, just let me know. I'm always happy to assist with out of the box thinking!
I hope you really are happy to assist with advice. I have another project that I am absolutely stumped on. If you could email me I'd like to have a little back and forth brainstorming with you. My email is holychachi@gmail.com <br><br>Thanks<br>Charlie
BTW - a stepper motor from an old floppy drive or CDROM would work perfectly, and they are very small. Test sketches are included in the arduiono IDE and the low power requirement may mean that very little external hardware would be needed, aside from some isolation diodes for back EMF. The digital pins can provide about 40 ma each to the stepper coils, should be enough for a tiny stepper. or use general-use NPN transistors on each stepper coil.
I'm probably doing something wrong but the program is not working here. <br> <br>I placed a jumper wire betweed digital pin 2 and analog pin 0 and copied your code. I expected the LED from pin 13 to blink/pulse but nothing happens at all. <br> <br>I'm trying to make an accurate clock and I'm checking all possibilities to make the clock run at 1ms exactly but the code i'm running now loses about 1 second every 10 minutes. <br> <br>This is the code i'm currently using (but wanting to change it to your code): <br> <br>void initTimer() { <br> TCCR0A = (1 &lt;&lt; WGM01); <br> TCCR0B = ((1 &lt;&lt; CS01) | (1 &lt;&lt; CS00)); <br> OCR0A = 249; <br> TIMSK0 = (1 &lt;&lt; OCIE0A); <br>} <br> <br>ISR(TIMER0_COMPA_vect) { <br> milis++; <br> <br> if(milis &gt;= 1000) <br> { <br> seconds++; <br> milis = 0; <br> <br> if(seconds &gt;= 10) <br> { <br> tensecs++; <br> secs = ; <br> <br> if(tensecs &gt;= 6) <br> { <br> mins++; <br> tensecs = 0; <br> <br> if(mins &gt;= 10) <br> { <br> tenmins++ <br> mins = 0; <br> <br> if(tenmins &gt;= 6) <br> { <br> hours++ <br> tenmins = 0; <br> <br> if(tenhours == 2 &amp;&amp; hours &gt;= 4) <br> { <br> tenhours =0; <br> hours = 0; <br> } <br> <br> if(tenhours == 1 || tenhours == 0 &amp;&amp; hours &gt;= 10) <br> { <br> tenhours++; <br> hours = 0; <br> } <br> } <br> } <br> } <br> } <br> } <br>} <br> <br>This code works, but loses secons too quickly. Any ideas why your code doesn't work on my board? I have an Arduino Mega 2560 R3.
nice project. I'm glad it works for you. couldn't you free up 2 pins though (not use any pins) by just using timer interrupts?
Thanks for the reply, and yes it can be done that way, or also using the millis() function. However there are drawbacks to both of these methods that are not issues using the accurate and predictable PWM frequency.<br><br>I've read on many forums that the timers can be delayed by processes in the background. Even if it is only milliseconds, over time it adds up. Using the millis() creates issues using some functions such as delay(). Using the PWM freq with a 50 percent duty cycle avoids these issues. The clock I made is still ticking away and keeping near perfect time. At least, I does not need to be adjusted every few days or even weeks !. With the results that I have had, I do not mind giving up 2 arduino pins ;)
have u give me full code of clock in serial..???i cant understand it how to do it..?? <br>Thanks in advance
The code above works on a Mega2560, because the mega has PWM ability on a few of the analog pins. Other arduino boards do not have PWM on the analog pins and are INPUT ONLY. Try using the 490 hz PWM signal on a free digital pin instead, using the same interrupt 0 pin. <br> <br>Just a thought, but it came to my attention that the tone command could also be used to produce a 'clock pulse', but I'm not sure how accurate it would be. I'd have to test it and check the signal on a scope. I suppose you could produce a 10 or 100 hz tone/square wave and count the pulses in the same fashion. But I think other processes might interfere with the accuracy of the frequency.
This is a great idea, I'm gonna have to try it on my next clock.
I'm always asking my mother &quot;Is the clock still keeping good time?&quot; She says it doesn't lose time at all and no adjustments needed. A small battery backup circuit keeps the MCU running during short power outages or brownouts (AA x 4).
Hey- Thanks for this instructable. I'm currently building a Toddler sleep training clock and I hope this will be a good basis for it. I've gotten the code to run on an UNO, I added code to format for hours output the time in HH:MM:SS format. I still need to implement the 12/24 hour rollover. here is my code so far:<br> <br> /*&nbsp; Simple internal clock demo: by Joseph Unik aka Relic1974<br> &nbsp;&nbsp;&nbsp; Uses analog PWM output of 490Hz with a 50% duty cycle to<br> &nbsp;&nbsp;&nbsp; keep very accurate time ;).&nbsp; Connect an LED to pin 13 to<br> &nbsp;&nbsp;&nbsp; watch seconds blink.&nbsp; Connect a jumper from D3<br> &nbsp;&nbsp;&nbsp; to Digital Pin 2 (interrupt 0). Minutes output to serial<br> &nbsp;&nbsp;&nbsp; monitor.&nbsp; http://www.planetxresearch.com 'Arduino' logo<br> &nbsp;&nbsp;&nbsp; for more projects and tricks...<br> &nbsp;&nbsp;<br> &nbsp;&nbsp;<br> &nbsp;&nbsp;&nbsp; (Feel free to use this code to expand into a fully-functional<br> &nbsp;&nbsp;&nbsp; clock or other project under Creative Commons ;)<br> */<br> <br> int clockInt = 0;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // digital pin 2 is now interrupt 0<br> int masterClock = 0;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // counts rising edge clock signals<br> int seconds = 0;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // variable<br> int minutes = 0;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // variable<br> int hours = 0;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // variable<br> <br> int ledPin = 13;<br> int state = LOW;<br> int oldstate = HIGH;<br> <br> void setup()<br> {<br> &nbsp; attachInterrupt(clockInt, clockCounter, CHANGE);<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //&nbsp; clockInt is our interrupt, clockCounter function is called when<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //&nbsp; invoked on a RISING clock edge<br> &nbsp; analogReference(DEFAULT);<br> &nbsp; pinMode(ledPin, OUTPUT);<br> &nbsp; Serial.begin(9600);<br> &nbsp; analogWrite(3, 127);&nbsp;&nbsp; // this starts our PWM 'clock' with a 50% duty cycle<br> }<br> <br> void clockCounter()&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // called by interrupt<br> {<br> &nbsp; masterClock ++;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // with each clock rise add 1 to masterclock count<br> &nbsp; if(masterClock &gt;= 979) // 490Hz reached&nbsp;&nbsp;&nbsp;&nbsp;<br> //&nbsp; if(masterClock &gt;= 130) // 490Hz reached&nbsp;&nbsp;&nbsp;&nbsp;<br> &nbsp; {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br> &nbsp;&nbsp;&nbsp; seconds ++;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // after one 490Hz cycle add 1 second ;)<br> &nbsp;&nbsp;&nbsp; masterClock = 0;&nbsp;&nbsp;&nbsp;&nbsp; // Reset after 1 second is reached<br> &nbsp; state = !state;<br> <br> //&nbsp;&nbsp;&nbsp; tone(13, 100, 100);&nbsp; // using tone to pulse LED without delay call ;)<br> &nbsp;&nbsp; }<br> &nbsp; return;<br> }<br> void printtime()<br> {<br> &nbsp;&nbsp;&nbsp; Serial.print(&quot;&nbsp; Time = &quot;);<br> &nbsp;&nbsp;&nbsp; zeroit(hours);<br> &nbsp;&nbsp;&nbsp; Serial.print(hours);<br> &nbsp;&nbsp;&nbsp; Serial.print(&quot;:&quot;);<br> &nbsp;&nbsp;&nbsp; zeroit(minutes);<br> &nbsp;&nbsp;&nbsp; Serial.print(minutes);<br> &nbsp;&nbsp;&nbsp; Serial.print(&quot;:&quot;);<br> &nbsp;&nbsp;&nbsp; zeroit(seconds);<br> &nbsp;&nbsp;&nbsp; Serial.println(seconds);<br> &nbsp;&nbsp;&nbsp; return;<br> }<br> <br> void zeroit(int value)<br> {<br> &nbsp; if (value &lt; 10)<br> &nbsp; Serial.print(&quot;0&quot;);<br> &nbsp; return;<br> }<br> void loop()<br> {<br> &nbsp; if(seconds == 60)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // NOW GETTING IN TO REAL TIME KEEPING<br> &nbsp; {<br> &nbsp;&nbsp;&nbsp; if (minutes == 60)// set to 60<br> &nbsp;&nbsp;&nbsp; {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; hours++;<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; minutes = 0;<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; seconds = 0;<br> &nbsp;&nbsp;&nbsp; }<br> &nbsp;&nbsp;&nbsp; else<br> &nbsp;&nbsp;&nbsp; {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; minutes ++;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // increment minutes by 1<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; seconds = 0;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // reset the seconds variable<br> &nbsp;&nbsp;&nbsp; }<br> &nbsp; }<br> <br> &nbsp; if (state != oldstate)<br> &nbsp; {<br> &nbsp;&nbsp;&nbsp; digitalWrite(13, state);<br> &nbsp;&nbsp;&nbsp; oldstate = state;<br> &nbsp;&nbsp;&nbsp; printtime();<br> &nbsp; }<br> <br> }<br> [/code]
I'd love to know how it works. Feel free to msg me if you run into any problems. Glad it helped someone.
I had a few minutes to play with a frequency counter at work, so I put the pwm signal on it. To the best I can remember, ~489.85 hz but it kept increasing in the tens of millihertz range. Next chance I get, I'll do it again and make sure to warm up the freq counter properly this time. I intend on writing an instructable on my clock, If I do, I'll post a link here.
Well, I just put on O-scope on this UNO and the PWM signal looks like it's running at 490.2Hz.
Try using the 'CHANGE' parameter in your interrupt and try counting to 980 , same 50% duty cycle. This will count 0-979 so if clock &gt;= 979 then reset. This is what I did to get it to work on the Nano 3.0
Relic, I didn't want to leave you hanging. I tried everything I could think of over the past couple weeks until my employeer &quot;strongly suggested&quot; that I go with an RTC and get some forward progress made on this project. Thanks for all the help though. I learned a lot. Thanks again.
understandable. may I ask though what your final results were with the modifications that i suggested. I'd like to investigate for future reference.
The last thing I tried was using the 'CHANGE' parameter in your interrupt and try counting to 980. This seemed to help in that it reduced my 14 seconds per hour to around 7 seconds per hour. I tried adjusting the count and the duty cycle, but no matter what minor adjustments I tried to make I just couldn't get any better than 7 seconds fast. My assumption was that the .2Hz was throwing me off but now that I look back (in my mind because I didn't save my code after modifying it) I may have had something going on in the wrong part of the loop causing delays. I would think that that would have slowed it down not speeded it up though. I have however used your code in another little project for our church youth group. :-) Again, I can't thank you enough for every thing I learned over the past couple weeks.
also, are you implementing bluetooth in your project? I know that most developers are having nightmares with the generic 'linvor' bluetooth modules, but they DO work very well when programmed correctly. I'm even now getting GREAT results with Processing &gt; Bluetooth &gt; Arduino and back. Just takes the right driver, bluetooth stack, and, the right library, and the correct code ;)<br><br>I may do a tutorial soon once I get it nailed down.
Yes, everything seems to be working fine and I'm really happy with how it fits perfectly into my project, it's just a little fast. Someone else said something about the frequency which makes the most sense to me, I just don't know what to change it to or how to change it.
First, I just now noticed an error in my diagram above. Note that only PWM enabled pins will work as a clock signal. The mega2560 is (as far as I know) the only version that has PWM ability on some of the analog pins...else use a digital PWM output. You cannot change the PWM frequency only the duty cycle. The code writes 127 to the PWM pin so the duty cycle is 50% or 500ms LOW and 500ms HIGH. So all you need to know is if the UNO's PWM frequency is a bit different from other arduino boards. You need to probe that PWM pin with either a frequency counter or an oscilloscope to reveal it's actual frequency. My guess is that the freq is a bit higher on the UNO. (10ms perhaps???) In the meantime, try adding 20 to your pulse counts in the clockCounter function. I'm posting an updated diagram also...
Forgot the updated diagram ...
Relic1974, thanks so much for your help and thanks for the detailed info, I'm sure that this should help. Affraid I won't have time to dig into it 'till next week but when I find out something I will gladly repost my findings. Before next week though, I just wanted to say thanks. :-)
// This is my code and btw it gains about 14 seconds not 17. :-) <br>//Any help to figure this out would be great. Thanks in advance. <br> <br> <br>const int buttonPin = 3; // the pin that the button is attached to <br>const int ledPin = 8; // to light an LED during development <br>int buttonState = 0; // current state of the button <br>int lastButtonState = 0; // previous state of the button <br>int incomingByte; // to read input into <br>int TM[3]={0,0,0}; <br>String readString; <br>int clockInt = 0; // digital pin 2 is now interrupt 0 <br>int masterClock = 0; // counts rising edge clock signals <br>int seconds = 0; // variable <br>int minutes = 0; // variable <br>int hours = 0; // variable <br> <br>void setup() <br>{ <br> pinMode(ledPin, OUTPUT); <br> pinMode(buttonPin, INPUT); <br> Serial.begin(9600); <br> attachInterrupt(clockInt, clockCounter, RISING); <br> // clockInt is our interrupt, clockCounter function is called <br> // when invoked on a rising clock edge <br> analogReference(DEFAULT); <br> analogWrite(10, 127); // this starts our PWM clock with a 50% duty cycle <br> <br>} <br> <br>void loop() <br>{ <br> if (Serial.available() &gt; 0) { //if any key is pressed <br> int incomingByte = Serial.read(); //read input into incomingByte <br> <br> switch(incomingByte){ //depending on the value of incomingByte... <br> <br> case 'z': <br> // z is just here so I can check the time without having to set it <br> Serial.print (&quot;P Station time is &quot;); <br> <br> Serial.print(hours); <br> Serial.print(&quot;:&quot;); <br> Serial.print(minutes); <br> Serial.print(&quot;:&quot;); <br> Serial.println(seconds); <br> Serial.println (&quot;&quot;); <br> break; <br> <br> case 'J': <br> <br> Serial.print (&quot;Set Station time &quot;); <br> if (hours &lt; 10){ <br> Serial.print(&quot;0&quot;); <br> } <br> Serial.print(hours); <br> Serial.print(&quot;:&quot;); <br> if (minutes &lt; 10){ <br> Serial.print(&quot;0&quot;); <br> } <br> Serial.print(minutes); <br> Serial.print(&quot;:&quot;); <br> if (seconds &lt; 10){ <br> Serial.print(&quot;0&quot;); <br> } <br> Serial.print(seconds); <br> Serial.print (&quot; &quot;); <br> <br> hours = TimeProcess(); //hours, minutes, and seconds are populated <br> Serial.print(&quot;:&quot;); //colons pops up between each set of 2 numbers <br> minutes = TimeProcess(); <br> Serial.print(&quot;:&quot;); <br> seconds = TimeProcess(); <br> <br> Serial.println (&quot;&quot;); // cariage return <br> Serial.print (&quot; Station time &quot;); <br> if (hours &lt; 10){ //puts a &quot;0&quot; in the first digit location if needed <br> Serial.print(&quot;0&quot;); <br> } <br> Serial.print(hours); <br> Serial.print(&quot;:&quot;); <br> if (minutes &lt; 10){ //same as was done for hours <br> Serial.print(&quot;0&quot;); <br> } <br> Serial.print(minutes); <br> Serial.print(&quot;:&quot;); <br> if (seconds &lt; 10){ //same as was done for hours <br> Serial.print(&quot;0&quot;); <br> } <br> Serial.print(seconds); <br> Serial.println (&quot; &quot;); <br> break; <br> <br> default: <br> Serial.println (&quot;Invalid entry. Enter J to set the Time.&quot;); <br> } <br> } <br>} <br> <br> <br> <br>void clockCounter() // called by interrupt <br>{ <br> masterClock ++; //with each clock rise add 1 to masterclock count <br> if(masterClock == 489) // 490hz reached <br> { <br> seconds ++; //after one 490Hz cycle add 1 second <br> masterClock = 0; //Reset after 1 second is reached <br> //tone(13, 100, 500); //using tone to pulse LED without delay call <br> if (seconds == 60) // Now getting into real time keeping <br> { <br> minutes ++; //increments minutes by 1 <br> seconds = 0; //reset the seconds variable <br> if (minutes == 30 || seconds == 30) //at each half hour and 30 seconds do this <br> { //I could have put this anywhere within the hour. I just choose 30 min 30 sec <br> seconds = (seconds - 14); //corrects the clock <br> } <br> if (minutes == 60)//when minutes reach 60 <br> { <br> hours ++;//incriments hours by 1 <br> minutes = 0;//resets the minutes variable <br> if (hours == 24)//when hours reach 24 <br> { <br> //days ++; <br> hours = 0;//rest the minutes variable <br> } <br> } <br> } <br> } <br> return; <br>} <br> <br>long TimeProcess() //populates int hours, minutes, or seconds for easy printing <br>{ <br> long var; <br> int cnt = 0; <br> for (int complete = 0; complete != 1;)//&quot;complete&quot; is initialized at 0 then the condition of the <br> // for loop is that &quot;complete&quot; is not 1 <br> { //loop will continue until &quot;complete&quot; becomes 1 <br> while (Serial.available() &gt; 0 ) <br> { //Serial.available recognizes digits pending in serial buffer <br> char c = Serial.read(); //reads data in serial buffer one byte at a time. <br> TM[cnt] = int(c - 48); //contents of c are copied to array TM <br> cnt++; //cnt is incrimented with each entery into the array <br> readString += c; //contents of char c are placed in readString <br> Serial.print (c); //prints each charicter as it's typed <br> delay(2); <br> if (cnt == 2) // when 2 digits are entered do this <br> { <br> Serial.print (&quot;&quot;); <br> complete = 1; //make &quot;complete&quot; 1 which satisfies the for loop <br> } <br> } <br> } <br> if (readString.length()&gt;0) //when readString gets content, do something <br> { <br> char carray[readString.length() + 1]; //creates an array of readString content <br> readString.toCharArray(carray, sizeof(carray)); // transfers readString into char array named carray. <br> long f = atol(carray); //creates long variable &quot;f&quot; equal to &quot;array to long&quot; conversion of data in carray. <br> var = f; //var is equal to &quot;f&quot; which we just converted to a number from array of chars. <br> readString=&quot;&quot;; // make readString empty for next time around <br> readString[2]; //allocate 8 bytes of memory for readString <br> } <br> return var; <br>} <br>
BTW I am assuming that my method for clock pulses is working on the UNO , but just a fast clock correct ?
Hi rustynkc. I'm looking over your code now and will get back to you asap. I had a simlilar problem now that I think about it when porting from the mega2560 to the Nano v 3.0. There were some differences in the PWM frequency and I remember having to change the masterClock count rate and the type of PWM change to trigger it on. <br> <br>Will get back soon!
Clever and simple, I'll definitely be using this. Thanks a lot!
Very excited about this approach; Been waiting to get fairly accurate timing without external hardware. I tried your code, it compiled, and uploaded, but no output. I've tried using another analog pin, but same results. I'm doing this on a breadboard with a 328P, and other sketches load fine (blink, fade, etc). It seems like it's not generating the interrupt?
Here's a few things to try and consider. First of all, you can test the analog pin's output with a multimeter or an oscilloscope. Either should show a 5V PWM signal @ 490Hz. Also keep in mind that different Arduino boards assign interrupt 0 on different pins. In most cases this is digital pin 2 but it may be different on other boards. Also make sure you are compiling with the correct board model selected. I have made this mistake when working with both the mega2560 and nano boards. If you forget to change the board model in the compiler you will get funky results!. Last of all, make sure you have a jumper wire between the analog pin and interrupt 0. Another nice feature about using this method versus accessing the timers directly is that the millis and delay functions are still operational. Whereas if you access the internal timers directly those functions become unusable. Let me know what you discover, and I'd like to know what arduino board you are working with. If you continue to have problems I'll help you dive deeper into the problem. I don't think I made a mistake in the code, as I'm using the same basic code on my clock project and it continues to rival stand-alone RTC chips. BTW the 100Hz 555 timer circuit also works well, and also uses the same basic coding.
On the Uno you have to change the pin from this info on the docs here: <br>PWM: 3, 5, 6, 9, 10, and 11. <br> <br>so I changed this: <br>analogWrite(10, 127); // digital pin 10 as a PWM, instead of your 0 <br> <br>And wired a jumper from digital pin 2 (interrupt 0 on the UNO) to digital pin 10 (PWM, output) on the Arduino Uno board. Here you can see the docs for the Uno talking about the pins: <br>http://arduino.cc/en/Main/arduinoBoardUno <br> <br>Excellent post btw. I was a little stumped at first but the salaee logic proved me right, when I got the pulses working it fell into place. So far seems to be accurate Ill post more info after a few days of playing around with it. <br>
How is it possible that you use a analog INPUT as output. Behind the A0 pin there is a ADC that converts a incoming analog signal to a digital signal for your microprocessor. This can only work one way.
The Sainsmart Mega2560 has PWM access on A0 thru A7

About This Instructable


70 favorites


More by relic1974: Arduino-controlled UV LED PCB Exposure Box Success Using the JY-MCU (linvor) Bluetooth Module Make an accurate Arduino clock using only one wire - NO external hardware needed!
Add instructable to: