0

在对 Stack Overflow 和 Google 进行了一些研究之后,我对 Arduino 的时间管理有很多疑问,所以我决定向你寻求帮助。

目标是在“void loop()”内创建一个 switch case 循环,该循环执行某个子例程一段时间(例如,三分钟)。我想到的伪代码是:

void setup() {
    Serial.begin(9600);
    Serial.println("Waiting for command");
}

void loop() {
    // This is where the "polling" occurs
    if(Serial.available()){
        char ch=Serial.read();
        switch(ch)
        {
            case '1':
            // do something
            break;

            case '2':
            //do something
            break;

            case '3':
            void Tempfunct();
            break;

            default:
            Serial.print(ch);
            Serial.println(" : unknown command!");
        }
    }
}

// Function to be called
void Tempfunct() {
    //Do something for  3*60*60*1000 s and return to switch case selection
}

我认为这个解决方案是一个起点,因为我认为涉及中断的解决方案会是一个更好的解决方案。具体来说,我期望这样的伪代码:

void setup() {
    Serial.begin(9600);
    Serial.println("Waiting for command");
}

void loop() {
    // This is where the "polling" occurs
    if(Serial.available()){
        char ch=Serial.read();
        switch(ch)
        {
            case '1':
                // Do something
                break;

            case '2':
               // Do something
               break;

            case '3':
                void Tempfunct();
                break;

            default:
                Serial.print(ch);
                Serial.println(" : unknown command!");
        }
    }
}

// Function to be called
void Tempfunct() {
   //Do something until an interrupt condition is received 
   //from Serial (such a key pressed by user) and then 
   //return to switch case selection.
}

我该怎么做?

对我来说,这种情况就像在一个“案例”内部有一种“测量回路”。当 Arduino 收到预设的“开始键”(开始字符)时,它开始测量。当用户按下串行监视器(或超级终端)中的另一个按钮时,它会向 Arduino 发送一个预设的“停止键”(停止字符):Arduino 感觉就像有一个外部中断,停止测量并返回 void loop(){...} 循环。

4

3 回答 3

1

也许我不明白你想要做什么,但我会建议一个非常简单的有限状态机,对于这样的事情,基本上是一个基于你的应用程序“状态”的 switch 语句。

至于在特定时间段内做某事,您可以将当前毫秒捕获到一个变量中,然后在程序运行时进行测试,如果当前毫秒 - 存储毫秒 >= 您的延迟时间。

这是一些代码:

#define IDLE  0; //better to use enum; oh well
#define RED   1;
#define BLUE  2;

int programState;
long delayPeriod;
long startTime;

void setup() {
  Serial.begin(9600);
  Serial.println("Waiting for command");

  programState = IDLE;
  delayPeriod = (1000 * 60) * 3; // 3 minutes
}

void loop() {

  switch(programState){
  case IDLE:
    checkSerial();
    break;

  case RED:
    // need to handle millis rollover eventually, depending on
    //what the program is doing
    if (millis() - startTime >= delayPeriod){
      programState = IDLE;
    } 
    else {
      //do your thing 

      // to make this interruptable move the 'checkSerial()' call
      // out of the switch - so that it gets called every loop
    }
    break;

  case BLUE:

    break;
  }
}


void checkSerial(){
  // this is where the "polling" occurs
  if(Serial.available()){
    char ch=Serial.read();
    switch(ch){
    case '1':
      programState = RED; //set state
      startTime = millis(); //store current milisecond
      break;

    default:

    }    
  }
}
于 2012-11-28T04:57:03.130 回答
0

我猜你想要一组命令(可从串行端口获得)来执行不同部分的代码,具体取决于键。因此,如果您开始做一些工作(即执行函数“Tempfunct”),您的问题是如何中断您正在做的事情以返回到开关部分(负责用户输入)。

我想重新写下你的问题。您想知道的是如何执行代码并同时处理用户输入。典型的解决方案是使用中断。您需要指定一个中断向量(处理中断的函数,使用 AVR-Compiler 可以使用保留字 SIGNAL),当有新字符出现时应触发该中断向量。

您的问题很容易回答:Arduino 的串行库已经在串行端口中使用了中断。如果您查看此库的实现,您可以了解它是如何工作的。有一个环形缓冲区存储尚未读取的字符。每当有新字符出现时,就会触发中断,并通过中断向量将字符保存到此环形缓冲区中,以便稍后使用 Serial.read() 函数读取它。根据微控制器(您使用的是哪个 Arduino 板?),您可能会有更多中断。例如,Arduino Mega(4 个串行端口)需要四个串行中断向量:SIG_USART0_RECV、SIG_USART1_RECV、SIG_USART2_RECV 和 SIG_USART3_RECV。

您需要在您的项目(您当前的草图)中再次重写此中断向量,并在其中添加一些自定义代码。中断向量与任何其他函数一样。注意不要添加太多代码,只需要定期检查。

我不是 100% 确定,但是如果您在同一个项目中包含两个中断向量,我猜第二个(您的主代码)将覆盖第一个(库)。但我建议你先试试,以防万一。

祝你好运!

于 2012-11-27T23:15:47.700 回答
0

如果我正确理解您的要求,您希望这样当您在串行监视器中输入“开始键”时,您的 Arduino 将进入测量状态或循环。为此,只需编写一个 if 语句。使用 Serial.read() 命令从串行监视器获取输入,然后将其保存到变量中。然后使用 if 语句检查变量的内容,如果它是您想成为开始键的变量,那么它将进入 if 语句,您可以在 if 语句中有一个循环,该循环将循环并进行测量. 当您准备好结束测量时,您可以执行类似的过程。有一个 Serial.read() 函数,它保存到一个变量中,并有另一个 if 语句,这样当你决定按下“结束键”时,它会从测量循环中中断。IE:

 input = Serial.read();
    if(input == '1')
    {
      while(true)
      {
      measurment();
      input_2 = Serial.read();
      if(input_2 == '2')
        break;
      }
    }
于 2012-11-28T02:57:42.317 回答