Projects Coming Soon
Project instructions will be available soon. Check back for updates!
Back to HomeProject instructions will be available soon. Check back for updates!
Back to HomeNow for an interlude in timers and interrupts! You will create a digital stopwatch using pushbutton switches and a 7-Segment Display with the ESP32. A piezo buzzer will beep when the buttons are pressed. What are you waiting for? Get started!
Here is a quick recap on how you can install Arduino libraries in the Arduino IDE 2.0.0+
Make sure to #include the library header file so that
your
code compiles correctly.
| Timer Library | Download |
| TM1637 Library | Download |
We will record the time elapsed between a start and stop point. To do so requires a device within the ESP32 board called the… wait for it… timer! The ESP32 conveniently has four timers, only one of which we will need for measuring the time. Keeping it simple, we will use a library to interface with the timer and configure what is effectively a stopwatch program.
You can download the Time library here. Make sure to include the header file:
#include <Timer.h>
You will first instantiate a Timer object, declaring it in the global scope. This will control the timer device.
Timer timer;
Examine the table below for an overview of its member functions:
| Function | Summary |
|---|---|
timer.start();
|
Starts the timer |
timer.pause();
|
Pauses the timer; this is the PAUSED state |
timer.resume();
|
Resumes the timer when paused |
timer.stop();
|
Stops the timer; in this STOPPED state,
the next call to timer.stop()
resets the timer |
timer.read();
|
Returns the time elapsed since (in milliseconds) timer.start()
was called |
timer.state();
|
Returns the state of the timer as one of three constants: RUNNING, PAUSED, and STOPPED |
An interrupt request (IRQ) is a request to the ESP32's CPU to halt the currently executing code when an event occurs. After the request (or IRQ) is sent, the CPU will call another function to handle the event; it's called an interrupt handler or interrupt service routine (ISR). This is particularly useful in embedded systems for handling external interrupts, which are triggered by devices external to the CPU. For example, a button press may trigger an interrupt…
In a previous project, you may have implemented a program with pushbutton switches using a loop. Every iteration of the loop, you read the pushbutton's state, waiting to see if it was pressed. What an ordeal! Instead, we can use an interrupt to let the ESP32 know when the button is pressed. Then, the interrupt handler will perform whichever instructions follow the button press.
We will use a built-in ESP32 function to initialize an interrupt. A digital pin will serve as the line in which IRQs are sent. That same pin is where the external device, such as a pushbutton, should be connected.
attachInterrupt(interrupt, ISR, mode);
Let's discuss the parameters in the function above:
interrupt is the desired number; it is not
a pin number
ISR is the name of the function which will be
called as the interrupt handler
mode configures the timing of the IRQ; the
constants you may pass here are as follows:
LOW triggers the IRQ when the pin is at a
LOW voltage
CHANGE triggers the IRQ when the pin when
it changes value
FALLING triggers the IRQ when the pin
voltage changes from HIGH to LOW
RISING triggers the IRQ when the pin
voltage changes from LOW to HIGH
You will call this function in setup() for each interrupt you wish to initialize. But how do you find the corresponding interrupt
number of the digital pin?
digitalPinToInterrupt(pin);
Using the function above, simply pass the digital pin number and it will return the interrupt number.
The recommended approach to calling these functions is to perform them all in one line:
attachInterrupt(digitalPinToInterrupt(pin), ISR, mode);
After initializing an interrupt, we ought to define an interrupt handler. This will be like defining any other function, except there are no parameters and no return value.
Here is an example definition:
void interruptHandler()
{
Serial.println("The interrupt has been handled");
}
We will pass the name of this function, interruptHandler, as the argument ISR in attachInterrupt.
If you have ever used a digital clock or watch, you have seen a seven-segment display! Each digit is composed of seven LEDs arranged into segments (as shown in the image below).
Activating a combination of the LEDs displays the desired number or character. It's very simple; however, the number of signal lines quickly grows for each additional digit. The TM1637 chip is designed to alleviate this exact problem. The IC interfaces with a 4-digit display and can be controlled via I2C protocol by the ESP32.
Below is a pinout of the TM1637. There are just four pins labeled on the side of the module.
Once again, you may recognize the two I2C pins: DIO and CLK. Although their names differ from the traditional SDA and SCL, they serve the same purpose. These pins should be connected to any two digital pins on the ESP32 board.
Of course, we also need to power the module with the GND and VCC pins. Note that the VCC pin accepts 5V, so connect it to the 5V pin of the ESP32 board.
Download the library here. Make sure to include the header file:
#include <TM1637Display.h>
First thing's first: Instantiate an object of the TM1637 class, declaring it in the global scope. Its two parameters are the digital pin numbers which have been connected to the module's DIO and CLK lines.
TM1637Display display(int CLK, int DIO);
You will call the display's clear() and setBrightness(int brightness) functions just once to
initialize the display. Place this
code in your setup() function.
display.clear();
display.setBrightness(7);
Note that the setBrightness(int brightness) function
changes the module's brightness and accepts a value between 0 (dim) and 7 (bright).
The next order of business is to display numbers! We will use the function below, which has three parameters of interest.
display.showNumberDecEx(int num, 0x40, bool leading_zero);
The first parameter, num, is the number that will be
displayed. The second parameter we will pass
0x40, which enables
the colon on the module. Lastly, leading_zero turns on
or off the leading zeroes on numbers which
are less than four
digits.
display.showNumberDecEx(123, 0x40, true); displays the
following to the module:
The digits populate right to left, and since leading_zero was set to true, the leftmost, unused
digit is a zero.
To learn more about what this library can do, check out the full documentation here.
A piezoelectric buzzer is a component used to emit sound.
Piezo buzzers come in two varieties: active and passive. Active buzzers have a built-in oscillator with a set frequency that cannot be changed. Passive buzzers do not; they have to be fed an oscillating signal. We will use a passive piezo buzzer.
We will use a built-in Arduino IDE function to send a PWM signal of specific frequency to the piezo
buzzer. Instead of using
analogWrite, we will try tone, which allows you to set
the frequency and duration (in milliseconds)
of the PWM signal.
This is perfect for playing music notes!
tone(int pin, int frequency, long duration);
tone is a non-blocking function. The
program will not
pause for the duration of the note; it will continue to execute.
Here are some music notes translated to frequencies:
| Music Note | Frequency (Hz) |
|---|---|
| C5 | 523 |
| D5 | 587 |
| E5 | 659 |
| F5 | 698 |
| G5 | 783 |
Try it out! Play note C5 for 1 second with tone(6, 523, 1000); where the buzzer is connected to pin
21.
Thinking about using a pin you don't know what it does? Refer to the ESP32 Board pinout diagram.
When trying to figure out what pin to use for your specific application/project, refer to the ESP32 Pinout diagram.
For readers who are enrolled in the course: In order to receive full marks on your project submission, make sure it meets the following minimum requirements.
attachInterrupt.
loop()).
attachInterrupt.
loop() only for time conversion, updating the display, and sounding the buzzer.
| Part Name | Qty |
|---|---|
| ESP32 | 1 |
| Breadboard | 1 |
| TM1637, 7 Segment Display | 1 |
| Switch, Tactile | 2 |
| Piezo Buzzer, 1.5V | 1 |
| Dupont Jumper Wire (Male-to-Female) | 4 |
Students enrolled in the course must submit the following deliverables to the corresponding Canvas course assignment.
Place the following files in a single folder:
Compress the folder to a zip file and rename the file using the format “ops_project7_lastname_firstname.zip” Then, submit the zip file to the Project 6 Canvas assignment.