Marco Zonca
Published © GPL3+

Arduino Nano ESP32 LED matrix precision clock

Time updated automatically via WiFi NTP service, manual setup via BLE bluetooth, USB powered, easy circuit!

IntermediateFull instructions provided2,960
Arduino Nano ESP32 LED matrix precision clock

Things used in this project

Hardware components

Arduino Nano ESP32
×1
Maxim Integrated 8x32 LED Dot Matrix display MAX7219
×1
Voltage level converter (3.3v 5v)
×1

Software apps and online services

Arduino Web Editor
PCBWay online Services for PCB and 3D Printing (optional)

Story

Read more

Schematics

Fritzing image schematic diagram

PCB Gerber file

3D printing Box

3D printing Box (back door)

Arduino Nano ESP32 datasheet PDF

PCB TOP side

PCB BOTTOM side

PCB top silk

Code

Arduino code (sketch)

Arduino
/*
  "ard_clock" Arduino sketch by Marco Zonca 10/2023, version 1.00
  
  Digital clock with 4 dot matrix displays, Arduino Nano ESP32, TTL level shifter,
  GL5539 photoresistor for automatic brightness adj, WiFi internet connection for 
  NTP time updating, Arduino WebEditor, a few other components, USB C power, 
  DST daylight saving time correction for Central Europe, personalized font, BLE setup,
  3 buttons and 1 led for manual time setup in case of no WiFi internet connection;
  
  To set Wifi (Access Point Name and Password) and time zone (+2 or +1 hours vs. UTC)
  enter Setup pressing the setup button and connect to the clock via Bluetooth 
  (i.e. using nRF Connect app); send new datas to the clock one at a time in Text format:
  APN=thename<nl> PSW=password<nl> TZ=2<nl>; then disconnect Bluetooth connection,
  press again setup button to save in the EEPROM internal memory and exit; with null APN the NTP 
  by the way of WiFi will not be checked, so you need a manual time setup using HH and MM buttons;

    Used syncro-serial transmission, 3 digital pins (like SPI but slower speed);
    Inspired by Eberhard Fahle and his LedControl library + examples code
    for controlling matrix led display using MAX7219;

    Approx. power consumption with full 256 leds on: level 0=75mA, 2=245mA, 6=525mA, 10=725mA;
    brightness level is available from 0 to 15 but let keep it below 5 because
    of current (mA) consumption considering USB powering;  
*/

#define OP_DECODEMODE  9
#define OP_INTENSITY   10
#define OP_SCANLIMIT   11
#define OP_SHUTDOWN    12
#define OP_DISPLAYTEST 15

#include <WiFi.h>
#include <NTPClient.h>
#include <Time.h>
#include <EEPROM.h>
#include <ArduinoBLE.h>

const boolean isDebug = false;  // set to "true" to activate debug on serial monitor
                                // if "true" the serial monitor MUST be available or
                                // the sketch does not run;
const byte BrightMin=0;
const byte BrightMed=2;
const byte BrightHigh=5;
const char poolUrl[] = "it.pool.ntp.org";  // NTP url server
const byte lightSens_pin = 23; // A6 (physical chip pin nr. 10)
const byte DATA_Pin = 10; // D10 (physical chip pin nr. 28)
const byte CLK_Pin = 9; // D9 (physical chip pin nr. 27)
const byte CS_Pin = 8; // D8 (physical chip pin nr. 26)
const byte LEDSetup_pin = 2; // D2 (physical chip pin nr. 20)
const byte butMinutes_pin = 3; // D3 (physical chip pin nr. 21)
const byte butHours_pin = 4; // D4 (physical chip pin nr. 22)
const byte butSetup_pin = 5; // D5 (physical chip pin nr. 23)
const byte Devices = 4; // how many matrixes of displays
const byte BIT_order = MSBFIRST;  // LSBFIRST=0 MSBFIRST=1
const byte MAX_Devices = 8;  // MAX Nr. of matrixes of display
const byte maxattempts = 10;  // nr. of WiFi connection attempts
const unsigned long updateRate = 60 * (60 * 1000); // 60 minutes NTP update rate
const unsigned long blinkDotsRate = 1 * (1000); // 1 second clock dots blink rate

