Interrupt called many times

Hi,

I build a small arduino project but I am having issues with interrupts and gpio values on a nodemcu v3 board.

In simple terms I have the following setup:

A nodemcu v3 board where two pins, pin D5 and D2 configured as input_pullup. On the D5 I have connected a normally close contact of a 240v relay and on the D2 pin I have connected a normally close contact of a 12v relay.

The 240v relay is closing its contact when an external motor is working and the 12v relay is closing its contact when a photocell is detecting movement.

On the arduino software I am defining the following code

const uint8_t MOTOR_STATUS = D5;
const uint8_t STOP_STATUS = D2;

in setup function

pinMode(MOTOR_STATUS, INPUT_PULLUP);
pinMode(STOP_STATUS, INPUT_PULLUP);

attachInterrupt(digitalPinToInterrupt(MOTOR_STATUS), motorMovement, CHANGE);
attachInterrupt(digitalPinToInterrupt(STOP_STATUS), forcedStop, CHANGE);

My problem is that when the motor is working (and only the 240v relays is closing its contacts) I see in arduino code that both motorMovement and forceStop function are being fired multiple times. When the motor is stop working then neither of the functions is being fired unless I use the photocell and operate the 12v relay. In this scenario only the forcedStop is being fired.

In the scenario when the motor is working I tried to check in the code whether the actual value of either pin is being changed multiple times and it appeared that it did. I then tried to measure the actual pin voltage on the nodemcu v3 board during the time that the motor was working but neither pin show any changes. For example when motor is working the voltage of the motor pin (D5) goes to 0 and the voltage of the stop pin (D2) is 3.3v as it should. When the motor is stop working the voltage of the motor pin (D5) goes to 3.3v.

I tried "replacing" the internal pullup resistors with a 4.7k external resistors by defining the pins just as INPUT instead of INPUT_PULLUP and adding the external resistors but the result was the same.

I also tried changing the arduino board with another one just to make sure is not hardware related but the result again the same.

Does anyone have any idea why this is happening? I have no other clue as to what might be the issue here. Could it be an issue with the arduino board that is being affected but the motor that is working? Please if someone can clarify.

Regards,

Phanos

We have no clue either... because you need to:

  • Post all your code.

  • Post a schematic of how the components are connected together.

Changing boards does not help. Most probably you have missing diodes or snubbers in your circuit, and use interrupts instead of polling and debouncing inputs. Please show a complete circuit diagram - no photos nor Fritzing.

Yes and we are asked about this nearly every day. You are suffering from EMI ( Electro Magnetic Interference ) that is being generated by motors and relays, and relays switching mains power.

There is no sure fire single cure, but there are things you can do to minimise either the EMI itself and the the effects any EMI has on your processor. And so eventually get a working circuit.

Note that EMI can be transferred by conduction, radiation or capacitive / inductive coupling

We need to see a schematic and a photograph of your wiring, as part of this problem can be caused by poor layout.

Keep the internal pull ups they do no harm but use a much lower value, about 220R for a start.

Hi and thanks for the replies. I am posting the code per request. I am not using polliing only interrupts as you can see. Does it matter though if the problem is related to inference? Should I try and change the code to see?

#include <PubSubClient.h>
#include <ESP8266WiFi.h>
#include <stdio.h>
#include <string.h>


const char *ssid = "*******";     // The SSID (name) of the Wi-Fi network you want to connect to
const char *password = "*******"; // The password of the Wi-Fi network
const char *mqtt_server = "*********";
const char *userName = "*******";
const char *passWord = "********";

String clientId = "ESP8266Client";

const uint8_t MOTOR_STATUS = D5;
const uint8_t STOP_STATUS = D2;

int number_of_motor = 0;
int number_of_stop = 0;

WiFiClient espClient;
PubSubClient client(espClient);

int motor_working = HIGH;
int force_lock = HIGH;

bool EstablishedWIFIConnection()
{
  if (WiFi.status() != WL_CONNECTED)
  {
    WiFi.begin(ssid, password); // Connect to the network

    int i = 0;
    while (WiFi.status() != WL_CONNECTED)
    { // Wait for the Wi-Fi to connect
      delay(1000);
      if (i > 10)
      {
        return false;
      }
    }
  }
  else
  {
  }
  return true;
}

