第16回 #defineの続きと算術演算子

今回は #define の続きと、算術演算子を習得します。

目次

#defineの追加

前回のスケッチではdelay(1000);の1000の部分を#defineで定義してスケッチを変更しやすくしました。

今回は残りのdelay(2000);の2000の部分を#defineで定義したいと思います。

前回のdelay(1000);の時と同様に、#define 単語 2000と書けばOKですよね。#defineで定義する場合、どのような単語で定義するか意外に悩みます。

今回定義するdelay(2000);は、delay(1000);の2倍の長さの時間です。

delay(1000);ではLED_JIKANという単語にしましたので、その2倍ということでLED_JIKAN_x2という単語にしようと思います。

「x2」は小文字のエックスと数字の2にしてみました。見た目、「かける2」って感じです。もっとわかりやすい書き方があればそれにしていただいても問題ありません。

定義する単語が決まりましたので、あとはスケッチに書くだけです。以下のようにしてみました。特に難しいところはないと思います。

あとは、#defineの部分をもう少し見やすくしておきます。

LED_JIKANLED_JIKAN_x2のあとの数字がそろっていないため、ちょっと見づらいので数字の先頭を合わせてみました。(このように、スペースを入れる場合は全角スペースにするとArduino IDEに怒られますので十分注意してください)

あとはLED_JIKAN_x2にコメントを書いて説明を追加しておきました。

算術演算子

#defineを使うことにより、delayの引数の変更作業が、最初に作ったスケッチより簡単になりましたよね。

以前のスケッチでdelayの引数を変更しようとするとdelay(1000);が4ヶ所、delay(2000);が2ヶ所の合計6ヶ所をいちいち変更する手間がかかりました。

#defineで定義することにより、時間を変更したい場合、#defineで定義した2ヶ所の数字を変更するだけの作業になりました。

それでは、さらにLEDの点滅パターンを以下のように変更してみたいと思います。

変更パターン

1秒を0.5秒、2秒を1秒に変更すればいいので、#defineを以下のように変更すれば大丈夫ですよね。

#define LED_JIKAN     500 // LEDの点滅時間(短い方の時間)
#define LED_JIKAN_x2 1000 // LEDの点滅時間(長い方の時間)

スケッチを変更できたらArduinoボードに送って動作を確認してみてください。

実際に動作させてるみたのですが、、、何だか点滅時間にキレがない感じなんですよね。

何度も何度も申し訳ございません。もうちょっと早めに点滅させてみたくなってしまいました。

そこで、ちょっと微妙な時間なんですが、短い方の時間を0.5秒ではなく、その4分の3の時間、0.375秒にしてどんな感じか様子を見てみたいんです。

LED時間変更

0.375秒は375ミリ秒です。ってことは、#define LED_JIKAN 500の 500 の部分を 375 に変更すればOKですよね。

では、「#define LED_JIKAN_x2 1000」の1000はいくつにすればいいかというと、、、

375を2倍すればいいのですが、375 x 2って、パッとすぐにわかる感じではないですよね。電卓で計算しても構いませんが、、、なんかおかしくないですか?

というのは、Arduinoは小さなコンピュータです。要するに「計算機」なんですが、なんで 375×2 という式を、計算機であるArduinoではなく、私たちの方で計算しなくてはいけないんでしょうか。計算機だったらそれぐらい計算してよ、って感じですよね。

ということで、375×2はArduinoに計算してもらいましょう。

スケッチでは以下の記号を使って四則演算をすることができます。

算数の授業では「足し算引き算掛け算割り算」とか「四則演算」などと呼んでいたと思います。

スケッチ(プログラミング)では、もう少し意識高い系の言葉を使うようで、これらは「算術演算子」と呼びます。

「算術」は算数という感じの意味でしょうか。「演算」は計算、「子」は記号の意味です。(「演算子」は英語では「Operator」で、「操作する人・もの」というような意味合いです)

「足し算引き算掛け算割り算」と呼ぶ代わりに、「算術演算子」と呼ぶ方がなんだか難しい話をしている雰囲気になりますので、これからは「算術演算子」と呼ぶようにしましょう。

なおプログラミングでは計算など、数字などの何かの操作をする記号を「演算子」と呼ぶことが多いですので、この点も頭の片隅においておいて下さい。

算術演算子について補足しておきます。

加算と減算はそれぞれプラス記号、マイナス記号なので違和感はないと思います。

乗算は「 * 」(アスタリクス記号)を使用します。アルファベット小文字のエックス「 x 」の方が掛け算の記号っぽいですが、エックスは文字ですので演算子には使えません。「 x 」以外に掛け算に近い記号ということで「 * 」が使用されているようです。

