Talking Clock

The talking clock can tell the current time aloud in English. Time announcement is triggered by pressing a button on a remote controller. When I awake at night I cannot recognize digits on any wall clock because I don’t have my dioptric glasses on. But I can easily find remote controller and press the trigger button just by touch, and thus learn that I don’t have to get up just yet (ideally).

Besides speaking, the clock has also some other notable features. Foremost, the display is realized using six nixie tubes, which give a nice orange friendly glow. Secondly, the time is continuously kept up-to-date by receiving the German public time signal DCF77 transmitted from Frankfurt at the frequency 77.5kHz and 50kW power. The transmission covers most of the Europe up to approximately 1500km from Frankfurt. Similar transmitters exist in the UK (MSF, 60kHz/50kW in Teddington, Middlesex), and in the USA (VWWB, 60kHz/70kW in Fort Collins).



  • Display: Six cold cathode neon readout (nixie) tubes Z573M, (or ‘digitrons’, as we call them here)

  • Time: Radio DCF77 module receives precise German time, backed up by a 32.768kHz watch crystal.

  • Remote control: infra-red (IR) sensor, software decoder for Sony remote controller I’ve got

  • Processor: AVR ATmega32 (8-bit, 32kB FLASH, 2kB RAM)

  • Storage of voice samples on SD card (e.g. 1GB) with FAT16/32 filesystem

  • Sound converter: 12-bit DAC with SPI interface (using MCP4921)

  • Amplifier: 1.5W (using TDA7233)

  • Debug: UART/RS232, AVR ISP interface

All the resources–software source code, schematic, and PCB layouts–are on github:




Related blog posts:

 Block Scheme

Figure below shows the functional block scheme of the Talking Clock. Software components are depicted by yellow boxes and hardware parts by green boxes. The software runs on ATMEGA32 controller CPU. The IR remote controller is coloured red, because it is not a part of the design: an off-the-shelf product is used.


The lower part of the scheme shows blocks dedicated to time keeping functions. There are two independent sources of the time information: a DCF radio receiver, providing a precise German date and time signal, and a local “watch” crystal oscillator. The DCF radio signal is a serial stream of bits. The bit-stream is decoded in software; more information about the decoding process is given below. The current time is updated according to the local crystal oscillator, and continuously corrected by DCF information as it is decoded. The current time expressed in hours, minutes and seconds is displayed on six nixie tubes (digitrons). Each nixie tube is capable of showing digits 0-9 and a dot.

The upper part of the functional block scheme above shows blocks that realize time announcements using voice. An announcement is triggered at any time by pressing a dedicated button on an infra-red (IR) remote controller. An IR signal is received by the IR sensor and output as a serial stream of bits to the CPU. If the correct button has been pressed the IR decoder triggers voice announcement. Voice messages are created by sequencing independent voice samples corresponding to individual words together. For instance, suppose the current time is 11:37. The speech sequencer first plays a voice sample that says ‘it is’. Then it plays samples that say ‘eleven’, ‘hours’, ‘thirty-seven’, and ‘minutes’. Voice samples are stored in files on SD-card (using the FAT16/32 filesystem). Analogue voice signal is synthesized using 12-bit digital-to-analogue converter (DAC), amplified, and made audible by a loudspeaker.

Nixie Display

Visual display of the clock is realized by six nixie tubes. Each Z573M tube can display digits 0-9 and a dot. Nixies produce light the same way as neon bulbs. There is a single anode at the front of the tube, made from a grid of thin wires so that you can see through it. Behind the anode there are 10 cathodes physically made of thin wires and shaped as letters ‘0’ to ‘9’, stacked one over another. The tube lights up when a high DC voltage (around 200V) is applied between anode and one of the ten cathodes (the dot is the eleventh cathode). A nice and friendly nuclear-age orange glow will appear around the cathode that is grounded, thus illuminating a digit.

The figure below shows the block scheme of display driver circuit. Nixies are driven in a multiplex. Cathodes of identical digits of all six nixies are connected together. Each cathode set can be switched to ground by an NPN transistor. Anodes are switched by PNP transistors. The transistors are driven from a serial shift register buffer implemented by three 74HC595’s. The CPU sends a 24-bit serial stream which is shifted in the register.


Nixies require high voltage around 200V DC to light up. This power is produced in a voltage quadrupler from 36V AC.

