Interrupt issue

Hello everyone,
I have an issue with the interruption in Arduino mega. I have an external interrupt using proximity sensor that turns on a relay and a motor (variable named "y"). While another external interrupt by another proximity sensor used to count number of gear teeth that once reach 16 teeth, it turns off the relay and the motor. As you can see on the code I reset the number of counting teeth once the first interrupt is triggered (count = 0).

The problem is that the turning on and off it occurs erratically such that it works fine for a while and then some errors and then works fine. Any suggestion of any errors on the code? or the problem occurs because of the unstable sensors' signals?

Here is the code,

#include "EasyNextionLibrary.h"  

EasyNex myNex(Serial);

const byte motor1_run = 21; 
const byte motor1_spd = 8;

const byte motor2_run = 4;
const byte motor2_spd = 9;

const byte motor3_run = 14;
const byte motor3_dir = 15;
const byte motor3_spd = 10;

const byte motor4_run = 16;
const byte motor4_dir = 17;
const byte motor4_spd = 11;


const byte count_sensor = 32;      //PNP sensor: used for counts 2 
const int clutch_sensor_2 = A3;    //NPN sensor:used for turn off clutch after certain counts

const int fill_sensor = A4;     //NPN sensor:used for turn off clutch 

const byte door_sensor = 25;   
const byte reset_weight_sensor = 30;
const byte reset_press_sensor = 31; 

const byte motor1 = 26;
const byte motor2 = 27; 
const byte clutch1 = 28;          //used for turn on clutch motor 
const byte clutch2 = 29;

byte x = 0;

byte number = 0;
byte Press = 0;
long Press_value = 0;
byte weight = 0; 
int weight_value = 0;

bool operating = false; 
bool Reset = false; 
bool prepare = false; 

const byte interruptPin = 3;
volatile byte count = 0;

const byte clutch_sensor_1 = 19;
volatile byte y = 0;

const byte count_interrupt = 18;
volatile byte count_d = 0;

byte x1 = 0;
byte x2 = 0;

unsigned long Time1 = 0;
unsigned long lastTime1 = 0;

/*unsigned long Time2 = 0;
unsigned long lastTime2 = 0;

unsigned long Time3 = 0;
unsigned long lastTime3 = 0;*/

void setup() {
  myNex.begin(9600); 
   
  pinMode(4,OUTPUT);
  pinMode(14,OUTPUT);
  pinMode(15,OUTPUT);
  pinMode(16,OUTPUT);
  pinMode(17,OUTPUT);
  pinMode(8,OUTPUT);
  pinMode(9,OUTPUT);
  pinMode(10,OUTPUT);
  pinMode(11,OUTPUT);
  pinMode(21,OUTPUT);
  pinMode(26,OUTPUT);
  pinMode(27,OUTPUT);
  pinMode(28,OUTPUT);
  pinMode(29,OUTPUT);
  
  pinMode(25,INPUT);
  pinMode(30,INPUT);
  pinMode(31,INPUT);
  
  attachInterrupt(digitalPinToInterrupt(interruptPin),counting,RISING);
  attachInterrupt(digitalPinToInterrupt(clutch_sensor_1),stateInv,RISING);
  attachInterrupt(digitalPinToInterrupt(count_interrupt),countingballs,FALLING);
 
  digitalWrite(motor1,LOW);
  digitalWrite(motor2,LOW);
  delay(2000);
}

void loop() { 
    myNex.NextionListen();

    if (prepare){
      servo_weight();
      servo_press();
      prepare = false; 
    }
    
    if (operating){
    digitalWrite(motor1,HIGH);
    digitalWrite(motor2,HIGH);

    if(y == 1 && analogRead(fill_sensor)<500){
      if(x == 0){
        noInterrupts();
        count = 0;
        interrupts();
        x = 1;
      }
    digitalWrite(clutch1,HIGH);
    servo_clutchOn();
                }
    
    if (y == 0) {
       digitalWrite(clutch1,LOW);
       servo_clutchOff();
       x = 0;
       }

    if (count > 16){
       y = 0;     
    }
    }

   else {
    digitalWrite(motor1,LOW);
    digitalWrite(motor2,LOW);
   }
 
   if (Reset){     
       if(digitalRead(reset_weight_sensor)==0){
       servo_weight_reset(); x1 = 0;}

       else if (digitalRead(reset_weight_sensor)==1)
       {servo_weight_off(); x1 = 1;}

       if(digitalRead(reset_press_sensor)== 0){
       servo_press_reset(); x1 == 0;}

       else if (digitalRead(reset_press_sensor)== 1)
       {servo_press_off(); x2 = 1;}

       if(digitalRead(reset_press_sensor)== 1 && digitalRead(reset_weight_sensor)==1 && x1 == 1 && x2 == 1)
       {Reset = false;}
                          }                        
}