unsigned long prevMillis = 0;
unsigned long prevBlinkDots = 0;
byte Brightness = 10;
byte prevBrightness = 0;
boolean isUpdated = false;
boolean isDotsOn = false;
boolean isClockSetup = false;
byte T_prev_hours = 99;
byte T_prev_minutes = 99;
time_t epoch = 0;
byte status[64];  // =Max_Devices*8
byte spidata[16];  // =Max_Devices*2
int i=0;
String myStrValue = "";
String AValue = "";

int eeaddress=0;
int eedata_TimeZone=0;
char eedata_Wifi_AccessPoint[40]="";
char eedata_Wifi_Password[40]="";

// following data change reading the EEPROM
char ssid[40] = "";  // was to put your SSID WiFi access point here
char pass[40] = "";  // was put your PASSWORD WiFi access point here
long utcOffset = +2 * (60 * 60);  // +- UTC offset +2 hours (see also Daylight saving)

// set numbers for display
byte matrix_09[10][7][6] =
      {
        {
          {0,1,1,1,1,0},  // 0
          {1,0,0,0,0,1},
          {1,0,0,0,0,1},
          {1,0,0,0,0,1},
          {1,0,0,0,0,1},
          {1,0,0,0,0,1},
          {0,1,1,1,1,0}
        },
        {
          {0,0,0,0,1,0},  // 1
          {0,0,0,1,1,0},
          {0,0,1,0,1,0},
          {0,1,0,0,1,0},
          {0,0,0,0,1,0},
          {0,0,0,0,1,0},
          {0,0,1,1,1,1}
        },
        {
          {0,1,1,1,1,0},  // 2
          {0,0,0,0,0,1},
          {0,0,0,0,0,1},
          {0,1,1,1,1,0},
          {1,0,0,0,0,0},
          {1,0,0,0,0,0},
          {1,1,1,1,1,1}
        },
        {
          {1,1,1,1,1,0},  // 3
          {0,0,0,0,0,1},
          {0,0,0,0,0,1},
          {0,1,1,1,1,1},
          {0,0,0,0,0,1},
          {0,0,0,0,0,1},
          {1,1,1,1,1,0}
        },
        {
          {1,0,0,0,0,1},  // 4
          {1,0,0,0,0,1},
          {1,0,0,0,0,1},
          {1,1,1,1,1,1},
          {0,0,0,0,0,1},
          {0,0,0,0,0,1},
          {0,0,0,0,0,1}
        },
        {
          {1,1,1,1,1,1},  // 5
          {1,0,0,0,0,0},
          {1,0,0,0,0,0},
          {0,1,1,1,1,0},
          {0,0,0,0,0,1},
          {1,0,0,0,0,1},
          {0,1,1,1,1,0}
        },
        {
          {0,0,1,1,1,0},  // 6
          {0,1,0,0,0,0},
          {1,0,0,0,0,0},
          {1,1,1,1,1,0},
          {1,0,0,0,0,1},
          {1,0,0,0,0,1},
          {0,1,1,1,1,0}
        },
        {
          {1,1,1,1,1,1},  // 7
          {0,0,0,0,0,1},
          {0,0,0,0,1,0},
          {0,0,0,1,0,0},
          {0,0,1,0,0,0},
          {0,1,0,0,0,0},
          {1,0,0,0,0,0}
        },
        {
          {0,1,1,1,1,0},  // 8
          {1,0,0,0,0,1},
          {1,0,0,0,0,1},
          {0,1,1,1,1,0},
          {1,0,0,0,0,1},
          {1,0,0,0,0,1},
          {0,1,1,1,1,0}
        },
        {
          {0,1,1,1,1,0},  // 9
          {1,0,0,0,0,1},
          {1,0,0,0,0,1},
          {0,1,1,1,1,1},
          {0,0,0,0,0,1},
          {0,0,0,0,1,0},
          {0,1,1,1,0,0}
        }
      };

WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, poolUrl, utcOffset);

BLEService myStrService("19b10000-e8f2-537e-4f6c-d104768a1214");
BLEStringCharacteristic myStrCharacteristic("19b10000-e8f2-537e-4f6c-d104768a1214", BLERead | BLEWrite, 40);

