NTP LED Matrix Clock
AKA: Nuclear Clock
Nano Info Time NTP RTC
ESP32.38 ESP32.30 ESP8266 WiFi
Wire Timezone ESP32 vs ESP8266 LED Matrix
Projector Arduino Serial Libs Arduino Libs Info NodeMCU
NV-Ram LCD I2C Luminosity Sensor
ESP8266 on an ESP01 Scrolling Time Sketch Scrolling ASCII Chars More about THE ATOMIC CLOCK

A new world, I got the Nano working with an ESP826 on an ESP01 adapter but, didn't have RAM left, so I am trying an ESP32 NodeMCU.   I call it a Nuclear Clock (Atomic Clock was already used) it's timekeeping depends on the energy state changes of cesium atoms passing through an RF field.  

06/21/22: Page Origin

A thought about initial Nuclear Clock setup without input devices on the clock:
It ocurred to me, that if a new WiFi device initially came up as another wireless network (with an SSID like "Clock") another device (like a lap top) could connect (on port 80), a setup menu would be provided which allowed the Clock Device to connect to the owner's existing WiFi network and ultimately, to the internet.  



ESP32NodeMCU 38 Pin pinout.


Connecting the ESP32NodeMCU to a DS3231 RTC:
RTC->SCL->ESP2->SCL i.e. Pin D22 (I2C)
RTC->SDA->ESP2->SDA i.e. Pin D21
RTC->Vcc->ESP2->Vcc -> 3.3 V
MAX7219 (LedMtx)
MTX->DAT->ESP32->MOSI ->13
MTX->CLK->ESP32->SPI CLK->14
MTX->CS->ESP32->27
MTX->Vcc->5V
The DS3231 also has a 24C32 Non-Volatile Ram chip on board.
DS3231 RTC pinout.  
DS3231 has and I2C interface,
CLK goes to ESP32->22
DAT goes to ESP32->21
The DS3231 also has an on-board 24C32 Non-Volatile RAM.


Cllck for larger PIC.


Led Matrix

MAX7219 Led Matrix conectors.  
MAX7219 has an SPI interface:
DIN -> ESP32->13
CLK -> Esp32->14
CS -> ESP32->27


Cllck for larger PIC.


Time Test
Time test lash-up.   You can see the ESP32NodeMCU (lower left), temporary display 2004 (upper right), and the DS3231 RTC top center of bread board.   The ESP32NodeMCU is getting the time from our NTP server, storing it into the RDC, retrieving it and finally displaying it on the 2004 LCD.

The Nano at the upper left isn't used, it just happened to be on the test board.

The sketch  


Closer look at the Time Test display.  


Led Matrix Number Test
The number test, all ascii chars scrolling.   This is a test of the Led Matrix driving code.   I started out with this scrolling "The quick brown fox jumped over the lazy dog" in both upper and lower case.   The program also scrolls all 128 ASCII characters.
The Sketch


This is on the lowest intensity setting.   Note the colon in the center is also present.


Some of the lower case characters.  



The ESP8266 mounted on an ESP-01 adapter.
 


Here is the ESP-01 and it's adapter.   The adapter takes care of all the ESP-01's needs, the only restriction is you can't reflash the ESP8266 with the Adapter.


Pinout of the ESP8266.  


Schematic of the ESP-01 Adapter.  


The RTC (DS3231).   The larger chip (top) is the DS3231, the smaller chip (lower) is the 24C32 EEPROM.


Note that the three adapter boards all have their pins 90° and will have to have them replaced with straight pins in order to mount them.  

Time Code
/*H********************************************************************
* Matrix clock with scrolling data.
* Mtx-2 = DAT, Mtx-3 = CS, Mtx-4 = CLK
**********************************************************************/
#include <LedControl.h>
#include "ChrCodes.h"

//************************* DEFINES ************************************
#define  MTX_DAT  2
#define  MTX_CLK  4
#define  MTX_CS   3
#define  BAUD   9600
typedef unsigned long ulong;

//************************* PROTOTYPES ************************************
void msg( char *msgStr ); 
void scrollFont(); 
void ldBuff( int chr );
void rotBuff();
void pntBuff( );

//************************* VARIABLES ************************************
const int NbrDevs = 4;                            // NUMBER OF MAX7219s USED
const long ScrlDly = 75;                           // ADJUST SCROLLING SPEED
ulong Buff[14] = {0}; 
//                         DAT, CLK CS, NbrDevs
LedControl Mtx = LedControl( MTX_DAT, MTX_CLK, MTX_CS, NbrDevs );
const char ScrlTxt[] = {
    "  THE QUICK BROWN FOX JUMPED OVER THE LAZY DOG 1234567890"
    "  the quick brown fox jumped over the lazy dog   " };

