W5GAA Clock

Developer(s): Frank Bouldin (W5GAA)
Date: 1985
Type: Program
Platform(s): TS 2068
Tags: Ham Radio

This program implements a precision digital clock displaying Coordinated Universal Time (UTC) using large block-graphic digits rendered with filled-square characters across a 5-row by 9-column cell for each numeral. The timing mechanism uses six nested FOR loops iterating over GOSUB line numbers (stored in variables G through W) that each render a digit 0–9, so the loop counters directly encode the current time as subroutine addresses rather than separate digit values. Fine timing calibration is achieved by inserting additional BEEP statements with carefully measured durations at the second, 10-second, minute, 10-minute, hour, and 24-hour boundaries, with the primary tick BEEP at line 2080 lasting approximately 0.7396 seconds. The initialization sequence draws a decorative “W5GAA” amateur-radio callsign using PLOT/DRAW vector graphics alongside a simulated television test card with color bars. The user is prompted via INPUT to set each of the four time digits before the clock begins running, with validation enforcing valid hour and minute ranges.


Program Analysis

Program Structure

The program is organized into several major sections: initialization (lines 4000–4070 and 5000–6100), digit-graphics subroutines (lines 1000–1190), the clock timing subroutines (lines 2000–2080), the time-entry subroutines (lines 3000–3310), and the main timing loop (lines 100–240). The splash screen is drawn at startup only, and the clock then runs indefinitely via GO TO 110.

The Core Timing Trick: Loop Counters as Line Numbers

The most distinctive technique in this program is using FOR-loop counters as subroutine addresses. Variables G through S are initialized to specific BASIC line numbers:

VariableLine numberDigit displayed
G10100
O10301
H10502
I10703 (labeled “4” in REM)
P10904
J11105
Q11306
R11507 (labeled “8” in REM)
S11708 (labeled “8” in REM)
K11909

Six nested FOR loops (variables AF) iterate over ranges of these line-number values in steps of 20. Because each digit subroutine occupies exactly 20 lines (e.g. 1010, 1030, 1050…), STEP 20 naturally advances through each digit in sequence. GO SUB A, GO SUB B, etc. thus invoke the correct digit-drawing subroutine for each clock position.

The six loops correspond to: A = tens-of-hours, B = units-of-hours, C = tens-of-minutes, D = units-of-minutes, E = tens-of-seconds, F = units-of-seconds. The innermost loop also calls GO SUB 2000 on each iteration for the timing BEEP.

Loop Boundary Management

The loop limits are maintained dynamically using variables L, M, N, T as the lower bounds of loops A, B, C, D respectively. When a loop counter reaches its upper bound, the lower bound is reset to G (line 1010, i.e. digit 0) for the next cycle. For example, line 110 sets L=G when A=H, correctly resetting the tens-of-hours digit to 0 after reaching 2. The special case at line 120 handles the 1-to-9 range for the tens-of-hours digit by forcing the upper bound of loop B to W=1070 (digit 3) when A=1050 (tens digit = 1), ensuring hours never exceed 19:xx.

Timing Calibration

Clock accuracy is achieved by inserting progressively longer BEEP calls at regular time boundaries rather than using PAUSE. The logic in lines 2010–2080 forms a priority chain:

  1. Line 2020: Once per 24 hours (at 00:00:00) — BEEP 0.6499
  2. Line 2030: Three times per 24 hours (at 06:00, 12:00, 18:00) — BEEP 0.6503
  3. Line 2040: Once per hour (on the hour) — BEEP 0.6521
  4. Line 2050: Once per 10 minutes — BEEP 0.6537
  5. Line 2060: Once per minute (at E=J, F=K, i.e. :59) — BEEP 0.6588
  6. Line 2070: Once per 10 seconds — BEEP 0.6631
  7. Line 2080: Every second (primary tick) — BEEP 0.7395532

Each BEEP uses note 69 (A above middle C at 440 Hz × 2 = 880 Hz) except at boundaries. The primary tick BEEP at line 2080 defines the fundamental second period; all other BEEP durations are chosen empirically to compensate for cumulative drift accumulated by the extra BASIC overhead at those times. A brief additional BEEP at line 2010 (BEEP .001,34) provides a subtle audio tick sound.