void setup()
{
  if (isDebug) {
    Serial.begin(9600);
    while (!Serial) {}
  }
  if (!EEPROM.begin(512)) {
    if (isDebug) {Serial.println("failed to initialize EEPROM");}
  }
  if (!BLE.begin()) {
    if (isDebug) {Serial.println("failed to initialize BLE");}
  }
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(lightSens_pin, INPUT);
  digitalWrite(LED_BUILTIN, LOW);
  pinMode(butMinutes_pin, INPUT_PULLUP);
  pinMode(butHours_pin, INPUT_PULLUP);
  pinMode(butSetup_pin, INPUT_PULLUP);
  pinMode(LEDSetup_pin, OUTPUT);
  digitalWrite(LEDSetup_pin, LOW);
  
  //-------------------------- display init
  Brightness=readLightSensor();
  prevBrightness=Brightness;
  pinMode(DATA_Pin, OUTPUT);
  pinMode(CLK_Pin, OUTPUT);
  pinMode(CS_Pin, OUTPUT);
  digitalWrite(CS_Pin,HIGH);
  for(i=0;i<(MAX_Devices*8);i++)
  {
    status[i]=0x00;
  }
  for(i=0;i<Devices;i++)
  {
      spiTransfer(i,OP_DISPLAYTEST,0);
      spiTransfer(i, OP_SCANLIMIT,7);
      spiTransfer(i,OP_DECODEMODE,0);
      clearDisplay(i);
      spiShutdown(i,false);
      setIntensity(i,Brightness);
  }
  //-------------------------- BLE init
  myStrValue.reserve(40);
  AValue.reserve(40);
  BLE.setLocalName("Clock setup: TZ= APN= PSW=");
  BLE.setAdvertisedService(myStrService);
  myStrService.addCharacteristic(myStrCharacteristic);
  BLE.addService(myStrService);
  BLE.advertise();
  if (isDebug) {Serial.println("BLE ready");}
  //-------------------------- other init
  setTime(967680000);  // initial datetime: 31/08/2000 00:00:00 in epoch format
  readEEPROM();
  displayNumbers();
  if (strcmp(ssid,"") != 0) 
  {
    updateTime();
   } else {
    if (isDebug) {Serial.println("Empty SSID, no WiFi");}
  }
}//setup()

void loop()
{
  readButtons();
  if (isClockSetup == false)
  {
    //------------------------------update display numbers
    if (second(now()) == 0)
    {
      displayNumbers();
    }
    //------------------------------update NTP time
    if (prevMillis > millis()) { prevMillis=millis(); }  // manage millis() rollover
    if ((((prevMillis + updateRate) <= millis()) && (second(now()) > 30) && (second(now()) < 40))
        || ((isUpdated==false) && (second(now()) > 30) && (second(now()) < 40)))  // update NTP time
    {
      if (strcmp(ssid,"") != 0) 
      {
        updateTime();
       } else {
        if (isDebug) {Serial.println("Empty SSID, no WiFi");}
      }
    }
    //------------------------------update brightness and blinking dots
    if (prevBlinkDots > millis()) { prevBlinkDots=millis(); }  // manage millis() rollover
    if ((prevBlinkDots + blinkDotsRate) <= millis())
    {
      Brightness=readLightSensor();
      if (prevBrightness != Brightness) 
      {
        for (int d=0;d<Devices;d++)
        {
          setIntensity(d,Brightness);
        }
        if (isDebug) {Serial.print("Brightness ");}
        if (isDebug) {Serial.println(Brightness);}
        prevBrightness=Brightness;
      }
      blinkDots();
    }
  }//if (isClockSetup == false)
  if (isClockSetup == true)
  {
    BLEDevice central = BLE.central();  // Listen for BLE connect
    if (central)
    {
      if (isDebug) {Serial.print("BLE Connected to: ");}
      if (isDebug) {Serial.println(central.address());}  // MAC address
      while (central.connected())  // While is still connected
      {
        if (myStrCharacteristic.written())  // If the remote device wrote to the characteristic
        {
          myStrValue=String(myStrCharacteristic.value());
          if (myStrValue.substring(0,3)=="TZ=")
          {
            AValue=myStrValue.substring(3);
            eedata_TimeZone=AValue.toInt();
          }
          if (myStrValue.substring(0,4)=="PSW=") 
          {
            AValue=myStrValue.substring(4);
            AValue.toCharArray(eedata_Wifi_Password, AValue.length()+1);
          }
          if (myStrValue.substring(0,4)=="APN=")
          {
            AValue=myStrValue.substring(4);
            AValue.toCharArray(eedata_Wifi_AccessPoint, AValue.length()+1);
          }
          if (isDebug)
          {
            Serial.print("BLE Received: ");
            Serial.print(myStrValue);
            Serial.print(" len=");
            Serial.println(myStrValue.length());
          }
          if (isDebug)
          {
            Serial.print(" TZ=");
            Serial.println(eedata_TimeZone);
            Serial.print(" APN=");
            Serial.print(eedata_Wifi_AccessPoint);
            Serial.print(" len=");
            Serial.println(strlen(eedata_Wifi_AccessPoint));
            Serial.print(" PSW=");
            Serial.print(eedata_Wifi_Password);
            Serial.print(" len=");
            Serial.println(strlen(eedata_Wifi_Password));
            Serial.println("");
          }
        }
      }
      // When the central disconnects
      if (isDebug) {Serial.print("BLE Disconnected: ");}
      if (isDebug) {Serial.println(central.address());}
    }
  }//if (isClockSetup == true)
}//loop()

