1Hz MicrocontrollerAugust 6, 2025 Introduction Hackaday.com was having a 1Hz challenge so I decided to create something for it. A few years ago I did a WWVB Binary Clock project where a WWVB module received a pulse once a second from a radio Colorado. The pulse could be 0.2s, 0.5s, or 0.8s depending on if the data is a 0, 1, or space. The thought here is, can that pulse be used as the clock signal for a microcontroller. By default the ATtiny85 runs on an internal 8MHz clock source divided down to 1MHz, but with some fuse settings it can get it's clock from a CLK-I pin. The WWVB receiver in this project is used to toggle that pin at 1Hz. Kind of an interesting thought: Not only is this a microcontroller running at 1Hz, but the CPU clk signal is 1454 km (904 miles) away from the actual CPU core. The WWVB module I used this time is a Canaduino Atomic Clock Receiver V4. Really nice module, might have to actually use it to grab the encoded time. Speaking of, just to make this clear: yes the WWVB module can read an encoded time / date from a radio in Colorado, but this project is using the fact that the data is encoded as pulses sent once a second to be a CPU clk source. This project has nothing to with the actual time and date. Video at the bottom of the page. Explanation The microcontroller of choice here is an 8 pin ATtiny85. Pin 0 is hooked up to an LED while pin 2 will configured (through the ATtiny85 fuses) as the CLK-I (clock in) pin. The code is pretty simple, turn PB0 on, turn PB0 off, and loop. The code (including the setup code) looks like this:
.include "tn85def.inc"
.avr8
; CKSEL = 0000 (Clock source is CLK-I pin)
; SUT = 0
; CKDIV8 = 1 (disabled)
; FUSE LOW = 11000000 = 0xc0
.org 0x000
rjmp start
start:
;; Disable interrupts.
cli
;; Setup stack ptr.
ldi r17, RAMEND & 0xff
out SPL, r17
;; r0 = 0, r1 = 1, r15 = 255.
eor r0, r0
eor r1, r1
inc r1
ldi r17, 0xff
mov r15, r17
;; Setup PORTB (10101).
;; PB0: LED output.
ldi r17, 0x01
out DDRB, r17
out PORTB, r0
; Enable interrupts.
sei
main:
cbi PORTB, 0
sbi PORTB, 0
rjmp main
The code is assembled with naken_asm which has the ability in both a regular disassembly and the .lst disassembly to show how many CPU cycles each instruction takes. For most instructions, the CPU takes only 1 cycle:
out DDRB, r17
0x000a: bb17 out 0x17, r17 cycles: 1
out PORTB, r0
0x000b: ba08 out 0x18, r0 cycles: 1
For the code in the main: block of code, each instruction takes 2 cycles:
main:
cbi PORTB, 0
0x000d: 98c0 cbi 0x18, 0 cycles: 2
sbi PORTB, 0
0x000e: 9ac0 sbi 0x18, 0 cycles: 2
rjmp main
0x000f: cffd rjmp 0xd (-3) cycles: 2
This means for every 2 pulses from the WWVB module, the CPU only runs 1 instruction in main. Because of this, the PB0 LED should be off for 2 WWVB blinks and on for every 4 WWVB blinks. The pulses from the WWVB look a bit erratic since they aren't 50% on 50% off, but this is just because they encode data. The microcontroller itself just needs an on and then off in order to execute code, so that part ends up not mattering. https://youtu.be/1bnt1-9yogY?si=o1tvMxbFk3XXks9d The PB0 LED (as seen in the video above) is connected to the eye on the left side. The LED on the right side is from the WWVB module. The WWVB LED blinks in an irregular way since the amount of time the LED is on tells if the data bit is 0, 1, or space. The amount of time for a full cycle of LED on / off (unless there is radio noise) is still 1 second. The LED from the microcontroller blinks 2 seconds off and 4 seconds on since it takes 2 cycles per instruction and the "rjmp main" is performed while the LED is on.
Copyright 1997-2025 - Michael Kohn
|