4 digit display impacts RPM count from Hall Effect Sensor.

Hi Guys,

I am measuring a DC motor’s speed using a arduino nano, a hall effect sensor + magnet on motor, and displaying it onto a 4 digit display.

The hall effect sensor is: Hall Sensor Module Magnetic Swich Speed Counting Sensor Module speed Counter Detection Sensor Module 3144 LM393

The display is: **TM1637 4 Bits Digital LED Display Module For arduino 7 Segment 0.36 Inch Clock RED Anode Tube Four Serial Driver Board Pack. **

https://trade.aliexpress.com/orderList.htm?spm=2114.11010108.1000002.15.650c649bX660h2&tracelog=ws_topbar

The code that causes the problem is highlighted in red.
display.showNumberDec(rpm); //

If I go to measure a motor with a known 100 rpm, then the serial print correctly displays 100 rpm if this line of code is commented out. If the display.display.showNumberDec(rpm); is added then I get 125 rpm. The same happens at different speeds, adding this line seems to overestimate rpm by about 25%. This happens whether or not the actual display is hooked up to the nano.

Does anyone have any idea on this? It’s driving me nuts trying to figure it out.

Below is the full code.

#include <TM1637Display.h>
#include <Wire.h>

// Module connection pins (Digital Pins)
#define DIO 3
#define CLK 4
TM1637Display display(CLK, DIO);

volatile byte pulse_counts_to_calculate;
unsigned long old_rpm;
unsigned long newmillis;
unsigned long timeold;
float pulsetime;
float Revs_per_Second;
float rpm;

void setup() {
Serial.begin(1200);           // set up Serial library at 1200 bps
pinMode(2, INPUT);    // this is the pin# for the interrupt input signal

attachInterrupt(digitalPinToInterrupt(2), magnet_detect, RISING);   //Initialize the interrupt pin (Arduino digital pin 2)
pulse_counts_to_calculate = 0;
timeold = millis();

display.setBrightness(0x0f);
display.showNumberDec(0000);
}


void loop() {

// this computes/averages the RPM based on the time it takes for pulse count revolutions
if (pulse_counts_to_calculate >= 30) {

newmillis = millis();
old_rpm = rpm;
detachInterrupt(digitalPinToInterrupt(2));    //Disable interrupt when calculating
pulsetime = (newmillis - timeold) / pulse_counts_to_calculate;
Revs_per_Second = 1000 / pulsetime;
rpm = 60 * Revs_per_Second;
Serial.println(rpm);



display.showNumberDec(rpm); //*************If I comment out this line then it works accurately, RPM.  But when it's in then it over estimates RPMS by about 25%
 

delay(50);
pulse_counts_to_calculate = 0;
timeold = millis();
attachInterrupt(digitalPinToInterrupt(2), magnet_detect, RISING);   //Initialize the interrupt pin (Arduino digital pin 2)
}
}

void magnet_detect()//This function is called whenever a magnet/interrupt is detected by the arduino
{
pulse_counts_to_calculate++;
}
#define CLK 2
TM1637Display display(CLK, DIO);
attachInterrupt(digitalPinToInterrupt(2), magnet_detect, RISING);

Are you using pin 2 for the display and the Hall sensor ?

Sorry that was a typo, the display is being run from pins 3 and 4, the interrupt is on pin 2. I went back and checked it again, and I am still getting the 25% increase in RPM whenever I uncomment the display line...display.showNumberDec(rpm); //.

Good pickup though, and thank you so much for reading my post and trying to help.

Sorry that was a typo,

I really don't understand how such a typo could occur as presumably you copy/pasted the code from the IDE to the forum or used the Copy for Forum option in the menu

What do you see if you print rpm to the Serial monitor ?

You don’t need to do all that flailing around with attachInterrupt() / detachInterrupt(). Also, I’d:

  • Increase the size of the pulse counter to int16_t (just to be safe). Then protect access to it with a Critical Section.

  • Add a cast to the ‘pulsetime’ calculation to be absolutely certain that it’s being done in floating point.

  • Append a “.0” to all floating point literal constants – that’s Best Practice.

  • Get rid of the delay. Make your ‘>=30’ greater if you want longer time between readings.

Try something like this:

#include <TM1637Display.h>
#include <Wire.h>

