Welcome to Hackster!
Hackster is a community dedicated to learning hardware, from beginner to pro. Join us, it's free!
anthias64
Published

WiFi NodeMCU ESP8266 Google Clock

WiFi NodeMCU ESP8266 Google Clock With Temp, Umidity and Dimmer - Case Included

IntermediateFull instructions provided1 hour508
WiFi NodeMCU ESP8266 Google Clock

Things used in this project

Hardware components

NodeMCU ESP8266 Breakout Board
NodeMCU ESP8266 Breakout Board
×1
MAXREFDES99# MAX7219 Display Driver Shield
Maxim Integrated MAXREFDES99# MAX7219 Display Driver Shield
×6
Photo resistor
Photo resistor
×1
Resistor 10k ohm
Resistor 10k ohm
×2

Story

Read more

Custom parts and enclosures

Clock enclosure

Sketchfab still processing.

Schematics

Clock schematics

Clock schematics 2

Code

Google Clock Code V.12

Arduino
// V.3 - Date converted to a number and daylight saving time calculation
// V.4 - Localized date
// V.6 - Temperature and humidity
// V.7 - Corrected animated clock + seconds +1.5
// V.8 - Calibration of thermometer and hygrometer
// V.9 - Corrected daylight saving time
// V.10 - Corrected date change at 00:00 -> May 4, 2020
// V.11 - Corrected daylight saving time for last Sundays
// V.12 - Code optimized and commented

#include "Arduino.h"
#include <ArduinoJson.h>
#include <ESP8266WiFi.h> // ESP8266 Core WiFi Library

WiFiClient client;

#define NUM_MAX 6

// for NodeMCU 1.0
#define DIN_PIN 13  // D7
#define CS_PIN  15  // D8
#define CLK_PIN 14  // D5

#include "max7219.h"
#include "fonts.h"

#include "DHT.h" // DHT sensor

// DHT sensor
#define DHTPIN 12  // GPIO 12 = D6
#define DHTTYPE DHT22   // DHT 22  (AM2302)

DHT dht(DHTPIN, DHTTYPE, 11); // for ESP8266

// DHT data
float temperature = 0;
int temp = 0;
byte minus = 0;
int humidity = 0;
int poz, poz2;
int mult = 0;

float temp_offset = -1.04; // Thermometer calibration
float rh_offset = +1;      // Hygrometer calibration

char TempLabel[] = "    Temperatura:  "; // Fixed text
char UmiLabel[] = "    Umidita':  ";    // Fixed text

// Test IP modification
const char ssid[] = "XXXXXXXX";  // Your network SSID
const char password[] = "XXXXXXXX"; // Your network password

// Localized months and days of the week
//String M_arr[13] = {" ", "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"};
//String Dow_arr[8] = {" ", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"};

String M_arr[13] = {" ", "Gennaio", "Febbraio", "Marzo", "Aprile", "Maggio", "Giugno", "Luglio", "Agosto", "Settembre", "Ottobre", "Novembre", "Dicembre"};
String Dow_arr[8] = {" ", "Lunedi", "Martedi", "Mercoledi", "Giovedi", "Venerdi", "Sabato", "Domenica"};

void setup() 
{
  Serial.begin(115200);

  initMAX7219();
  sendCmdAll(CMD_SHUTDOWN, 1);
  sendCmdAll(CMD_INTENSITY, 1); // Brightness from 1 to 5

  Serial.print("Connecting to ");
  Serial.println(ssid);
  
  WiFi.begin(ssid, password);

  printStringWithShift("Connecting", 30);
  delay(1000);
  
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.print("IP number assigned by DHCP is ");
  Serial.println(WiFi.localIP());

  printStringWithShift((String("  IP:") + WiFi.localIP().toString()).c_str(), 30);
  delay(1000);

  // DHT initialization
  dht.begin();
  temperature = dht.readTemperature();
  humidity = dht.readHumidity();

  Serial.print(temperature);
  Serial.println(" C");

  Serial.print(humidity);
  Serial.println(" %RH");

  if (temperature < 0) {
    temp = -10 * temperature;
    minus = 1;
  } else {
    minus = 0;
    temp = 10 * temperature;
  }
}

// =============================DEFINE VARS==============================
#define MAX_DIGITS 20
byte dig[MAX_DIGITS] = {0};
byte digold[MAX_DIGITS] = {0};
byte digtrans[MAX_DIGITS] = {0};
int updCnt = 0;
int dots = 0;
long dotTime = 0;
long clkTime = 0;
int dx = 0;
int dy = 0;
byte del = 0;
int h, m, s;
float utcOffset = +1; // Your timezone
long localEpoc = 0;
long localMillisAtUpdate = 0;
int day, month, year, dayOfWeek;
int monthnum = 0;
int downum = 0;
int summerTime = 0;
String date; 
String dayloc; 
String monthloc; 

