Bicycle Reed Switch Tachometer

the project: monitoring rpm of bicycle wheel with a reed switch from a cycle computer, with one magnet on the wheel, then activating different outputs dependent on the rpm.

I have played around with some simple code and circuits and have managed to get a clean debounced signal from the reed switch to the arduino and then output that on another pin to an led. The trouble i'm having is writing the sketch to make the reed switch work as an rpm counter and divide the rpm range into four bands(slow, med, fast and v.fast) with each band corresponding to an on/off output pin. As im still at a fairly basic level of programming iv'e been looking for existing code to work with, i found this peice of code for an IR tachometer but have not had much luck in adapting it yet. any help is welcome.

/*
 * Optical Tachometer
 *
 * Uses an IR LED and IR phototransistor to implement an optical tachometer.
 * The IR LED is connected to pin 13 and ran continually. A status LED is connected
 * to pin 12. Pin 2 (interrupt 0) is connected across the IR detector.
 *
 * 
 */

int ledPin = 13;                // IR LED connected to digital pin 13
int statusPin = 12;             // LED connected to digital pin 12

volatile byte rpmcount;
volatile int status;

unsigned int rpm;

unsigned long timeold;

 void rpm_fun()
 {
   //Each rotation, this interrupt function is run twice, so take that into consideration for 
   //calculating RPM
   //Update count
      rpmcount++;
      
   //Toggle status LED   
   if (status == LOW) {
     status = HIGH;
   } else {
     status = LOW;
   }
   digitalWrite(statusPin, status);
 }

void setup()
 {
   Serial.begin(9600);
   //Interrupt 0 is digital pin 2, so that is where the IR detector is connected
   //Triggers on FALLING (change from HIGH to LOW)
   attachInterrupt(0, rpm_fun, FALLING);
   
   //Turn on IR LED
   pinMode(ledPin, OUTPUT); 
   digitalWrite(ledPin, HIGH);
   
   //Use statusPin to flash along with interrupts
   pinMode(statusPin, OUTPUT);

   rpmcount = 0;
   rpm = 0;
   timeold = 0;
   status = LOW;
 }

 void loop()
 {
   //Update RPM every second
   delay(1000);
   //Don't process interrupts during calculations
   detachInterrupt(0);
   //Note that this would be 60*1000/(millis() - timeold)*rpmcount if the interrupt
   //happened once per revolution instead of twice. Other multiples could be used
   //for multi-bladed propellers or fans
   rpm = 30*1000/(millis() - timeold)*rpmcount;
   timeold = millis();
   rpmcount = 0;
   
   //Write it out to serial port
   Serial.println(rpm,DEC);
   
   //Restart the interrupt processing
   attachInterrupt(0, rpm_fun, FALLING);

  }

First, when you post code, please use the # button above.

It would be kind of you to fix this post.

Second:

i found this peice of code for an IR tachometer but have not had much luck in adapting it yet.

This statement is too vague. You need to describe what successes or failures you've had, or what difficulties you've encountered, or what you don't understand. We can help you with those parts. "Please write a program for me that does what I want" kinds of requests don't generally get much in the way of helpful answers.

Since you are able to detect when the reed switch is closed (or opened), the thing that you need to do is determine how many times that switch closes (or opens) in a given period of time.

You can do that by setting a start time, and then running a while loop for a known period of time (while millis() - startTime < desiredInterval), and reading the switch status over and over again. Count each time it closes (or opens). At the end of the interval, the number of switch closes (or opens) divided by the desiredInterval will give a speed.

Keep the interval short. Otherwise, you will not get a good reading on changing speeds.

You could use an interrupt, to be told when the switch closed (or opened). In the interrupt handler, you simply increment the counter. In loop, you monitor the time. When it is appropriate to display a new value, show the value, reset the last time displayed value, and reset the count of interrupts that have been received.

Which approach is best depends on your understanding of interrupts, and whether or not the Arduino is to be doing anything else.

