Parts list
| Part | Qty | Approx. | Buy |
|---|---|---|---|
| Arduino Nano (CH340, ATmega328P) | 1 | ₹300 | Buy Arduino Nano (CH340, ATmega328P) |
| KY-038 sound sensor module (microphone + LM393) | 1 | ₹50 | Buy KY-038 sound sensor module (microphone + LM393) |
| TM1637 4-digit display module | 1 | ₹70 | Buy TM1637 4-digit display module |
| Active buzzer module | 1 | ₹25 | Buy Active buzzer module |
| Push button | 1 | ₹10 | Buy Push button |
| Small plastic box + double-sided tape | 1 | ₹80 | Buy Small plastic box + double-sided tape |
| 5 V USB adapter or power bank | 1 | ₹150 | Buy 5 V USB adapter or power bank |
| Total | ₹685 |
Affiliate disclosure: “Buy” links may earn FlashReady a small commission at no extra cost to you. Prices are indicative.
Wiring
| Arduino Nano | Part · pin | Wire | Notes |
|---|---|---|---|
| A0 | KY-038 sound sensor (microphone + LM393) · A0 | green | Analog microphone signal |
| 5V | KY-038 sound sensor (microphone + LM393) · + | red | |
| GND | KY-038 sound sensor (microphone + LM393) · G | black | |
| D2 | TM1637 4-digit 7-segment display · CLK | orange | |
| D3 | TM1637 4-digit 7-segment display · DIO | green | |
| 5V | TM1637 4-digit 7-segment display · VCC | red | |
| GND | TM1637 4-digit 7-segment display · GND | black | |
| D8 | Active buzzer module (high-level trigger) · I/O | orange | |
| 5V | Active buzzer module (high-level trigger) · VCC | red | |
| GND | Active buzzer module (high-level trigger) · GND | black | |
| D4 | Push button (6 mm tactile switch) · 1 | blue | Tap = target, hold 2 s = reset, any press = stop alarm |
| GND | Push button (6 mm tactile switch) · 2 | black |
Board quirks: Put it on a shelf or wall about 1–2 m from the stove — close enough to hear the whistle clearly, far enough from the heat, steam and oil splashes. Never on the stove top. A whistle is a loud sound that lasts at least 0.6 s. The pressure cooker’s steady hiss before the whistle, a tadka’s splutter, or a dropped spoon are shorter or quieter and are ignored. After each whistle the counter waits 4 s, so one long whistle counts once. Turn the blue trimmer on the KY-038 so its D0 LED is just off in a quiet kitchen; that centres the microphone signal. Then adjust LOUD in the sketch while watching the Serial Monitor. It’s a reminder, not a safety device — don’t leave a cooker on the flame with nobody at home.
Code
// Pressure cooker whistle counter — Arduino Nano + KY-038 sound sensor + TM1637 + buzzer module
// KY-038: A0 -> A0, + -> 5V, G -> GND. TM1637: CLK D2, DIO D3. Buzzer module on D8.
// Push button D4 to GND: tap = whistles wanted (1-9), hold 2 s = start counting again from 0.
// Display "02:03" = 2 whistles heard of 3 wanted. At the target it beeps until you press the button.
#include <TM1637Display.h>
constexpr uint8_t MIC_PIN = A0;
constexpr uint8_t CLK_PIN = 2;
constexpr uint8_t DIO_PIN = 3;
constexpr uint8_t BUZZER_PIN = 8;
constexpr uint8_t BUTTON_PIN = 4;
constexpr int LOUD = 60; // peak-to-peak ADC counts that count as "whistling"
constexpr unsigned long WHISTLE_MS = 600; // a whistle is loud for at least this long
constexpr unsigned long GAP_MS = 4000; // ignore everything for 4 s after a whistle
constexpr unsigned long ALARM_MAX_MS = 60000UL;
TM1637Display display(CLK_PIN, DIO_PIN);
uint8_t target = 3, whistles = 0;
unsigned long loudSince = 0, quietSince = 0, lastWhistle = 0, alarmSince = 0;
bool alarming = false;
// Loudness: peak-to-peak of the microphone signal over 20 ms (one mains cycle of hum).
int loudness() {
int lo = 1023, hi = 0;
unsigned long t0 = millis();
while (millis() - t0 < 20) {
int v = analogRead(MIC_PIN);
if (v < lo) lo = v;
if (v > hi) hi = v;
}
return hi - lo;
}
void show(bool on = true) {
if (on) display.showNumberDecEx(whistles * 100 + target, 0b01000000, true); // "WW:TT" with colon
else display.clear();
}
void setup() {
Serial.begin(115200);
pinMode(BUZZER_PIN, OUTPUT);
pinMode(BUTTON_PIN, INPUT_PULLUP);
display.setBrightness(6);
show();
Serial.println(F("Whistle counter: tap = target, hold 2 s = reset"));
}
void loop() {
unsigned long now = millis();
// Button
if (digitalRead(BUTTON_PIN) == LOW) {
unsigned long t0 = now;
while (digitalRead(BUTTON_PIN) == LOW && millis() - t0 < 2000) delay(10);
bool held = millis() - t0 >= 2000;
if (alarming) {
alarming = false; // any press silences the alarm
} else if (held) {
whistles = 0;
Serial.println(F("Reset"));
} else {
target = target % 9 + 1;
}
digitalWrite(BUZZER_PIN, LOW);
show();
while (digitalRead(BUTTON_PIN) == LOW) delay(10);
now = millis();
}
int level = loudness();
bool loud = level > LOUD;
if (now - lastWhistle > GAP_MS || lastWhistle == 0) {
if (loud) {
quietSince = 0;
if (!loudSince) loudSince = now;
if (now - loudSince > WHISTLE_MS) {
whistles++;
lastWhistle = now;
loudSince = 0;
Serial.print(F("Whistle "));
Serial.print(whistles);
Serial.print('/');
Serial.println(target);
show();
if (whistles >= target && !alarming) {
alarming = true;
alarmSince = now;
Serial.println(F("Target reached - turn off the gas!"));
}
}
} else if (loudSince) {
// Allow short dips inside one whistle (the weight rattles).
if (!quietSince) quietSince = now;
if (now - quietSince > 150) loudSince = quietSince = 0;
}
}
if (alarming) {
bool on = (now / 300) % 2;
digitalWrite(BUZZER_PIN, on);
show(on);
if (now - alarmSince > ALARM_MAX_MS) {
alarming = false;
digitalWrite(BUZZER_PIN, LOW);
show();
}
}
static unsigned long lastLog = 0;
if (now - lastLog > 1000) {
lastLog = now;
Serial.print(F("loud="));
Serial.print(level);
Serial.print(F(" whistles="));
Serial.print(whistles);
Serial.print('/');
Serial.println(target);
}
}// Pressure cooker whistle counter — Arduino Nano + KY-038 sound sensor + TM1637 + buzzer module
// KY-038: A0 -> A0, + -> 5V, G -> GND. TM1637: CLK D2, DIO D3. Buzzer module on D8.
// Push button D4 to GND: tap = whistles wanted (1-9), hold 2 s = start counting again from 0.
// Display "02:03" = 2 whistles heard of 3 wanted. At the target it beeps until you press the button.
#include <TM1637Display.h>
constexpr uint8_t MIC_PIN = A0;
constexpr uint8_t CLK_PIN = 2;
constexpr uint8_t DIO_PIN = 3;
constexpr uint8_t BUZZER_PIN = 8;
constexpr uint8_t BUTTON_PIN = 4;
constexpr int LOUD = 60; // peak-to-peak ADC counts that count as "whistling"
constexpr unsigned long WHISTLE_MS = 600; // a whistle is loud for at least this long
constexpr unsigned long GAP_MS = 4000; // ignore everything for 4 s after a whistle
constexpr unsigned long ALARM_MAX_MS = 60000UL;
TM1637Display display(CLK_PIN, DIO_PIN);
uint8_t target = 3, whistles = 0;
unsigned long loudSince = 0, quietSince = 0, lastWhistle = 0, alarmSince = 0;
bool alarming = false;
// Loudness: peak-to-peak of the microphone signal over 20 ms (one mains cycle of hum).
int loudness() {
int lo = 1023, hi = 0;
unsigned long t0 = millis();
while (millis() - t0 < 20) {
int v = analogRead(MIC_PIN);
if (v < lo) lo = v;
if (v > hi) hi = v;
}
return hi - lo;
}
void show(bool on = true) {
if (on) display.showNumberDecEx(whistles * 100 + target, 0b01000000, true); // "WW:TT" with colon
else display.clear();
}
void setup() {
Serial.begin(115200);
pinMode(BUZZER_PIN, OUTPUT);
pinMode(BUTTON_PIN, INPUT_PULLUP);
display.setBrightness(6);
show();
Serial.println(F("Whistle counter: tap = target, hold 2 s = reset"));
}
void loop() {
unsigned long now = millis();
// Button
if (digitalRead(BUTTON_PIN) == LOW) {
unsigned long t0 = now;
while (digitalRead(BUTTON_PIN) == LOW && millis() - t0 < 2000) delay(10);
bool held = millis() - t0 >= 2000;
if (alarming) {
alarming = false; // any press silences the alarm
} else if (held) {
whistles = 0;
Serial.println(F("Reset"));
} else {
target = target % 9 + 1;
}
digitalWrite(BUZZER_PIN, LOW);
show();
while (digitalRead(BUTTON_PIN) == LOW) delay(10);
now = millis();
}
int level = loudness();
bool loud = level > LOUD;
if (now - lastWhistle > GAP_MS || lastWhistle == 0) {
if (loud) {
quietSince = 0;
if (!loudSince) loudSince = now;
if (now - loudSince > WHISTLE_MS) {
whistles++;
lastWhistle = now;
loudSince = 0;
Serial.print(F("Whistle "));
Serial.print(whistles);
Serial.print('/');
Serial.println(target);
show();
if (whistles >= target && !alarming) {
alarming = true;
alarmSince = now;
Serial.println(F("Target reached - turn off the gas!"));
}
}
} else if (loudSince) {
// Allow short dips inside one whistle (the weight rattles).
if (!quietSince) quietSince = now;
if (now - quietSince > 150) loudSince = quietSince = 0;
}
}
if (alarming) {
bool on = (now / 300) % 2;
digitalWrite(BUZZER_PIN, on);
show(on);
if (now - alarmSince > ALARM_MAX_MS) {
alarming = false;
digitalWrite(BUZZER_PIN, LOW);
show();
}
}
static unsigned long lastLog = 0;
if (now - lastLog > 1000) {
lastLog = now;
Serial.print(F("loud="));
Serial.print(level);
Serial.print(F(" whistles="));
Serial.print(whistles);
Serial.print('/');
Serial.println(target);
}
}Compiled for nano on avr 1.8.8 with TM1637 1.2.0 · 3 Nov 2026
How it works
“Three whistles for dal, five for rajma, one for rice” — every Indian kitchen counts pressure cooker whistles, and everyone has lost count while doing something else. This little box counts them for you and beeps when the number you set is reached.
How it works
The KY-038 has an electret microphone and an amplifier. Its A0 output is the raw sound waveform riding on about 2.5 V. Every 20 ms the Nano reads A0 as fast as it can and takes the peak-to-peak value — how loud the kitchen is right now.
A pressure cooker whistle is loud and long. The sketch only counts a whistle when the level stays above LOUD for at least 0.6 s (short dips of up to 150 ms, from the weight rattling, are allowed inside one whistle). After counting, it ignores sound for 4 s.
The TM1637 shows 02:03 — two whistles heard, three wanted. Tap the button to change the target (1–9); hold it for 2 s to start again from zero. When the count reaches the target, the display blinks and the buzzer beeps until you press the button (or for one minute).
Why these parts
- KY-038’s analog output — the module’s D0 comparator only says “loud or not”, which can’t tell a whistle from a spoon. The analog waveform lets the sketch measure how long the sound lasts.
- TM1637 — readable across the kitchen.
- Nano — small, and its 5 V ADC reads the module directly.
Calibration
Open the Serial Monitor (115200 baud). It prints loud=… every second. Note the value in a quiet kitchen (often 5–20), with the mixer running, and during a real whistle (often 150+). Set LOUD between the mixer and the whistle.
India notes
Kitchens here are loud — the exhaust fan, the mixer, the TV next door. The duration rule handles most of it; the rest is placement. Keep the box away from the chimney/exhaust fan’s airflow, which also carries oil.
Troubleshooting
It counts the mixer grinder or the TV
Raise LOUD (watch the loud= numbers on the Serial Monitor while the whistle blows and while the mixer runs, and pick a value between) or WHISTLE_MS. The mixer is loud but steady; moving the sensor nearer the cooker helps more than anything.
It misses whistles
The sensor is too far or the trimmer is off-centre. Check loud= reaches well above LOUD during a whistle; lower LOUD or move closer.
The display shows 00:03 and never changes
Check A0 goes to the module’s A0 pin, not D0. The A0 value should jump when you clap.
Upgrades
- Add a repeat reminder that beeps every minute until you press the button. (Don’t try to shut the gas automatically — a hobby board must never control an LPG valve on a lit stove.)
- Show the time since the last whistle, for recipes that say “simmer 10 minutes after 1 whistle”.
- Use an ESP32 and send the “done” to your phone through ntfy.sh when you’re in another room.