/*F********************************************************************
*
**********************************************************************/
void 
setup( )
{
    Serial.begin( BAUD );
    for( int x =0; x < NbrDevs; x++ )
    {
        Mtx.shutdown( x, false );// MAX72XX IS IN POWER-SAVING MODE ON STARTUP
        Mtx.setIntensity( x, 0 );          // SET BRIGHTNESS TO DEFAULT VALUE
        Mtx.clearDisplay( x );                           // AND CLEAR DISPLAY
    }
    Serial.println( "startup end" );
}
/*F********************************************************************
*
**********************************************************************/
void 
loop( )
{ 
    Serial.println("Loop bgn");
    msg( ScrlTxt );
      Serial.println( "loop past scroll Msg" );
    scrollFont();
}
/*F********************************************************************
* DISPLAYS ENTIRE ChrCodes ARRAY
**********************************************************************/
void 
scrollFont() 
{
    int   ndx;

    for( ndx = 0x20; ndx < 0x80; ndx++ )
    {
        ldBuff( ndx );
        delay( 33 );     // WAS 500
    }
}
/*F********************************************************************
* Scroll Message
**********************************************************************/
void 
msg( char *msgStr ) 
{
    int cnt = 0, chr =0;

    for( cnt =0; (chr = ScrlTxt[cnt]) != 0; cnt++ )
        ldBuff( chr );                               // READ BACK A CHAR
}
/*F********************************************************************
* Load character into scroll buffer, ALL THE SHUCKING AND JIVING HAPPENS HERE
**********************************************************************/
void 
ldBuff( int chr )
{
    int    ndx;
    byte   cnt1, cnt2, cnt3, kcnt;
    ulong  var1, var2;

    if( chr >= 0x20 && chr <= 0x7f )
    {
        for( cnt1 =0; cnt1 < 7; cnt1++ )
        {                                       // LOOP 7 TIMES FOR 5X7 FONT
                                            // NDX INTO CHAR TBL GET ROW DAT
            var1 = Font5x7[((chr -0x20) *8 ) +cnt1];
            var2 = Buff[cnt1 *2];             // LOAD CURR SCROLL BUFFER
            var2 = var2 | var1;      // OR NEW CHARACTER ONTO END OF CURRENT
            Buff[cnt1 *2] = var2;                     // STORE IN BUFFER
        }
        kcnt = Font5x7[((chr -0x20 ) *8 ) +7];
        for( cnt3 =0; cnt3 < kcnt; cnt3++ )            // ACTUAL SCROLL CODE
        {
            rotBuff();
            pntBuff();
            delay( ScrlDly );
        }
    }
}
/*F********************************************************************
* Rotate buffer
**********************************************************************/
void 
rotBuff( )
{
    int    cnt;
    ulong  var; 
    byte   bit;

    for( cnt =0; cnt < 7; cnt++ )
    {                                         // LOOP 7 TIMES FOR A 5X7 FONT
        var = Buff[cnt *2];                      // GET LOW BUFFER ENTRY
        bit = bitRead( var, 31 );        // CPY HI BIT GETS LOST IN ROTATION
        var = var << 1;                               // ROTATE LEFT ONE BIT
        Buff[cnt *2] = var;                      // STORE NEW LOW BUFFER
        var = Buff[cnt *2 +1];                  // GET HIGH BUFFER ENTRY
        var = var << 1;                               // ROTATE LEFT ONE BIT
        bitWrite( var, 0, bit );                          // STORE SAVED BIT
        Buff[cnt *2 +1] = var;                  // STORE NEW HIGH BUFFER
    }
}  
/*F********************************************************************
* DISPLAY BUFFER ON LED MATRIX
**********************************************************************/
void 
pntBuff( )
{
    int    ndx;
    byte   byt;
    ulong  var;

    for( ndx =0; ndx < 7; ndx++ )
    {                                         // LOOP 7 TIMES FOR A 5X7 FONT
        var = Buff[ndx *2 +1];                      // GET HIGH BUFFER ENTRY
        byt = var;                               // MASK OFF FIRST CHARACTER
        Mtx.setRow( 3, ndx, byt );      // SEND ROW TO RELEVENT MAX7219 CHIP
        var = Buff[ndx *2];                          // GET LOW BUFFER ENTRY
        byt = ( var >> 24 );                    // MASK OFF SECOND CHARACTER
        Mtx.setRow( 2, ndx, byt );      // SEND ROW TO RELEVENT MAX7219 CHIP
        byt = ( var >> 16 );                     // MASK OFF THIRD CHARACTER
        Mtx.setRow( 1, ndx, byt );      // SEND ROW TO RELEVENT MAX7219 CHIP
        byt = ( var >> 8 );                      // MASK OFF FORTH CHARACTER
        Mtx.setRow( 0, ndx, byt );      // SEND ROW TO RELEVENT MAX7219 CHIP
    }
}
#ifdef BARF

bitWrite( x, n, b )
Parameters

    x: the numeric variable to write into
    n: bit of var to write, 0 == LSB (rightmost) bit.
    b: value to write to var bit (0 or 1).

byte X = 0b10000000;                            // BEFORE
    bitWrite( X, 0, 1 );        // WRITE '1' TO LSB OF VAR X
byte X = 0b10000001;                           // AFTER
    bitWrite( X, 0, 1 );

