It was my intention to make a video on producing simple PCBs at home on a CNC machine using only CAD and a .DXF to G-Code converter which I had written in Python, but I got very side tracked by JLCPCB. I have taken some time to learn EasyEDA Schematic and board design online software (using Firefox). So far I have had some version 1.0 seven segment LED display module PCBs back, these had an error on because I tried to put some text on to a copper layer which coursed a short circuit between GND and VCC but luckily it was easily fixed with a Stanly knife. I have received the new V1.1 modified boards back and they are now working. I have also mede a version 2.0, which uses twice the amount of LEDS and is now 50X100mm. The boards are based around a 74HC595 shift register and a few LEDs arranged in to a seven segment shape, which can then be chained together to make a multiple number display. For the clock you can use ether four or six together depending on weather it has seconds or not, and maybe a seventh for AM/PM? There is now a third board for the dot between the numbers and uses the power from the dot on the number display next to it.
Version 1.0
Version 2.0
The Seven segment number displays can be used with just an Arduino for any project and can be connected using pin 4 to LAT (latch pin), pin 2 to CLK (clock pin), pin 3 to DAT (data pin), +5 to +5 and GND to GND. You can chain several of these together and the number will keep shifting over to the next digit. This can be tested with the code below.
// ARDUINO SEVEN SEGMENT PCB TEST CODE
// Seven Segment Display PCB Test
// Number Counter - Shift registor
// Status LED test
// Richard Creese October 2019
int latchPin = 4; // ST_CP pin 74HC595
int clockPin = 2; // SH_CP pin 74HC595
int dataPin = 3; // DS pin 74HC595
int LEDPin = 13; // Status LED
byte NUMBER[] = { 238, 6, 124, 62, 150, 186, 250, 38, 254, 182, 246, 218, 232, 94, 248, 240,0 };
void setup() {
pinMode ( latchPin , OUTPUT );
pinMode ( clockPin , OUTPUT );
pinMode ( dataPin , OUTPUT );
pinMode ( LEDPin , OUTPUT );
// Flash status LED five times
for (int i = 0; i <= 4; i++) {
digitalWrite ( LEDPin , HIGH );
delay (500);
digitalWrite ( LEDPin , LOW );
delay (500);
} //NEXT i
} // END setup
void loop() {
for (int i = 0; i <= 15; i++) { // Count to 16 in hexadecimal
digitalWrite ( latchPin , LOW ); // Turn shift register output off
shiftOut ( dataPin , clockPin , MSBFIRST , NUMBER[i] ); // Shift bits out
digitalWrite ( latchPin , HIGH ); // Turn shift register output on
delay(1000); // Wait one second
} // NEXT i
} // END loop
I have designed a clock board module, the same size as the display, based on an ATmega328 and a DS1307 RTC chip. The power supply based on a LM7805 rectifier and can take between 7.5V and 35V, but the higher the voltage the more heat it will produce and will need a heat sink. The module has headers for all the unused pins so you can connect more switches, buzzers etc and any I2c device like a LCD screen. I have designed a V2.0 board that has three switches and a buzzer built in.
To test the DS1307 RTC clock chip I connected the I2C headers to an Arduino (Clock to pin A5 , Data to pin A4, VCC and GND). I used the library MD_DS1307 and the TEST example which talks to the clock using a serial monitor and uses commands like 's' for status and 'tr' for time read, this was also how I set the time. On then version 2 clock you can set the time using the onboard buttons. The clock chip needs a 3V battery so it doesn't forget the time.
Testing the DS1307 RTC using an Arduino with I2c connection. (Version 1 PCB shown)
I have written a simple program to run on the ATMega328 which displays the time and when you press the button on the PCB it shows the date. The program needs to be uploaded on an Arduino because of the USB interface.
Setup used when programing the V1.0 clock PCB so I could keep connected to the Arduino IDE. The Atmega328 is still in the Arduino socket.
Setup used to program the V2.0 clock PCB. The Atmega328 chip now sits on the clocks PCB and the socket on the Arduino remains empty. To connect to the Arduino, TX to TX, RX to RX, GND to GND, +5V to +5V and RESET to RESET. It can now be programmed as if it where a stranded Arduino from its IDE on a PC.
Below is the code to run on the ATMega328 chip for Versions V1.0 and V2.0 of the PCB. Both will run on ether clock but may have reduced functionality. On both press the 'SET' for about half a second to see the date. On V2.0 press and hold the 'SET' button until it beeps, use '+' and '-' to change the hours, then 'SET' to move on to the mins and then the seconds. If you don't press anything for one min it will drop out of time setting without saving any changes. You can download a text file of the code at the bottom of the page which can be pasted into your Arduino IDE.
// DIGITAL CLOCK CODE V1.0
// Digital Clock Code
// Richard Creese
// October 2019
#include <MD_DS1307.h>
#include <Wire.h>
int TENS = 0;
int UNITS = 0;
int YEAR = 2000;
int DOTS = 0;
int latchPin = 4; // ST_CP pin 74HC595
int clockPin = 2; // SH_CP pin 74HC595
int dataPin = 3; // DS pin 74HC595
int LEDPin = 13; // Status LED
int switchPin = 12; // Switch
byte NUMBER[] = { 238, 6, 124, 62, 150, 186, 250, 38, 254, 182, 246, 218, 232, 94, 248, 240,0 };
void setup()
{
// Set pin functions
pinMode ( latchPin , OUTPUT );
pinMode ( clockPin , OUTPUT );
pinMode ( dataPin , OUTPUT );
pinMode ( LEDPin , OUTPUT );
pinMode ( switchPin , INPUT );
digitalWrite ( latchPin , LOW ); // Turn off shift registor output
// Flash status LED five times
for (int i = 0; i <= 4; i++) {
digitalWrite ( LEDPin , HIGH );
delay (250);
digitalWrite ( LEDPin , LOW );
delay (250);
} //NEXT i
// Output numbers for visual check display is working
for (int i = 0; i <= 9; i++) {
digitalWrite ( latchPin , LOW ); // Turn shift registor output off
shiftOut ( dataPin , clockPin , MSBFIRST , NUMBER[i] ); // Shift bits out
digitalWrite ( latchPin , HIGH ); // Turn shift registor output back on
delay (250); // Wait 1/4 second
}
//Serial.begin(57600); // For testing
} // END steup
void printTime()
{
// Print Date on serial monitor
Serial.print("\n");
Serial.print(RTC.yyyy);
Serial.print("-");
Serial.print(RTC.mm);
Serial.print("-");
Serial.print(RTC.dd);
// Print Time on serial monitor
Serial.print(" ");
if (RTC.h < 10) {Serial.print("0");}
Serial.print(RTC.h);
Serial.print(":");
if (RTC.m < 10) {Serial.print("0");}
Serial.print(RTC.m);
Serial.print(":");
if (RTC.s < 10) {Serial.print("0");}
Serial.print(RTC.s);
} // END printTime
void shiftTimeOut(){
DOTS=DOTS+1; // Turn the dots on and off alturnatevly
if ( DOTS >= 2 ){ DOTS = 0 ;}
digitalWrite ( latchPin , LOW ); // Turn shift registor output off
// Shift out hours
TENS = RTC.h / 10;
UNITS = RTC.h % 10;
shiftOut ( dataPin , clockPin , MSBFIRST , NUMBER[TENS] ); // Shift bits out
shiftOut ( dataPin , clockPin , MSBFIRST , NUMBER[UNITS]+DOTS ); // Shift bits out
// Shift out Minuets
TENS = RTC.m / 10;
UNITS = RTC.m % 10;
shiftOut ( dataPin , clockPin , MSBFIRST , NUMBER[TENS] ); // Shift bits out
shiftOut ( dataPin , clockPin , MSBFIRST , NUMBER[UNITS]+DOTS ); // Shift bits out
// Shift out Seconds
TENS = RTC.s / 10;
UNITS = RTC.s % 10;
shiftOut ( dataPin , clockPin , MSBFIRST , NUMBER[TENS] ); // Shift bits out
shiftOut ( dataPin , clockPin , MSBFIRST , NUMBER[UNITS] ); // Shift bits out
digitalWrite ( latchPin , HIGH ); // Turn shift registor output back on
}
void shiftDateOut(){
digitalWrite ( latchPin , LOW ); // Turn shift registor output off
// Shift out Years
YEAR = RTC.yyyy - 2000;
TENS = YEAR / 10;
UNITS = YEAR % 10;
shiftOut ( dataPin , clockPin , MSBFIRST , NUMBER[TENS] ); // Shift bits out
shiftOut ( dataPin , clockPin , MSBFIRST , NUMBER[UNITS] ); // Shift bits out
// Shift out Months
TENS = RTC.mm / 10;
UNITS = RTC.mm % 10;
shiftOut ( dataPin , clockPin , MSBFIRST , NUMBER[TENS] ); // Shift bits out
shiftOut ( dataPin , clockPin , MSBFIRST , NUMBER[UNITS] ); // Shift bits out
// Shift out Day
TENS = RTC.dd / 10;
UNITS = RTC.dd % 10;
shiftOut ( dataPin , clockPin , MSBFIRST , NUMBER[TENS] ); // Shift bits out
shiftOut ( dataPin , clockPin , MSBFIRST , NUMBER[UNITS] ); // Shift bits out
digitalWrite ( latchPin , HIGH ); // Turn shift registor output on
digitalWrite ( LEDPin , HIGH ); // Flash status LED
delay (250); // Wait
digitalWrite ( LEDPin , LOW ); // Status LED off
delay(2000); // Wait 2 seconds
}
void loop()
{
RTC.readTime(); // Read the DS1307 RTC
//printTime(); // Print time/date to serial monitor for testing
shiftTimeOut(); // Display time on Seven Segment Display
if ( digitalRead (switchPin) == HIGH ){ shiftDateOut();} // Display Date
delay(500); // Wait 1/2 second
}
// Digital Clock Code V2.0
// Richard Creese
// October 2020
#include <MD_DS1307.h>
#include <Wire.h>
int TENS = 0;
int UNITS = 0;
int YEAR = 2000;
int DOTS = 0;
unsigned long T = 0;
unsigned long TT = 0;
long DURATION = 0; // variable for the duration of sound wave travel
int DISTANCE = 0; // variable for the distance measurement
int QTY = 0;
int latchPin = 4; // ST_CP pin 74HC595
int clockPin = 2; // SH_CP pin 74HC595
int dataPin = 3; // DS pin 74HC595
int LEDPin = 13; // Status LED
int switchPinMINUS= 12; // Switch '-'
int switchPinSET = 5; // Switch 'SET'
int switchPinPLUS = 6; // Switch '+'
int speakerPin = 9; // Speaker
byte NUMBER[] = { 238, 6, 124, 62, 150, 186, 250, 38, 254, 182, 246, 218, 232, 94, 248, 240,0 };
void setup()
{
// Set pin functions
pinMode ( latchPin , OUTPUT );
pinMode ( clockPin , OUTPUT );
pinMode ( dataPin , OUTPUT );
pinMode ( LEDPin , OUTPUT );
pinMode ( speakerPin , OUTPUT );
pinMode ( switchPinSET , INPUT );
pinMode ( switchPinMINUS, INPUT );
pinMode ( switchPinPLUS , INPUT );
digitalWrite ( latchPin , LOW ); // Turn off shift registor output
// Flash status LED five times
for (int i = 0; i <= 4; i++) {
digitalWrite ( LEDPin , HIGH );
delay (100);
digitalWrite ( LEDPin , LOW );
delay (100);
} //NEXT i
beep();
// Output numbers for visual check display is working
for (int i = 0; i <= 9; i++) {
digitalWrite ( latchPin , LOW ); // Turn shift registor output off
shiftOut ( dataPin , clockPin , MSBFIRST , NUMBER[i] ); // Shift bits out
digitalWrite ( latchPin , HIGH ); // Turn shift registor output back on
delay (250); // Wait 1/4 second
}
//Serial.begin(57600); // For testing
} // END steup
void printTime()
{
// Print Date on serial monitor
Serial.print("\n");
Serial.print(RTC.yyyy);
Serial.print("-");
Serial.print(RTC.mm);
Serial.print("-");
Serial.print(RTC.dd);
// Print Time on serial monitor
Serial.print(" ");
if (RTC.h < 10) {Serial.print("0");}
Serial.print(RTC.h);
Serial.print(":");
if (RTC.m < 10) {Serial.print("0");}
Serial.print(RTC.m);
Serial.print(":");
if (RTC.s < 10) {Serial.print("0");}
Serial.print(RTC.s);
} // END printTime
void shiftTimeOut(){
DOTS=DOTS+1; // Turn the dots on and off alturnatevly
if ( DOTS >= 2 ){ DOTS = 0 ;}
digitalWrite ( latchPin , LOW ); // Turn shift registor output off
// Shift out hours
TENS = RTC.h / 10;
UNITS = RTC.h % 10;
shiftOut ( dataPin , clockPin , MSBFIRST , NUMBER[TENS] ); // Shift bits out
shiftOut ( dataPin , clockPin , MSBFIRST , NUMBER[UNITS]+DOTS ); // Shift bits out
// Shift out Minuets
TENS = RTC.m / 10;
UNITS = RTC.m % 10;
shiftOut ( dataPin , clockPin , MSBFIRST , NUMBER[TENS] ); // Shift bits out
shiftOut ( dataPin , clockPin , MSBFIRST , NUMBER[UNITS]+DOTS ); // Shift bits out
// Shift out Seconds
TENS = RTC.s / 10;
UNITS = RTC.s % 10;
shiftOut ( dataPin , clockPin , MSBFIRST , NUMBER[TENS] ); // Shift bits out
shiftOut ( dataPin , clockPin , MSBFIRST , NUMBER[UNITS] ); // Shift bits out
digitalWrite ( latchPin , HIGH ); // Turn shift registor output back on
}
void shiftDateOut(){
digitalWrite ( latchPin , LOW ); // Turn shift registor output off
// Shift out Day
TENS = RTC.dd / 10;
UNITS = RTC.dd % 10;
shiftOut ( dataPin , clockPin , MSBFIRST , NUMBER[TENS] ); // Shift bits out
shiftOut ( dataPin , clockPin , MSBFIRST , NUMBER[UNITS] ); // Shift bits out
// Shift out Months
TENS = RTC.mm / 10;
UNITS = RTC.mm % 10;
shiftOut ( dataPin , clockPin , MSBFIRST , NUMBER[TENS] ); // Shift bits out
shiftOut ( dataPin , clockPin , MSBFIRST , NUMBER[UNITS] ); // Shift bits out
// Shift out Years
YEAR = RTC.yyyy - 2000;
TENS = YEAR / 10;
UNITS = YEAR % 10;
shiftOut ( dataPin , clockPin , MSBFIRST , NUMBER[TENS] ); // Shift bits out
shiftOut ( dataPin , clockPin , MSBFIRST , NUMBER[UNITS] ); // Shift bits out
digitalWrite ( latchPin , HIGH ); // Turn shift registor output on
digitalWrite ( LEDPin , HIGH ); // Flash status LED
delay (2000); // Wait 2 seconds
digitalWrite ( LEDPin , LOW ); // Status LED off
} // end shiftdateout
void beep()
{
digitalWrite ( speakerPin , HIGH );
delay (50);
digitalWrite ( speakerPin , LOW );
} // end beep
void settings()
{
for (int i = 0; i <= 4; i++) { beep(); delay (100); }
delay (1000); // wait 1 second for 'SET' button to be released
byte MAXV[] = { 0, 23,59,59 }; // Filler , Hours , Mins , Secs
byte MINV[] = { 0,0,0,0 };
int V = 0; // value
byte opp = 1;
byte old = 1;
T = millis();
while ( opp < 4 ) { // Loop around all setting operations
switch ( opp ){ // Load current data form clock chip
case 1: // Hours
V = RTC.h, DEC;
break;
case 2: // Mins
V = RTC.m, DEC;
break;
case 3: // Seconds
V = 0;
break;
}
while ( digitalRead ( switchPinSET ) == LOW ){ // Loop until 'SET' is pressed again
TT = millis(); // If nothing happens for sixty seconds then finish setting without saving
if ( TT - T >= 60000 ) { old = 100; opp = 100; break;}
switch ( old ) { // old = opp when something changes otherwise old = 100 and will not refresh display
case 1: // Display Hours
TENS = V / 10;
UNITS = V % 10;
digitalWrite ( latchPin , LOW ); // Turn shift registor output off
shiftOut ( dataPin , clockPin , MSBFIRST , NUMBER[TENS] ); // Shift bits out
shiftOut ( dataPin , clockPin , MSBFIRST , NUMBER[UNITS] ); // Shift bits out
shiftOut ( dataPin , clockPin , MSBFIRST , 16 ); // Shift bits out
shiftOut ( dataPin , clockPin , MSBFIRST , 16 ); // Shift bits out
shiftOut ( dataPin , clockPin , MSBFIRST , 16 ); // Shift bits out
shiftOut ( dataPin , clockPin , MSBFIRST , 16 ); // Shift bits out
digitalWrite ( latchPin , HIGH ); // Turn shift registor output on
old = 100;
break;
case 2: // Display mins
TENS = V / 10;
UNITS = V % 10;
digitalWrite ( latchPin , LOW ); // Turn shift registor output off
shiftOut ( dataPin , clockPin , MSBFIRST , 16 ); // Shift bits out
shiftOut ( dataPin , clockPin , MSBFIRST , 16 ); // Shift bits out
shiftOut ( dataPin , clockPin , MSBFIRST , NUMBER[TENS] ); // Shift bits out
shiftOut ( dataPin , clockPin , MSBFIRST , NUMBER[UNITS] ); // Shift bits out
shiftOut ( dataPin , clockPin , MSBFIRST , 16 ); // Shift bits out
shiftOut ( dataPin , clockPin , MSBFIRST , 16 ); // Shift bits out
digitalWrite ( latchPin , HIGH ); // Turn shift registor output on
old = 100;
break;
case 3: // Display seconds
TENS = V / 10;
UNITS = V % 10;
digitalWrite ( latchPin , LOW ); // Turn shift registor output off
shiftOut ( dataPin , clockPin , MSBFIRST , 16 ); // Shift bits out
shiftOut ( dataPin , clockPin , MSBFIRST , 16 ); // Shift bits out
shiftOut ( dataPin , clockPin , MSBFIRST , 16 ); // Shift bits out
shiftOut ( dataPin , clockPin , MSBFIRST , 16 ); // Shift bits out
shiftOut ( dataPin , clockPin , MSBFIRST , NUMBER[TENS] ); // Shift bits out
shiftOut ( dataPin , clockPin , MSBFIRST , NUMBER[UNITS] ); // Shift bits out
digitalWrite ( latchPin , HIGH ); // Turn shift registor output on
old = 100;
break;
case 100: // Do nothing
// do nothing
break;
} // end switch
// code to change numbers here
if ( digitalRead (switchPinPLUS) == HIGH ){ // 'PLUS' button pressed?
old = opp;
V = V + 1;
if ( V > MAXV[opp] ) { V = MINV[opp];}
delay (250);
T = millis();
}
if ( digitalRead (switchPinMINUS) == HIGH ){ // 'MINUS' button pressed?
old = opp;
V = V - 1;
if ( V < MINV[opp] ) { V = MAXV[opp];}
delay (250);
T = millis();
}
} // end while. 'SET' button not pressed yet so round we go again
switch ( opp ){ // Save new time data to clock chip
case 1: // Hours
RTC.h = V;
break;
case 2: // Mins
RTC.m = V;
break;
case 3: // Seconds
RTC.s = V;
RTC.writeTime();
break;
} // End Switch
beep();
opp++;
old = opp;
delay (500); // wait half second for 'SET' button to be released
}// end while opp
} // end settings
void loop()
{
RTC.readTime(); // Read the DS1307 RTC
//printTime(); // Print time/date to serial monitor for testing
shiftTimeOut(); // Display time on Seven Segment Display
if ( digitalRead (switchPinSET) == HIGH ) // 'SET' button pressed?
{ shiftDateOut(); // Display Date
if ( digitalRead (switchPinSET) == HIGH ) { settings(); }; // 'SET' button still being pressed?
}
delay(500); // Wait 1/2 second
} // end loop
PCB - Gerber files at bottom of page
DS1307 RTC IC (U1)
ATmega328p-pu Microcontroler IC (U2)
LM7805 Power Regulator (U3)
32.768 KHz Crystal (X1)
16 MHz crystal (X2)
Capacitor 22uf 2off (C1-2)
Capacitor 470uf (C3)
Capacitor 1uf (C4)
Resistor 10K 3off (R1 R2 R4) Version 1
Resistor 10K 5off (R1 R2 R4 R5 R6) Version 2
Resistor 1K 2off (R3 R5)
LED Green 5mm (LED1)
LED Red 5mm (LED2)
Diode 1N4007 (D1)
Barrel Power Connector (J1)
Switch Button 6X6X6 1off (SW1) Version 1
Switch Button 6X6X6 3off (SW1-SW3) Version 2
Battery Holder CR2032 (B1)
Buzzer Version 2
Headers Male as required (H1-H5 P1)
PCB - Gerber files at bottom of page
74HC595 Shift Register IC (U1)
1K Resistor 8off (R1-R8) Version 1
1K Resistor 15off (R1-R16) Version 2
LED Red 5mm 15 or 16off (LED1-LED17) Version 1
LED Red 5mm 29 or 31off (LED1-LED31) Version 2
Male / Female Header pins (H1-H2) as required
Downloads for this project versions V1.0 and V2.0.
Programs as a .txt file, Schematics as a .pdf file and Gerber .zip files for the PCBs.
Seven Segment Display Schematic V1.0 .pdf
Seven Segment Display Gerber V1.1 .zip
Clock module Schematic V1.0 .pdf
Clock code AtMega328 / Arduino V1.0 .txt
Seven Segment Display Schmatic V2.0 .pdf
Seven Segment Display Gerber V2.0 .zip