第15回 #define

今回はLEDの点滅パターンを変更してみます。

スケッチをコピーする

ずいぶんと長い道のりでしたが、LEDを1秒ごとにつけたり消したりするスケッチがやっと完成しました。今回はLEDの点滅(てんめつ)パターンを変えてみたいと思います。

前回までに作成したスケッチは記念すべき最初のスケッチですので、そのままの状態でとっておくことにします。

今回は、前回までに作成したスケッチに変更を加えて、LEDの点滅パターンを変更します。そこで、最初にスケッチをコピーして、そのコピーしたスケッチに変更を加えることにします。

それでは以下の手順で「LED_blink」の丸ごとコピーを作成しましょう。

最初に「LED_blink」を開きます。スケッチを開いたら「ファイル」→「名前を付けて保存」メニューを選択します。

名前を付けて保存メニュー

選択すると保存ダイアログが表示されますので、「LED_test」という名前で保存しておきます。これで「LED_blink」のスケッチ内容を丸々コピーした新しいスケッチ「LED_test」ができました。この「LED_test」の内容を変更して、LEDの点滅パターンを変更します。

なお、このスケッチのコピーのやり方はArduino IDEのメニューから行う方法ですが、他にフォルダとファイルをコピーするやり方もあります。Arduino IDEを起動しなくてもコピーできますが、注意点がありますので手順を説明しておきます。

以下は「LED_blink」をフォルダごとコピーして、コピーしたものを「LED_test」という名前に変更する方法です。

Windowsの場合はエクスプローラで「ドキュメント」フォルダを開きます。macOSの場合はFinderで「書類」フォルダを開きます。「Arduino」フォルダの中に前回までに作成した「LED_blink」がありますので、これをフォルダごとコピーします。

フォルダコピー

次にフォルダ名とファイル名を変更しますが、「フォルダ名」と「拡張子を除いたファイル名」を完全に同じ名前にする点に注意してください。変更する際、フォルダ名とファイル名が異なるとArduino IDEで開くときにフォルダ構成がおかしくなってしまいます。

「LED_blink」を「LED_test」に変更する場合、フォルダ名を「LED_test」に変更して、ファイル名を「LED_test.ino」に変更します。

フォルダ名とファイル名の変更

 

コメント文の変更

それでは「LED_test」を変更していきましょう。

前回のスケッチを丸々コピーしましたので、コメント文もそのままです。あとからみてわかるようにコメント文を自分がわかる内容に変更しておきましょう。

コメント文修正

これで準備できましたので、これからLEDの点滅パターンを変えていきます。

 

LEDの制御内容を変更する

LEDの点滅のパターンを「ピカ、ピカ、ピカーッ」の繰り返しに変更してみたいと思います。言葉ではよわからないので、図で説明すると以下のようになります。

LED点滅新パターン

LEDを「1秒つけて、1秒消して、1秒つけて、1秒消して、2秒つけて、2秒消して」というパターンを繰り返すようにスケッチを修正してみましょう。今まで習得したことで実現できますので、まずは自分の力でスケッチを変更してみてください。

できましたか? 以下のようなスケッチになります。

LED新点滅パターンスケッチ

スケッチの修正ができたら、実際にArduinoを動かしてLEDが思った通りに点滅するか確認してください。

うまく動きましたか?

「ピカーッ、ピカーッ、ピカーーッ」って感じでなんだかのんびりした光り方になってしまいました。イメージとしては、もっと早く点滅させたかったんですが…

ということで、全体の時間の長さを半分にしてみたいと思います。パターンとしては「「0.5秒つけて、0.5秒消して、0.5秒つけて、0.5秒消して、1秒つけて、1秒消して」という繰り返しになります。

すみません、こっちのパターンでした

delay命令のパラメータはミリ秒でしたよね。1秒=1000ミリ秒なので、1秒の半分の0.5秒は、1000ミリ秒の半分ですので500ミリ秒です。ということで、0.5秒待つ部分は「delay(500);」と書けばOKです。

先ほどのスケッチの「delay(1000);」を「delay(500);」に、「delay(2000);」を「delay(1000);」に変更すれば全体の点滅パターンの時間が半分になります。

それではスケッチを変更しましょう、、、と行きたいところですが、正直、変更するところが多くて面倒じゃないですか?

スケッチをもう一度見てみましょう。

同じ値の命令

このように、赤色4ヶ所のdelay命令は全て同じ値(1000)にしています。また、青色2ヶ所のdelay命令も同じ値(2000)になります。さらに「ピカ、ピカ、ピカーッ」と点滅させるために、青色2ヶ所のdelay命令は赤色4ヶ所のdelay命令の2倍の値にしています。

