Hall sensor tachometer getting to much noise interference

Hi All,

I've put together a tachometer display to show the spindle speed on my lathe. It works well when bench testing but as soon as I go near the lathe with it the readout goes crazy.

I'm using and OLED for the display, an AH1807 Hall sensor and an Arduino Uno (RedBoard).

This is the data sheet for the hall sensor and it is wired according to the diagram on the second page.

I've tried 2 different hall circuit configurations.
First was to have the 10K resistor and 70nf capacitor down on the BOB with the arduino and the hall sensor by itself and the end of the wires.
When the lathe was started the displayed RPM would jump around within the 10s to 100s of thousands regardless of how fast/slow the lathe was running. If I was to move the hall sensor about 100mm away from the machine it would settle down and finally rest at 0 rpm.

Second attempt was to move the 68K resistor and 70nf capacitor up with the hall sensor.
In this configuration I found the arduino itself was susceptible to noise as well as the hall. But the end result was no different than the first. I had to remove both from within the lathe before it would settle down.

Is the a better way to wire a circuit to prevent this, or some way to shield everything from interference?

Cheers,
J

This is the code I'm using.

/*
 * This sketch is desinged for a Tachometer. A hall sensor reads pulses from magnets on a wheel which is counted
 * and converted to Revolutions Per Minute (RPM). It is then displayed on an OLED display.
 * Arduino Uno board.
 */
#include <Arduino.h>
#include <U8g2lib.h>

#ifdef U8X8_HAVE_HW_SPI
#include <SPI.h>
#endif

/* 
 *  Below is an entry for OLED display specific for the u8g2 library. OLED displays can be found under 
 *  File/Examples/u8g2/FullBuffer/FontUsage
 *  The complete list is available here: https://github.com/olikraus/u8g2/wiki/u8g2setupcpp
*/  
U8G2_SH1106_128X64_NONAME_F_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); 
                                        /* CLK = 13; MOSI = 11; These 2 aren't defined but need to be connected.
                                           Hall sensor connected to Pin 3, +5v and ground.*/
volatile byte  count = 0;
byte numCount = 8;   //number of pulse intervals to count before interupt.
byte multiplier = 60;  //Set this number according to how many pulses/magnets you have per 1 revolution. 
                       //(60 / the number of magnet you have). eg, 60/4 magnets = a multiplier of 15.                                                      
volatile unsigned long startTime;
volatile unsigned long endTime;
unsigned long copy_startTime;
unsigned long copy_endTime;
volatile boolean finishCount = false;
float period;
unsigned long rpm = 0;
unsigned long currentMillis;
unsigned long previousMillis;
unsigned long interval = 2000;


void setup(void) {
  
  attachInterrupt(digitalPinToInterrupt(3), isrCount, FALLING);//interrupt on pin3
  u8g2.begin();
  u8g2.enableUTF8Print();    // enable UTF8 support for the Arduino print() function
  u8g2.clearBuffer();
  u8g2.setFont(u8g2_font_smart_patrol_nbp_tf);
  u8g2.setCursor(25, 30);
  u8g2.print("NUMBER 5");
  u8g2.setCursor(25, 50);
  u8g2.print("IS ALIVE !!");  
  u8g2.sendBuffer();
  delay (5000);
}

void loop(void) {
  
  u8g2.clearBuffer();
//  u8g2.setFont(u8g2_font_ncenB10_tr);
//  u8g2.setFont(u8g2_font_sirclivethebold_tr);
  u8g2.setFont(u8g2_font_smart_patrol_nbp_tf);
  u8g2.setCursor(52, 20);
  u8g2.print("RPM:");
//  u8g2.setFont(u8g2_font_inr24_mf);
  u8g2.setFont(u8g2_font_osr21_tn);
  u8g2.setCursor(35, 55);
  u8g2.print(rpm);
//  u8g2.print("3568");
  u8g2.sendBuffer();
  
  if (finishCount == true)
  {
    finishCount = false;//reset flag
    
    // disable interrupts, make protected copy of time values
    noInterrupts();
    copy_startTime = startTime;
    copy_endTime = endTime;
    count = 0;
    interrupts();

    period = (copy_endTime - copy_startTime) / 1000.0; //micros to millis
    rpm = numCount * multiplier * (1000.0 / period);

    previousMillis = currentMillis;
  }
  
  else if (finishCount == false)
  {
     currentMillis = millis();
     if(currentMillis - previousMillis >= interval) 
     {
      //Displays RPM as 0 if numCount is not met within the interval time limit.
        rpm = 0;
     }
  }
}

