RPM display for my bike with Arduino Uno

Hello everyone in this forum,

I'm currently developing an RPM display for my bike using an Arduino Uno. The bike speed will need to consider RPM values between 0-180.

Current Setup
My wheel has 4 magnets attached and the movement is captured using a hall effect sensor connected to my Arduino Uno. Each time the magnet passes the hall effect sensor an interrupt (pin 2) occurs on the Arduino Uno. The sketch on the Arduino is programmed to calculate the RPM when a full cycle is performed (that is, when the 4th magnet passes the hall effect sensor).

=================================================================

#include<avr/wdt.h>

const byte interruptPin = 2;

volatile byte rpmcount;
unsigned int rpm;

unsigned long timeold;

unsigned int rpmhundred;
unsigned int rpmten;
unsigned int rpmone;


void rpm_fun() {
rpmcount++;
}


void setup() { 

Serial.begin(9600);  
attachInterrupt(digitalPinToInterrupt(interruptPin), rpm_fun, RISING);  


pinMode(13,OUTPUT);
digitalWrite(13,HIGH);

rpmcount = 0;
rpm = 0;
timeold = 0;

rpmhundred = 0;
rpmten = 0;
rpmone = 0;

watchdogSetup();  
}




void loop(){

//Every 4th magnet detected by the hall effect sensor, calculate the values below.
if(rpmcount>=4) {
  rpm=(60000)/(millis()-timeold); 
  timeold = millis();
  rpmcount = 0;


//I wanted to calculate and print each digit of the RPM separately.
  if(rpm>=100){
    rpmhundred = rpm/100;
    rpmten = (rpm/10)%10;
    rpmone = rpm%10;

  }


  else if(rpm>=10 || rpm<100) {
    rpmhundred = 0;
    rpmten = rpm/10;
    rpmone = rpm%10;
   
  }


  else if(rpm<10){

    rpmhundred = 0;
    rpmten = 0;
    rpmone = rpm;
  }
  
   showResults(); //Print out results to serial monitor using the function showResults() 
   wdt_reset(); //If 4th magnet passing does not occur within next 4 sec, then reset Arduino
}


}




void watchdogSetup(void){
cli();     // disable all interrupts 
wdt_reset();  // reset the WDT timer 


// Enter Watchdog Configuration mode: 
WDTCSR |= (1<<WDCE) | (1<<WDE); 

// Set Watchdog settings to 4000msec:
WDTCSR = (1<<WDIE) | (1<<WDE) | (1<<WDP3) | (0<<WDP2) | (0<<WDP1) | (0<<WDP0); 
sei();
}



ISR(WDT_vect) // Watchdog timer interrupt.
{
// Nothing done here
}




void showResults(){
Serial.print(rpmhundred);
Serial.print(rpmten);
Serial.print(rpmone);
Serial.print(",");
Serial.flush();

}

=================================================================

Current Issue
The display (or serial monitor) is showing proper results with the TX light blinking every time serial information is sent to the computer, but after a while (approx. 20-40mins) the Arduino freezes. I tried multiple observations and it seems I'm running into different types of freezing situation. After working 20-40 mins:

  1. The TX blink will completely stop and not blink at all
  2. The blink interval (time going on and off-usually like the time of an eye blinking) of the TX light gets slow. In other words, instead of TX (on-off) it will go TX (On--------off).
  3. The TX will still blink properly, but no information is sent to the serial monitor.

Current attempts to solve issue
I. I've considered it as a memory issue and looked at <MemoryFree.h> and the memory was showing approximately 1,800 bytes the whole time.
II. I've setup a watchdog to reset the loop when the a full cycle of the bike (4th magnet) was not occurring in the next 4 seconds from the last completed cycle.

I'm thinking it could something very simple that I did not follow or just something I'm not aware of. I would greatly appreciate any type of help.

