第25回 変数の利用

今回の記事では、時間を計測するスケッチを作成します。

目次

説明内容

前回の記事では、C++言語に「変数」という仕組みが用意されていることを説明しました。変数はメモ用紙のようなものですが、ちょっと変わった感じのメモ用紙でしたよね。

その変数の特徴を理解した上で、変数を用意するスケッチの書き方を習得しました。

今回の記事では、最初に用意した変数をスケッチでどのように利用するのか解説します

変数の利用方法がわかったら、いよいよ変数を利用して時間を計測するスケッチを作成していきます

変数の利用方法

変数はメモ用紙のようなものですので、まずは数字を書く方法を知らないと始まりませんよね。

そこで、変数に数字を書いたり、変更したりする方法を確認していきましょう。

代入演算子

メモ用紙、つまり変数に数字を書くには、C++言語では「 = 」記号を使用して以下のように書きます。

このように、「 = 」記号の左側には変数の名前を書いて、右側には書き込む数字を書きます。

メモ用紙に数字を書く、つまり変数に数字を書くことを「変数に代入する」と呼んでいます

「 = 」記号は普通「左側と右側が等しい」という意味ですが、C++言語の「 = 」記号は「右側の値を左側に代入する」という意味であることに十分注意してください。

基本的な代入の例

それでは具体例でスケッチの書き方を確認していきましょう。

例えば、以下のように変数を宣言したとします。

uint8_t count;

変数型がuint8_tで、変数名が「count」という変数の宣言です。つまり、0〜255の数字を書ける「count」というタイトルのメモ用紙を用意しています。

このメモ用紙に0を書きたい場合、つまり「countという変数に0を代入」したい場合は以下のように書きます。

count = 0;

ここで注意していただきたいことがあります。

count = 0;は、必ずuint8_t count;のあとに書く必要があるという点です。

同じスケッチ内だとしてもuint8_t count;より前にcount = 0;と書くと、countというメモ用紙が用意されていないのにそのメモ用紙を使おうとしているので、Arduino IDEに怒られます。

Arduino IDEは、指示を上から順番に見ていきます。「スケッチを先読みする」ということはしませんので注意です。

いろいろな代入の例

基本的な変数の利用方法がわかったところで、他の利用方法も確認します。

代入する値の部分は計算式でも構いません。

count = 12 + 34;

上のスケッチでは、「 = 」右側の「値」の部分は、そのままcountに代入できる値になっていません。そこで、Arduino IDEは最初に右側の「12 + 34」を計算して「46」にします。これで代入できる値になったので、変数countに46を代入します。

ここで、Arduino IDEの「 = 」記号の処理で重要なポイントがあります。

Arduino IDEは、「 = 」を処理するとき、右側の内容を代入できる数値の状態にしてから、左側の変数に代入する。

ここからだんだん複雑になってきますので、上のポイントを押さえた上でArduino IDEの気持ちになって(?)スケッチをじっくり読み解いてみてください。

今まで説明では、「 = 」記号の右側は数字でしたが、変数でも問題ありません。

ここで、名前が「a」と「b」の2つの変数を宣言したとします。

uint8_t a;
uint8_t b;

最初に変数aに123を代入します。

a = 123;

結果として、変数aに「123」という数値が代入されます。

このとき、次のように書くとどうなるでしょうか?

b = a;

変数bに代入する「値」の部分は変数aになっています。

変数bに変数a自体を代入するということはできません。メモ用紙で例えると、『 「タイトルbのメモ用紙」に「タイトルaのメモ用紙」を書く』ということになり、意味がわかりませんよね。

このとき、Arduino IDEは「 = 」の右側を変数aの内容、つまり「123」という数値にしてから代入します。結果として変数bは123になります。メモ用紙の例えでは、『 「タイトルbのメモ用紙」に「タイトルaのメモ用紙の内容」を書く』

補足

変数宣言のとき、同じ変数型の場合は次のように , で区切ってまとめて宣言することもできます。

uint8_t a, b;  // uint8_t型の「a」と「b」という変数が用意される

また、変数を宣言するとき、同時に値を代入することもできます。これを変数の初期化と呼ぶこともあります。

uint8_t count = 0;  // uint8_t型の「count」を用意するとともに0を代入する

それでは、次の命令を実行すると、cdには何が代入されるか一緒に考えてみましょう!

uint8_t c, d;

c = 5;
d = c + 10;

変数cには当然ながら5が代入されます。

次のd = c + 5;では、「 = 」の右側は代入できる状態になっていません。

