Dick Cappels' project pages http://www.projects.cappels.org

return to HOME

Morse Code Alarm Clock Modification
(Almost) Trivial application of an AT90S2313 or ATtiny2313 in an alarm clock to change the alarm from "BEEP BEEP BEEP BEEP BEEP BEEP BEEP BEEP..." to "WAKE UP" in Morse code. This was designed in response to a request and is in daily use

Downloads (Updated 5 December, 2004)
AVR Studio Assembly Source: morclk041204A
AVR STudio Hex file: morclk041204A.hex


The speaker is mounted on the top edge and
the AA battery holder is glued to the back. Flat ribbon
cable is used for all the interconnections.

An inexpensive alarm clock was modified by installing a small circuit board inside the clock body and attaching some wires to the clock's circuit board. The second AA cell needed to bring the voltage up to 3 volts for the micro controller is mounted on the back. The high impedance speaker was temporarily mounted on the top as I pondered where the best permanent location would be, and like many decisions that are delayed with the aid of a temporary fix, its still waiting final disposition.


The adapter is a micro controller with a crystal clock, an input interface circuit,
and AC coupling for a speaker that is driven directly by the controller's output pins.
The 0.22 uf capacitors are ceramic monolithic

The micro controller sleeps most of the time, consuming mere micro amps until it receives an interrupt. and wakes up, then, using timing loops, it generates timing for "WAKE UP" in Morse code. Interrupts provide a 2 kHz square wave on pins 14 and 15 that are 180 degrees out of phase with one another (when one pin is high, the other pin is low), which means that the speaker sees a square wave that is nearly 6 volts peak-to-peak (or 3 volts RMS since it is a square wave). The 100 uf capacitor in series with the speaker keeps it from drawing any DC power. Once the "WAKE UP" message has been sent, the micro controller goes back to sleep.

The digital inputs are pulled high with the chips' weak internal pull-ups to minimize power dissipation. The speaker outputs are configured as outputs (I hope that is not a surprise).

The clock module runs from a single 1.5 volt AA cell. To raise the voltage to 2.7V or greater to run the AT90S2313, I added a second AA cell that only powers the AT90S2313.

The alarm signal is taken from one of the wires from the alarm clock module to the clock's speaker. When the signal swings to ground, the 2N4401 in the alarm module sinks enough current to pull the interrupt pin low.  The 39k resistor on the base of the 2N4401 sets the base current to (1.5V-0.7V)/39k = 20 micro amps. The weak pull-up on pin 6 supplies less than 85 micro amps when grounded, with 30 micro amps being typical, so the base drive is more than sufficient. Notice that this transistor's main function is to amplify the 1.5 V peak-to-peak signal from the alarm module to one that swings from ground to the micro controllers' positive power supply. The 0.22 uf capacitor cleans up the signal on the collector so that the collector goes low when the alarm signal comes in and stays low for about 2 milliseconds after the last beep.

A crystal oscillator was used because I have a whole lot of AT90S2313's and they don't have an internal oscillator. A better choice would be something like an ATtiny12 running with its internal oscillator. While on the subject of what could be better, the 100 uf capacitor can be eliminated provided that the firmware is modified to assure that pins 14 and 15, which drive the speaker, are in the same state (high, low,  as inputs) when the tone is not being sounded or that at least one of them is configured as an input when the tone is not being sounded.

A note about the speaker: I used a high impedance transducer that I picked up at a surplus store. I was told that it is piezoelectric and appears to be so  as it measures as greater than 20 Megohms on my ohmmeter. Be careful to use a piezoelectric transducer or other type of speaker with high enough impedance to feel comfortable that the current through it will not exceed 40 milliamps when driven by a 6 volt peak-to-peak signal. Anything measuring higher than 150 Ohms DC would fulfill this if it does not have a large shunt capacitance.


After power-on reset, the firmware does the usual housekeeping -setting the stack pointer, initializing the I/O ports, and setting up timer 1, which is used to produce the tone for the speaker when the code is sent, and then it goes to sleep and waits for an interrupt from the alarm clock.

rjmp start

The loop above, is where the CPU spends its "foreground time", the time when its not servicing interrupts. When an interrupt occurs, it wakes and services the interrupt then returns to the "rjmp start" instruction where it goes through the housekeeping routines again to make sure everything is set up properly before going back to sleep.

The interrupt service routine is below, but with some extra comments.
int0service:	;Alarm has gone off, so wake up
;The entire housekeeping routine is executed
;first to make sure everything is properly set up.
clr temp
out GIMSK,temp ;Interrupt are disabled.
out MCUCR,temp

clr flagreg ;Clear the firmware flag resister/

;TIMER 1 SETUP for proper tone pitch.
ldi temp,$09 ;Set timer 1 to reset 0000 after compare match. Prescaler = 1X.
out TCCR1B,temp
ldi temp,intcounthigh ;Set compare register to establish interrupt frequency.
out OCR1AH,temp
ldi temp,intcountlow
out OCR1AL,temp
ldi temp,$40 ;Enable interrupt on compare match.
out TIMSK,temp

