如何在Arduino上构建一个小型FSM,为什么我的不工作?

时间:2017-06-13 21:53:00

标签: arduino

// the loop routine runs over and over again forever:
void loop() {
    int voltage = analogRead(A0);
    pushNewData(voltage);
    if(data[SIZE-1] != 0){
        int average = (int)(calculateAVG(data));
        int sd = (int)(calculateSD(data));
        /*
        Serial.print(voltage);
        Serial.print(",");
        Serial.print(average);
        Serial.print(",");
        Serial.print(average+2*sd);
        Serial.print(",");
        Serial.println(average-2.5*sd);
        */
        if(voltage > average+2*sd || voltage < average+2.5*sd){
            interval = 5;
        }
        else{
            interval = 50;
        }

        //Serial.println(blinkElapsed);
        unsigned long currentMillis = millis();
        if(currentMillis - previous > interval) {
            // save the last time you blinked the LED 
            previous = currentMillis;   

            // if the LED is off turn it on and vice-versa:
            if (current_state == 1){
                Serial.println("1");
                led1_state = HIGH;
                led2_state = LOW;
                led3_state = LOW;
                digitalWrite(led1, led1_state);
                digitalWrite(led2, led2_state);
                digitalWrite(led3, led3_state);
                current_state = current_state + 1;
            }
            else if(current_state == 2){
                Serial.println("2");
                led1_state = LOW;
                led2_state = HIGH;
                led3_state = LOW;
                digitalWrite(led1, led1_state);
                digitalWrite(led2, led2_state);
                digitalWrite(led3, led3_state);
                current_state = current_state + 1;
            }
            else if(current_state ==3){
                Serial.println("3");
                led1_state = LOW;
                led2_state = LOW;
                led3_state = HIGH;
                digitalWrite(led1, led1_state);
                digitalWrite(led2, led2_state);
                digitalWrite(led3, led3_state);
                current_state = 1;
            }
        }
    }
}

状态是前面的全局变量。我希望这些LED一个接一个地闪烁,间隔由声级决定。但它只是继续运行state1而永远不会进入state2。我不知道为什么。为什么它永远不会被添加1?

2 个答案:

答案 0 :(得分:2)

我认为你的有限状态机“不是有限的”。状态3应该可以循环回到状态1,这是因为该过程有可能重复。现在回到1的唯一方法是状态3触发很多次,current_state变量滚动到4..5..6..integer最大值。 0..1。

else if(current_state ==3){
  Serial.println("3");
  led1_state = LOW;
  led2_state = LOW;
  led3_state = HIGH;
  digitalWrite(led1, led1_state);
  digitalWrite(led2, led2_state);
  digitalWrite(led3, led3_state);
  current_state = 1;
}

如果这不能解决问题,那么让我们开始倒退。如果程序被第一个LED点亮,那么很可能是这个代码

 else if(current_state == 2){
  //...
  current_state = current_state + 1;
}

从未执行过。因此,我们开始质疑我的状态机是否正在推进状态要了解这是否正在发生,暂时让我们重用一个输出引脚,led3作为一种“心跳“别针。因此,在代码更远的地方插入“flash LED3”剪辑,如下所示:

unsigned long currentMillis = millis();

// STOP FOR A SECOND TO TOGGLE THE STATE
if (led3_state == HIGH)
    led3_state = LOW;
else
    led3_state = HIGH;
// FLASH THE LED TO SEE IF WE'RE GETTTING HERE
digitalWrite(led3, led3_state);

// CONTINUE
if(currentMillis - previous > interval) {

你看,通过移动这个代码块,我们可以弄清楚我们要去的地方。现在,这个LED可能会非常快速地闪烁 - 足够快以显示持续亮起 - 但这是通过学习“是的,我的代码达到这一点”进行调试的基本方法。当你使用没有屏幕,没有键盘,没有打印机,没有这样的,没有示波器的“计算机”时,有时这就是你所能做的。

所以请这样做,并继续移动此代码块直到它退出工作。然后你会找到不起作用的声明,我们可以从那里开始。那声音怎么样?

答案 1 :(得分:2)

我重新格式化了你的代码。

现在有一些事情需要检查:

if(data[SIZE-1] != 0){

这会评估为true吗? (这可能是因为您在该块中使用了一些调试打印)。

if(currentMillis - previous > interval) {

变量previous是否正确初始化(在循环外)?例如:

unsigned long previous = millis();

current_state的初始值是多少?例如,如果它为零,则不会执行3个块(并且您可能正在查看某个默认状态)。

您还可以将最后else if(current_state ==3){更改为else{以至少抓住这些问题 - 或者甚至更好,正如Patrick在评论中建议的那样,添加额外的else分支来捕获可能无效的current_state

还要确保current_state在任何其他功能中都不会改变。