そこで、右側を数値の状態にするのですが、右側には変数cがあります。変数cには5が代入されていますので、cを5に置き換えてd = 5 + 10;の状態にします。

あとは先ほどと同じように5 + 10の結果15を変数dに代入する、という処理になります。


慣れてきましたか?

ではこのセクションの最後に、次のスケッチを実行するとどうなるか考えてみましょう。

uint8_t g;

g = 3;
g = g + 5;

最初のg=3;では、変数gに「3」が代入されます。これは問題ないですよね。

次のg = g + 5;はどうなるのでしょうか?

「 = 」の両側に同じ変数gがあるのでちょっと混乱してしまいそうですが、今までの「最初に右側を代入できる数値にしてから、その値を左側の変数に代入する」という考え方でOKです。

メモ用紙を使って順番に考えてみましょう。

最初のg = 3;では「g」というタイトルのメモ用紙に「3」という数字が書かれます。

g = 3;

次のg = g + 5;では右側が代入できる数値になっていません。

そこで、右側のg + 5を数値にします。メモ用紙に書かれている数字は「3」ですので、「3 + 5」で「8」になります。

g + 5の計算

これで代入できる数値になりましたので、「8」をメモ用紙に書きます。

g = g + 5;

これまでの内容をまとめると、g = g + 5;という処理は、現在のgの値に5を足す、ということになります。

実際のスケッチでは、変数の値に数字を足したり引いたりする処理は多く出てきますので、この書き方に慣れましょう!

参考

C++言語をはじめ多くのプログラミング言語では、変数に代入する記号として「 = 」が採用されています。

でも、中には「右側の値を左側の変数に代入する」ということを表現するために、「 <- 」という記号を採用している「R」というプログラミング言語もあります。

R言語では、例えば変数countに0を代入したい場合、次のように書きます。

count <- 0

このように書くと「<-」の部分が矢印に見えるので、いかにも「0」を「count」に入れる、というイメージになりますよね。(R言語では最後の「 ; 」も必要ありません)

R言語は、プログラマ向けというより、統計学を利用していろいろな分析を行う経済学者などをユーザとして想定している言語のようです。あまりプログラムに馴染みのない人の場合、代入が「 = 」というのは混乱するので「 <- 」が採用されたのかもしれませんね。

C++言語で採用している「 = 」は代入というイメージは湧きづらいですが、「 <- 」のようなイメージでスケッチを読むようにすると良いと思います。(C++言語も代入演算子は「<-」だったらよかったのに…)

一定回数処理をするスケッチ

電子工作のプログラミングでは、決まった回数、何かの処理をすることがよくあります。

ジオラマ模型で何かの電飾をLEDで作った場合は「LEDを〇〇回点滅する」、ロボットの場合は「〇〇歩あるく」など、決まった回数の処理をする、ということが多くあります。

このような処理は、今まで習得した知識を組み合わせると実現できるんです。

とはいっても、ゼロから知識を組み合わせて考えてみましょうというと、その過程で迷子になってしまいます。

そこでこのセクションでは、最初に一定回数処理をする典型的なスケッチ示して、そのスケッチでなぜ一定回数処理ができるのか、という順番で説明することにします。

一定回数処理をするスケッチ

次のスケッチはwhileの中に書かれている「指示」を3回実行するスケッチです。

このスケッチは「指示」を3回繰り返して動作を停止します。

初めて見ると何をしているのかよくわからないと思います。

そこで、Arduinoボードがこのスケッチをどのように処理していくのか、ひとつひとつ順を追って確認しましょう。

スケッチ処理の流れ

これから、loopの中に書かれている処理の流れを追っていきます。

回数を数えるための変数を用意する

最初に、回数を数えるための変数を用意します。

loopの最初に、uint8_t型で、変数名が「count」という変数を宣言しています。同時に0を代入して初期化しておきます。

このように変数countを宣言すると、Arduinoボードは上のイラストの右下のように「0」が書かれた変数(メモ用紙)を用意してくれます。

whileの1回目

いよいよwhileの処理に入ります。

whileの条件部分の判定はcount < 3、つまり変数countの値が3未満、という判定になります。

変数countの値を確認すると「0」ですので、count < 3は成立します。

これにより、whileの「 { 」と「 } 」で囲間れた部分の処理が実行されます。

「 { 」と「 } 」の部分では最初に指示;が実行されます。指示の実行は1回目になります

続いて、変数countの値が1プラスされて1になります。

これでwhileの処理が終わりました。

この処理でのポイントは、1回目の「指示」を処理して、変数countの値が1になっている点です。つまり、変数countは処理した回数を意味していることになります。

