If you need to measure rotational speed (RPM) or detect a limit position, the direct answer is to use a A3144EUA-T digital hall sensor paired with a 10kΩ pull-up resistor on an interrupt pin. If your project requires measuring linear distance or magnetic field strength (like a joystick or suspension travel), use the SS49E analog hall sensor wired to an ADC pin. This guide focuses on the digital A3144 for RPM and pulse counting, as it is the most common and practical application for makers.
Choosing the Right Arduino Hall Sensor Module
Hall effect sensors output a signal based on the presence of a magnetic field. However, not all sensors output the same type of signal. Selecting the wrong variant will result in either a floating digital pin or a useless analog voltage. Use the decision tree below to pick the exact part number for your workbench.
| Application Goal | Output Type | Recommended Part | Why This Pick Wins |
|---|---|---|---|
| RPM counting, limit switches, tachometers | Digital (On/Off) | A3144EUA-T | Open-drain output provides sharp, clean edges for microcontroller interrupts. Highly immune to analog noise. |
| Proximity sensing, joysticks, pedal position | Analog (Linear) | SS49E | Ratiometric output scales linearly with magnetic flux density. Perfect for ADC reading. |
| High-temperature environments, precision robotics | Analog (Linear) | DRV5055 | Superior temperature stability and tighter factory calibration compared to the SS49E. |
Parts List and Spec Sheet
To build a reliable RPM tracker, you need more than just the sensor. The A3144 has an open-drain output, meaning it can pull the signal line to ground, but it cannot drive it high. You must provide the high state externally.
| Component | Exact Variant / Spec | Estimated Cost (2026) | Notes |
|---|---|---|---|
| Microcontroller | Arduino Uno R3 (ATmega328P) | $22.00 (Official) / $14.00 (Clone) | 5V logic, 16MHz clock. Code targets this exact board. |
| Hall Sensor | Allegro A3144EUA-T | $0.30 / ea | Digital, South-pole activated, 4.5V to 24V VCC. |
| Pull-up Resistor | 10kΩ (1/4W Carbon Film) | $0.02 | Required for open-drain output. (Skip if using a pre-built module with an onboard resistor). |
| Magnet | Neodymium N42 (10x3mm) | $0.50 | N42 grade provides sufficient flux density to trigger the A3144 at a 15mm air gap. |
| Bypass Capacitor | 0.1µF Ceramic (50V) | $0.05 | Place across VCC and GND to suppress motor EMI. |
Wiring the Sensor to the Arduino Uno R3
Motor environments are electrically noisy. Keep your sensor wires under 6 inches, use twisted pairs if possible, and always include the bypass capacitor. Below is the exact pin mapping for the bare A3144 IC.
| A3144 Pin (Facing you, text upright) | Arduino Uno R3 Pin | Intermediate Components |
|---|---|---|
| Pin 1 (VCC) | 5V | 0.1µF capacitor to GND |
| Pin 2 (GND) | GND | None |
| Pin 3 (OUT) | Digital Pin 2 | 10kΩ pull-up resistor to 5V |
Note: If you bought a 3-pin or 4-pin KY-003 or similar breakout module, the onboard comparator and resistors handle the pull-up and voltage regulation. Wire Module VCC to 5V, GND to GND, and DO (Digital Out) to Pin 2.
- De-energize the board: Ensure the Arduino is unplugged from USB and any external motor power supplies are turned off.
- Install the pull-up: Connect the 10kΩ resistor between the Arduino 5V pin and Digital Pin 2.
- Wire the sensor: Connect A3144 Pin 1 to 5V, Pin 2 to GND, and Pin 3 to Digital Pin 2 (the junction of the pull-up resistor).
- Install the bypass cap: Solder or breadboard the 0.1µF capacitor as close to the A3144 VCC and GND legs as physically possible.
- Mount the magnet: Secure the N42 neodymium magnet to your rotating shaft. Ensure the South pole faces the sensor (marked side of the A3144).
Complete C++ Code for RPM and Pulse Counting
This code targets the Arduino Uno R3. It uses hardware interrupts to catch every magnet pass without blocking the main loop, calculating RPM based on the microsecond interval between pulses. It includes error handling for zero-division and micros() overflow.
/*
* Arduino Hall Sensor RPM Tracker
* Target Board: Arduino Uno R3 (ATmega328P)
* Sensor: A3144EUA-T (Digital, Open-Drain)
* Author: ElectricalFlux
*/
// --- PIN DEFINITIONS ---
#define HALL_SENSOR_PIN 2
#define HALL_INTERRUPT digitalPinToInterrupt(HALL_SENSOR_PIN)
// --- CONFIGURATION ---
const float PULSES_PER_REV = 1.0; // Change if using multiple magnets
const unsigned long TIMEOUT_MICROS = 1000000; // 1 second timeout (60 RPM minimum)
// --- VOLATILE ISR VARIABLES ---
volatile unsigned long lastPulseMicros = 0;
volatile unsigned long pulseIntervalMicros = 0;
volatile bool newPulseReceived = false;
void setup() {
Serial.begin(115200);
// Configure pin with internal pull-up as a fallback (external 10k is preferred)
pinMode(HALL_SENSOR_PIN, INPUT_PULLUP);
// Attach interrupt: Trigger on FALLING edge (A3144 pulls low when magnet is near)
attachInterrupt(HALL_INTERRUPT, magnetDetectedISR, FALLING);
Serial.println("Hall Sensor RPM Tracker Initialized.");
}
void loop() {
unsigned long currentMicros = micros();
// Check for new pulse data
if (newPulseReceived) {
// Prevent division by zero
if (pulseIntervalMicros > 0) {
// RPM = (60 seconds * 1,000,000 microseconds) / (interval * pulses per rev)
float rpm = (60000000.0 / pulseIntervalMicros) / PULSES_PER_REV;
Serial.print("RPM: ");
Serial.println(rpm, 1); // 1 decimal place
}
newPulseReceived = false;
lastPulseMicros = currentMicros;
}
// Handle motor stall / timeout (prevents displaying stale high RPMs)
// Also handles micros() overflow safely
else if ((currentMicros - lastPulseMicros) > TIMEOUT_MICROS) {
if (pulseIntervalMicros != 0) { // Only print 0 once when it stalls
Serial.println("RPM: 0.0 (Motor Stalled or No Magnet)");
pulseIntervalMicros = 0;
}
}
}
// --- INTERRUPT SERVICE ROUTINE ---
void magnetDetectedISR() {
unsigned long currentMicros = micros();
// Debounce: Ignore pulses closer than 1000us (prevents double-triggers from magnet bounce)
if ((currentMicros - lastPulseMicros) > 1000) {
pulseIntervalMicros = currentMicros - lastPulseMicros;
lastPulseMicros = currentMicros;
newPulseReceived = true;
}
}
Debugging: First Three Things to Check When It Fails
When your serial monitor refuses to show the correct RPM, do not rewrite the code immediately. Hardware and physics are usually the culprits. Here is the ranked troubleshooting path.
Symptom 1: Serial monitor stuck at RPM: 0.0 or State: 1
This means the interrupt is never firing. The microcontroller never sees the pin go LOW.
- Missing or blown pull-up resistor: The A3144 is open-drain. Without a pull-up to 5V, the output pin floats. Measure the voltage at Digital Pin 2 with a multimeter; it should read ~5V when the magnet is away, and ~0.1V when the magnet is near. If it floats around 2.5V, your pull-up is missing.
- Wrong magnet polarity: The A3144 is South-pole activated. If you are using the North pole, the sensor will never trigger. Flip the magnet 180 degrees. (Refer to the Allegro A3144 Datasheet for hysteresis curves).
- Air gap exceeds threshold: Magnetic flux density drops off at the cube of the distance. An N42 magnet might trigger the A3144 at 15mm, but a weaker ceramic fridge magnet will fail at 5mm. Move the sensor within 5mm of the magnet.
Symptom 2: Compilation Error: 'digitalPinToInterrupt' was not declared in this scope
This exact error string appears if you copy this code to an ESP8266, ESP32, or ATTiny85 without modification.
- Cause: The
digitalPinToInterrupt()macro is specific to standard AVR Arduinos (Uno, Mega, Nano). - Fix for ESP32: Delete the macro and use the raw GPIO number in
attachInterrupt(). Example:attachInterrupt(2, magnetDetectedISR, FALLING);(Assuming GPIO 2).
Symptom 3: RPM reading fluctuates wildly (e.g., jumping from 1200 to 8500 RPM)
- Cause: Electromagnetic interference (EMI) from the motor brushes is inducing false voltage spikes on the sensor wire, tricking the interrupt.
- Fix: Ensure the 0.1µF ceramic bypass capacitor is installed directly across the sensor's VCC and GND. If using a long wire, add a 100Ω series resistor on the signal line right at the Arduino pin to form an RC low-pass filter with the internal pin capacitance.
Extending and Simplifying the Build
Depending on your final application, you may need to scale this project up for industrial use or down for low-power battery operation.
If you are tracking a slow-moving mechanism (like a wind turbine or a gate hinge) where RPM is under 60, drop the hardware interrupt. Use
digitalRead() inside a simple polling loop with a delay(50). This eliminates the ISR overhead, prevents debounce edge-cases, and allows the ATmega328P to enter deeper sleep states between reads.
How to Extend (High Speed / Multi-Sensor):
- Hardware Timers for >10,000 RPM: At extremely high RPMs, the ISR overhead (roughly 5-8 microseconds per trigger) can cause missed pulses or skew the main loop. Use the Arduino attachInterrupt() Reference to understand limits, then migrate to a hardware timer (like Timer1) configured in Input Capture mode to timestamp pulses at the silicon level without CPU intervention.
- Direction Tracking (Quadrature): If you need to know which way the shaft is spinning, add a second A3144 sensor offset by 90 degrees (mechanically) or wire up a dedicated quadrature encoder IC like the LS7366R. You will read the state of Sensor B inside Sensor A's ISR to determine direction.
- Display Output: To make it a standalone tachometer, wire an I2C SSD1306 128x64 OLED display to A4 (SDA) and A5 (SCL). Use the
Adafruit_SSD1306library, but remember to move the display update to a 10Hz timer in the main loop so the I2C bus blocking doesn't cause you to miss magnet pulses.
For reliable RPM tracking, the A3144EUA-T paired with a physical 10kΩ pull-up resistor and a 0.1µF bypass capacitor remains the undisputed standard. It provides the clean digital edges required for accurate microsecond timing, outperforming analog sensors and optical encoders in dusty, dirty, or poorly lit motor environments.