このようにスケッチの中に何度も出てくる同じ数字を一度に変更するいい方法はないのでしょうか。

すぐに思いつくのはアプリケーションによくある「検索・置換」機能ですよね。でも「検索・置換」機能はよくよく注意して使わないと大変なことになってしまいます。

先ほど作成したスケッチの中で、赤色部分の1000を500に、青色部分の2000を1000に変更したい場合を例に考えてみます。最初に「検索・置換」機能で2000を1000に変更してしまった場合、この時点で全てのdelay命令は1000になってしまいます。さらにこの状態で1000を500に置換すると全てのdelay命令のパラメータが500になってしまう、という問題が発生してしまいます。

Arduino IDEに「検索・置換」機能がありますが、この機能を使ってスケッチを変更するのは得策ではないですよね。

そこで、スケッチの中で同じ値が何度も出てくる場合に便利な方法がありますので、その方法を使ってスケッチを変更してみましょう。

 

文字の置き換え

突然ですが、通販を利用しているとメルマガが届きますよね。例えば、

「小林様にお得な情報をご案内します。多くのお客様に満足いただいているサービスをご利用になりませんか? 今回、小林様には特典がついております」

みたいな感じで、文章中にところどころ名前が出てきます。

このような文章は、名前の部分にいちいちキーボードで文字を入力しているわけではなく、個人別にメールを送るときにコンピュータで自動的に置き換えしています。例えば今の例の場合、最初に以下の文章を用意しておきます。

「A様にお得な情報をご案内します。多くのお客様に満足いただいているサービスをご利用になりませんか? 今回、A様には特典がついております」

この文章に対して、例えば小林さんあての文章を作成したい場合は「A」の部分を「小林」に置き換える、ということをしています。

このようにすれば、文章中に何度も同じ名前が出てきても、全ての場所を簡単に置き換えることができます。

C/C++言語では、これと同じように仕組みが用意されているんです。

 

#define

C/C++言語では「#define」(デファイン)という、文字を置き換えてもらう仕組みがあります。

#define

スケッチの中に、このように「#define A B」と書いておくと、Arduino IDEはこの「#define」を書いた行以降に出てくる「A」を「B」に置き換えて解釈してくれます。

なお「A」は1文字である必要はなく単語であればOKですが、必ず1単語である必要があります。また「B」については単語の羅列(られつ)でもOKです。実際の書き方の注意点はあとで詳しく説明します。

「define」は日本語で「定義する」という意味です。「#define A B」の意味合いとしては、「AをBと定義します」という感じでしょうか。実際にC/C++言語のプログラミング解説書では「#defineで定義します」などと書かれていることもあります。また人によっては「#defineを切る」などという言い方もします。なぜ「切る」なのかは謎です。

それでは実際に#defineを使って先ほどの通販メールのようにスケッチを変更してみましょう。

まず、先ほどのスケッチで赤色4ヶ所の部分は同じ値にしますので、以下のようにいったん「A」としておきます。

#defineの使い方

次に、「A」を「1000」と解釈してもらうように#defineで定義します。#defineを書く場所は「A」が出てくるより前の行であればOKですが、プログラムの最初の方に書く慣習があります。一般的にはスケッチ(プログラム)先頭のコメント文のあとが一般的です。

#defineの使い方

このように書いておくと、Arduino IDEは「delay(A);」は「delay(1000);」として解釈してくれます。このように書いておくと、スケッチの変更が簡単になりますよね。例えば1000を500にしたい場合は「#define A 500」に変更すれば、4ヶ所の「delay(A); 」は全て「delay(500);」と解釈してくれるわけです。先ほどのように4ヶ所の1000を500に変更しなくても1ヶ所の変更で済んでしまいます。

ところで、、、注意深い方はちょっと「あれっ?」って思ったかもしれません。

今までの命令はpinMode命令にしてもdigitalWrite命令にしても、命令の最後に必ず「;」がついていましたよね。でもこの#defineの最後には「;」がありません。この理由を今の時点の知識で正確に理解することは難しいですが(基礎編の後半で詳しく説明します)、気になってしまうと思いますので、イメージを説明しておきます。

Arduino IDEで作成したスケッチをArduinoボードに送る場合、スケッチをそのまま送るわけではなく、Arduinoボード用に変換して送っていることは説明しました。