bool connecttoMQTT()
{
  if (client.connected() == false)
  {
    // Serial.print("Attempting MQTT connection...");
    if (client.connect(clientId.c_str(), userName, passWord))
    {
      // Serial.println("connected");
      //  ... and resubscribe
      client.subscribe(inTopic);
    }
    else
    {
      return false;
    }
  }
  else
  {
    // Serial.println("Already Connected");
  }

  return true;
}

boolean publishetoMQTT(const char *message, const char *topic)
{
  if (connecttoMQTT() == true)
  {
    // Serial.println(message);
    // Serial.println(topic);
    if (client.publish(topic, message) == false)
    {
      return false;
    }
    else
    {
      return true;
    }
  }
  else
  {
    // Serial.println("Failed to connect to MQTT Broker");
    return false;
  }
}

ICACHE_RAM_ATTR void motorMovement()
{
  motor_working = digitalRead(MOTOR_STATUS);
  number_of_motor++;
  char temp_str[100];
  sprintf(temp_str, "number_of_motor runs = %d\n", number_of_motor);
  publishetoMQTT(temp_str, "LogData");

  /// Motor Working
  if (motor_working == LOW)
  {
    publishetoMQTT("Motor Running...", "LogData");
  }
  else
  {
    /// Motor Stops
    if (motor_working == HIGH)
    {
      publishetoMQTT("Motor Stopped...", "LogData");
    }
    else
    {
      publishetoMQTT("Motor Status Unknown...", "LogData");
    }
  }
}
}

/// Runs when someone passes in front of the
/// photocells or when forceStop though relay 2
ICACHE_RAM_ATTR void forcedStop()
{
  force_lock = digitalRead(STOP_STATUS);
  number_of_stop++;
  char temp_str[100];
  sprintf(temp_str, "number_of_stop runs = %d\n", number_of_stop);
  publishetoMQTT(temp_str, "LogData");
  if (force_lock == HIGH)
  {
    publishetoMQTT("Photo detected...", "LogData");
  }
  else
  {
    /// Force Unlocked
    if (force_lock == LOW)
    {
      publishetoMQTT("Photo release...", "LogData");
    }
    else
    {
      publishetoMQTT("Photo Unknow status...", "LogData");
    }
  }
}

void setup()
{
  ///  specify inputs with pullup (Always HIGH when nothing is connected to it
  pinMode(MOTOR_STATUS, INPUT_PULLUP);
  pinMode(STOP_STATUS, INPUT_PULLUP);

  attachInterrupt(digitalPinToInterrupt(MOTOR_STATUS), motorMovement, CHANGE);
  attachInterrupt(digitalPinToInterrupt(STOP_STATUS), forcedStop, CHANGE);

  Serial.begin(115200); // Start the Serial communication to send messages to the computer

  if (EstablishedWIFIConnection() == true)
  {
    // Serial.println("Successfull Connected to WIFI!");
  }
  else
  {
    // Serial.println("Unable to connect to WIFI!");
  }
}

void loop()
{
}

I will try to make a schematic and/or photograph of my wiring for you to check. In a nutshell the wiring is rather simple. Both 240v and 12v relays are about 10-15 cm away from the micro controller close in a waterproof box. The 240v motor is about 30cm away (outside the box) but the 240v wires are run close to the microcontroller (about 8 cm away).

Hi Grumpy_Mike,

I am truly a newbie on this so please be patient with my questions :). Do you mean adding a 220omh resistor serially (not parallel) with the internal pull up resistor? This will increase the resistor value not decrease it correct? Does this mean it will make the 3.3v more stable or more subjective to changes?

Can you please clarify? Also If I add a capacitor to the input will this make the gpio more stable? I mean as I understand it will make the gpio change value with a delay correct? If this is the idea how does it help in my situation?

Thanks,

Phanos

No I don't mean that. I mean keep the internal pull up resistor and add an external one. This will put in in parallel and so will reduce the the value of the pull up resistor which WILL reduce the overall value of the resistor, which is what you want to do, to make it less susceptible to interference.

Not sure what capacitor you mean here. But again it is not making the GPIO more stable but less susceptible to EMI. You might think this is the same thing but it is not.

No.

I see I will add it as you suggesting and I will check again. Do I need to put on both gpios (motor and photocell) or just the 240v relays inputs?

