Path: Home =>
DCF77 alarm clock m16 => Software
AVR single chip controllers AT90S, ATtiny, ATmega and ATxmega
DCF77 alarm clock with LCD
The assembler software
The assembler software for the DCF77 alarm clock with LCD
The source code for the assembler is parted into the following
- The software structure
- The debug switches
- Adjusting software properties
- Time and date
- DCF77 synchronization
- Music playing
- dcf77_clock_m16_v5_en.asm: is the
main program. It inits the hardware and processes interrupts,
performs DCF77 signal processing, the clock, reacts on keys
and controls the AD conversion,
- lcd.inc: holds all routines for control
and operation of the LCD: initializing, positioning, output of
control commands and character writing, conversion and displaying
binaries in decimal and hex, generating special characters on the
- music_code.inc: contains all
routines for generating and encoding of music that is played on
wake-up, definition of music notes, encoding of notes, their
duration and of pauses, stored pieces of music, conversion of
stored music pieces to a series of tone frequencies and their
- debug_code_en.inc: all
routines, that are needed for processing and displaying debug
options, this code is assembled only if debug options are
enabled, for the final version all dbg switches have to be
set to zero.
As an assistance during setting up the hardware several debug
switches were built into the software that allow for testing
the hardware components of the device. Those options are
activated by setting those switches in the part "Debug
switches" of the software to one and re-assembling. Note
that some of the options start solely that specific debugging
program part and do not perform other debugging parts or
normal operations any more. As the debug output appears on the
same line of the LCD it makes no sense to set more than one
debug option to one.
The following switches are implemented and are listed in their
All debug switches have to be set to zero to achieve normal
operation conditions and re-assembled. The debug code is not
assembled in the final version.
- dbgLcd: This option switches the LED on, sets its backlight
to 50% and displays the opening message in lines 1 and 2,
while line 3 shows that debugging is active. Line 4 should
be empty. After having done this nothing else happens. As all
subsequent debug options are depending on the LCD to work
correct, dbgLcd will have to be set to zero to test other
- dbgAdc: This option switches the LCD and its backlight on,
measures the selected ADC channel (0, 1 or 2) and displays the
result in hex on line 4. No further actions are performed.
dgbAdc must be set to 0 to activate further debug options or
- dbgKey: This option switches the LCD and its backlight on
and displays the key pins PB0, PB1 and PB2 in binary format.
No other actions are performed. Set dgbKey to zero to select
other debug options or normal operation.
- dbgSpk: This option tests the attached speaker by issuing
a permanent tone on the speaker output pin. No further
actions are performed.
- DCF debug options: When those options are selected the
normal operation is performed, but no menus appear on line
- dbgDcfDur: displays the duration of incoming signals
on the DCF input pin displays those in Milliseconds in
decimal format in line 4. Active-High and Active-Low
signals are displayed separately. Ok and Error
signalization for the DCF signal in line 3 also works
correct (here: s1 for a too short signal).
- dbgDcfSig: displays errors in the received DCF signal
in text form on line 4 (the text displayed stems from
the table DcfReports: in the source code of the
main asm file). Short versions of the error messages
in line 3 works correct.
- dbgDcfBits: displays the number of received DCF bits
in hex and the last eight bits in binary form on line 4.
- dbgDcfRcvd: displays the received DCF information day,
month, year, hour and minute in hex format, including
those that were only received partially (undecoded parts
are displayed as 0xFF),
- dbgMusic: displays in line 4 the output progress of music
tones. In each second are displayed
all as 16 bit hex.
- 'a' and the address in SRAM, that is played next,
- 'c' and the CTC value of timer 1 in hex (that corresponds
to clock (3,276,800) / 2 / frequency of the tone - 1),
- 'd' and the counter value that determines the duration ofe
the played tone or pause (depending from the frequency),
- dbgPlayStat: displays on line 4 the current status of timer
TC1 in each second:
Additionally 'St' and the current stack pointer value in SPH:SPL
is displayed in hex format.
- the interrupt enable bit OCIE1A (i = off, I = on),
- the OC1A bits (T = Toggle, C = Clear),
The software for normal operation is controlled with with two
- LCD related properties, and
- other properties.
3.1 LCD properties
The LCD is connected to the ATmega16 as follows:
Version 5 of the software works with the LCD routines of
lcd.inc, which in detail is described here.
All properties that lcd.inc works with are defined in the
- The 8 bit data bus is connected to Port C. By default port
operation is unidirectional (the R/W control input of the LCD
is permanently connected with GND). The necessary wait cycles
are generated with time loops.
- The LCD input pin E (Enable) is on portpin PB3. Depending
from the controller clock frequency this is activated for one
microsecond (by default four nop cycles) and then deactivated
- The LCD input LCD-RS (Register Select) is on PB4. Its polarity
allows the selection of control (Low) or data (High) is written
to the LCD.
- The anode of the backlight LEDs of the LCD is connected to
the operating voltage, the cathode via a resistor of 220Ω
on the OC2 output pin of the controller. Timer 2 controls the
brightness via PWM mode.
of the source code.
; L C D C O N F I G U R A T I O N
The following properties are configured.
The controller's clock frequency is configurable with the
constant clock. By default the following clock rate
Possible and useful, and without any other changes in the
source code, xtals with 2.048 or 2.097152 or 2.4576 MHz
can be used and adapted with that constant.
.equ Clock = 3276800 ; X-tal clock
If an xtal with 4.194304 MHz shall be used the calculated
constant cSecDiv in the section "Fixed and derived
constants" has to be set to zero (which is 256), otherwise
an error message would occur.
Other xtals cannot be used without more complicated changes
to the source code (concerning mainly the TC0 operation and
the related interrupt service routine, while lcd.inc operates
correct with any possible frequency).
3.1.2 LCD size
The software only works correct if a 4-by-20 LCD is attached.
Adaption to any other size requires major changes in the
; LCD size:
.equ LcdLines = 4 ; Number of lines (1, 2, 4)
.equ LcdCols = 20 ; Number of characters per line (8..24)
3.1.3 LCD ports and portpins
The following constants concern the LCD ports for data and
control and the used portpins and are configured as the
Communication mode has been set as LcdWait = 1,
which inserts wait cycles following each control and data
write. If you prefer the busy option, tie the R/W pin of
the LCD to a Port B portpin (any pin used for ISP would
be ok), define the port and portpin constants and change
to LcdWait = 0 to configure R/W and busy operation
mode of the LCD.
3.1.4 Conversion options
The constant LcdDecimal has to be defined because
decimal conversion is used by several instances of the
software. As the light sensor's measurements are displayed
in hex, and in any case if you use debug options, the
constant LcdHex also has to be defined. The values
to which those two constants are set do not matter.
3.2 Other properties to be adjusted
Please find the other propertied that can be adjusted in
the main source code under the section
; C O N S T A N T S T O A D J U S T
3.2.1 DCF77 time constants
These constants, that start with cDcf and end with
Time, in the source code are set as follows:
The meanings of those constants are described in the section
DCF77 signal analysis. By changes to these
constants, differing properties of the DCF receiver can be
adjusted. Please note that the polarity of the DCF input pin
(Active-High or Active-Low) is of no importance, because the
signal analysis is insensitive for this and reacts correct
with both configurations.
; DCF signal durations
.equ cDcfIgnoreShortTime = 20 ; Ignore short pulses less than 20 ms
.equ cDcfMinTime = 50 ; Minimum signal duration time
.equ cDcfMaxZeroTime = 150 ; Maximum zero time
.equ cDcfMaxOneTime = 250 ; Maximum one time
.equ cDcfMinInactiveTime = 700 ; Minimum inactive time
.equ cDcfMaxInactiveTime = 1000 ; Maximum inactive time
.equ cDcfMin59Time = 1700 ; Minimum 59th second time
.equ cDcfMax59Time = 2000 ; Maximum 59th second time
.equ cDcfTimeOutTime = 2500 ; Time out
When changing to those constants are made make sure that no
overlapping can occur.
3.2.2 LCD backlight
The backlight of the LCD is controlled via the timer TC2. TC2
is operated with a prescaler of 64 as a PWM (fPWM =
3.276.800 / 64 / 256 = 200 Hz). Higher values in the
Compare port register increase the brightness of the backlight
The collector voltage of the photo transistor (or diode) with
a 100k resistor to plus is measured for its voltage each three
seconds (adjustable with cBackPeriodsTime). The AD converter
of channel ADC1 sums up 64 single values and inverts the MSB
of the sum (the higher the ambience brightness the smaller the
collector voltage). This value is multiplied with the term
(255 - Minimum brightness) and the minimum brightness is added
to the MSB of the result (minimum brightness adjustable with
the constant cBackMin) and the result is written to
the compare port register OC2 of TC2.
From this the brightness of the LED backlight is depending
from the ambient brightness like shown in the diagram.
configure the backlight renewal sequence timing and the minimum
of the backlight. Adjust the minimum so that the LCD can be read
in absolute darkness, if your LCD has different backlight current
properties. The cBackPeriodsTime is a matter of
taste and avoids flickering of the LCD.
; LCD backlight brightness, 80 to 200
.equ cBackPeriodsTime = 3000 ; ms for renewal of backlight setting
.equ cBackMin = 10 ; Minimum brightness of the backlight
3.2.3 S-Meter display
S-Meter display only makes sense if your DCF77 receiver provides
such a signal and if the signal strength voltage is attached to
the analog input pin ADC2. If not, the display shows S0.
The renewal property can be adjusted with the constant
If no signal is provided, set this constant to a very long time
(maximum around 24,000, depending from the clock frequency).
; DCF77 signal strength display update
.equ cSigStrTime = 2000 ; Update LCD every milliseconds
Which external voltage leads to which displayed S stage is
defined in the table SignalTable: in the source code.
The table is by default adjusted to the described DCF77
receiver with the TCA440. If your receiver provides different
voltages it can be useful to change to debug mode dbgAdc
with channel ADC2 to measure those voltages and to recalculate
the table values according to those readings. Note that the
last entry in the table is for a displayed value of S9+.
3.2.4 Debouncing of the keys
Debouncing of the keys is adjusted with the constant
A minimum of 20 ms and a maximum of 100 ms makes
; Key processing: delay on key cleared
.equ cKeyCntTime = 30 ; key must be inactive for 30 ms
3.2.5 Alarm repetitions
The number of alarm repetitions is a matter of taste and can
be adjusted with the constant
; Alarm repetitions
.equ cAlarmRepet = 3 ; Number of alarm repetions
3.2.6 Melody at restart
This property is only useful if you correct a currently
stored or if you write a new melody. The constant
allows you to select this so that you do not have to wait
randomly to check if your melody is correct.
; Default music play at startup
.equ cDefaultMelody = 8 ; Melody to be played at startup
A comprehensive general description of time and date in
AVRs with assembler is here.
The following is based on that more general description and
describes the implementation in the DCF77 alarm clock with
Timer TC0 generates the seconds clock signal:
Date and time are located in SRAM from address sDateTime:
on in binary format. The storage sequence follows the display
- The prescaler of 64 divides the controller clock to
yield a timer tick of 51.2 kHz.
- For 256 ticks 5 ms are required (200 Hz),
then a TC0 overflow interrupt occurs.
- Within the overflow interrupt service routine the
register rSecDiv is down-counted from 200 to zero.
If that reaches zero, the flag bSec in the flag
register rFlag is set, which outside of the service
routine increases time and date and triggers other
reactions as well.
The alarm time (hour, minute) is following in SRAM.
- Weekday: 0 (Monday) to 6 (Sunday)
- Day: 1 to 31
- Month: 1 to 12
- Year: 0 to 99
- Hours: 0 to 23
- Minutes: 0 to 59
- Seconds: 0 to 59
The routine IncSec: increases the time by one second
and, if necessary, increases minutes, hours, weekday, day,
month and year. This also works without the DCF77 signal
analysis, when the clock works as an unsynchronized
stand-alone device. Only those components of time and
date are renewed on the LCD that have changed within
the last second's increase.
If the manual input of date and time is activated (yellow
key), the output of date and time is suppressed. Other than
displayed, the increase of seconds (and synchronization
with DCF77) also works during manual input but just is not
displayed (to be able to skip input and to return back).
The second's increase is straight forward and as defined
in the more general description.
The implementation of the DCF77 signal analysis in this
alarm clock here is rather sophisticated, therefore it
is described in any detail in this chapter.
5.1 DCF77 signal input
Recognition of those signals is performed via the INT0
external interrupt. Both edges (Low==>High,
High==>Low) lead to an interrupt.
In the interrupt service routine for INT0
Further processing of those recognized DCF77 signals follows
outside the interrupt service routine and within the routine
- the current state of the counter
rDcfCntH:rDcfCntL is read, which is increased
by the timer TC0 each 5 ms,
- checks if the counter is smaller than defined in
the constant cDcfIgnoreShort, if that is the
case, the pulse is ignored and the time counter runs
- the count in the register pair rDcfH:rDcfL
- the flag bDcf in the flag register
rFlag is set, and
- the time counter rDcfCntH:rDcfCntL is cleared.
No matter which polarity the DCF77 signal from the
receiver has the signal durations are as follows:
According to the selected timing when increasing the
counter (5 ms) the 100 ms of a Zero are
associated with a count of 20, etc.etc.
- a Zero bit is 100 ms,
- a One bit is 200 ms,
- a missing second (minute signal) is between 1,800
and 1.900 ms long,
- the time between the end of a bit and the begin of
the next bit is between 800 (One bit) and 900 ms
(One bit) long.
Because the recognition of a Zero and One bit in the
receiver's RC needs a certain time, the above times have
to include a tolerance. This tolerance has been selected
in a wide range, e. g. a Zero bit can be between
50 and 149 ms long, the count can be between 10 and
29 to avoid signal errors.
5.2 DCF77 signal checks
From that the accepted signal durations and the errors
in the duration can be derived. Signals with blue are
correct and accepted, signals in red are errors.
5.3 DCF77 signal processing
That leads to the flow diagram of the DCF77 signal analysis.
N are the counter values (based on 5 ms).
Detected signal errors are assigned to error reporting
codes between s1 and s4, to be displayed in line 3 of
the LCD. If the DCF77 is inactive for longer than
2.5 s, the "S5 Signal missing" is
Correct signal durations for a Zero or One bit shift
a respective bit into the SRAM buffer sDcfBits:
(by shifting all 64 bits from left to right, with the
58th bit left adjusted in the highest byte).
The 59 collected bits per minute are analyzed when the
missing second pulse is recognized.
The analysis first checks if
In the second case the number of received bits is
displayed in line 3 of the LCD. In both cases further
analysis of the received bits is not continued.
- no signal errors (s1 to s5) occurred, and
- 59 bits have been received.
5.4 DCF77 information conversion
5.4.1 DCF77 minutes and hours
If the 59 signals are fine, the first bit of the minute
(DCF bit 1 = bit 5 in byte 0 of the SRAM buffer in
sDcfBits:) is checked: it has to be zero,
otherwise error "E0" is reported and further
analysis is skipped.
Then the four bits of minute ones are checked. Those
are located in the bits 2 to 5 at the SRAM address
sDcfBits+3. If those are larger than nine,
error "MO" is thrown and further execution
Then the minute tens (three bits) are isolated from
bit 6 and 7 of byte 3 and bit 0 in byte 4, by using
two LSL and ROL instructions, followed by
an ANDI 0x07. If the minute tens exceed five
error "MT" is reported and further execution
is skipped. If not, the tens are multiplied by ten and
added to the minute ones.
Then the parity of the minute bits (bits 2 to 7 in
byte 3 plus bits 0 and 1 in byte 4) is calculated by
counting the ones in those bits. If the sum is odd
(parity is not zero) the "PM" error is
reported and further analysis is stopped. If the sum
of ones is even, the received minutes are stored.
Similarly the hours are checked for
If none of these conditions are detected the hour
byte is stored and the date information is analyzed.
- the ones exceeding 9, and
- the tens exceeding 2, and
- the number of ones including the parity bit being
5.4.2 DCF77 date
The date informations are distributed over three bytes
in the DCF bits. Error checking is similar, as shown
here. The parity bit in that case covers all 23 bits
of the date information. The weekday is encoded as
1 for Monday to 7 for Sunday.
If all error checking is absolved and all information
is collected, the date and time is synchronized with
DCF77. The decoded date and time is copied to the buffer
DateTime: (if manual input is not active) and
"ok<" is displayed in line 3 of the LCD. The
seconds prescaler is set to 200 and the seconds are
cleared. The displayed date and time on the LCD is
The three keys are read within the interrupt service
routine of timer TC2 each 5 ms. If one of the
keys is pressed the flag bKey in the flag
register rFlag is set and the debouncing
register rKeyCnt is set to 30 ms (can
be adjusted with the constant cKeyCntTime).
Further key events are accepted if this register
is at zero.
If key input is deactivated and if alarm is off
(sKeyMode = 0) then pressing the
- red key activates the alarm function
(sKeyMode = 1),
- yellow key activates manual date and time
(sKeyMode = 2), and the
- white key activates adjusting the alarm time
(sKeyMode = 3).
If the alarm is on (displayed on line 2 of the LCD)
Those increases are set only temporarily, by
deactivating the alarm the original alarm time is
- red key deactivates the alarm,
- yellow key increases the alarm time by
5 minutes, and
- white key increases the alarm time by
In both manual adjustment modes (date/time, alarm)
the currently active input position blinks. Even
though only one character blinks the ones and tens
are adjusted in one step. In those modes the
Changes at the activated input position are made by
moving the potentiometer position left (decreasing
values) or right (increasing values).
- red key moves the input cursor left by one
location, if the input position is the most left
position (date/time: weekday, alarm time: alarm
hour) the input is skipped and the original value
- yellow key restores the original (previous)
value and moves one position to the right,
- white key moves the input position one right,
if the input position is the last one (date/time:
seconds, alarm time: minutes) the changed data
is copied to the respective SRAM buffer, if the
alarm time is finally adjusted the alarm is set
Tone generation works with the 16 bit timer TC1. The
prescaler is set to 1. The tone frequency is determined
with the compare port register A. If the TC1 count reaches
the compare value
If tone generation is activated the compare interrupt
service routine decreases a 16 bit counter rDurH:rDurL.
This counter counts the number of cycles and determines
the duration of the tone or pause. If the number of
cycles reaches zero, the next CTC value is read from
the SRAM buffer. If that value is 0xFFFF the speaker
output is cleared on compare match (COM1A1 to clear),
otherwise the output is set to toggle (COM1A1 to toggle).
The CTC value is then written to the compare A port
register. Following is the reading of the counter value
in rDurH:rDurL from SRAM. If this value is zero,
the melody ends and the timer TC1 interrupt is disabled.
- the timer restarts (CTC mode),
- either toggles the output pin OC1A (tone on) or
clears OC1A (tone off), and
- triggers the Compare-A-interrupt (if tone generation
If the alarm is active (sKeyMode = 1) each minute
change triggers comparison of the alarm time with the
current time. If equal, one of the stored melodies in the
flash memory is selected and converted to CTC and counter
values in the SRAM buffer (routine MusicConvert:).
The number of repetitions in sAlarmRepeat: is set
to the adjusted constant cAlarmRepeat:. In each
following minute the same melody is restarted (routine
MusicPlay:) until either the red key decativates
the alarm (sKeyMode = 0) or sAlarmRepeat
The melodies prior to their conversion are encoded in
flash memory tables as follows.
- Musical notes are defined with names starting with
'n' and assigning a tone (C, D, E, F, G, A and H) and
its octave (German notation: m, none, 1 to 7) with a
Additionally a note p is defined as a pause.
See the complete note definitions in the source code
include file under NotesNameTable:. Those
70 constants ease writing melody tables.
- nCm = 9 with 65.4 Hz,
- nc = 16 with 130.8 Hz,
- nc1 = 23 with 261.6 Hz,
- nc2 = 30 with 523.25 Hz,
- nc3 = 37 with 1,046.5 Hz,
- nc4 = 44 with 2,093 Hz,
- nc5 = 51 with 4,186 Hz,
- nc6 = 58 with 8,372 Hz, und
- nc7 = 65 with 16,744 Hz.,
- In the melody table each note and pause constant
has to be followed by a duration constant. The lower
nibble of the byte says how often the duration has
to be divided by two:
Note that high division rates with low tones
might not yield exact times due to rounding.
- no division, duration one second,
- divide by two, duration half second,
- divide by four, duration 0.25 seconds,
- divide by eight, duration 0.125 seconds,
- divide by sixteen, duration 0.0625 seconds.
The upper nibble determines how often to add the
divided cycle count. By that it is possible to
encode durations of 3/4 or 5/8.
The constants d1, d2, d4, d8 and d16 define
two-divided durations, d38 and d316 encode three
octa and three sixteenth durations.
- The melodies are encoded in the flash, the
table MelodyTab: points to the beginning
of those melodies (address multiplied by two).
- For each musical note the frequency is assigned
as a constant (see source code in the include file
- Each note frequency is converted to a table that
See this table in the source code under
NotesTimerTable:. With this table the melody
consisting of note constants can be converted to
CTC compare and duration words.
- a 16 bit CTC value, and
- a 16 bit counter value for the duration in
cycles per second.
©2018 by http://www.avr-asm-tutorial.net