From 1af9cf18d9695be25cd78b2d5a56385124c09b40 Mon Sep 17 00:00:00 2001 From: Lomanic Date: Sun, 12 Jan 2020 23:46:53 +0100 Subject: [PATCH] initial commit --- README.md | 12 +++ nodemcu-max7219-clock.ino | 149 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 161 insertions(+) create mode 100644 README.md create mode 100644 nodemcu-max7219-clock.ino diff --git a/README.md b/README.md new file mode 100644 index 0000000..d4bf9ff --- /dev/null +++ b/README.md @@ -0,0 +1,12 @@ +# Nodemcu NTP clock with Max7219 LED matrix + +## Hardware parts + +* [Nodemcu v3 board](https://www.aliexpress.com/item/32565317233.html) +* [MAX7219 Dot Matrix Module For Microcontroller 4 In One Display with 5P Line](https://www.aliexpress.com/item/32616345083.html) + +## Software dependencies + +This uses the Arduino IDE with the [esp8266 core](https://arduino-esp8266.readthedocs.io/en/2.6.3/installing.html#boards-manager) and the following libraries, installed using the Libraries manager: +* [ezTime](https://github.com/ropg/ezTime) 0.8.3, to get time from NTP pool, properly format it and take in account timezones +* [MajicDesigns's MD_MAX72XX](https://github.com/MajicDesigns/MD_MAX72XX) library 3.2.1, to write hours on the Max7219 LED matrix (this builds mostly upon [the MD_MAX72xx_PrintText](https://github.com/MajicDesigns/MD_MAX72XX/blob/25da52707cd3bbcc2406b9984d694afabecf6002/examples/MD_MAX72xx_PrintText/MD_MAX72xx_PrintText.ino) sample) diff --git a/nodemcu-max7219-clock.ino b/nodemcu-max7219-clock.ino new file mode 100644 index 0000000..da15b62 --- /dev/null +++ b/nodemcu-max7219-clock.ino @@ -0,0 +1,149 @@ +#include +#include +#include + +ESP8266WiFiMulti wifiMulti; + +#include +#include + +// Define the number of devices we have in the chain and the hardware interface +// NOTE: These pin numbers will probably not work with your hardware and may +// need to be adapted +#define HARDWARE_TYPE MD_MAX72XX::FC16_HW +#define MAX_DEVICES 4 + +#define DATA_PIN 14 // or MOSI (D5 on NodeMCU) +#define CS_PIN 12 // or SS (D6 on NodeMCU) +#define CLK_PIN 13 // or SCK (D7 on NodeMCU) + +// SPI hardware interface +//MD_MAX72XX mx = MD_MAX72XX(HARDWARE_TYPE, CS_PIN, MAX_DEVICES); +// Arbitrary pins +MD_MAX72XX mx = MD_MAX72XX(HARDWARE_TYPE, DATA_PIN, CLK_PIN, CS_PIN, MAX_DEVICES); + +// Text parameters +#define CHAR_SPACING 1 // pixels between characters + +// Global message buffers shared by Serial and Scrolling functions +#define BUF_SIZE 6 +char message[BUF_SIZE] = "00:00"; + +void printText(uint8_t modStart, uint8_t modEnd, const char *pMsg) +// Print the text string to the LED matrix modules specified. +// Message area is padded with blank columns after printing. +{ + uint8_t state = 0; + uint8_t curLen; + uint16_t showLen; + uint8_t cBuf[8]; + int16_t col = ((modEnd + 1) * COL_SIZE) - 1; + + mx.control(modStart, modEnd, MD_MAX72XX::UPDATE, MD_MAX72XX::OFF); + + do // finite state machine to print the characters in the space available + { + switch (state) + { + case 0: // Load the next character from the font table + // if we reached end of message, reset the message pointer + if (*pMsg == '\0') + { + showLen = col - (modEnd * COL_SIZE); // padding characters + state = 2; + break; + } + + // retrieve the next character form the font file + showLen = mx.getChar(*pMsg++, sizeof(cBuf) / sizeof(cBuf[0]), cBuf); + curLen = 0; + state++; + // !! deliberately fall through to next state to start displaying + + case 1: // display the next part of the character + mx.setColumn(col--, cBuf[curLen++]); + + // done with font character, now display the space between chars + if (curLen == showLen) + { + showLen = CHAR_SPACING; + state = 2; + } + break; + + case 2: // initialize state for displaying empty columns + curLen = 0; + state++; + // fall through + + case 3: // display inter-character spacing or end of message padding (blank columns) + mx.setColumn(col--, 0); + curLen++; + if (curLen == showLen) + state = 0; + break; + + default: + col = -1; // this definitely ends the do loop + } + } while (col >= (modStart * COL_SIZE)); + + mx.control(modStart, modEnd, MD_MAX72XX::UPDATE, MD_MAX72XX::ON); +} + +void setWifi() { + Serial.print("Connecting to wifi: "); + printText(0, MAX_DEVICES - 1, "WiFi"); + WiFi.mode(WIFI_STA); + wifiMulti.addAP("XXX", "XXX"); + wifiMulti.addAP("XXX", "XXX"); + wifiMulti.addAP("XXX ", "XXX"); + while (wifiMulti.run() != WL_CONNECTED) { // Wait for the Wi-Fi to connect: scan for Wi-Fi networks, and connect to the strongest of the networks above + delay(1000); + Serial.print('.'); + } + Serial.println(); +} + +Timezone myTZ; +void setClock() { + printText(0, MAX_DEVICES - 1, "NTP"); + // Make ezTime show us what it is doing + setDebug(INFO); + // Wait for ezTime to get its time synchronized + waitForSync(); + // See if local time can be obtained (does not work in countries that span multiple timezones) + if (myTZ.setLocation()) { + Serial.println(myTZ.dateTime()); + } else { + Serial.println(errorString()); + myTZ.setPosix(F("CET-1CEST,M3.5.0,M10.5.0/3")); // Europe/Paris + } + myTZ.setDefault(); + Serial.println(myTZ.dateTime()); + // Set NTP polling interval to 1 hour. + setInterval(60 * 60); +} + +void setup() { + mx.begin(); + + Serial.begin(115200); + Serial.println(); + setWifi(); + setClock(); +} + +bool showColon = true; +void loop() { + // Register ezTime events + events(); + if (secondChanged()) { + showColon = !showColon; + char dateFormat[BUF_SIZE] = "H:i"; + if (!showColon) { + strcpy(dateFormat, "H i"); + } + printText(0, MAX_DEVICES - 1, dateTime(dateFormat).c_str()); + } +}