Hall sensor tachometer getting to much noise interference

const byte hallPin = 3;

byte val, lastVal;

word count;  // 0 is default value

unsigned long updateTime = 5000;
unsigned long previousMillis = 0;

void setup() {

  Serial.begin(115200); // change Monitor to match, high speed prints faster

  pinMode(hallPin, INPUT);

}

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

    if (millis() - previousMillis >= updateTime) 
    {
      // save the last time you blinked the LED
      previousMillis += updateTime;  // keeps this time from "slipping" due to >= interval
  
      Serial.println(count);
      count = 0;
    }
}

BTW, if you print HEX instead of DEC, the conversion to text will be quicker.
Converting binary values to decimal text is one of the hidden costs of print.

Thanks for the tip. I really struggle with code. I swapped out the hall sensor for a photo interrupter and a 2 speed drill with a 4 gaped disk mounted in the chuck.
Turns out the code I posted at the start doesn't work. It wouldn't read anything above about 200rpm.
I've been surfing the web for another piece of code but nothing I've tried works. Can't work out why. I even tried a Mega to see it made a difference.

20200721_195516[1].jpg

Did you try the sketch I posted?
Possibly change the Hall pin mode to INPUT_PULLUP. If your Hall circuit isn't delivering enough to push a pin HIGH, the mode will do it and a HALL LOW will take INPUT_PULLUP down LOW very quickly.

Arduino Mega has the same CPU core as every other ATmega chip.

Calculate how long in millis it takes for the drill at full RPM to make a revolution. A sketch should be able to poll the sensor 50 or more times per milli if there is nothing blocking execution, and that is what I left a 1st draft of. If it can't keep up, I would look to the circuit connecting the sensor first.

How close do you have the drill motor running to unshielded jumpers? A hands-width might be okay and easy to check with a simple sketch and analog reads of a jumper near a running drill. When you test, you become more sure, for sure.

Yip I tried your sketch. It made sense what you put in there. I can't remember the out come of that as I've tried so many variations of different sketches in the last few days.

After doing a bit more research in how interrupts work I did find a major floor in my original code. Turns out I shouldn't be calling for "micros" inside the irs function. I also wondered if by giving the sensor pin a longer time to change from HIGH to LOW would make any difference.

So I relocated that part part of the code

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

   if (count == numCount)
   {
       endTime = micros();
       finishCount = true;
   }

And printed out a new shaped disk with just 2 slots

It appears to be working up to around 1100rpm (I think that's as fast as my drill goes). The RPM jumps around by +-150rpm at that speed so I guess the next step is to implement some smoothing.

20200722_124837[1].jpg

Here is the latest sketch I'm running

/*

#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); 
                                       
volatile byte  count = 0;
byte numCount = 20;   //number of pulse intervals to count before interupt.
byte multiplier = 30;  //Set this number according to how many pulses you have per 1 revolution. 
                       //(60 / the number of pulses you have). eg, 60/4 pulse = 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 = 10000;
//-------------------------------------------
void setup() 
{
  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(28, 50);
  u8g2.print("IS ALIVE !!");  
  u8g2.sendBuffer();
  delay (5000);
/*  Serial.begin(9600);
  Serial.print(" READY   ");
  delay(1500);
  Serial.print(" SET   ");
  delay(1500);
  Serial.println(" GO!! ");
  delay(1500); */
}
//----------------------------------------------
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();
/*  Serial.print(" RPM ");
  Serial.print(rpm);
  Serial.print("   Count ");
  Serial.println(count);*/
//------------------------------------------------  
   if (finishCount == true)
   {
       finishCount = false;//reset flag

       noInterrupts();  // disable interrupts, make protected copy of time values
       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 >= zeroOut)   //Displays RPM as 0 if numCount is not met within the zeroOut time limit.
       {
          rpm = 0;
       }
