2

mysql データベースに格納された (arduino に接続された) センサーから値を読み取り、それが Web ページに表示される状況があります。同時に、リレー値が Web ページから読み取られ、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 のコアが 1 つしかないことを理解することです。したがって、次から次へと処理が行われます。ここで、「action1()」、「action2()」、および「action3()」という 3 つの関数を「同時に」実行したいとします。これを実現するには、次のことを確認する必要があります。

  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;
}

もちろん、サブ アクションは十分に高速に実行する必要があります。よく遭遇するもう 1 つの問題は、ブロックせずに待機する方法です。これは、必要な遅延を格納することによって実現されます。たとえば、このように

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;
}

もちろん、これはあくまでも基本原則です。「実際の」実装では、必要に応じてこれを変更できます。

もう 1 つよく必要になるのは、何らかの処理を行うメイン ループと、その他の処理を行う高周波数の「ループ」を用意することです。これは通常、いわゆるタイマー割り込みで実行されます。これはより高度ですが、通常はより効率的です。割り込みのトリッキーな点は、デバッグがやや難しくなる傾向があることです。私のブログには、これに関する文書化された例がいくつかあります。

異なる周波数でいくつかの LED を点滅させます。 VU メーターの実験 (スクロールダウン!)

于 2013-07-04T19:38:24.710 に答える