// =======================================================================

void loop()
{
  if (updCnt <= 0) { // Every 10 scrolls, ~450s = 7.5m
    updCnt = 60;
    Serial.println("Getting data ...");
    printStringWithShift("   Get Time...", 30);
    getTime();
    Serial.println("Data loaded");
    clkTime = millis();
  }

  contrast(); // Auto-brightness

  // Print data
  if (millis() - clkTime > 30000 && !del && dots) { // Clock for 30s, then scrolls for about 30s
    printStringWithShift("            ", 30);  // Space before
    printStringWithShift(date.c_str(), 30);    // Date

    // Reading temperature and humidity 
    int humidity = dht.readHumidity();
    float temperature = dht.readTemperature(); 
    
    humidity = humidity + rh_offset;
    temperature = temperature + temp_offset;
    
    Serial.println("Corrected Temp and Humidity");
    Serial.println(temperature);
    Serial.println(humidity);
    
    int t2 = 10 * temperature; 

    // Print temperature
    char c[3], d[2]; 
    String str1, str2;
    int t2z = t2 / 10;
    int t2u = t2 - t2z * 10;
    str1 = String(t2z);
    str1.toCharArray(c, 3);
    str2 = String(t2u);
    str2.toCharArray(d, 2);
    printStringWithShift(TempLabel, 30);  // Send scrolling text
    printStringWithShift("+", 30);
    printStringWithShift(c, 30);
    printStringWithShift(",", 30);
    printStringWithShift(d, 30);
    printStringWithShift(" C^", 30);

    // Print humidity
    char b[3];
    String str;
    str = String(humidity);
    str.toCharArray(b, 3);
    printStringWithShift(UmiLabel, 30);  // Send scrolling text
    printStringWithShift(b, 30);
    printStringWithShift(" %", 30);
    
    printStringWithShift("                 ", 30);  // Space after
    delay(200);

    updCnt--;
    clkTime = millis();
  }
  
  if (millis() - dotTime > 500) {
    dotTime = millis();
    dots = !dots;
  }
  updateTime(); // Get time

  // Print clock
  showAnimClock();
}

// =======================================================================

void showSimpleClock()
{
  dx = dy = 0;
  clr();
  showDigit(h / 10,  0, dig6x8);
  showDigit(h % 10,  8, dig6x8);
  showDigit(m / 10, 17, dig6x8);
  showDigit(m % 10, 25, dig6x8);
  showDigit(s / 10, 34, dig6x8);
  showDigit(s % 10, 42, dig6x8);
  setCol(15, dots ? B00100100 : 0);
  setCol(32, dots ? B00100100 : 0);
  refreshAll();
}

// =======================================================================

void showAnimClock()
{
  byte digPos[6] = {0, 8, 17, 25, 34, 42};
  int digHt = 12;
  int num = 6; 
  int i;
  
  if (del == 0) {
    del = digHt;
    for (i = 0; i < num; i++) digold[i] = dig[i];
    dig[0] = h / 10 ? h / 10 : 10;
    dig[1] = h % 10;
    dig[2] = m / 10;
    dig[3] = m % 10;
    dig[4] = s / 10;
    dig[5] = s % 10;
    for (i = 0; i < num; i++) digtrans[i] = (dig[i] == digold[i]) ? 0 : digHt;
  } else {
    del--;
  }
  
  clr();
  for (i = 0; i < num; i++) {
    if (digtrans[i] == 0) {
      dy = 0;
      showDigit(dig[i], digPos[i], dig6x8);
    } else {
      dy = digHt - digtrans[i];
      showDigit(digold[i], digPos[i], dig6x8);
      dy = -digtrans[i];
      showDigit(dig[i], digPos[i], dig6x8);
      digtrans[i]--;
    }
  }
  dy = 0;
  setCol(15, dots ? B00100100 : 0);
  setCol(32, dots ? B00100100 : 0);
  refreshAll();
  delay(10); // Default 30
}

// =======================================================================

void showDigit(char ch, int col, const uint8_t *data)
{
  if (dy < -8 || dy > 8) return;
  int len = pgm_read_byte(data);
  int w = pgm_read_byte(data + 1 + ch * len);
  col += dx;
  for (int i = 0; i < w; i++)
    if (col + i >= 0 && col + i < 8 * NUM_MAX) {
      byte v = pgm_read_byte(data + 1 + ch * len + 1 + i);
      if (!dy) scr[col + i] = v; else scr[col + i] |= dy > 0 ? v >> dy : v << -dy;
    }
}

// =======================================================================