Block-Graphic Digit Rendering

Each digit is drawn as a 5-row by 3-character-wide cell using Spectrum block-graphic characters. The AT X,Y coordinates place digits at fixed screen positions, with X fixed at 15 (lower half of screen) and Y set by the calling loop. Notable characters used include \:: (full block █), \'' (upper-half ▀), \.. (lower-half ▄), and spaces for clear areas.

Bugs and Anomalies

  • REM label errors: Lines 1060 and 1080 both have the REM comment "4" graphic; lines 1140 and 1160 both say "8" graphic. Line 1060 actually draws a “3” pattern and line 1140 draws a “7”.
  • Case mismatch at line 3030: LET l=H: GO SUB h uses lowercase l and h. On the Spectrum, variable names are case-insensitive in the tokenizer and these would resolve correctly to L and H.
  • Trailing period at line 4050: The line ends with GO SUB 1010. — the period is interpreted as the decimal point of a numeric literal and does not cause an error, but it is unintentional.
  • Unused variable Y at line 110: LET Y=0 is set in loop A but immediately overridden in subsequent loop bodies, making it redundant for most iterations.
  • Line 3108 validation gap: The check IF V>1 AND Z>3 attempts to reject hours like 24–29, but only resets the second digit; it does not re-prompt the first digit, which could lead to invalid hour states if V=2 and Z=4–9 are entered together before validation catches them.
  • Variable W reuse: W is used both as a temporary upper-bound override in the timing loop (lines 110, 120) and initialized to 1190 in line 4070. This dual use is intentional but fragile.

Splash Screen and Graphics

The startup display draws the amateur callsign “W5GAA” using PLOT/DRAW vector lines (lines 6000–6100) and also renders a simulated television test card with color bars (lines 5110–5158). The “W” is constructed from 16-pixel-wide strokes drawn with diagonal DRAW commands. The color bars use INK 0–6 with block-graphic fill characters across line 13 of the screen. A pixel-level grid pattern is added using a PLOT/DRAW loop at lines 5154–5158.

Initialization Sequence

Line 4010 writes 100 to system variable address 23609 (FRAMES LSB / interrupt delay), effectively setting the TV border color flash rate. Lines 4052–4053 print static colon separators in INK 2 (green) between the digit pairs before the user is prompted for time entry. The GO SUB 3000 at line 4070 triggers the interactive time-setting routine before the main loop begins.

Content

Appears On

One of a series of library tapes. Programs on these tapes were renamed to a number series. This tape contained

Related Products

Related Articles

Related Content

Image Gallery

W5GAA Clock