void isrCount()
{
  if (count == 0) //first entry to isr
  {
    startTime = micros();
  }

  if (count == numCount)
  {
    endTime = micros();
    finishCount = true;   
  }
  count++; //increment after test for numCount
}

Use shielded or twisted pair cable to reduce external noise. Connect Arduino GND to machine GND.

Eventually the sensor is too sensitive for your application. Mount it onto a U shaped iron/ferrite core to limit the sensitive area to the open end of the U. Modify the mounting to match the sensitivity direction of the sensor, the data sheet contains almost no hints.

Hi,

Can you please post a copy of your circuit, in CAD or a picture of a hand drawn circuit in jpg, png?

Have you tried using a drill as your source of rotation to check if it is code or interference from the lathe motor?

Have you got some simple code that just puts the RPM on serial monitor and does not have any of the display code in it?

Thanks... Tom.... :slight_smile:

Thanks for the replies,

The diagram attached is rough and ready. The components used are not quite right but the wiring is accurate.

I've put the 10k resistor and 70nf cap back back on the BOB, Wrapped the cable that runs from the BOB to the hall sensor with tin foil, looked through / adjusted the code and ran some tests using a small geared motor and serial monitor.

This is the code I used to run the test.

/*
 * This sketch is desinged for a Tachometer. A hall sensor reads pulses from magnets on a wheel which is counted
 * and converted to Revolutions Per Minute (RPM). It is then displayed on an OLED display.
 * Arduino Uno board.
 */
#include <Arduino.h>
/*#include <U8g2lib.h>

#ifdef U8X8_HAVE_HW_SPI
#include <SPI.h>
#endif

/* 
 *  Below is an entry for OLED display specific for the u8g2 library. OLED displays can be found under 
 *  File/Examples/u8g2/FullBuffer/FontUsage
 *  The complete list is available here: https://github.com/olikraus/u8g2/wiki/u8g2setupcpp
*/  
//U8G2_SH1106_128X64_NONAME_F_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); 
                                        /* CLK = 13; MOSI = 11; These 2 aren't defined but need to be connected.
                                           Hall sensor connected to Pin 3, +5v and ground.*/
volatile byte  count = 0;
byte numCount = 5;   //number of pulse intervals to count before interupt.
byte multiplier = 60;  //Set this number according to how many pulses/magnets you have per 1 revolution. 
                       //(60 / the number of magnet you have). eg, 60/4 magnets = a multiplier of 15.                                                      
volatile unsigned long startTime;
volatile unsigned long endTime;
unsigned long copy_startTime;
unsigned long copy_endTime;
volatile boolean finishCount = false;
float period;
unsigned long rpm = 0;
unsigned long currentMillis;
unsigned long previousMillis;
unsigned long zeroOut = 5000;


void setup() {

  Serial.begin(9600);
  attachInterrupt(digitalPinToInterrupt(3), isrCount, FALLING);//interrupt on pin3
/*  u8g2.begin();
  u8g2.enableUTF8Print();    // enable UTF8 support for the Arduino print() function
  u8g2.clearBuffer();
  u8g2.setFont(u8g2_font_smart_patrol_nbp_tf);
  u8g2.setCursor(25, 30);
  u8g2.print("NUMBER 5");
  u8g2.setCursor(25, 50);
  u8g2.print("IS ALIVE !!");  
  u8g2.sendBuffer();
  delay (5000);*/
}

