2

我有一种情况,我从传感器(连接到 arduino)读取值,这些值存储在 mysql 数据库中,然后显示在网页上。同时从网页读取继电器值,存储在 mysql 上,然后写入 arduino。我可以分别做每一个,但不能同时做。我附上了一些代码来展示我想要完成的事情。我认为这与串行可用性有关

/*----( SETUP: RUNS ONCE )----*/
void setup() {
  Serial.begin(115200);
  sensors.begin();     //Get DS18B20 temperatures
  sensors.setResolution(probe1, 10); //set resolution to 10bit
  sensors.setResolution(probe2, 10); //set resolution to 10bit
  Wire.begin();        // Start the Wire (I2C communications)
  RTC.begin();         // Start the RTC Chip

  digitalWrite(Relay_1, RELAY_OFF); //Relays
  digitalWrite(Relay_2, RELAY_OFF);

  pinMode(Relay_1, OUTPUT); //Set relays as outputs
  pinMode(Relay_2, OUTPUT);  
}
/*--(end setup )---*/

/****** LOOP: RUNS CONSTANTLY ******/
void loop() {
  ReadSensors();
  delay(1000);
  ReadRelays();  
}

/****** Read Sensors ******/
void ReadSensors()
{
  DateTime now = RTC.now();  //Get time from RTC
  photolevel = analogRead(photopin);  //Read light level

  sensors.requestTemperatures();
  dallas1 = sensors.getTempC(probe1);
  dallas2 = sensors.getTempC(probe2);

  dtostrf(photolevel, 1, 0, photo1);
  dtostrf(dallas1, 1, 2, temp1);
  dtostrf(dallas2, 1, 2, temp2);

  String tempAsString1 = String(photo1);
  String tempAsString2 = String(temp1);
  String tempAsString3 = String(temp2);

  Serial.print(now.year(), DEC);
  Serial.print('/');
  Serial.print(now.month(), DEC);
  Serial.print('/');
  Serial.print(now.day(), DEC);
  Serial.print(" ");
  Serial.print(now.hour(), DEC);
  Serial.print(':');
  Serial.print(now.minute(), DEC);
  Serial.print(" ");  
  Serial.println(tempAsString1 + " " + tempAsString2 + " " + tempAsString3);
  Serial.flush();
}

void ReadRelays()
{
  Serial.flush();
  // Read all serial data available, as fast as possible
  while(Serial.available() > 0)
  {
    char inChar = Serial.read();
    if(inChar == SOP)
    {
       index = 0;
       inData[index] = '\0';
       started = true;
       ended = false;
    }
    else if(inChar == EOP)
    {
       ended = true;
       break;
    }
    else
    {
      if(index < 79)
      {
        inData[index] = inChar;
        index++;
        inData[index] = '\0';
      }
    }
  }

  if(started && ended)
  {
    // The end of packet marker arrived. Process the packet 
    if (strlen(inData) > 0)
   {
      char *token = strtok(inData, ",");
      if(token)
      {
         index = 0;         
         array[index] = atoi(token);
         while (token = strtok(NULL, ","))
         {
            array[index++] = atoi(token);
         }
      }
    }

    Serial.println(array[0]);
    Serial.println(array[1]);

    // Reset for the next packet
    started = false;
    ended = false;
    index = 0;
    inData[index] = '\0';
  }
}

任何建议将不胜感激??

4

1 回答 1

1

“同时”做几件事的关键是要了解 Arduino 只有一个核心。因此,它只会一步一步地处理东西。现在假设您要同时执行三个函数“action1()”、“action2()”和“action3()”。为了实现这一点,您必须确保

  1. 所有动作都可以尽可能快地执行,最好是亚毫秒
  2. 他们都没有“块”

然后像这样将它们连续放置就可以达到预期的效果

void loop() {
    action1();
    action2();
    action3();
}

这就是“协同多任务”的基本思想。因此,任何操作都必须使用 delay() 或阻塞等待。例如

  while(Serial.available() == 0);

是阻塞等待,必须避免。如果任何操作是一组冗长且涉及的计算,事情就会变得更加复杂。假设 action1() 需要 1 秒来处理。然后 action1() 必须被拆分成足够快的执行速度。在“状态机”的帮助下,这些片段仍然可以保存在 action1() 中。例如

void action1() {
    static uint8_t state = 0;

    switch (state) {
        case 1: sub_action1_1(); break;
        case 2: sub_action1_2(); break;
        case 3: sub_action1_2(); break;
        default: state = 0; return;
    }        
    ++state;
}

当然,子动作必须执行得足够快。另一个经常遇到的问题是如何等待而不阻塞。这是通过存储所需的延迟来实现的。比如像这样

void action1() {
    static uint8_t state = 0;
    static unsigned long start_millis = 0;

    switch (state) {
        case 1: sub_action(); break;

        case 2: // this starts the delay
            start_millis = millis();
            break;

        case 3: // this checks if the delay has elapsed
            if (millis() - start_millis < 1000) {
                // if it did not yet elapse ensure that the state will not progress to the next step
                return;
            }
            // if the delay has elapsed proceed to next state
            break;

        case 4: next_sub_action(); break;

        default: state = 0; return;
    }        
    ++state;
}

当然这只是基本原理。在“真实”实现中,您可以根据需要改变它。

另一个经常需要的事情是有一个做一些事情的主循环和一个做一些其他事情的更高频率的“循环”。这通常通过所谓的定时器中断来执行。这更先进,但通常也更有效。中断的棘手之处在于它们往往更难调试。我的博客中有一些记录在案的示例。

闪烁几个不同频率的 LED。 VU Meter 实验(向下滚动!)

于 2013-07-04T19:38:24.710 回答