4

Webサーバーからデータを読み取るArduinoプロジェクトがあります。

EthernetClientコールバック関数でデータを1文字ずつ読み取るがあります。

私の作業コードは次のようになります(関連する部分のみ):

void setup() {
  Serial.begin(9600);
  ...
}

void loop() {
  char* processedData = processData(callback); // this is in a external lib
}

boolean callback(char* buffer, int& i) {
  ...

  if (Client.available()) {
    char c      = client.read();
    buffer[i++] = c;

    Serial.print(c);
  }

  ...
}

これは問題なく動作します(データの読み取りと処理)が、削除Serial.begin(9600);Serial.print(c);て動作を停止すると、理由がわかりませんか?唯一の変更点は、char cが印刷されないことです。何が問題なのですか?

4

2 に答える 2

2

一見無関係なコードが変更されたときにコールバック関数の動作が変わる一般的な理由は、オプティマイザー関連のバグです。

多くの組み込みコンパイラは、プログラム内でコールバック関数 (または割り込みサービス ルーチン) が呼び出されることを認識できません。彼らはその関数への明示的な呼び出しを確認せず、それが呼び出されることはないと想定します。

コンパイラがそのような仮定を行った場合、コールバック関数によって変更された変数を最適化します。これは、変数が初期化のポイントとアクセスのポイントの間でプログラムによって変更されたことを確認できないためです。

// Bad practice example:

int x; 

void main (void)
{
  x=5;
  ...

  if(x == 0) /* this whole if statement will get optimized away, 
                the compiler assumes that x has never been changed. */
  {
    do_stuff();
  }
}

void callback (void)
{
  x = 0;
}

このバグが発生すると、発見することはほとんど不可能であり、何らかの奇妙な症状を引き起こす可能性があります。

解決策は、main() と割り込み/コールバック/スレッドの間で共有されるすべてのファイル スコープ (「グローバル」) 変数を常にvolatile宣言することです。これにより、コンパイラがオプティマイザの誤った想定を行うことができなくなります。


volatile(キーワードを使用して同期を達成することも、メモリバリアを保証することもできないことに注意してください。この回答は、そのような問題にはまったく関係ありません!

于 2012-12-19T15:49:58.583 に答える
0

推測: シリアル ドライバーが開始されていないため、処理するデータがないため、コールバックはヒットしません。

データがない場合、シリアル コールバックが何をすることを期待していましたか?

とに関する詳細情報を提供するClientprocessData役立つ場合があります。

于 2012-12-19T13:44:08.820 に答える