//-------------------------------------------------       
   }
   if (count == 0) //first entry to isr
   {
       startTime = micros();
   }

   if (count == numCount)
   {
       endTime = micros();
       finishCount = true;
   }
}

void isrCount()
{
  count++; //increment after test for numCount
}

You may do better to add a little more to the ISR. See this example of where the count is incremented within the isr and how the start and end time are picked up.

volatile unsigned long isrMicros;
unsigned long latestIsrMicros;
unsigned long previousIsrMicros;
unsigned long microsThisRev;
volatile boolean newISR = false;


void setup()
{
  attachInterrupt(0, myISR, RISING);
}

void loop() {
  if (newISR == true) {
    previousIsrMicros = latestIsrMicros; // save the old value
    noInterrupts(); // pause interrupts while we get the new value
    latestIsrMicros = isrMicros;
    newISR = false;
    interrupts();
    microsThisRev = latestIsrMicros - previousIsrMicros;
   //Serial print or process the time value
  }
}

void myISR() {
  static byte count; // if number of counts less than 255, other wise type as static unsigned int
  count++;
  if (count == 60) // some number which makes sense for you rotations
  {
    isrMicros = micros();
    newISR = true;
    count = 0;
  }
}

I did have something similar to that in the original sketch but I relocated it after reading this in the arduino reference.

Generally, an ISR should be as short and fast as possible. If your sketch uses multiple ISRs, only one can run at a time, other interrupts will be executed after the current one finishes in an order that depends on the priority they have. millis() relies on interrupts to count, so it will never increment inside an ISR. Since delay() requires interrupts to work, it will not work if called inside an ISR. micros() works initially but will start behaving erratically after 1-2 ms. delayMicroseconds() does not use any counter, so it will work as normal.

Ok. Ive been busy test cycle speeds all afternoon and turns out the code I posted last has a clock speed of 0.011244 seconds while at idle and up to 0.02 seconds when running, which is not very impressive and is therefor missing pulses from the sensor or processing the program incorrectly.

The results of that are unstable, giving me fluctuation of +- 500rpm and often freezing on an rpm including 0rpm.

I've been working on this code in the background which came up with great cycle times even with u8g2lib
and u8g2.print. Something like 0.000009 seconds per cycle. Big difference!

#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.
                       // Sensor connected to Pin 3, +5v and ground.
const byte photoInterupterPin = 3;
byte val, lastVal;
unsigned long RPM;
word count;  // 0 is default value
unsigned long updateTime = 1000;
unsigned long previousMillis = 0;

void setup() {

  Serial.begin(9600); // change Monitor to match, high speed prints faster
  pinMode(photoInterupterPin, INPUT);
  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(28, 50);
  u8g2.print("IS ALIVE !!");  
  u8g2.sendBuffer();
  delay (5000);

}

void loop() {
  
  val = digitalRead(photoInterupterPin);
    if (val != lastVal)
    {
       if (val == LOW)
       {
         count++ ;
       } 
    }
  lastVal=val;
  RPM = (count/2)/1*60; 

    if (millis() - previousMillis >= updateTime)
    {
       previousMillis += updateTime;  // keeps this time from "slipping" due to >= interval
       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();
       count = 0;
    }
}

The readouts from this are much more stable and consistent, not really varying at all.

I guess only time will tell if it can handle speeds above 1200rpm.

The code can become faster if not required evaluations are suppressed. In fact calculations only are required when count changes.

  val = digitalRead(photoInterupterPin);
  if (val != lastVal)
  {
     lastVal=val;
     if (val == LOW)
     {
       count++ ;
       RPM = (count/2)/1*60; //eq: RPM += 30;
     }
  }

Every other count is lost by count/2, otherwise each count increments RPM by 30.

For less jitter I'd reset previousMilliis just after the output:

    if (millis() - previousMillis >= updateTime)
    {
       ...
       count = 0;
       previousMillis = millis;  // ignore time spent in display
     }

You really should set serial to 115200 or faster to get the output print buffer empty quicker.