Source Code

   10 REM "W5GAA-clok" (precision    digital clock, version "A").
   30 REM  By Frank Bouldin                (11/13/85).
   40 REM  To adjust clock speed,change value of BEEP duration inline 2080. Decrease in value    makes clock run faster. PAUSE   values in lines 2020-2070 are   for fine trim insertions at the times indicated in the REMs.
   50 REM  Follow INPUT prompts  to set exact clock time.
   90 GO SUB 4000
  100 REM  6 nested timing loops:
  110 FOR A=L TO H STEP 20: LET Y=0: LET W=K: IF A=H THEN LET L=G
  120 IF A=1050 THEN LET W=1070
  130 GO SUB A
  140 FOR B=M TO W STEP 20: LET Y=4: IF B=W THEN LET M=G
  150 GO SUB B
  160 FOR C=N TO J STEP 20: IF C=J THEN LET N=G
  170 LET Y=12: GO SUB C
  180 FOR D=T TO K STEP 20: IF D=K THEN LET T=G
  190 LET Y=16: GO SUB D
  200 FOR E=G TO J STEP 20: LET Y=24: GO SUB E
  210 IF U=0 THEN PRINT FLASH 1; INK 1;AT 21,0;" -Press any key to start clock- "
  220 IF U=0 THEN PAUSE 0: LET U=1: PRINT INK 0;AT 21,0;"COORDINATED UNIVERSAL TIME (UTC)"
  240 LET Y=28: FOR F=G TO K STEP 20: GO SUB F: GO SUB 2000: NEXT F: NEXT E: NEXT D: NEXT C: NEXT B: NEXT A: GO TO 110
 1000 REM  "0" graphic:
 1010 PRINT AT X,Y;"\::\::\::";AT X+1,y;"\:: \::";AT X+2,Y;"\:: \::";AT X+3,Y;"\:: \::";AT X+4,Y;"\::\::\::": RETURN 
 1020 REM  "1" graphic:
 1030 PRINT AT X,Y;"\ :\:: ";AT X+1,Y;" \:: ";AT X+2,Y;" \:: ";AT X+3,Y;" \:: ";AT X+4,Y;"\ :\::\:  ": RETURN 
 1040 REM  "2" graphic:
 1050 PRINT AT X,Y;"\::\::\::";AT X+1,Y;"\'' \::";AT X+2,Y;"\::\::\::";;AT X+3,Y;"\:: \..";AT X+4,Y;"\::\::\::": RETURN 
 1060 REM  "4" graphic:
 1070 PRINT AT X,Y;"\::\::\::";AT X+1,Y;"\'' \::";AT X+2,Y;"\ :\::\::";AT X+3,Y;"\.. \::";AT X+4,Y;"\::\::\::": RETURN 
 1080 REM  "4" graphic:
 1090 PRINT AT X,Y;"\:: \::";AT X+1,Y;"\:: \::";AT X+2,Y;"\::\::\::";AT X+3,Y;"  \::";AT X+4,Y;"  \::": RETURN 
 1100 REM  "5" graphic:
 1110 PRINT AT X,Y;"\::\::\::";AT X+1,Y;"\::  ";AT X+2,Y;"\::\::\::";AT X+3,Y;"\.. \::";AT X+4,Y;"\::\::\::": RETURN 
 1120 REM  "6" graphic:
 1130 PRINT AT X,Y;"\::\::\::";AT X+1,Y;"\:: \''";AT X+2,Y;"\::\::\::";AT X+3,Y;"\:: \::";AT X+4,Y;"\::\::\::": RETURN 
 1140 REM  "8" graphic:
 1150 PRINT AT X,Y;"\::\::\::";AT X+1,Y;"\'' \::";AT X+2,Y;"  \::";AT X+3,Y;"  \::";AT X+4,Y;"  \::": RETURN 
 1160 REM  "8" graphic:
 1170 PRINT AT X,Y;"\::\::\::";AT X+1,Y;"\:: \::";AT X+2,Y;"\::\::\::";AT X+3,Y;"\:: \::";AT X+4,Y;"\::\::\::": RETURN 
 1180 REM  "9" graphic:
 1190 PRINT AT X,Y;"\::\::\::";AT X+1,Y;"\:: \::";AT X+2,Y;"\::\::\::";AT X+3,Y;"\.. \::";AT X+4,Y;"\::\::\::": RETURN 
 2000 REM  Clock "ticks":
 2010 BEEP .001,34
 2012 REM  Clock timing adjust:
 2015 REM  1 PAUSE every 24 hours    (AT 00:00:00):
 2020 IF A=G AND B=G AND C=G AND D=G AND E=G AND F=G THEN BEEP .6499,6: RETURN 
 2025 REM 3 PAUSEs every 24 hoursat 06:00:00,12:00:00 & 18:00:00:
 2030 IF (A=G AND B=Q OR A=O AND (B=H OR B=S)) AND C=G AND D=G AND E=G AND F=G THEN BEEP .6503,18: RETURN 
 2035 REM  1 PAUSE each hour, on the hour, except for the above:
 2040 IF C=G AND D=G AND E=G AND F=G THEN BEEP .6521,22: RETURN 
 2045 REM  1 PAUSE every 10 min.     except for the above:
 2050 IF D=G AND E=G AND F=G THEN BEEP .6537,69: RETURN 
 2055 REM  1 PAUSE each minute,       except for the above:
 2060 IF E=J AND F=K THEN BEEP .6588,69: RETURN 
 2065 REM  1 Pause every 10 sec.     (except for the above):
 2070 IF F=K THEN BEEP .6631,69: RETURN 
 2075 REM  PRIMARY time adjust   (1 PAUSE every second, (except  for the above):
 2080 BEEP 0.7395532,69: RETURN 
 2999 REM  Clock digit settings:
 3000 INK 1: LET Y=0: FLASH 1: GO SUB G
 3005 INPUT "    ENTER first digit ";V: FLASH 0
 3010 IF V=0 THEN LET L=G: GO SUB G
 3020 IF V=1 THEN LET L=O: GO SUB O
 3030 IF V=2 THEN LET l=H: GO SUB h
 3040 IF V>2 THEN GO TO 3000
 3050 LET Y=4: FLASH 1: GO SUB G
 3055 INPUT "    ENTER second digit ";Z: FLASH 0
 3060 IF Z=0 THEN LET M=G: GO SUB G
 3070 IF Z=1 THEN LET M=O: GO SUB O
 3080 IF Z=2 THEN LET M=H: GO SUB H
 3090 IF Z=3 THEN LET M=I: GO SUB I
 3100 IF Z=4 THEN LET M=P: GO SUB P
 3101 IF Z=5 THEN LET M=J: GO SUB J
 3102 IF Z=6 THEN LET M=Q: GO SUB Q
 3103 IF Z=7 THEN LET M=R: GO SUB R
 3104 IF Z=8 THEN LET M=S: GO SUB S
 3105 IF Z=9 THEN LET M=K: GO SUB K
 3106 IF Z>9 THEN GO TO 3050
 3108 IF V>1 AND Z>3 THEN LET Y=4: GO SUB G: GO TO 3000
 3110 LET Y=12: FLASH 1: GO SUB G
 3115 INPUT "    ENTER third digit ";Z: FLASH 0
 3120 IF Z=0 THEN LET N=G: GO SUB G
 3130 IF Z=1 THEN LET N=O: GO SUB O
 3140 IF Z=2 THEN LET N=H: GO SUB H
 3150 IF Z=3 THEN LET N=I: GO SUB I
 3160 IF Z=4 THEN LET N=P: GO SUB P
 3170 IF Z=5 THEN LET N=J: GO SUB J
 3180 IF Z>5 THEN GO TO 3110
 3190 LET Y=16: FLASH 1: GO SUB G
 3195 INPUT "    ENTER fourth digit ";Z: FLASH 0
 3200 IF Z=0 THEN LET T=G: GO SUB G
 3210 IF Z=1 THEN LET T=O: GO SUB O
 3220 IF Z=2 THEN LET T=H: GO SUB H
 3230 IF Z=3 THEN LET T=I: GO SUB I
 3240 IF Z=4 THEN LET T=P: GO SUB P
 3250 IF Z=5 THEN LET T=J: GO SUB J
 3260 IF Z=6 THEN LET T=Q: GO SUB Q
 3270 IF Z=7 THEN LET T=R: GO SUB R
 3280 IF Z=8 THEN LET T=S: GO SUB S
 3290 IF Z=9 THEN LET T=K: GO SUB K
 3300 IF Z>9 THEN GO TO 3190
 3310 RETURN 
 4000 REM  Program Initialization
 4010 CLS : POKE 23609,100
 4020 BORDER 7: PAPER 7: INK 0: CLS 
 4045 REM  Variables:
 4050 GO SUB 5000: LET B=0: LET X=15: LET Y=0: GO SUB 1010: LET Y=4: GO SUB 1010: LET Y=12: GO SUB 1010: LET Y=16: GO SUB 1010: LET Y=24: GO SUB 1010: LET Y=28: GO SUB 1010.
 4051 REM  Clock colons:
 4052 PRINT INK 1;;AT 21,0;"ENTER INPUT prompts to set clock"
 4053 PRINT INK 2;AT 16,9;"\::";AT 16,21;"\::";AT 18,9;"\::";AT 18,21;"\::"
 4055 REM  More Variables:
 4060 LET G=1010: LET H=1050: LET I=1070: LET J=1110: LET K=1190: LET L=1010: LET M=1010: LET N=1010
 4070 LET O=1030: LET P=1090: LET Q=1130: LET R=1150: LET S=1170: LET T=1010: LET U=0: LET W=1190: GO SUB 3000: RETURN 
 5000 REM  "W5GAA" graphics:
 5005 INK 0: GO SUB 6000
 5010 PRINT AT 0,7;" \::\::\::\::\:: \::\::\::\::\::"
 5020 PRINT AT 1,7;" \::\::    \::\::  \::"
 5030 PRINT AT 2,7;" \::\::    \::\::"
 5040 PRINT AT 3,7;" \::\::    \::\::"
 5050 PRINT AT 4,7;" \::\::\::\::\:: \::\:: \::\::"
 5060 PRINT AT 5,7;"     \:: \::\::  \::"
 5070 PRINT AT 6,7;" \::\::  \:: \::\::  \::"
 5080 PRINT AT 7,7;" \::\::\::\::\:: \::\::\::\::\::"
 5090 GO SUB 6050
 5100 REM  "television" graphics:
 5110 INK 4: PRINT AT 8,2;"\ .\.     \..        \ .\.    \ .\. "
 5120 PRINT AT 9,2;"\.:\:. \..\.. \:: \ .\..\. \ .\.  \. \..\. \ .\..\. \..\. \ .\..\. \..\..\. "
 5130 PRINT AT 10,2;"\ :\:  \::\.: \:: \ :\:.\: \ :\:.\ .\: \ :\: \ :\:.\. \ :\: \ :\: \: \ :\: \: "
 5140 PRINT AT 11,2;"\ :\:. \::\.. \::\. \ :\:.\.  \':\:' \ :\:.\ .\.:\: \ :\:.\ :\:.\: \ :\: \:."
 5148 REM  Color bars:
 5149 INK 0: PLOT 0,72: DRAW 255,0: DRAW 0,-9: DRAW -255,0: DRAW 0,9
 5150 PRINT INK 0;AT 13,1;"   "; INK 6;AT 13,3;"\::\::\::"; INK 5;AT 13,6;"\::\::\::"; INK 4;AT 13,9;"\::\::\::"; INK 3;AT 13,12;"\::\::\::"; INK 2;AT 13,15;"\::\::\::"; INK 1;AT 13,18;"\::\::\::"; INK 0;AT 13,21;"\::\::\::"
 5154 INK 0: LET X1=192: FOR N=64 TO 71 STEP 2: PLOT X1,N: DRAW 32,0: NEXT N
 5158 LET Y1=64: FOR N=224 TO 255 STEP 2: PLOT N,Y1: DRAW 0,8: NEXT N
 5499 RETURN 
 6000 REM  "W" graphic
 6010 LET XX=7: FOR N=0 TO 15: PLOT N,175: DRAW XX,-63: NEXT N
 6020 LET XX=12: FOR N=27 TO 34: PLOT N,163: DRAW -XX,-51: NEXT N
 6030 LET XX=14: FOR N=27 TO 34: PLOT N,163: DRAW XX,-51: NEXT N
 6040 LET XX=7: FOR N=48 TO 55: PLOT N,175: DRAW -XX,-63: NEXT N: RETURN 
 6045 REM  "A" graphic
 6050 FOR N=171 TO 187: PLOT N,175: DRAW -12,-63: NEXT N
 6060 FOR N=178 TO 187: PLOT N,175: DRAW 12,-63: NEXT N
 6070 FOR N=131 TO 124 STEP -1: PLOT 175,N: DRAW 16,0: NEXT N
 6080 FOR N=219 TO 235: PLOT N,175: DRAW -12,-63: NEXT N
 6090 FOR N=226 TO 235: PLOT N,175: DRAW 12,-63: NEXT N
 6100 FOR N=131 TO 124 STEP -1: PLOT 223,N: DRAW 16,0: NEXT N: RETURN 
 9998 REM  to SAVE with auto-RUN:
 9999 CLEAR : SAVE "W5GAA-clok" LINE 1

Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.

Scroll to Top