Built-in project · Arduino Uno R3

Tilt alarm on an Arduino Uno

Tip the tilt switch and a buzzer and a lamp sound off until the arcade button on pin 3 resets them. Half-size board. The whole build, an Arduino Uno and 5 more parts, runs here in your browser on the firmware below; open it in the editor to change the wiring or the code and run it again.

Teaching? Assign it to your class in one click.

Beginner About 15 minutes to build and run. Runs in your browser. Free, and no account needed.

The parts retail for about $32. On Mokxi they're free.

Step by step, with the wiring and the common mistakes: Arduino Tilt Sensor (SW-520D): Wiring and Code

The circuit runs here once the page has loaded.

What you'll learn

  • Debouncing a noisy switch with a settle time
  • Latching an alarm until it is reset
  • Blinking without delay using millis
  • Two INPUT_PULLUP inputs to ground
  • Difficulty: Beginner
  • Time: About 15 minutes
  • Board: Arduino Uno R3
  • Parts: 7

How it works

A tilt switch on pin 2 is a metal ball in a can. Upright, it reads LOW. Tipped, the ball rolls off the contacts and the pull-up makes pin 2 read HIGH. Since the ball rattles on landing, the sketch only believes a reading once it has held for 50 ms.

When a tip is accepted, the alarm latches on. The buzzer on pin 8 and the red LED on pin 9 beep together every 150 ms. Standing the box back up does not stop it. Only the arcade button on pin 3 resets it.

Wiring table

Every connection, pin by pin, read from the circuit itself. Each row joins the pin on the left to the pin on the right, by a jumper wire or a breadboard strip.

Part and pinConnects to
Resistor, 220 Ω pin 1Arduino Uno R3 pin 9
Buzzer pin 1Arduino Uno R3 pin 8
Arcade button pin 2Arduino Uno R3 pin 3
Tilt switch pin 1Arduino Uno R3 pin 2
Tilt switch pin 2Arduino Uno R3 pin GND
Arcade button pin 1Arduino Uno R3 pin GND
Buzzer pin 2Arduino Uno R3 pin GND
LED, red pin CArduino Uno R3 pin GND
LED, red pin AResistor, 220 Ω pin 2

The code

The firmware exactly as the editor opens it. Change a line there and press Run: it compiles in the browser.

sketch.ino · Arduino Uno R3
// Tilt alarm: knock it over and it shouts until you press the big button.
//
//   pin 2  the tilt switch, other leg to GND, internal pull-up
//   pin 3  the arcade button, other leg to GND, internal pull-up
//   pin 8  the buzzer, other leg to GND
//   pin 9  the lamp, through 220 ohm to GND
//
// A tilt switch is a metal ball in a can. Upright, the ball rests on both
// contacts and the pin reads LOW; tipped past about fifteen degrees, the ball
// rolls off and the pull-up takes the pin HIGH. That is the whole sensor, and
// the ball rattles for a good few milliseconds as it lands, which is why the
// sketch waits for the reading to hold before it believes it.
//
// # Latching
//
// The alarm does not stop when the box is stood back up. It has seen a tip,
// and it keeps sounding until somebody presses the button, which is what an
// alarm is for: the point is that it happened, not that it is still
// happening. Click the switch on the canvas to tip it, then press the button
// to reset.

const int TILT = 2;
const int BUTTON = 3;
const int BUZZER = 8;
const int LAMP = 9;

const unsigned long SETTLE_MS = 50;
const unsigned long BEEP_MS = 150;

bool alarm = false;
int lastRaw = LOW;
unsigned long changedAt = 0;
int tilt = LOW;

void setup() {
  pinMode(TILT, INPUT_PULLUP);
  pinMode(BUTTON, INPUT_PULLUP);
  pinMode(BUZZER, OUTPUT);
  pinMode(LAMP, OUTPUT);
  digitalWrite(BUZZER, LOW);
  digitalWrite(LAMP, LOW);
  Serial.begin(115200);
  Serial.println("Mokxi Uno: tilt alarm armed. Tip the switch.");
}

