質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
Arduino

Arduinoは、AVRマイコン、単純なI/O(入出力)ポートを備えた基板、C言語を元としたArduinoのプログラム言語と、それを実装した統合開発環境から構成されたシステムです。

Q&A

解決済

3回答

1477閲覧

LEDの点灯方法を変える

Red373

総合スコア1

Arduino

Arduinoは、AVRマイコン、単純なI/O(入出力)ポートを備えた基板、C言語を元としたArduinoのプログラム言語と、それを実装した統合開発環境から構成されたシステムです。

0グッド

0クリップ

投稿2021/06/23 12:20

編集2021/06/23 12:22

はじめまして。

2日前にArduino MEGAのスターターキットを購入し、一通り各種動作やプログラムを動かしてみました。

次のステップとして、複数の動作を実行したいと思い、プログラムを組んでみましたが思うような動きがされず、本サイトを知り、質問させて頂きます。

・やりたい動作
1) タクトスイッチAを押すとLEDが点滅する。
2) タクトスイッチBが押されるまで1)を継続する。もしくは3分経過した場合はLEDを消灯する。
3) タクトスイッチBを押している間はLEDを点灯させる
4) タクトスイッチBを離すとLED消灯する。

・困っていること
LEDを点滅させる、スイッチ押している間LED点灯させる、の個々の動作は問題なくプログラム作成、動作しますが、上記連続動作ができない。

初心者のため、非常に簡単な内容かもしれませんが、具体的なプログラムの書き方をアドバイス頂けますと幸いです。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

その動作をさせるためには、スイッチAとBをずっと監視していなければいけません。
もし、点滅を

Arduino

1digitalWrite(LED,HIGH); 2delay(500); 3digitalWrite(LED,LOW); 4delay(500);

のように実装していたら、(少なくともAVRのArduinoの一般的なスキームのなかでは)希望の動作はできません。
ではどうするか...方法は一つではありません。
例えば、
マイコンは基本的に一時にはひとつの仕事しかできませんがしかし、人間から見ればそれなりの速さでたくさんの仕事ができます。ならば、いくつかの仕事を細切れにして実行してやる、ということでいくつかの、今回で言えばLEDの点滅とスイッチの監視という2つの仕事を同時に(見えるように)行うこともできます。

Arduino

1int count=0; 2void loop(){ 3 if(count<500){ 4 digitalWrite(LED,HIGH); 5 }else{ 6 digitalWrite(LED,LOW); 7 } 8 count++; 9 if(count>1000){ 10 count=0; 11 } 12 delay(1); 13}

というプログラムでも先のプログラムとほぼ同様にLEDが点滅する、というのは理解できますか? しかし、このプログラムは、delay()のところで0.5秒間とどまる先のものとは違い、常にloop()関数の先頭から最後までを実行します。1msだけ足踏みしますが...たった1000分の1秒だけ。人間にはこれを止まっていると認識することはできません。

では、タクトスイッチを監視してみましょう。スイッチを押したらLEDが点滅をやめるプログラムは

Arduino