void trigger1(){
operating = true;
}
void trigger2(){
operating = false;
}
void trigger3(){
Reset = true;
}

void trigger4(){
 number = myNex.readNumber("nNumber.val");
 weight = myNex.readNumber("nWeight.val");
 Press = myNex.readNumber("nPress.val");
 
 Press_value = Press * 500;
 
 if (weight == 25){
  weight_value = 1500;
 }
 else if (weight == 30){
  weight_value = 2000;
 }
 else if (weight == 35){
  weight_value = 2600;
 }
 else if (weight == 40){
  weight_value = 3250;
 }
 else if (weight == 45){
  weight_value = 3900;
 }
 else if (weight == 50){
  weight_value = 4600;
 }
 else if (weight == 55){
  weight_value = 5200;
 }
 else if (weight == 60){
  weight_value = 5850;
 }
 else if (weight == 65){
  weight_value = 6500;
 }
 else if (weight == 70){
  weight_value = 7150;
 }
 else if (weight == 75){
  weight_value = 7800;
 }
 else if (weight == 80){
  weight_value = 8450;
 }
 else if (weight == 85){
  weight_value = 9100;
 }
 else if (weight == 90){
  weight_value = 9750;
 }
 else if (weight == 95){
  weight_value = 10400;
 }
 else if (weight == 100){
  weight_value = 11050;
 }
 else if (weight == 105){
  weight_value = 11700;
 }
 else if (weight == 110){
  weight_value = 12350;
 }
 else if (weight == 115){
  weight_value = 13000;
 }
 else if (weight == 120){
  weight_value = 13650;
 }
 else if (weight == 125){
  weight_value = 14300;
 }
 else if (weight == 130){
  weight_value = 14950;
 }
 else if (weight == 135){
  weight_value = 15600;
 }
 else if (weight == 140){
  weight_value = 16250;
 }
 else if (weight == 145){
  weight_value = 16900;
 }
 else if (weight == 150){
  weight_value = 17550;
 }
 else if (weight == 155){
  weight_value = 18200;
 }
 else if (weight == 160){
  weight_value = 18850;
 }
 else {weight_value = 0;}
 
 prepare = true; 
}

void countingballs(){
  Time1 = millis();
  if(Time1 - lastTime1 > 250){
  count_d++;
  lastTime1 = Time1;
  }
}

void counting(){
  count++;
}

void stateInv(){
  y = 1;
  }

void servo_clutchOn(){
  digitalWrite(motor1_run,LOW);
  digitalWrite(motor2_run,LOW);
  analogWrite(motor1_spd,100);
  analogWrite(motor2_spd,100);
}

void servo_clutchOff(){
  digitalWrite(motor1_run,HIGH);
  digitalWrite(motor2_run,HIGH);
}


void servo_press(){
  digitalWrite(motor3_run,LOW);
  digitalWrite(motor3_dir,LOW);        //LOW is Down && HIGH is Up && sensor3 is for top stop 
  analogWrite(motor3_spd,50);        
  delay(Press_value);                        //5000 milliseconds for 10%      
  digitalWrite(motor3_run,HIGH);
  delay(1000);
}

void servo_press_reset(){
  digitalWrite(motor3_run,LOW);
  digitalWrite(motor3_dir,HIGH);         //HIGH is for weight increase && LOW is for weight decrase
  analogWrite(motor3_spd,50);                                    
}

void servo_press_off(){
  digitalWrite(motor3_run,HIGH); 
  digitalWrite(motor3_dir,HIGH);         //HIGH is for weight increase && LOW is for weight decrase
  analogWrite(motor3_spd,50);                                    
}

