Double Kitchen Timer

Overview

A wooden box with a silver number keypad on the left, and a small LCD display, with a switch and two red buttons underneath.

This is a dual kitchen timer designed for me and my roommates to be able to more efficiently spend time cooking together while simultaneously not driving each other up the wall with our different alarm noises. It toggles between two timers which function independently and can be set for up to 99 hours for a really complicated sourdough project.

Detail Images of Final Double Kitchen Timer

A close up image of timer. A blue LCD screen is lit up displaying the text: "Set Timer 2: 00:00:01."

The powered on "Set  Mode" Screen for Timer 2.

A front on view of a wooden box with a timer, lcd screen, buttons and a switch. The LCD screen is powered off.

A front view of the timer powered off.

The back of the box. It is a sheet of cardboard with a semicircle cutout at the bottom through which the Arduino power connections can be seen.

The back of the box, with a cutout for both the power supply and an computer cable if necessary.

Video of the Double Kitchen Timer

Double Kitchen Timer.mp4

Process Images and Review

A solderless breadboard with a potentiometer, as well as various wires plugging into a second breadboard connected to an LCD screen and an Arduino board.

An earlier prototype which was going to use a potentiometer for alarm selection, a rotary encoder (not pictured) to set the time and a real time clock.

A silver number keypad sits on a white table. There are wires attached to the top connected to an Arduino Uno board.

The beginnings of trying to get the keypad to work! This image was taken right after I soldered the wires to the keypad and started trying to figure out how they connected.

Two breadboards sit on a white table. A number of colorful wires connected to a LCD screen, a numeric keyboard and a switch.

Nearing the assembly stage, this was most of the final circuit used for the timer. In this stage it was mostly a code troubleshooting time.

A back view of the open machine. Two breadboards and an arduino sit on a wooden base, which is connected to a front panel. The backs of various electrical components are displayed.

The beginning of the final assembly of the box and related components. I spent a bit of time trying to figure out how to fit everything in the box.

There were two major aspects of the project that took longer than expected - one was the wiring of the keypad and the other was a few rounds of debugging with the timer library. The first one - the wiring of the keypad, was an exercise in reading the documentation and very carefully plugging in each wire to the correct pin. The second was a number of hiccups in the timer library I used, one which counted a minute as a second - for a reason that took me about 4 days to figure out. It took combing through documentation of the library and example code with Zach to finally realize a small function which I had skipped when initializing the timer was essential to making it work as needed. Both of these were excellent learning experiences in that they taught me a specific and important lesson about code and hardware debugging.

Discussion

I am very happy with how my project is in its current state. This ended up being a challenge on both the code and physical construction aspects of the project and I learned a lot throughout the entire project. The feedback I got during the class critique was generally pretty positive and gave me some great ideas for how to continue iterating on this project in the future. One of the ideas that I’m thinking about implementing is one which said “it would be cool if there was some kind of whiteboard/label surface to mark whose timer is whose,” which I think could be a very useful addition. One of my favorite comments was one which said “This might be the most efficient way to fix the friendship issue,” because it really hit with the problem I was trying to assist in my day-to-day life, and I’m glad it was communicated well with the class.

I learned a lot about my speed and accuracy of building prototypes for this project - I noticed that sometimes I can rush which can lead to mistakes which take more time to rewire - correcting the wiring of the keypad being the biggest example. This project ended up being a pretty heavy code lift, and one of my biggest challenges ended up being a bug with the timer library I used which was only solved with very careful comparison against an example sketch from the library. After getting really stuck on the code and that stopped me from laser cutting more than once - and that resulted in a box that really didn’t fit a lot of the components super well (although I think it worked out alright in the end). In the future I’m definitely going to start my physical prototype earlier.

I am hoping to build a second more practical iteration of this project with the following changes - firstly, making a new casing that fits a little bit better out of acrylic (wood in a kitchen doesn’t fully sit right with me) - and secondly making the buzzer sound for the two alarms different in order to better distinguish the alarms. If I have unlimited time I also want to add a little Mario Kart track on top that has characters running a race and finishing with the timer, but that’s more of a fun cosmetic effect for my roommates and I. This project was a really enjoyable learning experience for me, and I’m excited to continue building my skills in project 3.

