Hall Effect Sensor Question

Hey everyone!

I am a senior Mechanical/Aerospace engineering student and am just getting into using the Arduino for some undergraduate research I am doing. I really am loving all the possibilities this little board offers and already have some projects planned with it. However, right now it is all business. I built a turntable-like device that is basically a small disk mounted on top of a continuous rotation servo. On the underside of the disk I have a fairly powerful magnet attached. As the disk rotates the magnet will pass over a Hall Effect sensor. The idea is that using this combination I can measure the revolutions per minute of the disk. However, I am not quite sure how to program the Arduino to do this for me. I can pick up code fairly quickly, but I am still a beginner and am not exactly sure how I should go about doing this. I did a quick search on Google and was a bit confused by the code I found, so I was wondering if anyone here had some code that could potentially solve my problem. Any explanations/commented code would be absolutely amazing, as I really want to learn how everything works and not just copy and paste some text. Thanks in advance to anyone who can help out, I appreciate it more than you know!

  • Mike

HI Mike,

Welcome to the wonderfull world of Arduino,

You could use an interrupt counter. See - http://www.arduino.cc/en/Reference/AttachInterrupt -

You should connect the signal of the hall sensor to the IRQ pin 2

int pin = 13;
volatile int state = LOW;
volatile unsigned long count = 0;
unsigned long lastTime = 0;

void setup()
  pinMode(pin, OUTPUT);
  attachInterrupt(0, irq, RISING);

void loop()
  digitalWrite(pin, state);

  if (millis() - lastTime > 60000L)
    lastTime = millis();

void irq()
  state = !state;

If you want a more instantaneous readout of rpm, you can measure the interval between pulses and convert that to RPM, like this.

const int sensorPin = 2;
const int ledPin = 13;
const int sensorInterrupt = 0;
const int timeoutValue = 5;

volatile unsigned long lastPulseTime;
volatile unsigned long interval = 0;
volatile int timeoutCounter;

bool blink = false;

void setup()
  pinMode(sensorPin, INPUT);
  digitalWrite(sensorPin, HIGH);    // enable internal pullup (if Hall sensor needs it)
  pinMode(ledPin, OUTPUT);
  attachInterrupt(sensorInterrupt, sensorIsr, RISING);
  lastPulseTime = micros();
  timeoutCounter = 0;

void sensorIsr()
  unsigned long now = micros();
  interval = now - lastPulseTime;
  lastPulseTime = now;
  timeoutCounter = timeoutValue;

void loop()
  Serial.print(" RPM ");
  if (timeoutCounter != 0)
    float rpm = 60e6/(float)interval;
    Serial.print(rpm, 1);
  blink = !blink;
  digitalWrite(ledPin, blink ? HIGH : LOW);

The timeout is to avoid displaying the last reading continuously when the rpm drops to very low values.

[EDIT: added 'volatile' qualifiers]

Well done dc42,
you have the better solution (IMHO), but you need to declare the global vars used in the irq as volatile

Well done dc42,
you have the better solution (IMHO), but you need to declare the global vars used in the irq as volatile

Quite right, I forgot to declare them volatile. Surprisingly perhaps, it works without. [Actually, not so surprising when you consider the program flow. But they should still be declared volatile.]