Set the same rate on Serial Monitor down in the lower right corner.

Integer RPM won't be as accurate as a Frequency (count) readout.

1200 RPM is only 20 revs/sec, 50 ms per rev. Arduino can read 50 micros frequency with polling.

You can replace the Arduino digitalRead() with direct port manipulation code which is 5x faster.

Cut narrower slots in your disk for higher accuracy. Calculate how long they will be open in the light gate, in micros. It really does take a while for the speed Arduino is capable of to sink in.

Also see about changing from millis() to micros() as millis aren't just wider but the timing can be +/- 1ms.

When close counts, use micros.

Ok, I tried to take your advice and apply it to my original sketch. Here's what I come up with.

#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.
                       // Sensor connected to Pin 3, +5v and ground.
volatile byte  count = 0;
byte numCount = 100;    //number of interrupts to count.
byte multiplier = 6;  //Set this number according to how many pulses you have per 1 revolution. 
                       //(60 / the number of pulses you have). eg, 60/4 pulse = a multiplier of 15.                                                      
volatile unsigned long startTime;
volatile unsigned long endTime;
volatile boolean finishCount = false;
volatile float period;
float previousPeriod = 0.0;
unsigned long bufferPeriod = 100;  //buffer for smoothing out rpm readings
unsigned long rpm = 0;
unsigned long currentMillis;
unsigned long previousMillis;
unsigned long zeroOut = 1000;
//-------------------------------------------
void setup() 
{
  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(28, 50);
  u8g2.print("IS ALIVE !!");  
  u8g2.sendBuffer();
  delay (2000);
}
//----------------------------------------------
void loop() 
{ 
   if (count == 0) 
   {
       startTime = micros();
   }
   if (count == numCount)
   {
       endTime = micros();
       finishCount = true;
   }
   if (finishCount == true)
   {
       finishCount = false;//reset flag
       period = (endTime - startTime) / 1000.0; //micros to millis 
       noInterrupts();
       if ((period <= previousPeriod - bufferPeriod) || (period >= previousPeriod + bufferPeriod))
       {
          rpm = numCount * multiplier * (1000.0 / period);
          displayRPM();
       }
       interrupts();
       previousPeriod = period;
       previousMillis = currentMillis;
       count = 0;       
   }
   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;
          displayRPM();
       }
   }
}
//-------------------------------------------------
void isrCount()
{
  count++; //increment numCount
}
//-------------------------------------------------
void displayRPM()
{
   u8g2.clearBuffer();
   u8g2.setFont(u8g2_font_smart_patrol_nbp_tf);
   u8g2.setCursor(20, 20);
   u8g2.print("Rev Per Min:");
   u8g2.setFont(u8g2_font_osr21_tn);
   u8g2.setCursor(35, 55);
   u8g2.print(rpm);
   u8g2.sendBuffer();
}

It appears to be working ok on the drill up to 1200rpm, stable and accurate. And doesn't increment in multiples of 60. I'm current printing out a 10 gap disk for the lathe spindle and will put it to the test once it's done.

Well that didn't work. It's favorite speed was 3673rpm. For a start my lathe shouldn't be spinning that fast and when I slowed it down it still read 3673rpm. In fact the only time it didn't read 3673rpm was when the lathe was stopped. At least that parts working correct.

Oh well. I'll keep plucking away with this sketch and use the other one in the mean time.

20200724_222307[1].jpg

       period = (endTime - startTime) / 1000.0; //micros to millis

When you changed micros to millis you lost 3 digits accuracy. Why?

The difference between 123.456 and 123456 is just what unit you count with.
123456 micros is 123.456 millis but no decimal point needed.

Call them your working units and only convert to make display units.

       // this is more than 250x on-the-mark using micros than when using millis.

       if ((period <= previousPeriod - bufferPeriod) || (period >= previousPeriod + bufferPeriod))