Nixieboard: high-voltage power source schematic
Nixieboard: nixies connected in multiplex, schematic
Nixieboard: shift register, driver transistors. Schematic.

Radio Receiver

DCF77 is a German long-wave time signal and a standard-frequency radio station located in Mainflingen near Frankfurt. The transmitter frequency is 77.5kHz, the power is 50kW.

DCF77 uses amplitude shift keying to transmit digitally coded time information. The carrier signal is 77500Hz. At the beginning of each second the amplitude of the carrier is reduced to 15% of the normal for 100ms or 200ms. A 100ms reduction denotes a binary 0; a 200ms reduction is binary 1. As a special case, the last second of every minute is marked with no carrier power reduction.

dcf77-time_frameThe time interval for the transfer of one bit of information is 1 second, the whole frame that encodes the current date and time takes exactly 1 minute. The figure below shows mapping of the 59-bits of a one-minute frame (the 60th second is a marker that is not modulated) to minutes, hours, and date. Numbers are encoded using BCD.

The talking clock uses a kit module from Flajzar that requires just power (5V), and has a single digital output corresponding to a demodulated AM signal. The module is internally realized by a ferrite antenna and U4221B integrated circuit. The output of the kit module is connected to INT1 pin at the CPU in the clock and triggers an interrupt whenever it changes level (edge detection). The interrupt routine in the CPU measures the duration of the logic levels: the duration 100ms means bit-0, and 200ms is bit-1 in the DCF bitstream. Once the whole 1-minute frame is received, it is checked for parity errors and if correct, the current time is updated to the received information.

IR Control

The clock can be controlled using an IR remote controller. The receiver module in TO92 package is mounted on the display board and connected using three wires (power and signal) the CPU board. The signal is connected to INT0 input on the CPU. Any edge triggers an interrupt.


IR data is encoded by pulse width. The Sony remote that I use has three symbols that it sends: a start-bit, a zero-bit, and a one-bit. By experiment I determined that the start bit has pulse width 2.1ms to 2.75ms, one-bit is between 0.92ms and 2.1ms, zero-bit are pulses less than 0.92ms.

Each symbol (start, zero, one) is sent as a burst of on-off light pulses at the frequency roughly 38kHz. The IR module drives its output high when it detects light pulses.



Speech synthesis is realized by playing out digital samples of individual words from SD card to DAC (digital-audio converter), and through an analogue amplifier to a loudspeaker.

Voice samples are stored in files on SD card. The SD card is formatted using standard FAT16 or FAT32 filesystem, hence the files can be normally written on any PC. The SD card hardware is connected to the ATMEGA32 CPU via SPI interface (MOSI, MISO, SCK). One minor issue is that the SD card operates on 3.3V while the rest of the design is 5V. Thankfully, all that is needed are a couple of resistors on links from CPU to the card.

The firmware has two layers of software to operate the SD-Card: SPI block-driver layer, and FAT filesystem layer. I used “Tiny FAT filesystem module” by ChaN. The SPI driver communicates with card. The card is organized into 512B-sectors. The block-layer driver can read any sector from the card and place it into internal RAM of the CPU. The FAT filesystem driver understands the FAT16/32 filesystems. It reads FAT allocation tables and directory structures. To an application it presents a simple API that allows to open a directory, list files, open a file by name, and read sequentially or randomly from the file.

Suppose the current time is 11:37. The speech sequencer first plays a voice sample that says ‘it is’. Then it plays samples that say ‘eleven’, ‘hours’, ‘thirty-seven’, and ‘minutes’. These samples are stored in files it-is.raw, n11.raw, hours.raw, n37.raw, and minutes.raw.

Sampling rate of the sound is 8kHz. Each sample is stored as 16-bit unsigned number. Samples are read from file into a working buffer (256B) and then played out at the fixed rate 8kHz through a digital-to-analog converter (DAC). The bit rate is 128kbit/s, or 16kB/s.

The DAC is connected using a separate SPI interface, which is emulated by software because ATMEGA32 has only one hardware SPI (it is used for SD-Card). The DAC is only 12-bit, hence 4 sample bits are lost. The analogue output of the DAC is filtered by a low-pass RC filter, and amplified by a single-chip 1-watt amplifier. The amplifier is powered from 12V supply.

