0

I am using Arduino Duemilanove and a hall effect sensor to calculate the speed of a motor. When I used sensor out directly to Interrupt0, the rising edges of noise were also detected. So the speed calculation went wrong.

So now sensor is connected to A0.and a threshold is put. Pin No 13 is connected to Interrupt 0(Pin 2). I use the following code.

volatile byte count;
 const int analogPin = A0;
 const int digitalPin=13;
 const int threshold =20;
 unsigned int rpm;
 unsigned long starttime;

 void setup()
 {
   pinMode(digitalPin,OUTPUT);
   digitalWrite(analogPin,HIGH);
   digitalWrite(digitalPin,HIGH);
   Serial.begin(9600);
   attachInterrupt(0,sense,FALLING);
   rpm=0;
   starttime=0;
   count=0;    
 }
 void loop()
 {
   int sensorValue = analogRead(analogPin);
   Serial.println(sensorValue);
   if (sensorValue < threshold)
   {
     digitalWrite(digitalPin,LOW);
     if (count>=20)
     {
       rpm=60*1000*count/(millis()-starttime);
       starttime=millis();
       count=0;
       Serial.println(rpm,DEC);
     }
   }
   else
   {
     digitalWrite(digitalPin,HIGH);
   }

 }
 void sense()
 {
  count++;
 }

But I get actual speed only in between. The speed changes back . I feel there is some problem with the sampling or rpm updation. Looking forward for help

2
  • You could try adding an RC filter to filter out the noise, before feeding it into the INT0 pin.
    – Gerben
    Commented May 30, 2015 at 20:35
  • I don't see the point of using attachInterrupt here since this is your code that artificially triggers interrupts by writing to digitalPin. Hence I think your sense function is not called as many times as you would expect. Also, where does the value 20 for threshold come from?
    – jfpoilpret
    Commented May 31, 2015 at 6:30

3 Answers 3

1

It sounds like you need a debouncing circuit.
You can do it in code, but you are then trying to execute more code in you interrupt handler. I would go for a hardware version. I don't have the circuit to hand but if you search for a 'Schmidtt Trigger' based debouncing circuit. You can implement it with 5 resistors, a capacitor, a LM386 OpAmp and a CMOS XOR IC (Inverts the signal which the inverting Schmidtt trigger inverts).

What happens is the Schmidtt trigger goes low when the input passes a certain voltage. It remains low until the voltage passes the low voltage threshold at which point it goes high. The CMOS XOR IC (I think its a 4004??) takes two inputs and inverts them. It also adds extra hysteresis which further damps the bouncing.

The values of your resistors affect the thresholds, but there are plenty of calculators on the web that will solve the values for you.

The LM386 has two channels and the CMOS usually has 4 so it becomes quite easy to debounce multiple signals.

Hope that helps.

0

A possibility I am toying with for a similar problem is realizing that there will always be a delay between valid sensor readings. For example, imagine you had a maximum speed of 10 revolutions/second. That would mean that there would be a maximum of 10 sensor inputs/second or 1 interrupt every 100 msecs.

If you changed your interrupt processing logic to something like:

if (millis() - timeOfLastSensorReading >= 10) {
   count++;
   timeOfLastSensorReading = millis();
}

Then your logic would become "Only register a sensor change if at least 10 msecs has passed since the last reading".

You might have to tune the values based on your real situation ... but it might go a long way to eliminate some aspects of false readings.

0
       rpm=60*1000*count/(millis()-starttime);

Since rpm is an unsigned int (which has a maximum of 65535) you will almost certainly overflow if count is more than 1, which will give you negative numbers, or incorrect positive numbers.

Plus, outputting to serial constantly will cause the program to lock up waiting for the serial buffer to empty, which will throw out any timings you are doing.

I suggest making rpm unsigned long (or float as you seem to have done already) and only display the RPM every second or so.


Also see my page Using the Arduino Analog Comparator. This is a much faster way of detecting an analog signal merely passing some threshold. This only takes a few microseconds compared to 104 µS for a single analogRead. In the ISR then you just add one to a counter (which is the number of times it passes the threshold). Every second take this counter, and work out the RPM, then zero it. Make sure you make a copy of the counter in a protected way as shown on my page about Interrupts.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.