void readButtons()
{
  if (isClockSetup == true)
  {
    isUpdated=false;
    blinkDots();
    if (digitalRead(butMinutes_pin) == LOW)
    {
      delay(250);
      time_t NowTime=now();
      NowTime = NowTime + 60;
      setTime(NowTime);  // set MPU time +1 minute
      displayNumbers();
    }
    if (digitalRead(butHours_pin) == LOW)
    {
      delay(250);
      time_t NowTime=now();
      NowTime = NowTime + (60 * 60);
      setTime(NowTime);  // set MPU time +1 hour
      displayNumbers();
    }
    if (digitalRead(butSetup_pin) == LOW)
    {
      digitalWrite(LEDSetup_pin, LOW);
      // UPDATES after SETUP here...
      updateEEPROM();
      isClockSetup=false;
    }
   }else{
    if (digitalRead(butSetup_pin) == LOW)
    {
      delay(1000);
      if (digitalRead(butSetup_pin) == LOW)
      {
        digitalWrite(LEDSetup_pin, HIGH);
        delay(1000);
        isClockSetup=true;
      }
    }
  }
}//readButtons()

void updateEEPROM()
{
  bool isDataChanged=false;
  if (utcOffset != (eedata_TimeZone * (60 * 60)))
  {
    eeaddress=101;
    EEPROM.put(eeaddress,eedata_TimeZone);
    delay(10);
    utcOffset = (eedata_TimeZone * (60 * 60));
    timeClient.setTimeOffset(utcOffset);
    isDataChanged=true;
  }
  if (strcmp(ssid,eedata_Wifi_AccessPoint) != 0)
  {
    eeaddress=201;
    EEPROM.put(eeaddress,eedata_Wifi_AccessPoint);
    delay(10);
    strcpy(ssid,eedata_Wifi_AccessPoint);
    isDataChanged=true;
  }
  if (strcmp(pass,eedata_Wifi_Password) != 0)
  {
    eeaddress=301;
    EEPROM.put(eeaddress,eedata_Wifi_Password);
    delay(10);
    strcpy(pass,eedata_Wifi_Password);
    isDataChanged=true;
  }
  if (isDataChanged==true) {EEPROM.commit();}
  if (isDebug && isDataChanged==true) {Serial.println("EEPROM updated");}
}

