Project 04 - Retro Digital Clock (Nixie Type)

<< Click to Display Table of Contents >>

Navigation:  Projects >

Project 04 - Retro Digital Clock (Nixie Type)

This project draws a retro digital clock with nixie font (bitmap files) using the PCF8523T RTC component. It uses the PCF8523T CleO library to interact with the PCF8523T RTC component.

 

 

Component(s)

 

This project uses the following component(s) -

 

PCF8523T RTC

56mm, 80hm 0.5W(RMS) / 1W(Peak) Internal CleO speaker

 

 

Wiring Diagram

 

 

Project 04-Retro Digital Clock

 

 

Code

 

The following code shows how the setup() routine checks for the Oscillator Stop Flag (OSF) in PCF8523T RTC component. Based on the OSF flag, it shows the SetDateTime() widget or continues with the existing date and time value from the RTC hardware. It then loads the nixie image files along with the play and setting icons. If the RTC is not present, then it uses the software timer to display the selected date and time.

 

The 1-wire library is first initialized to interact with the PCF8523T RTC component. Later the SetDateTime() widget is invoked which prompts the users to select the date and time. This information will be stored in the epoch time. The Epoch time is converted to year, month, day of month, hour, minute, second and day of week using the EpochToDate() routine.

 

void setup() {

 Serial.begin(115200);

 #ifdef _VARIANT_ARDUINO_DUE_X_

   Wire1.begin(); // Shield I2C pins connect to alt I2C bus on Arduino Due

 #else

   Wire.begin();

 #endif

 

 if (rtc.begin() == -1) // RTC is not detected

   software_timer = true;

 

/* Initialize CleO */

 CleO.begin();

 CleO.Start();

 CleO.Show();

 

/* Get each digit image handle */

 digit[0] = CleO.LoadImageFile("@Pictures/nixie/0.png", 0);

 digit[1] = CleO.LoadImageFile("@Pictures/nixie/1.png", 0);

 digit[2] = CleO.LoadImageFile("@Pictures/nixie/2.png", 0);

 digit[3] = CleO.LoadImageFile("@Pictures/nixie/3.png", 0);

 digit[4] = CleO.LoadImageFile("@Pictures/nixie/4.png", 0);

 digit[5] = CleO.LoadImageFile("@Pictures/nixie/5.png", 0);

 digit[6] = CleO.LoadImageFile("@Pictures/nixie/6.png", 0);

 digit[7] = CleO.LoadImageFile("@Pictures/nixie/7.png", 0);

 digit[8] = CleO.LoadImageFile("@Pictures/nixie/8.png", 0);

 digit[9] = CleO.LoadImageFile("@Pictures/nixie/9.png", 0);

 

 icon_play[0] = CleO.LoadIcon("@Icons/m48.ftico", ICON_PLAY_CIRCLE_OUTLINE);

 icon_play[1] = CleO.LoadIcon("@Icons/m48.ftico", ICON_PLAY_CIRCLE_FILLED);

 icon_setting = CleO.LoadIcon("@Icons/m48.ftico", ICON_SETTINGS);

 int16_t s = 0, m = 0, h = 0, dayOfWeek = 0, dayOfMonth = 0, mon = 0, y = 0;

 if (software_timer == true)

 {

   CleO.SetDateTime("Date/Time", t0);

   CleO.EpochToDate(t0, y, mon, dayOfMonth, h, m, s, dayOfWeek);

  }

 

else if (!rtc.isrunning() || rtc.checkOSF() == 1) {

   CleO.SetDateTime("Date/Time", t0);

   CleO.EpochToDate(t0, y, mon, dayOfMonth, h, m, s, dayOfWeek);

   rtc.set_time(y, mon + 1, dayOfMonth, h, m, s, dayOfWeek);

 }

 else { /* RTC is running fine */

   rtc.get_time(y, mon, dayOfMonth, h, m, s, dayOfWeek);

   CleO.DateToEpoch(t0, y, mon - 1, dayOfMonth, h, m, s);

 }

 

 startTime = millis();

 

 CleO.Start();

 CleO.Show();

}

 

The loop() routine checks for the touch events and then updates the nixie images based on the date and time values.

 

void loop() {

 touchControl();

 updateTimer();

}

 

The updateTimer() routine checks if the software timer should be used or not. Once the updated values of hour and seconds are received, it displays the bitmaps and icons.

 