このArduino IDEが行う変換作業ですが、スケッチをすぐに変換しているわけではありません。変換する前にスケッチのチェックをしています。このチェックではいろいろなことが行われていますが、#defineが書かれているかも確認しています。もし#defineが書かれている場合、スケッチの中で#defineで定義された部分を置き換えます。この置き換え作業は裏で行うので実際にスケッチ自体が書き換えられてしまうわけではありません。この#defineの置き換え作業や他のチェック作業が終わったら、ようやくスケッチをArduinoボードに変換しています。

コンパイラ指示

この一連の処理の流れで、「#define A B」と定義した部分は、Arduino IDEがスケッチをチェックするときにだけ使われていて、Arduinoボードに送っているわけではありません。つまり「#define」はArduinoボードを動作させる命令ではなく、Arduino IDEに対する情報というわけです。

Arduinoボードの命令は最後に「;」をつける決まりになっていますが、「#define」はArduinoボードに対する命令ではありませんので最後に「;」をつけていない、というわけです。

プログラミングに慣れてくると、うっかり#defineにも「;」をつけてしまうことがありますので注意してください。

また、スケッチをよく見ると「#define」の文字は緑色になっていますよね。Arduinoボードの命令はオレンジ色でしたが、「#define」はArduinoボードの命令ではないので緑色に色分けしています。

それでは「LED_test」を#defineを使って変更して、Arduino IDEの検証ボタンでスケッチに問題がないか確認してください。「コンパイルが完了しました」と表示されればOKです。

 

#defineの定義名のルール

先ほどのスケッチでは、delay命令のパラメータを「A」にしておき、#defineでAを1000に定義しました。

このあと、delay(2000);の命令も#defineで定義しようと思いますが、同じように例えば「delay(B);」として、「#define B 2000」などとするとあとあと問題が出てきます。

というのは、今後スケッチにいろいろな機能を追加していくと#defineが増えてきます。例えば


#define A 1000
#define B 2000
#define C 5000
#define D 100

このような感じになってきて、「A」や「B」は何に使っているのかわからなくなってきます。そこで、#defineで定義するときは、「A」や「B」の部分はわかりやすい単語にするルールになっています。ということで、一般的なルールを確認しておきましょう。

まず「#define A B」の「A」の部分はアルファベット大文字と数字の組み合わせにするのが一般的です。

今回定義した部分は、LEDをつけたり消したりする時間間隔です。そこで「A」ではなく「LEDをつけたり消したりする時間」ということで「LED JIKAN」という単語で#define定義したいと思います。とはいっても、

#define LED JIKAN 1000

と書いてはダメです。「#define A B」は「A」という1単語を「B」に置き換えます。

define詳細1

そのため「#define LED JIKAN 1000」と書くと、以下のように「LED」を「JIKAN 1000」に置き換えください、という意味になってしまいます。

define詳細2

ということで、「LED JIKAN」を1単語にするために以下のように書いてみましたが、、、

#define LEDJINKAN 1000

なんだかわかりづらいですよね。

#defineで定義する場合の置き換える部分は以下のように意味の区切り部分に「_」(アンダースコア)を入れる慣習になっています。アンダースコアは「-」(ハイフン/マイナス記号)ではありませんので注意してください。

#define LED_JIKAN 1000

「_」を入れることにより「LED_JIKAN」は1単語として認識されるようになります。

それでは、「A」と書いていた部分をもう少しわかりやすい「LED_JIKAN」に書き換えましよう。

#defineとdelay命令の「A」を「LED_JIKAN」に変更すればOKです。変更できたら検証ボタンでスケッチに問題がないか確認して、問題なければスケッチをArduinoボードに送って動作を確認しておきましょう。

#defineスケッチ

問題なく動作しましたか?

今回のスケッチはこれで完成ですが、#defineで定義した「LED_JIKAN」というのをもう少しわかりやすく、コメントで補足しておきましょう。以下のようにコメントで#defineを補足説明しておきました。

#defineコメント

 

#defineの補足

今回の記事では「1000」という値を「LED_JIKAN」という単語で定義しました。このように値を単語で定義する場合、#defineは最近あまり使われない傾向にあります。

最初から最近の書き方を説明したいところですが、以下の理由から#defineを基礎編の最初の方で説明することにしました。

ひとつの理由は、最近の書き方は、この先習得する多くの知識が必要になり、今の知識では#defineの方が使いやすいためです。

もうひとつの理由は、スケッチ内容によっては#defineでしか書けないところもあるためです。

ネットでArduinoのサンプルスケッチを見ると、#defineが多く出てきますので、まずは#defineを自分のものにしてください。

 

 

更新履歴

日付 内容
2019.8.3 新規投稿