如何强制中断重新启动主循环而不是恢复? (时间问题!)
How to force interrupt to restart main loop instead of resuming? (timing issue!)
在过去的两天里,我写了一个程序,从根本上说,它生成了一个相当准确的用户可调脉冲信号(频率和占空比都可调)。它基本上使用 micros() 函数来跟踪时间,以便拉低或拉高 4 个数字输出通道。
这 4 个通道始终需要有 90 度的相位差(想想 4 缸发动机)。为了让用户更改设置,一个 ISR 被实现,其中 returns 一个标志到主循环以重新初始化程序。此标志定义为布尔值 'set4'。当它为 false 时,主循环中的 'while' 语句将 运行 输出。当它为真时,'if' 语句将执行必要的重新计算并重置标志,以便 'while' 语句将恢复。
该程序与初始值完美配合。相位是完美的。然而,当 ISR 被调用并返回到主循环时,根据我的理解,它会从最初中断的地方恢复 'while' 语句中的程序,直到它完成并重新检查标志 'set4'看到它现在是真的,它应该停止。
然后,即使 'if' 语句之后重置并重新计算所有必要的变量,这 4 个输出通道之间的相位也会丢失。手动测试我看到根据调用 ISR 的时间它会给出不同的结果,通常将所有 4 个输出通道同步在一起!
即使我可能不更改任何值,也会发生这种情况(因此 'if' 例程将变量重置为完全相同的变量,当您第一次启动 arduino 时!)。但是,如果我注释掉这个例程并只留下重置标志 'set4' 的行,程序将正常继续,就像什么都没发生过一样!
我很确定这是由 micros() 计时器引起的,因为循环将从调用 ISR 的地方恢复。我尝试通过使用 cli() 和 sei() 检查和禁用中断来以不同的方式做到这一点,但我无法让它工作,因为它只会在 cli() 的参数为真时冻结。我能想到的唯一解决方案(我已经尝试了所有方法,花了一整天的时间搜索和尝试)是强制 ISR 从循环开始处恢复,以便程序可以正确初始化。想到的另一个解决方案是可能以某种方式重置 micros() 计时器..但这会弄乱我相信的 ISR。
为了帮助您直观地了解正在发生的事情,这是我的代码片段(请不要介意微量变量中的“Millis”名称和任何缺少的大括号,因为它不是纯复制粘贴:p) :
void loop()
{
while(!set4)
{
currentMillis = micros();
currentMillis2 = micros();
currentMillis3 = micros();
currentMillis4 = micros();
if(currentMillis - previousMillis >= interval) {
// save the last time you blinked the LED
previousMillis = currentMillis;
// if the LED is off turn it on and vice-versa:
if (ledState == LOW)
{
interval = ONTIME;
ledState = HIGH;
}
else
{
interval = OFFTIME;
ledState = LOW;
}
// set the LED with the ledState of the variable:
digitalWrite(ledPin, ledState);
}
.
.
//similar code for the other 3 output channels
.
.
}
if (set4){
//recalculation routine - exactly the same as when declaring the variables initially
currentMillis = 0;
currentMillis2 = 0;
currentMillis3 = 0;
currentMillis4 = 0;
//Output states of the output channels, forced low seperately when the ISR is called (without messing with the 'ledState' variables)
ledState = LOW;
ledState2 = LOW;
ledState3 = LOW;
ledState4 = LOW;
previousMillis = 0;
previousMillis2 = 0;
previousMillis3 = 0;
previousMillis4 = 0;
//ONTIME is the HIGH time interval of the pulse wave (i.e. dwell time), OFFTIME is the LOW time interval
//Note the calculated phase/timing offset at each channel
interval = ONTIME+OFFTIME;
interval2 = interval+interval/4;
interval3 = interval+interval/2;
interval4 = interval+interval*3/4;
set4=false;
}
}
知道出了什么问题吗?
亲切的问候,
肯
问题出在这里:
previousMillis = 0;
previousMillis2 = 0;
previousMillis3 = 0;
previousMillis4 = 0;
所有 if 语句将在下一个循环中为真。
试试:
previousMillis = micros();
previousMillis2 = micros();
previousMillis3 = micros();
previousMillis4 = micros();
在过去的两天里,我写了一个程序,从根本上说,它生成了一个相当准确的用户可调脉冲信号(频率和占空比都可调)。它基本上使用 micros() 函数来跟踪时间,以便拉低或拉高 4 个数字输出通道。
这 4 个通道始终需要有 90 度的相位差(想想 4 缸发动机)。为了让用户更改设置,一个 ISR 被实现,其中 returns 一个标志到主循环以重新初始化程序。此标志定义为布尔值 'set4'。当它为 false 时,主循环中的 'while' 语句将 运行 输出。当它为真时,'if' 语句将执行必要的重新计算并重置标志,以便 'while' 语句将恢复。
该程序与初始值完美配合。相位是完美的。然而,当 ISR 被调用并返回到主循环时,根据我的理解,它会从最初中断的地方恢复 'while' 语句中的程序,直到它完成并重新检查标志 'set4'看到它现在是真的,它应该停止。 然后,即使 'if' 语句之后重置并重新计算所有必要的变量,这 4 个输出通道之间的相位也会丢失。手动测试我看到根据调用 ISR 的时间它会给出不同的结果,通常将所有 4 个输出通道同步在一起! 即使我可能不更改任何值,也会发生这种情况(因此 'if' 例程将变量重置为完全相同的变量,当您第一次启动 arduino 时!)。但是,如果我注释掉这个例程并只留下重置标志 'set4' 的行,程序将正常继续,就像什么都没发生过一样!
我很确定这是由 micros() 计时器引起的,因为循环将从调用 ISR 的地方恢复。我尝试通过使用 cli() 和 sei() 检查和禁用中断来以不同的方式做到这一点,但我无法让它工作,因为它只会在 cli() 的参数为真时冻结。我能想到的唯一解决方案(我已经尝试了所有方法,花了一整天的时间搜索和尝试)是强制 ISR 从循环开始处恢复,以便程序可以正确初始化。想到的另一个解决方案是可能以某种方式重置 micros() 计时器..但这会弄乱我相信的 ISR。
为了帮助您直观地了解正在发生的事情,这是我的代码片段(请不要介意微量变量中的“Millis”名称和任何缺少的大括号,因为它不是纯复制粘贴:p) :
void loop()
{
while(!set4)
{
currentMillis = micros();
currentMillis2 = micros();
currentMillis3 = micros();
currentMillis4 = micros();
if(currentMillis - previousMillis >= interval) {
// save the last time you blinked the LED
previousMillis = currentMillis;
// if the LED is off turn it on and vice-versa:
if (ledState == LOW)
{
interval = ONTIME;
ledState = HIGH;
}
else
{
interval = OFFTIME;
ledState = LOW;
}
// set the LED with the ledState of the variable:
digitalWrite(ledPin, ledState);
}
.
.
//similar code for the other 3 output channels
.
.
}
if (set4){
//recalculation routine - exactly the same as when declaring the variables initially
currentMillis = 0;
currentMillis2 = 0;
currentMillis3 = 0;
currentMillis4 = 0;
//Output states of the output channels, forced low seperately when the ISR is called (without messing with the 'ledState' variables)
ledState = LOW;
ledState2 = LOW;
ledState3 = LOW;
ledState4 = LOW;
previousMillis = 0;
previousMillis2 = 0;
previousMillis3 = 0;
previousMillis4 = 0;
//ONTIME is the HIGH time interval of the pulse wave (i.e. dwell time), OFFTIME is the LOW time interval
//Note the calculated phase/timing offset at each channel
interval = ONTIME+OFFTIME;
interval2 = interval+interval/4;
interval3 = interval+interval/2;
interval4 = interval+interval*3/4;
set4=false;
}
}
知道出了什么问题吗? 亲切的问候, 肯
问题出在这里:
previousMillis = 0;
previousMillis2 = 0;
previousMillis3 = 0;
previousMillis4 = 0;
所有 if 语句将在下一个循环中为真。
试试:
previousMillis = micros();
previousMillis2 = micros();
previousMillis3 = micros();
previousMillis4 = micros();