CPU board: sound synthesis with DAC, schematic.
CPU board: SD-Card connection, schematic.
CPU board: ATMEGA32, schematic.
CPU board: power source, schematic.


Firmware is stored in internal flash memory in the CPU. As the software must cater for several asynchronous functions concurrently, it is split in independent tasks that cooperate through shared-time multiplexing and communicate by sending messages.

Interrupt routines run in background. There are four interrupt sources: 1) precise watch-clock oscillator 32768Hz that generates periodic interrupts 128-times per second; 2) 8kHz periodic interrupt generated by CPU timer to recreate the audio sample rate; 3) burst detector in the infra-red receiver; and 4) demodulated DCF77 signal.

Low-frequency 128Hz periodic interrupt (1) is driven by external 32768Hz clock oscillator. The interrupt routine increments the current time by 1/128s.

High-frequency 8kHz periodic interrupt (2) is driven by an internal timer and the clock is derived from a CPU crystal oscillator, which is typically rather imprecise. It is used to drive the Nixie tube display multiplex (at roughly 1kHz frequency) and to output audio samples to DAC if sound is playing.

The IR burst detector (3) and DCF77 demodulator (4) each drive a separate interrupt pin at the CPU. Interrupts are generated at both the rising and falling edges of signals. The interrupt routines measure time intervals between edges, and decode signals accordingly.

Interrupt routines run in background. In foreground there are 7 `processes’ which are executed in a loop. Technically, the system implements shared-time multiprocessing with message passing. Each `process’ is a function with a single argument `const message_t *msg’ – a pointer to the current message. The function can react to the message, it can create and send (enqueue) new messages, or it can do any other processing.


  • voice_process() – Sequences current time into file names of samples that shall be played. recv: Cmd_SayTime, Cmd_FinishedPlay; send: Cmd_PlayFileName
  • vfs_process()- Opens file by name and passes the handle to sound player. recv: Cmd_PlayFileName; send: Cmd_PlayFileHandle
  • sound_process()- Receives file handle from VFS process, reads samples from the file and sends them at fixed rate to DAC. recv: Cmd_PlayFileHandle; send: Cmd_FinishedPlay
  • ir_process()- Retrieves decoded word from IR receiver, compares to known codewords, sends Cmd_SayTime if the correct button has been pressed. send: Cmd_SayTime
  • debug_process()- Communicates over UART for debug. send: Cmd_SayTime, Cmd_PlayFileName
  • btn_process()- Checks hardware buttons on the CPU board. recv: Cmd_ClockTick
  • clock_process()- Sends periodic clock event messages. send: Cmd_ClockTick

Mechanical Construction

The system has two PCB boards: display board with nixies and high-voltage electronics, and CPU board with ATMEGA32, SD-Card, and sound subsystem. The CPU board is mounted over the display board and a little bit behind, so the two boards form a cascade. The board assembly is mounted on a wooden baseplate–I used a small chopping desk from Ikea. No other cover is used because I like having electronics exposed.

CPU Printed Circuit Board
Nixieboard PCB


The PCB board has a couple of bugs, and they should be fixed by anyone wishing to replicate the design.

  • Connector P1 on CPU board is package DIP-6__300ELL, but the corresponding connector P1 on nixie board is package 6DIP-CONN. While the physical footprints on PCB are the same, the logical assignment of signals to pins is different! Hence a straight flat cable between the connectors will connect incorrect signals. Suggested correction: change package and reroute a part of one of the boards.

  • Drill holes for potentiometer RV2 on CPU board are small.

  • Drill holes for buttons on CPU board are small.


Talking Clock: CPU board schematic

Talking Clock: Nixieboard schema

Project repository on github


4 thoughts on “Talking Clock”

  1. Very nice design!…
    I am interested in making one but could not find if the clock is both 12hr and 24hr enabled? Perhaps I may have missed it. Very well documented as well.

    1. It is 24h, but this is encoded in firmware, so easily changed if you’re not afraid of little programming.

  2. Hello there! I know this is kind of off topic but I was wondering which blog platform are you using for this site?

    I’m getting fed up of WordPress because I’ve had problems with hackers
    and I’m looking at options for another platform.
    I would be fantastic if you could point me in the direction of a good platform.

    1. This is WordPress, indeed, with a theme. I use Akismet plugin to fight spam, and Two Factor Auth to improve login strength.

Leave a Reply

Your email address will not be published. Required fields are marked *