16-bit micros can count up to 65.535 millis. At full speed I think it takes far less time between gaps while at low speed maybe not. 16-bit math runs twice as fast as 32-bit is why to measure and possibly go from unsigned long to word variables for time. Both are unsigned which is critical to time difference calculating.

What went wrong with your code... nothing jumped out at me on the first look.

Why so many volatile variables? The only volatile is 'count'.

I'd stop the interrupts during evaluation, finally set count=0 and in the next iteration of loop() enable the interrupts again iff count==0.

Changed everything to micros(), got rid of volatiles and played with the timing of the bufferPeriod. Seems to work pretty slick up to around 1000rpm. My drill only goes to 1150rpm and if I slowly increase the rpm the display only updates to about 1050rpm and doesn't register the last 100rpm. If I gun it (the drill) straight to full speed then it registers/displays 1150rpm

DrDiettrich:
I'd stop the interrupts during evaluation, finally set count=0 and in the next iteration of loop() enable the interrupts again iff count==0.

Not sure how or where to put this in without blocking the rest of the code?

Latest code update

#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.
                       // Sensor connected to Pin 3, +5v and ground.
volatile byte  count = 0;
byte numCount = 100;    //number of interupts to count.
byte multiplier = 6;  //Set this number according to how many pulses you have per 1 revolution. 
                       //(60 / the number of pulses you have). eg, 60/4 pulse = a multiplier of 15.                                                      
 unsigned long startTime;
 unsigned long endTime;
 boolean finishCount = false;
 float period = 0.0;
float previousPeriod = 0.0;
unsigned long bufferPeriod = 20000;  //buffer for smoothing out rpm readings
unsigned long rpm = 0;
unsigned long currentMicros;
unsigned long previousMicros;
unsigned long zeroOut = 6000000;

//-------------------------------------------
void setup() 
{
  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(28, 50);
  u8g2.print("IS ALIVE !!");  
  u8g2.sendBuffer();
  delay (2000);
}
//----------------------------------------------
void loop() 
{ 
   if (count == 0) 
   {
       startTime = micros();
   }
   if (count == numCount)
   {
       endTime = micros();
       finishCount = true;
   }
   if (finishCount == true)
   {
       noInterrupts();
       finishCount = false;//reset flag
       period = (endTime - startTime);
       
       if ((period <= previousPeriod - bufferPeriod) || (period >= previousPeriod + bufferPeriod))
       {
          rpm = numCount * multiplier * (1000000.0 / period);
          displayRPM();
       }
       interrupts();
       previousPeriod = period;
       previousMicros = currentMicros;
       count = 0;       
   }
   else if (finishCount == false)
   {
       currentMicros = micros();
       if (currentMicros - previousMicros >= zeroOut)   //Displays RPM as 0 if numCount is not met within the zeroOut time limit.
       {
          rpm = 0;
          displayRPM();
       }
   }
}
//-------------------------------------------------
void isrCount()
{
   count++; //increment numCount
}
//-------------------------------------------------
void displayRPM()
{
   u8g2.clearBuffer();
   u8g2.setFont(u8g2_font_smart_patrol_nbp_tf);
   u8g2.setCursor(20, 20);
   u8g2.print("Rev Per Min:");
   u8g2.setFont(u8g2_font_osr21_tn);
   u8g2.setCursor(35, 55);
   u8g2.print(rpm);
   u8g2.sendBuffer();
}
byte numCount = 100;    //number of interupts to count.
byte multiplier = 6;  //Set this number according to how many pulses you have per 1 revolution.
                       //(60 / the number of pulses you have). eg, 60/4 pulse = a multiplier of 15.                                                      

........

 float period = 0.0;
float previousPeriod = 0.0;

.......

Arduinos (with rare exceptions) do not have Floating Point Units, only slow and crappy 32-bit FP.

Work with micros, display seconds.

This is not going to give RPM.

       if ((period <= previousPeriod - bufferPeriod) || (period >= previousPeriod + bufferPeriod))
       {
          rpm = numCount * multiplier * (1000000.0 / period);
          displayRPM();
       }