Thank you. :slight_smile:

  1. What are you using for power?

  2. An interrupt causing rpmcount++ to get lost will occasionally occur during this:

  if(rpmcount>=4) {
    rpm=(60000)/(millis()-timeold); 
    timeold = millis();
    rpmcount = 0;

This should not cause a freeze but will cause rpm to be miscomputed.

  1. This:
 else if(rpm>=10 || rpm<100) {

should probably be

 else if(rpm>=10 && rpm<100) {

Notice the && to get the range of two digit numbers.

By the way, there are better ways to get the digits of an integer.
itoa(...) and snprintf(...) come to mind. There may be others.
This may cause rpm to be displayed incorrectly but will not cause a freeze.

  1. You would have to be cycling awfully fast for interrupts to be needed (or perhaps the output from the hall sensor is very brief). Otherwise, this could have been handled by examining the pin in loop() and not using interrupts. This would avoid the problem in (2).

vaj4088 thanks so much for the response.

  1. I'm using the power from the USB cable that is connected to my iMac.

  2. Are you saying that the interrupts from the hall effect sensor might interfere the computation of the rpmcount++ because of it being a volatile byte? I haven't seen miscalculation in the RPM values though.

  3. Very true. I changed them to the AND operators. Thanks. It seems itoa() or snprintf() deal with string variables. Would that cause more memory usage? Would the current computation be better? Since they are just computation of unsigned integers?

  4. Cycling goes only up to 150ish max. The hall sensor is a quick light on and off so I guess it's considered very brief?

I'm still going through bunch of the forums and still struggling.

*Would I need to empty the serial buffer? Is it getting maxed out?
*Should I disable all other USB peripherals that is connected to the back of my iMac and try using a bluetooth mouse and keyboard? I've seen opinions that USB might interfere with each other.

  • Should I change my USB cable? Currently I'm using an 8ft USB cable purchased from Amazon.

Hi,
Check the voltage when it freezes since your are using the power from the computer.

Thank you tauro0221 for the opinion on possibly being a power related issue.

Sorry. I am fairly new at this :slight_smile: Is there a way to check the voltage even after the Arduino freezes? If the freezing is due to lack of power, should I purchase a 9v adapter?

Thanks.

Hi,
If you check the board there is a label that read POWER and you will see below small prints that label the pins as follow : 5V RES 3.3 5V GND GND GND VIN. Check the voltage at the pin label 5V. Also you can check the power ON LED light to see if it is ON when the program stop running or freezes . The power ON LED it is next to the USB connector.

Hi,

I think my issue has been resolved, so far no freezing issues. As vaj4088 mentioned above, I used digitalread instead of interrupts since the rpm is relatively slow compared to super fast motors (e.g., power tools). I've also got rid of the serial flush and changed my rpm variable to type long. Below is the code, if anyone wants to utilize it.

I used the hall effect sensor from Sunfounder (I've included an image). I think this is what I purchased (https://www.amazon.com/SunFounder-Sensor-Kit-Raspberry-Extension/dp/B00P66XRNK/ref=sr_1_9?ie=UTF8&qid=1480951710&sr=8-9&keywords=sunfounder)

I hope this helps for others creating a simple RPM reader for bikes (Relatively lower RPMs). Feel free to add anything to this if it'll help others! Thanks :smiley:

int hallPin = 8;

volatile byte rpmcount;

unsigned long rpm;

unsigned long timeold;


unsigned int rpmhundred;
unsigned int rpmten;
unsigned int rpmone;


int hallstate = 0;
int lasthall = 0;

void setup() { 

  pinMode(hallPin,INPUT);
  digitalWrite(hallPin,LOW);
  
  pinMode(13,OUTPUT);
  digitalWrite(13,LOW);

  rpmcount = 0;
  rpm = 0;
  timeold = 0;
  
  rpmhundred = 0;
  rpmten = 0;
  rpmone = 0;

  Serial.begin(57600);  
  //attachInterrupt(digitalPinToInterrupt(interruptPin), rpm_fun, RISING); 

  //watchdogSetup();
}



void loop(){

  hallstate = digitalRead(hallPin);
  
  if (hallstate != lasthall){
    
    if (hallstate == LOW){
        rpmcount++;
        
         if(rpmcount==4) {

            
            rpm=(60000)/(millis()-timeold);
            timeold = millis();
            rpmcount = 0;
    
            if(rpm>=100){
              rpmhundred = rpm/100;
              rpmten = (rpm/10)%10;
              rpmone = rpm%10;
            }

            else if(rpm>=10 && rpm<100) {
              rpmhundred = 0;
              rpmten = rpm/10;
              rpmone = rpm%10;
            }
    
            else if(rpm<10){
              rpmhundred = 0;
              rpmten = 0;
              rpmone = rpm;
              }
    
            showResults();
    
         }  
    }
  }
  
  lasthall = hallstate; 
}





void showResults(){
  //while(Serial.available()){Serial.read()};



  Serial.print(rpmhundred);
  Serial.print(rpmten);
  Serial.print(rpmone);
  Serial.print(",");
  //Serial.flush();
  
}

hall.png