whileの2回目

再度whileの条件の判定に戻ります。

whileの条件部分の判定はcount < 3、つまり変数countの値が3未満、という判定になります。

変数countの値を確認すると「1」ですので、count < 3は成立します。

これにより、whileの「 { 」と「 } 」で囲間れた部分の処理が実行されます。

「 { 」と「 } 」の部分で指示;が実行されます。指示の実行は2回目になります。また、変数countの値が1プラスされて2になります。

これでwhileの処理は終わりです。

ここまでで2回「指示」を実行しました。変数countの値も2になっています。

whileの3回目

再度whileの条件の判定に戻ります。(なんだか似たように処理が続きますね…。飽きてしまっているかもしれませんが、もうしばらくお付き合いくださいませ)

whileの条件部分の判定はcount < 3、つまり変数countの値が3未満、という判定になります。

変数countの値を確認すると「2」ですので、count < 3は成立します。

これにより、whileの「 { 」と「 } 」で囲間れた部分の処理が実行されます。

「 { 」と「 } 」の部分で指示;が実行されます。指示の実行は3回目になります。また、変数countの値が1プラスされて3になります。

これでwhileの処理は終わりです。

ここまでで、「指示」は3回実行されて、変数countも3になっています

「指示」を3回実行するのが目的ですので、これで終わるはずですね。

whileの4回目?

先ほど、whileの「 { 」と「 } 」の部分を処理しましたので、再度whileの条件判定に戻ります。

3回処理するはずなのに、whileは4回目になってしまいました。大丈夫なのでしょうか?4回「指示」を実行してしまわないのでしょうか?

ここで、条件判定される状況を確認してみましょう。

whileの判定条件はcount <3で「3未満」、つまり3は含みませんので、今回の判定結果は「条件不成立」となります。

つまり、ここでwhileの「 { 」と「 } 」の部分を処理せず、その次の指示に進みます

結果として、このようにwhileを使うと「指示」を3回処理することができます。

このノリで?、これからLEDの点滅回数を数えていこう、というわけです。

処理を止める

先ほどの処理が終わると、次の部分を処理します。

最後は何もしないをずっと繰り返すスケッチにしていますので、Arduinoボードはこの処理をずっと続けます。外から見るとArduinoボードは処理を停止しているように見えます。


処理を一つ一つ追ってきましたが、処理が一通り終わると結果として「指示」は3回繰り返されていますよね。

このように一定回数繰り返すには変数とwhileを使用すれば実現できるんです。

今回は、電子工作などでよく使われる「一定回数処理を繰り返す」というスケッチを作成しました。このスケッチはwhileや変数、演算子といったそれぞれの機能を組み合わせて意味のある処理を実現していますよね。

プログラミングはこのように一つ一つの機能のパーツを組み合わせて処理を実現していきます。処理を実現するために、どの機能をどのように組み合わせれば良いかは難しいところもありますが、面白いところでもあります。

今後もいろいろな機能や組み合わせが出てきますので、だんだん慣れていってみてください。

プログラミングパターン

プログラミングは、実現したい処理を、変数やwhile、digitalWriteなどの機能をうまく組み合わせていきますが、ちょっと難しそうですよね。

でも実現したい処理はパターンがあります。

例えば今回のような「指示を◯回繰り返す」という処理は多くの場面で出てきます。

そこで、よく出てくる処理のパターンをテンプレとして覚えてしまうのが良いと思います。(覚えなくともメモしておけば十分です!)

例えば「指示を◯回繰り返す」という処理は次のスケッチをテンプレにする、という感じです。

uint8_t count;

count = 0;
while( count < ◯ ) {
  指示;
  count++
}

このようにある決まった処理をするプログラムを「プログラミングパターン」や「プログラムスニペット」(スニペット=断片)とも呼ばれています。

いろいろなプログラミングパターン、つまりすぐにコピペできるテンプレ集を作っておくと、スケッチが早く作成できるようになります。

複合代入演算子・インクリメント演算子・デクリメント演算子

今まで説明したように、プログラミングでは変数に何かを足す、または変数から何かを引く、という処理が多く出てきます。

一定回数処理をする場合、countという変数を用意してcountに1を足して回数を数えました。

変数countに1を足す場合、代入演算子を使うと次のような書き方になります。

count = count + 1;

この処理はcountという変数を2回書く必要があるので、入力に手間がかかります。

そこで、スケッチを書く手間を少なくするべく、いつくかの代替の書き方が用意されています。いずれの書き方も頻出の書き方ですので慣れてみてください。