除算は普通に書くと「 ÷ 」ですが、この文字はアルファベットにありませんので「 / 」(スラッシュ記号)を使用します。割り算が「 / 」というのはわかりづらいかもしれませんが、小学校で習った分数を思い出してみてください。

このように、割り算は分数ですので、割り算記号は分数を表す横棒に近い「 / 」とイメージしていただければと思います。

ちょっと話はそれますがパーセント記号「%」ってありますよね。「%」記号の斜め線も割り算(=分数の横棒)の意味合いがあるのをご存知でしょうか。ちょっと???って感じですよね。

「パーセント」は日本語にそのまま訳すと「100あたり」という意味です。全体を100とした場合、いくつになるか、という意味です。75%という場合、全体を100とすると75、ということになります。

ただ、「数学で扱う割合」は0〜1の実数です。例えば50%といった場合、数学でいう割合は0.5です。

つまり、実際の割合の数字はパーセント表現の数字を100で割ると出てきます。75%であれば、実際には75 ÷ 100 = 0.75で、数学的な割合の数字は「0.75」になります。

75% = 0.75

このように「パーセント」は「 ÷100 」という意味なのですが、これを先ほどの演算子を使って表現すると「 /100 」になります。

これからこの「 /100 」をどんどん変形していきます。

次の図のように、最初に「 /100 」の最初の「 /1 」をまとめて1本の斜め線にします。これだとバランスが悪いので、「 / 」を「 00 」の間に移動します。さらにもうちょっとバランスを整えると「%」になります。

「パーセント」の「パー」は「〜あたり」、「セント」は「100」という意味です。「パーセント」は「100あたり」という意味になります。

他にも「1000あたり」という意味のパーミル「 ‰ 」という記号もあります。この記号がなぜこのような形なのか、パーセント記号の意味がわかれば想像つくかな、と思います。

話がそれてしまいましたが、スケッチを修正してLEDの点滅の時間間隔を変更してみましょう。

短い方の時間を375ミリ秒、長い方の時間はその2倍ですので375 * 2と書けばOKです。スケッチをそのように変更してみます。変更後、検証ボタンでスケッチに問題がないか確認してみてください。

#define LED_JIKAN    375     // LEDの点滅時間(短い方の時間)
#define LED_JIKAN_x2 375 * 2 // LEDの点滅時間(長い方の時間)

なお、「 375 」と「 * 」と「 2 」の間のスペースはあってもなくても構いません。Arduino IDEはスペースがあってもなくても「375かける2」と解釈できるためです。

さて、スケッチをこのように変更してみましたが、375ミリ秒を変更したい場合、まだ2ヶ所変更の必要がありますよね。

この2ヶ所の数字は同じです。せっかく#define LED_JIKAN 375LED_JIKANを定義したわけですから、この後に出てくる375はLED_JIKANが使えますよね。

このように考えると、スケッチは以下のようにに変更することができます。

これで全体のLEDの点滅時間を変更したい場合、基本となるLED_JIKANを1ヶ所変更するだけであとはArduino IDEが2倍の時間を計算して、delayの引数を裏で置き換えてくれます。

このようにスケッチの中で同じ値が多く出てくる場合は、#defineで定義すると、スケッチを変更するとき楽になります。また何ヶ所も変更する必要がないので、変更し忘れなどがなくなります。

さらに、#defineで定義した名前を意味がわかるようにしておけば、スケッチ中に数字だけ書いてあるより、スケッチが理解しやすくなります。

スケッチの規模が大きくなってくると、だんだん複雑になってきて、ちょっとした変更でも手間がかかるようになってきます。少しでも間違いがなく、手間を減らすように、このようにコメントや#defineを活用して、スケッチを変更しやすくするようにしてみて下さい。

このようにスケッチを見やすくしたり変更しやすくしたりすることを「スケッチ(プログラム)のメンテナンス性をよくする」と言われることがあります。普段使わないように言葉を使うと、知的な印象を相手に与えることができますので、ぜひ使ってみて下さい。

完成したスケッチは以下のようになります。スケッチ先頭のコメント内容の更新履歴の内容を追記しました。

/*
  動作内容: LEDの点滅時間をいろいろ変更してみる
  作成日:   2024.11.20
  変更履歴:
    2024.11.22: LEDの点滅時間を定義
*/

#define LED_JIKAN    375           // LEDの点滅時間(短い方の時間)
#define LED_JIKAN_x2 LED_JIKAN * 2 // LEDの点滅時間(長い方の時間)

void setup() {
  pinMode(12, OUTPUT);
}

void loop() {
  digitalWrite(12, HIGH);
  delay(LED_JIKAN);
  digitalWrite(12, LOW);
  delay(LED_JIKAN);
  digitalWrite(12, HIGH);
  delay(LED_JIKAN);
  digitalWrite(12, LOW);
  delay(LED_JIKAN);
  digitalWrite(12, HIGH);
  delay(LED_JIKAN_x2);
  digitalWrite(12, LOW);
  delay(LED_JIKAN_x2);
}