Technical Information

Block Diagram

A block diagram of the double kitchen timer.

Electrical Schematic

An electrical schematic on a white background.

Code

// Double Kitchen Timer

// By Gemma Tait


// Code Purpose:

// Runs a LCD screen which displays two independent timers.

// These timers are set by the edit button followed by a keypad entry.

// There is a start button which triggers each timer depending on switch position.


// Pin Map:

// Pin Number | Type   | Connection

// 2          | INPUT  | Keypad Pin 4

// 3          | INPUT  | Keypad Pin 2

// 4          | INPUT  | Keypad Pin 1

// 5          | INPUT  | Keypad Pin 6

// 6          | INPUT  | Keypad Pin 3

// 7          | INPUT  | Keypad Pin 7

// 8          | INPUT  | Keypad Pin 5

// 9          | INPUT  | Button (Used for Start Function)

// 10         | OUTPUT | Passive Buzzer

// 11         | INPUT  | Button (Used for Edit Function)

// 12         | INPUT  | Analog Switch

// SCL        | OUTPUT | LCD Screen SDA

// SDA        | OUTPUT | LCD Screen SCL


//Libraries Used

#include <Keypad.h>

#include "Countimer.h"

#include <LiquidCrystal_I2C.h>


// LCD Screen Setup

LiquidCrystal_I2C screen(0x27, 16, 2);


// Timer setup

Countimer timer1;

Countimer timer2;


// Keyboard Setup

const byte ROWS = 4;  //four rows

const byte COLS = 3;  //three columns


char keys[ROWS][COLS] = {

 { '1', '2', '3' },

 { '4', '5', '6' },

 { '7', '8', '9' },

 { '*', '0', '#' }

};

byte rowPins[ROWS] = { 2, 3, 4, 5 };  //connect to the row pinouts of the kpd

byte colPins[COLS] = { 6, 7, 8 };     //connect to the column pinouts of the kpd


Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);


void setup() {

 // put your setup code here, to run once:

 Serial.begin(9600);

 // Analog Switch

 pinMode(12, INPUT);

 // Button (Edit)

 pinMode(11, INPUT);

 // Passive Buzzer

 pinMode(10, OUTPUT);

 // Button (Start/Stop)

 pinMode(9, INPUT);


 // Setting a default time of 10 min for the timers

 timer1.setCounter(0, 0, 0, timer1.COUNT_DOWN, nothing);

 timer2.setCounter(0, 0, 0, timer2.COUNT_DOWN, nothing);


 // Setting timer update intervals for once every second

 timer1.setInterval(get_clock_time, 1000);

 timer2.setInterval(get_clock_time, 1000);


 // LCD initialization

 screen.init();

 screen.backlight();

 screen.home();

 screen.setCursor(0, 0);

 screen.print("Timer 1:");

 screen.setCursor(8, 0);

 screen.print(timer1.getCurrentTime());

 screen.setCursor(0, 1);

 screen.print("Timer 2:");

 screen.setCursor(8, 1);

 screen.print(timer2.getCurrentTime());

}


void loop() {

 timer1.run();

 timer2.run();

 // int times_through = 0;

 // if edit button pressed start edit mode (will affect whichever alarm the switch is toggled to in the moment)

 if (digitalRead(11) == HIGH) {

   alarm_set();

 }

 // if start button is pressed, whichever alarm is toggled via switch will start.

 if (digitalRead(9) == HIGH) {

   if (digitalRead(12) == HIGH) {

     if (timer1.isStopped()) {

       timer1.start();

     }

   }

   if (digitalRead(12) == LOW) {

     if (timer2.isStopped()) {

       timer2.start();

     }

   }

 }

}


void start_timer1() {

 timer1.start();

}



void get_clock_time() {

 screen.setCursor(0, 0);

 screen.print("Timer 1:");

 screen.setCursor(8, 0);

 screen.print(timer1.getCurrentTime());

 screen.setCursor(0, 1);

 screen.print("Timer 2:");

 screen.setCursor(8, 1);

 screen.print(timer2.getCurrentTime());

}


