過去 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;
}
}
何がうまくいかないのですか?敬具、ケン