書き方は覚えた方が良いですが、用語は覚えなくて大丈夫です!

複合代入演算子

C++言語では変数に何か足したり引いたりする場合のために「複合代入演算子」というものが用意されています。(用語は覚えなくて大丈夫!書き方は頻出ですので覚えましょう!)

count = count + 1;と書く代わりにcount += 1;と書けるわけです。入力文字数も減りますし、スケッチもちょっとだけ短くなりますので、変数に何か数字を足したりする場合はこれらの演算子を意識的に使った方がいいですね。

インクリメント演算子・デクリメント演算子

一定回数処理をするスケッチでは、変数count1を足しましたよね。

このように「1を足す」という場面はとても多いので、「1を足す演算子」が特別に用意されています

「インクリメント演算子」と呼ばれています。「インクリメント」は日本語で「増やす」という意味です。

また、「1を引く」デクリメント演算子もあります。「デクリメント」は減らす、という意味です。

これらの演算子も頻出なので、ぜひ早めに慣れていただければと思います。


ところで、このシリーズで習得しているプログラミング言語は「C++言語」なのですが、「C++言語」の意味はなんとなく想像つくのではないでしょうか。

「C++言語」は「C言語」を元に色々な拡張をした言語です。「C言語」を一歩進めた、ということで「C++」というように言語名にインクリメント演算子が使われています。

一定回数LEDを点滅するスケッチ

これで一定回数LEDを点滅するスケッチを作る知識がそろいました。

今までの知識をまとめて、スイッチを押すとLEDが3回点滅するスケッチを作成してみました。

一つ一つの解説はしませんので、今まで習得した知識をフル活用して、このスケッチが3回点滅する処理になっているか、処理を追ってみてください。

LEDは1秒に1回点滅していますので、このスケッチでは3秒の計測できるようになっています。キッチンタイマーに少し近づいてきましたね。

/*
  キッチンタイマー
  
  内容: スイッチ、LED、スピーカーを使ったキッチンタイマー
  変更履歴:
    2024.11.25: 新規作成
    2024.12.01: スイッチが押されたらLED点滅開始
    2024.12.02: スイッチ関連の#define追加
    2024.12.05: 点滅回数カウント追加
*/

// 秒を表現するLED関連の定義
#define BYOU_LED 12  // 秒を表現するLEDの接続端子
#define BYOU_ON  50 // 秒を表現するLEDを点灯している時間(単位:ミリ秒)
#define BYOU_OFF (1000 - BYOU_ON) // 秒を表現するLEDを消している時間(単位:ミリ秒)

// タイマースタートスイッチ関連の定義
#define SWITCH A5 // スイッチを接続している端子名
#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 = 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 ) {
  }

}

【補足】「count++」と「++count」の違い

この知識は補足になりますので、頭の片隅に置いておいていただければと思います。

というのは、他の人が書いたスケッチを見ていると、インクリメント演算子が変数の「後」ではなく「前」に書かれていることがあります。

count++;  // 後に書くケース
++count;  // 前に書くケース

今回の記事で、while文の処理の最後に count++ と書きました。このように単独で書く場合は「count++」「++count」どちらも結果は同じになります。


ところが、状況によってはこれらの意味が異なるケースが出てきます。

それは、他の変数に代入するケースなどです。

具体例として以下の2つの式を考えてみます。

uint8_t count;     // インクリメントする変数
uint8_t mae, ato;  // 結果を代入する変数「前」「後」意味

// count++のケース
count = 1;
ato   = count++;

// ++countのケース
count = 1;
mae   = ++count;

ちょっとわかりづらいですが、最初にこれらの違いをまとめます。

書き方意味
ato = count++;最初に「countの値をatoに代入」してから「countの値を+1」する
mae = ++count;最初に「countの値を+1」してから
「countの値をmae」に入れる

かなりややこしいですよね。

「++」が変数名の「後」に書かれている場合は、「++」の計算は代入の「後」に行う、というイメージです。

変数の「前」に書かれている場合は、計算は代入の「前」に行うというイメージです。

私は勘違いしやすいタイプなので、自分でスケッチを作成する場合は、なるべく勘違いしないように書いています。

例えばcountを代入の後でインクリメントしたい場合は以下のように書くことがあります。

uint8_t count, ato;

count = 1;

// 後にインクリメント
ato = count;
count++;

先にインクリメントしたい場合は以下のように書いています。

uint8_t count, mae;

count = 1;

// 前にインクリメント
count++;
ato = count;