void nothing() {

 //nothing! just in here as a filler so nothing is triggered in initialization.

}



void buzz() {

 digitalWrite(10, HIGH);

 delay(10);

 digitalWrite(10, LOW);

 digitalWrite(10, HIGH);

 delay(10);

 digitalWrite(10, LOW);

 digitalWrite(10, HIGH);

 delay(10);

 digitalWrite(10, LOW);

 digitalWrite(10, HIGH);

 delay(10);

 digitalWrite(10, LOW);

}


void alarm_set() {

 // establishes integers needed for the implentation of the code

 int button_press = 0;

 int entered_val = 0;

 int current_val = 0;

 int digit_in = 0;

 int time_pass = 0;

 int sec = 0;

 int min = 0;

 int hrs = 0;


 // sets screen cleared/in timer mode.

 screen.clear();

 if (digitalRead(12) == HIGH) {

   screen.print("Set Timer 1:");

 }

 if (digitalRead(12) == LOW) {

   screen.print("Set Timer 2:");


 }

 while (button_press < 1) {

   // function to retrieve keypad key.

   char key = keypad.getKey();

   if (key) {

     entered_val = key - '0';

     // Serial.println(entered_val);

     if (digit_in == 0) {

       current_val += (int(entered_val) * 10);

       digit_in += 1;

       time_pass += 1;

     } else {

       digit_in = 0;

       current_val += int(entered_val);

       time_pass += 1;

     }

     switch (time_pass) {

       case 1:

         // first digit entered for seconds

         sec = (current_val / 10);

         screen.setCursor(0, 1);

         screen.print("00:00:0");

         screen.setCursor(7, 1);

         screen.print(sec);

         break;

       case 2:

         // second digit entered for seconds

         sec = current_val;

         screen.setCursor(6, 1);

         screen.print(sec);

         break;

       case 3:

         // first digit entered for minutes

         min = (current_val - sec) / 10;

         screen.setCursor(4, 1);

         screen.print(min);

         break;

       case 4:

         // second digit entered for minutes

         min = current_val - sec;

         screen.setCursor(3, 1);

         screen.print(min);

         break;

       case 5:

         // first digit entered for hours

         hrs = (current_val - min - sec) / 10;

         screen.setCursor(1, 1);

         screen.print(hrs);

         break;

       case 6:

         // second digit entered for hours

         hrs = current_val - min - sec;

         screen.setCursor(0, 1);

         screen.print(hrs);

         button_press += 1;

         break;

       default:

         break;

     }

     // debug for the seconds just to see that it was working

     // if (digitalRead(11) == HIGH) {

     //   button_press += 1;

   }

 }

 // checking which alarm to set}

 if (digitalRead(12) == HIGH) {

   timer1.setCounter(hrs, min, sec, timer1.COUNT_DOWN, end_1);

 }

 if (digitalRead(12) == LOW) {

   timer2.setCounter(hrs, min, sec, timer2.COUNT_DOWN, end_2);

 }

 return;

}




void end_1() {

 // ending for timer 1 without clearing timer 2's countdown display

 timer1.stop();

 screen.setCursor(0, 0);

 screen.print("Timer 1 Complete!");

 while (digitalRead(9) == LOW) {

   buzz();

   if (digitalRead(9) == HIGH) {

     timer1.stop();

     timer1.setCounter(0, 0, 0, timer1.COUNT_DOWN, nothing);

     break;

   }

 }

 screen.setCursor(0, 0);

 screen.print("Timer 1:");

 screen.setCursor(8, 0);

 screen.print(timer1.getCurrentTime());

}


void end_2() {

 // ending for timer 2 two without clearing timer 1's countdown display

 timer2.stop();

 screen.setCursor(0, 1);

 screen.print("Timer 2 Complete!");

 while (digitalRead(9) == LOW) {

   buzz();

   if (digitalRead(9) == HIGH) {

     timer2.stop();

     timer2.setCounter(0, 0, 0, timer2.COUNT_DOWN, nothing);

     break;

   }

 }

 screen.setCursor(0, 1);

 screen.print("Timer 2:");

 screen.setCursor(8, 1);

 screen.print(timer2.getCurrentTime());

}