What are the best value of a capacitor to put here. I have a capacitor around 100 nanofarad is this sufficient or need something else?

Again please excuse my ignorance I very new to this.

Phanos

Not sure what you mean here. I am talking about inputs to the Arduino. I am not suggesting anything to do with the 240V relay. Wouldn't that be an output from the Arduino?

A 100nF ceramic capacitor is a good value for general purpose decoupling.

Have a read of this
http://www.thebox.myzen.co.uk/Tutorial/De-coupling.html

Still waiting for the schematic and photograph.

Why not "by convection"?

Not sure if this is a joke or not, but as there is no emoji to signal a joke the explanation is that convection is a mechanism for the transfer of heat through a fluid.

1 Like

Can "electric charge" associated with lightning be seen as being transferred by "convection process"?

I looked at your code. I'm no expert but I see you have two complicated and slow interrupt routines - involving both serial and MQTT transfers.

I'd suggest you rewrite your program and just use interrupts (if absolutely necessary) to set flags you can use in your program to handle the occurrences. Or perhaps just poll.

Also, (I hesitate to disgree with the others who have already replied) but I see your inputs are from relay contacts; which by their nature are VERY prone to bounce.
That will trigger the interrupts many times - before they have even completed.

You could try connecting a small capacitor (say 0.1uF) directly across the switch contacts to suppress bounce and EMI as shown here

No.

Lightning is transferred by the breakdown of a gas into a plasma where the electrical charge strips the elections from the gas atoms. A plasma is electrical conductive because it is basically a cloud of electrons.

Convection is where one part of a fluid gets heated up and so expands. The expansion makes that part of a fluid less dense and so it rises, according to Archimedes law of displacement. As the fluid rises it cools due to the cooler fluid higher up and eventually contracts so that it falls again. This causes a circulation motion that is called convection. Note the fluid can be a liquid or a gas.

In secondary school, I learnt the definitions of conduction, induction, radiation, and convection; where, convection was defined as a process that physically conveyed mass/energy from one place to another.

During thundering/lightning, is it not the massive electric charge accumulated in the mid-sky and then moved towards earth surface to sink crushing everything in-between?

It could be thought of like that but the mechanism is not called convection. That is conduction.

See
https://en.wikipedia.org/wiki/Convection

I gave you the true definition of convection which I also learned at secondary school. When I was lecturing physics at a University I used to describe to my students of astronomy the convection cells that can be seen on the photosphere of the Sun. And also the convection cell that resulted in the Great Red Spot on Jupiter.

I also told my instruments students about relay contact sparks which were caused by the proximity of a contact once broken that caused a very high electrical field due to the very short distance the contacts were apart. This was known as arching and was the same physical mechanism as lightning.

1 Like

Hi Grumpy_Mike,

thanks for the help. Sorry for not providing a schematic by now I will try to do it soon. Just note that the whole setup is pretty simple. The motor and photocells are connected to the inputs of the relays. The Live (240v) from motor +12v dc from photocell are connected to the relays is such a way so where there is motor movement or photocells detection the corresponding relay is activated.

From the relays (their corresponding outputs) are connected as input to the Arduino. No other components (external resistors, capacitors etc) exists on my setup. (Maybe this is the problem).

In a controlled environment (when you test an Arduino input from a relay) everything might look just fine but after you connect everything together the problems I describe above appear. Again please excuse my ignorance since I am knew to this :).

I will have a look to the link you provide and get back to you.

Regards,

Phanos

Hi johnerrington,

you are right in a way. Interrupts functions should be as simple as possible and they should only signal the main loop function to do stuff like sending output info (either mqtt or Serial) but I do not think this is the problem here.

When I first write the program the interrupt functions were very minimal with very simple code. After I realize that the problem was with the interrupt functions I put those lines there for testing and troubleshooting purposes, especially to see if these functions there were truly called more than once!

To be honest I was not aware that you could the same effect by using polling instead of interrupts in arduino. I can try using poling to see if it helps but can you please direct me to the correct article? Is it the same as writing polling functions in c language?

Also thanks for the link. I will definitely read and try to follow.

Regards,

Phanos

That's an invalid description. The inputs of a relay cause the relay to switch. Please supply a circuit diagram if you can not describe your circuit in clear words.

Hi DrDiettrich,

I made a simple schematic. Here it is hope it clears thinks.