google-site-verification: google3bd66dd162ef54c7.html

Arduino よもやま話 -3 (予約語の定義はどこ?)

1.まえがき
 Arduino よもやま話、今回は予約語の話です。但し、タイトルには予約語と書きましたが、正確には予約語では無く、Arduino が定義している変数や関数の名前の話です。C言語に限らずプログラム言語における予約語は厳密に定義されています。

 Arduinoでは何も宣言しなくても、CPUのレジスタ名を使った読み書きが出来ます。また、言語リファレンスには書かれていない関数が使えたりします(例えばacosなど)。これらはシステムがあらかじめ宣言(定義)しているようで、ユーザーは何もしないでも使えるので、予約語のように見えます。

 難しいことを考えなくてもプログラムが書けるようにするために、そういう作りになっているのだと思います。でも少し気持ち悪いし、予約語(のように見える単語)の範囲が明確では無い気がします。ということで、どういう仕組みになっているか調べてみます。

2.CPUのレジスタ名の一部
 仕組みを調べる前に、まずは予約語のように見えるCPUのレジスタ名を見てみます。どんなレジスタがあるかはATmega328Pのデーターシートに書いてありますが、下記はその一部です。(mega88日本語レファレンスより抜粋)
ATmega88のレジスタ一覧の一部
 レジスタ名とそのビット位置に全て名前が付いています。まあハードウェアの仕様書なので当然です。でも、驚いたことに、こんなに沢山あるのに Arduino からその名前を呼ぶだけでレジスタの操作(読み書き)が出来ます。下記はタイマーレジスタを読み出した例です。
// CPUのレジスタを読む例
void setup() {
Serial.begin(9600);
}
void loop() {
Serial.println(TCNT1L); // TCNT1Lのアドレスは0x85
delay(200);
}
 このプログラムはTCNT1Lの内容を0.2秒間隔でシリアルに出力します。変数であるTCNT1Lの宣言は何もやっていないのに問題無く動きます。つまりこの名前はどこかで定義されています。

3.仕組み
 どうしてこんなことが出来るのか、その理由はコンパイルの前処理でちょっとした細工が行われているためでした。そのあたりは、garretlabさんのArduinoで遊ぶのスケッチのコンパイルプロセスの「ソースコードの変換」の項で詳しく解説されていました。どうも Arduino.h をインクルードするのがポイントのようです。実際に Arduino.h の中身を見てみると、下記のようにいろいろなライブラリがインクルードされています。(下記は Arduino.h の一部を書きだしたものです)
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <math.h>

#include <avr/pgmspace.h>
#include <avr/io.h>
#include <avr/interrupt.h>
 ここでいろいろな設定が読み込まれるので、ユーザーは何もしなくても良かったわけです。試しにmath.hの中を見ると、確かにacosの定義が入っています。双曲線関数だって入ってました。CPUのレジスタについては、avr/io.hを経由して、最終的にはiom328p.hが読み込まれ、この中に上の表に書いてあるCPUのIOレジスタ名とアドレスの対応関係が書かれていました。

4.まとめ
 Arduino として動かすための設定は Arduino.h で定義されていました。まあネーミングから考えたら当たり前の話なのですが、これですっきりしました。

 Arduino のリファレンスのどこかに、「変数名には Arduino が使っている名前は使えません」 と書かれていたと思います。それって具体的に何なのよ、とずっと思っていたのですが、Arduino.h から読み出される一連の定義のことでした。

 CPUのレジスタ名として定義されている名前の数はものすごく多いので、たまたま同じ名前を使ってしまう可能性があり、その場合はコンパイルエラーになるはずです。ただ、CPUのレジスタ名は全部大文字が使われているので、キャメルケースなどの小文字がたくさん入る変数名を使うことで、名前が衝突する危険性は回避出来るはずです。ここは、Arduino よもやま話 -2 (変数名の命名方法)の中で少し触れた話です。

 ちなみに、CPUのレジスタ名は、プログラムよりずっと上位の存在なので、これを全部大文字で書くのはすごく納得出来る作法です。

Arduino よもやま話 -2 (変数の命名方法)

1.まえがき
 Arduino よもやま話の2回目、今回は変数名の話です。プログラムを書くためには、変数の名前を決める必要があります。役割が一目で判る良い変数名を付けることが出来れば、コーディングがはかどります。一方で、ちょっと違うなーという感じの名前だと、それが気になって、なかなかプログラムを書き進むことが出来なくなったりします。

 ということで、変数名はとても重要です。