RPS = numCount * 1000000 / multiplier / period; // numCount slots pass, multiplier slots pass per rev.

( numCount * 1000000 / multiplier ) gives millionths of a rev, period is UL elapsed millionths of a second.

1200 RPM is 20 RPS, 120 slots/sec, and numCount == 100, takes 833333 micros for 16.667

100000000 uCounts / 6 / 833333 = 20.000008 RPS, 20 uRevs/uSec.

20 RPS * 60 Sec/Min = 1200 RPM

TBH, I did integer math a lot at work long before FPU's became standard in CPU's (x486 IIRC) and in school math was on paper, chalkboard, or in the head for me. I have a gift for it and years of practice that hammered it in deep. If you go back to pencil and paper which I sometimes still do, where the decimal goes is all in the units. It's functionally the same as fixed-point but less fool-yourself.

Consider how we talk about mV with leds. That is thousands of volt and no decimal, if we want more we go to microvolts (a digitalRead soaks up about 1 uA), 6 places accuracy so if 2 or 3 are lost to division rounding there's still 3 or 4 places precise.

Integer operations mostly beat floating point, except at multiply or divide by 10 and there is a FAST div/10 up on the Arduino Playground.

And sometime have a look at 64-bit type unsigned long long, can hold any UL * any UL when scaling 32-bit unsigned long (UL) --- then you divide back down into a 32-bit. Morris Dovey wrote a clock library that uses ULL timers, good for billions of years!

1200 RPM = 20 RPS gives 50000 micros per rev, 8333 micros per 1/6th rev (slot to slot).

Here is a sketch that tells you how many times void loop() ran in the last second.
With not much to do, that number is > 100K.
That function is for putting in a sketch and seeing how responsive it is.
It is not hard to poll a digital sensor and do a few other things (like count loops, blink leds, etc) with loop() running 67 KHz. Add analog read it will slow down. Remember that 10 KHz means on average sensing and running tasks 10 times every millisecond, every 100 micros where slot to slot at 1200 RPM takes 8333 micros. Get the scale and speed, each slot might be detected more than once -- why bother with interrupts? If you were timing 1 rev then sure, you need interrupt-close timing.

// add-a-sketch_loop_counter 2018 by GoForSmoke @ Arduino.cc Forum
// Free for use, Apr 29/2018 by GFS. Compiled on Arduino IDE 1.6.9.
// This sketch counts times that loop has run each second and prints it.
// It uses the void LoopCounter() function that does not block other code.

#define microsInOneSecond 1000000UL

void setup()
{
  Serial.begin( 115200 );
  Serial.println( F( "\n\n\n  Loop Counter, free by GoForSmoke\n" ));
  Serial.println( F( "This sketch counts times that loop has run each second and prints it." ));
}

void LoopCounter() // tells the average response speed of void loop()
{ // inside a function, static variables keep their value from run to run
  static unsigned long count, countStartMicros; // only this function sees these

  count++; // adds 1 to count after any use in an expression, here it just adds 1.
  if ( micros() - countStartMicros >= microsInOneSecond ) // 1 second
  {
    countStartMicros += microsInOneSecond; // for a regular second
    Serial.println( count ); // 32-bit binary into decimal text = many micros
    count = 0; // don't forget to reset the counter 
  }
}

void loop()  // runs over and over, see how often with LoopCounter()
{
  LoopCounter(); // the function runs as a task, the optimizer will inline the code.
}

That's a whole lot of math and it really had me stumped for a while because I was getting the same rpm read out as your answer.
I think where we are getting our wires crossed is the "multiplier". I think your thinking it corresponds to the number of slots in the wheel but in fact it's 60/theNumberOfSlots (10) which would give a "multiplier"of 6. The number of slots in the wheel is 10.

I change the code to eliminate further confusion.

