How to Make a Digital Clock on a Vintage B&W TV using Arduino
This project successfully transforms a vintage TV into a functional and stylish retro clock.
Components and supplies
1
Arduino Nano
1
Resistor 10k ohm
1
Resistor 1k Ohm
1
DS3231 clock module
Tools and machines
1
Soldering iron kit.
Apps and platforms
1
Arduino IDE
Project description
Code
Code
cpp
...
1// Arduino CRT TV Clock by mircemk, September 2025 2 3#include <TVout.h> 4#include <fontALL.h> 5#include "MyLogo.h" 6#include <Wire.h> 7#include <avr/pgmspace.h> // For PROGMEM 8 9TVout TV; 10 11#define DS3231_I2C_ADDRESS 0x68 12 13long previousMillis = 0; 14byte second, minute, hour, dayOfWeek, dayOfMonth, month, year; 15long interval = 1000; // Update every 1 second 16byte lastDayOfWeek = 0; // To track changes in day of week 17byte lastDayOfMonth = 0; // To track changes in date 18 19// Array of day names in PROGMEM (1=Sunday, 2=Monday, ..., 7=Saturday) 20const char day0[] PROGMEM = "Unknown"; 21const char day1[] PROGMEM = "Sunday"; 22const char day2[] PROGMEM = "Monday"; 23const char day3[] PROGMEM = "Tuesday"; 24const char day4[] PROGMEM = "Wednesday"; 25const char day5[] PROGMEM = "Thursday"; 26const char day6[] PROGMEM = "Friday"; 27const char day7[] PROGMEM = "Saturday"; 28const char *const dayNames[] PROGMEM = {day0, day1, day2, day3, day4, day5, day6, day7}; 29 30byte decToBcd(byte val) { 31 return ((val/10*16) + (val%10)); 32} 33 34byte bcdToDec(byte val) { 35 return ((val/16*10) + (val%16)); 36} 37 38void getDateDs3231() { 39 Wire.beginTransmission(DS3231_I2C_ADDRESS); 40 Wire.write(0x00); 41 Wire.endTransmission(); 42 Wire.requestFrom(DS3231_I2C_ADDRESS, 7); 43 second = bcdToDec(Wire.read() & 0x7f); 44 minute = bcdToDec(Wire.read()); 45 hour = bcdToDec(Wire.read() & 0x3f); 46 dayOfWeek = bcdToDec(Wire.read()); 47 dayOfMonth = bcdToDec(Wire.read()); 48 month = bcdToDec(Wire.read()); 49 year = bcdToDec(Wire.read()); 50} 51 52void setup() { 53 Wire.begin(); 54 getDateDs3231(); 55 TV.begin(PAL, 130, 96); 56 TV.select_font(font8x8); 57 TV.set_cursor(15, 13); 58 TV.print("DIY Arduino"); 59 TV.set_cursor(22, 40); 60 TV.print("CRT Clock"); 61 TV.draw_rect(20, 38, 75, 13, 1, -1); 62 TV.draw_rect(17, 35, 81, 19, 1, -1); 63 TV.set_cursor(8, 67); 64 TV.print("TVout Library"); 65 TV.delay(5000); 66 TV.clear_screen(); 67 intro(); 68 TV.set_cursor(12, 2); 69 TV.print("Time & Date:"); 70 TV.draw_rect(6, 0, 105, 12, 1, 2); 71 72 73 TV.draw_line(15, 39, 103, 39, 1); 74 TV.draw_line(15, 61, 103, 61, 1); 75 76 // Initial display of day and date 77 78 TV.set_cursor(25, 45); 79 char buffer[10]; 80 strcpy_P(buffer, (char *)pgm_read_word(&dayNames[dayOfWeek])); 81 TV.print(buffer); 82 TV.set_cursor(20, 68); 83 TV.print(char(dayOfMonth/10 + 0x30)); 84 TV.print(char(dayOfMonth%10 + 0x30)); 85 TV.print("/"); 86 TV.print(char(month/10 + 0x30)); 87 TV.print(char(month%10 + 0x30)); 88 TV.print("/"); 89 TV.set_cursor(68, 68); 90 TV.print("20"); 91 TV.print(char(year/10 + 0x30)); 92 TV.print(char(year%10 + 0x30)); 93 lastDayOfWeek = dayOfWeek; 94 lastDayOfMonth = dayOfMonth; 95} 96 97void loop() { 98 unsigned long currentMillis = millis(); 99 if (currentMillis - previousMillis > interval) { 100 previousMillis = currentMillis; 101 getDateDs3231(); 102 #ifdef TVOUT_VBLANK 103 TV.wait_for_vblank(); // Synchronize with vertical blanking if available 104 #endif 105 printTime(); 106 } 107} 108 109void printTime() { 110 // Clear and print time (changes every second) 111 TV.draw_rect(25, 25, 48, 8, 0, 1); // Clear time area (width for HH:MM:SS) 112 TV.set_cursor(25, 25); 113 TV.print(char(hour/10 + 0x30)); 114 TV.print(char(hour%10 + 0x30)); 115 TV.print(":"); 116 TV.print(char(minute/10 + 0x30)); 117 TV.print(char(minute%10 + 0x30)); 118 TV.print(":"); 119 TV.print(char(second/10 + 0x30)); 120 TV.print(char(second%10 + 0x30)); 121 122 // Print day of week only if it has changed 123 if (dayOfWeek != lastDayOfWeek && dayOfWeek >= 1 && dayOfWeek <= 7) { 124 TV.draw_rect(25, 45, 80, 8, 0, 1); // Clear day area (width for longest day name) 125 TV.set_cursor(25, 45); 126 char buffer[10]; 127 strcpy_P(buffer, (char *)pgm_read_word(&dayNames[dayOfWeek])); 128 TV.print(buffer); 129 lastDayOfWeek = dayOfWeek; 130 } 131 132 // Print date only if dayOfMonth has changed 133 if (dayOfMonth != lastDayOfMonth) { 134 TV.draw_rect(10, 68, 64, 8, 0, 1); // Clear date area (width for DD/MM/YYYY) 135 TV.set_cursor(10, 68); 136 TV.print(char(dayOfMonth/10 + 0x30)); 137 TV.print(char(dayOfMonth%10 + 0x30)); 138 TV.print("/"); 139 TV.print(char(month/10 + 0x30)); 140 TV.print(char(month%10 + 0x30)); 141 TV.print("/"); 142 TV.set_cursor(58, 68); 143 TV.print("20"); 144 TV.print(char(year/10 + 0x30)); 145 TV.print(char(year%10 + 0x30)); 146 lastDayOfMonth = dayOfMonth; 147 } 148} 149 150void intro() { 151 unsigned char w, l, wb; 152 int index; 153 w = pgm_read_byte(MyLogo); 154 l = pgm_read_byte(MyLogo+1); 155 if (w & 7) 156 wb = w/8 + 1; 157 else 158 wb = w/8; 159 index = wb*(l-1) + 2; 160 for (unsigned char i = 1; i < l; i++) { 161 TV.bitmap((TV.hres() - w)/2, 0, MyLogo, index, w, i); 162 index -= wb; 163 TV.delay(50); 164 } 165 for (unsigned char i = 0; i < (TV.vres() - l); i++) { 166 TV.bitmap((TV.hres() - w)/2, i, MyLogo); 167 TV.delay(50); 168 } 169 TV.delay(3000); 170 TV.clear_screen(); 171}
Downloadable files
Libs
...
Libraries.zip
Documentation
Schematic
...
Schematic.jpg

Comments
Only logged in users can leave comments