// Module connection pins (Digital Pins)
#define DIO 3
#define CLK 4
TM1637Display display(CLK, DIO);

volatile uint16_t pulse_counts_to_calculate;
uint32_t timeold;
float pulsetime;
float Revs_per_Second;
float rpm;

void setup() {
  Serial.begin(1200);           // set up Serial library at 1200 bps
  pinMode(2, INPUT);    // this is the pin# for the interrupt input signal

  attachInterrupt(digitalPinToInterrupt(2), magnet_detect, RISING);   //Initialize the interrupt pin (Arduino digital pin 2)
  pulse_counts_to_calculate = 0;
  timeold = millis();

  display.setBrightness(0x0f);
  display.showNumberDec(0000);
}


void loop() {
  bool newReading = false;
  uint16_t localPulseCount;
  uint32_t newmillis;

  noInterrupts();
  newmillis = millis();
  if (pulse_counts_to_calculate >= 30) {
    localPulseCount = pulse_counts_to_calculate;
    pulse_counts_to_calculate = 0;
    newReading = true;
  }
  interrupts();

  if (newReading) {
    pulsetime = (newmillis - timeold) / (float) localPulseCount;
    Revs_per_Second = 1000.0 / pulsetime;
    rpm = 60.0 * Revs_per_Second;
    timeold = newmillis;
    Serial.println(rpm);
    display.showNumberDec(rpm);
  }
}

void magnet_detect()//This function is called whenever a magnet/interrupt is detected by the arduino
{
  pulse_counts_to_calculate++;
}

Hi, thanks so much for the advice from both of you. GFVALVO, I tried your code, it ran fine but still had the same problem of the serial and display reading 125 rpm when the display code was added, but when the display code was removed the serial reads 100 rpm (which is correct).

I have modified someone else’s code and found this solved the problem. So I post the code below to assist anyone else making a hall effect RPM.

// Module connection pins (Digital Pins)
#include <TM1637Display.h>
#define DIO 2
#define CLK 4

TM1637Display display(CLK, DIO);

volatile byte  count = 0;
volatile byte  count1 = count;
byte numCount = 1; //number of pulse intervals to measure
byte numCount1 = numCount;

volatile unsigned long startTime;
volatile unsigned long endTime;
unsigned long copy_startTime;
unsigned long copy_endTime;
volatile unsigned long startTime1;
volatile unsigned long endTime1;
unsigned long copy_startTime1;
unsigned long copy_endTime1;

volatile boolean finishCount = false;
volatile boolean finishCount1 = false;
volatile boolean delayCount1 = true;
float period;
float period1;

unsigned int rpm = 0;

void setup()
{
	Serial.begin(1200);
	attachInterrupt(digitalPinToInterrupt(3), isrCount, FALLING);//interrupt on pin3
}

void loop()
{
	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);

		rpm = numCount * 60000000 / period;

		Serial.print("RPM = ");
		Serial.println(rpm);
	}

	if (finishCount1 == true)
	{
		finishCount1 = false;//reset flag
							 // disable interrupts, make protected copy of time values
		noInterrupts();
		copy_startTime1 = startTime1;
		copy_endTime1 = endTime1;
		count1 = 0;
		interrupts();

		period1 = (copy_endTime1 - copy_startTime1);

		rpm = numCount1 * 60000000 / period1;

		Serial.print("RPM = ");
		Serial.println(rpm);
		display.showNumberDec(rpm);	//
	}
}


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

	if (delayCount1 == false)//skips first pulse
	{
		if (count1 == 0)//first entry to isr
		{
			startTime1 = micros();
		}
	}

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

	if (count1 == numCount1)
	{
		endTime1 = micros();
		finishCount1 = true;
	}

	if (delayCount1 == false)
	{
		count1++;
	}

	count++;
	delayCount1 = false;
}

Don't quite understand what's going on with the two sets of counting variables in that code.

I must admit I don't fully understand it either, it is modified from code I found online. What I do know is that I get the correct RPM over a range from 10 RPM to 4000 RPM with known RPM outputs from a motor, and it works with and without the 4 digit display, so it is a solution for me.

Again, many thanks for your (and others) replies, I really do appreciate the time taken to think about my post.

Cheers,

Ian.