PWM appears to be conflicting with External Interrupts

I’m not sure if this is best handled in this motor section or the sensor section since it involves both. I’ve searched the forum concerning PWM conflicting with External Interrupts and haven’t found anything so I suspect it’s something wrong with my circuit.

Basically, I want to power a large motor (130V DC @ 10Amps). I also want to monitor its rpm. I started out with the PWM circuit I found here: bildr High-Power Control: Arduino + N-Channel MOSFET - bildr. This working by itself works like a champ.

I then added the circuit using an infrared led /photodiode combo in an rpm counter based roughly on this: bildr Are we getting close? Proximity Sensors + Arduino - bildr. The only difference, I use one of the digital interrupt lines and trigger the revolution counter off a “RISING” value. Again, this running by itself works like a champ. I just tap on it with my finger to simulate on/off cycles. The fastest I have ever been able to simulate with my finger is 400 rpm.

Tests running both – If the PWM is outputting any wave form, the sensor give erroneous and rather random looking data. Sometimes it’s in the 4000 range, sometimes it’s around the correct answer and sometimes well below expected.

• If I set the Mosfet channel high using digitalWrite, everything runs fine, so I don’t think it’s because of motor noise.
• If I set the PWM to 255 or 0 (no waveforms) it works fine.
• If the PWM is set to anything between 1 and 254, I get the random sensor readings. There doesn’t seem to be any correlation to the setting.
• Removing the power to the motor and setting the PWM between 1 and 254 and the sensor gives random data.
• Also, I have tried every combination of the two interrupt pins and the five PWM pins… same results.

Here is a picture of the combined circuit. It’s not using the honk’n motor yet… just a pip-squeak. :smiley:

Here is the code:

#define MOTOR 3
#define TACKOMETER 0
#define UPDATETACK 1000   // milliseconds

int _rpm = 0;
int _old = 0;

// =======================================================================

void setup() 
{
  // Set the Mosfet motor pin
  pinMode(MOTOR, OUTPUT);
  
  // Attach the interrupt for the tachometer reading
  // and display base rpm.
  attachInterrupt(TACKOMETER, Rev, RISING);
  
  Serial.begin(9600);
}

// =======================================================================

void loop() 
{
  // Convert to 0 to 255 used for PWM output.
  int p = 128;

  // Set the PWM for the Mosfet  
  if (p > 250)
    digitalWrite(MOTOR, HIGH);
  else
    analogWrite(MOTOR, 255);

  if (_rpm == _old)
    return;
  _old = _rpm;
  Serial.println(_old);
}

// =======================================================================

void Rev()
{
  static int rev = 0;
  static unsigned long last = millis();

  rev++;

  // Get time.
  unsigned long time = millis();
  
  // Get the elapsed time.
  unsigned long elapsed = time - last;

  // Only update if elapsed time is more than UPDATETACK.
  if (elapsed < UPDATETACK)
    return;
  
  // Convert to revs / minute
  _rpm = (int)(rev * 60000 / elapsed);

  rev = 0;
  last = time;
}

// =======================================================================

Thanks for any help!

You should declare "_rpm" as volatile so the compiler doesn't optimize away some of the operations on it.

johnwasser:
You should declare "_rpm" as volatile so the compiler doesn't optimize away some of the operations on it.

Thanks,

I was wondering about thread safety across the interrupt. Glad to see its available. Added it, but it didn't help my problem. :frowning:

If you adde thread saftey you will be the first to have aceived that on the single threaded Arduino.

All that volatile does is tell the compiler - look i know you might not think i am using this anywhere and you want to optimise but please dont do that I am using it in another peice of code that you are not looking at right now.

What you do need to do is turn interrupts off before accessing the variable in you loop code, if you do not do this, the ISR can update it while you are reading it leaving you with half a new value and half an old value.

There is a good introduction to Arduino interrupts if you search for the post 'reading multiple rc channels' on rcarduino.blogspot.com

Duane B

Another problem that may well be affecting your signals is inductive interference. What this means is that the PWM signal is being picked up an the interrupt pin because of proximity to the interrupt wire. You have lots of wires running in big loop and no apparent separation. And then the breadboard has its own set of problems that it can add to the equation. Try re-arranging the circuit on the breadboard so the 2 signals are at opposite ends of the breadboard and add some de-coupling capacitors on the breadboad power supply rails. Add some short wires to the transistor so you can plug it into the breadboard and eliminate those wires.

You've made the classic mistake of using a common ground wire for your sensor and your motor. Dedicate one of the Arduino ground pins as sensor ground, and connect the ground side of the sensor to that. Use a different ground pin for power and the ground side of output devices.

PS - also connect a capacitor of several hundred uF between the mosfet source terminal and motor +ve terminal. That will reduce the power supply and ground noise.

It’s no surprise I'm making a mistake (classic or otherwise)... I'm a software type, who requires a cook book when it comes to hardware :~. So thank you both (kf2qd and dc42) for the constructive advice.

• I definitely can understand the directions on the wires RF'ing to each other and can remove or shorten them.
• I can understand the segregation to opposite ends of the breadboard.
• I basically understand what you want me to do with the two ground planes, but I always thought all the ground pins on the Arduino were basically just connected to each other. I never gave it any thought. I’ll put the PWM/Mosfet circuit ground on one and the sensor on another.
• But… when you both talk about adding capacitors… I can just see those words flying over my head. I wouldn’t dare ask for you draw out a schematic for me, but I would really appreciate a Wikipedia level reference so I can read and learn about the topic. And I’m a little paranoid about hooking up things.

An old EE friend of mine says the secret to hardware is keeping the smoke inside the little black boxes. I’d think 130 volt, 15 Amp current through my Arduino might let out the smoke. :fearful:

Thanks guys! One of your suggestions did it. I wasn’t systematic, so I can’t say which. :smiley: I put the sensor circuitry on a separate breadboard and I shortened all the leads and jumpers on the Mosfet side. Adding all the other jumpers for the LCD didn't seem to add any issues. I haven’t done anything with the capacitors yet since where to stick them and how to size them isn’t in my cookbook. Do you think when I actually get a chance to hook it up to the big motor, that the extra voltage / current will bring this problem up again?

Here are the results.

Side note: While taking pictures, I noticed that my cell phone camera can see in the infrared range… way cool! 8)

Video of it working. I left a long slow portion at the end to double check against a stopwatch.
http://s652.photobucket.com/albums/uu249/Inquisitor720/?action=view&current=20120824_224340.mp4

THANKS AGAIN!

Is there no way to give a helpful post / poster… a star, brownie points, kudo’s?

Cause you all definitely saved my plans. I didn’t have a clue what to do next!

Thanks to dc42 - had a similar issue to Inquisitor, separating the grounds solved the problem.

I have a water pump that uses RC-PWM input (using servo library), and has a tachometer output (1 pulse/revolution) that I’m measuring by tracking pulses with interrupts. All worked fine until I tried to use PWM-driven LEDs to provide a visual cue to indicate pump speed (red LEDs directly from digital outputs 5 and 6 to ground). Calculated RPM went up by unpredictable amounts that varied depending on how long I allowed the tacho counter to run before converting to RPM. The LED ground was originally connected to the same ground line on the breadboard that the pump/tacho was using.

The solution was to leave the pump/tacho ground line connected to the ground pin next to Arduino Vin, and to create a second ground line on the breadboard connected to the Arduino ground between AREF and pin 13.

All the high current wire pairs are best as twisted pair, that really reduces interference. You want zero
net current in each wire bundle, so always twist together a wire with its return wire.