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

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

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

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

Q&A

解決済

2回答

6907閲覧

Arduinoでカウントダウンとカウントアップ同時に計測表示したい

Q_1986-kt

総合スコア13

Arduino

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

0グッド

0クリップ

投稿2020/09/20 04:00

設定した時間(秒)でカウントダウンするタイマーを作っています。LCDモジュールにタイムを表示
スイッチになるボタンを押している間だけカウントダウンし、ボタンを離すとタイマーがストップ、また押すとタイムを継続して測る。
設定した時間が経過すると表示は0になる。コードです。そして、リセット・ボタンで設定してある時間表示に戻る。
ここまでは、とりあえず動いています。

しかし、ボタンを押している間だけカウントさせるため、実際にボタンを押した時間をわかるようにしたいので、
カウントダウンと同時にカウントアップ(ストップウォッチとして)も表示したいと思っています。

今のコードでは、設定した時間(15.5秒)でカウントダウンして3行目に表示、
4行目に0から押している間の時間を表示します。ボタンを押し終わるのが、15.5秒以内であれば問題ありません。
例:3行目 Set Time 0.50 4行目 Time Up 15.0 と表示します。

しかし、設定した時間より長くボタンを押しているときには、
例:3行目 Set Time 0.00 4行目 Time Up 0.0 と Time Up の部分が0になってしまいます。

この部分を15.5秒から継続して計測、表示できるように(16.75秒などのように)
するにはどのようにすればいいのでしようか?

#include <Wire.h> #include <LiquidCrystal_I2C.h> float SetTime = 15.5; // 設定時間(秒単位) const int Time_Switch = 14; // 入力スイッチ ( A0 ) const int TimeReSet_Botann = 6; // 時間リセット ( D12 ) const int Switch_ON = LOW; // スイッチはプルアップ仕様のためONでLOW const int Switch_OFF = HIGH; // OFFでHIGH // ----------- 時間設定スイッチ関連 --------------------------------------------------------------- int swPrevState = 0; // 1つ前のスイッチ状態 int swCurrState = 0; // 現在のスイッチ状態 int SwitchOn = 0; // 立ち上がりエッジ検出 int ResetOn = 0; // 立ち上がりエッジ検出 int TimeState = 0; // タイマー状態 0:初期状態 1:動作 2:完了 3:停止 int TimeSet1 = 0; // 設定時刻プラス int TimeSet2 = 0; // 設定時刻マイナス int TimeReset = 0; // 設定時刻リセット int TimeSet = SetTime; // スイッチ設定時刻 float TimeDisp = SetTime; // 表示時刻 float Time_On = 0; // 設定時間 float TimeTotal = 0; // 設定時間 float TimeNow; // 現在時刻 float TimeStart; // タイマー開始時刻 float TimeStop; // 一時停止時刻 float TimeStart2; // タイマー開始時刻 float TimeStop2; // 一時停止時刻 LiquidCrystal_I2C lcd(0x27, 20, 4); // --------------------------------------------------------------------------------------------- void setup() { Wire.begin(); // LCDディスプレイ ------------ lcd.init(); lcd.backlight(); displayEntryScreen(); showEnteredTime(); // -------------------------- pinMode(Time_Switch, INPUT_PULLUP); // スイッチ pinMode(TimeReSet_Botann, INPUT_PULLUP); // リセット・スイッチ } void loop() { TimeNow = millis(); //現在の時間取得 //-------------- スイッチ設定 立ち上がりエッジ検出 ----------------------------------------- swCurrState = digitalRead(Time_Switch); //現在のスイッチ状態 if (swCurrState == Switch_ON) { SwitchOn = 1; // スイッチONで1 } else { SwitchOn = 0; // スイッチOFFで0 } //-------------- スイッチ動作状態の判定 ------------------------------------------------- switch (TimeState) { case 1: // 動作 if (SwitchOn == 0) { TimeState = 3; TimeStop = TimeNow; } else if ((TimeNow - TimeStart) / 1000 >= (TimeSet)) { TimeState = 2; } break; case 2: // 完了 if (SwitchOn == 1) { TimeState = 0; } break; case 3: // 停止 if (SwitchOn == 1) { TimeState = 1; TimeStart = TimeNow - (TimeStop - TimeStart); // TimeStart = TimeStart; } else if (TimeReset == LOW) { TimeState = 0; TimeSet = TimeDisp; TimeStart = TimeNow; } break; default: // 初期 if (SwitchOn == 1) { TimeState = 1; TimeSet = TimeDisp; TimeStart = TimeNow; } break; } //------------------ 表示時間の計算 --------------------------------------------------------- switch (TimeState) { case 1: //動作 TimeDisp = TimeSet - ((TimeNow - TimeStart) / 1000); TimeTotal = (TimeNow - TimeStart) / 1000; break; case 2: //完了 TimeDisp = 0; TimeTotal = (TimeNow - TimeStart) / 1000; break; case 3: //停止 TimeDisp = TimeSet - ((TimeStop - TimeStart) / 1000); TimeTotal = (TimeStop - TimeStart) / 1000; break; default: //初期 break; } //------------- リセット ------------------------------------------------------------------- TimeReset = digitalRead(TimeReSet_Botann); if (TimeReset == LOW) { TimeDisp = SetTime; TimeTotal = 0; delay(100); } lcd.setCursor(15, 2); lcd.print(TimeDisp,2); lcd.setCursor(15, 3); lcd.print(TimeTotal,2); } // ---------------- SetUp LCD --------------------------------------------------------------- void showEnteredTime() { lcd.setCursor(15, 3); lcd.print(TimeDisp,2); } void clearScreen() { lcd.setCursor(0, 0); lcd.print(" "); lcd.setCursor(0, 1); lcd.print(" "); lcd.setCursor(0, 2); lcd.print(" "); lcd.setCursor(0, 3); lcd.print(" "); } void displayEntryScreen() { clearScreen(); lcd.setCursor(0, 0); lcd.print("Set Time"); lcd.setCursor(0, 1); lcd.print(" "); lcd.setCursor(0, 2); lcd.print("Set Time"); lcd.setCursor(15, 2); lcd.print(SetTime,2); lcd.setCursor(0, 3); lcd.print("Time Up"); lcd.setCursor(15, 3); lcd.print(TimeDisp,2); }

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

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

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

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

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