But this did prompt me to do further research and I stumbled across a post with a suggestion to only update a section of the display. This way I could remove the call for u8g2.print("Rev Per Min:") each time it updates and just update the section of screen that displays the actual RPM readout.

So like most of my coding it was just a case of copying and pasting and trial and error till something worked! And I ended up with a nice little box around the rpm readout as well. :slight_smile:

GoForSmoke:
why bother with interrupts? If you were timing 1 rev then sure, you need interrupt-close timing.

I would like to see this sketch working with interrupts as there is a future possibility of modifying it to accommodate a second IR sensor. But more so, I just like the opportunity to learn about it and see it through. So learning about cycle times, what/why it slows them down and having the means to test it is a great thing to know.

20200726_231259[1].jpg

Updated code. I'll test it on the lathe tomorrow. It seems pretty good on the drill.

#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.
                       // Sensor connected to Pin 3, +5v and ground.
volatile byte  count = 0;
byte numCount = 100;    //number of interupts to count.
byte slotsInDisk = 10;                                                       
 unsigned long startTime;
 unsigned long endTime;
 boolean finishCount = false;
float period;
unsigned long previousPeriod;
unsigned long bufferPeriod = 2000;  //buffer for smoothing out rpm readings
unsigned long rpm = 0;
unsigned long rps = 0;
unsigned long currentMicros;
unsigned long previousMicros;
unsigned long zeroOut = 6000000;

const uint8_t tile_area_x_pos = 2;  // Update area left position (in tiles)
const uint8_t tile_area_y_pos = 4;  // Update area upper position (distance from top in tiles)
const uint8_t tile_area_width = 12;
const uint8_t tile_area_height = 3; // this will allow cour18 chars to fit into the area
const u8g2_uint_t pixel_area_x_pos = tile_area_x_pos*8;
const u8g2_uint_t pixel_area_y_pos = tile_area_y_pos*8;
const u8g2_uint_t pixel_area_width = tile_area_width*8;
const u8g2_uint_t pixel_area_height = tile_area_height*8;

//-------------------------------------------
void setup() 
{
  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(28, 50);
  u8g2.print("IS ALIVE !!");  
  u8g2.sendBuffer();
  
  delay (4000);
  u8g2.clearBuffer();
  u8g2.setFont(u8g2_font_smart_patrol_nbp_tf);
  u8g2.setCursor(20, 27);
  u8g2.print("Rev Per Min:");
  u8g2.drawBox(pixel_area_x_pos-1, pixel_area_y_pos-1, pixel_area_width+2, pixel_area_height+2);
  u8g2.sendBuffer();
}
//----------------------------------------------
void loop() 
{ 
   if (count == 0) 
   {
       startTime = micros();
   }
   if (count == numCount)
   {
       endTime = micros();
       finishCount = true;
   }
   if (finishCount == true)
   {
       finishCount = false;
       noInterrupts();       
       period = (endTime - startTime); 
       if ((period <= previousPeriod - bufferPeriod) || (period <= previousPeriod + bufferPeriod))
       {
          rpm = (numCount * 1000000.0 / slotsInDisk) / period * 60;
          displayRPM();
       }
       interrupts();
       previousPeriod = period;
       previousMicros = currentMicros;
       count = 0;       
   }
   else if (finishCount == false)
   {
       currentMicros = micros();
       if (currentMicros - previousMicros >= zeroOut)   //Displays RPM as 0 if numCount is not met within the zeroOut time limit.
       {
          rpm = 0;
          displayRPM();
       }
   }
}
//-------------------------------------------------
void isrCount()
{
   count++; //increment numCount
}
//-------------------------------------------------
void displayRPM()
{
   u8g2.clearBuffer();
   u8g2.setFont(u8g2_font_osr21_tn);
   u8g2.setCursor(30, 55);
   u8g2.print(rpm);
   u8g2.updateDisplayArea(tile_area_x_pos, tile_area_y_pos, tile_area_width, tile_area_height);
}