A problem with interupts in code.

Hello

As a start I'm not a very good programmer, so my code is bit of a mess, but it's working for what I need it to do.

The project is a sensor array for a device to be placed in a parent's bed with their infant sleeping in it. The idea is that the accelerometers will trigger an alarm if a dangerous situation is detected, from a tilt or the device moving around on the bed. Right now that's all working fine, the settings need a bit of fine tuning, but it works. The problem is we'd also like a "night light" that would turn on for a time when a button is pressed, and off after a set time or the button is pressed again.

I've rigged a momentary push button to the no.0 interrupt pin on an Arduino Mega 2560. The code, as I understand it, should stop whatever is running and rung the LIGHT function if the interrupt pin changes between LOW and HIGH, regardless of the direction. I've tried attaching the button to the 5V pin, and to ground and neither way seems to work. I've also confirmed that the button is wired correctly, by just using it as a switch on the LED array when attached to a battery pack.

The interrupt is attached in the setup, and the function it calls is at the end of the code.

Any recommendations would be greatly appreciated, here's the code:

//Pins for Accelerometer 1  set in bridge
const int Pinx1 = 0;
const int Piny1 = 1;
const int Pinz1 = 2;

//Pins for Accelerometer 2 Set in Bridge
const int Pinx2 = 3;
const int Piny2 = 4;
const int Pinz2 = 5;

//Pins for Accelerometer 3  Set in base
const int Pinx3 = 6;
const int Piny3 = 7;
const int Pinz3 = 8;

//Reference values for Accelerometers
int refx1, refx2, refx3, refy1, refy2, refy3, refz1, refz2, refz3;
float grefx1, grefx2, grefx3,grefy1, grefy2, grefy3,grefz1, grefz2, grefz3;

//Read values during operation
float greadx1, greadx2, greadx3,gready1, gready2, gready3,greadz1, greadz2, greadz3;


//Button values
int button1, button2, button3;

//LED Pin

int LEDpin = 13;

void setup ()
{
  
  Serial.begin(9600);
  
  

  //Set startup reference values
  grefx1 = analogRead(Pinx1)/102.3*9.81;
  grefy1 = analogRead(Piny1)/102.3*9.81;
  grefz1 = analogRead(Pinz1)/102.3*9.81;
  grefx2 = analogRead(Pinx2)/102.3*9.81;
  grefy2 = analogRead(Piny2)/102.3*9.81;
  grefz2 = analogRead(Pinz2)/102.3*9.81;
  grefx3 = analogRead(Pinx3)/102.3*9.81;
  grefy3 = analogRead(Piny3)/102.3*9.81;
  grefz3 = analogRead(Pinz3)/102.3*9.81;
Serial.println(grefx1);
Serial.println(grefx2);
Serial.println(grefx3);
Serial.println(grefy1);
Serial.println(grefy2);
Serial.println(grefy3);
Serial.println(grefz1);
Serial.println(grefz2);
Serial.println(grefz3);
 //attachInterrupt(0,LIGHT, CHANGE);
}

void loop()
{

  int danger=0;
 danger = TILT (grefx1,grefx2,grefx3,grefy1,grefy2,grefy3,grefz1,grefz2,grefz3);
  Serial.println("danger");
  Serial.println(danger);
  if (
  danger == 1){
    ALARM();
  }
  danger = DISPLACEMENT ();
  Serial.println("danger");
  Serial.println(danger);
  if (
  danger == 1){
    ALARM();
  }
}