void loop() {
  // Debounce: a reading counts once it has held for SETTLE_MS.
  int raw = digitalRead(TILT);
  if (raw != lastRaw) {
    lastRaw = raw;
    changedAt = millis();
  } else if (raw != tilt && millis() - changedAt >= SETTLE_MS) {
    tilt = raw;
    if (tilt == HIGH && !alarm) {
      alarm = true;
      Serial.println("TILT! alarm on");
    }
  }

  if (digitalRead(BUTTON) == LOW && alarm) {
    alarm = false;
    digitalWrite(BUZZER, LOW);
    digitalWrite(LAMP, LOW);
    Serial.println("reset");
    while (digitalRead(BUTTON) == LOW) {
      delay(10);
    }
  }

  if (alarm) {
    int on = (millis() / BEEP_MS) % 2 == 0 ? HIGH : LOW;
    digitalWrite(BUZZER, on);
    digitalWrite(LAMP, on);
  }
  delay(5);
}

Code walkthrough

The key functions of the sketch, and what each one does.

setup sketch.ino

Sets the tilt switch and the button as INPUT_PULLUP, the buzzer and lamp as outputs, and turns both off. It opens serial and says the alarm is armed.

void setup() {
  pinMode(TILT, INPUT_PULLUP);
  pinMode(BUTTON, INPUT_PULLUP);
  pinMode(BUZZER, OUTPUT);
  pinMode(LAMP, OUTPUT);
  digitalWrite(BUZZER, LOW);
  digitalWrite(LAMP, LOW);
  Serial.begin(115200);
  Serial.println("Mokxi Uno: tilt alarm armed. Tip the switch.");
}

loop sketch.ino

First it debounces the tilt pin. A change must last SETTLE_MS before it counts, and a HIGH then sets alarm. Then, if the button is pressed while the alarm is on, it clears the alarm and waits for release. While the alarm is on, it toggles the buzzer and lamp every BEEP_MS.

void loop() {
  // Debounce: a reading counts once it has held for SETTLE_MS.
  int raw = digitalRead(TILT);
  if (raw != lastRaw) {
    lastRaw = raw;
    changedAt = millis();
  } else if (raw != tilt && millis() - changedAt >= SETTLE_MS) {
    tilt = raw;
    if (tilt == HIGH && !alarm) {
      alarm = true;
      Serial.println("TILT! alarm on");
    }
  }

  if (digitalRead(BUTTON) == LOW && alarm) {
    alarm = false;
    digitalWrite(BUZZER, LOW);
    digitalWrite(LAMP, LOW);
    Serial.println("reset");
    while (digitalRead(BUTTON) == LOW) {
      delay(10);
    }
  }

  if (alarm) {
    int on = (millis() / BEEP_MS) % 2 == 0 ? HIGH : LOW;
    digitalWrite(BUZZER, on);
    digitalWrite(LAMP, on);
  // ... 3 more lines in the editor

Troubleshooting

The usual mistakes with this circuit, and the fix for each.

  • The alarm triggers when the box is upright This project
    The switch must read LOW when upright. Check one leg goes to pin 2 and the other to GND.
  • The alarm will not stop This project
    The button on pin 3 needs its other leg on GND. Press it while the alarm is sounding.
  • The buzzer is silent but the lamp blinks This project
    Check the buzzer is on pin 8 with its other pin on GND.
  • The reading flickers when the switch is moved. Tilt switch
    The ball bounces on the contacts, giving many fast changes. Debounce in software by waiting 20 to 50 ms before accepting a new state, or average a few readings.
  • The input floats and never gives a clean reading. Tilt switch
    A tilt switch is just a switch, so the pin floats when it is open. Use INPUT_PULLUP with the switch between the pin and GND, or add a 10 k pull-down resistor.
  • The button reads pressed all the time, or never changes, when wired to a pin. Arcade button
    Use the COM and NO terminals of the microswitch. Wire COM to ground, NO to the pin, and use INPUT_PULLUP. NC is the opposite and reads pressed when released.
  • One press counts as several presses in your code. Arcade button
    Microswitch contacts bounce for a few milliseconds. Ignore changes for 10 to 20 ms after the first one, or react only to the edge and wait before checking again.
  • The buzzer makes a constant tone, or you cannot change its pitch. Buzzer
    An active buzzer has its own oscillator, so it only beeps on and off. A passive buzzer needs tone() to set pitch. Check which type you have.

Change it and keep it

Open it in the editor, change the circuit or the code, and keep your version in a free account.