void setCol(int col, byte v)
{
  if (dy < -8 || dy > 8) return;
  col += dx;
  if (col >= 0 && col < 8 * NUM_MAX)
    if (!dy) scr[col] = v; else scr[col] |= dy > 0 ? v >> dy : v << -dy;
}

// =======================================================================

int showChar(char ch, const uint8_t *data)
{
  int len = pgm_read_byte(data);
  int w = pgm_read_byte(data + 1 + ch * len);
  for (int i = 0; i < w; i++)
    scr[NUM_MAX * 8 + i] = pgm_read_byte(data + 1 + ch * len + 1 + i);
  scr[NUM_MAX * 8 + w] = 0;
  return w;
}

// =======================================================================

// Function to print characters with shift
void printCharWithShift(unsigned char c, int shiftDelay) {
  if (c < ' ' || c > '~'+25) return;
  c -= 32;
  int w = showChar(c, font);
  for (int i = 0; i < w + 1; i++) {
    delay(shiftDelay);
    scrollLeft();
    refreshAll();
  }
}

// =======================================================================

void printStringWithShift(const char* s, int shiftDelay) {
  while (*s) {
    printCharWithShift(*s, shiftDelay);
    s++;
  }
}

// =======================================================================

void getTime()
{
  WiFiClient client;
  if (!client.connect("www.google.com", 80)) {
    Serial.println("Connection to Google failed");
    return;
  }

  client.print(String("GET / HTTP/1.1\r\n") +
               String("Host: www.google.com\r\n") +
               String("Connection: close\r\n\r\n"));
  int repeatCounter = 0;
  while (!client.available() && repeatCounter < 10) {
    delay(500);
    repeatCounter++;
  }

  String line;
  client.setNoDelay(false);
  while (client.connected() && client.available()) {
    line = client.readStringUntil('\n');
    line.toUpperCase();
    if (line.startsWith("DATE: ")) {
      date = line.substring(6, 22);
      date.toUpperCase();

      Serial.println(date); // Check

      int day = atoi(date.substring(5, 7).c_str()); // Day number
      int year = 2000 + atoi(date.substring(13, 16).c_str()); // Year number

      monthnum = month2index(date.substring(8, 11)); // Convert month to number
      month = monthnum;

      downum = dow2index(date.substring(0, 3)); // Convert day of week to number
      dayOfWeek = downum;

      Serial.println(day); // Check
      Serial.println(month); // Check
      Serial.println(year); // Check
      Serial.println(dayOfWeek); // Check

      monthloc = M_arr[month]; // Localize month
      dayloc = Dow_arr[dayOfWeek]; // Localize day of week

      date = dayloc + " " + day + " " + monthloc + " " + year;
      Serial.println(date); // Check

      h = line.substring(23, 25).toInt();
      m = line.substring(26, 28).toInt();
      s = line.substring(29, 31).toInt() + 1.5; // Correct time

      // Calculate daylight saving time (DST)
      if (month > 3 && month < 10) {
        summerTime = 1; // Between April and September is always DST
      } else if (month == 3) {
        if (day >= 31 - (((5 * year / 4) + 4) % 7)) {
          summerTime = 1; // DST starts on the last Sunday of March
        }
      } else if (month == 10) {
        if (day < 31 - (((5 * year / 4) + 1) % 7)) {
          summerTime = 0; // DST ends on the last Sunday of October
        }
      }

      Serial.print("Summertime: ");
      Serial.println(summerTime);

      if (h + utcOffset + summerTime > 23) {
        h = h - 24;
        dayOfWeek = (dayOfWeek % 7) + 1;
        day += 1;
        // Check for month and year rollover
        unsigned short Tage_Monat[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
        if (day > Tage_Monat[month - 1]) {
          day = 1;
          month += 1;
          if (month > 12) {
            month = 1;
            year += 1;
          }
        }
      }

      monthloc = M_arr[month]; // Localize month
      dayloc = Dow_arr[dayOfWeek]; // Localize day of week
      date = dayloc + ",   " + day + " " + monthloc + " " + year;
      Serial.println(date); // Check

      localMillisAtUpdate = millis();
      localEpoc = (h * 60 * 60 + m * 60 + s);
    }
  }
  client.stop();
}

// =======================================================================

// Convert month string to month number
int month2index(String month)
{
  String months[12] = {"JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"};
  for (int i = 0; i < 12; i++) {
    if (months[i] == month)
      return i + 1;
  }
  return 0;
}

// =======================================================================

// Convert day of week string to day number
int dow2index(String dayOfWeek)
{
  String dows[7] = {"MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN"};
  for (int i = 0; i < 7; i++) {
    if (dows[i] == dayOfWeek)
      return i + 1;
  }
  return 0;
}

// =======================================================================

void updateTime()
{
  long curEpoch = localEpoc + ((millis() - localMillisAtUpdate) / 1000);
  long epoch = round(curEpoch + 3600 * (utcOffset + summerTime) + 86400L);
  h = ((epoch % 86400L) / 3600) % 24;
  m = (epoch % 3600) / 60;
  s = epoch % 60;
}

// =======================================================================

void contrast()
{
  int brightness = analogRead(A0);  // Auto-brightness (+3.3V ---|==10k==|---A0---|GND)
  brightness = map(brightness, 0, 1023, 0, 4);  // Brightness 0-4
  sendCmdAll(CMD_INTENSITY, brightness);
}

font.h

Arduino
const uint8_t dig3x8[] PROGMEM = { 4,
0x03, 0xFF, 0x81, 0xFF,
0x02, 0x02, 0xFF, 0x00,
0x03, 0xF9, 0x89, 0x8F,
0x03, 0x81, 0x89, 0xFF,
0x03, 0x1F, 0x10, 0xFC,
0x03, 0x8F, 0x89, 0xF9,
0x03, 0xFF, 0x89, 0xF9,
0x03, 0x01, 0xF1, 0x0F,
0x03, 0xFF, 0x89, 0xFF,
0x03, 0x9F, 0x91, 0xFF,
};

const uint8_t dig6x8[] PROGMEM = { 7,
0x06, 0x7E, 0xFF, 0x81, 0x81, 0xFF, 0x7E,
0x06, 0x00, 0x82, 0xFF, 0xFF, 0x80, 0x00,
0x06, 0xC2, 0xE3, 0xB1, 0x99, 0x8F, 0x86,
0x06, 0x42, 0xC3, 0x89, 0x89, 0xFF, 0x76,
0x06, 0x38, 0x3C, 0x26, 0x23, 0xFF, 0xFF,
0x06, 0x4F, 0xCF, 0x89, 0x89, 0xF9, 0x71,
0x06, 0x7E, 0xFF, 0x89, 0x89, 0xFB, 0x72,
0x06, 0x01, 0x01, 0xF1, 0xF9, 0x0F, 0x07,
0x06, 0x76, 0xFF, 0x89, 0x89, 0xFF, 0x76,
0x06, 0x4E, 0xDF, 0x91, 0x91, 0xFF, 0x7E,
6, 0,0,0,0,0,0
};

const uint8_t dig4x8[] PROGMEM = { 5,
0x04, 0xFF, 0x81, 0x81, 0xFF,
0x04, 0x04, 0x02, 0xFF, 0x00,
0x04, 0xF9, 0x89, 0x89, 0x8F,
0x04, 0x81, 0x89, 0x89, 0xFF,
0x04, 0x1F, 0x10, 0x10, 0xFE,
0x04, 0x8F, 0x89, 0x89, 0xF9,
0x04, 0xFF, 0x89, 0x89, 0xF8,
0x04, 0x01, 0xC1, 0x31, 0x0F,
0x04, 0xFF, 0x89, 0x89, 0xFF,
0x04, 0x1F, 0x91, 0x91, 0xFF,
};

const uint8_t dig3x7[] PROGMEM = { 4,
0x03, 0xFE, 0x82, 0xFE, 
0x03, 0x08, 0x04, 0xFE, 
0x03, 0xF2, 0x92, 0x9E, 
0x03, 0x82, 0x92, 0xFE, 
0x03, 0x3E, 0x20, 0xFC, 
0x03, 0x9E, 0x92, 0xF2, 
0x03, 0xFE, 0x92, 0xF2, 
0x03, 0x02, 0xE2, 0x1E, 
0x03, 0xFE, 0x92, 0xFE, 
0x03, 0x9E, 0x92, 0xFE, 
};
                                  
const uint8_t dig3x6[] PROGMEM = { 4,
0x03, 0xFC, 0x84, 0xFC, 
0x03, 0x10, 0x08, 0xFC, 
0x03, 0xF4, 0x94, 0x9C, 
0x03, 0x84, 0x94, 0xFC, 
0x03, 0x3C, 0x20, 0xF8, 
0x03, 0x9C, 0x94, 0xF4, 
0x03, 0xFC, 0x94, 0xF4, 
0x03, 0x04, 0xE4, 0x1C, 
0x03, 0xFC, 0x94, 0xFC, 
0x03, 0xBC, 0xA4, 0xFC, 
};

const uint8_t dig3x5[] PROGMEM = { 4,
0x03, 0xF8, 0x88, 0xF8, 
0x02, 0x10, 0xF8, 0x00, 
0x03, 0xE8, 0xA8, 0xB8, 
0x03, 0x88, 0xA8, 0xF8, 
0x03, 0x38, 0x20, 0xF8, 
0x03, 0xB8, 0xA8, 0xE8, 
0x03, 0xF8, 0xA8, 0xE8, 
0x03, 0x08, 0x08, 0xF8, 
0x03, 0xF8, 0xA8, 0xF8, 
0x03, 0xB8, 0xA8, 0xF8, 
};
const uint8_t dig5x8rn[] PROGMEM = { 6,
0x05, 0x7E, 0x81, 0x81, 0xFF, 0x7E, 
0x05, 0x04, 0x02, 0xFF, 0xFF, 0x00, 
0x05, 0xF1, 0x89, 0x89, 0x8F, 0x86, 
0x05, 0x81, 0x89, 0x89, 0xFF, 0x76, 
0x05, 0x1F, 0x10, 0x10, 0xFE, 0xFE, 
0x05, 0x8F, 0x89, 0x89, 0xF9, 0x71, 
0x05, 0x7E, 0x89, 0x89, 0xF9, 0x70, 
0x05, 0x01, 0xC1, 0xF1, 0x3F, 0x0F, 
0x05, 0x76, 0x89, 0x89, 0xFF, 0x76, 
0x05, 0x0E, 0x91, 0x91, 0xFF, 0x7E, 
};

const uint8_t dig5x8sq[] PROGMEM = { 6,
0x05, 0xFF, 0x81, 0x81, 0xFF, 0xFF, 
0x04, 0x04, 0x02, 0xFF, 0xFF, 0x00, 
0x05, 0xF9, 0x89, 0x89, 0x8F, 0x8F, 
0x05, 0x81, 0x89, 0x89, 0xFF, 0xFF, 
0x05, 0x1F, 0x10, 0x10, 0xFE, 0xFE, 
0x05, 0x8F, 0x89, 0x89, 0xF9, 0xF9, 
0x05, 0xFF, 0x89, 0x89, 0xF9, 0xF9, 
0x05, 0x01, 0x01, 0x01, 0xFF, 0xFF, 
0x05, 0xFF, 0x89, 0x89, 0xFF, 0xFF, 
0x05, 0x9F, 0x91, 0x91, 0xFF, 0xFF, 
};

const uint8_t dweek_pl[] PROGMEM = { 11,
0x0A, 0xFC, 0x08, 0x10, 0xFC, 0x00, 0xFC, 0x00, 0xFC, 0x94, 0x84, 
0x09, 0xFC, 0x24, 0x24, 0x3C, 0x00, 0xFC, 0x84, 0x84, 0xFC, 0x00,  
0x09, 0xFC, 0x80, 0xF0, 0x80, 0xFC, 0x00, 0x04, 0xFC, 0x04, 0x00, 
0x09, 0xDC, 0x94, 0x96, 0xF5, 0x00, 0xFC, 0x24, 0x64, 0xBC, 0x00,
0x09, 0xFC, 0x84, 0x84, 0xCC, 0x00, 0xC4, 0xA4, 0x94, 0x8C, 0x00,
0x0A, 0xFC, 0x24, 0x24, 0x3C, 0x00, 0xFC, 0x00, 0xFC, 0x24, 0xFC,  
0x09, 0xDC, 0x94, 0x94, 0xF4, 0x00, 0xFC, 0x84, 0x84, 0xFC, 0x00,  
0x09, 0x07, 0x05, 0x07, 0x00, 0xFF, 0xFF, 0x81, 0x81, 0x81, 0x00,  
};

const uint8_t dweek_en[] PROGMEM = { 11,
0x09, 0x9C, 0x94, 0x94, 0xF4, 0x00, 0xFC, 0x80, 0x80, 0xFC, 0x00,
0x0A, 0xFC, 0x04, 0x3C, 0x04, 0xFC, 0x00, 0xFC, 0x84, 0x84, 0xFC,
0x0A, 0x04, 0x04, 0xFC, 0x04, 0x04, 0x00, 0xFC, 0x80, 0x80, 0xFC,
0x0A, 0xFC, 0x80, 0xF0, 0x80, 0xFC, 0x00, 0xFC, 0x94, 0x94, 0x84,
0x0A, 0x04, 0x04, 0xFC, 0x04, 0x04, 0x00, 0xFC, 0x10, 0x10, 0xFC,
0x09, 0xFC, 0x24, 0x24, 0x04, 0x00, 0xFC, 0x24, 0x64, 0xBC, 0x00,
0x09, 0x9C, 0x94, 0x94, 0xF4, 0x00, 0xFC, 0x24, 0x24, 0xFC, 0x00,
0x09, 0x07, 0x05, 0x07, 0x00, 0xFF, 0xFF, 0x81, 0x81, 0x81, 0x00,
};

const uint8_t font[] PROGMEM = {6,
2, B00000000, B00000000, B00000000, B00000000, B00000000, // space
1, B01011111, B00000000, B00000000, B00000000, B00000000, // !
3, B00000011, B00000000, B00000011, B00000000, B00000000, // "
5, B00010100, B00111110, B00010100, B00111110, B00010100, // #
4, B00100100, B01101010, B00101011, B00010010, B00000000, // $
5, B01100011, B00010011, B00001000, B01100100, B01100011, // %
5, B00110110, B01001001, B01010110, B00100000, B01010000, // &
1, B00000011, B00000000, B00000000, B00000000, B00000000, // '
3, B00011100, B00100010, B01000001, B00000000, B00000000, // (
3, B01000001, B00100010, B00011100, B00000000, B00000000, // )
5, B00101000, B00011000, B00001110, B00011000, B00101000, // *
5, B00001000, B00001000, B00111110, B00001000, B00001000, // +
2, B10110000, B01110000, B00000000, B00000000, B00000000, // ,
4, B00001000, B00001000, B00001000, B00001000, B00000000, // -
1, B01000000, B00000000, B00000000, B00000000, B00000000, // .
3, B01100000, B00011100, B00000011, B00000000, B00000000, // /
4, B00111110, B01000001, B01000001, B00111110, B00000000, // 0
3, B01000010, B01111111, B01000000, B00000000, B00000000, // 1
4, B01100010, B01010001, B01001001, B01000110, B00000000, // 2
4, B00100010, B01000001, B01001001, B00110110, B00000000, // 3
4, B00011000, B00010100, B00010010, B01111111, B00000000, // 4
4, B00100111, B01000101, B01000101, B00111001, B00000000, // 5
4, B00111110, B01001001, B01001001, B00110010, B00000000, // 6
4, B01100001, B00010001, B00001001, B00000111, B00000000, // 7
4, B00110110, B01001001, B01001001, B00110110, B00000000, // 8
4, B00100110, B01001001, B01001001, B00111110, B00000000, // 9
1, B01000100, B00000000, B00000000, B00000000, B00000000, // :
2, B10000000, B01010000, B00000000, B00000000, B00000000, // ;
3, B00010000, B00101000, B01000100, B00000000, B00000000, // <
3, B00010100, B00010100, B00010100, B00000000, B00000000, // =
3, B01000100, B00101000, B00010000, B00000000, B00000000, // >
4, B00000010, B01011001, B00001001, B00000110, B00000000, // ?
5, B00111110, B01001001, B01010101, B01011101, B00001110, // @
4, B01111110, B00010001, B00010001, B01111110, B00000000, // A
4, B01111111, B01001001, B01001001, B00110110, B00000000, // B
4, B00111110, B01000001, B01000001, B00100010, B00000000, // C
4, B01111111, B01000001, B01000001, B00111110, B00000000, // D
4, B01111111, B01001001, B01001001, B01000001, B00000000, // E
4, B01111111, B00001001, B00001001, B00000001, B00000000, // F
4, B00111110, B01000001, B01001001, B01111010, B00000000, // G
4, B01111111, B00001000, B00001000, B01111111, B00000000, // H
3, B01000001, B01111111, B01000001, B00000000, B00000000, // I
4, B00110000, B01000000, B01000001, B00111111, B00000000, // J
4, B01111111, B00001000, B00010100, B01100011, B00000000, // K
4, B01111111, B01000000, B01000000, B01000000, B00000000, // L
5, B01111111, B00000010, B00001100, B00000010, B01111111, // M
5, B01111111, B00000100, B00001000, B00010000, B01111111, // N
4, B00111110, B01000001, B01000001, B00111110, B00000000, // O
4, B01111111, B00001001, B00001001, B00000110, B00000000, // P
4, B00111110, B01000001, B01000001, B10111110, B00000000, // Q
4, B01111111, B00001001, B00001001, B01110110, B00000000, // R
4, B00100110, B01001001, B01001001, B00110010, B00000000, // S
5, B00000001, B00000001, B01111111, B00000001, B00000001, // T
4, B00111111, B01000000, B01000000, B00111111, B00000000, // U
5, B00001111, B00110000, B01000000, B00110000, B00001111, // V
5, B00111111, B01000000, B00111000, B01000000, B00111111, // W
5, B01100011, B00010100, B00001000, B00010100, B01100011, // X
5, B00000111, B00001000, B01110000, B00001000, B00000111, // Y
4, B01100001, B01010001, B01001001, B01000111, B00000000, // Z
2, B01111111, B01000001, B00000000, B00000000, B00000000, // [
4, B00000001, B00000110, B00011000, B01100000, B00000000, // \ backslash
2, B01000001, B01111111, B00000000, B00000000, B00000000, // ]
3, B00000010, B00000001, B00000010, B00000000, B00000000, // hat
4, B01000000, B01000000, B01000000, B01000000, B00000000, // _
2, B00000001, B00000010, B00000000, B00000000, B00000000, // `
4, B00100000, B01010100, B01010100, B01111000, B00000000, // a
4, B01111111, B01000100, B01000100, B00111000, B00000000, // b
4, B00111000, B01000100, B01000100, B00101000, B00000000, // c
4, B00111000, B01000100, B01000100, B01111111, B00000000, // d
4, B00111000, B01010100, B01010100, B00011000, B00000000, // e
3, B00000100, B01111110, B00000101, B00000000, B00000000, // f
4, B10011000, B10100100, B10100100, B01111000, B00000000, // g
4, B01111111, B00000100, B00000100, B01111000, B00000000, // h
3, B01000100, B01111101, B01000000, B00000000, B00000000, // i
4, B01000000, B10000000, B10000100, B01111101, B00000000, // j
4, B01111111, B00010000, B00101000, B01000100, B00000000, // k
3, B01000001, B01111111, B01000000, B00000000, B00000000, // l
5, B01111100, B00000100, B01111100, B00000100, B01111000, // m
4, B01111100, B00000100, B00000100, B01111000, B00000000, // n
4, B00111000, B01000100, B01000100, B00111000, B00000000, // o
4, B11111100, B00100100, B00100100, B00011000, B00000000, // p
4, B00011000, B00100100, B00100100, B11111100, B00000000, // q
4, B01111100, B00001000, B00000100, B00000100, B00000000, // r
4, B01001000, B01010100, B01010100, B00100100, B00000000, // s
3, B00000100, B00111111, B01000100, B00000000, B00000000, // t
4, B00111100, B01000000, B01000000, B01111100, B00000000, // u
5, B00011100, B00100000, B01000000, B00100000, B00011100, // v
5, B00111100, B01000000, B00111100, B01000000, B00111100, // w
5, B01000100, B00101000, B00010000, B00101000, B01000100, // x
4, B10011100, B10100000, B10100000, B01111100, B00000000, // y
3, B01100100, B01010100, B01001100, B00000000, B00000000, // z
3, B00001000, B00110110, B01000001, B00000000, B00000000, // {
1, B01111111, B00000000, B00000000, B00000000, B00000000, // |
3, B01000001, B00110110, B00001000, B00000000, B00000000, // }
4, B00001000, B00000100, B00001000, B00000100, B00000000, // ~

5, B00100000, B01010100, B01010100, B11111000, B10000000, // a
4, B00111000, B01000100, B01000110, B00101001, B00000000, // c
4, B00111000, B01010100, B11010100, B10011000, B00000000, // e
3, B01010001, B01111111, B01000100, B00000000, B00000000, // l
4, B01111100, B00000100, B00000110, B01111001, B00000000, // n
4, B00111000, B01000100, B01000110, B00111001, B00000000, // o
4, B01001000, B01010100, B01010110, B00100101, B00000000, // s
3, B01100100, B01010110, B01001101, B00000000, B00000000, // z
3, B01100100, B01010101, B01001100, B00000000, B00000000, // z
5, B01111110, B00010001, B00010001, B11111110, B10000000, // A
4, B00111100, B01000010, B01000011, B00100101, B00000000, // C
5, B01111111, B01001001, B01001001, B11000001, B10000000, // E
4, B01111111, B01001000, B01000100, B01000000, B00000000, // L
5, B01111110, B00000100, B00001010, B00010001, B01111110, // N
4, B00111100, B01000110, B01000011, B00111100, B00000000, // O
4, B00100100, B01001010, B01001011, B00110000, B00000000, // S
4, B01100010, B01010110, B01001011, B01000110, B00000000, // Z
4, B01101001, B01011001, B01001101, B01001011, B00000000, // Z

5, B00111110, B01010101, B01100001, B01010101, B00111110, // :)
5, B00111110, B01100101, B01010001, B01100101, B00111110, // :(
5, B00111110, B01000101, B01010001, B01000101, B00111110, // :o
5, 0x06, 0x1F, 0x7E, 0x1F, 0x06,   // heart
5, 0x04, 0x02, 0x7F, 0x02, 0x04,   // arrow up
5, 0x10, 0x20, 0x7F, 0x20, 0x10,   // arrow down
3, B00000010, B00000101, B00000010, B00000000, B00000000, // deg
};

max7219.h

Arduino
// MAX7219 functions by Pawel A. Hernik
// 2016.12.10 updated for rotated LED Martices, define ROTATE below (0,90 or 270)

// MAX7219 commands:
#define CMD_NOOP   0
#define CMD_DIGIT0 1
#define CMD_DIGIT1 2
#define CMD_DIGIT2 3
#define CMD_DIGIT3 4
#define CMD_DIGIT4 5
#define CMD_DIGIT5 6
#define CMD_DIGIT6 7
#define CMD_DIGIT7 8
#define CMD_DECODEMODE  9
#define CMD_INTENSITY   10
#define CMD_SCANLIMIT   11
#define CMD_SHUTDOWN    12
#define CMD_DISPLAYTEST 15

byte scr[NUM_MAX*8 + 8]; // +8 for scrolled char

void sendCmd(int addr, byte cmd, byte data)
{
  digitalWrite(CS_PIN, LOW);
  for (int i = NUM_MAX-1; i>=0; i--) {
    shiftOut(DIN_PIN, CLK_PIN, MSBFIRST, i==addr ? cmd : 0);
    shiftOut(DIN_PIN, CLK_PIN, MSBFIRST, i==addr ? data : 0);
  }
  digitalWrite(CS_PIN, HIGH);
}

void sendCmdAll(byte cmd, byte data)
{
  digitalWrite(CS_PIN, LOW);
  for (int i = NUM_MAX-1; i>=0; i--) {
    shiftOut(DIN_PIN, CLK_PIN, MSBFIRST, cmd);
    shiftOut(DIN_PIN, CLK_PIN, MSBFIRST, data);
  }
  digitalWrite(CS_PIN, HIGH);
}

void refresh(int addr) {
  for (int i = 0; i < 8; i++)
    sendCmd(addr, i + CMD_DIGIT0, scr[addr * 8 + i]);
}

void refreshAllRot270() {
  byte mask = 0x01;
  for (int c = 0; c < 8; c++) {
    digitalWrite(CS_PIN, LOW);
    for(int i=NUM_MAX-1; i>=0; i--) {
      byte bt = 0;
      for(int b=0; b<8; b++) {
        bt<<=1;
        if(scr[i * 8 + b] & mask) bt|=0x01;
      }
      shiftOut(DIN_PIN, CLK_PIN, MSBFIRST, CMD_DIGIT0 + c);
      shiftOut(DIN_PIN, CLK_PIN, MSBFIRST, bt);
    }
    digitalWrite(CS_PIN, HIGH);
    mask<<=1;
  }
}

void refreshAllRot90() {
  byte mask = 0x80;
  for (int c = 0; c < 8; c++) {
    digitalWrite(CS_PIN, LOW);
    for(int i=NUM_MAX-1; i>=0; i--) {
      byte bt = 0;
      for(int b=0; b<8; b++) {
        bt>>=1;
        if(scr[i * 8 + b] & mask) bt|=0x80;
      }
      shiftOut(DIN_PIN, CLK_PIN, MSBFIRST, CMD_DIGIT0 + c);
      shiftOut(DIN_PIN, CLK_PIN, MSBFIRST, bt);
    }
    digitalWrite(CS_PIN, HIGH);
    mask>>=1;
  }
}

#define ROTATE 90

void refreshAll() {
#if ROTATE==270
  refreshAllRot270();
#elif ROTATE==90
  refreshAllRot90();
#else
  for (int c = 0; c < 8; c++) {
    digitalWrite(CS_PIN, LOW);
    for(int i=NUM_MAX-1; i>=0; i--) {
      shiftOut(DIN_PIN, CLK_PIN, MSBFIRST, CMD_DIGIT0 + c);
      shiftOut(DIN_PIN, CLK_PIN, MSBFIRST, scr[i * 8 + c]);
    }
    digitalWrite(CS_PIN, HIGH);
  }
#endif
}


void clr()
{
  for (int i = 0; i < NUM_MAX*8; i++) scr[i] = 0;
}

void scrollLeft()
{
  for(int i=0; i < NUM_MAX*8+7; i++) scr[i] = scr[i+1];
}

void invert()
{
  for (int i = 0; i < NUM_MAX*8; i++) scr[i] = ~scr[i];
}

void initMAX7219()
{
  pinMode(DIN_PIN, OUTPUT);
  pinMode(CLK_PIN, OUTPUT);
  pinMode(CS_PIN, OUTPUT);
  digitalWrite(CS_PIN, HIGH);
  sendCmdAll(CMD_DISPLAYTEST, 0);
  sendCmdAll(CMD_SCANLIMIT, 7);
  sendCmdAll(CMD_DECODEMODE, 0);
  sendCmdAll(CMD_INTENSITY, 0); // minimum brightness
  sendCmdAll(CMD_SHUTDOWN, 0);
  clr();
  refreshAll();
}

Credits

anthias64
1 project • 3 followers
an old techie boomer
Contact
Thanks to Nat .

Comments

Please log in or sign up to comment.