y_waiwai

2020/09/20 05:58

現状のコードではどういう不具合があるんでしょうか。 いまいち説明がわかりません
Q_1986-kt

2020/09/20 12:46

カウントダウン(設定時間あり)とカウントアップ(ストップウォッチ)を1つのスイッチで 行います。カウントダウンは、設定値15.5秒から0までを表示。 カウントアップの部分は、ストップウォッチとして機能して、カウントダウンの設定時間をすぎても 計測して計測が終わった時間を表示、例として16.7秒です。
guest

回答2

0

ベストアンサー

[動作]状態でボタンが押し続けられて経過時間が設定時間を超えたら[完了]に遷移するわけですが、そのときボタンは押されているので[完了]のスイッチ検査に引っかかって[初期]状態に即遷移してしまいます。[完了]のスイッチ検査の極性が逆になっている気がします。
そこを反転したとして、一旦ボタンを放して再度押すと、その挙動はちょっと変に思います。[初期]での変数設定がおかしくないでしょうか。


あと、余計なことをいくつか。

  • TimeStateのような状態変数は、enumを使って、各値に適切な名前をつけたほうがよろしいのでは
  • "Set Time"の項に変数TimeTotalを表示し、"Time Up"の項にTimeDispを表示し、TimeSetやSetTimeという変数もまた別にあってTimeSet = SetTime;なんてやっているのは混乱のもとと思います
  • さらには、SwitchOnという変数とSwitch_ONという定数があるというのはどうでしょう。変数はキャメルケースにして定数はスネーク、という使い分けのようですが、全体として似すぎていませんか
  • リセットの処理が[スイッチ動作状態の判定]の停止の項と[リセット]のところに別れているのはどちらかにまとめてもよいのでは

投稿2020/09/21 01:58

thkana

総合スコア7703

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

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

Q_1986-kt

2020/09/21 02:22

ご指摘ありがとうございます。 ネットで色々調べながら、あれこれやっていて、どんどん自分でもわかりずらくなり 整理しなくてはと思っていました。 もう一度、変数から整理して試してみたいと思います。
Q_1986-kt

2020/09/24 04:53

遅くなってしまいましたが、とりあえず、設定する時間にオフセット・タイムを設定して 計算するときにはプラス、表示させる値は、オフセット値を引いた値を表示させることで 対応しました。時間的に問題でとりあえず動かさなくて行けなかったので、 ただ、ご指摘のように、いろいろなコードを参考にしながら組み合わせ作っているので コードが(変数、定数名なども)ごちゃごちちゃしていますので、改めて一から書き直してみたいと思います。
guest

0

コードを読んだだけで、試したりはしていませんが、ボタンを押したまま、15.5秒たつと、TimeStateが、1⇒2⇒0と遷移し、初期化のコードを実行してしまうからではないでしょうか?

15.5秒経過しても、ボタンを押している時間(TimeTotal)をリセットせずに更新するには、スイッチ動作状態の判定のdefaultで、TimeStart = TimeNow;をやめる。ただし、これだと1回目が困りそうなので、状態の数を増やすとか、1回目だけTimeStartを設定するとか、が必要なのではないでしょうか?

投稿2020/09/20 07:26

mkgt00

総合スコア165

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

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

Q_1986-kt

2020/09/20 12:59

ありがとうございます。 試してみましたが、この方法だと、カウントアップのスタートが0から始まりません。 5秒、とか2秒とかから始まり、カウントダウンも、その時間分進んだ10秒、13秒からカウントを 初めてしまいます。 しかし、設定時間をすぎてからも、カウントアップはしているので16秒、17秒とカウントはします。 ”TimeStart = TimeNow;をやめる。”では、うまく行きません。 カウントアップ、とカウントダウン、別にコードを書く必要があるのでしょうか?
mkgt00

2020/09/20 21:49

”TimeStart = TimeNow;をやめる。”ではなく、"TimeStart = TimeNow;をやめる。ただし、これだと1回目が困りそうなので、状態の数を増やすとか、1回目だけTimeStartを設定するとか"です。 15.5秒たった後、どういう契機でTimeStartを初期化する必要があるのかがわかりませんが、例えば、以下のような方法が考えられます。 - 「タイムアウトしたけど、ボタンは押されたまま」という状態を作る。ここではTimeStartは更新しない。 - TimerStartを初期化済みか、初期化未かを表す、変数を定義する。初期化未のときだけ、TimerStartにTimeNowを代入する。(結局は状態を増やしているんですが)
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問