void updateTimer() {

 int16_t s, m, h, dayOfWeek, dayOfMonth, mon, y;

 

 if (software_timer == false) {

rtc.get_time(y, mon, dayOfMonth, h, m, s, dayOfWeek);

  else {

   elapsedTime = (millis() - startTime) / 1000L;

   CleO.EpochToDate(t0 + elapsedTime, y, mon, dayOfMonth, h, m, s, dayOfWeek);

   mon += 1; /* CleO.EpochToDate() gives January month as 0 */

   dayOfWeek += 1; /* CleO.EpochToDate() gives Sunday as 0 */

 }

 

/* Update speaking time */

 speak_hour = h, speak_min = m;

 

/* Start drawing the screen shot */

 CleO.Start();

 CleO.BitmapJustification(MM);

 

 /* Draw bitmap digits for hour, minute and second */

 show2(400 - 250, 240 - 150, h);

 show2(400 - 50, 240 - 150, m);

 show2(400 + 150, 240 - 150, s);

 

/* Draw bitmap digits for month and day of month */

 show2(400 - 140, 240 - 20, mon);

 show2(400 + 50, 240 - 20, dayOfMonth);

 

/* Draw bitmap digits for year */

 show2(400 - 110, 240 + 120, y / 100);

 show2(400 + 25, 240 + 120, y % 100);

 

/* Draw play icon */

CleO.Tag(100);

CleO.Bitmap(icon_play[playing], 400 - 200, 430);

 

  /* Draw setting icon */

  CleO.Tag(101);

  CleO.Bitmap(icon_setting, 400 + 190, 430);

 

 /* Show the screenshot */

 CleO.Show();

}

 

The touchControl() routine checks for the play or setting button press events.

 

This project has the capabilities of presenting the time as sound. The sound plays the current time displayed on the screen. On pressing the play icon, it plays the wav files stored on the device based on the hour and minutes value. For various values of hour and minute, the AudioPlay() command is used to play the relevant WAV files. The following code snippet shows how to play various sounds on touch -

 

/* UpdateTimer() routine is called to update UI while speaking time */

void processTags(int16_t tag) {

 char buf[40];

 if (tag == 100) {

   CleO.AudioPlay("@Music/Sounds/TheTimeIsNow.wav", PLAY_WAIT);

   updateTimer();

 

   if (speak_hour > 12)

     speak_hour -= 12;

 

   if (speak_hour == 0 || speak_hour == 12)

     CleO.AudioPlay("@Music/Sounds/12.wav", PLAY_WAIT);

   else {

     sprintf(buf, "@Music/Sounds/%d.wav", speak_hour);

     CleO.AudioPlay(buf, PLAY_WAIT);

   }

 

   updateTimer();

   CleO.AudioPlay("@Music/Sounds/oClock.wav", PLAY_WAIT);

   updateTimer();

 

   if (speak_min > 0) {

     if (speak_min < 21 || speak_min == 30 || speak_min == 40 || speak_min == 50) {

       sprintf(buf, "@Music/Sounds/%d.wav", speak_min);

       CleO.AudioPlay(buf, PLAY_WAIT);

       updateTimer();

     } else {

       if (speak_min < 30)

         CleO.AudioPlay("@Music/Sounds/20.wav", PLAY_WAIT);

       else if (speak_min < 40)

         CleO.AudioPlay("@Music/Sounds/30.wav", PLAY_WAIT);

       else if (speak_min < 50)

         CleO.AudioPlay("@Music/Sounds/40.wav", PLAY_WAIT);

       else

         CleO.AudioPlay("@Music/Sounds/50.wav", PLAY_WAIT);

 

       updateTimer();

       sprintf(buf, "@Music/Sounds/%d.wav", speak_min % 10);

       CleO.AudioPlay(buf, PLAY_WAIT);

       updateTimer();

     }

 

     CleO.AudioPlay("@Music/Sounds/minutes.wav", PLAY_WAIT);

     updateTimer();

   }

 } else if (tag == 101) { /* Setting button is pressed */

  CleO.Start();

   CleO.Show();

   int16_t s = 0, m = 0, h = 0, dayOfWeek = 0, dayOfMonth = 0, mon = 0, y = 0;

   elapsedTime = (millis() - startTime) / 1000L;

   uint32_t t1 = t0 + elapsedTime;

   int16_t ret = CleO.SetDateTime("Date/Time", t1);

 

   CleO.Start();

   CleO.Show();

 

   if (0 == ret) {

     CleO.EpochToDate(t1, y, mon, dayOfMonth, h, m, s, dayOfWeek);

     rtc.set_time(y, mon + 1, dayOfMonth, h, m, s, dayOfWeek);

     startTime = millis();

     t0 = t1;

   }

 }

}

 

 

Output

 

 

Project04-RetroDigitalClockNIXIEType