なによりもまず。
if(digitalRead(7)==HIGH){
としていますが、スイッチの回路はどうなっているでしょう。
初心者にありがちな致命的ミスとして、電源(5V)からスイッチを通してPINに繋いでいるだけ、という配線をしがちで、そうするとこのプログラムになるのですが。(プログラムがこうだから必ず間違っている、というわけでもないです)
スイッチがOFFのときにマイコンのピンはどこにも繋がっていない(電位が固定されない)状態になるわけで、それはやってはいけないことです。
ハードウェアが間違っていると、ソフトがどんなに頑張ってもまともに動かせないことも多いです。
ソフト面でとてもとても大きな勘違いがあるのではないかと思うのが、
time=millis();
です。
この後で
if(time>5000){
とか
if(time>10000){
という使い方をしていますが、time=millis();というのはその後timeを参照するとその時点でのmillis()が取得できるということではありません 。
あくまで、プログラムを順次実行していって、time=millis();という文に到達したときにmillis()という関数を実行して得られた結果の値がtimeに入るだけです。timeが例えば10という値になったら、新たにtime=millis()等で値が代入されるまではず~っと10でしかありません。なんなら、
Arduino
1 void setup ( ) {
2 Serial . begin ( 9600 ) ;
3 }
4 void loop ( ) {
5 unsigned long time = millis ( ) ;
6 while ( 1 ) {
7 Serial . println ( time ) ;
8 }
9 }
とかいうプログラムで確かめて見ればいいです。このプログラムでは表示される値はず~っと変わりません。
ボタンが押されてからの経過時間を知りたいのなら、ボタンが押されたときにtime=millis();
として値を取得し、millis()-time
を計算することで経過時間を得ることになるでしょう。
すでに指摘がある部分、
while(digitalRead(2)==LOW) {}
ここで2pinをどうこうする、というのはあり得ませんね。7pinの間違い、また、スイッチが「押されている間」ここにとどまっていたいということでしょうから、digitalRead()がHIGHかLOWしか返さないのでどちらも同じことですが、
while(digitalRead(7) == HIGH); //慣習的に{}ではなく;
あるいは
while(digitalRead(7) != LOW);
でしょうね。
あとよくある間違いというか。
switch文というのは、switchのカッコの中の値を調べて、それと同じ値のcaseラベル(一致するものがなければdefaultラベル)に飛ぶ、というそれだけの動作をします。それ以上のなにかはありません。なので、
Arduino
1 switch ( val ) {
2 case 0 :
3 Serial . println ( "#0" ) ;
4 case 1 :
5 Serial . println ( "#1" ) ;
6 case 2 :
7 Serial . println ( "#2" ) ;
8 default :
9 Serial . println ( "#d" ) ;
10 }
というのは、valが0の場合
valが2なら
という出力をします。あくまで、caseラベルに飛ぶというだけで次のラベルで止まるとかそういう仕組みはありませんから。
もし、valが0の時に以降の出力をしたくないのなら(そしてそれぞれvalの値だけを出力したいなら)
Arduino
1 switch ( val ) {
2 case 0 :
3 Serial . println ( "#0" ) ;
4 break ; //switch文を終了する
5 case 1 :
6 Serial . println ( "#1" ) ;
7 break ;
8 case 2 :
9 Serial . println ( "#2" ) ;
10 break ;
11 default :
12 Serial . println ( "#d" ) ;
13 break ;
14 }
のようにbreakを入れてやらなければいけません。
これぐらい修正すれば動かないかなぁ...(確認していません)
追記。
for(;;)を抜ける手段が用意されていなくて「電源を切る」ところに行き着かないので...
ちょっと格好はよくないですけれど、餌をやり終わったら電源OFF、もcaseの中でやっちゃいましょうか。
Arduino
1 case 1 :
2 servo1 . write ( 105 ) ;
3 lcd . clear ( ) ;
4 lcd . print ( "mode 1" ) ;
5 if ( time > 5000 ) {
6 lcd . clear ( ) ;
7 lcd . print ( "open" ) ;
8 servo1 . write ( 50 ) ;
9 delay ( 5000 ) ;
10 lcd . clear ( ) ;
11 lcd . print ( "end" ) ; //このendはほとんど表示される間もなく電源が落ちるかも
12 servo2 . write ( 0 ) ; //このサーボ動作で電源OFF
13 while ( 1 ) ; //念の為、無限ループで動作を止める
14 break ;
15 case 2 :
16 //同様の変更
そうすると、ついでに(?)for(;;)そのものが不要になったりしますけれど。
Arduino
1 int val = 0 ; //valはloop()を出ても保存される必要がある
2
3 void loop ( ) {
4 if ( digitalRead ( 7 ) != LOW ) { //LOWと比較するのは私の趣味と思って下さい。一応理由はありますが。
5 time = millis ( ) ;
6 val = val + 1 ;
7 if ( val > 2 )
8 val = 0 ;
9 delay ( 20 ) ;
10 while ( digitalRead ( 7 ) != LOW ) { }
11 }
12 switch ( val ) {
13 //略
14 }
15 }
とか。
とりあえず解決になったところで、好き勝手に書いてみたのでご参考まで。コンパイルは通ってるけど動作確認はしてません。
Arduino
1 # include <Servo.h>
2 # include <LiquidCrystal.h>
3
4 //変わりそうな値はプログラム中に値を書き込まず、一旦変数を介する
5 //HARDWARE SETTINGS
6 const int PIN_BUTTON = 7 ;
7 const int PIN_servoFeed = 13 ;
8 const int PIN_servoPwr = 8 ;
9
10 //ANGLE DEFINITIONS
11 const int ANG_CLOSE = 105 ; //餌箱閉じる角度
12 const int ANG_FEEDING = 50 ; //餌箱開く
13 const int ANG_PON = 90 ; //電源ON
14 const int ANG_POFF = 0 ; //電源OFF
15
16 //TIME DEFINITIONS
17 const int TM_MODE1 = 5000 ; //餌箱動作時間1
18 const int TM_MODE2 = 10000 ; //同2
19 const int TM_FEED = 5000 ; //給餌時間
20 const int TM_WAIT = 1000 ; //汎用待ち時間
21 const int TM_POFF = 500 ; //電源OFF待ち時間
22
23 //自明な、プログラムそのままのことはコメントに書かない
24
25 //DEVICE INSTANCE
26 Servo servoFeed ; //給餌用サーボ
27 Servo servoPwr ; //終了時電源スイッチ操作してOFFするサーボ
28 LiquidCrystal lcd ( 12 , 11 , 5 , 4 , 3 , 2 ) ; //lcd(RS,ENABLE,D4,D5,D6,D7)を宣言
29
30 //valiables
31 unsigned long time ; //時間測定用時刻保持
32 int val = 0 ; //待ち時間モード保持
33 bool feeding = false ; //給餌開始かどうか
34 String modeStr ; //モード表示の文字列
35 int feederAngle ; //餌箱サーボの角度
36 int pwrAngle ; //電源制御の角度
37
38 void setup ( ) {
39 Serial . begin ( 9600 ) ; // 9600bpsでシリアル通信のポートを開く
40 lcd . begin ( 16 , 2 ) ; //(桁数,行数)を指定
41 pinMode ( PIN_BUTTON , INPUT ) ;
42 pinMode ( 10 , OUTPUT ) ; //10PIN?
43 servoFeed . attach ( PIN_servoFeed ) ;
44 servoPwr . attach ( PIN_servoPwr ) ;
45 feederAngle = ANG_CLOSE ;
46 servoFeed . write ( feederAngle ) ;
47 pwrAngle = ANG_PON ;
48 servoPwr . write ( pwrAngle ) ;
49 }
50
51 void lcdPrint ( String line1 , String line2 = "" ) {
52 lcd . clear ( ) ;
53 lcd . print ( line1 ) ;
54 lcd . setCursor ( 0 , 1 ) ;
55 lcd . print ( line2 ) ;
56 }
57
58 void loop ( ) {
59 if ( ! feeding ) {
60 feederAngle = ANG_CLOSE ;
61 unsigned long tm ;
62 if ( digitalRead ( PIN_BUTTON ) == HIGH ) {
63 //ボタンが押されたら
64 time = millis ( ) ; //時計リセット
65 //モード変更
66 val = val + 1 ;
67 if ( val > 2 )
68 val = 0 ;
69 //モードの設定
70 switch ( val ) {
71 case 0 :
72 modeStr = "mode select" ;
73 digitalWrite ( 10 , HIGH ) ; //???
74 break ;
75 case 1 :
76 modeStr = "mode 1" ;
77 tm = TM_MODE1 ;
78 break ;
79 case 2 :
80 modeStr = "mode 2" ;
81 tm = TM_MODE2 ;
82 break ;
83 default :
84 break ;
85 }
86 lcdPrint ( "close" , modeStr ) ;
87 delay ( 20 ) ;
88 //ボタンが離されるのを待つ
89 while ( digitalRead ( PIN_BUTTON ) == HIGH ) { }
90 }
91 if ( val != 0 && ( millis ( ) - time > tm ) ) {
92 //時間が来た
93 feeding = true ; //給餌に遷移
94 lcdPrint ( "open" , modeStr ) ;
95 time = millis ( ) ;
96 }
97 } else {
98 //給餌開始
99 feederAngle = ANG_FEEDING ;
100 if ( millis ( ) - time > TM_FEED ) {
101 feederAngle = ANG_CLOSE ;
102 lcdPrint ( "end" ) ;
103 if ( millis ( ) - time > TM_FEED + TM_POFF ) {
104 pwrAngle = ANG_POFF ;
105 }
106 }
107 }
108 //サーボ制御はここで一括
109 servoFeed . write ( feederAngle ) ;
110 servoPwr . write ( pwrAngle ) ;
111 }
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2019/10/22 14:10
2019/10/24 14:53