AttachInterrupt is not working with an analog sensor on A0

I'm wanting to use attachInterrupt() on an analog QRE1113 sensor to read when I have a signal peak and a valley.
However, it is not triggering the function defined in the Interrupt at any time.


This one was brown on the A0 and my sensor.

Code:

#define ANALOG_INPUT A0
#define THRESHOLD 512
#define BANDS 2

unsigned long startTime;
unsigned long peakTime;
unsigned long valleyTime;
int previousValue = 0;

void peak() {
  peakTime = micros() - startTime;
}

void valley() {
  valleyTime = micros() - startTime;
}

void setup() {
  Serial.begin(9600);
  startTime = micros();
  attachInterrupt(digitalPinToInterrupt(ANALOG_INPUT), peak, RISING);
  attachInterrupt(digitalPinToInterrupt(ANALOG_INPUT), valley, FALLING);
}

void loop() {
  int value = analogRead(ANALOG_INPUT);

  if (value > THRESHOLD && previousValue <= THRESHOLD) {
    peakTime = 0;
  }

  if (value <= THRESHOLD && previousValue > THRESHOLD) {
    valleyTime = 0;
  }

  if (peakTime != 0 && valleyTime != 0) {
    unsigned long timeDifference = valleyTime - peakTime;
    float RPM = (60 * 1000) / (timeDifference * BANDS);
    Serial.println("RPM: " + String(RPM));
    peakTime = 0;
    valleyTime = 0;
  }

  previousValue = value;
}

The analogRead function can read perfectly, but the interrupt does not work.

What is the board? Mega?
Arduino Mega doesn't have interrupt in A0 pin.
See availiable IRQ pins in table:

Sorry, yes it is a Mega. I tried connecting the sensor to pin 2 digital and it didn't work either

Besides the wrong pin, you still have a many errors in the program.

First - you can't attach a two IRQ handlers to a single pin in the same time:

Choose only one.

Next - all variables, that will changed in interrupt handler - must be declared with "volatile" keyword...

And think again on logic of your code - you try to determine signal both as analog threshold and a digital pulse edge... on the same pin?!
I don't consider it resonable...

Etc...

Well, my goal is to identify the peaks and valleys and for that reason I was using the inturrupts. Is there a way to do this with just one?

A most important question is: why do you want to use an interrupt to detect peaks and valleys? Many beginners try to use interrupts for inappropriate purposes, so we need to be certain that your reasons are appropriate.

Interrupts are usually generated by digital signals, and your signal is analog. External circuits can be used to turn your analog signal into an appropriate digital signal, but often those circuits can be quite complex, and easier to achieve in code.

You can first determine rise edge with RISING interrupt, then just in handler attach FAILING interrupt to the same pin and wait for failing edge... than again reattach RISING interrupt... and so on

I need to use an interrupt to read the feedback from the sensor, this sensor detects black and white stripes on a disc that is spinning at high speed. I want to use the interrupt to keep the ADC running free so that the read can be done as fast as possible.

If your sensor has an analog output, you should use a comparator for detecting edges, interrupts are not suited for analog signals.

1 Like

A comparator with hysteresis ... a schmitt trigger.

1 Like

Then the output is digital, not analog, isn't it? Why are you using ADC at all?

@Matheus_Markies
I think your basic problem is that you want the A/D to run in the background and then get a certain value to trigger an interrupt on a peak and a trough ( proper word for valley ) reading.

Quite simply the whole Arduino can't work like this. Nice as it would be for it to work like this but unfortunately it can't.

You can have a digital signal trigger an interrupt and the the ISR can read the free running A/D, or rather the last time the free running A/D finished a reading. But to know a peak or trough you have to know when you reach one, and that can only be done with code that does the readings and compares it to a previous reading and see if it is higher or lower, but the code will know the reading if you just take a reading continuously. So there is no point in triggering an interrupt at all.

To detect the times of peaks and valleys I would run the ADC in free-running mode (start a new reading as soon as the old reading is complete). About 9800 Hz. You can get a 'conversion complete' interrupt to read each sample. If the current reading is higher than the previous, note the time as the peak time. When the reading is lower than the previous one, note the time (micros()) as the 'valley' time. When the signal starts going up again, the last recorded peak and valley times are correct for that half-cycle.

You can get sample rates up to 1 MHz if you only need 8 bits of accuracy.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.