void readEEPROM()
{
  eeaddress=101;
  EEPROM.get(eeaddress,eedata_TimeZone);
  eeaddress=201;
  EEPROM.get(eeaddress,eedata_Wifi_AccessPoint);
  eeaddress=301;
  EEPROM.get(eeaddress,eedata_Wifi_Password);
  if (isDebug)
  {
    Serial.print(" TZ=");
    Serial.println(eedata_TimeZone);
    Serial.print(" APN=");
    Serial.print(eedata_Wifi_AccessPoint);
    Serial.print(" len=");
    Serial.println(strlen(eedata_Wifi_AccessPoint));
    Serial.print(" PSW=");
    Serial.print(eedata_Wifi_Password);
    Serial.print(" len=");
    Serial.println(strlen(eedata_Wifi_Password));
    Serial.println("");
  }
  
  if (utcOffset != (eedata_TimeZone * (60 * 60)))
  {
    utcOffset = (eedata_TimeZone * (60 * 60));
    timeClient.setTimeOffset(utcOffset);
  }
  strcpy(ssid,eedata_Wifi_AccessPoint);
  strcpy(pass,eedata_Wifi_Password);
}//readEEPROM()

byte readLightSensor()
{
  byte bright=0;
  int ls=analogRead(lightSens_pin);
  int n=map(ls,0,4095,0,255);
  if ((n >= 0  ) && (n <= 100)) { bright=BrightMin; }
  if ((n >= 101) && (n <= 220)) { bright=BrightMed; }
  if ((n >= 221) && (n <= 255)) { bright=BrightHigh; }  // max brightness is 15
  return bright;
}  //readLightSensor()

void blinkDots()
{
  if (isUpdated==true)  // dots blinking active
  {
    switch (isDotsOn)
    {
      case true:
        setColumn(2,7,B00000000);  // set off dots at right of display 2 
        setColumn(1,0,B00000000);  // set off dots at left of display 1 
        //if (isDebug) {Serial.println("_");}
        isDotsOn=false;
      break;
      case false:
        setColumn(2,7,B01101100);  // set ON dots at right of display 2 
        setColumn(1,0,B01101100);  // set ON dots at left of display 1 
        //if (isDebug) {Serial.println(".");}
        isDotsOn=true;
      break;
    }
  }
  else  // dots steady, not blinking
  {
    setColumn(2,7,B01101100);  // set ON dots at right of display 2 
    setColumn(1,0,B01101100);  // set ON dots at left of display 1 
    //if (isDebug) {Serial.println(".");}
    isDotsOn=true;
  }
  prevBlinkDots=millis();
}//blinkDots()

void updateTime()
{
  isUpdated=false;
  blinkDots();
  byte attempts = 0;
  while ((WiFi.status() != WL_CONNECTED) && (attempts < maxattempts) )
  {
    if (isDebug) {
      Serial.print("Attempting to connect to '");
      Serial.print(ssid);
      Serial.println("'");
    }
    WiFi.begin(ssid, pass);
    delay(4000);
    if (isDebug) {
      if (WiFi.status() == WL_NO_SHIELD) {Serial.println("* no shield available *");}
      if (WiFi.status() == WL_IDLE_STATUS) {Serial.println("* idle *");}
      if (WiFi.status() == WL_CONNECT_FAILED) {Serial.println("* failed *");}
      if (WiFi.status() == WL_NO_SSID_AVAIL) {Serial.println("* no SSID available *");}
      if (WiFi.status() == WL_CONNECTION_LOST) {Serial.println("* connection lost *");}
      if (WiFi.status() == WL_CONNECTED) {Serial.println("* connected *");}
      if (WiFi.status() == WL_DISCONNECTED) {Serial.println("* disconnected *");}
    }
    attempts++;
  }
  if (attempts < maxattempts)
  {
    if (isDebug)
    {
      Serial.print("Connected to '");
      Serial.print(WiFi.SSID());
      Serial.println("'");
    }
    digitalWrite(LED_BUILTIN, HIGH);
    timeClient.update();
    delay(4000);
    if (timeClient.isTimeSet() == true)
    {
      isUpdated=true;
      epoch = timeClient.getEpochTime();
      if (isDebug) {
        Serial.print("Formatted time is ");
        Serial.println(timeClient.getFormattedTime());
      }
      setTime(epoch);  // set MPU time
    }
    else
    {
      if (isDebug) {
        Serial.print("* no time *");
      }
    }
    while (WiFi.status() != WL_DISCONNECTED)
    {
      WiFi.disconnect();
      delay(4000);
      if (isDebug) {
        if (WiFi.status() == WL_NO_SHIELD) {Serial.println("* no shield available *");}
        if (WiFi.status() == WL_IDLE_STATUS) {Serial.println("* idle *");}
        if (WiFi.status() == WL_CONNECT_FAILED) {Serial.println("* failed *");}
        if (WiFi.status() == WL_NO_SSID_AVAIL) {Serial.println("* no SSID available *");}
        if (WiFi.status() == WL_CONNECTION_LOST) {Serial.println("* connection lost *");}
        if (WiFi.status() == WL_CONNECTED) {Serial.println("* connected *");}
        if (WiFi.status() == WL_DISCONNECTED) {Serial.println("* disconnected *");}
      }
    }
    if (isDebug) {
      Serial.println("Disconnected.");
      Serial.print("\n");
    }
    digitalWrite(LED_BUILTIN, LOW);
  }
  else
  {
    if (isDebug) {
      Serial.print("Connection failed after ");
      Serial.print(attempts);
      Serial.println(" attempts.");
      Serial.print("\n");
    }
  }
  prevMillis=millis();
}//updateTime()