sbi PORTB,0
cbi PORTB,1

sei ;Enable interrupts so that the tone can be output when code is

ldi temp,20 ;Set a variable for 10 words per minute code speed.
mov dotlength,temp
rcall TypeMessage ;Send "WAKE UP" message in Morse Code

rjmp start ;Go back to start (set up then sleep).
Notice that there is a lot of redundant initialization of registers and I/O ports. Its done when the processor first starts up, which is when the battery is installed, then it happens at the start of each interrupt when the alarm goes off, and then is done again at the end of each interrupt. This is for operational reliability. I have had controllers in the past that suffered reconfiguration their I/O ports without CPU intervention, when subject to high level, high frequency noise.  (I won't mention the name of the  manufacturer save Motorola from embarrassment). Reinitializing takes only a few additional microseconds, consumes negligible power, especially compared to that of driving the speaker for many seconds, and negligible code space since most of the flash memory in this chip is left unprogrammed. In return, I have a little piece of mind that if the $3 alarm clock sends its alarm signal on time, it will be heard and awaken the sleeper.

The section that sends the morse code is fairly primitive in operation, but relies on a neat trick to format the Morse code symbols in memory and much cleaner than the formatting methods I came up with myself. I found it on a web page by a fellow  named David Robinson, and he credits N1KDO in an article in the February 1997 issue of QST. In the format, each character is encoded in a single byte, with a 1 representing a dah and a 0 representing a dit. An additional 1 is written as a sort of a "stop" bit. The characters are shifted out until the register contains only obooooooo1, and at that point, the entire word has been shifted out. For example,  the letter A is encoded as "0b00000110"

Here is a view of the shift register as the code is shifted out:

"0b00000110"    Before anything is send
"0b00000011"   A dit is sent and the byte shifted right
"0b00000001"   A dah is sent and the byte shifted again. Since the register now contains "0b00000001", the operation is complete.

The hardest part of this was transcribing the Morse Code into binary and typing it in. I thank N1KDO for the technique and David Robinson for featuring it on his web page.

Using the method above, a routine accepts ASCII characters, looks up the format of the Morse Code character, then calls the dot routine, the dash routine, or exits, as the formatted Morse is shifted out.

The routine that sends the ASCII string to be sent out was taken directly from an Atmel application note, AVR108: Setup and use of the LPM Instructions. It can be found on Atlems's web site http:www.atmel.com. You migh save time navigating Atmel's website if you just  do a Google search on "DOC1233.PDF".

The routine is below:
TypeMessage:				;Type greeting
push ZL
push ZH
ldi ZH,high(2*Message) ;Load high part of byte address into ZH
ldi ZL,low(2*Message) ;Load low part of byte address into ZL
rcall sendromstring ;Send it
pop ZH
pop ZL

.db "WAKE UP "
.db $0A,$0D
.db $00,$00
The message can be changed by changing the text within the quotes. Additional lines maybe used to extend the string to the capacitor of the flash memory. Just remember to keep the ".db $00,$00" at the end so the TypeMessage routine knows when to stop.

The routine sendromstring: actually sends the character off to be changed to Morse code and beeped out. A space is interpreted as one interword period.


All of the components were mounted on a small
piece of pre punched circuit board and the electrical
connections were made with a piece of ribbon cable.

The components were wired point-to-point,  mostly by bending leads toward their intended connection points and soldering them. The components were placed so I could connect them with the minimum of fuss- which means as few insulated jumpers as possible.

Heat shrink tubing was used on the ribbon cable at stress points, like where it went through a hole in the alarm clock case, and at flex points, and great care was taken to keep flex stress off parts of the stranded wire that had solder wicked into them.


Contents ©2004 Richard Cappels All Rights Reserved. http://www.projects.cappels.org/

You can send mail to me at the address in the image below. Questions answered gladly.  If you modify this for another chip, let me know.

GIF of email address

 Liability Disclaimer and intellectual property notice
(Summary: No warranties, use these pages at your own risk. You may use the information provided here for personal and educational purposes but you may not republish or use this information for any commercial purpose without explicit permission.)
I neither express nor imply any warranty for the quality, fitness for any particular purpose or  user, or freedom from patents or other restrictions on the rights of use of any software, firmware, hardware, design, service,information, or advice provided, mentioned,or made reference to in these pages. By utilizing or relying on software, firmware, hardware, design, service,information, or advice provided, mentioned, or made reference to in these pages, the user takes responsibility to assume all risk and associated with said activity and hold Richard Cappels harmless in the event of any loss or expense associated with said activity. The contents of this web site, unless otherwise noted, is copyrighted by Richard Cappels. Use of information presented on this site for personal, nonprofit educational and noncommercial use is encouraged, but unless explicitly stated with respect to particular material, the material itself may not be republished or used directly for commercial purposes. For the purposes of this notice, copying binary data resulting from program files, including assembly source code and object (hex) files into semiconductor memories for personal, nonprofit educational or other noncommercial use is not considered republishing. Entities desiring to use any material published in this pages for commercial purposes should contact the respective copyright holder(s).