2.変数名の決め方
 変数名の決め方については、Arduinoのコーディングルールと命名規則を調べてみたに書かれている内容が網羅的に情報をカバーされているのでとても参考になります。いろいろな流儀があるようですが、私はロワーキャメルケースを使っています。スネークケースの例も以下に示します。
例) ロワーキャメルケース: sunRiseTime ←私はこれ派
   スネークケース:sun_rise_time

 英単語を二つつ三つ使って、その関数の役割を簡潔に表現するのがポイントです。

 あと、1文字だけの短い変数名は使わないことが推奨されています。でも、1文字変数を使った方が判り易くな場合もあるので一概にダメでも無いと思います。例えば下記、これは日の出日の入り時刻を計算した時に作った関数です。
float eCalc(int n) {                           // 近似式で均時差を求める
float e, w;
w = (n + 0.5) * 2 * M_PI / 365; // 日付をラジアンに換算
e = + 0.0072 * cos(w) - 0.0528 * cos(2 * w) - 0.0012 * cos(3 * w)
- 0.1229 * sin(w) - 0.1565 * sin(2 * w) - 0.0041 * sin(3 * w);
return e; // 均一時差を返す(単位は時)
}
 数式通りに書けているので読み易いと思います。こんなふうに関数の中のローカル変数だったら、1文字変数でも許してもらえるはずです。

3.グローバル変数の書き方
 グローバル変数は、すぐわかるように先頭を大文字で書くという作法があるようです。つまり私の場合、変数名をアッパーキャメルケースで書くことになります。
 アッパーキャメルケース:SunRiseTime ←先頭が大文字になっています

 なるほどこれは良いかも、と思って一度やってみたことがあります。でも Arduino の場合はよろしくないと思いました。というのは、Arduinoではグローバル変数がとても多くなることが多いからです。もちろん関数内だけで閉じている変数はローカル変数を使いますが、その数は意外と少ないです。それに、引数を渡して、結果を戻り値で返すという手順を踏むより、グローバル変数を直接いじった方が手っ取り早いということもあります。(お行儀が悪いですが)

 ともかくそんなことで、プログラムはグローバル変数だらけになったわけですが、変数がアッパーキャメルケースで書いてあると、大文字が目立ってしまって、ソースが読み難くなってしまいました。

 あと、Arduino ではほとんどの場合、一人でプログラムを作るので、変数名の競合なんて心配する必要がありません。それにメモリも小さいので、サイズの大きなプログラムになることはありません。そんなことで、グローバル変数だらけになってしまっても、いいのではないか思います。

4.ハードウエアレジスタ名との衝突
 グローバル変数は全部大文字で書く(アッパーケースで書く)、という作法もあるようです。でもArduinoでは、ハードウエアのレジスタ名がアッパーケースであらかじめ大量に定義されているので、これと衝突する恐れがあります。そんなことで、アッパーケースの変数名は使わない方が良いと思います。それにソースが読み難いです。

5.まとめ
 Arduino のリファレンスには変数名は説明的な名前を付けましょう、と書かれているだけでキャメルケースなどの具体的な表現のテクニックまでは書かれていないようです。初心者に余計なプレッシャーを与えないように気を使っているのだと思いますが、少し上達すると、この記事に書いたようなことも大切になってくるはずです。

 あと、変数名は各々の人でこだわりがあるようなので、組織に属していない人は好きなものを使えば良いのですが、こんな意見もあるよ、という感じでこの記事を読んで頂ければ幸いです。

Arduino よもやま話 -1 (関数を書く順序)

1.まえがき
 これまでArduinoを使っていろいろな物を作ってきましたが、そういう経験を通じて得られた知識やノウハウなどを整理すると、これからArduinoを勉強しようという方の参考になりそうです。まあ、そんなたいそうな話では無くても、自分の経験を整理することで、新たな発見(勘違いの発見?)があるかも知れません。

 そんなことで、「Arduino よもやま話」と題して、感じたことや気付いたことを記事にしてみることにしました。ベテランの方から見るとアホみたいなことばかり書くかもしれませんが、ご容赦下さい。なお、Arduinoではプログラムのことをスケッチと言いますが、ここでは原則としてプログラムと呼ぶことにします。