void loop() {
  
/*  u8g2.clearBuffer();
  u8g2.setFont(u8g2_font_smart_patrol_nbp_tf);
  u8g2.setCursor(52, 20);
  u8g2.print("RPM:");
  u8g2.setFont(u8g2_font_osr21_tn);
  u8g2.setCursor(35, 55);
  u8g2.print(rpm);
  u8g2.sendBuffer();*/
  
  if (finishCount == true)
  {
     finishCount = false;//reset flag
    
     // disable interrupts, make protected copy of time values
     noInterrupts();
     copy_startTime = startTime;
     copy_endTime = endTime;
     count = 0;
     interrupts();

     period = (copy_endTime - copy_startTime) / 1000.0; //micros to millis
     rpm = numCount * multiplier * (1000.0 / period);
     Serial.print("period ");
     Serial.print(period);
     previousMillis = currentMillis;
     startTime = endTime;
     Serial.print("  RPM ");
     Serial.println(rpm);
  }
  
  else if (finishCount == false)
  {
     currentMillis = millis();
     
     if(currentMillis - previousMillis >= zeroOut) 
     {
      //Displays RPM as 0 if numCount is not met within the zeroOut time limit.
        rpm = 0;
      //  Serial.println("RPM 0");
     }
  }
}

void isrCount()
{
  if (count == 0) //first entry to isr
  {
     startTime = micros();
  }

  if (count == numCount)
  {
     endTime = micros();
     finishCount = true;
     loop();   
  }
  count++; //increment after test for numCount
  Serial.println(count);
}

And these are the results. I think the discrepancies are due to me not holding the motor and hall sensor steady and in the same position the whole time.

1
2
3
4
5
period 1637.25  RPM 183
1
2
3
4
5
period 1251.96  RPM 239
1
2
3
4
5
period 1637.38  RPM 183
1
2
3
4
5
period 1251.96  RPM 239
1
2
3
4
5
period 1348.21  RPM 222
1
2
3
4
5
period 1348.31  RPM 222
1
2
3
4
5
period 1348.26  RPM 222
1
2
3
4
5
period 1251.95  RPM 239
1
2
3
4
5
period 1637.26  RPM 183
1
2
3
4
5
period 1636.89  RPM 183
1

Serial.print in an ISR is a no-no-no-no!!

Paul

Ok got rid of the Serial.print in the Void irsCount()

Results seem to be a bit more stable.

period 2792.00 RPM 107
period 3081.06 RPM 97
period 6454.22 RPM 46
period 1829.88 RPM 163
period 2022.81 RPM 148
period 2118.96 RPM 141
period 2023.18 RPM 148
period 2119.04 RPM 141
period 1830.36 RPM 163
period 1830.22 RPM 163
period 1830.20 RPM 163
period 1830.07 RPM 163
period 2119.31 RPM 141

That is great! Are you cutting anything on the lathe? Is it a metal working lathe or wood? Seems pretty slow for wood.

Paul

I've been trying to get a stable readout by setting the test gearmotor and hall at a fixed distance but I'm not convinced the hall is picking up every passing from the magnet. It all seems a bit to finicky.

Might be worth taking JCA34F's advice and try an optical sensor but I hate letting something like this get the better of me.

period 6353.94  RPM 47
period 2504.00  RPM 119
period 1540.81  RPM 194
period 1444.63  RPM 207
period 1830.04  RPM 163
period 1829.86  RPM 163
period 1829.91  RPM 163
period 1540.91  RPM 194
period 1829.90  RPM 163
period 2311.17  RPM 129
period 1733.64  RPM 173
period 1829.59  RPM 163
period 1637.34  RPM 183
period 1829.56  RPM 163
period 1926.21  RPM 155
period 2022.21  RPM 148
period 2022.27  RPM 148
period 2407.40  RPM 124
period 2022.12  RPM 148
period 1829.28  RPM 163
period 2311.51  RPM 129
period 2022.98  RPM 148
period 2119.19  RPM 141
period 1830.30  RPM 163
period 1733.72  RPM 173
period 2601.57  RPM 115
period 1829.95  RPM 163
period 2600.66  RPM 115
period 2312.08  RPM 129
period 1830.28  RPM 163
period 1830.59  RPM 163
period 2023.10  RPM 148
period 1830.38  RPM 163
period 1830.25  RPM 163
period 1830.27  RPM 163
period 1830.16  RPM 163
period 2023.22  RPM 148
period 2023.12  RPM 148
period 2312.32  RPM 129
period 2023.49  RPM 148
period 2601.29  RPM 115

It's a small metal lathe and those speeds are from a test rig. If I take it near the lathe it goes haywire.

Hi,
OPs image,


How many magnets do you have on the shaft, and are they all oriented the same way?
Tom... :slight_smile:

Just the one magnet. And I don't think it matters which way it is with the AH1807 Hall. The magnet is a little ND 3mm diameter x 4mm length. Not sure on the gauss but it should provide ample field for the hall.

gyrojeremy:
Just the one magnet. And I don't think it matters which way it is with the AH1807 Hall. The magnet is a little ND 3mm diameter x 4mm length. Not sure on the gauss but it should provide ample field for the hall.

Do yu have a much weaker magnet to test with? That one may be spreading it's field so far that there are twists and wriggles in the field.

Is the magnet mounted on steel or other magnetic material? If so, it may be creating other magnetic fields.

Paul

A magnet on/in steel, the steel will try and soak up the field.

Hall sensors have an axis they measure field along, it should align with N-S to get the highest reading.

gyrojeremy:
Just the one magnet. And I don't think it matters which way it is with the AH1807 Hall. The magnet is a little ND 3mm diameter x 4mm length. Not sure on the gauss but it should provide ample field for the hall.

That should be okay, if you use a DMM and measure the output voltage of the sensor, you should be able to see it change as the magnet goes by when you rotate by hand.

Can you post a picture of your project so we can see your component layout please?
Tom.... :slight_smile:

Is the Hall device a sensor or a switch? The switch is cheaper.

I think the hall is a switch.

I've been testing using this code to see if u8g2.print is slowing things down. Using a drill and one magnet turning at 1500rpm the hall is only picking up roughly 20 pulses per 5 seconds. I should be getting around 125 pulses each time the display updates

/*

#include <Arduino.h>
#include <U8g2lib.h>

#ifdef U8X8_HAVE_HW_SPI
#include <SPI.h>
#endif

  
U8G2_SH1106_128X64_NONAME_F_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); 

int hallPin = 3;
int val;
int lastVal;
int count=0;
int updateTime=5000;
unsigned long previousMillis = 0;

void setup() {

//  Serial.begin(9600);
  pinMode(hallPin, INPUT);
  u8g2.begin();
  u8g2.enableUTF8Print();    // enable UTF8 support for the Arduino print() function

}

void loop() {

  unsigned long currentMillis = millis();

    if (currentMillis - previousMillis >= updateTime) {
    // save the last time you blinked the LED
    previousMillis = currentMillis;
     u8g2.clearBuffer();
     u8g2.setFont(u8g2_font_smart_patrol_nbp_tf);
     u8g2.setCursor(30, 20);
     u8g2.print("Pulses ");
     u8g2.setFont(u8g2_font_osr21_tn);
     u8g2.setCursor(35, 55);
     u8g2.print(count);
     u8g2.sendBuffer();
    }

     val = digitalRead(hallPin);
  if(val != lastVal){
     if(val == LOW){
        count++ ;
     }  
  }
  lastVal=val;
}


20200720_173112[1].jpg

20200720_173205[1].jpg

Hi,
Back in post #3 I suggested you write a simple code for the tacho WITHOUT any display code included in it.

Have you tried this?

Thanks.. Tom.. :slight_smile:

Hey tom,
I tried the code I posted above with the OLED display and without the OLED and all associated libraries. Basically a stripped down version. Like this one.

int hallPin = 3;
int val;
int lastVal;
int count=0;
int updateTime=5000;
unsigned long previousMillis = 0;

void setup() {

  Serial.begin(9600);
  pinMode(hallPin, INPUT);

}

void loop() {

  unsigned long currentMillis = millis();

    if (currentMillis - previousMillis >= updateTime) {
    // save the last time you blinked the LED
    previousMillis = currentMillis;
  
     Serial.println(count);
    }

     val = digitalRead(hallPin);
  if(val != lastVal){
     if(val == LOW){
        count++ ;
     }  
  }
  lastVal=val;
}

I also tried the original code without the OLED, just serial monitor. In both cases the results are not promising.
I think after about 150 - 200 rpm the hall can't keep up.

I forgot to mention the magnet is mounted in an aluminium pulley. The pulley is mounted on a steel shaft. At a guess I would say there is 5-10mm of alloy between the magnet and shaft. The gear next to the pulley is plastic.

20200720_191501[1].jpg

I also try a sketch that counted up with every arduino cycle to see if the OLED could keep up with the count. And it was counting up pretty fast. got into the thousands pretty quickly.