I am trying to make a stop watch that displays minutes and seconds, and after reaching 59,59, I want it to display hours and minutes. Then it also has a start and reset button. The set button starts the time, and if you press it again you pause the time, and if you press the reset button it resets the time. I have also attached LED's that will light up when certain hours are crossed. The issue I am having is that the display isn't displaying fast enough, it is flickering even though the delay I set for the screen is small enough, I have a common cathode 4 digit 7 segment display.
Connections:
Arduino 8, 9, 10 to 595 14, 12, 11 respectively.
595 1, 2, 3, 4, 5, 6, 7, 15 to display B, C, D, E, F, G, DP, A
595 8 goes to 595 13, which is connected to ground
The Cathodes are connected to 13,12,11, and 6 in the arduino through a resistor.
And my LED's are connected to 2, 3, 4 on the arduino.
My buttons start and reset are connected to 7 and 5 respectively.
Here is an image of what it looks like without the buttons and LED's
Here is my code that I have so far:
//Buzzer
int buzzer = 12; //the pin of active buzzer
//Register
int latch=9; //74HC595 pin 9 STCP
int clock=10; //74HC595 pin 10 SHCP
int data=8; //74HC595 pin 8 DS
//Lights
int red = 2; //the pin of red light
int yellow = 3; //the pin of the yellow light
int green = 4; //the pin of the green light
//Buttons
int start = 7; //the pin of start button
int reset = 5; //the pin of start button
//digits
int first = 0;
int second = 0;
int third = 0;
int fourth = 0;
//Hexadecimal Values for 0-9 for 7 Segment Display
unsigned char segmentTable[] = {
0x3F, // 0
0x06, // 1
0x5B, // 2
0x4F, // 3
0x66, // 4
0x6D, // 5
0x7D, // 6
0x07, // 7
0x7F, // 8
0x6F // 9
};
unsigned char tableWithDP[] = {
0xBF, // 0 with DP
0x86, // 1 with DP
0xDB, // 2 with DP
0xCF, // 3 with DP
0xE6, // 4 with DP
0xED, // 5 with DP
0xFD, // 6 with DP
0x87, // 7 with DP
0xFF, // 8 with DP
0xEF // 9 with DP
};
const int digitPins[] = {6, 11, 12, 13};
// Variables to track time
unsigned long previousMillis = 0; // Stores the last time update occurred
unsigned long currentMillis = 0;
int seconds = 0; // Total seconds elapsed
int minutes = 0;
int hours = 0;
// Variables for refresh timing
unsigned long lastRefreshTime = 0;
const int refreshInterval = 1000; // Refresh interval in microseconds (~1ms)
int currentDigit = 0;
// Function prototypes
void displayDigit(int number, int digitIndex);
void updateTime();
void setup() {
// put your setup code here, to run once:
pinMode(buzzer, OUTPUT);
pinMode(latch,OUTPUT);
pinMode(clock,OUTPUT);
pinMode(data,OUTPUT);
pinMode(red, OUTPUT);
pinMode(yellow, OUTPUT);
pinMode(green, OUTPUT);
pinMode(start, INPUT);
pinMode(reset, INPUT);
// Initialize digit select pins
for (int i = 0; i < 4; i++) {
pinMode(digitPins[i], OUTPUT);
digitalWrite(digitPins[i], HIGH); // Turn off all digits initially
}
}
void loop() {
// put your main code here, to run repeatedly:
static int startPressed = 0;
int resetPressed = 0;
while(startPressed == 0){
int displayDigits[] = {0, 0, 0, 0};
/*for (int i = 0; i < 4; i++) {
// Display one digit at a time
displayDigit(displayDigits[i], i);
delay(5); // Small delay for persistence of vision
}*/
if((digitalRead(start)==HIGH)){
startPressed = 1;
}
}
long int t1 = millis();
while((digitalRead(start)==LOW)&&(startPressed==1)&&(resetPressed==0)){
int displayDigits[] = {first, second, third, fourth};
updateLights(second);
// Update time every second
currentMillis = millis();
if (currentMillis - previousMillis >= 1000) { // Check if 1 second has passed
previousMillis = currentMillis;
updateTime(); // Increment time
}
for (int i = 0; i < 4; i++) {
// Display one digit at a time
displayDigit(displayDigits[i], i);
delay(50); // Small delay for persistence of vision
}
// Multiplexing: Update display at high speed
if (micros() - lastRefreshTime >= refreshInterval) {
lastRefreshTime = micros();
// Determine what to display
int displayDigits[4];
if (hours == 0) {
// Display MM:SS (minutes and seconds)
displayDigits[0] = minutes / 10;
displayDigits[1] = minutes % 10;
displayDigits[2] = seconds / 10;
displayDigits[3] = seconds % 10;
} else {
// Display HH:MM (hours and minutes)
displayDigits[0] = hours / 10;
displayDigits[1] = hours % 10;
displayDigits[2] = minutes / 10;
displayDigits[3] = minutes % 10;
}
// Display the current digit
displayDigit(displayDigits[currentDigit], currentDigit);
// Move to the next digit
currentDigit = (currentDigit + 1) % 4;
}
if(digitalRead(reset)==HIGH){
resetPressed = 1;
}
updateLights(second);
}
//start button already pressed and pressed again - stops timer
while((startPressed==1)&&(resetPressed==0)){
if(digitalRead(reset)==HIGH){
resetPressed = 1;
}
if(digitalRead(start)==HIGH) {break;};
}
//reset button pressed - resets timer and startPressed
if(resetPressed == 1){
seconds = 0;
minutes = 0;
hours = 0;
}
}
void displayDigit(int number, int digitIndex) {
// Turn off all digits
for (int i = 0; i < 4; i++) {
digitalWrite(digitPins[i], HIGH);
}
// Send segment data for the number to the shift register
if(digitIndex==1){
shiftOut(data, clock, MSBFIRST, tableWithDP[number]);
} else {
shiftOut(data, clock, MSBFIRST, segmentTable[number]);
}
// Latch the data to display it
digitalWrite(latch, LOW);
digitalWrite(latch, HIGH);
// Enable the current digit
digitalWrite(digitPins[digitIndex], LOW);
}
// Function to update the time
void updateTime() {
seconds++;
if (seconds == 60) {
seconds = 0;
minutes++;
}
if (minutes == 60) {
minutes = 0;
hours++;
}
if (hours == 100) {
// Reset to zero after 99 hours (to fit display)
hours = 0;
}
}
void updateLights(int hours){
if(hours == 8){
digitalWrite(red, HIGH);
} else if(hours > 5){
digitalWrite(yellow, HIGH);
} else{
digitalWrite(green, HIGH);
}
}
Here is what chatgpt has given me instead, which is working slightly better but it is still flickering:
//Buzzer
int buzzer = 12; //the pin of active buzzer
//Register
int latch=9; //74HC595 pin 9 STCP
int clock=10; //74HC595 pin 10 SHCP
int data=8; //74HC595 pin 8 DS
//Lights
int red = 2; //the pin of red light
int yellow = 3; //the pin of the yellow light
int green = 4; //the pin of the green light
//Buttons
int start = 7; //the pin of start button
int reset = 5; //the pin of start button
//digits
int first = 0;
int second = 0;
int third = 0;
int fourth = 0;
//Hexadecimal Values for 0-9 for 7 Segment Display
unsigned char segmentTable[] = {
0x3F, // 0
0x06, // 1
0x5B, // 2
0x4F, // 3
0x66, // 4
0x6D, // 5
0x7D, // 6
0x07, // 7
0x7F, // 8
0x6F // 9
};
unsigned char tableWithDP[] = {
0xBF, // 0 with DP
0x86, // 1 with DP
0xDB, // 2 with DP
0xCF, // 3 with DP
0xE6, // 4 with DP
0xED, // 5 with DP
0xFD, // 6 with DP
0x87, // 7 with DP
0xFF, // 8 with DP
0xEF // 9 with DP
};
const int digitPins[] = {6, 11, 12, 13};
// Variables to track time
unsigned long previousMillis = 0; // Stores the last time update occurred
unsigned long currentMillis = 0;
int seconds = 0; // Total seconds elapsed
int minutes = 0;
int hours = 0;
// Variables for refresh timing
unsigned long lastRefreshTime = 0;
const int refreshInterval = 100; // Refresh interval in microseconds (~1ms)
int currentDigit = 0;
// Function prototypes
void displayDigit(int number, int digitIndex);
void updateTime();
void setup() {
// put your setup code here, to run once:
pinMode(buzzer, OUTPUT);
pinMode(latch,OUTPUT);
pinMode(clock,OUTPUT);
pinMode(data,OUTPUT);
pinMode(red, OUTPUT);
pinMode(yellow, OUTPUT);
pinMode(green, OUTPUT);
pinMode(start, INPUT);
pinMode(reset, INPUT);
// Initialize digit select pins
for (int i = 0; i < 4; i++) {
pinMode(digitPins[i], OUTPUT);
digitalWrite(digitPins[i], HIGH); // Turn off all digits initially
}
}
unsigned long previousMillisDisplay = 0; // Tracks last refresh time
const int digitRefreshInterval = 2; // Refresh each digit every 2 ms
// Current digit being displayed
void loop() {
static int startPressed = 0;
int resetPressed = 0;
// Wait for start button press
while (startPressed == 0) {
int displayDigits[] = {0, 0, 0, 0}; // Default display: 0000
multiplexDisplay(displayDigits); // Refresh display smoothly
if (digitalRead(start) == HIGH) {
startPressed = 1;
}
}
// Stopwatch is running
while ((digitalRead(start) == LOW) && (startPressed == 1) && (resetPressed == 0)) {
// Update time every second
currentMillis = millis();
if (currentMillis - previousMillis >= 1000) {
previousMillis = currentMillis;
updateTime(); // Increment time
updateLights(hours); // Update lights
}
// Determine digits to display
int displayDigits[4];
if (hours == 0) {
// Display MM:SS
displayDigits[0] = minutes / 10;
displayDigits[1] = minutes % 10;
displayDigits[2] = seconds / 10;
displayDigits[3] = seconds % 10;
} else {
// Display HH:MM
displayDigits[0] = hours / 10;
displayDigits[1] = hours % 10;
displayDigits[2] = minutes / 10;
displayDigits[3] = minutes % 10;
}
// Refresh the display smoothly
multiplexDisplay(displayDigits);
// Check for reset button
if (digitalRead(reset) == HIGH) {
resetPressed = 1;
}
}
while((startPressed==1)&&(resetPressed==0)){
if(digitalRead(reset)==HIGH){
resetPressed = 1;
}
if(digitalRead(start)==HIGH) {break;};
}
// Reset or pause logic
if (resetPressed == 1) {
seconds = 0;
minutes = 0;
hours = 0;
startPressed = 0; // Reset stopwatch
}
}
// Function for non-blocking display multiplexing
void multiplexDisplay(int displayDigits[]) {
unsigned long currentMillisDisplay = millis();
// Check if it's time to update the next digit
if (currentMillisDisplay - previousMillisDisplay >= digitRefreshInterval) {
previousMillisDisplay = currentMillisDisplay;
// Turn off all digits
for (int i = 0; i < 4; i++) {
digitalWrite(digitPins[i], HIGH);
}
// Send segment data for the current digit
if (currentDigit == 1) {
shiftOut(data, clock, MSBFIRST, tableWithDP[displayDigits[currentDigit]]);
} else {
shiftOut(data, clock, MSBFIRST, segmentTable[displayDigits[currentDigit]]);
}
// Latch the data to the shift register
digitalWrite(latch, LOW);
digitalWrite(latch, HIGH);
// Enable the current digit
digitalWrite(digitPins[currentDigit], LOW);
// Move to the next digit
currentDigit = (currentDigit + 1) % 4;
}
}
void displayDigit(int number, int digitIndex) {
// Turn off all digits
for (int i = 0; i < 4; i++) {
digitalWrite(digitPins[i], HIGH);
}
// Send segment data for the number to the shift register
if(digitIndex==1){
shiftOut(data, clock, MSBFIRST, tableWithDP[number]);
} else {
shiftOut(data, clock, MSBFIRST, segmentTable[number]);
}
// Latch the data to display it
digitalWrite(latch, LOW);
digitalWrite(latch, HIGH);
// Enable the current digit
digitalWrite(digitPins[digitIndex], LOW);
}
// Function to update the time
void updateTime() {
seconds++;
if (seconds == 60) {
seconds = 0;
minutes++;
}
if (minutes == 60) {
minutes = 0;
hours++;
}
if (hours == 100) {
// Reset to zero after 99 hours (to fit display)
hours = 0;
}
}
void updateLights(int hours){
if(hours == 8){
digitalWrite(red, HIGH);
digitalWrite(yellow, LOW);
digitalWrite(green, LOW);
} else if(hours > 5){
digitalWrite(red, LOW);
digitalWrite(yellow, HIGH);
digitalWrite(green, LOW);
} else{
digitalWrite(red, LOW);
digitalWrite(yellow, LOW);
digitalWrite(green, HIGH);
}
}