補足 〜 #define定義の注意点 〜

今回のスケッチでは何か問題が出るということはありませんでしたが、#defineを使用する場合には注意点があります。もし余力があればお読みいただければと思います。

#define定義の注意点

今回のスケッチでは、#defineを使って計算式を使って次のように定義しました。

#define  LED_JIKAN_x2  LED_JIKAN * 2

このケースでは問題ないのですが、実は定義する内容によっては問題が出てくることがあります。

例えば次のような例です。

#define  LED_JIKAN  300 + 75

この定義では、LEDの点灯時間を300という数字を基準として、数値を足して調整する、というようなイメージでしょうか。

スケッチの中では、このLED_JIKANを使って例えば次のように書いたとします。

delay( LED_JIKAN * 2 );

ここでは、LED_JIKANを2倍にする意図があります。

#defineの定義では、LED_JIKANは実際には375(300+75)ですので、このdelayではその2倍の750になることを期待しています。

それでは、実際のArduino IDEの処理の様子を見ていきましょう。

Arduino IDEはスケッチをArduinoボードに送るときに、裏で次のように「LED_JIKAN」を「300 + 75」に置き換えます。

delay( 300 + 75 * 2 );

このdelayの引数の計算式ですが、四則演算では掛け算が先、足し算が後に計算されますので、先に「75 x 2 = 150」、次に「300 + 150 = 450」になってしまいます。

本来でしたら750になるところが、LED_JIKANを置き換える部分に掛け算があるため、意図した結果にならない、ということになってしまいます。

このように#defineで定義する場合、意図しない問題が発生してしまうことがあります。

そこで、#defineで定義する場合、次のような対策をしておくと良いです。

#define定義の対策

#defineで定義する際、複数の項目に置き換える場合は基本的には「 ( ) 」で囲むようにします。言葉ではわかりづらいので、先ほどの例で確認します。

先ほど、「LED_JIKAN」を「300 + 75」で定義しましたが、これをカッコで囲み「 (300 + 75) 」というように定義します。

#define  LED_JIKAN  (300 + 75)

このように定義した場合、次のdelayの引数がどうなるか考えてみます。

delay( LED_JIKAN * 2 );

「LED_JIKAN」は「 (300 + 75) 」に置き換えられますので、Arduino IDEは裏で次のように置き換えます。

delay( (300 + 75) * 2 );

この式は最初にカッコ内を計算することになりますので、先に「 (300 + 75) = 375 」となり、この後「375 x 2 = 750」という正しい結果が得られます。

#defineで定義をする場合、複数の項目に定義する場合は「 ( ) 」で囲む方が安全になります。余分に囲む分には問題はありませんので、なるべく「 ( ) 」で囲む方がいいですね。

更新履歴

日付内容
2019.8.5新規投稿
2021.8.22新サイトデザイン対応
2022.2.3補足記事案内追加
2024.11.21Arduino IDE2のスクリーンショットに変更
第46回のコンテンツをこの記事に統合
通知の設定
通知タイミング
guest
2 コメント
新しい準
古い順 一番投票が多い
本文中にフィードバック
全てのコメントを見る
hada setuo
hada setuo
3 年 前

初めまして

全くの初心者で、Arduinoが昨日届いたので早速試しましたが、なかなか理解が出来ませんでしたが、あなた様のホームーページで、Arduinoでプログラミング入門〜基礎編パート1〜を実践しています。テキストエディタに打ち込みましたがなぜか何回見ても、コンパイルでエラーになります。

Arduinoのバージョン 1.8.12 です。

下が見て打ち込んだのですが。

/*
 * 動作確認: チャレンジ課題1
 *       8番ピンに接続したLEDを制御する
 * 作成日:2021.9.14
 * 変更履歴:
 * 
 */

#define LED_JIKAN   375      //LEDの点減時間間隔(単位はミリ秒)
#define LED_JIKAN_x2 LED_JIKAN * 2 //2倍のLEDの点減時間間隔(単位はミリ秒)

void setup() {
 pinMode(12, OUTPUT); //12番ピンを出力に設定
 }

void loop() {
 digitalWrite(12, HIGH);
 delay(LED_JIKAN);
 digitalWrite(12, LOW); //LEDをオフ
 delay(LED_JIKAN);
 digitalWrite(12, HIGH);
 delay(LED_JIKAN);
 digitalWrite(12, LOW);
 delay(LED_JIKAN);
 digitalWrite(12, HIGH)
 delay(LED_JIKAN_x2);
 digitalWrite(12, LOW);
 delay(LED_JIKAN_x2);
}

ここで delay(LED_JIKAN_x2);エラーメッセージが出ます。
宜しくお願いします。

目次