第15回 #define

タイトル画像

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

目次

スケッチをコピーする

ずいぶんと長い道のりでしたが、LEDを1秒ごとにつけたり消したりするスケッチがやっと完成しました。

1秒に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秒消して」というパターンを繰り返すようにスケッチを修正してみましょう。

今まで習得したことで実現できますので、できれば自分の力でスケッチを変更してみてください。

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

スケッチの修正ができたら、実際に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では、「ピカ、ピカ、ピカーッ」と点滅させるために、赤色のdelayの2倍の値にしています。

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

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

先ほど作成したスケッチの中で、赤色部分の1000を500に、青色部分の2000を1000に変更したい場合を例に考えてみます。

最初に「検索・置換」機能で2000を1000に変更してしまった場合、この時点で全てのdelay命令は1000になってしまいます。さらにこの状態で1000を500に置換すると全てのdelayのパラメータが500になってしまう、という問題が発生してしまいます。

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

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

文字の置き換え

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

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

という文章では、2ヶ所に同じ名前が出てきます。

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

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

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

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

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

#define

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

スケッチの中に、このように「#define A B」と書いておくと、Arduino IDEは、この「#define」を書いた行以降に出てくる「A」を「B」に置き換えて解釈してくれます(これより前のスケッチには効力がない点に注意してください)。

なお「A」は1文字である必要はなく単語であればOKですが、必ず1単語である必要があります。また「B」については複数の単語でもOKです。この説明ではピンとこないかもしれませんよね。実際の書き方の注意点はあとで詳しく説明します。

「define」は日本語で「定義する」という意味です。「#define A B」の意味合いとしては、「AをBと定義します」という感じでしょうか。

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

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

まず、先ほどのスケッチで「1000」と書いてあったアンダーライン4ヶ所の部分は同じ値にしますので、以下のようにいったん「A」としておきます。

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

このように書いておくと、Arduino IDEはdelay(A);delay(1000);として解釈してくれます。

例えばAの部分を500にしたい場合は#define A 500と書けば、4ヶ所のdelay(A); は全てdelay(500);と解釈してくれるわけです。先ほどのように4ヶ所の1000を手動で500に変更しなくても1ヶ所の変更で済んでしまいます。

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

今までの命令はpinModeにしてもdigitalWriteにしても、命令の最後に必ず「 ; 」(セミコロン)がついていましたよね。

でも#defineの最後には「 ; 」がありません

この理由を今の時点の知識で正確に理解することは難しいですが(基礎編の後半で詳しく説明します)、気になってしまうと思いますので、イメージを説明しておきます。

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

このArduino IDEが行う変換作業ですが、スケッチをすぐに変換しているわけではありません。変換する前にスケッチのチェックをしています。

このチェックではいろいろな処理が行われていますが、#defineが書かれているかも確認しています。

上の図の一番左側は、#define A 1000でAを定義してあるスケッチです。

Arduino IDEは、Arduinoボードに送る前に、#defineが書かれているかチェックします。書かれていれば、スケッチの中で#defineで定義された部分を定義されている内容に置き換えます。上の図で中央の状態です。この置き換え作業はArduino IDEが裏で行うので実際にスケッチ自体が書き換えられてしまうわけではありません。

この#defineの置き換え作業や他のチェック作業が終わったら、ようやくスケッチに書かれている命令をArduinoボード用に変換しています。

この一連の処理の流れで、#define A Bと定義した部分は、Arduino IDEがスケッチをチェックするときにだけ使われていて、#define A B自体をArduinoボードに送っているわけではありません。上の図では、Arduino Microに送る前の状態はすでに#defineがなくなっています。

つまり#define「Arduinoボード」を動作させる命令ではなく、「Arduino IDE」に対する単なる情報というわけです。

Arduinoボードに送る段階では、#define A Bという定義の情報はなくなっています。

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

プログラミングに慣れてくると、うっかり#defineにも「 ; 」をつけてしまうことがありますので注意してください。とはいっても私自身もいまだにうっかり「 ; 」をつけてArduino IDEに怒られる、ということがよくあります。怒られたら修正するって感じで気楽にいきましょう。

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

それでは「LED_test」を#defineを使って変更して、Arduino IDEの検証ボタンでスケッチに問題がないか確認してください。

#defineの定義名のルール

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

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

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

#define A 1000
#define B 2000
#define C 500

このような感じになってきて、「A」や「B」は何に使っているのかわからなくなってきます。そこで、#defineで定義するときは、「A」や「B」の部分はわかりやすい単語にする慣習になっています。

ということで、一般的な慣習を確認しておきましょう。

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

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

#define  LED JIKAN 1000

と書くとArduino IDEはこちらの意図通りに解釈してくれません。#define A Bは「A」という1つの単語を「B」に置き換えます。

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

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

#define LEDJINKAN 1000

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

そこで、C++言語では慣習として#defineで定義する部分は、次のように単語(意味)の区切り部分に「 _ 」(アンダースコア)を入れることが一般的になっています。(他の書き方をする人もいるので、ゆるい慣習という感じです)

#define LED_JIKAN 1000

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

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

#definedelayの「A」を「LED_JIKAN」に変更すればOKです。

なお、#defineで定義した内容をわかりやすくするために、スケッチには次のようにコメントで補足しておきました。

変更できたら検証ボタンでスケッチに問題がないか確認して、問題なければスケッチをArduinoボードに送って動作を確認しておきましょう。

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

更新履歴

日付内容
2019.8.3新規投稿
2021.8.22新サイトデザイン対応
2022.2.3#define説明追加
2024.11.20Arduino IDE2のスクリーンショットに変更
#defineの説明補足
通知の設定
通知タイミング
guest
0 コメント
新しい準
古い順 一番投票が多い
本文中にフィードバック
全てのコメントを見る
目次