[英]arduino interrupts with servo motor
目前正在使用arduino UNO和伺服电机打开带有访问代码的门的项目。 正常操作需要使用键盘正常输入访问密码。 另一种选择是需要按下一个引起中断以旋转伺服电机的按钮。 我的问题是我的中断只能工作一次,而不能再工作了。 另外,我如何将for循环延迟地插入中断功能中的伺服电机。 我知道这是不可能的,但是我正在调用另一个具有delayMicroseconds的函数,但所有这些都无法正常工作。 下面是我的实现,请帮忙
#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
}
}
上面的代码在变形中模拟的arduino UNO上运行,中断按钮是一个按钮。 如果还有其他实现方法,但是具有与我上面所述相同的行为,请帮忙。 非常感谢
您发布的代码片段中有两个问题。 仅出于完整性考虑,您应该发布循环函数,因为我们无法猜测您在其中编写的内容。
只是一个评论:你放了引体向上吗? 否则,将INPUT_PULLUP而不是INPUT用于按钮pinmode。
主要的原因是您将中断附加到了高电平模式,该中断将在引脚上升时(而不是在上升沿时)触发中断。 并且请使用宏digitalPinToInterrupt
映射到正确的引脚:
attachInterrupt(digitalPinToInterrupt(openButtonPin), enforceOpenAccess, RISING);
然后..让我们改进代码。 实际上,只有在必须立即对输入做出响应(=少于几毫秒)的情况下,才应该真正使用中断。 在这里,您不必这样做,因此最好检查循环中的按钮(更多有关旋转电机的信息)
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;
...
}
这也使您能够正确地反跳按钮:
#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
}
...
}
另一方面,如果您确实要使用中断(因为等待几毫秒对于您来说太麻烦了),则应该执行以下操作:
#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
}
看起来像您的代码? 不,因为现在我们要谈论旋转电动机
您不应该使用延迟来执行步骤,因为否则您将等待30ms * 180步= 5.4s,然后才能执行其他操作。
但是,您可以制作一种简化状态机。 您希望您的伺服以1的步长从0移到180。因此,让我们将“请勿移动”状态编码为任何大于180的值,因此,我们可以在循环中执行以下操作:
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);
}
}
}
然后,使用前面的任何示例,而不是// Start turning the motor
写
lastServoTime = millis();
servoPosition = 0;
servo.write(servoPosition);
这样,即使按下按钮,您也不会阻塞主循环
这就是我的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++;
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.