このように書くと、変数代入の前にインクリメントするのか、後にするのか明確になると思います。

でもato = count++;などのような表記も多くみられますので、インクリメント/デクリメント演算子の位置も注意していただければと思います。

ミニチャレンジ課題

今回の記事で一定回数処理をすることができましたので、ぜひ次の課題にチャレンジしてみてくだい。

ミニチャレンジ課題1

今回の記事で作成したスケッチは、LEDを3回点滅して停止しました。つまり3秒計測できたわけです。そこで、せっかくですのでタイマーっぽいものを作ってみたいと思います。次のような動作をするようなスケッチを作成してください。

  • スイッチを押すとカウントを開始する
  • カウント開始後は、1秒間に1回ピカッと点滅してタイマーカウントしていることを表現する
  • タイマーで10秒計測する
  • 10秒経過したらLEDを点灯したままにする

設定時間がきたらLEDを点灯したままにして時間が来たことを表現してみたいと思います。(音で知らせてくれるわけではなく、LEDの点滅を見る必要があるのでキッチンタイマーとは呼べないですが…)

ミニチャレンジ課題2

次はスケッチの動作を理解するために、スケッチの動作を追ってみます。変数が2個出てきて、動作がちょっと複雑ですのでじっくり考えてみてください。

次のスケッチはをArduinoボードに送ると、シリアルモニタに処理した結果を表示してくれます。その結果がどのようになるか考えてみてください。

ポイントは、while構文が何回繰り返されるのか明確にして、その間に2つの変数がどのようになるのか考えてみるようにしてみてください。また、考えるときも頭の中だけで考えると混乱してきますので、ノートに変数の値がどのように変化していくか考えると良いと思います。

/*
   Arduinoプログラミング入門 第25回
    ミニチャレンジ課題2
*/

void setup() {
  // シリアルモニタ設定
  // while処理の部分はまだ説明していません。
  // 第47回の記事にこのスケッチの意味を解説していますので、
  // 気になるようでしたらご確認いただければと思います。
  Serial.begin(9600);
  while(!Serial){
  }

  // 変数の宣言
  uint16_t count = 0;  // カウント用の変数
  uint16_t goukei = 0; // 計算用の変数

  // whileで変数操作
  while( count < 5 ){
    count++;
    goukei += count;
  }

  // 結果をシリアルモニタに表示
  Serial.print("変数goukeiの結果: ");
  Serial.println(goukei);

}

void loop() {
}

ミニチャレンジ課題解答例

ミニチャレンジ課題2については、実際にArduinoボードで試してみてください。

課題1については、次のように作成してみました。

/*
   Arduinoプログラミング入門 第25回
    ミニチャレンジ課題1
*/

// 秒を表現するLED関連の定義
#define BYOU_LED 12  // 秒を表現するLEDの接続端子
#define BYOU_ON  50 // 秒を表現するLEDを点灯している時間(単位:ミリ秒)
#define BYOU_OFF (1000 - BYOU_ON) // 秒を表現するLEDを消している時間(単位:ミリ秒)

// タイマースタートスイッチ関連の定義
#define SWITCH A5 // スイッチを接続している端子名
#define SWITCH_OFF 1 // スイッチOFFの時のdigitalReadの値
#define SWITCH_ON  0 // スイッチONの時のdigitalReadの値

// タイマー時間設定(LEDの点滅回数)
// 10秒タイマーにする
#define TIMER_JIKAN 10

void setup() {
  // 端子の設定
  pinMode(BYOU_LED, OUTPUT);     // 秒表現のLED接続端子の出力設定
  pinMode(SWITCH, INPUT_PULLUP); // スイッチ接続端子をプルアップ設定

  // スイッチが押されるまで何もしないで待つ
  while( digitalRead(SWITCH) == SWITCH_OFF ) {
  }
}

void loop() {
  // LEDの点滅回数を数えるための変数宣言と初期化
  uint8_t 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++;
  }

  // タイマー時間になったので、LEDを点灯状態にする
  digitalWrite(BYOU_LED, HIGH);

  // 何もしないで待つ
  while( true ) {
  }

}

更新履歴

日付内容
2019.9.8新規投稿
2021.8.24新サイトデザイン対応
2022.2.13ミニチャレンジ課題追加
2022.2.15インクリメント演算子説明追加
2024.12.5whileの条件判断を変更
ミニチャレンジ課題を変更
通知の設定
通知タイミング
guest
0 コメント
新しい準
古い順 一番投票が多い
本文中にフィードバック
全てのコメントを見る
目次