2

So I am creating a tachometer using black/white detector sensor. Here's the code.

unsigned long WaktuOLD;
unsigned long WaktuNOW;
int Detection = HIGH;
int Counter = HIGH;
float HitungWaktu;
float HitungRPM;

void setup() {
  Serial.begin(9600);
  attachInterrupt(digitalPinToInterrupt(3), rpm, RISING);
  WaktuNOW = millis();
}

void rpm() {
  Detection = digitalRead(3);
  if (Detection == HIGH && Counter == LOW) {
    WaktuNOW = millis();
    HitungWaktu = WaktuNOW - WaktuOLD;
    HitungRPM = 60 / (HitungWaktu / 1000);
    Counter = HIGH;
  } else if (Detection == HIGH && Counter == HIGH) {
    Counter = LOW;
    WaktuOLD = millis();
  }
}

void loop() {
  Serial.println(HitungRPM);
  delay(5000);
}

The code works well and it can read RPM correctly. And then from the same arduino, I am controlling a servo motor, in this case I am using GWS03N/STD/F, with this code :

#include <Servo.h>

Servo myservo;
int pos = 0;

void setup() {
  myservo.attach(9);
}

void loop() {
  myservo.write(90);
}

And this code works well too.

But, when I am trying to combine both codes, only the servo code is working well. The tachometer reading is not correct (the reading must be around 1000-1500rpm, but now it reads 3000-30krpm). I am already trying to change my tachometer interrupt to pin 2 or 3, and servo to 3, 5, 6, and 9 but still the same.

So what is wrong in here. Thank you so much.

This is my code when combining both codes.

#include <Servo.h>

Servo myservo;
int pos = 0;
unsigned long WaktuOLD;
unsigned long WaktuNOW; 
int Detection = HIGH;
int Counter = HIGH;
float HitungWaktu;
float HitungRPM;

void setup() {
  Serial.begin(9600);
  attachInterrupt(digitalPinToInterrupt(3), rpm, RISING);
  WaktuNOW = millis();
  myservo.attach(9);
}

void rpm() {
  Detection = digitalRead(3);
  if (Detection == HIGH && Counter == LOW) {
    WaktuNOW = millis();
    HitungWaktu = WaktuNOW - WaktuOLD;
    HitungRPM = 60 / (HitungWaktu / 1000);
    Counter = HIGH;
  } else if (Detection == HIGH && Counter == HIGH) {
    Counter = LOW;
    WaktuOLD = millis();
  }
}

void loop() {
  Serial.println(HitungRPM);
  myservo.write(90);
  delay(5000);
}

2 Answers 2

2
+50

Your problem is probably that of interrupt conflicts.

The 8-bit Arduinos don't have any concept of interrupt priorities. When one interrupt routine is running it is impossible for any other interrupt routine to run until that first one has finished.

Interrupts have a "natural call priority" in that lower numbered pending interrupts will be called in preference to higher numbered ones, however that doesn't mean that they can interrupt each other.

The problem here is that the servo library uses a timer (and its associated interrupt) to generate the waveform. That uses a lot of interrupt calls running all the time - and while they are running your external interrupt can't be called - at least not until the currently executing timer interrupt completes, at which point your external interrupt handler will be called since it is the highest priority.

So the results you get with all that delaying are pretty meaningless.

So what can you do? Well, there's a number of options - all of which involve not using interrupts.

  • You could not use the Servo.h library and instead reconfigure the hardware PWM to the right frequency and use that for the servo
  • You could use one of the timers with an external clock source to count your tacho pulses (I think Timer 1 has that ability on the Uno)

Or even better: do both. That would give you the most efficient system whereby the main CPU is only involved in getting the count from the timer periodically, and adjusting the PWM value for your servo. The rest is then done by hardware completely asynchronously.

Of course, for this you will want to study the datasheet so you know how to configure the various hardware modules.

10
  • Are there another libraries instead of "Servo.h", which may solve this issue? Commented Oct 14, 2018 at 10:10
  • Not that I am aware of, but there are plenty of tutorials around on changing the frequency of the PWM.
    – Majenko
    Commented Oct 14, 2018 at 10:27
  • This may be of interest to you...
    – Majenko
    Commented Oct 14, 2018 at 10:31
  • Can we use a PWMServo as same as the Servo.h ? Commented Oct 14, 2018 at 10:40
  • It depends which timers both are using. If they're on different timers then sure. If not, no.
    – Majenko
    Commented Oct 14, 2018 at 10:40
0

All of those variables that are accessed inside the ISR need to be declared as volatile.

You are using a RISING interrupt, so there should be no need to test the pin in the ISR. You can be confident that it went HIGH for the interrupt to be run.

2
  • I stand corrected. I must have misread the pin number somehow. Still, the variables need to be volatile.
    – Delta_G
    Commented Jul 6, 2017 at 2:05
  • It's a typo on one of the pin number on Detection var, I already correct it now. And I already try to volatile WaktuOLD, WaktuNOW, Detection, Counter, HitungWaktu, and HitungRPM but it still no good. I haven't try to remove Detection var though.
    – Naufal B
    Commented Jul 6, 2017 at 11:04

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.