Simple Dot Matrix Clock Using Node MCU
by grizelli in Circuits > Arduino
10789 Views, 80 Favorites, 0 Comments
Simple Dot Matrix Clock Using Node MCU
This describes the build of a simple clock to display hours and minutes on a dot matrix display made up of four 8 x 8 modules. The processor is a generic Arduino-compatible NodeMCU board based on the ESP8266 chip to give it integrated wi-fi capability. We are not using the Wi-fi for this project, but I am planning to add to it later.
I wanted a simple clock that just displays the time, nothing more complex than that. All the off the shelf clocks seem to include alarms, and the last one I bought wouldn't deal with Summer time, not would it survive a power failure despite having a battery which only seemed to function to keep the alarm beeping. This went out the window after a power failure, followed by the clock automatically setting an alarm for midnight, and the alarm 'off' button only making the damn thing snooze so that it triggered again five minutes after I had unplugged it from the power.
The display automatically dims after 8pm, and only shows the time in 12 hour format (although this is easy to change). It also automatically makes an adjustment of 1 hour for British Summer Time in March and October (this can also be amended to suit other time zones).
I have also included a link to a utility which allows the RTC module to be set up with the time.
The RTC module is a high accuracy device, which keeps time for approximately ten years even with the power turned off.
All the parts can be bought on Ebay for a total of around £10 - £12
Real Time Clock Module
This is a ready-made module based on the DS3231 clock chip. These are readily available on Ebay for less than £2, cheaper still if you buy a bunch at a time. They connect to the processor module using the I2C format: on the NodeMCU device the connections are as follows:-
DS3231 pins connect to pin on NodeMCU
SCL --------------------------D1
SDA --------------------------D2
Vcc -------------------------- Vin (ie 5 volt pin)
GND -------------------------GND
The RTC module might already be set to tell the correct time when you buy it, but its probably a good idea to reset it to what you conside to be the correct time before you start. The one I used showed the right time, but not the correct day of the week and since this is used to calculate the BST/GMT changeover it needs to be set.
Software to set the clock is at the end of this instructable
Node MCU Board
This board is an Arduino-compatible processor with a built-in ESP8266 Wi-Fi module fully integrated with the board. Make sure that you order yours with the Arduino option, otherwise the only way to program the board is using some madness called LUA , which is almost the same as other programming langauages but different enough to make exploration a nightmare.
These boards are widely available on Ebay for around £6 each from a UK source, or less than £3 if you buy direct from a Chinese source and don't mind waiting maybe three weeks for it to arrive. They are actually called a Node MCU Development Board which have a built in USB port and run off the standard 5 volt supply – you can buy just the ESP8266 wireless module, but its a lot more complex to hook up.
Since I made my clock, I see that there are even smaller versions of these boards available, but they seem to have less I/O pins and I havn't tried them out.
You will need to download the Arduino IDE environment from arduino.cc and you will need to go through a bit of a rigmarole to get it to recognise the Node MCU board – go to nodemcu.com and read up how to do this.
You will also have to include the wire library, part of the standard IDE, and also locate another library called Ledcontrol – find it at https://github.com/wayoda/LedControl , download the .zip file and extract its contents into the /program files/arduino/libraries folder on your PC. Note that the download gives you a folder named Ledcontrol-master, you will need to rename this to take the '-master' part off the end.
LED Dot Matrix Display
These are also readily available on Ebay, either as single modules that can be daisy-chained together (up to a maximum of 8 modules), or in a single strip containing four modules. I chose to use the latter as it looks a lot neater, however there is some work to do in the software to make the time read along the strip instead of from top to bottom. The strip costs around £6, but only seems to come in red LEDs, I can't find any in any other colour.
The LEDs are really bright, and although the intensity can be set from 0 to 10 even on the lowest (0) setting its still waaay too bright at night. I installed mine behind a sheet of dark grey tinted perspex which dims the light to a sensible level and also hides the outline of the modules so it looks much neater.
Connection to the NodeMCU is simple, as follows:-
Display pin connect to pin on NodeMCU
Vcc --------------------------------3v3
GND ------------------------------GND
Din ---------------------------------D7
CS ---------------------------------D6
CLK -------------------------------D5
Now to put it all together .....
Setting the RTC Clock Time
Once you have all this hardware connected together, the Arduino IDE set up to recognise the Node MCU board, and the PC recognising the right USB port that its connected to, you are ready to get started on loading the software.
First, set the time of the RTC module using the software listed below – just copy all the text and paste it into a blank screen on the Arduino IDE. Enter the correct time and other details where shown in red, not forgetting the day of the week ('day') where '1' is Sunday, and Saturday is '7'.
Set the time a minute or so later than actual to allow for the time it takes to upload it, then hit the 'upload' button to install it on the Node MCU.
Software file is on this page, the code is as follows if you can't read the file:-
#include "Wire.h"
#define DS3231_I2C_ADDRESS 0x68
// Convert normal decimal numbers to binary coded decimal
byte decToBcd(byte val)
{
return( (val/10*16) + (val%10) );
}
// Convert binary coded decimal to normal decimal numbers
byte bcdToDec(byte val)
{
return( (val/16*10) + (val%16) );
}
void setup()
{
Wire.begin();
Serial.begin(9600);
// set the initial time here:
// DS3231 seconds, minutes, hours, day, date, month, year
setDS3231time(30,42,21,4,26,11,14);
}
void setDS3231time(byte second, byte minute, byte hour, byte dayOfWeek, byte
dayOfMonth, byte month, byte year)
{
// sets time and date data to DS3231
Wire.beginTransmission(DS3231_I2C_ADDRESS);
Wire.write(0); // set next input to start at the seconds register
Wire.write(decToBcd(30)); // set seconds
Wire.write(decToBcd(40)); // set minutes
Wire.write(decToBcd(13)); // set hours
Wire.write(decToBcd(6)); // set day of week (1=Sunday, 7=Saturday)
Wire.write(decToBcd(9)); // set date (1 to 31)
Wire.write(decToBcd(12)); // set month
Wire.write(decToBcd(16)); // set year (0 to 99)
Wire.endTransmission();
}
void readDS3231time(byte *second,
byte *minute,
byte *hour,
byte *dayOfWeek,
byte *dayOfMonth,
byte *month,
byte *year)
{
Wire.beginTransmission(DS3231_I2C_ADDRESS);
Wire.write(0); // set DS3231 register pointer to 00h
Wire.endTransmission();
Wire.requestFrom(DS3231_I2C_ADDRESS, 7);
// request seven bytes of data from DS3231 starting from register 00h
*second = bcdToDec(Wire.read() & 0x7f);
*minute = bcdToDec(Wire.read());
*hour = bcdToDec(Wire.read() & 0x3f);
*dayOfWeek = bcdToDec(Wire.read());
*dayOfMonth = bcdToDec(Wire.read());
*month = bcdToDec(Wire.read());
*year = bcdToDec(Wire.read());
}
void displayTime()
{
byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
// retrieve data from DS3231
readDS3231time(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month,
&year);
// send it to the serial monitor
Serial.print(hour, DEC);
// convert the byte variable to a decimal number when displayed
Serial.print(":");
if (minute<10)
{
Serial.print("0");
}
Serial.print(minute, DEC);
Serial.print(":");
if (second<10)
{
Serial.print("0");
}
Serial.print(second, DEC);
Serial.print(" ");
Serial.print(dayOfMonth, DEC);
Serial.print("/");
Serial.print(month, DEC);
Serial.print("/");
Serial.print(year, DEC);
Serial.print(" Day of week: ");
switch(dayOfWeek){
case 1:
Serial.println("Sunday");
break;
case 2:
Serial.println("Monday");
break;
case 3:
Serial.println("Tuesday");
break;
case 4:
Serial.println("Wednesday");
break;
case 5:
Serial.println("Thursday");
break;
case 6:
Serial.println("Friday");
break;
case 7:
Serial.println("Saturday");
break;
}
}
void loop()
{
displayTime(); // display the real-time clock data on the Serial Monitor,
delay(1000); // every second
}
When you copy the code above, make sure that you get all of it, including the '}' at the end. Leave this off, and you're dead.
Last step coming up, get the clock running ......
Downloads
Making the Clock Work
Either use the file above, or copy the following and paste it into your Arduino IDE: as before, make sure you get it all, from the '/*' at the beginning to the '}' at the end
/*
Real time clock with dot matrix LED display - Final_dot_matrix_clock_v1-0
Uses a NodeMCU development kit board, with the ds3231 RTC module and a 4-module dot matrix display
note, these displays are normally oriented so that the connectors are at the top, so a single 4-module unit will normally need to be either
mounted vertically, or split into 4 separate chunks and rewired.
This software re-writes the table which draws out the dots on each module to make it display with the strip mounted horizontally, connector to the left
The RTC needs to be pre-set with the correct time as well as date, day of the week, etc so that the switch to BST operates correctly
Use a separate app for setting up the RTC - use 'configure_ds3231_rtc_only.ino' for this, manually inserting correct values befor uploading
This software makes adjustments for GMT/BST transitions, and is hard coded to show the time in 12 hour format - the RTC still uses 24H format
Other notes: the Arduino development environment hold libraries in a variety of different places, not all are easy to find
The programming of the table for the dot matrix display is non-intuitive, see separate notes on this
Written by Martin Howell 9th December 2016
Change log:-
Version 1.0 dd 9/12/16 - original release
*
/device connections:
// RTC
// SCL to D1 on NodeMCU
//SDA to D2
//Vcc to Vin
//GND to GND next to Vin pin
// Dot matrix display module
//Vcc to 3v3 pin on NodeMCU
//GND to GND pin next to 3v3 pin
//Din to D7
//CS to D6
//CLK to D5
#include
#include
#include
#define DS3231_I2C_ADDRESS 0x68
int i=0;
int x=0;
int bstflag=0;
int twelve = 0; //variable for 12 hour hour counter
// Convert normal decimal numbers to binary coded decimal
byte decToBcd(byte val)
{
return( (val/10*16) + (val%10) );
}
// Convert binary coded decimal to normal decimal numbers
byte bcdToDec(byte val)
{
return( (val/16*10) + (val%16) );
}
// set up display - data, clock, cs, numdevices
LedControl lc = LedControl(D7,D5,D6,4); //pins for Din, CLK, CS
//matrix table for display
//first element on each row is the bottom row of the display, then rising up through the display
const int num[10][8] = {
//this table positions numbers horizontally on the matrix, from L to R in conjunction with 'setRow' table below
{0x00,0x1e,0x33,0x33,0x33,0x33,0x33,0x1e}, // zero
{0x00,0x3f,0x0c,0x0c,0x0c,0x0c,0x0f,0x0c}, // one
{0x00,0x3f,0x06,0x0c,0x18,0x30,0x33,0x1e}, // two
{0x00,0x1e,0x31,0x30,0x1e,0x30,0x31,0x1e}, // three
{0x00,0x30,0x30,0x7f,0x33,0x32,0x34,0x38}, // four
{0x00,0x1e,0x31,0x30,0x30,0x1f,0x03,0x3f}, // five
{0x00,0x1e,0x33,0x33,0x1f,0x03,0x23,0x1e}, // six
{0x00,0x03,0x06,0x0c,0x18,0x30,0x33,0x3f}, // seven
{0x00,0x1e,0x33,0x33,0x1e,0x33,0x33,0x1e}, // eight
{0x00,0x1e,0x33,0x30,0x3e,0x33,0x33,0x1e} // nine
};
void drawNum(int number, int display)
{
//using setRow instead of setColumn turns all characters on their sides, BUT makes them back to front
//unless used with the horizontal table above
lc.setRow(display, 7, num[number][7]);
lc.setRow(display, 6, num[number][6]);
lc.setRow(display, 5, num[number][5]);
lc.setRow(display, 4, num[number][4]);
lc.setRow(display, 3, num[number][3]);
lc.setRow(display, 2, num[number][2]);
lc.setRow(display, 1, num[number][1]);
lc.setRow(display, 0, num[number][0]);
}
//====================================================================================
void setup()
{
Wire.begin();
Serial.begin(9600);
// power up led matrices
for (i=0; i<4; i++)
{
lc.shutdown(i,false); // come out of powersaving
lc.setIntensity(i,0); // set brightness 0-15
lc.clearDisplay(i); // clear display
}
}
//====================================================================================
void readDS3231time(byte *second,
byte *minute,
byte *hour,
byte *dayOfWeek,
byte *dayOfMonth,
byte *month,
byte *year)
{
Wire.beginTransmission(DS3231_I2C_ADDRESS);
Wire.write(0); // set DS3231 register pointer to 00h
Wire.endTransmission();
Wire.requestFrom(DS3231_I2C_ADDRESS, 7);
// request seven bytes of data from DS3231 starting from register 00h
*second = bcdToDec(Wire.read() & 0x7f);
*minute = bcdToDec(Wire.read());
*hour = bcdToDec(Wire.read() & 0x3f);
*dayOfWeek = bcdToDec(Wire.read());
*dayOfMonth = bcdToDec(Wire.read());
*month = bcdToDec(Wire.read());
*year = bcdToDec(Wire.read());
}
//=======================================================================================
void displayTime()
{
byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
// retrieve data from DS3231
readDS3231time(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month,
&year);
//modify brightness at night
for (i=0; i<4; i++)
{
if ((hour>20) && (hour<8))
{
lc.setIntensity(i,0);
}
else
{
lc.setIntensity(i,5);
}
}
// print hour to led =======================================================
//first set hours to show just 0 in second module after midnight
//change time display for BST/GMT - 'hour' is in 24H format and set for GMT
//first set BST summer time flag for months from April through Septemebr
if ((month>3) && (month<10))
{
bstflag=1;
}
else
{
bstflag=0;
}
// Now set the summer time flag after the last Sunday in March ===============
if ((month==3) && (dayOfMonth>24) && (dayOfWeek==1) && (hour>1))
{
bstflag=1;
}
//and remove the BST flag after the last sunday in October
if ((month==10) && (dayOfMonth>24) && (dayOfWeek==1) && (hour>1))
{
bstflag=0;
}
//from here on use bstflag to increment the displayed hour ====================
//work out display for 12 hour format
hour += bstflag;
if (hour>12)
{
hour -= 12;
}
twelve = hour;
//Serial.println(hour);
//Serial.println(twelve);
if (twelve<10)
{
drawNum(twelve,1); //and write whole hour in second module
}
if (twelve>9)
{
drawNum(twelve/10,0); //write first digit in first module
drawNum(twelve%10,1); //and write whole hour in second module
}
// print minute to led ========================================================
if (minute < 10)
{
drawNum(0,2); //put 0 in module 3
}
else
{
drawNum(minute/10,2); //or put minutes/10 in mod 3
}
drawNum(minute%10,3); //and the rest of the minutes/10 in module 4
}
//================================================================================================
void loop()
{
displayTime(); // display the real-time clock data on the Serial Monitor,
// blinking dot to show we are working
if (x==0)
{
lc.setLed(1, 0, 0, true);// settings are module, row, column where count modules from L to R, rows from bottom to top, columns are R to L
lc.setLed(1, 7, 0, false);
delay(1000); // every second
x=1;
}
else
{
lc.setLed(1, 0, 0, false);
lc.setLed(1, 7, 0, true);
delay(1000); // every second
x=0;
}
}
Same as before, hit the upload button to load it into the Node MCU (it will simply over-write any code that is already running). There is a tiny blue LED on the board that will flicker while it is loading, when it stops and the PC screen says the upload is 100%, you will see the current time on the display. Hooray!
If you don't like the shape of the numbers, you can change the display by altering the values in the table at the beginning of the code above. If you don't know how to do this, here's a clue: its not as simple as it looks :-)