Make a Tomato Timer with Me!

Learn how to program an Arduino

Saif Uddin Mahmud
Dabbler in Destress
10 min readOct 26, 2018

--

A few days ago I realized I wasn’t getting a lot of things done when I was home. Determined to pull my act back together, I decided I’ll start using the Pomodoro Technique. There was only one problem: I did not have a Tomato Timer for my sessions. I could use an app/a website, but screens are the best sources of distraction. I could buy one, but let’s face it: DIY is way more fun (and helps me escape real work).

Now, I don’t want to have all the productivity by myself. So I decided I’ll document this and help spread some maker culture.

Regardless of your skill level, I hope to offer you something in this article. We’ll cover basic Arduino operations (Writes, Reads, Serial, delays) and some intermediate concepts such as Interrupts and delay-less code. I’ll provide links to relevant concepts which might intrigue you, but you’ll not have to know them all to follow along. The article assumes basic programming knowledge, preferably in C, and basic circuit knowledge. Regardless, feel free to jump around the sections according to your skills/interest!

All the code for the article is present at my GitHub repo here: https://github.com/Psyf/Pomoduino. The parts used in this project are very basic, and you can find them in any electrical/hardware/hobbyist store (/online)

“focus photo of gray and black circuit board” by Nicolas Thomas on Unsplash

The Circuit

The breadboard schematic below shows how you should wire everything together. If you need a refresher on how breadboard circuits work, follow this link: https://learn.sparkfun.com/tutorials/how-to-use-a-breadboard.

Usage: We’re going to use the 3 variable resistors to configure our study/work time — how long each study session will last, how long each break session is and how many sessions we want in total. The resistance is what determines what our Arduino reads, and the values can be tweaked by using something like a screwdriver. (If anyone was wondering, I prefer 35 minutes of study, 10 minutes of break, and 3 sessions in total.)

The LEDs form our “screen” and let us know at which point of the study session we’re in — fading red for study, steady green for a break. The Piezo Speaker acts like our alarm, so we can concentrate on our work instead of the lights. We also have a handy little red RESET button on the Arduino to “restart” after we end one run through. The Arduino will derive power from our laptop/desktop’s USB port for now (we explore alternate powering options later in the article).

Explanation: Red wires represent Power (5V, in this case), while black wires represent a connection to Ground (GND, or 0V) by convention. It is always a great idea to color code your wires.

The cyan wires are inputs from the rheostat (variable resistor) going to pins A3, A4 and A5 (A for Analog). The LEDs are connected to resistors (to limit the current flowing through, otherwise they burst) on one end, and Digital Pins on the other. Do take care about connecting them the right way round: the shorter leg is the negative terminal and will connect to the resistor. If you’re very sharp, you’ll notice how all the red LEDs are connected to pins with a ~ beside them. More on that later.

The Code

Now that we have the circuit all wired up and our work cut out, let’s jump into the code. We’ll need to read the input from the 3 potentiometers for initial configuration, measure time, light the LEDs in order and make sounds before and after study sessions.

We’ll be coding in the Arduino IDE, which takes care of a lot of the “low-level stuff” (like importing libraries) in the background, making it super-fun and easy to write actual code.

Now the bulk of your Arduino code goes into two functions: setup() and loop(). The first function is run once to — you guessed it — setup the registers inside the Arduino. The second function is where we put the logic in, to run in an infinite loop. The rest of the code should is simple, procedural C, and should be quite easy to follow:

Now that’s a lot to take in at once if you’re playing with Arduino for the first time. Let me walk you through it.

We start with a few C Preprocessor Directives because it’s better programming practice and makes your life way easier, especially for changing Pins. We also use a few to global variables to store the LED pins and the program’s state. The unused variable pause will give you a hint in what’s to come in the coming sections ;)

We now move onto the setup() function. pinMode is a function that takes in a pin number and sets it to either OUTPUT or INPUT, depending on whether you want to use that pin for running devices (LEDs and Piezo for us), or reading from sensors (rheostats here). We also set up Serial Communication, also known as UART/USART, by calling Serial.begin() with a baud rate of 9600. The Arduino can communicate with your laptop (send/receive data) through the USB port or pins RX(0)/TX(1). This is why we do not use pins 0 and 1 in our circuit. All these functions are doing is setting some bytes/registers so the hardware is ready. You can do this in bare-metal too, and we’ll cover that in a later tutorial.

Then we move onto the loop() function. You can think of the loop as a while(1) — an infinite loop. To act against that, we make use of the variable over that turns to 1 once we finish our study session. Next we call some functions I made, namely getSessTime, getNumSess and getBreakTime, which are fairly obvious names and contain similar code. All of them use a function analogRead to read from the analog pins (prefixed with an A, if you still remember). The return value of analogRead is from 0 (0V) to 1023 (5V), scaled linearly. So we can change the resistance of the potentiometers to change the duration of the programs according to our needs. We print the values we’re going to use with Serial.println(). You can see the values printed in the Serial Monitor (open with Ctrl+Shift+M).

The other functions hold() and fadeAndHold() are more interesting. Hold is used to light up the green LEDs during our break times. It also waits inside the function for x minutes, x being the value we specified. Let’s look at the code for hold:

// Any output pin can use this
// duration in minutes
void hold(int led, int duration) {
unsigned long targetTime = millis() + duration*1000*60;
digitalWrite(led, HIGH);
while (millis() < targetTime) continue;
}

