从我所读到的,我的问题的解决方案是使用中断,但如果我正确理解它,我不能在中断调用的例程中使用延迟。我有一个很大的按钮LED开关。我希望它在闲置时有一个心跳,但一旦推动它,保持绿色并执行代码。
如果我按下按钮足够次,我可以打破heartbeat()
(我假设在完成heartbeat
的循环时恰好在正确的时间进行状态更改,但我卡住了关于如何使它在第一次点击时工作。有没有其他方法可以做我正在尝试的事情?
void loop(){
heartbeat(); //Make LED beat.
buttonVal = digitalRead(buttonPin); //Check the button.
if (buttonVal != buttonState) { //If the button state changed.
if (buttonVal == HIGH){ //Check if the button is pressed.
analogWrite(greenPin, 255); //Button stays green once pushed.
functionA //Has some delays in it.
functionB //Has some other delays.
}
}
}
void heartbeat(){
for(i = 0; i < pmw; i++) {
analogWrite(greenPin,i);
delay(((60000/rate)*.1)/pmw);
}
for (i = pmw; i > 0; i--){
analogWrite(greenPin,i);
delay(((60000/rate)*.2)/pmw);
}
for(i = 0; i < pmw; i++) {
analogWrite(greenPin,i);
delay(((60000/rate)*.1)/pmw);
}
for (i = pmw; i > 0; i--){
analogWrite(greenPin,i);
delay(((60000/rate)*.6)/pmw);
}
}
答案 0 :(得分:5)
你的大部分假设都是对的。处理此问题的正确方法是使用中断,并且在中断服务例程(ISR)中存在延迟并不是一个好主意。所以你想要做的是在ISR中设置一个标志,并在主循环中检查该标志。
// Flag needs to be volatile if used in an ISR
volatile int buttonFlag = 0;
void loop()
{
if (buttonFlag == 0)
{
heartbeat(); //make led beat
}
else
{
analogWrite(greenPin, 255); //button stays green once pushed
functionA //has some delays in it
functionB //has some other delays
buttonFlag = 0; //clear flag after executing code
}
}
// Interrupt Service Routine attached to INT0 vector
ISR(EXT_INT0_vect)
{
buttonFlag = digitalRead(buttonPin); //set flag to value of button
}
由于中断只会在按钮状态发生变化时触发,因此您无需检查。
确保您的标志变量是全局的,并声明volatile
以便在ISR中使用。并确保使用正确的中断向量与您正在使用的引脚一起使用。
这是关于Arduino中断的good tutorial。这是你要做的另一个good example。
您可能还想查看debouncing your switch印刷机,具体取决于您使用的开关类型。如果没有错过第一次按下,你得到太多印刷机,你需要实施某种类型的去抖动。
答案 1 :(得分:2)
我是一名专业程序员,但我是Arduino世界的新手。我注意到许多Arduino所有者不了解编程的基础知识,并且在使用这项神奇的技术时无法取得好成绩。
特别是,我想建议不要使用Arduino中断,如果没有必要,因为它们只有两个,即使你可以为一个传感器或执行器写一个“漂亮”的代码,当你有要实现更复杂的项目,就不能使用它们。当然你使用中断来处理单个按钮是正确的,但如果你有四个按钮要管理怎么办?
出于这个原因,我使用“时间片”或“单步”技术重写了“心跳”草图。使用这种技术,每次执行循环功能时,只运行控制功能的“单步”,因此您可以根据需要插入任意数量,并且同样快速响应您正在使用的所有传感器。 为此,我为每个必须实现的控制函数使用全局计数器,每次执行循环函数时,我执行每个函数的一个步骤。 这是新草图:
// Interrupt.ino - this sketch demonstrates how to implement a "virtual" interrupt using
// the technique of "single step" to avoid heavy duty cycles within the loop function.
int maxPwm = 128; // max pwm amount
int myPwm = 0; // current pwm value
int phase = 1; // current beat phase
int greenPin = 11; // output led pin
int buttonPin = 9; // input button pin
int buttonFlag = 1; // button flag for debounce
int myDir[] = {0,1,-1,1,-1}; // direction of heartbeat loop
int myDelay[] = {0,500,1000,500,3000}; // delay in microseconds of a single step
void setup()
{
pinMode(buttonPin, INPUT); // enable button pin for input
// it's not necessary to enable the analog output
}
void loop()
{
if(phase>0) heartbeat(); // if phase 1 to 4 beat, else steady
buttonRead(); // test if button has been pressed
}
// heartbeat function - each time is executed, it advances only one step
// phase 1: the led is given more and more voltage till myPwm equals to maxPwm
// phase 2: the led is given less and less voltage till myPwm equals to zero
// phase 3: the led is given more and more voltage till myPwm equals to maxPwm
// phase 4: the led is given less and less voltage till myPwm equals to zero
void heartbeat()
{
myPwm += myDir[phase];
analogWrite(greenPin, myPwm);
delayMicroseconds(myDelay[phase]);
if(myPwm==maxPwm||myPwm==0) phase = (phase%4)+1;
}
// buttonRead function - tests if the button is pressed;
// if so, forces phase 0 (no beat) and enlightens the led to the maximum pwm
// and remains in "inoperative" state till the button is released
void buttonRead()
{
if(digitalRead(buttonPin)!=buttonFlag) // if button status changes (pressed os released)
{
buttonFlag = 1 - buttonFlag; // toggle button flag value
if(buttonFlag) // if pressed, toggle between "beat" status and "steady" status
{
if(phase) myPwm = maxPwm; else myPwm = 0;
phase = phase==0;
analogWrite(greenPin, myPwm);
}
}
}
如您所见,代码非常紧凑且执行速度快。我将心跳循环划分为四个“阶段”,由myDelay数组调节,其计数方向由myDir数组调节。如果没有任何反应,pwm led引脚的电压在每一步增加,直到达到maxPwm值,然后环路进入第2阶段,其中电压递减到零,依此类推,实现原始心跳。
如果按下该按钮,则循环进入零相位(无心跳),并且LED使用maxPwm电压进行补偿。从现在开始,循环保持稳定的led,直到按钮被释放(这实现了“去抖”算法)。如果再次按下该按钮,buttonRead功能将重新启动心跳功能,使其再次进入阶段1,从而恢复心跳。
如果再次按下按钮,心跳停止,依此类推。所有人都没有任何兴奋或反弹。