2.関数を書く順序の問題
 初回の記事は「関数を書く順序」です。ArduinoはC言語をベースに、初心者向きに使い易くしたもの、という理解で良いと思いますが、ちょっと違いがあります。そのあたりが一番はっきりと出ているのが、関数を書く順序だと思います。

 Arduinoのプログラムを触った人なら誰でも知っていますが、Arduino のプログラムは以下のような構造になっていて、setup() とloop() をプログラムの最初に書くことになっています。
void setup() {
}
void loop() {
}
 いつもこういう書き方になっていたら判り易いだろう、ということでこの書き方、つまり先頭にsetup()を置いて、次にloop() を書くことになっています。簡単なプログラムなら、この構造の中に全部の内容を書くことが出来ますが、少し複雑な処理を書く場合は、サブルーチンを使う、つまり関数を使って下記のように書くことになります。
void setup() {
}
void loop() {
hogeFunction();
}
void hogeFunction(){
}
 hogeFunction() が追加された関数です。

 Arduinoで関数を使う場合、上に書いたようにように、loop() の後に書くしかありません。何しろsetup() と loop() は先頭に書くのが約束なので、これより前にhogeFunction() を書くわけにはいかないからです。

 これ、Arduinoでは当たり前の書き方ですが、C言語でこの書き方は許されません。関数は、それが実行される前に定義しておく、(あるいはプロトタイプ宣言を行って入出力を明確化しておく、)というルールなので、このままでは、Cコンパイラは通りません。

3.解決策
 どうしているかと言うと、コンパイラに掛ける前にプリプロセッサで構文解析を行い、抜けているプロトタイプ宣言を追加しています。
 プリプロセッサでは setup とloop の処理を、main()の中に展開している、という解説がよく出てきますが、同時にプロトタイプ宣言の追加ということもやっています。

 コンパイラの前処理でこういう操作が行われているため、ユーザーは関数の定義の順序を気にしないでプログラムを書くことが出来るようになっています。

Arduinoの関数のリファレンスに、「関数はloop()の前でも後でも、どちらに書いても良い」とさらっと書いてありますが、このために裏では面倒な処理が行われている訳です。原文だと、下記がそれに相当する部分です。
 Arduinoのレファレンスの関数の説明(Functions)に、Our function needs to be declared outside any other function, so "myMultiplyFunction()" can go either above or below the "loop()" function.

4.まとめ
 ネットにはいろいろなArduinoのプログラムが公開されていますが、その中にはsetup() とloop() が最初に書かれていないものがたまにあります。Arduinoのルール違反と言えなくも無いですが、そういう書き方される方は、たぶんC言語に精通された方なんだろうと思います。変な癖が付くと困るので、あえてCの標準スタイルでプログラムを書かれているのでしょう。
 実は昔、そういうプログラムを見た時に、なんでこういう読みにくい書き方になっているのか、理由が判りませんでした。でも、Cのプログラムとしては、そういう書き方が正しいわけです。実際、そういう書き方になっているプログラムは、高度な内容のものが多いです。

 実は私、C言語は大昔に使ったことがあって、関数の定義を先に書くなんて当たり前にやっていたはずです。でも、うん十年ぶりにArduinoからC言語を使うと、そんなことはすっかり忘れていました。後付けされた関数の参照の解決なんて、機械で出来るんだから人間にやらせるなよ、と言いたくなりますが、C言語はそういう緊張感の下でコードを書くものなんでしょう。

 ということで、よもやま話の初回は、関数を書く順序の話でした。なお、この話は "Arduino プロトタイプ宣言" あたりで検索するともっと質の良い解説が出てくると思います。
カレンダー
05 | 2018/06 | 07
- - - - - 1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
プロフィール

ラジオペンチ

Author:ラジオペンチ
電子工作を中心としたブログです。たまに近所(東京都稲城市)の話題など。60過ぎて視力や器用さの衰えを感じつつ日々挑戦!
コメントを入れる時にメールアドレスの記入は不要です。なお、非公開コメントは受け付けていません。

記事が気に入ったらクリックを!
最新記事
カテゴリ
最新コメント
リンク
FC2カウンター
検索フォーム
月別アーカイブ
RSSリンクの表示
QRコード
QRコード