Clock Works¶
Author: | Erich Wälde |
---|---|
Contact: | amforth-devel@lists.sourceforge.net |
Date: | 2018-12-15 |
License: | CC BY-NC-SA |
Intro¶
This is the top page of a project, which deals with clocks. However, this project did happily explode into a large collection of fun projects, too many to do them all. Instead of giving up, I decided to do a series of documentation units, starting with the bare minimum and adding optional units to cover other things.
If you speak or read German: a lot of this material has been covered in the journal “Vierte Dimension” of “Forth Gesellschaft e.V.” available at https://www.forth-ev.de and https://wiki.forth-ev.de/doku.php/vd-archiv starting 2016-04 and references therein. There is a corresponding page for some source code and pointers in the wiki as well, see https://wiki.forth-ev.de/doku.php/projects:clockworks:clockworks
Warning¶
Let’s be very clear about this: Noone needs yet another clock! — there are way too many of them already dictating our course during the day. But if you decide to ignore this warning and try to make your own nonetheless, you will enter a whole new world of little wonders, fantastic sights, and incredible creativity. Welcome to the world of AmForth on atmega microcontrollers, time, and clocks. Have the appropriate amount of fun!
License¶
AmForth is licensed under GPLv3 (since version 5.6), and GPLv2 before.
This documentation is licensed under CC-BY-NC-SA (Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License). This documentation is not part of AmForth, allthough it is kindly hosted here.
The example code (even when included in the documentation) is placed under the CC0 (Creative Commons Zero License, 1.0 unported). This should be equivalent to placing the example code directly in the public domain, worldwide!
What can you do with the example code?
You can take the example code, verbatim or modified, and run it on a device of your choice.
You can use the example code to create your own project.
You can give the example code verbatim or modified to your neighbour, or better still, point your neighbour to this project.
However, when you give the example code to anyone else in compiled form (think programmed controller using AmForth), then the distribution obligations of the license for AmForth come in: be sure to provide the code of the AmForth system, the used example code, your modifications — all in source form (the preferred representation for modification, gpl v3 section 1). If you cannot do this for whatever reason, AmForth is not a possible choice for your project.
Explanation: compiling Forth code extends the Forth system in use. In compiled form, neither can the newly compiled functions (aka words) be used as an independant entity, nor are new words distinguishable from the words of the original Forth system in any way. Thus compiled Forth code always creates a derived works of the underlying Forth system, including its license. There are no exceptions.
When you reuse the example code for some other Forth/language, then the license of the example code would have to be respected. Thus I would like to place the example code voluntarily in the public domain. Apparently I cannot legally do so in my jurisdiction, so I have to resort to CC0 (Creative Commons Zero License, 1.0 unported).
If you find a bug in the example code, or if you think the documentation should be enhanced or corrected, I’m happy to receive a report.
If you find this documentation useful, or if you use the example code for your project, I would be very interested to hear about it. If you use AmForth, please consider contributing a link for the Commented Projects Section.
Setup of Hardware¶
The code presented here was developed and tested on an atmega-644p
controller. The AmForth system (version 6.5 at the time of writing)
has been derived from the files in appl/template/
. The only
changes in template.asm
were the frequency of the main crystal
(.equ F_CPU = 11059200
), the baud rate (.set BAUD=115200
), and
as a matter of personal preference .set WANT_IGNORECASE = 0
. The
first two you typically have to adjust for your project anyway. The
example code should work without the third change, however, I did not
test this.
Allthough care has been taken and allthough the shown schematics work for the author himself, the author does not garantee the shown schematics to work under any conditions. You have to verify that things work for you. Do not burn your house!
Ingredients and Clocks¶
A microcontroller driven clock needs some means to produce a periodic event, e.g. a timer overflow interrupt at some known frequency. This represents the smallest meaningful unit of time on this system, let’s call this a tick. These ticks are counted to measure a second, which in turn are counted to measure a minute and so forth. Add some means to display the values of said counters and we do have a minimal clock.
While this clock is definitely rather lacking in several respects, we already run into a lengthy list of options regarding its implementation. We have to make choices before the first line of code is written.
- Generating Ticks from the main crystal — this option is readily available without any additional hardware.
- OR Generating Ticks from an additional clock crystal — this option needs an extra crystal and possibly tiny load capacitors. However, it enables the possibility to make the controller go to sleep between ticks.
- OR Generating Ticks from an external clock source — using an external clock source might provide greater long term accuracy, e.g. by using a TCXO (temperature compensated crystal oscillator) or a pps pin of a GPS unit.
- Keeping Track of Time using common counters (sec, min, hour, …) — while these counters are very common, they are not strictly neccessary. There could be other means to extract the common time format from some counter (seconds of the day, e.g.).
- Periodic Jobs — I have implemented various parts of the clock using jobs (simple functions, really) which are called periodically. While this is kind of an obvious solution, it is not strictly neccessary.
- Multitasking — execute
run-loop
in the background. Not strictly neccessary.- Display — to see the whole thing work
Model 1: The Fairly Minimal Clock¶
Model 1 needs one version of clock ticks, keeping track of time, the periodic jobs plus some means to display its counters representing the time, in other words: a main program to make the whole magic work.
- Adding a RTC (battery backed) — if we want to keep time over a power outage, we better have one of these!
- Accessing Shift Registers — accessing LEDs and 7-segment digits without the flicker
- Abakus display — even more geek than binary?
Model 2: The Abakus Clock¶
Model 2 features a unique display and also a battery backed real time clock to keep correct time across power outage.
- 7-Segment LED Digits — a display with four digits. Could be expanded!
- Unix Epoch Seconds — in order to implement time zones I decided to use epoch seconds. They implement another software clock.
- Time Zones — want to display local time rather than UTC? This is the way to go.
Model 3: The UTC Wall-Clock¶
Model 3 features four 7-segment digits as a display, however, they are large (70mm high) to make them readable across the room. The concept of time zones has been added, so daylight savings time is only flipping a switch away.
- Small improvements for readable code — there are a lot of functions available to write your code more concise.
- Changing the prompt / StationID — we add a station ID to the code running on every board and display its value in the prompt. Because we can!
- Managing several sets of clock counters — using
structures
will ease book keeping. Along the way we add labels for time zones. And we can run several such clocks in parallel, if needed.- Calculating the length of a month in the Gregorian Calendar might be useful in its own right, so factored it.
- Keeping Track of Time revisited — cleaning up the remaining code while using clocks.
- Creating a persisten jump table — this is a technique I have used in other places. The content of the jump table is calculated at compile time (in RAM) and then preserved in flash memory.
- Reading a dcf77 receiver — this turns out to be quite complex and requires a lengthy chunk of code.
Model 4: The DCF77 controlled UTC Wall-Clock¶
Model 4 is Model 3 but with a large software addition: the time is read from a DCF77 receiver and periodically synchronised to the microcontrollers counters, and optionally to the attached RTC.
Another warning: DCF77 is a central-european facility. There are alternatives elswehere on the planet, consult wikipedia Radio Clock for a list.
More Stuff to come¶
phase accumulator to compensate a frequency offset in ticks
Multitasker and simultaneous access on serial interface
Conversion to Unix Epoch Seconds Date/Time to unix time and back
Long term accuracy
Displays, also fancy ones
This represents the visible part of the clock. Given diverse preferences amongst people, this is the most creative area of clock projects. I urge you to spend an afternoon looking at all the fancy clock designs, that can be found on the world wide web! This list cannot be complete ever, not even in categories:
- serial interface
- some LCDisplay — this is a common choice
- LEDs of 7Segment-Digits, multiplexed in some way.
- Did I mention that I hate multiplexed displays? It hurts my eyes, so please use shift-registers and do away with multiplex blinking!
- analog type displays
- audio display for the vision impaired, or just because we can
Time Zones, Daylight Savings Time
Other Time Scales
- Epoch seconds
- siderial time
- swatch beats
Alarm Clock
The Things Side¶
While dealing with such a project, once in a while a number of things must be relearned the hard way. Afterwards they are obvious, however, while in the (code–)jungle they are not funny at all. On the other hand, what would the world be if noone had to tell stupid stories …
- Cables — There exists a subtle variation of “is the cable connected?”: Never underestimate the possibility to have more than one broken cable at the same time.
Included Docs¶
- Generating Ticks from the main crystal
- Generating Ticks from an additional clock crystal
- Generating Ticks from an external clock source
- Keeping Track of Time
- Periodic Jobs
- Multitasking
- Unix Epoch Seconds, revisited
- Adding a RTC (battery backed)
- Adding a RTC: PCF8583
- Adding a RTC: DS3231
- Accessing Shift Registers
- Timezones
- Small increments for better code
- Changing the prompt / StationID
- Persistent Jump Table
- Software Clock Counters
- lastday_of_month
- Keeping Track of Time, revisited
- Reading the DCF77 Signal
- Display
- Abakus Display
- 7-Segment Digits
- Model 1: The Fairly Minimal Clock
- Model 2: The Abakus Clock
- Model 3: The UTC Wall Clock
- Model 4: The Radio Controlled UTC Clock
- Date/Time to unix time and back