int TILT (float grefx1,float grefx2,float grefx3,float grefy1,float grefy2,float grefy3,float grefz1,float grefz2,float grefz3)
{
  greadx1 = analogRead(Pinx1)/102.3*9.81;
  greadx2 = analogRead(Piny1)/102.3*9.81;
  greadx3 = analogRead(Pinz1)/102.3*9.81;
  gready1 = analogRead(Pinx2)/102.3*9.81;
  gready2 = analogRead(Piny2)/102.3*9.81;
  gready3 = analogRead(Pinz2)/102.3*9.81;
  greadz1 = analogRead(Pinx3)/102.3*9.81;
  greadz2 = analogRead(Piny3)/102.3*9.81;
  greadz3 = analogRead(Pinz3)/102.3*9.81;
  
  Serial.println(greadx1);
Serial.println(greadx2);
Serial.println(greadx3);
Serial.println(gready1);
Serial.println(gready2);
Serial.println(gready3);
Serial.println(greadz1);
Serial.println(greadz2);
Serial.println(greadz3);
  //caculate the sine of half the angle from initial, from direction of gravity	
  double Theta1 = asin(sqrt((pow((grefx1-greadx1),2) + pow((grefy1-gready1),2) + pow((grefz1-greadz1),2)))/2 / sqrt((pow(grefx1,2) + pow(grefy1,2) + pow(grefz1,2))));
  double Theta2 = asin(sqrt((pow((grefx2-greadx2),2) + pow((grefy2-gready2),2) + pow((grefz2-greadz2),2)))/2 / sqrt((pow(grefx2,2) + pow(grefy2,2) + pow(grefz2,2))));
  double Theta3 = asin(sqrt((pow((grefx3-greadx3),2) + pow((grefy3-gready3),2) + pow((grefz3-greadz3),2)))/2 / sqrt((pow(grefx3,2) + pow(grefy3,2) + pow(grefz3,2))));
Serial.print("Theta1");
 Serial.println(Theta1);
 Serial.print("Theta2");
Serial.println(Theta2);
Serial.print("Theta3");
Serial.println(Theta3);
  //Note, Safety angle in degrees, initial set to 15
  float SafetyAngle = 15*3.14/180;

  if (Theta3 >= SafetyAngle/2)
  {
    return 1;
  }
  else if( Theta2 >= SafetyAngle/2)
  {
    return 1;
  }
  else if (Theta1 >= SafetyAngle/2)
  {
    return 1;
  }
  else{
    return 0;
  }

}
int DISPLACEMENT ()
{
  int dispAccelx1[100], dispAccelx2[100], dispAccelx3[100], dispAccely1[100], dispAccely2[100], dispAccely3[100], dispAccelz1[100], dispAccelz2[100], dispAccelz3[100];
  float aveAccelx1 =0, aveAccelx2 =0, aveAccelx3 =0, aveAccely1 =0, aveAccely2 =0, aveAccely3 =0, aveAccelz1 =0, aveAccelz2 =0, aveAccelz3 =0;
float drefx1, drefx2, drefx3,drefy1, drefy2, drefy3,drefz1, drefz2, drefz3;
  //loop to read 10 samples of acceleration 
drefx1 = analogRead(Pinx1)/102.3*9.81;
  drefy1 = analogRead(Piny1)/102.3*9.81;
  drefz1 = analogRead(Pinz1)/102.3*9.81;
  drefx2 = analogRead(Pinx2)/102.3*9.81;
  drefy2 = analogRead(Piny2)/102.3*9.81;
  drefz2 = analogRead(Pinz2)/102.3*9.81;
  drefx3 = analogRead(Pinx3)/102.3*9.81;
  drefy3 = analogRead(Piny3)/102.3*9.81;
  drefz3 = analogRead(Pinz3)/102.3*9.81;
  for (int count = 0; count < 99; count++){
    dispAccelx1[count]=analogRead(Pinx1);
    dispAccelx2[count]=analogRead(Pinx2);
    dispAccelx3[count]=analogRead(Pinx3);

    dispAccely1[count]=analogRead(Piny1);
    dispAccely2[count]=analogRead(Piny2);
    dispAccely3[count]=analogRead(Piny3);

    dispAccelz1[count]=analogRead(Pinz1);
    dispAccelz2[count]=analogRead(Pinz2);
    dispAccelz3[count]=analogRead(Pinz3);
  }

  //loop to count the total acceleration

  for (int count = 0; count < 99 ; count++){
    aveAccelx1 = aveAccelx1 + dispAccelx1[count]/102.3*9.81;
    aveAccely1 = aveAccely1 + dispAccely1[count]/102.3*9.81;
    aveAccelz1 = aveAccelz1 + dispAccelz1[count]/102.3*9.81;

    aveAccelx2 = aveAccelx2 + dispAccelx2[count]/102.3*9.81;
    aveAccely2 = aveAccely2 + dispAccely2[count]/102.3*9.81;
    aveAccelz2 = aveAccelz2 + dispAccelz2[count]/102.3*9.81;

    aveAccelx3 = aveAccelx3 + dispAccelx3[count]/102.3*9.81;
    aveAccely3 = aveAccely3 + dispAccely3[count]/102.3*9.81;
    aveAccelz3 = aveAccelz3 + dispAccelz3[count]/102.3*9.81;
  }

  //determining the average acceleration

  aveAccelx1 = aveAccelx1/100;
  aveAccelx2 = aveAccelx2/100;
  aveAccelx3 = aveAccelx3/100;


  aveAccely1 = aveAccely1/100;
  aveAccely2 = aveAccely2/100;
  aveAccely3 = aveAccely3/100;


  aveAccelz1 = aveAccelz1/100;
  aveAccelz2 = aveAccelz2/100;
  aveAccelz3 = aveAccelz3/100;

  //Net accelration (loses direction in this eqn.)

  float netAccel1 = sqrt((pow(aveAccelx1-drefx1,2) + pow(aveAccely1-drefy1,2) + pow(aveAccelz1-drefz1,2)));
  float netAccel2 = sqrt((pow(aveAccelx2-drefx2,2) + pow(aveAccely2-drefy2,2) + pow(aveAccelz2-drefz2,2)));
  float netAccel3 = sqrt((pow(aveAccelx3-drefx3,2) + pow(aveAccely3-drefy3,2) + pow(aveAccelz3-drefz3,2)));

  //estimate of read time, based on .0001 sec per read

  float time = .09;

  //displacement based on 0 initial velocity

  float disp1 = .5 * netAccel1 * pow(time,2);
  float disp2 = .5 * netAccel2 * pow(time,2);
  float disp3 = .5 * netAccel3 * pow(time,2);
  Serial.println(disp1);
   Serial.println(disp2);
    Serial.println(disp3);

  if ( disp3 >= .3)
  {
    return 1;
  }
  else if (abs(disp1-disp3) >= .01)
  {
    return 1;
  }
  else if(abs(disp2-disp3) >= .01)
  {
    return 1;
  }
  else{
    return 0;
  }
}


