Interfacing a reed switch with a microcontroller seems trivial until you encounter floating inputs, contact chatter, or phantom triggers caused by 60Hz mains interference. Unlike Hall effect sensors, reed switches are purely mechanical, magnetically actuated contacts. They draw zero quiescent current when open, making them the undisputed champion for battery-powered door alarms, liquid level sensors, and bicycle speedometers.
The Direct Answer: For 90% of DIY and prototyping applications, use a Normally Open (NO) encapsulated reed switch wired between GND and Digital Pin 2, and enable the microcontroller's internal pull-up resistor in software. This eliminates external resistors, prevents floating pins, and leverages the hardware interrupt vector for zero-latency detection.
Decision Tree: Choosing Your Reed Switch and Topology
Not all reed switches are created equal. The glass envelope, the contact plating (ruthenium vs. rhodium), and the Ampere-Turns (AT) sensitivity dictate where they fail. Use this decision matrix to select the exact component for your build.
| Application | Required Switch Type | Wiring Topology | Concrete Part Recommendation |
|---|---|---|---|
| Door/Window Security Alarm | NO, Encapsulated (shock resistant) | GND to D2 (Internal Pull-Up) | Standex KSK-1A66 |
| Tank Liquid Level (Float) | NO, Glass (vertical mount) | GND to D2 (Internal Pull-Up) | Standex KSK-1A87 |
| Bicycle Speedometer / RPM | NO, Glass (high sensitivity) | GND to D2 (Internal Pull-Up) | CT10-1A40 (Coto) |
| High-Current Mains Relay Trigger | NO, Heavy Duty (Ruthenium contacts) | External 10k Pull-Up + BJT | Standex KSK-1A82 |
Hardware Spec Sheet and Pin Mapping
This build targets the Arduino Nano V3 (ATmega328P). We use Digital Pin 2 specifically because it maps to the INT0 hardware interrupt vector on the ATmega328P, allowing the CPU to sleep while waiting for the magnet.
| Component | Exact Variant / Value | Estimated Cost (2026) |
|---|---|---|
| Microcontroller | Arduino Nano V3 (ATmega328P, 5V/16MHz) | $4.50 (Clone) / $22.00 (Genuine) |
| Reed Switch | Standex KSK-1A66 SPST-NO (Encapsulated) | $2.15 each |
| Magnet | N42 Neodymium Cylinder (10mm x 3mm) | $0.80 each |
| Wiring | 22 AWG Solid Core Copper | $0.10 per foot |
| Pull-Up Resistor | None (Using Internal 20kΩ - 50kΩ) | $0.00 |
Pin Mapping Table
| Reed Switch Lead | Arduino Nano Pin | Notes |
|---|---|---|
| Lead 1 (Arbitrary) | GND | Provides the LOW signal when closed |
| Lead 2 (Arbitrary) | D2 (INT0) | Reads HIGH via pull-up when open, LOW when closed |
Note: Reed switches are non-polarized. Unlike diodes or electrolytic capacitors, either lead can go to GND or D2.
Wiring Procedure and the 'First Three Checks'
Before uploading code, physically wire the circuit and verify the hardware. Mechanical switches fail in predictable ways if installed blindly.
- Strip and Seat: Strip 1/4 inch of insulation from your 22 AWG wires. Insert the reed switch leads into the breadboard. If using an encapsulated switch, ensure the sensing axis (usually marked with a line or flattened side) faces the path of your magnet.
- Connect Ground and Signal: Run a jumper from one switch lead to the Nano's GND pin. Run the second lead to Digital Pin 2.
- Magnet Proximity Test: Pass the N42 magnet over the switch. You should hear a faint, distinct 'click' from the glass envelope inside the housing. If you don't hear it, your magnet is too weak or too far away.
1. Multimeter Continuity: Set your DMM to continuity (beep) mode. Probe the breadboard traces (not the switch leads directly, to avoid bending them). Pass the magnet over the switch. The meter should beep cleanly. If it doesn't, the switch is dead or the breadboard contact is loose.
2. Floating Pin Voltage: Set DMM to DC Volts. Probe D2 with the black lead on GND. With the magnet away, you must read ~5.0V. If you read 0.0V or a fluctuating millivoltage, your internal pull-up is not enabled in code, or the pin is shorted to ground.
3. Magnet Polarity & Distance: While most reed switches are omnidirectional, some high-sensitivity variants exhibit a 'dead zone' directly in the center of the poles. Move the magnet in a figure-8 pattern to find the optimal actuation axis.
Complete Arduino Code: Interrupts and Software Debounce
Reed switches suffer from severe contact bounce. When the ferromagnetic reeds snap together, they physically vibrate for 1 to 5 milliseconds, generating dozens of false HIGH/LOW transitions. This code uses a hardware interrupt combined with a software millis() debounce timer to filter the chatter.
Target Board: Arduino Nano V3 (ATmega328P). Ensure 'ATmega328P (Old Bootloader)' is selected if using a cheap clone that fails to upload.
/*
* Reed Switch Debounced Interrupt Code
* Target: Arduino Nano V3 (ATmega328P)
* Author: ElectricalFlux Bench Team
*/
// --- PIN DEFINITIONS ---
#define REED_PIN 2 // Hardware INT0 on ATmega328P
#define LED_PIN 13 // Onboard Nano LED for visual feedback
// --- DEBOUNCE CONFIG ---
#define DEBOUNCE_MS 50 // 50ms filters out mechanical reed chatter
#define CHATTER_THRESHOLD 10 // Max triggers allowed per second before error flag
// --- VOLATILE VARIABLES (Modified in ISR) ---
volatile unsigned long lastTriggerTime = 0;
volatile unsigned long triggerCount = 0;
volatile bool stateChanged = false;
void setup() {
// Initialize Serial with error handling for USB enumeration
Serial.begin(115200);
unsigned long serialTimeout = millis();
while (!Serial && (millis() - serialTimeout < 2000)) {
// Wait up to 2 seconds for Serial port to open (native USB boards)
}
if (!Serial) {
// Fallback for boards where Serial check fails but hardware works
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, HIGH); // Solid LED indicates Serial failure
} else {
Serial.println(F("[INIT] Reed Switch Controller Online"));
Serial.println(F("[INIT] Target: ATmega328P, Pin D2 (INT0)"));
}
// Configure Pins
pinMode(LED_PIN, OUTPUT);
// CRITICAL: Enable internal pull-up resistor (approx 32k ohm on ATmega328P)
// This pulls D2 HIGH when the switch is open, and LOW when closed to GND.
pinMode(REED_PIN, INPUT_PULLUP);
// Attach hardware interrupt.
// FALLING triggers when magnet approaches (switch closes, pulling D2 to GND)
attachInterrupt(digitalPinToInterrupt(REED_PIN), reedISR, FALLING);
Serial.println(F("[READY] Waiting for magnet..."));
}
void loop() {
// Handle the state change outside the ISR to keep interrupt execution fast
if (stateChanged) {
stateChanged = false;
digitalWrite(LED_PIN, !digitalRead(LED_PIN)); // Toggle LED
Serial.print(F("[TRIGGER] Magnet detected. Total count: "));
Serial.println(triggerCount);
}
// Background diagnostic: Check for hardware failure or EMI chatter
static unsigned long lastDiagTime = 0;
if (millis() - lastDiagTime >= 1000) {
lastDiagTime = millis();
// If we get more than 10 triggers a second, it's not a human with a magnet.
// It's either a welded switch contact or severe 60Hz EMI interference.
if (triggerCount > CHATTER_THRESHOLD) {
Serial.print(F("[ERROR] ISR_CHATTER_DETECTED: "));
Serial.print(triggerCount);
Serial.println(F(" triggers in 1000ms. Check pull-up and EMI shielding."));
}
triggerCount = 0; // Reset diagnostic counter every second
}
}
// --- INTERRUPT SERVICE ROUTINE (ISR) ---
void reedISR() {
unsigned long currentTime = millis();
// Software Debounce: Ignore triggers that happen within DEBOUNCE_MS
if ((currentTime - lastTriggerTime) > DEBOUNCE_MS) {
lastTriggerTime = currentTime;
triggerCount++;
stateChanged = true;
}
}
Troubleshooting: Floating Pins and Phantom Triggers
When working with high-impedance inputs and mechanical contacts, you will eventually encounter the ISR_CHATTER_DETECTED error string in your serial monitor, or the LED will flicker randomly without a magnet present. Here is the ranked decision path to fix it.
Symptom: Serial monitor spams triggers; LED flickers randomly
- Ranked Cause 1: Missing Pull-Up Resistor (Floating Pin). If you used
pinMode(REED_PIN, INPUT)instead ofINPUT_PULLUP, the pin is high-impedance. It acts as an antenna, picking up 50/60Hz electromagnetic interference from nearby AC mains wiring. Fix: Change to INPUT_PULLUP or add an external 10kΩ resistor to 5V. - Ranked Cause 2: Inductive Coupling from AC Lines. Even with a pull-up, if your 22 AWG jumper wires run parallel to 120V/240V AC Romex for more than a few feet, capacitive coupling can induce enough voltage to cross the ATmega's logic LOW threshold (~1.5V). Fix: Route low-voltage sensor wires perpendicular to AC mains, or use shielded twisted-pair cable for long runs.
- Ranked Cause 3: Contact Welding (Overcurrent). Did you wire the reed switch directly to a relay coil or a capacitive load without a flyback diode? The inrush current likely welded the microscopic ruthenium contacts shut. Fix: Desolder the switch, test with a DMM. If it reads 0Ω with the magnet removed, the switch is destroyed. Replace it and add a snubber circuit.
Symptom: Compile Error: 'REED_PIN' was not declared in this scope
If you copied the logic but missed the preprocessor directives at the top of the sketch, the compiler will halt. Ensure #define REED_PIN 2 is placed before void setup(). Never hardcode pin numbers inside the attachInterrupt() function; always use the digitalPinToInterrupt() macro to ensure compatibility if you later migrate the code to an Arduino Mega or ESP32.
Extending and Simplifying the Build
Once the baseline circuit is proven on the bench, you will likely want to scale it. Here is how to adapt this topology for production or low-power edge nodes.
Simplifying: Migrating to ESP32 Deep Sleep
If you are building a battery-powered door sensor, the Arduino Nano's ~15mA idle current will drain a CR2032 coin cell in days. Migrate to an ESP32-WROOM-32 module. The ESP32 can enter deep sleep (drawing ~10µA) and use the reed switch to wake it via the RTC GPIO pins.
Wire the reed switch to GPIO 4 (an RTC-capable pin on the ESP32). Replace the interrupt code with the sleep configuration:
// ESP32 Deep Sleep Wakeup Configuration
esp_sleep_enable_ext0_wakeup(GPIO_NUM_4, 0); // Wake on LOW (switch closed)
esp_deep_sleep_start();
Extending: Multi-Sensor Security Arrays
If you need to monitor 4 doors and 2 windows, do not use 6 interrupt pins. The ATmega328P only has 2 external interrupts (D2 and D3). Instead, wire all reed switches in a multiplexed matrix or use a port expander like the MCP23017 over I2C. The MCP23017 has its own interrupt pin (INTA) that can wake the Arduino, while handling up to 16 individual reed switches with internal pull-ups configured via I2C registers.
For further reading on hardware interrupt vectors, consult the official Arduino attachInterrupt() documentation. For deep-dive physics on Ampere-Turns sensitivity and contact wetting current, refer to the Standex Electronics Technical Center application notes.