void displayNumbers() 
{
  time_t NowTime=now();
  byte T_Hours=checkDaylightSaving(NowTime);  // DST hour correction
  byte T_Minutes=minute(NowTime);
  if ((T_prev_hours != T_Hours) || (T_prev_minutes != T_Minutes)) {
    byte col=0;
    byte row=0;
    byte disp=0;
    byte rowval=0;
    int hdeci=(int)(T_Hours/10);
    int hunit=T_Hours-(hdeci*10);
    int mdeci=(int)(T_Minutes/10);
    int munit=T_Minutes-(mdeci*10);
    int prev_hdeci=(int)(T_prev_hours/10);
    int prev_hunit=T_prev_hours-(prev_hdeci*10);
    int prev_mdeci=(int)(T_prev_minutes/10);
    int prev_munit=T_prev_minutes-(prev_mdeci*10);
    
    if (hdeci != prev_hdeci) // change 1st number
    {
      disp=3;
      for (row=0;row<=6;row++) {  // row 7 always off
        rowval=0;
        for (col=0;col<=5;col++) {
          setLed(disp,row,col+1,matrix_09[hdeci][row][col]);
        }
      }
    }
    if (hunit != prev_hunit) // change 2nd number
    {
      disp=2;
      for (row=0;row<=6;row++) {  // row 7 always off
        rowval=0;
        for (col=0;col<=5;col++) {
          setLed(disp,row,col,matrix_09[hunit][row][col]);
        }
      }
    }
    if (mdeci != prev_mdeci) // change 3th number
    {
      disp=1;
      for (row=0;row<=6;row++) {  // row 7 always off
        rowval=0;
        for (col=0;col<=5;col++) {
          setLed(disp,row,col+2,matrix_09[mdeci][row][col]);
        }
      }
    }
    if (munit != prev_munit) // change 4th number
    {
      disp=0;
      for (row=0;row<=6;row++) {  // row 7 always off
        rowval=0;
        for (col=0;col<=5;col++) {
          setLed(disp,row,col+1,matrix_09[munit][row][col]);
        }
      }
    }
    if (isDebug) {
      Serial.print("Clock is ");
      Serial.print(hdeci);
      Serial.print(hunit);
      Serial.print(":");
      Serial.print(mdeci);
      Serial.println(munit);
    }
    T_prev_hours=T_Hours;
    T_prev_minutes=T_Minutes;
  }
}//displayNumbers()

