Difficulty with External Interrupt Triggering

Hi, firstly, I hope I’ve got this in the right category, please advise where to put it if not! I’m fairly new to the forum, although have spent a fair bit of time lurking, so excuse any faux pas.

As a bit of background, I’m working on a project making a speedometer to retrofit into my 1970’s car, with the eventual plan of having lots of exciting functionality like rpm, mpg, engine temp, remote oil level etc.

For the first stage, I’m measuring speed by triggering a reed switch using magnet attached to the transmission brake drum (180 degrees opposite each other to increase resolution//help balance). I want to trigger an external interrupt when the pin goes high, as it would save missing passes of the magnets, and reduces the amount the processor has to do. (previously I’ve just looked at the status in the main loop, which worked after a fashion but seemed a bit cack handed).

Annoyingly I can’t get the interrupt to work properly. I thought I’d try a simple example initially, so have been using the code below, which is intended to switch on and off an LED when the switch in the circuit changes:

int pbIn = 0;                  // Interrupt 0 is on DIGITAL PIN 2!
int ledOut = 4;                // The output LED pin
volatile int state = LOW;      // The input state togg

void setup()
{
  Serial.begin(9600);
  // Set up the digital pin 2 to an Interrupt and Pin 4 to an Output
  pinMode(ledOut, OUTPUT);
  pinMode(pbIn, INPUT);           // set pin to input
  digitalWrite(pbIn, HIGH);       // turn on pullup resistors

  //Attach the interrupt to the input pin and monitor for ANY Change
  attachInterrupt(pbIn, stateChange, CHANGE);
}

void loop()
{
  
  Serial.println(state);
  //Simulate a long running process or complex task
  for (int i = 0; i < 100; i++)
  {
    // do nothing but waste some time
    delay(10);
  }
}

with LED + resistor between D4 and GND, and ‘switch’ (touching wires together) between +5V and D2.

So in theory when interrupt pin 0 changes from low to high or vice versa it should trigger. In reality, the change has no effect, and it seems to trigger all by itself. I’ve had a search of forums but not had much luck. I’ve set the internal pull resistor for the interrupt pin high, but this has had no effect, could anyone advise me as to what I might be doing wrong?

Thanks in anticipation
Jake

(using a sainsmart mega 2560 if it’s of any relevance)

PbIn is declared =0 , not 2.

Interrupt 0 is pin 2, so use pin 2 in the pinMode calls!!

Thanks!

Applied that, it appears to have addressed the phantom trigger, although it’s still not triggering when D2 changes (ie I touch a wire from 5V to it) nothing happens, this is after trying the code in both the instances mentioned below. Any further clues would be greatly appreciated!

If I change the pinmode calls from 0 to 2, would I do the same in the ‘attach interrupt’, ie changing from:

attachInterrupt(0, stateChange, CHANGE);

to

attachInterrupt(2, stateChange, CHANGE);

Hi Jake

In the code you posted, I can't see your ISR function stateChange(). Was that your complete program?

Regards

Ray

It is a bit confusing, but the interrupt is 0 the pin is 2. You have the internal pullup enabled, right, so touch the wire to ground to cause a FALLING or LOW interrupt. The internal pullup pulls to Vcc so touching Vcc has little effect. You will probably need some debouncing of the input to prevent spurious interrupts.

Hi Ray,

Just looked again at the original cod eI posted, I missed it off the end, it’s as follows:

void stateChange()
{
  state = !state;
  digitalWrite(ledOut, state);
}

Thanks groundfungus, I hadn’t previously fully understood how the internal pull up resistor works, but that makes sense, and it now works! (Apart from a little bit of what I assume to be debounce issues, but that’s not the end of the world)

You chantry a 0.1uf cap from ground to the input. That will help if not solve the bounce

Debouncing is not compatible with external interrupts, and will lead you down a frustrating path. Depending on your rpm you might be able to pick up the state changes by using polling in the loop rather than the interrupt.

I think you will be best off by changing the reed switch for a Hall sensor which has no bounce to deal with.

I agree that Hall switches would be better than reed switches. I, also, agree that software denounce is not compatabile with external interrupts. However, hardware denounce is compatible and often necessary.

If the reed closures (pulses) are at a low frequency, i.e. 0-1 kHz (1 ms minimum period) and its contact bounce specification is 100µs, then why not let the bouncing occur and do nothing until a certain time period has elapsed?

For example:

void stateChange()
{
  if (micros() - PreviousMicros > 200) {
    state = !state;
    digitalWrite(ledOut, state);
    PreviousMicros = micros();
  }
}

I guess this would be considered software debouncing within the interrupt routine. However, in this example the stateChange function would only be called up to 10% of the time at 1 kHz reed frequency and it would only change the output state if 200µs has elapsed since the last call.

EDIT: I haven’t used external interrupts yet … curious why software debounce is incompatible with external interrupts.

Thanks for the advice, I shall look into what it would require to use one. I had originally intended to use a hall effect sensor, but then realised I had a whole load of old bike speedometers kicking about, which is why I went down the reed switch round, as it was free.

For anyone that’s interested, I’m using a 0.96’’ OLED from ebay, and will set it into the gauge so it looks as stock as possible. The two images below show how I’ve currently got it, so showing the logo on start up followed by various bits of info when driving.