今回は #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_JIKAN
とLED_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秒にしてどんな感じか様子を見てみたいんです。
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 375
でLED_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.21 | Arduino IDE2のスクリーンショットに変更 第46回のコンテンツをこの記事に統合 |
初めまして
全くの初心者で、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);エラーメッセージが出ます。
宜しくお願いします。
このシリーズをお読みいただきどうもありがとうございます。
またご質問いただきどうもありがとうございます。
いただいたプログラムですが、エラーの意味がなかなかわからないケースになります。
最初に原因をご説明しますと、エラーが出る行の1行前に原因があります。
エラーが出る「delay(LED_JIKAN_x2);」の1行前に「digitalWrite(12, HIGH)」とありますが、この行の最後に「 ; 」が抜けてしまっています。「 digitalWrite(12, HIGH); 」というように最後に「 ; 」を付ければ動くと思います。
このエラーについて、2点補足させていただきます。
まず1点目ですが、このエラーは「digitalWrite(12, HIGH)」の行ではなく、次の行でエラーになっているのが疑問に思われたと思います。次の行でエラーが発生する理由は以下になります。
まず、Arduino Microは、「digitalWrite(12, HIGH)」の行をみて最後に「 ; 」が付いていないので、まだ命令が続くと判断して次の行を続けて読み始めます(改行はArduinoにとって意味がないもの、ということを思い出してみてください)。次の行を読み進めると、最後に「 ; 」がありますので、Arduinoは「 digitalWrite(12, HIGH)delay(LED_JIKAN_x2);」という1つの命令だ、と判断します。この時点でこのような命令はArduinoは知らないのでエラーにしてしまっています。(すみません、説明が悪く、わかりづらいようでしたら再度ご質問いただけると幸いです)
次に2点目ですが、「 ; 」忘れはプログラマになった証です!というのは、実は私もいまだに「 ; 」を忘れてエラーになることがあります。私の周りのプログラム歴が長い人もついうっかり忘れてエラーになったりしています。
ということで、このエラーは誰でも経験することと、意外にずっと付き合っていくエラーですので、今後不可解なエラーが出てきたら、前の行を確認してみる、ということもしてみてください。
こちらで確認したプログラムを添付いたします。
他に不明点ございましたらご質問いただければと思います。