0
votes

currently am working on project to open a door with access code using arduino UNO and a servo motor. Normal operation requires entering access code using keypad which is working fine. Another option requires pressing a button that causes an interrupt to rotate the servo motor. My problem is my interrupt only works once and never works again. Plus how do i put the for-loop to rotate the servo motor inside the interrupt function with a delay. I know that is not possible but am calling another function that has the delayMicroseconds but all this is not working. Below is my implementation please help

#include <Keypad.h>
#include <LiquidCrystal.h>
#include <Servo.h>

Servo servo;


const int openButtonPin = 2;

void setup() {
  // put your setup code here, to run once:

  servo.attach(5);

  pinMode(openButtonPin, INPUT); //Pin 2 is input
  attachInterrupt(0, enforceOpenAccess, HIGH); // PIN 2

}


void(* resetFunc)(void) = 0;

void loop()
{
  //My other keypad implementations go here
}

void myDelay(int x)  // function to cause delay in the interrupt
{
  for(int i = 0; i<x; i++)
  {
    delayMicroseconds(1000); 
  }
}


void enforceOpenAccess() // ISR
{
   for(int k =0; k<=180; k+=2)
   {  
     servo.write(k); //rotate the servo
     myDelay(30);  //delay the rotation of the servo
   }
}

The code above is run on arduino UNO being simulated in proteus and the interrupt button is a push button. Please if there is other ways of implementing that but with the same behaviour as I have described above help out. Thanks a lot

2
And why is the service routine only running once when the button is pressed and never runs againodich daniel
Doing work that take long time in interrupt handler isn't good. I think you should have your interrupt handler just raise a flag and loop() should poll the flag and do the work if the flag is raised.MikeCAT

2 Answers

0
votes

There are a couple of problems in the slice of code you posted. Just for completeness, you should post the loop function, since we can't guess what you wrote inside.

Just one comment: did you put a pullup? Otherwise use INPUT_PULLUP instead of INPUT for the button pinmode.

The main one is that you attached the interrupt for the HIGH mode, which will trigger the interrupt any time the pin is up, not on the rising edge. And please use the macro digitalPinToInterrupt to map to the correct pin:

attachInterrupt(digitalPinToInterrupt(openButtonPin), enforceOpenAccess, RISING);

Then.. Let's improve the code. You really should use the interrupts only when strictly necessary when you have to respond IMMEDIATELY (= less than a couple of milliseconds) to an input. Here you don't have to, so it's MUCH better to check for the button in the loop (more on turning the motor following)

uint8_t lastState;

void setup()
{
    ...
    lastState = LOW;
}

void loop()
{
    uint8_t currentState = digitalRead(openButtonPin);
    if ((currentState != lastState) && (currentState == HIGH))
    {
        // Start turning the motor
    }
    lastState = currentState;
    ...
}

This will enable you to properly debounce the button too:

#include <Bounce2.h>
Bounce debouncer = Bounce(); 

void setup()
{
    ...
    pinMode(openButtonPin, INPUT); //Pin 2 is input
    debouncer.attach(openButtonPin);
    debouncer.interval(5); // interval in ms
}

void loop()
{
    debouncer.update();
    if (debouncer.rose())
    {
        // Start turning the motor
    }
    ...
}

If, on the other way, you REALLY want to use the interrupts (because waiting for a couple of milliseconds is too much for you), you should do something like this:

#include <Bounce2.h>
Bounce debouncer = Bounce(); 

void setup()
{
    ...
    pinMode(openButtonPin, INPUT);
    attachInterrupt(digitalPinToInterrupt(openButtonPin), enforceOpenAccess, RISING);
}

void loop()
{
    ...
}

void enforceOpenAccess() // ISR
{
    // Start turning the motor
}

It looks like your code? No, because now we'll speak about turning the motor

You should NOT use delays to make steps, because otherwise you will wait for 30ms * 180 steps = 5.4s before being able to do anything else.

You can, however, make a sort of reduced state machine. You want your servo to move from 0 to 180 in steps of 1. So let's code the "don't move" state with any value greater than 180, and consequently we can do something like this in the loop:

unsigned long lastServoTime;
uint8_t servoPosition = 255;
const int timeBetweenSteps_in_ms = 30;

void loop()
{
    ...
    if (servoPosition <= 180)
    { // servo should move
        if ((millis() - lastServoTime) >= timeBetweenSteps_in_ms)
        {
            lastServoTime += timeBetweenSteps_in_ms;
            servoPosition++;
            if (servoPosition <= 180)
                servo.write(servoPosition);
        }
    }
}

Then, using any of the previous examples, instead of // Start turning the motor write

lastServoTime = millis();
servoPosition = 0;
servo.write(servoPosition);

This way you won't block the main loop even when the button is pressed

0
votes

This is what is in my loop()

 char key = keypad.getKey();
  if(key)
  {   

    if(j < 10)
      {

        studentNumber[j] = key;
        //holdMaskedNumber[j] = '*';
        lcd.setCursor(0,2);
        lcd.print(String(studentNumber));

        if(j == 9)
        {
          studentNumber[9] = '\0';
          //holdMaskedNumber[9] = 0;
          lcd.clear();
          //String number = String(studentNumber);
          //lcd.print(number);

          //delay(1000);
          //lcd.clear();
          lcd.print("Access Code");

        }

        j++;
      }


    else
    {
       if(i < 5)
    {
      accessCode[i] = key;
      holdMaskedCode[i] = '*';
      lcd.setCursor(1,2);
      lcd.print(String(holdMaskedCode));
      if(i == 4)
      {
        holdMaskedCode[5] = '\0';
        accessCode[5] = '\0';
        //lcd.clear();
        //lcd.setCursor(0,0);
        //accessCodeString = String(accessCode);
        //lcd.print(accessCodeString);
        //delay(1000);
        lcd.clear();


     for(int i =0; i<6; i++)
          {
            lcd.print("Please wait.");
            delay(500);
            lcd.clear();
            lcd.print("Please wait..");
            delay(500);
            lcd.clear();
            lcd.print("Please wait...");
            delay(500);
            lcd.clear();

          }
          digitalWrite(4, HIGH);
          lcd.print("Access Granted"); 
          for(int k =0; k<=180; k+=2)
          {  
            servo.write(k);
            delay(30);
          }
          resetFunc();

      }

      i++;
    } 
    }  
  }