0

私が読んだことから、私の問題の解決策は割り込みを使用することですが、それらを正しく理解していれば、割り込みによって呼び出されるルーチンで遅延を使用することはできません。大きな押しボタン式のLEDスイッチがあります。アイドル状態でハートビートを鳴らしたいのですが、プッシュしたら緑色のままでコードを実行します。

ボタンを十分な回数押すと壊れることがheartbeat()ありますが(ループが終了すると、ちょうどいいタイミングで状態が変化すると思いますheartbeat)、最初のクリックでボタンを機能させる方法に固執しています。私が試みていることを行う別の方法はありますか?

void loop(){

heartbeat();                                    //Make LED beat.
buttonVal = digitalRead(buttonPin);             //Check the button.
    if (buttonVal != buttonState) {               //If the button state changed.
        if (buttonVal == HIGH){                   //Check if the button is pressed.
            analogWrite(greenPin, 255);         //Button stays green once pushed.
            functionA                           //Has some delays in it.
            functionB                           //Has some other delays.
        }
    }
}

void heartbeat(){
    for(i = 0; i < pmw; i++) {
        analogWrite(greenPin,i);
        delay(((60000/rate)*.1)/pmw);
    }

    for (i = pmw; i > 0; i--){
        analogWrite(greenPin,i);
        delay(((60000/rate)*.2)/pmw);
    }

    for(i = 0; i < pmw; i++) {
        analogWrite(greenPin,i);
        delay(((60000/rate)*.1)/pmw);
    }

    for (i = pmw; i > 0; i--){
        analogWrite(greenPin,i);
        delay(((60000/rate)*.6)/pmw);
    }
 }
4

3 に答える 3

5

あなたはほとんどの仮定で正しいです。これを処理する適切な方法は、割り込みを使用することであり、割り込みサービスルーチン(ISR)に遅延を設けることはお勧めできません。したがって、実行したいのは、ISRにフラグを設定し、メインループでそのフラグを確認することです。

// Flag needs to be volatile if used in an ISR
volatile int buttonFlag = 0; 

void loop()
{
    if (buttonFlag == 0)
    {
        heartbeat();                        //make led beat
    }
    else
    {
        analogWrite(greenPin, 255);         //button stays green once pushed
        functionA                           //has some delays in it
        functionB                           //has some other delays
        buttonFlag = 0;                     //clear flag after executing code
    }

}

// Interrupt Service Routine attached to INT0 vector
ISR(EXT_INT0_vect)
{
    buttonFlag = digitalRead(buttonPin);    //set flag to value of button
}

割り込みはボタンの状態が変化したときにのみトリガーされるため、それを確認する必要はありません。

volatileフラグ変数がグローバルであり、ISRで使用するために宣言されていることを確認してください。また、使用しているピンで使用するために正しい割り込みベクトルを使用していることを確認してください。

これはArduino割り込みに関する優れたチュートリアルです。そして、これがあなたがやろうとしていることのもう一つの良い例です。

使用しているスイッチの種類によっては、スイッチプレスのデバウンスを検討することもできます。最初のプレスを見逃す代わりに、プレスが多すぎる場合は、何らかのタイプのデバウンスを実装する必要があります。

于 2012-11-27T13:16:56.200 に答える
2

私はプロのプログラマーですが、Arduinoの世界は初めてです。Arduinoの所有者の多くはプログラミングの基礎を知らず、この驚くべきテクノロジーを使用しても良い結果を得ることができないことに気づきました。

特に、Arduino割り込みは2つしかないため、必要がない場合は使用しないことをお勧めします。単一のセンサーまたはアクチュエーターに「美しい」コードを記述できる場合でも、実装する必要がある場合はより複雑なプロジェクトでは、それらを使用することはできません。確かに、割り込みを使用して1つのボタンを処理することは正しいと思いますが、管理するボタンが4つある場合はどうでしょうか。

このため、「タイムスライス」または「シングルステップ」の手法を使用して「ハートビート」スケッチを書き直しました。この手法を使用すると、ループ機能を実行するたびに、制御機能の「シングルステップ」のみを実行できるため、必要な数だけ挿入でき、使用しているすべてのセンサーに同じように迅速かつ応答します。そのために、実装する必要のある制御関数ごとにグローバルカウンターを使用し、ループ関数を実行するたびに、各関数の1つのステップを実行します。これは新しいスケッチです:

// Interrupt.ino - this sketch demonstrates how to implement a "virtual" interrupt using
// the technique of "single step" to avoid heavy duty cycles within the loop function.

int maxPwm = 128;   // max pwm amount
int myPwm = 0;      // current pwm value
int phase = 1;      // current beat phase
int greenPin = 11;  // output led pin
int buttonPin = 9;  // input button pin
int buttonFlag = 1; // button flag for debounce

int myDir[] = {0,1,-1,1,-1}; // direction of heartbeat loop
int myDelay[] = {0,500,1000,500,3000}; // delay in microseconds of a single step

void setup()
{
   pinMode(buttonPin, INPUT); // enable button pin for input
   // it's not necessary to enable the analog output
}

void loop()
{
   if(phase>0) heartbeat(); // if phase 1 to 4 beat, else steady
   buttonRead(); // test if button has been pressed
}

// heartbeat function - each time is executed, it advances only one step
// phase 1: the led is given more and more voltage till myPwm equals to maxPwm
// phase 2: the led is given less and less voltage till myPwm equals to zero
// phase 3: the led is given more and more voltage till myPwm equals to maxPwm
// phase 4: the led is given less and less voltage till myPwm equals to zero
void heartbeat() 
{
   myPwm += myDir[phase];
   analogWrite(greenPin, myPwm);
   delayMicroseconds(myDelay[phase]);
   if(myPwm==maxPwm||myPwm==0) phase = (phase%4)+1;
}

// buttonRead function - tests if the button is pressed; 
// if so, forces phase 0 (no beat) and enlightens the led to the maximum pwm
// and remains in "inoperative" state till the button is released
void buttonRead()
{
   if(digitalRead(buttonPin)!=buttonFlag)   // if button status changes (pressed os released)
   {
      buttonFlag = 1 - buttonFlag; // toggle button flag value
      if(buttonFlag) // if pressed, toggle between "beat" status and "steady" status
      {
         if(phase) myPwm = maxPwm; else myPwm = 0;
         phase = phase==0;
         analogWrite(greenPin, myPwm);
      }
   }
}

ご覧のとおり、コードは非常にコンパクトで実行が高速です。ハートビートループを4つの「フェーズ」に分割し、myDelay配列によって制御され、カウントの方向はmyDir配列によって制御されます。何も起こらない場合、pwm LEDピンの電圧はmaxPwm値に達するまで各ステップでインクリメントされ、ループはフェーズ2に入り、そこで電圧はゼロまでデクリメントされ、以下同様に元のハートビートが実装されます。

ボタンが押されると、ループはフェーズ0(ハートビートなし)に入り、LEDはmaxPwm電圧で調整されます。これ以降、ボタンが離されるまで、ループは安定したLEDを維持します(これにより、「デバウンス」アルゴリズムが実装されます)。ボタンをもう一度押すと、buttonRead機能がハートビート機能を再開し、フェーズ1に戻るため、ハートビートが復元されます。

ボタンをもう一度押すと、ハートビートが停止します。興奮や跳ね返りはまったくありません。

于 2015-09-03T12:19:26.663 に答える
0

Arduinoは実際にattachInterruptを使用して2つの割り込みしか持つことができませんが、Arduino Mega / Due / ...のような他のボードには、attachInterruptを使用した割り込みに使用できるさらに多くのピンがあります。さらに、attachInterruptsの代わりに直接レジスタ書き込み(低レベル操作)を使用する場合は、ArduinoUnoの任意のデジタル入力を使用して割り込み処理を行うことができます。ピン変更割り込みとhttps://ukmars.org/projects/ukmarsbot/developer-notes/encodersの適切な説明については、 https://thewanderingengineer.com/2014/08/11/arduino-pin-change-interrupts/を参照してください。 -on-ukmarsbot /外部割り込みに関する情報。この直接法はattachInterruptよりも高速であるため、Unoで使用して、pidループやシリアル通信などの他の処理を同時に実行しながら、直交エンコーダ入力で最大100kcounts/秒をカウントできます。これは、メインループでデジタル回線をポーリングする場合には不可能です。

于 2022-02-16T17:50:19.283 に答える