← All projects
Sensors Intermediate

The SW-420 Vibration Sensor: Counting Knocks With an Interrupt Without Confusing Bounce With Events

One knock on a table is not one pulse but dozens: the spring contact inside the SW-420 rattles. We catch the edges with an interrupt, group them into events by a 200 ms pause, and get a knock counter for an alarm or a secret-knock lock.

Difficulty
Intermediate
Time
40 min
Category
Sensors
Updated

About the project

The SW-420 is a metal cylinder with a spring and a contact inside, plus an LM393 comparator on the module board. At rest the contact is closed and DO stays LOW; a jolt makes the spring bounce, and short HIGH pulses appear on DO. The sensor does not measure how strong a vibration is, but it catches knocks on a table, a door or a drawer — for an alarm, an opening counter or a secret-knock lock.

What you need

  • ESP32 DevKit (or an Arduino)
  • An SW-420 module
  • An LED and a 220 Ω resistor

Wiring

Module ESP32
VCC 3V3
GND GND
DO GPIO16
LED GPIO26 → 220 Ω → GND

The trimmer on the module sets the comparator threshold — in other words, how long the contact has to open for the module to call it vibration.

Why one knock is many pulses

After a knock the spring keeps swinging for another 100–200 ms, and every time it opens you get a separate edge. Count edges and "one knock" turns into "twenty". The right way:

  1. An interrupt on every RISING edge — nothing is missed, not even half-millisecond pulses that a digitalRead() in loop() would easily miss.
  2. Group by a pause: an event is over when there has been no edge for 200 ms.

Code

// Knock detector: SW-420 + an interrupt, the rattle is grouped into single events
const int VIB_PIN = 16;
const int LED_PIN = 26;

volatile unsigned long lastEdgeMs = 0;
volatile int edges = 0;

void IRAM_ATTR onVibration() {
  edges++;
  lastEdgeMs = millis();
}

int knocks = 0;

void setup() {
  Serial.begin(115200);
  pinMode(VIB_PIN, INPUT);
  pinMode(LED_PIN, OUTPUT);
  attachInterrupt(digitalPinToInterrupt(VIB_PIN), onVibration, RISING);
}

void loop() {
  // a knock is a burst of edges; it is over after 200 ms of silence
  if (edges > 0 && millis() - lastEdgeMs > 200) {
    noInterrupts();
    int n = edges;
    edges = 0;
    interrupts();
    knocks++;
    Serial.printf("Knock #%d (%d edges)\n", knocks, n);
    digitalWrite(LED_PIN, HIGH);
    delay(100);
    digitalWrite(LED_PIN, LOW);
  }
}

Click the sensor in the simulator — that is a "knock". The Serial Monitor shows how many edges one knock produced, and the counter goes up by one.

Why noInterrupts()

edges changes inside the interrupt. If the interrupt fires between reading edges and clearing it, one edge is lost. A short noInterrupts() … interrupts() block makes the two steps indivisible. On a dual-core ESP32 a portMUX_TYPE with portENTER_CRITICAL() is more robust, but for a knock counter this is enough.

Ideas

  • A secret knock: remember the intervals between three to five knocks and open a lock (a servo) only for a similar rhythm, within ±25 %.
  • A washing machine monitor: count events per minute. When the vibration has stopped for 5 minutes, the wash is done — send a Telegram message.
  • On an Arduino Uno only D2 and D3 have interrupts — the simulator's Uno variant moves the sensor to D2 by itself.