0

過去 2 日間、私は基本的にはかなり正確なユーザー調整可能なパルス信号 (周波数とデューティ サイクルの両方が調整可能) を生成するプログラムを作成しました。基本的に micros() 関数を使用して時間を追跡し、4 つのデジタル出力チャネルをローまたはハイにプルします。

これらの 4 つのチャネルには、常に 90 度の位相差が必要です (4cyl エンジンを考えてください)。ユーザーが設定を変更できるように、プログラムを再初期化するためにメイン ループにフラグを返す ISR が実装されています。このフラグはブール値の「set4」として定義されています。false の場合、メイン ループの「while」ステートメントが出力を実行します。true の場合、'if' ステートメントは必要な再計算を実行し、フラグをリセットして、'while' ステートメントを再開します。

プログラムは初期値で完全に動作します。フェーズは完璧です。ただし、ISRが呼び出されてメインループに戻ると、最初に中断された場所から「while」ステートメントでプログラムを再開し、終了してフラグ「set4」を再チェックして、今は真であり、停止する必要があります。その後、「if」ステートメントが後で必要なすべての変数をリセットして再計算しても、これらの 4 つの出力チャンネル間の位相は失われます。手動でテストしたところ、ISR が呼び出された時間に応じて異なる結果が得られ、通常は 4 つの出力チャネルすべてが同期されています。これは、値を変更しない場合でも発生します (したがって、最初に arduino の電源を入れたときに、'if' ルーチンによって変数がまったく同じ値にリセットされます!)。でも、

これは、ISR が呼び出された場所からループが再開されるため、micros() タイマーが原因であると確信しています。cli() と sei() を使用して割り込みをチェックして無効にすることで、別の方法で実行しようとしましたが、cli() の引数が true の場合にフリーズするだけなので、動作させることができませんでした。私が考えることができる唯一の解決策 (私はすべてを試し、一日中検索して試してみました) は、ISR を強制的にループの最初から再開させて、プログラムが正しく初期化されるようにすることです。頭に浮かぶ別の解決策は、おそらく micros() タイマーを何らかの方法でリセットすることです..しかし、これは私が信じているISRを台無しにするでしょう。

何が起こっているのかを視覚化するのに役立つように、ここに私のコードの一部を示します(純粋なコピーアンドペーストではないため、micros変数の「Millis」名と中括弧の欠落を気にしないでください:p):

    void loop()
    {
        while(!set4)
        {
        currentMillis = micros();
        currentMillis2 = micros();
        currentMillis3 = micros();
        currentMillis4 = micros();

          if(currentMillis - previousMillis >= interval) {
            // save the last time you blinked the LED 
            previousMillis = currentMillis;   

            // if the LED is off turn it on and vice-versa:
            if (ledState == LOW)
            {
              interval = ONTIME;
              ledState = HIGH;
            }
            else
            {
             interval = OFFTIME; 
             ledState = LOW;
            }

            // set the LED with the ledState of the variable:
            digitalWrite(ledPin, ledState);
            }
    .
    .
    //similar code for the other 3 output channels
    .
    .
    }
    if (set4){
    //recalculation routine - exactly the same as when declaring the variables initially  
      currentMillis = 0;
      currentMillis2 = 0;
      currentMillis3 = 0;
      currentMillis4 = 0;

      //Output states of the output channels, forced low seperately when the ISR is called (without messing with the 'ledState' variables)
      ledState = LOW;
      ledState2 = LOW;
      ledState3 = LOW;
      ledState4 = LOW;

      previousMillis = 0;
      previousMillis2 = 0;
      previousMillis3 = 0;
      previousMillis4 = 0;

     //ONTIME is the HIGH time interval of the pulse wave (i.e. dwell time), OFFTIME is the LOW time interval
     //Note the calculated phase/timing offset at each channel

      interval = ONTIME+OFFTIME;
      interval2 = interval+interval/4;
      interval3 = interval+interval/2;
      interval4 = interval+interval*3/4;

      set4=false;

    }
}

何がうまくいかないのですか?敬具、ケン

4

1 に答える 1