1int count=0; 2bool blinking=true; 3 4void loop(){ 5 bool sw=digitalRead(SWPIN)==LOW;//スイッチは押すとマイコンピンがLになるように接続しているものとする 6 if(blinking){ 7 //LED点滅処理 8 if(count<500){ 9 digitalWrite(LED,HIGH); 10 }else{ 11 digitalWrite(LED,LOW); 12 } 13 count++; 14 if(count>1000){ 15 count=0; 16 } 17 } 18 if(sw){ 19 blinking=false; 20 } 21 delay(1); 22}

これくらいヒントがあると、だいぶ進むんじゃないかと思いますがどうでしょう。

投稿2021/06/23 13:34

thkana

総合スコア7703

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Red373

2021/06/24 02:53

ご回答ありがとうございました! delay()を使うという方法しか見ていた資料にはありませんでしたが、他にもいろいろあること、勉強になります。 取り急ぎ、お礼申し上げます。
guest

0

ベストアンサー

2日でそこまで行くとはすごいね。
私なんて、一か月ぐらい?、開梱もしなかったなぁ。

上手いアドバイスは難しいね。作ったスケッチがあれば指摘しやすいけど。

まずは、動作(条件と結果)を理解、分類する事かな。
まぁ、今回は本人が考えたものだから、最初から頭の中にあるのでしょうけど。
※基本的にすべての操作を考慮するから、今回ので言うと、Aを押して、3分以内にまたAを押した場合の処理はどうするのか?という部分が分類出来ない。(時間を延長か、SW無効か)

動きが判ったら、次はスケッチ上でどう表すか?どういった条件で書くか。
今回のだと
・点滅とSW処理を両立しなければならないから、loopをぐるぐる回す。
まぁ、基本、常にloopをぐるぐる回すスケッチを書いていればどんなのも対応出来ます。
・SW処理は、押した瞬間をとらえる必要は無さそう。(その時のSWを見るだけで良さそう)
・LEDの状態を表す変数と、点滅用の変数を用意する必要がある
ぐらいかな。おおまかに。

あとは、条件(注意事項)を頭の中に入れながらスケッチを書いていくだけです。
細かい点は、アドバイスは難しいですね。実際には、打ち込むときは常に気を使いますから。
具体的には↓のを参考にして下さい。
※あくまで1例です。特に「参考になる良いもの」を意識して書いた訳では無いです。

Arduino

1 2byte sw_A=2; 3byte sw_B=3; 4byte led=4; 5 6byte led_state;//0:消灯、1:点灯、2:点滅 7word cnt;//点滅用 8 9void setup(){ 10 pinMode(sw_A,INPUT_PULLUP);//負論理。ピン-SW-GND 11 pinMode(sw_B,INPUT_PULLUP);//負論理。ピン-SW-GND 12 pinMode(led,OUTPUT); 13} 14 15void loop() { 16 if(digitalRead(sw_A)==LOW) {//スイッチAを押したら点滅に 17 if(led_state!=2)cnt=0;//カウンタをリセット。(※延長なしの場合) 18 led_state=2; 19 } 20 if(digitalRead(sw_B)==LOW)led_state=1;//スイッチBを押したら点灯 21 else if(led_state==1)led_state=0;//点灯状態からSWを離したのなら消灯 22 23 if(led_state==2) {//点滅なら 24 digitalWrite(led,cnt%100<50);//点滅させる 25 if(++cnt==18000)led_state=0;//(約)3分経ったら、消灯 26 } else digitalWrite(led,led_state);//点灯、消灯処理 27 28 delay(10);//基準時間10ms 29}

投稿2021/06/23 16:31

nac_tnk

総合スコア494

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Red373

2021/06/24 02:52

ご回答ありがとうございました! 記載いただいたプログラムで、やりたいことが実行できました。 プログラムの内容はこれから自分なりにしっかり理解し、他への応用も含めて使用できるようにしていきます。コメントいただきました通り、正解は一つではないと思いますので、自分なりにどうすればやりたいことができるのかを引き続き勉強していきます。 取り急ぎ、お礼申し上げます。
Red373

2021/06/24 03:03

追加コメント、すみません。 ※今回ので言うと、Aを押して、3分以内にまたAを押した場合の処理はどうするのか?という部分が分類出来ない。(時間を延長か、SW無効か) →ここは、一連の操作((1)-(4))が終わった後に、Aが押された回数を繰り返す。という仕組みにしたいと考えています。この場合、どうプログラムを追記すればいいのか、、はもう少し勉強、トライアルが必要です。。。
nac_tnk

2021/06/24 03:27

> Aが押された回数を繰り返す。 それなら、↑と入力処理がちょっと変わります。 今回は単にその時のピンを見ればよかったのだけども、カウントする場合は「押した瞬間」ですから、↑又は↓の変化する時を捉える必要があります。 つまり、前回がHIGHで今回がLOWだった場合、というように。 まずは単独で、押した回数を数えるスケッチを書いてみるのが良いです。 ※ポイントをおさえるには、複合的なものより、簡単なスケッチの方が良いです。  複数解らない個所があるのは、覚えるのにかえって時間がかかります。
Red373

2021/06/30 05:51

cnt%100<50 が点滅になる仕組みがわからず。 0ならLOWと同じなので消灯、1ならHIGHと同じなので点灯はわかるのですが。。。
nac_tnk

2021/06/30 08:39

「%」と「<」の演算子は「%」の方が優先順位が高いので、まずはcnt%100が演算されます。 cnt自体は10ms毎にカウントアップしています。(cntが100で1秒) つまり、cnt%100で、10ms単位のストップウォッチの1秒以上の桁を消しています。 (1秒以下の2桁だけが繰り返しをしている) その値と「<50」(50=0.5秒よりも小さい)が演算されます。 当然、cntの値によって、真(1)か偽(0)になります。 digitalWrite(led,cnt%100<50);//点滅させる は if(cnt%100<50)digitalWrite(led,HIGH); else digitalWrite(led,LOW); の2行と全く同じです。 ※ただし、digitalWriteの第2引数はuint8_t(8bit符号なし整数)です。 0ならLOW出力、それ以外はHIGH出力です。
Red373

2021/07/01 00:27

ありがとうございます!理解できました。今時点でできたプログラムを掲載させて頂きます。大変参考になりました。
Red373

2021/07/01 00:45

byte sw_A=6; byte sw_B=7; byte sw_C=8; byte sw_D=9; byte ledA=10; byte ledB=11; byte ledC=12; byte led_stateA; //0:消灯、1:点灯、2:点滅 byte led_stateB; //0:消灯、1:点灯、2:点滅 byte led_stateC; //0:消灯、2:点滅 word cntA; //LED A点滅用 word cntB; //LED B点滅用 word cntC; //LED C点滅用 word coinA; //カウントA word coinB; //カウントB word coinC; //カウントC void setup(){ pinMode(sw_A,INPUT_PULLUP); //負論理。ピン-SW-GND pinMode(sw_B,INPUT_PULLUP); //負論理。ピン-SW-GND pinMode(sw_C,INPUT_PULLUP); //負論理。ピン-SW-GND pinMode(sw_D,INPUT_PULLUP); //負論理。ピン-SW-GND pinMode(ledA,OUTPUT); pinMode(ledB,OUTPUT); pinMode(ledC,OUTPUT); } void loop() { if(digitalRead(sw_A)==LOW) { //スイッチAを押したら if(led_stateA!=2) { cntA=0; //カウンタAをリセット。(※延長なしの場合) } led_stateA=2; //LED A点滅 coinA=1; //カウントA } if(coinA>=1) { //カウント1以上の場合 if(digitalRead(sw_B)==LOW) { //スイッチBを押したら led_stateA=1; //LED A点灯 } else if(led_stateA==1) { //点灯状態からSWを離したのなら led_stateA=0; //LED A消灯 coinA=0; //カウントAリセット cntB=0; //カウンタBをリセット。(※延長なしの場合) led_stateB=2; //LED B点滅 coinB=1; //カウントB } } if(coinB>=1) { //カウント1以上の場合 if(digitalRead(sw_C)==LOW) { //スイッチCを押したら led_stateB=1; //LED B点灯 } else if(led_stateB==1) { //点灯状態からSWを離したのなら led_stateB=0; //LED B消灯 coinB=0; //カウントBリセット cntC=0; //カウンタCをリセット。(※延長なしの場合) led_stateC=2; //LED C点滅 coinC=1; //カウントC } } if(coinC>=1) { //カウント1以上の場合 if(digitalRead(sw_D)==LOW) { //スイッチDを押したら led_stateC=0; //LED C消灯 } } if(led_stateA==2) { digitalWrite(ledA,cntA%100<50); //LED A点滅させる if(++cntA==1000) { //(約)10秒経ったら led_stateA=0; //LED A消灯 coinA=0; //カウントAリセット } } if(led_stateA==1) { digitalWrite(ledA,led_stateA); //LED A点灯 } if(led_stateA==0) { digitalWrite(ledA,led_stateA); //LED A消灯 } if(led_stateB==2) { digitalWrite(ledB,cntB%100<50); //LED B点滅させる if(++cntB==1000) { //(約)10秒経ったら led_stateB=0; //LED B消灯 coinB=0; //カウントBリセット } } if(led_stateB==1) { digitalWrite(ledB,led_stateB); //LED B点灯 } if(led_stateB==0) { digitalWrite(ledB,led_stateB); //LED B消灯 } if(led_stateC==2) { digitalWrite(ledC,cntC%100<50); //LED C点滅させる if(++cntC==1000) { //(約)10秒経ったら led_stateC=0; //LED C消灯 coinC=0; //カウントCリセット } } if(led_stateC==0) { digitalWrite(ledC,led_stateC); //LED C消灯 } delay(10); //基準時間10ms }
nac_tnk

2021/07/01 19:33

ちょっと、やりたい事自体が判りません。 > Aが押された回数を繰り返す。 が、Aを押した回数で点滅時間を決めるのかと思っていたのですけど、違ったようですね。 雰囲気的には、点滅LED+SWがA→B→Cと移行していく&途中で10秒LED点滅したら終了、みたいな感じなのかな。 配列を使って纏めて書くと↓のような感じ。(数が多いほど配列にした方が良い) ※LEDは、1つしか光らせないようだから、その場合は対象位置&状態で行う方が楽かも。  まぁ、結局は、自分のやりたい事を実現出来ていればどんなスケッチでも良いと思っていますけど。 byte sw[4]= {6,7,8,9}; byte led[3]= {10,11,12}; byte led_state;//0:消灯 1:点灯 2:点滅 byte led_num;//対象のLED位置 word cnt; void setup() { for(byte i=0; i<4; i++)pinMode(sw[i],INPUT_PULLUP); for(byte i=0; i<3; i++)pinMode(led[i],OUTPUT); } void loop() { if(digitalRead(sw[led_num])==LOW) {//スタート if(led_state!=2)cnt=0; led_state=2; } if(digitalRead(sw[led_num+1])==LOW && led_state==2) { led_state=1; } else if(led_state==1) { cnt=0; led_state=2; if(++led_num==3) { led_num=0;//リセット処理 led_state=0; } } for(byte i=0; i<3; i++) { if(led_state==2 &&led_num==i) { digitalWrite(led[i],cnt%100<50); if(++cnt==1000) { led_state=0;//10秒経ったら、消灯 led_num=0;//リセット } } else digitalWrite(led[i],led_state && led_num==i);//点灯、消灯処理 } delay(10);//基準時間10ms }
guest

0

LEDの状態を表す変数(enumだと分かりやすい)を用意し、
現在の状態が何かで条件分岐して、
その状態に応じたLED出力をし、
さらにその状態のときどういう操作をしたらどんな状態に遷移するかを書く

点滅にdelayを使っている場合は使わない方法に切り替える
例えばmillsなど、詳しくは調べれば出てくる

投稿2021/06/23 12:28

ozwk

総合スコア13553

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Red373

2021/06/24 02:55

ご回答ありがとうございます。 やりたいことの条件をしかり記載し、プログラムを組み立てていくことが重要だと認識しました。 知らない関数もまだまだ多数ありますので、日々勉強して理解したいと思います。 取り急ぎ、お礼申し上げます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問