時間を計測するスケッチを検討します。
メモ用紙の書き換え方法
前回の記事では、C/C++言語に変数が用意されていることを説明しました。変数はメモ用紙のようなもので、ちょっと変わった感じのメモ用紙でした。特徴は覚えていますか?
今回の記事では、この変数を活用して時間を計測するスケッチを作成していきますが、最初に変数の扱い方を習得します。メモ用紙、つまり変数に数字を書くには、C/C++言語では「=」記号を使用して以下のように書きます。
「=」記号の左側には変数の名前を書きます。「=」記号の右側には書き込む数字を書きます。
メモ用紙に数字を書く、つまり変数に数字を書くことを「変数に代入する」と呼んでいます。それではこの変数の代入について、詳しくみていきます。
例えば、以下のように変数を宣言したとします。
uint8_t count;
これはuint8_t型(0〜255)で、変数名が「count」という変数の宣言ですよね。ようするに、0〜255の数字を書ける「count」というタイトルのメモ用紙を用意しています。
このメモ用紙に0を書きたい場合、つまりcountという変数に0を代入したい場合は以下のように書きます。
count = 0;
代入する数字は計算式でも構いません。
count = 12 + 34;
「=」の使い方はちょっとわかってきましたか? ここからだんだん複雑になってきます。
先ほどの説明で、「=」記号の右側は数値、と説明しましたが、変数でも問題ありません。ここで、名前が「a」と「b」の2つの変数を宣言したとします。
uint8_t a;
uint8_t b;
最初に変数「a」に123を代入します。
a = 123;
この命令を実行すると、変数「a」に「123」という数値が代入されます。次に以下のように書くと、変数「a」の内容を、変数「b」に代入することもできます。
b = a;
この命令を実行すると、変数「b」に変数「a」の内容、つまり「123」という数値が代入されます。
それでは、以下の命令を実行するとcとdは何が代入されるか考えてみてください。
uint8_t c;
uint8_t d;
c = 10 + 20;
d = c;
最初にuint8_t型の変数「c」と「d」を宣言しています。次に、cには10+20、つまり30が代入されます。そのあと、cの内容をdに代入しますので、dにも30が代入されます。答えは「cは30、dも30」です。
それでは、次の命令を実行すると、eとfには何が代入されるか考えてみてください。
uint8_t e;
uint8_t f;
e = 5 + 5;
f = e + 5;
eには5+5、つまり10が代入されます。次の「f = e + 5;」では、変数fには変数eの内容に5を加えたものを代入しますので、fには10+5で15が代入されます。答えは「eは10、fは15」です。
ちょっと慣れてきましたか? では最後に以下の命令を実行するとどうなるか考えてみましょう。
uint8_t g;
g = 3;
g = g + 5;
最初の「g = 3;」では、変数「g」に「3」が代入されます。これは問題ないですよね。
さて、次の「g = g + 5;」はどうなるのでしょうか。「=」記号は、右側の内容を左側に代入する命令ですので、最初に「g + 5」が計算されて、その結果が「g」に代入されます。つまり、8が「g」に代入されます。
ちょっとわかりづらいですよね。メモ用紙で考えてみましょう。「g = 3;」では「g」というタイトルのメモ用紙に「3」という数字が書かれます。
次の「g = g + 5;」は「『=』記号の、(1)右側の内容を、(2)左側に代入する」という処理をします。最初の「(1)右側の内容」という処理は、メモ帳gに書かれている数字は「3」ですので、「3 + 5」で「8」になります。
次にその結果を「(2)左側に代入」しますので、gには「8」が代入されることになります。
結局、「g = g + 5;」という処理は、現在のgの値に5を足す、という動作になります。このように、変数の値に数字を足したり引いたりする処理は多く出てきますのでこの書き方に慣れてください。
ところで、数学で出てくる「=」記号は「『=』記号の左側と右側が等しい」という意味でした。C/C++言語ではその意味が変わって、「『=』記号の右側の内容を左側の変数に代入する」という意味になることに注意してください。C/C++言語の「=」記号は決して「左側と右側の内容が等しい」という意味ではありません。
ということで、「=」は正確には以下のような動作になります。
一定回数処理をするスケッチ
電子工作のプログラミングでは、決まった回数、何かの処理をすることがよくあります。ジオラマ模型を作った場合は「LEDを〇〇回点滅する」、ロボットの場合は「〇〇歩あるく」など、決まった回数の処理をする、ということが多くあります。
このような処理は、今まで習得した知識を活用すると実現できるんです。とはいっても、ゼロから考えてみましょう、というとかなり大変ですので、最初に一定回数処理をする典型的なスケッチを示して、そのスケッチでなぜ一定回数処理ができるのか、説明することにします。
以下のスケッチは「処理」を3回実行するスケッチです。uint8_t型の「count」という名前の変数と、while構文を使用して実現しています。
このスケッチは「処理」を3回繰り返して動作を停止します。初めて見ると何をしているのかよくわからないと思いますので、Arduinoボードがどのように処理を進めていくのか、ひとつひとつ順を追って確認しましょう。
最初に回数を数えるための変数を用意します。uint8_t型の変数名が「count」という変数です。変数名はなんでも構いませんが、数えるので「count」としました。変数countを宣言すると、Arduinoボードは適当な数字が書かれた変数を用意してくれます。
宣言したばかりの変数は適当な数字が書かれていますので、回数を数えるために1を代入します。
いよいよwhile構文の処理に入ります。whileの式の判定は「count <= 3」、つまり変数countの値が3以下、という条件になります。countの現在の値は1ですので、式が成立します。while構文の{と}で囲んだ処理が実行されます。
最初に「処理」が実行されます。この処理の実行は1回目になります。
次に変数countの値に1足します。結果として変数countの値は2になります。
{と}で囲んだ処理が終わりましたので、再度whileの式の判定に戻ります。現在の変数countの値は2、条件は「count <= 3」ですので、条件成立です。再度{と}の処理を実行します。
「処理」を実行します。この「処理」の実行は2回目です。
次に変数countに1を足します。変数countの値は3になります。
{と}で囲んだ処理が終わりましたので、再度whileの式の判定に戻ります。現在の変数countの値は3、条件は「count <= 3」ですので、条件成立です。再度{と}の処理を実行します。
「処理」を実行します。この「処理」の実行は3回目です。
次に変数countに1を足します。変数countの値は4になります。
{と}で囲んだ処理が終わりましたので、再度whileの式の判定に戻ります。現在の変数countの値は4、条件は「count <= 3」ですので、条件が成立しませんので、while構文は処理を終えて次の命令に進みます。
最後は何もしないをずっと繰り返すスケッチにしていますので、Arduinoボードはこの処理をずっと続けます。外から見ると何もしていないように見えます。
処理を一つ一つ追ってきましたが、処理が一通り終わると「処理」の部分は3回繰り返されていますよね。このように一定回数繰り返すには変数とwhile構文を使用すれば実現できるんです。
今回は、電子工作などでよく使われる「一定回数処理を繰り返す」というプログラミングをしましたが、今後自分で考えた動作をさせたい場合、このようにC/C++言語の命令を組み合わせて実現することになります。どのように組み合わせれば実現できるか、考える力を身につけていくようにしてください。
ところで、一定回数繰り返すスケッチのサンプルはできましたが、この書き方は一般的ではないんです。次に問題点と一般的な書き方を習得します。
プログラミングパターンとベストプラクティス
先ほどのスケッチでは一定回数処理をすることができましたが、ちょっとだけ問題があるんです。そのちょっとした問題を説明します。
変数を使って回数を数えましたが、uint8_t型の変数に代入できる数字の範囲は0〜255です。先ほどのスケッチでは最初に「count = 1;」として、数を1から数えていましたよね。
ちょっとした問題、というのは、uint8_t型の変数は0〜255を代入できるのに0を使っていない、ということなんです。0〜255まで使えば最大256回の回数を数えることができますが、先ほどのスケッチでは0を使っていないので、最大1〜255の255回になってしまいます。
日常生活で数を数える場合、1から始めますよね。プログラミングの世界では0から数えるのが一般的ですので是非0から数えることに慣れましょう。
ということで、一定回数を数えるスケッチの一般的な書き方は以下になります。
このスケッチでは、最初のcountの値は0にして、処理をするたびに1を足していきます。0から開始をしたので、whileの条件判定式は「3未満」としています。
このスケッチの一つ一つの動作は説明しませんが、ぜひ先ほどと同じようにきちんと「処理」が3回実行されるか、ご自分で確認してみてください。
ところで注意深い方は気づいたかもしれませんが、whileの条件式として「count <= 2」という書き方もありますよね。このように書いても3回実行されますが、この書き方は一般的ではありません。「count <= 2」と書くと、条件式は「2」という数字が使用されていまいます。「3」回処理をするのに「2」という数字が出てきて紛らわしいので、「count = 3」というように「<」記号と「3」という数字を使用して、「3」回ということを表現する慣習になっています。
このように「一定回数数える」などの典型的な処理をするスケッチ(プログラム)には決まった形があります。柔道などのスポーツなどでも形がありますよね。このように決まった形のプログラムのことを「プログラミングパターン」と呼んでいます。また、プログラミングパターンの中でも一番良い形を「ベストプラクティス」と呼ばれています。「ベスト」は日本語で「一番」、「プラクティス」は「慣習」という意味です。
今回の記事では、一定回数処理を行う方法としてwhile構文で書く方法(プログラミングパターン)を説明しましたが、実はこの形はベストプラクティスではありません。次回、一定回数処理を行うベストプラクティスを習得します。
代入演算子とインクリメント演算子
先ほど説明したように、プログラミングでは変数に何かを足す、または変数から何かを引く、という処理が多く出てきます。一定回数処理をする場合、countという変数を用意してcountに1を足して回数を数えました。
変数countに1を足す場合、以下のように書くことは説明しました。
count = count + 1;
この処理は「count」という変数を2回書く必要があるので、入力に手間がかかりますよね。そこで、C/C++言語ではこのように変数に何か足したり引いたりする場合のために「代入演算子」というものが用意されています。
「count = count + 1;」と書く代わりに「count += 1;」と書けるわけです。入力文字数も減りますし、スケッチもちょっとだけ短くなりますので、変数に何か数字を足したりする場合はこれらの記号を使いましょう。
また、ネットでサンプルスケッチを見ると、このような書き方が多用されていますので、ぜひこの書き方に慣れてください。
ところで、先ほどの数を数えるケースでは変数に1を足しましたよね。このように1を足すという場面はとても多いので、1を足す演算子も用意されています。「インクリメント演算子」と呼ばれています。「インクリメント」は日本語で「増やす」という意味です。
インクリメント演算子には1を引く「--」という記号があります。インクリメントは「増やす」ですが、逆に「減らす」は「デクリメント」という英語があるのですが、「++」と「--」を合わせてインクリメント演算子と呼んでいるようです。
ところで、このシリーズで習得しているプログラミング言語は「C/C++言語」なのですが、「C++言語」の意味はなんとなく想像つくのではないでしょうか。「C++言語」は「C言語」を元に色々な拡張をした言語です。「C言語」を一歩進めた、ということで「C++」というインクリメント演算子が使われています。
一定回数LEDを点滅するスケッチ
これで一定回数LEDを点滅するスケッチを作る知識がそろいました。以下はスイッチを押すとLEDが3回点滅するスケッチです。それでは、今まで習得した知識をフル活用して、このスケッチが3回点滅する処理になっているか、処理を追ってみてください。
LEDは1秒に1回つけていますので、LEDの点滅回数を数えると時間が計測できるようになります。キッチンタイマーに近づいてきましたね。
/* * キッチンタイマー * * 内容: スイッチ、LED、スピーカーを使ったキッチンタイマー * 変更履歴: * 2019. 8.11: 新規作成 * 2019. 8.15: スタートスイッチ処理を追加 * 2019. 8.17: スイッチ関連の#define追加 * 2019. 9. 8: 点滅回数カウント追加 */ // 秒を表現するLED関連(青色LED) #define BYOU_LED 12 // 秒を表現する青色LEDの端子番号 #define BYOU_ON 50 // 秒を表現するLEDをつけている時間 (単位:ミリ秒) #define BYOU_OFF 1000 - BYOU_ON // 秒を表現するLEDを消している時間 (単位:ミリ秒) // スタートスイッチ関連 #define SWITCH 23 // スイッチを接続している端子番号 #define SWITCH_OFF 1 // スイッチOFFの時のdigitalReadの値 #define SWITCH_ON 0 // スイッチONの時のdigitalReadの値 // タイマー時間設定(LEDの点滅回数) #define TIMER_JIKAN 3 void setup() { // 端子の設定 pinMode(BYOU_LED, OUTPUT); // 青色LED接続端子設定 pinMode(SWITCH, INPUT_PULLUP); // スイッチ接続端子の設定 // スイッチが押されるまで待つ while(digitalRead(SWITCH) == SWITCH_OFF) { } } void loop() { // LEDの点滅回数を数えるための変数宣言 uint8_t count; // countに0を代入 count = 0; // TIMER_JIKAN分の回数を数える while( count < TIMER_JIKAN ) { // 1秒に1回青色LEDを点滅する digitalWrite(BYOU_LED, HIGH); delay(BYOU_ON); digitalWrite(BYOU_LED, LOW); delay(BYOU_OFF); // countを1プラス count++; } // 何もしないで待つ while( true ) { } }
更新履歴
日付 | 内容 |
---|---|
2019.9.8 | 新規投稿 |