電子工作入門プログラミング入門-基礎1今回の記事では、Arduinoボードが変数をどのように処理しているのか習得して、変数の扱い方の理解を深めます。前回の記事で変数の性質についていろいろ習得しました。最後に説明した「グローバル変数」と「ローカル変数」は重要な考え方なのでしっかり理解しておくようにしてください。」内にもなく、宣言した行以降どこでも使用できます。ところで、キッチンタイマーの時間計測に使用する「count」という名前の変数は、ローカル変数で宣言してもグローバル変数で宣言しても問題なく動作します。上の2つのスケッチは、変数「count」をグローバル変数、ローカル変数両方のパターンで宣言したものですが、どちらも問題なく動作します。前回の記事の最後で出てきた疑問は、グローバル変数とローカル変数はどのように使い分ければいいのか、というものでした。今回の記事では、Arduinoボード本体が内部でどのように変数を扱っているのか調べて、変数の使い方の理解を深めます。メモリ以下のように変数を宣言すると、Arduinoボード本体の内部では「count」という名前を変数が用意されます。「count」というタイトルのメモ帳が準備されるイメージでしたよね。今まで、「変数が用意される」とか「メモ帳が用意される」という表現で説明してきました。これから、Arduinoボード本体の内部では具体的にどのような処理がされているのか確認していきます。Arduinoボード本体の中には、いろいろなデータを記憶しておく場所があります。Microの場合、以下の部分に入っています。この記憶する場所は「メモリ」と呼ばれています。「メモリ」は日本語で「記憶」という意味ですが、普段から「メモリカード」など「メモリ」という言葉は出てきますのですでに使い慣れてるかもしれませんね。このメモリは大きく分けて2種類あります。ひとつはスケッチを記憶しておくメモリ、もうひとつは変数を記憶しておくメモリです。これら2種類のメモリについてもう少し知っておきましょう。今までの記事で何度もスケッチをArduinoボード本体に送って動作確認しました。IDEで作成したスケッチをArduinoボード本体に送ると、先ほどのスケッチを記憶するメモリに保存されます。Microの電源をOFFにしても内容が保存されています。このように電源を切っても内容が保存されるメモリを「フラッシュメモリ」と呼びます。ひとつの変数を記憶するメモリは、スケッチで変数を宣言するとこのメモリに変数が用意されます。count;」とスケッチに書くとArduinoボードが「count」という名前のメモ帳を用意してくれる、という説明をしました。具体的には、この変数を記憶するメモリに変数が用意されます。このメモリは電源をOFFにすると内容は消えてしまいます。このようなメモリを「RAM」や「SRAM」、または単に「メモリ」と呼んでいます。Arduinoボード本体の中には、このように2種類のメモリがありますが、このメモリには大きさがあります。最初に大きさの単位を確認しましょう。メモリの大きさは「バイト」という単位で数えます。PCを購入する場合にもメモリ容量やSSD容量など出てきますのですでにご存知の方も多いですよね。Microの場合、フラッシュメモリは32,768バイト、RAMは2560バイトあります。スケッチで変数を宣言すると、RAMに変数が用意されることはわかりました。ところで、変数の型によってその変数に代入できる数字の範囲が異なっていましたよね。実は、変数の型によってRAMを使用するバイト数が異なるんです。そこで、それぞれの変数型でRAMを何バイト使用するのか確認します。以下は変数型によって必要なRAMのバイト数です。変数の型によって代入できる数字の範囲が異なっていましたが、使用するRAMのバイト数が異なっている、ということがわかりました。RAMの使われ方を確認していきましょう。count;」と宣言してcountという変数を使用しました。実際にはArduinoボード内部では以下のようにcountという名前の変数がRAMの1バイトを使用して変数が用意されていたわけです。test;」と宣言すると、以下のようにRAMの2バイトを使用してuint16_t型の変数名「test」という変数が用意されます。難しくなってきましたが、まずはArduinoボード内部のメモリの構成、変数とRAMの関係をおさえておいてください。グローバル変数/ローカル変数とRAMの関係スケッチで変数を宣言すると、変数型に応じたバイト数でRAMに変数が用意されることはわかりました。ところで、変数にはグローバル変数とローカル変数がありましたよね。これら2種類の変数について、RAMに変数が用意されるタイミングについて確認していきます。「変数が用意されるタイミング」って言われても何だかピンときませんよね。変数宣言した時にRAMに変数が用意されるわけですから、「変数が用意されるタイミング」って言っても「変数宣言した時にRAMに用意されます」以上のことはなさそうです。そこで、キッチンタイマーのスケッチを例に、グローバル変数とローカル変数がRAMをどのように使用しているのか詳しく見ていきます。最初は以下のように変数「count」をグローバル変数で宣言した場合をみていきます。このように変数をグローバル変数として宣言すると、Arduinoボードの内部では、スケッチが動き始めた直後から、電源をOFFにするまでRAMに変数がずっと用意されたままになります。グローバル変数は、宣言した以降の行でいつでも使えるわけですから、いつ使われてもいいように電源が入っている間、ずっとRAMにあります。次に、以下のように変数「count」をローカル変数で宣言した場合をみていきます。このように変数countをローカル変数として宣言すると、スケッチが動き始めた直後はRAMに何も用意されていません。スケッチが動き始めると、Arduinoボードはsetupの部分の命令の処理を始めます。pinMode命令で端子の設定をして、その後スイッチが押されるまで待ちますが、この間もRAMには変数が用意されません。スイッチが押されると、setupのwhile構文の処理が終わり、loopの部分の繰り返し処理に入ります。count;」で変数の宣言がされますので、ここで初めてRAMにcountという変数が宣言されます。ここまでの説明では、結局、変数が宣言されたタイミングでRAMに変数が用意される、というだけですよね。ローカル変数はさらに重要なことがあります。この重要な点を理解するためにキッチンタイマーのスケッチに機能を追加します。現在のキッチンタイマーのスケッチは、スケッチが動き始めるとスイッチを確認し続け、スイッチが押されたらLEDの点滅を開始します。このような動作ですとスケッチが動き始めたかどうかわからないので、スケッチが動き始めたらLEDを3回点滅させるように機能を追加してみます。以下のようにスケッチに機能を追加してみました。このスケッチに出てくる変数を、Arduinoボードがどのように処理をしているか順を追って確認していきましょう。Arduinoボードがこのスケッチの処理を開始すると、最初にsetup部分を上から順番に処理をしていきます。setupの処理開始時はメモリには何も変数が用意されていません。最初に33行目と34行目のpinMode命令を実行します。この命名が終わると37行目で変数の宣言がありますので、Arduinoボードはこの時はじめてメモリ(RAM)に1バイトのcountという変数を用意します。次に39行目から44行目のLEDを3回点滅する処理を実行し、スイッチが押されるまで47行目と48行目を実行します。何もしないで待ちます。」でsetup部分が終わります。」の時に、先ほどメモリに用意した変数countは削除します。このように、ローカル変数は必要なくなるとArduinoボードはメモリから削除して、元のメモリの状態に戻します。このように必要なくなったメモリの変数を元の状態に戻すことを「メモリを解放する」と呼んでいます。引き続きこの後の処理をみていきます。setup部分の処理が終わったため、Arduinoボードはloopの処理に入ります。loopの最初では53行目で変数の宣言がありますので、Arduinoボードはメモリにcountという名前の変数を1バイト用意します。この変数「count」は先ほどsetup部分で使用した変数と同じ名前ですが、先ほどのcountとは別物です。先ほどのsetup部分では、LEDを3回点滅処理をした後、変数countの値は3になっていますが、setupが終わるとメモリが解放されて変数countはなかったことになります。その後、loop部分で同じ名前の変数を宣言しても、また別物として用意されます。」のところでメモリが解放される、という性質があります。グローバル変数とローカル変数の特徴は以上になります。この特徴を理解した上で変数の使い分けを考えていきましょう。変数の使い方グローバル変数は、スケッチの動作開始と同時にメモリに用意されて、電源がOFFになるまでずっとメモリにあります。そのため、グローバル変数は特に理由がない限り使用しないようにします。グローバル変数が必要な場合は、例えばsetup部分で変数を使用した何かの処理をして、その結果をloop部分でも使用する、というようなケースです。このような場合はグローバル変数を使用しないと実現できません。具体的な例としては、例えばsetup部分でユーザがボタンを押した回数をカウントしておき、loopではその押した回数に応じた処理をする、というような場合です。このような場合はグローバル変数にする必要があります。キッチンタイマーの時間計測で使用した変数countはloop内で使用するだけですので、グローバル変数ではなく、ローカル変数を使用します。はいってもタイマー時間計測の変数はグローバル変数でも動作するので問題ないのでは、と思ってしまいますよね。そこで極端な例で説明します。setup部分とloop部分で多くの変数を利用した処理をする場合を考えてみます。具体的な例として、例えばsetup部分とloop部分の両方で、異なるアラーム音楽を鳴らすために多くのメロディー(音程)のデータが必要だとします。このデータは2,000バイトで、変数に音程のデータを代入してメモリに保存する場合を考えてみます。Microボード本体のRAMは2,560バイトです。Arduinoボードがスケッチの処理を始めると、最初にsetup部分の命令を実行します。setup部分では変数2,000バイト分のメモリが必要になりますので、2,560バイトのRAMのうち、2,000バイト使用します。」のところで2,000バイトのメモリを解放します。次にArduinoボードは、loop部分の処理を開始します。このloop部分でも変数2,000バイトのメモリが必要になりますので、先ほどと同様に2,560バイトのRAMのうち、2,000バイト使用します。」のところで2,000バイトのメモリを解放します。loopは何度も繰り返し実行しますので、また最初からメモリを使用して、解放して、ということを繰り返します。それでは、setupで使用するメモリとloopで使用する変数をグローバル変数としたらどうなるでしょうか。setup用の2,000バイトの変数とloop用の別の2,000バイトの変数をグローバル変数として宣言すると、グローバル変数として4,000バイトのメモリが必要になってしまいます。Microボード本体のRAMは2,560バイトですので、グローバル変数としてメロディーのデータを用意することはできなくなってしまいます。このように、理由がない限りローカル変数を使うようにします。IDEが教えてくれています。キッチンタイマーのスケッチを開いて、検証ボタンを押してみてください。待っていると、ウインドウの下の方の黒い部分に情報が表示されますよね。1行目の「最大28672バイトのフラッシュメモリのうち、スケッチが4328バイト(15%)を使っています」はフラッシュメモリ、つまりスケッチを保存しておくメモリをどのぐらい使っているか、という情報です。Microのフラッシュメモリは32,767バイトある、と説明しました。IDEのメッセージでは28,672バイトと言っています。4096バイト少ない値です。IDEはスケッチで書いたもの以外に、裏でいろいろな処理を追加していてそれが隠れているためです。IDE(Arduinoシステム)が裏で使用しているため、フラッシュメモリの値はカタログに書かれたものより4096バイト少なくなっています。このメッセージでは、キッチンタイマーのスケッチは4328バイトあることもわかります。使えるフラッシュメモリのうち15%しか使っていませんので、もっと長いスケッチが書けますね。2行目の「最大2560バイトのRAMのうち、グローバル変数が149バイト(5%)を使っていて、ローカル変数で2411バイト使うことができます」という部分は、RAMが2,560バイトあって、グローバル変数は149バイト使っていることがわかります。キッチンタイマーのスケッチではグローバル変数は使ってないのに、なぜか149バイトも使っていることになっています。IDE(Arduinoシステム)が149バイト分のグローバル変数を裏で使用しているためこのようになっています。ところで、ローカル変数は何バイト使うか書かれていませんが、これはなぜかわかりますか?ローカル変数は、実行している場所によって何バイト使うか変動するため、あらかじめ書くことができないためです。IDEの検証ボタンを押した時点ではローカル変数は何バイト必要、とは言えないためです。それでは、最後にsetupとloopで使用している変数countをグローバル変数で宣言した場合、先ほどのメッセージはどうなるか確認してみましょう。変数countはuint8_t型ですのでメモリは1バイト必要です。そのため先ほどの149バイトに1バイト追加した150バイトがグローバル変数で使用されることがわかります。