thanks for the advice, I'll try and refine the question and post something again soon.

i found this code on the arduino playground which successfully gives me an rpm readout.
http://www.arduino.cc/playground/Main/ReadingRPM

The serial print readout gave an rpm range of about 0-420, which i want to divide in to four bands, each band would light up a different led. to start with the bands would be 60-99 = led 1, 100-199 = led 2, 200-299 led 3, and 300-450 = led 4.

I added this code which works. the four leds light up in relation to the rpm.

 if((rpm >= 60) && (rpm < 99)){
    digitalWrite( ledPin1, HIGH);
    digitalWrite(ledPin2, LOW);
digitalWrite(ledPin3, LOW);
digitalWrite(ledPin4, LOW);
 }
 
 else{ 
  digitalWrite(ledPin1, LOW);
digitalWrite(ledPin2, LOW);
digitalWrite(ledPin3, LOW);
digitalWrite(ledPin4, LOW);
 }
  
  
 if((rpm >= 100) && (rpm < 199)){
    digitalWrite( ledPin1, LOW);
    digitalWrite(ledPin2, HIGH);
digitalWrite(ledPin3, LOW);
digitalWrite(ledPin4, LOW);
 }
 
 else{ 
  digitalWrite(ledPin1, LOW);
digitalWrite(ledPin2, LOW);
digitalWrite(ledPin3, LOW);
digitalWrite(ledPin4, LOW);
 }
  
 if((rpm >= 200) && (rpm < 299)){
    digitalWrite( ledPin1, LOW);
    digitalWrite(ledPin2, LOW);
digitalWrite(ledPin3, HIGH);
digitalWrite(ledPin4, LOW);
 }
 
 else{ 
  digitalWrite(ledPin1, LOW);
digitalWrite(ledPin2, LOW);
digitalWrite(ledPin3, LOW);
digitalWrite(ledPin4, LOW);
 }
  
 if((rpm >= 300) && (rpm < 450)){
    digitalWrite( ledPin1, LOW);
    digitalWrite(ledPin2, LOW);
digitalWrite(ledPin3, LOW);
digitalWrite(ledPin4, HIGH);
 }
 
 else{ 
  digitalWrite(ledPin1, LOW);
digitalWrite(ledPin2, LOW);
digitalWrite(ledPin3, LOW);
digitalWrite(ledPin4, LOW);
 }
  }
  
  

 void rpm_fun()
 {
   rpmcount++;
   //Each rotation, this interrupt function is run twice
 }

so the next part is getting the relays to work...

ok now i have a problem with getting the relays to turn on. The arduino is putting out only 1.2v on the pins 12-9 when they are on HIGH, enough to light an led, but not enough to power the relay.

i built the relay circuit following this diagram: Arduino Playground - HomePage

the relay im using is a rayex leg-6. with an operating voltage of 4.5v -7.8v

i tested the relay circuit works by using the blink sketch (on the same pins 12-9) and it worked fine, with the pins giving a full 4.9v

has anyone else encountered this problem of lower voltage on output pins?

What is the current draw of the relay? I suspect that the Arduino can't supply the necessary current to power the relay, so the voltage drops.

the current draw is 60Ma, but i'm not sure that this is the problem as i have tested the voltage of the outputs when the relay circuit is not plugged in and it makes not difference.

You can not draw more than absolutely max. 40mA from an Arduino pin.

If you draw more you are at great risk of frying either the pin or the whole Atmega IC.

You should also realize that a relay that draws 60 mA when engaged, can draw a lot more for a short time when it is turned on, up to 10 times more.

You need to drive the relay with something that can handle the current.
For instance a TIP120 transistor and a diode to protect against back emf spikes.

Google Arduino + relay to see how it's done.

EDIT:

Sorry, i didn't read your last post to end before posting :slight_smile:

How are you powering the relay and the Arduino ?
From USB ?