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);
  Serial.begin(115200);
}

void loop()
{
  digitalWrite(pin, state);

  if (millis() - lastTime > 60000L)
  {
    lastTime = millis();
    Serial.println(count);
  }
}

void irq()
{
  state = !state;
  count++;
}

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);
  Serial.begin(9600);
  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)
  {
    --timeoutCounter;
    float rpm = 60e6/(float)interval;
    Serial.print(rpm, 1);
  }
  Serial.println();
  delay(500);
  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

robtillaart:
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.]