目前正在开展项目,使用arduino UNO和伺服电机打开带门禁密码的门。正常操作需要使用工作正常的键盘输入访问代码。另一个选项需要按下一个按钮,该按钮会导致中断旋转伺服电机。我的问题是我的中断只能工作一次而且再也不能工作了。另外,如何使用for-loop将伺服电机旋转到中断功能中并延迟。我知道这是不可能的,但我正在调用另一个具有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上运行的,模拟了proteus,中断按钮是一个按钮。请问是否有其他方法可以实现,但具有与上述相同的行为帮助。非常感谢
答案 0 :(得分:0)
您发布的代码片段中存在一些问题。为了完整起见,你应该发布循环函数,因为我们无法猜出你在里面写的是什么。
只有一条评论:你是否提出了一个问题?否则使用INPUT_PULLUP代替INPUT作为按钮pinmode。
主要原因是您将中断连接到HIGH模式,这将在引脚上升时触发中断,而不是在上升沿触发。请使用宏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);
这样即使按下按钮也不会阻止主循环
答案 1 :(得分:0)
这就是我的循环()
NSPredicate