digitalWrite() takes in the pin number, and writes either discrete HIGH (5V) or LOW (GND or 0V) to the pins. millis() is giving us the time since the Arduino started, and we can use this to wait (in the while loop) for duration amount of time (which has been scaled from minutes to milliseconds, if you notice the equation). We can actually write the same function as:

void hold(int led, int duration) {
digitalWrite(led, HIGH);
delay(duration*1000*60);
}

delay() is doing the same thing. So why do I not opt for the “cleaner” looking code? It’s because delay() is blocking every other operation (including external interrupts) as the Arduino only has a single core/thread. On the other hand millis() does not block interrupts, and we can use this to pause our timer in the latter part of the article.

fadeAndHold() is even more interesting. It uses a function called analogWrite(). Remember the ~ signs against every red LED pin? This tilde tells us that the pins can output analog (values between 0V and 5V), kind of. This lets us control the brightness of the red LEDs. In the code, we increase the brightness every 5 milliseconds by 1 (0 represents 0V and 255 represents 5V), and then once it hits the top, we decrease by 1. Fairly standard fading in and out. How does the Arduino do that? It “fakes” an analog output by means of a technique called Pulse-Width Modulation (PWM for short). You can read more about how it does this with the help of variable duty-cycles in the link provided, or keep an eye out for my article covering PWM.

The rest of the function is straightforward if you’ve been following along. We keep fading the LED until time for a study session is up, and then keep it steady at HIGH to represent how many sessions we’ve completed.

The tone() function is given by a library for the Piezo. It takes pin, frequency_of_sound and duration as 3 arguments. We use this for auditory feedback after before breaks and after breaks.

Write the code in Arduino IDE, choose port and board correctly and hit upload. If all goes well, you now have a working Pomodoro timer. So now you can adjust your durations, power the Arduino with a USB cable and enjoy. You can hit the RESET button on the Arduino to restart the program.

Interrupts

Up until now, we can only RESET our program, not PAUSE it. Personally, I like to pause it if I want to go use the restroom or something. How do we implement that? We can obviously add a switch that we can keep reading after every other instruction. But that would be a very naive approach, make the code clunky and ugly (and nullify the point of this section). A better option would be Interrupts.

Think of Interrupts as Emergency calls. Whenever an Interrupt is triggered/detected by the Arduino, it stops whatever it is doing and deals with the interrupt as described by the Interrupt Service Routine (ISR for short). Sounds fancy, but is just another function. We have to make sure this function is short, simple and fast so it can handle the “emergency” quickly and get back to the original flow of the program. We will add a switch for the interrupt, as shown in the modified circuit diagram below. The rest of the circuit is untouched.

The Arduino has “external” interrupts and “pin-change” interrupts. You can do external interrupts with only 2 pins, INT0 and INT1 (pins 2 and 3, respectively). Pin-change can happen on all the pins, but we’ll focus on “external” interrupts, as pin-change is a bit more complicated and deserves its own article.

So now that you see why we chose pin 2 for the input of the switch, we can move on. If you’re curious, we did not choose pin 3 because the Piezo library specifies that we should keep pin 3 and pin 11 free. How do I know? I read the documentation.

Let’s look at the code changes now. Obviously, we have a new #define for the switch. In our setup() function, we also have this line attachInterrupt(digitalPinToInterrupt(START_BUTTON_PIN), pause_ISR, HIGH); This tells Arduino that START_BUTTON_PIN is to be treated as an Interrupt pin and that every time it reads HIGH, we should call the function pause_ISR() Let’s look pause_ISR() just turns the flag pause to 1 and calls the function pause_Exec(), which basically sits idle (using an infinite loop) until we flip the switch again. Note this goes against good interrupt practice. Interrupts should be fast, and not blocking like it is now. But since it is a simple example, this works well enough for us.

This Interrupt is why we did not use delay() anywhere in our code. You see, when we call delay(), even interrupts can’t interrupt them. So if you happened to flip the switch in the milliseconds the program was in delay() (which is not unlikely, given how often we would have called it), you would have missed executing the ISR, and the program would go on as if nothing had happened. The full code is given below for your reference:

So messy!

This is what my circuit looks like in-real-life. I later changed to an Arduino Nano for a smaller footprint and used stripped wires instead of Jumper wires to make it cleaner.

Future Improvements

  1. Right now we can only tune the durations before the circuit starts operating and verify the tuning using the Serial monitor. Can you come up with an elegant solution to the problem of tuning the duration during operation? I’ll leave this as an exercise and will be looking forward to solutions you post in the comments below.
  2. Till now we’ve been powering our projects through a USB cable, but that is not very practical for a simple device like this. Can we decrease the power consumption of the circuit and power it with a small battery? There are quite a few tricks we can use, ranging from easy to quite difficult. We will be looking at this interesting dimension in a followup article soon.
  3. Another improvement is to hook this up to the internet, send data to a server, and do some data analysis before showing pretty graphs to track our study times/patterns.
  4. Another improvement is playing some sort of music while the program runs. The piezo music samples are available online. The challenging bit is to multithread the program using libraries. I don’t know if I’ll be able to do that satisfactorily, but I guess I’ll just have to try after I take my Real-Time Operating System course next semester. Stay tuned for some advanced dabbling!

Hopefully you’ve taken away something valuable from this tutorial. If this is the first time you’ve played with an Arduino, congratulations on starting your journey! You can play around with code examples in the Arduino IDE or go to Arduino’s website to learn more. Keep an eye out for more Arduino related articled on Dabbler in Destress as well.

Let us know what you think about these articles in the comment sections down below. Thank you for dropping by!

--

--