teratail header banner
teratail header banner
質問するログイン新規登録

回答編集履歴

1

コメントについて追記

2020/03/28 00:58

投稿

thkana
thkana

スコア7735

answer CHANGED
@@ -8,4 +8,102 @@
8
8
 
9
9
  `a=a*(-1);`なんてことさえしなければ、小学生だって単純な負の数ぐらい聞きかじっているでしょうし
10
10
 
11
- (そもそも私だったら割り込み使わないなぁ)
11
+ (そもそも私だったら割り込み使わないなぁ)
12
+
13
+ ---
14
+ コメント頂きました。
15
+ > 今回想定しているのが、
16
+ ①delayを使ってLEDの点滅を制御。歩行者信号機で、青点灯→点滅→赤 のような感じです。
17
+ ②スイッチが押されたら、①の青点灯のdelayを待たずに割り込んで、点滅→赤
18
+ のようなプログラムなのですが、割り込みを使わないでできる方法があれば、教えてくださいませ。
19
+
20
+ とのことですので、サンプルを書きました。青点灯10秒->青点滅5秒->赤点灯10秒を繰り返します。それぞれの途中でボタンSWを押す(ピン-GND間短絡)と、時間を待たずに次の状態に遷移します。割り込みは使っていません。
21
+ ```Arduino
22
+ const int BUTTON = 10;//ピンアサインは私の環境に合わせています。適宜変更して下さい
23
+ const int GREEN = 2;
24
+ const int RED = 3;
25
+
26
+ const int DLY_UNIT = 10;//1ループの時間(ミリ秒)
27
+ const int PERIOD_GREEN = 10 * 1000 / DLY_UNIT;//緑点灯期間(DLY_UNIT単位)
28
+ const int PERIOD_BLINK = 5 * 1000 / DLY_UNIT;//緑点滅期間
29
+ const int PERIOD_RED = 10 * 1000 / DLY_UNIT;//赤点灯期間
30
+ const int BLINK_CYCLE = 0.5 * 1000 / DLY_UNIT;//緑点滅周期
31
+ int count = 0; //時間を計るための変数
32
+ const int CHATFILTER = 100 / DLY_UNIT; //チャタリング除去時間
33
+ bool buttonHistory[CHATFILTER];//チャタリング除去のための履歴
34
+
35
+ enum STATUS { //LED状態変数
36
+ STAT_GREEN,
37
+ STAT_BLINK,
38
+ STAT_RED
39
+ } stat;
40
+
41
+ void setup() {
42
+ for (int i = 0; i < CHATFILTER; i++) {
43
+ buttonHistory[i] = true;
44
+ }
45
+ pinMode(GREEN, OUTPUT);
46
+ pinMode(RED, OUTPUT);
47
+ pinMode(BUTTON, INPUT_PULLUP);
48
+ stat = STAT_GREEN;
49
+ Serial.begin(115200);
50
+ }
51
+
52
+ bool checkButtonOn() {//ボタンが「押された」ことを検出する
53
+ static bool prevButton = true;
54
+ bool currentButton = true;
55
+ bool isButtonStable = true;
56
+ bool ret = false;
57
+ currentButton = digitalRead(BUTTON);
58
+ for (int i = 1; i < CHATFILTER; i++) {
59
+ if (currentButton != buttonHistory[i - 1]) {
60
+ isButtonStable = false;
61
+ }
62
+ buttonHistory[i] = buttonHistory[i - 1];
63
+ }
64
+ buttonHistory[0] = currentButton;
65
+ if (isButtonStable) {
66
+ ret = prevButton != currentButton && prevButton;
67
+ prevButton = currentButton;
68
+ }
69
+ return ret;
70
+ }
71
+
72
+ void loop() {
73
+ bool green = false;
74
+ bool red = false;
75
+ bool isButtonTurnedOn = checkButtonOn();
76
+ Serial.println(isButtonTurnedOn);
77
+ switch (stat) {//状態によって動作を振り分ける
78
+ case STAT_GREEN:
79
+ green = true;//緑の点灯処理
80
+ if (count > PERIOD_GREEN || isButtonTurnedOn) {//次に遷移する条件
81
+ count = 0;//時間クリア
82
+ stat = STAT_BLINK;//次の状態へ
83
+ }
84
+ break;
85
+ case STAT_BLINK:
86
+ green = (count / BLINK_CYCLE) & 1;
87
+ if (count > PERIOD_BLINK || isButtonTurnedOn) {
88
+ count = 0;
89
+ stat = STAT_RED;
90
+ }
91
+ break;
92
+ case STAT_RED:
93
+ red = true;
94
+ if (count > PERIOD_RED || isButtonTurnedOn) {
95
+ count = 0;
96
+ stat = STAT_GREEN;
97
+ }
98
+ break;
99
+ default:
100
+ stat = STAT_GREEN;
101
+ }
102
+ digitalWrite(RED, red);
103
+ digitalWrite(GREEN, green);
104
+ delay(DLY_UNIT);
105
+ count++;
106
+ }
107
+ ```
108
+ この程度のプログラムの場合、割り込みを使う使わないは本質ではありません。なんなら、ボタンの検出部分を割り込みを使ったものに置き換えるのも大した手間ではないでしょう。
109
+ 要は、長時間のdelay()がプログラムの動作を阻害するので、それを短時間のdelay()の繰り返しに置き換えてやる、ということです。あるいは、細切れのdelay()ではなくmillis()を使って時間を計ってもいいですけれど、とにかく長時間のdelay()を使わないことですね。