Because of the widely publicized incident of the young Texan clock maker being arrested for bringing his creation to school, there has been a surge of interest in designing and making clocks. And that's awesome. Clocks are well known, and it's particularly easy to make them with microcontrollers (far easier than with discrete logic, but something can be said for the awesomeness of doing something the hard way). But clockmaking is deceptive. It's easy to make a clock that's functional, but if it's so inaccurate that you have to reset it frequently, then it's not very useful. And it turns out that achieving a useful level of accuracy is not trivial.
A clock fundamentally has two parts: a counter and an oscillator. The counter assumes that the oscillator operates accurately at a known frequency and displays the current cycle count, calibrated as a time. Some clocks use AC line frequency as their oscillator. Doing so outsources the problem, and is actually a good move (it should be mentioned that if you want to make a line-powered clock, you should buy yourself a UL approved low voltage AC transformer "wall wart" to do so. You shouldn't mess with AC line voltage directly, and for a clock there's certainly no need to do so), but more on that later.
There's very little to say about the counter portion of a clock. It's really all about the oscillator. Oscillators can be characterized by two factors - their accuracy and their stability. Put simply, accuracy is the difference between their actual frequency and their expected frequency and stability is the rate of change of accuracy over time.
There are lots of choices available for oscillators, but for amateur clockmakers, the only two worth seriously considering are AC line frequency or crystals.
Put simply, AC line frequency is very accurate, but highly unstable. You can count on a line frequency driven clock to be very accurate over a long term, but in the short term, there's no point in attempting to display seconds, because there can be multiple seconds of drift before it's corrected. But it is corrected eventually - the electric grids are typically disciplined so that in the course of a day the correct number of cycles take place.
If you want a battery powered clock, then you'll need to use a crystal. For the purpose of this discussion, crystals are quite stable, but their absolute accuracy is relatively poor. When I discovered this, it came as quite a shock. I thought that if I bought a crystal with a 10 ppm tolerance that that meant that I could count on the frequency being within 10 ppm. In fact, what that specification means is that if you buy a pile of that type of crystal, they will all be within 10 ppm of each other. And that's not the same thing at all.
A typical arrangement for a crystal clocked modern microcontroller is a crystal wired to two pins of the controller, with a loading cap on each lead to ground. The crystal will have a characteristic loading capacitance. The two capacitors, the PCB traces and the controller will all contribute capacitance. But what's the impact of that?
If you plot a crystal's frequency against the total loading capacitance, you get an inverse logarithm. That is, with no or low capacitance, the frequency will be too high. As you increase the loading capacitance, the frequency will drop precipitously at first, but then it will flatten out. Too much capacitance will eventually swamp the oscillator, but that happens much further on.
What the crystal manufacturers do is design and trim the crystals so that the desired frequency (within the tolerance, at least) is achieved with a particular capacitance value. And that value typically is far enough along the inverse log curve that it's somewhat flat, but not so far along that it can't still be pulled slower. The manufacturers choose this because they know that designers are going to want to engineer in the ability to fine tune the frequency, so there has to be room to pull the frequency lower, but at the same time, you want to reduce the sensitivity of the crystal by having the "sweet spot" be on a flatter portion of the curve.
So if you do the math correctly and pick the theoretically correct capacitor values - even if you take all of the parasitic capacitance into account - and then build your clock using a crystal with a 10 ppm tolerance, you still might find that it's 20 ppm slow. That's 12 seconds a week. The crappiest dime store digital watch can do far better than that. What happened? Well, if you were to build a dozen of them, what you'd find is that all of them would be within 10 ppm of each other, centered around some value. Given our single sample, we'd expect the center to be between 10 ppm and 30 ppm slow.
What happened is that the various component tolerances all contributed error. In the case of my crazy clock design, I tried crystals from three different manufacturers. With the same loading caps and same circuit, each wound up having a different batch center frequency with the three batches spread over a 20 ppm range! Altering the loading cap values gave even more points. I wound up going with a particular crystal and an loading cap value pairing that yielded a batch that averaged 5 ppm fast, ±10 ppm. That was the best I could do.
If you were building just one, then the best idea would be to substitute a variable capacitor for one of the loading caps. You could then trim the frequency manually. If you noticed the clock was running slow, you could just tweak it a little and it would come back into line. But if you're building a bunch of clocks, that's impractical. Much better would be to add the ability to "trim" the oscillator in software. That's what I did for the crazy clock.
It's not that hard to do. Out of every million oscillator cycles you need to either add or subtract "n" of them to effect an "n ppm" trimming. Or if you look at it another way, if you take one million and divide it by "n," then you need to add or remove a single cycle after counting that many.
The crazy clock works by arranging for one of the controller's timers to generate 10 Hz interrupts. It does this by performing a fractional division system. The software trimming simply counts how many cycles have been counted and increments or decrements the current cycle's count for one interrupt whenever the trimming counter overflows. What that allows me to do is write into EEPROM a trimming value. At startup, the math is done once and the trimming counter initialized appropriately.
That's as much as you need to do to just make a clock. Going further you can delve much more deeply into crystal stability factors, which will lead you to temperature stability, aging, and lots more.