void servo_weight(){
  digitalWrite(motor4_run,LOW);
  digitalWrite(motor4_dir,HIGH);         //HIGH is for weight increase && LOW is for weight decrase
  analogWrite(motor4_spd,20);        
  delay(weight_value);                         //130 milliseconds for 1 gram && starts with 15 gram                
  digitalWrite(motor4_run,HIGH); 
  delay(1000);
}

void servo_weight_reset(){
  digitalWrite(motor4_run,LOW);
  digitalWrite(motor4_dir,LOW);         //HIGH is for weight increase && LOW is for weight decrase
  analogWrite(motor4_spd,20);                                    
}

void servo_weight_off(){
  digitalWrite(motor4_run,HIGH);
  digitalWrite(motor4_dir,LOW);         //HIGH is for weight increase && LOW is for weight decrase
  analogWrite(motor4_spd,20);                                   
}

Digital Write and delay should never be in an interrupt function. Rethink what you want to do. No other interrupt code can begin during those functions.
Paul

Sorry, but no digitalWrite and delay are used in an interrupt function in this code, here are the interrupts functions.

void countingballs(){
  Time1 = millis();
  if(Time1 - lastTime1 > 250){
  count_d++;
  lastTime1 = Time1;
  }
}

void counting(){
  count++;
}

void stateInv(){
  y = 1;
  }

The problem is that the turning on and off it occurs erratically such that it works fine for a while and then some errors and then works fine.

What do you mean by "turning on and off"? What is turned off?

Give examples of the errors, and describe the erratic behavior.

Please also post a complete wiring diagram and a photo of your setup. Motor electrical noise is a common cause of program malfunction.

Sorry, you are correct and I did not fully examine your code.
You are expecting 16 teeth plus one missing tooth on a gear. Is it a 17 tooth gear?
Paul

Hello @jremington ,
Turning on and off of the relay and motor that is controlled by the two interrupts, one of turning on, then start counting the number of teeth once 16 got, the relay and motor should turn off.
The erratic behavior is that sometimes they turn on when the sensor gives the signal and sometime they do not.

The machine is used for weighting the rounding dough balls and it was controlled previously by siemens controller but it was damaged and I am trying to re-operate it by Arduino Mega.

Loose wiring radiates electrical noise very efficiently.

The Arduino and all its wiring must be effectively shielded. Use a well filtered, shielded power supply for the Arduino as well.

The counting of teeth should be 16 that was handled by an interrupt to turn the relay and motor off , but the problem occurs more frequently with the other interrupt that used to turn on the relay and motor, which handled by a proximity sensor that is triggered for every half rotation of another gear.

I am using this shield to connect the wires to Arduino and I think they are well sheilded by it.

The myNex.NextionListen(); has a delay in it. So your sketch can not respond quickly.
Other functions for the Nextion wait for a reply.
I'm not sure what the myNex.readNumber() is doing, it is probably up to no good as well.

Do you use the normal Serial port for the Nextion ? Please use the normal Serial port for debug messages to the Serial Monitor and use one of the others for the Nextion display.

I think they are well sheilded by it.

No, not at all.

This is a properly shielded Arduino.

Hello @Koepel ,

myNex.readNumber() is used for inserting the number of dough balls by Nextion , that once the sensor reads the target number using the ISR "void countingballs()". And I have not written the commands for this in the normal loop function yet.

In addition, I am using the normal Serial port for Nextion screen (pins: 0 and 1) and I am not using the serial monitor.

I got the point of myNex.NextionListen(); function , Thank you.

Okay , I will consider it , thank you.

In ISR routine, the interrupt logic remains disabled; but, you are using mills() function which needs enabled interrupt logic for its operation. Do you think that millis() function is working in this ISR?

Actually, this is used to eliminate any noise from the sensor signal used for interrupting to get accurate counting of dough balls, and it works fine with me since millis() does not increment inside the ISR but it increments outside normally.

millis can be read during an ISR, but it will not increment, so the code should work for accessing the millis count when the interrupt occurred.

1 Like

Are you talking about this isr?

void stateInv(){
  y = 1;
  }

How fast is this gear turning. Have your tried to put a timed lock out in this interrupt like in the countingballs()?

Have you tried any RC hardware filtering on this interrupt input pin?

If the gear is slow enough, and you eliminate the delays from your program so it is not blocking, you may be able to replace the interrupt with noise resistant code which expects to see an input in a certain state for a period of time.