//Program name:
//Filename:
//Description:
//Version: 24September 2024
//Copyright: Mallari/Manadong, DENSO Techno Philippines, Inc.
#include <LiquidCrystal.h>
#include <avr/wdt.h> // For Watchdog timer
#define MAXCOUNT 20.0
#define ZEROSEC 0.0
#define TENTHCOUNT 10
#define COUNTER 0.1
#define STARTUPDELAY 2000 // 2 seconds delay for the startup message
//Initialize the LCD pins (RS, EN, D4, D5, D6, D7)
const int RS = 12;
const int EN = 11;
const int D4 = 10;
const int D5 = 8;
const int D6 = 7;
const int D7 = 6;
LiquidCrystal lcd(RS, EN, D4, D5, D6, D7);
volatile float countValue= 0.0;
volatile unsigned long wait_time_ms = 0; // Wait time in ms (incremented by Button 4)
volatile unsigned int wait_exec_count = 0; // Number of wait executions
volatile bool countingDown = false;
volatile bool countingUp = false;
volatile bool countStop = true;
volatile bool countWD = true;
//Pin definitions
const int pushButton1 = 5; //Button connected to pin 5 (count up)
const int pushButton2 = 4; //Button connected to pin 4 (count down)
const int pushButton3 = 3; //Button connected to pin 3 (stop/reset)
const int pushButton4 = 2; //Button connected to pin 2 (wait time increase in timer interrupt processing)
bool button1Pressed = 0;
bool button2Pressed = 0;
bool button3Pressed = 0;
bool button4Pressed = 0;
String status[] = {"COUNT_UP", "COUNT_DOWN", "STOP"};
void handleCountUp();
void handleCountDown();
void updateDisplay();
void displayWD();
//Function name: setup()
//Description: Initializes the Arduino, sets pin modes, initializes the LCD,
// displays the startup message, and sets up Timer1 for interrupts.
//Input: None
//Output: None
//Copyright: Mallari/Manadong, DENSO Techno Philippines, Inc.
void setup() {
Serial.begin(9600);
//To help monitor when the watchdog timer resets
lcd.begin(16, 2);
lcd.setCursor(3, 0);
lcd.print("STOPWATCH");
delay(STARTUPDELAY);
lcd.clear();
//Set button pins as input
DDRD &= ~(1 << DDD5); // Set Pin 5 as input
DDRD &= ~(1 << DDD4); // Set Pin 4 as input
DDRD &= ~(1 << DDD3); // Set Pin 3 as input
DDRD &= ~(1 << DDD2); // Set Pin 2 as input (not used for this exercise yet)
PORTD |= (1 << PORTD5); // Pull up for pin 5
PORTD |= (1 << PORTD4); // Pull up for pin 4
PORTD |= (1 << PORTD3); // Pull up for pin 3
PORTD |= (1 << PORTD2); // Pull up for pin 2
// Timer1 setup
noInterrupts();
TCCR1A = 0;
TCCR1B = 0;
TCCR1B |= 0x05; // Prescaler 1024
OCR1A = 1562; // 100ms
TCCR1B |= (1 << WGM12); // CTC mode
TIMSK1 |= (1 << OCIE1A); // Enable Timer1 interrupt
interrupts();
// Watchdog Timer setup (250ms timeout)
wdt_enable(WDTO_250MS);
// Initial state
updateDisplay();
countValue= 0.0;
wait_exec_count = 0;
}
//Function name: loop()
//Description: Main logic of the program and where the functions for each pushbutton were handled
//Input: None
//Output: None
//Copyright: Mallari/Manadong, DENSO Techno Philippines, Inc.
void loop() {
button1Pressed = !(PIND & (1 << PIND5)); // Check if button on pin 5 is pressed
button2Pressed = !(PIND & (1 << PIND4)); // Check if button on pin 4 is pressed
button3Pressed = !(PIND & (1 << PIND3)); // Check if button on pin 3 is pressed
button4Pressed = !(PIND & (1 << PIND2)); // Check if button on pin 2 is pressed
if (button1Pressed) {
if (countStop) {
countingUp = true;
countingDown = false;
countStop = false;
}
}
if (button2Pressed) {
if (countStop) {
countingDown = true;
countingUp = false;
countStop = false;
}
}
if (button3Pressed) {
if (!countStop) {
countStop = true;
}
else {
countValue = ZEROSEC;
}
updateDisplay();
}
if (button4Pressed) {
wait_exec_count++;
updateDisplay();
}
// Simulated delay according to wait_exec_count
for (unsigned int i = 0; i < wait_exec_count; i++) {
delay(60);
}
// Reset watchdog timer
wdt_reset();
}
//Function name: ISR(TIMER1_COMPA_vect)
//Description: Interrupt Service Routine (ISR) for Timer1. This function is triggered every 100ms
// when Timer1 reaches the set compare value. It checks if counting is active and
// updates the count value by calling the appropriate function (handleCountUp or handleCountDown).
//Input: None (triggered by Timer1 interrupt)
//Output: Updates the count value and sends the updated information to the LCD.
//Copyright: Mallari/Manadong, DENSO Techno Philippines, Inc.
ISR(TIMER1_COMPA_vect) {
if (!countStop) {
if (countingUp) {
handleCountUp();
}
else if (countingDown) {
handleCountDown();
}
}
wait_time_ms = wait_exec_count * 60;
displayWD();
}
//Function name: handleCountUp()
//Description: Increments the countValue by COUNTER each time it's called, up to MAXCOUNT.
// Stops the counting when MAXCOUNT is reached.
//Input: None
//Output: None
//Copyright: Mallari/Manadong, DENSO Techno Philippines, Inc.
void handleCountUp() {
countValue += COUNTER;
if (countValue >= MAXCOUNT) {
countStop = true;
countValue = MAXCOUNT;
}
updateDisplay();
}
//Function name: handleCountDown()
//Description: Decrements the countValue by COUNTER each time it's called, down to ZEROSEC.
// Stops the counting when ZEROSEC is reached.
//Input: None
//Output: None
//Copyright: Mallari/Manadong, DENSO Techno Philippines, Inc.
void handleCountDown() {
countValue -= COUNTER;
if (countValue <= ZEROSEC) {
countStop = true;
countValue = ZEROSEC;
}
updateDisplay();
}
//Function name: updateDisplay()
//Description: Updates the LCD with the current stopwatch status (counting up, counting down, or stopped)
// and displays the countValue and wait time.
//Input: None
//Output: None
//Copyright: Mallari/Manadong, DENSO Techno Philippines, Inc.
void updateDisplay() {
lcd.clear();
if (countStop) {
lcd.setCursor(0, 0);
lcd.print(status[2]);
}
else if (countingUp) {
lcd.setCursor(0, 0);
lcd.print(status[0]);
}
else if (countingDown) {
lcd.setCursor(0, 0);
lcd.print(status[1]);
}
lcd.setCursor(0, 1);
if (countValue < 10) {
lcd.print("0");
}
lcd.print(countValue, 1);
lcd.print("s");
lcd.setCursor(6, 2);
lcd.print("Wait:");
}
//Function name: displayWD()
//Description: Updates the LCD with the wait ms
//Input: None
//Output: None
//Copyright: Mallari/Manadong, DENSO Techno Philippines, Inc.
void displayWD() {
lcd.setCursor(11, 2);
lcd.print(wait_time_ms);
lcd.print("ms");
}