void ALARM ()
{
  int Buzzer = 12;
  while (1)
  {
    analogWrite(LEDpin, 153);
    analogWrite(Buzzer, 255);

    delay(1000);

    analogWrite(LEDpin, 0);
    analogWrite(Buzzer, 0);

    delay(1000);
  }
}

void LIGHT ()
{
  analogWrite(LEDpin, 153);
Serial.println("light");
  delay(300000);
  analogWrite(LEDpin, 0);
  return;
}

I've tried attaching the button to the 5V pin, and to ground and neither way seems to work. I've also confirmed that the button is wired correctly, by just using it as a switch on the LED array when attached to a battery pack

Wiring a switch from either ground or +5vdc and the other side directly to an arduino input pin does not work. That is because when you are not pressing the button there is not a active 0vdc or +5vdc wired to the pin so it is said to be a 'floating input pin' and will give random return values just based on electrical noise. One needs to use pull-up or pull-down resistors (say 10k ohms) from the input pin to +5vdc or ground respectively. Another simpler method is to enable the internal pull=up resistor for that pin in software and then wire the switch between the input pin and ground. Switch pushed will read a LOW and not pushed a HIGH.

Also in you interrupt ISR function LIGHT you have a serial output function. That won't work as serial output are interrupt driven and all interrupts are disabled while inside an active ISR. So remove it and if you have to have a serial output as a result of a user interrupt just set a global volatile variable flag in the ISR and then test the flag in the main loop to perform the serial output.

Lefty

Why do you need an interrupt to detect the switches? Is it really important to turn the light on within nanoseconds of the switch press?

If not, polling the switch really should be good enough, and far simpler.

As I said, I'm basically a novice at arduino, and my only other coding experience was a intro to C++ class I had to take.

I'm not sure I really understand how to enable the internal pull up resistor.

The serial output was an attempt to check if we ever got to the light function.

The purpose of using the interrupt is that the rest of the function will stop, without triggering the alarm function from any movement, like the parent taking the child out of the device. How would I poll the switch?

The purpose of using the interrupt is that the rest of the function will stop, without triggering the alarm function from any movement, like the parent taking the child out of the device.

You need to be more specific. The rest of what function?

An ISR should be fast. Very, very fast. Typically, that means setting a flag that is detected later, in loop() (or other function), triggering action there. Detecting that flag, or reading (polling) a switch pin, take the same amount of time/could happen in the same place, resulting in the light coming on/going off at the same time.

One final thought. Using interrupts (Do this NOW!) and delay() (sit on your hands for a while) in the same sketch hardly seems like a good idea.

I'm not sure I really understand how to enable the internal pull up resistor.

In your setup function, to set the internal pull-up resistors on for any specific digital input pin, you do this:

pinMode(2, INPUT_PULLUP); //turns on internal pull-up resistor for digital pin number 2, which is the
// user interrupt 0 pin

Lefty

Thank you both for the help. I've gotten it to work now.