#endif
LED Matrix Scrolling ASCII Characters
/*H********************************************************************
* Matrix clock test
* Mtx-2 = DAT, Mtx-3 = CS, Mtx-4 = CLK
**********************************************************************/
#include <LedControl.h>

//************************* DEFINES ************************************
#define  MTX_DAT  2
#define  MTX_CLK  4
#define  MTX_CS   3
#define  HR10     3
#define  HR1      2
#define  MIN10    1
#define  MIN1     0
#define  BAUD   9600
typedef unsigned long ulong;

//************************* PROTOTYPES ************************************
void putChr( byte mtxNbr, byte *dat );
void colon( bool on );

//************************* VARIABLES ************************************
const int  NbrDevs = 4;                            // NUMBER OF MAX7219s USED
const long ScrlDly = 75;                           // ADJUST SCROLLING SPEED
byte  State =0, Tggl =0;
ulong  NewNbrs, ColonBlink;
//                         DAT, CLK CS, NbrDevs
LedControl Mtx = LedControl( MTX_DAT, MTX_CLK, MTX_CS, NbrDevs );
byte  Nbrs[11][8] = { 
    { 0x38,0x44,0x4C,0x54,0x64,0x44,0x38},  // '0'
    { 0x10,0x30,0x10,0x10,0x10,0x10,0x38},  // '1'
    { 0x38,0x44,0x04,0x08,0x10,0x20,0x7C},  // '2'
    { 0x7C,0x08,0x10,0x08,0x04,0x44,0x38},  // '3'
    { 0x08,0x18,0x28,0x48,0x7C,0x08,0x08},  // '4'
    { 0x78,0x40,0x78,0x04,0x04,0x44,0x38},  // '5'
    { 0x18,0x20,0x40,0x78,0x44,0x44,0x38},  // '6'
    { 0x7C,0x44,0x04,0x08,0x10,0x10,0x10},  // '7'
    { 0x38,0x44,0x44,0x38,0x44,0x44,0x38},  // '8'
    { 0x38,0x44,0x44,0x3C,0x04,0x08,0x30}   // '9'
    { 0x00,0x00,0x00,0x3000x00,0x00,0x300   // BLANK
};
byte Colon[8] = { 0x00,0xC0,0xC0,0x00,0xC0,0xC0,0x00 };

/*F********************************************************************
*
**********************************************************************/
void 
setup( )
{
    Serial.begin( BAUD );
    for( int x =0; x < NbrDevs; x++ )
    {
        Mtx.shutdown( x, false );// MAX72XX IS IN POWER-SAVING MODE ON STARTUP
        Mtx.setIntensity( x, 0 );          // SET BRIGHTNESS TO DEFAULT VALUE
        Mtx.clearDisplay( x );                           // AND CLEAR DISPLAY
    }
    NewNbrs = millis() + 1000;                    // SET MATTRIX UPDATE TIME
    ColonBlink = millis() +500;                      // SET COLON BLINK TIME
}
/*F********************************************************************
*
**********************************************************************/
void 
loop( )
{ 
    int    ndx;

    delay( 500 );
    if( millis() > NewNbrs )
    {
        for( ndx =0; ndx < 4; ndx++ )
            Mtx.clearDisplay( ndx );                    // AND CLEAR DISPLAY
        switch( State )
        {
            case 0:
                putChr( HR10,  Nbrs[1] );    // '1'
                putChr( HR1,   Nbrs[2] );    // '2'
                putChr( MIN10, Nbrs[3] );    // '3'
                putChr( MIN1,  Nbrs[4] );    // '4'
                State++;
                break;
            case 1:
                putChr( HR10,  Nbrs[5] );    // '5'
                putChr( HR1,   Nbrs[6] );    // '6'
                putChr( MIN10, Nbrs[7] );    // '7'
                putChr( MIN1,  Nbrs[8] );    // '8'
                State++;
                break;
            case 2:
                putChr( MIN10, Nbrs[9] );    // '9'
                putChr( MIN1,  Nbrs[0] );    // '0'
                State = 0;
                break;
        }
        NewNbrs = millis() + 1000;                // SET DISPLAY UPDATE TIME
    }
    if( (ColonBlink < millis()) && (Tggl ^= 1) )
    {
        colon( true );
        ColonBlink = millis() + 500;                 // SET COLON BLINK TIME
    }
    delay( 2000 );
}
/*F********************************************************************
* USE inbound byte as address, GET 7 bytes from mFont5x7[], ouput each 
to a row in one of 4 matrices.  
**********************************************************************/
void 
putChr( byte mtxNbr, byte dat[]  ) 
{
    byte  ndx, byt;

    for( ndx =0; ndx < 7; ndx++ )    // SCAN CHR'S 7 ROWS OF 7 BYTES Vs ROW#
    {
        byt = dat[ndx];                               // GET ASCII NUMERIC VALUE
        Mtx.setRow( mtxNbr, ndx, byt );
    }
}
/*F********************************************************************
* PUT COLON IN ROW 7 MTX 2
**********************************************************************/
void
colon( bool on )
{
    byte  col;
    
    if( on  )
        col = 0X6C;
    else
        col =0;
    Mtx.setColumn( 2, 7, col );
}