byte checkDaylightSaving(time_t unixTimeNow)  // adjust actual hour with DST
{                                             // Daylight Saving Time (Central Europe Summer Time)
  tmElements_t te;  //Time elements structure
  time_t unixTime03;
  time_t unixTime10;

  int d=0;
  int x=0;
  int c=0;
  byte correctedHour=0;
  
  // convert date and time into unix Summer (UTC+1) start Time, offset 1970
  // last Sunday of March at 03:00
  te.Hour = 3; 
  te.Minute = 0;
  te.Second = 0;
  te.Month = 3;  //March
  te.Year = (year(now()) - 1970);
  for (x=25;x<=31;x++) 
  {
    te.Day = x;
    unixTime03 = makeTime(te);
    d=(weekday(unixTime03) - 1);  // converts day 1 of the week from sunday to monday
    if (d==0) { d=7; }
    if (d==7) { break; }  // find the last sunday of March
  }

  // convert date and time into unix Standard (UTC+2) start time, offset 1970
  // last Sunday of October at 03:00
  te.Hour = 3; 
  te.Minute = 0;
  te.Second = 0;
  te.Month = 10;  //October
  te.Year = (year(now()) - 1970);
  for (x=25;x<=31;x++) 
  {
    te.Day = x;
    unixTime10 = makeTime(te);
    d=(weekday(unixTime10) - 1);  // converts day 1 of the week from sunday to monday
    if (d==0) { d=7; }
    if (d==7) { break; }  // find the last sunday of October
  }

  // compare the two dates with now()
  if ((unixTimeNow < unixTime03) || (unixTimeNow >= unixTime10))
  {
    c=(hour(unixTimeNow)-1);
    if (c == -1) {c = 23;}
  } else {
    c=(hour(unixTimeNow));
  }
  correctedHour=c;
  return correctedHour;
}//checkDaylightSaving()

void setColumn(int addr, int col, byte value)
{
  byte val;
  for (int row=0;row<8;row++)
  {
    val=value >> (7-row);
    val=val & 0x01;
    setLed(addr,row,col,val);
  }
}//setColumn()

void setRow(int addr, int row, byte value)
{
  int offset;
  offset=addr*8;
  status[offset+row]=value;
  spiTransfer(addr, row+1,status[offset+row]);
}//setRow()

void setLed(int addr, int row, int column, boolean state)
{
  int offset;
  byte val=0x00;
  offset=addr*8;
  val=B10000000 >> column;
  if (state)
  {
    status[offset+row]=status[offset+row]|val;
   }else{
    val=~val;
    status[offset+row]=status[offset+row]&val;
  }
  spiTransfer(addr, row+1,status[offset+row]);
}//setLed()

void setIntensity(int addr, int intensity)
{
  if (intensity>=0 && intensity<16)
  {
    spiTransfer(addr, OP_INTENSITY, intensity);
  }else{
    spiTransfer(addr, OP_INTENSITY, 0);
  }
}//setIntensity()

void spiShutdown(int addr, bool shut)
{
  if (shut)
  {
    spiTransfer(addr, OP_SHUTDOWN, 0);
  }else{
    spiTransfer(addr, OP_SHUTDOWN ,1);
  }
}//spiShutdown()

void clearDisplay(int addr)
{
    int offset;
    offset=addr*8;
    for (int i=0;i<8;i++)
    {
      status[offset+i]=0;
      spiTransfer(addr, i+1,status[offset+i]);
    }
}//clearDisplay()

void spiTransfer(int addr, volatile byte opcode, volatile byte data) {
    //Create an array with the data to shift out
    int offset=addr*2;
    int maxbytes=MAX_Devices*2;

    for (int i=0;i<maxbytes;i++)
    {
      spidata[i]=(byte)0;
    }
    //put our device data into the array
    spidata[offset+1]=opcode;
    spidata[offset]=data;
    //enable the line 
    digitalWrite(CS_Pin,LOW);
    //Now shift out the data 
    for(int i=maxbytes;i>0;i--)
        serialSyncroTX(DATA_Pin,CLK_Pin,BIT_order,spidata[i-1]);
    //latch the data onto the display
    digitalWrite(CS_Pin,HIGH);
}//spiTransfer()

void serialSyncroTX(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val) 
{
  uint8_t i=0;
  for (i = 0; i < 8; i++)  {
    if (bitOrder == LSBFIRST) {
      digitalWrite(dataPin, !!(val & (1 << i)));
     }else{ 
      digitalWrite(dataPin, !!(val & (1 << (7 - i))));
    }
    digitalWrite(clockPin, HIGH);
    digitalWrite(clockPin, LOW);    
  }
}//serialSyncroTX()

Credits

Marco Zonca

Marco Zonca

12 projects • 42 followers
"From an early age I learned to not use pointers"

Comments