- ベストアンサー
Arduinoのプログラムでボタンが押されたときにLEDを点灯させる方法
- Arduinoのプログラムで2番ピンに信号が入ると割り込みで13番ピンのLEDが設定時間点灯しますが、設定時間になると信号が入っていてもLEDは消灯してしまいます。
- ボタンが押されている間はLEDに点灯してもらいたいです。2番ピンに入る信号が不安定ですが、LEDをずっと点灯させたいです。
- Delayは使いたくありません。
- みんなの回答 (7)
- 専門家の回答
質問者が選んだベストアンサー
>このプログラムをLEONARDOで4系統で制御したいのですが上手くいきません。 すべて4つ必要。 volatile int PinFlag1 ; //1系統目INPUT2/OUTOUT13用 volatile int PinFlag2 ; //2系統目INPUT3/OUTOUT12用 volatile int PinFlag3 ; //3系統目INPUT0/OUTOUT11用 volatile int PinFlag4 ; //4系統目INPUT1/OUTOUT10用 long TimeCount1 ; //1系統目INPUT2/OUTOUT13用 long TimeCount2 ; //2系統目INPUT3/OUTOUT12用 long TimeCount3 ; //3系統目INPUT0/OUTOUT11用 long TimeCount4 ; //4系統目INPUT1/OUTOUT10用 //1系統目INPUT2割り込み void InterPin1() { PinFlag1 = 1 ; // 割込み有ればON } //2系統目INPUT3割り込み void InterPin2() { PinFlag2 = 1 ; // 割込み有ればON } //3系統目INPUT0割り込み void InterPin3() { PinFlag3 = 1 ; // 割込み有ればON } //4系統目INPUT1割り込み void InterPin4() { PinFlag4 = 1 ; // 割込み有ればON } void setup() { pinMode(2,INPUT) ; // 1系統目2番ピン付属ボタン入力 pinMode(3,INPUT) ; // 2系統目3番ピン付属ボタン入力 pinMode(0,INPUT) ; // 3系統目0番ピン付属ボタン入力 pinMode(1,INPUT) ; // 4系統目1番ピン付属ボタン入力 pinMode(13,OUTPUT) ; // 1系統目13番ピン付属LED出力 pinMode(12,OUTPUT) ; // 2系統目12番ピン付属LED出力 pinMode(11,OUTPUT) ; // 3系統目11番ピン付属LED出力 pinMode(10,OUTPUT) ; // 4系統目10番ピン付属LED出力 attachInterrupt(2,InterPin1, CHANGE) ; // 1系統目2番ピンの割込みを指定(変化したら割り込み) attachInterrupt(3,InterPin2, CHANGE) ; // 2系統目3番ピンの割込みを指定(変化したら割り込み) attachInterrupt(0,InterPin3, CHANGE) ; // 3系統目0番ピンの割込みを指定(変化したら割り込み) attachInterrupt(1,InterPin4, CHANGE) ; // 4系統目1番ピンの割込みを指定(変化したら割り込み) PinFlag1 = 0 ; // 1系統目 PinFlag2 = 0 ; // 2系統目 PinFlag3 = 0 ; // 3系統目 PinFlag4 = 0 ; // 4系統目 TimeCount1 = 0 ; // 1系統目 TimeCount2 = 0 ; // 2系統目 TimeCount3 = 0 ; // 3系統目 TimeCount4 = 0 ; // 4系統目 } void loop(){ { // 1系統目 // 割込み有ればその時点の時刻を保存する while(PinFlag1) { PinFlag1 = 0 ; // 立ち上がりか立ち下がりか調べて if (digitalRead(2)==HIGH) { // 立ち上がりなのであれば TimeCount1 = 0 ; // タイマー停止 digitalWrite(13,HIGH) ; // LEDを点灯 } else { // 立ち下がりなのであれば TimeCount1 = millis() ; // 現在の時刻を保存 } // 設定秒間カウントしたらLEDを消灯する if (TimeCount1 != 0) { if ((millis() - TimeCount1) >= 1010) { TimeCount1 = 0 ; digitalWrite(13,LOW) ; // LEDを消灯 } } } // 2系統目 // 割込み有ればその時点の時刻を保存する while(PinFlag2) { PinFlag2 = 0 ; // 立ち上がりか立ち下がりか調べて if (digitalRead(3)==HIGH) { // 立ち上がりなのであれば TimeCount2 = 0 ; // タイマー停止 digitalWrite(12,HIGH) ; // LEDを点灯 } else { // 立ち下がりなのであれば TimeCount2 = millis() ; // 現在の時刻を保存 } // 設定秒間カウントしたらLEDを消灯する if (TimeCount2 != 0) { if ((millis() - TimeCount2) >= 1010) { TimeCount2 = 0 ; digitalWrite(12,LOW) ; // LEDを消灯 } } } // 3系統目 // 割込み有ればその時点の時刻を保存する while(PinFlag3) { PinFlag3 = 0 ; // 立ち上がりか立ち下がりか調べて if (digitalRead(0)==HIGH) { // 立ち上がりなのであれば TimeCount3 = 0 ; // タイマー停止 digitalWrite(11,HIGH) ; // LEDを点灯 } else { // 立ち下がりなのであれば TimeCount3 = millis() ; // 現在の時刻を保存 } // 設定秒間カウントしたらLEDを消灯する if (TimeCount3 != 0) { if ((millis() - TimeCount3) >= 1010) { TimeCount3 = 0 ; digitalWrite(11,LOW) ; // LEDを消灯 } } } // 4系統目 // 割込み有ればその時点の時刻を保存する while(PinFlag4) { PinFlag4 = 0 ; // 立ち上がりか立ち下がりか調べて if (digitalRead(1)==HIGH) { // 立ち上がりなのであれば TimeCount4 = 0 ; // タイマー停止 digitalWrite(10,HIGH) ; // LEDを点灯 } else { // 立ち下がりなのであれば TimeCount4 = millis() ; // 現在の時刻を保存 } // 設定秒間カウントしたらLEDを消灯する if (TimeCount4 != 0) { if ((millis() - TimeCount4) >= 1010) { TimeCount4 = 0 ; digitalWrite(10,LOW) ; // LEDを消灯 } } } } 系統番号とINPUTピン番号、OUTPUTピン番号が順番通りになってない場合は、以下のような対応一覧表を作って、ミスを防ぎましょう。 系統番号 INPUT OUTPUT InterPin TimeCount PinFlag 1 2 13 1 1 1 2 3 12 2 2 2 3 0 11 3 3 3 4 1 10 4 4 4
その他の回答 (6)
- chie65536(@chie65535)
- ベストアンサー率44% (8740/19838)
重要な追記。 割り込みルーチンの中で変化する変数には「volatile」を付けないといけません。 int PinFlag ; は volatile int PinFlag ; と書かないといけません。 「volatile」は「割り込みの中で値が変化するから、毎回、ちゃんと値を調べないといけない」と言う修飾です。 例えば int Flag ; void loop() { Flag=0 ; while(Flag) { // Flagを一切使わない処理 } } と書いたら、最適化されて int Flag ; void loop() { Flag=0 ; while(0) { // Flagを一切使わない処理 } } になり、「while(0)の部分は絶対に実行されないから」と更に最適化されて int Flag ; void loop() { Flag=0 ; } になり、Flagに値を代入したあと使ってないので更に最適化され int Flag ; void loop() { } になってしまう可能性があります。 もし、こうなってしまったら「ボタンもLEDも何も動かない。実行しても何もしない」と悩む事になります。 なので、割り込み内で値が変化する変数は「最適化するな」と指示しないといけません。 そのため、割り込みの中で値が変化する変数は volatile int Flag ; のように書かないといけません。 これを忘れると、思わぬ落とし穴にハマります。
お礼
重ね重ね、ありがとうございます。 volatile int Flag ; の事を丁寧にありがとうございます。 本当に勉強になります。もう少し調べてみます。 今回のスケッチにもvolatile int PinFlag ;に変えました。 今の所、変える前でも変えても希望通りに動作しています。 変えておいた方が、忘れないのと勉強になるのでvolatile int PinFlag ;で行きます。 感謝します。 ありがとうございました。
補足
chie65535 すみません、その後ハマってしまっています。 このプログラムをLEONARDOで4系統で制御したいのですが上手くいきません。 入力は分割できたのですが出力が1個光っていると他のLEDが消えません。 で4個同時に消えるプログラムになってしまいました。 その後、LEDを消灯するプログラムも4分割したのですが全く動作しません。 TimeCountが4個有ると指定して各チャンネルに設定しないといけないのでしょうか? 大変申し訳ありません。 よろしければ、教えて下さい。 volatile int PinFlag ; long TimeCount ; void InterPin() { PinFlag = 1 ; // 割込み有ればON } void setup() { pinMode(2,INPUT) ; // 2番ピン付属ボタン入力 pinMode(3,INPUT) ; // 3番ピン付属ボタン入力 pinMode(0,INPUT) ; // 0番ピン付属ボタン入力 pinMode(1,INPUT) ; // 1番ピン付属ボタン入力 pinMode(13,OUTPUT) ; // 13番ピン付属LED出力 pinMode(12,OUTPUT) ; // 12番ピン付属LED出力 pinMode(11,OUTPUT) ; // 11番ピン付属LED出力 pinMode(10,OUTPUT) ; // 10番ピン付属LED出力 attachInterrupt(0,InterPin, CHANGE) ; // 2番ピンの割込みを指定(変化したら割り込み) attachInterrupt(1,InterPin, CHANGE) ; // 3番ピンの割込みを指定(変化したら割り込み) attachInterrupt(2,InterPin, CHANGE) ; // 0番ピンの割込みを指定(変化したら割り込み) attachInterrupt(3,InterPin, CHANGE) ; // 1番ピンの割込みを指定(変化したら割り込み) PinFlag = 0 ; TimeCount = 0 ; } void loop(){ { // 割込み有ればその時点の時刻を保存する while(PinFlag) { PinFlag = 0 ; // 立ち上がりか立ち下がりか調べて if (digitalRead(2)==HIGH) { // 立ち上がりなのであれば TimeCount = 0 ; // タイマー停止 digitalWrite(13,HIGH) ; // LEDを点灯 } else { // 立ち下がりなのであれば TimeCount = millis() ; // 現在の時刻を保存 } } // 設定秒間カウントしたらLEDを消灯する if (TimeCount != 0) { if ((millis() - TimeCount) >= 1010) { TimeCount = 0 ; digitalWrite(13,LOW) ; // LEDを消灯 } } } { // 割込み有ればその時点の時刻を保存する while(PinFlag) { PinFlag = 0 ; // 立ち上がりか立ち下がりか調べて if (digitalRead(3)==HIGH) { // 立ち上がりなのであれば TimeCount = 0 ; // タイマー停止 digitalWrite(12,HIGH) ; // LEDを点灯 } else { // 立ち下がりなのであれば TimeCount = millis() ; // 現在の時刻を保存 } } // 設定秒間カウントしたらLEDを消灯する if (TimeCount != 0) { if ((millis() - TimeCount) >= 1010) { TimeCount = 0 ; digitalWrite(12,LOW) ; // LEDを消灯 } } } { // 割込み有ればその時点の時刻を保存する while(PinFlag) { PinFlag = 0 ; // 立ち上がりか立ち下がりか調べて if (digitalRead(0)==HIGH) { // 立ち上がりなのであれば TimeCount = 0 ; // タイマー停止 digitalWrite(11,HIGH) ; // LEDを点灯 } else { // 立ち下がりなのであれば TimeCount = millis() ; // 現在の時刻を保存 } } // 設定秒間カウントしたらLEDを消灯する if (TimeCount != 0) { if ((millis() - TimeCount) >= 1010) { TimeCount = 0 ; digitalWrite(11,LOW) ; // LEDを消灯 } } } { // 割込み有ればその時点の時刻を保存する while(PinFlag) { PinFlag = 0 ; // 立ち上がりか立ち下がりか調べて if (digitalRead(1)==HIGH) { // 立ち上がりなのであれば TimeCount = 0 ; // タイマー停止 digitalWrite(10,HIGH) ; // LEDを点灯 } else { // 立ち下がりなのであれば TimeCount = millis() ; // 現在の時刻を保存 } } // 設定秒間カウントしたらLEDを消灯する if (TimeCount != 0) { if ((millis() - TimeCount) >= 1010) { TimeCount = 0 ; digitalWrite(10,LOW) ; // LEDを消灯 } } } }
- chie65536(@chie65535)
- ベストアンサー率44% (8740/19838)
>すみません、問題が発覚しました。 >割り込みで設定した時間(1010ms)以上、ボタンを押しているとLEDが消えずに点灯したままになってしまいました。 >時間設定を長くする以外に方法有りますか int PinFlag ; long TimeCount ; void InterPin() { PinFlag = 1 ; // 割込み有ればON } void setup() { pinMode(2,INPUT) ; // 2番ピン付属ボタン入力 pinMode(13,OUTPUT) ; // 13番ピン付属LED出力 attachInterrupt(0,InterPin, CHANGE) ; // 2番ピンの割込みを指定(変化したら割り込み) PinFlag = 0 ; TimeCount = 0 ; } void loop() { // 割込み有ればその時点の時刻を保存する while(PinFlag) { PinFlag = 0 ; // 立ち上がりか立ち下がりか調べて if (digitalRead(2)==HIGH) { // 立ち上がりなのであれば TimeCount = 0 ; // タイマー停止 digitalWrite(13,HIGH) ; // LEDを点灯 } else { // 立ち下がりなのであれば TimeCount = millis() ; // 現在の時刻を保存 } } // 設定秒間カウントしたらLEDを消灯する if (TimeCount != 0) { if ((millis() - TimeCount) >= 1010) { TimeCount = 0 ; digitalWrite(13,LOW) ; // LEDを消灯 } } }
お礼
ありがとうござます。 スケッチしていただき申し訳ありません。 勉強させていただきました。 実際に書き込んで長時間ボタンを押して話しても1010ms後に消えました。 本当にありがとうございました。 さらに勉強します。
- chie65536(@chie65535)
- ベストアンサー率44% (8740/19838)
追記。 立ち上がりと立ち下りの両方を割り込みさせる(attachInterruptの3番目にCHANGEを指定すると)、割り込みは、同じルーチンに飛んで来るので、PinFlagで割り込みの有無を調べるだけでは足りません。 「割り込みの有無を表すPinFlag変数」の他に「立ち上がり、立ち下り、どっちの割り込みかを表す変数」が必要になるでしょう。 変数を使わない場合は、setupにpinMode(2,INPUT)を追加して、割り込みあったと判定した後で、digitalRead(2)の戻り値がLOWかHIGHか判定して、立ち上がり、立ち下りを区別して下さい。
- tsunji
- ベストアンサー率20% (196/958)
割込みを使う必要はないです。 ループの中で2番ピンがHIGHならPinFlagを1にするプログラムを追加するだけ。
お礼
ありがとうございます。 難しく考えすぎました。 { if (digitalRead(2) == HIGH) { //スイッチの状態を調べる digitalWrite(13,HIGH) ; //スイッチが押されているならLEDを点灯 Loopの下に、これを入れたら思い通りの動作しました。 本当にありがとうございました。
補足
すみません、問題が発覚しました。 割り込みで設定した時間(1010ms)以上、ボタンを押しているとLEDが消えずに点灯したままになってしまいました。 時間設定を長くする以外に方法有りますか
- kngj1740
- ベストアンサー率18% (197/1052)
Arduinoのハードウェアに詳しくないですが、ボタンが押されている状態を検出する手段がないと出来ません。普通はポートの状態を読み取れる筈ですが。タイマールーチンにより定期的にボタンが押されている状態をチェックします。押されている限りLEDを点灯します。ボタン押下の割り込みで起動する必要はないように思います。キーボードのキースキャンなどと同じやり方です。
お礼
説明不足、申し訳ありませんでした。 信号が連続ONの時とパルスに時が有るのです。 ありがとうございました。
- chie65536(@chie65535)
- ベストアンサー率44% (8740/19838)
プログラムを ・2番ピンの立ち上がり割り込み時 LEDの点灯と、TimeCountを0にする処理を行う ・2番ピンの立ち下がり割り込み時 現在時刻の保存だけを行う(TimeCountを0以外の値にする) ・メインループ TimeCountが0でないなら、現在時刻とTimeCountを比較し、指定秒間に達したら、LEDを消灯してTimeCountを0にする処理を行う と言う形にすれば良いです。 LEDが消灯されるのは「立下りのあと、指定した時間、何も割り込みが起きない時だけ」なので、2番ピンが不安定でチャタリングを起こしても、つまり、立ち上がりと立下りの割り込みが短時間に連続で入ってきても、点灯しっ放しになります。
お礼
ご丁寧に、ありがとうございます。 ただ、私は初心者でして「なんとなく」分かるのですがどうしたらいいのか・・・・ さらに、勉強してchie65535様のプログラムもスケッチしてみたいです。 本当に、ありがとうございました。
お礼
chie65535様 ありがとうございます。 {と}を追加したら動作しました。 ありがとうございました。 本当に勉強になりました。 これから、もっと勉強しますので、よろしくお願い致します。
補足
chie65535様 早速のご回答ありがとうございます。 スケッチをコピーしてIDE(ライティングソフト)に張り付けましたがエラーに void loop(){の{ を削除したら書き込めたのですがLEDは点灯せず。 スケッチとにらめっこしていますが、修正するところが見つかりません。 全て、4系統必要なのですね・・・・勉強になります。 一覧表は必要ですね。作成します。 本当に、ありがとうございます。差し上げるお礼ポイントが足りないです。