三値デジタル太陽計

DEMO9S08QG8評価ボードには、 フォトトランジスタ一個とLED二個が実装されています。 これらを使って、デジタル太陽計(照度計)を作ってみましょう。 ここにもProcessor Expertの出番です。

アジェンダ

ハードウェア概要

このアプリケーションは、 DEMO9S08QG8評価ボードしか必要としません。 アプリケーションに必要な部分の回路は、 以下のようになっています。

太陽計回路図

プロジェクト作成

プログラムの開発には、CodeWarriorを使います。 CodeWarriorでは、 一つのプログラムの単位を「プロジェクト」と呼んでいます。 ここでは、新規にプロジェクトを作成します。 ここでは、V5.0を使って説明します。

CodeWarriorの起動

スタートメニューからCodeWarriorを起動するとCodeWarriorが起動します。

初めてCodeWarriorを起動したときには、 下のような"Startup"ダイアログが出てきますが、 今はこのダイアログは使用しませんので、 X をクリックしてダイアログを閉じます。

CodeWarrior起動画面

この後、"Tip of the Day"ダイアログが出てくるかも知れませんが、 これも X をクリックして閉じてしまいましょう。

使用言語とディレクトリの設定

メニューから"File → New Project..."を選ぶと、 "HC(S)08 New Project"ダイアログが開きます。 まずは、"Project Parameters"(プロジェクトのパラメータ)を設定します。

新規プロジェクト画面1

使用する言語に"C"を選び、 プロジェクトを作成する場所を設定します。 この例では、"C:\Projects\CW\TaiyouKei"というディレクトリに "TaiyouKei.mcp"というプロジェクトファイルを作成しています。 設定を終えたら、「次へ」をクリックします。

デバイスと接続法の設定

画面が変わって、 "Device and Connection"(デバイスと接続方法)の設定に移ります。

新規プロジェクト画面2

デバイスには"HCS08 → HCS08QG Family → MC9S08QG8"を選び、 デフォルトの接続方法には"P&E Multilink/Cyclone Pro"を選び、 「次へ」をクリックします。

追加するファイルの設定

3枚目の画面は、 "Add Additional Files"(追加するファイル)の設定です。 プロジェクトで使用するソースコードなどがあれば、 ここで設定します。

新規プロジェクト画面3

今回は、追加するファイルはありませんので、 そのまま「次へ」をクリックします。

プロセッサエキスパートの設定

4枚目の画面は、 "Processor Expert"(プロセッサエキスパート)の設定です。

新規プロジェクト画面4

"Processor Expert"を選んでこの機能の使用を宣言します。 さらに、「次へ」をクリックします。

C/C++のオプションの設定

5枚目の画面は、"C/C++ Options"の設定です。

新規プロジェクト画面5

すべて、デフォルトのままの設定にします。

startup codeANSI
memory modelSmall
floating point formatNone

設定を確認して 「次へ」をクリックします。

PC-Lintの設定

最後の画面は、"PC-Lint"の設定です。 PC-lint™というのは、 プログラムの書式を検査するためのプログラムです。 今回は使用しません。

新規プロジェクト画面6

"No"をチェックして 「完了」をクリックすると、 新規プロジェクトの作成が始まります。

パッケージを選ぶ

MC9S08QG8マイコンには、 いくつかの異なる種類のパッケージが存在します。 その中から、今から使おうとしているパッケージが どのパッケージなのかを指定するのが次のウィンドウです。

パッケージ選択画面

今回は、評価ボードに搭載されている 16PIN-DIPパッケージを使いますので、 "MC9S08QG8_16"だけを選択して「OK」をクリックします。

使用する設定を選ぶ

これが、新規プロジェクトのための 最後の設定です。 "Select Configurations"(設定を選べ)というのは、 実にあいまいですが、 ここでは、アプリケーション開発の結果を何に使うかを指定します。 もちろん、独立した製品に仕上げるのが最終目的には 違いないのですが、 プログラムの開発中には、デバッガを接続した状態で プログラムを実行する必要もあります。

"Debug"設定は、このようなデバッガを接続した状態を考慮した 設定を行います。 このため、BKGD端子には、デバッガが接続されアプリケーションでは 使用できなくなります。

一方、"Release"設定は、最終製品での使用を考慮した設定を行うため、 すべての端子がアプリケーションに開放されます。

今回は、デバッグ環境である評価ボードでアプリケーション開発を 行いますので、 "Debug"だけを選択して「OK」をクリックします。

新規プロジェクト最終画面

以上で、プロセッサエキスパートを使用する 新規プロジェクトができました。

新規プロジェクト最終画面

リソース設定

ここから、 プロセッサエキスパートのプロパティを設定していきます。

A/Dコンバータの設定

まず、 A/Dコンバータ (A/D Converter: ADC) というブロックの設定をします。

ADCビーンの呼び出し

CodeWarriorのウィンドウの中央下には、 "Bean Selector"(ビーン選択)というサブウィンドウがあります。

ADC呼び出し

プロセッサエキスパートでは、 マイコンの機能を抽象化した物を「Bean」(ビーン:豆)と 呼んでいます。

ADCビーンを使用するためには、 このウィンドウの "CPU Internal Peirpherals → Converter → ADC → ADC"を 見つけ出してダブルクリックします。 すると、 中央上にある"Target CPU"というサブウィンドウの "PTB3"に"ADC"ビーンが付き、 右側にある"Bean Inspector"(ビーン検査官)というサブウィンドウに ADCの設定項目が現れます。

ADC設定画面

以下、この"Bean Inspector"を使用してビーンの設定を行っていきます。

アナログ入力端子の設定

"ADC"ビーンは、初期状態では"PTB3"からアナログ入力を行うように 設定されています。 今回のアプリケーションでは、 "PTA1"につながったフォトトランジスタの出力を使用するので、 アナログ入力端子を"PTA1"に変更します。

ADCポートの設定

A/Dチャンネル(端子名を選べ)

ペリフェラルの詳細: 汎用入出力ポートAのビット1、 キーウェイクアップ端子1、 A/Dコンバータチャンネル1、 コンパレータ反転入力

"Bean Inspector"の 項目"A/D Channels → Channel0 → A/D Channel (pin)"を "PTA1_KBIP1_ADP1_ACMPMINUS"に設定すると、 "Target CPU"のADCビーンが"PTA1"に移動します。

A/D変換時間の設定

後は、なるべく初期状態のまま使いたいのですが、 もう一つ設定しなくてはならない箇所があります。

プロセッサエキスパートでは、 必須設定項目あるいは問題のある設定には、 !マークが現れます。 現状、項目"Conversion Time"(A/D変換時間)に !マークが 表示されていますので、この設定だけを行います。

"Bean Inspector"の項目"Conversion Time"に カーソルを移動するとこの項目が何を意味し、 どうして問題が起こっているのかが表示されます。

変換時間についての説明

一変換あたりの時間。 ここには、数値と単位を一緒に記入する必要があります。 (時間設定文法を参照してください。) ボタン"..."をクリックすると開く タイミングダイアログボックスの助けを借りて 設定することもできます。

選択された実行時設定:固定値

エラー:タイミング未設定

お言葉に甘えて、 タイミングダイアログボックスを使ってみましょう。 "Bean Inspector"の項目"Conversion Time"の ...を クリックすると、A/D変換時間を設定するダイアログが現れます。

可能な設定の説明

ダイアログの下半分には、 "Possible Setting:"という説明が現れます。

可能な設定:

最も近い値:なし

可能な値:5.750µs, 11.500µs, 23µs, 46µs

"Latin-1"の"µ"のフォントが "Shift-JIS"では、半角の"オ"に割り当てられているため、 文字が正しく出ていませんが、 設定自体は正しく"µs=マイクロ秒"になります。

A/D変換時間とは、 プログラムがA/DコンバータにA/D変換の開始を指令した後、 どのくらいの時間で変換結果が戻ってくるかという時間です。 一般的にこの時間は、長いほうが精度が高くなります。 このアプリケーションでは、精度も反応速度も必要ないのですが、 最長の変換時間を選びます。 "Possible Setting:"の"46µs"の付近をクリックすると プルダウンメニュが出てきて、簡単に値を設定することができます。

変換時間の設定

「OK」をクリックすると、 ダイアログボックスは閉じます。

ADCビーン設定終了

これで、ADCビーンの設定は終了です。 変更したのは、二箇所だけでした。

ADCビーンの設定終了

ポート出力の設定

このアプリケーションでは、A/Dコンバータの出力に従って、 汎用ポートに接続された二つのLEDを点灯・消灯させます。 ここでは、汎用ポートの設定を行います。

ポートI/Oビーンの呼び出し

A/Dコンバータの時と同じように 汎用ポートのビーンを呼び出します。

Bits呼び出し

汎用多ビット入出力(1から8ビット)

ビーンのレベル:高レベルビーン

このビーンを現在のプロジェクトに挿入するにはダブルクリックせよ。

汎用ポートのビーンは、 "Bean Selector"ウィンドウの "CPU Internal Peirpherals → Port I/O → BitsIO"に ありますので、 見つけ出してダブルクリックします。 すると、 "Target CPU"サブウィンドウの"PTA0"に"BitsIO"ビーンが付き、 右側にある"Bean Inspector"サブウィンドウに BitsIOの設定項目が現れます。

BitsIO設定画面

端子の関連付け

"BitsIO"ビーンは、複数の端子と関連付けることができます。 このアプリケーションでも、 "PTB7"と"PTB6"の二つの端子を関連付けます。

まずは、二つの端子に関連付ける設定にします。 項目"Pins"の +をクリックすると、 端子の数が二つに増えます。

端子数の設定

LEDが接続されている端子は、"PTB"なので、 項目"Port"を"PTB"に設定します。

ポートの設定

そして、最後に項目"Pin1"と"Pin0"に "PTB7"と"PTB6"を関連付けます。

端子の関連付けの設定

端子の設定

このビーンに関連付けた端子は、すべて出力として定義します。 端子の入出力の設定は、 項目"Direction"(方向)で行います。

入出力方向の設定

ビーンの入出力方向: input(入力), output(出力), input/output(入出力) (端子の入出力方向は、実行時に切り替え可能です。 SetDir, SetInput, SetOutputメソッドを参照してください。)

端子の方向を出力(output)に設定したら、端子の設定は終わりです。

A/D入力のプログラム

プロセッサエキスパートの設定が終わったら、 プログラムのコーディングを行います。 第一段階として、 A/Dコンバータに変換を指示して、 変換された値を取り出すプログラムを作成し、 デバッガで動作を確認します。

コードの生成

プロセッサエキスパートの設定を行っただけでは ソースコードは生成されません。 ソースコードを生成させるには、 CodeWarriorのウィンドウの左側にあるプロジェクトペインの Makeボタンを クリックします。

Makeボタン

すると、コード生成、コンパイル、リンクが行われます。 生成されたソースコードは、 プロジェクトペインの "Generated Modules"(生成されたモジュール)フォルダの中に 収納されます。

生成されたモジュール

"AD1.c"と"Bits1.c"が、 プロセッサエキスパートの設定を行ったことによって 生成されたソースコードです。 また、"Cpu.c"は、マイコンの基本的な設定を行うコードです。

ソースコードの修正

この時に"TaiyouKei.c"というファイルも同時に生成されています。

メインコード

このファイルには、 マイコンがリセットされた後で実行される "main()"関数が記述されています。 ここをダブルクリックすると、 "TaiyouKei.c"ファイルを編集するテキストエディタが開きます。

テキストエディタを開く

メインルーチンのうち、変更する箇所は、 以下の通りです。

メインルーチンの変更

変数の宣言

A/Dコンバータからは、16ビットのデータを受け取ります。 この時に使用する受け渡し場所を変数といい、 以下のように宣言して場所を確保します。

word value;  // converted value.

wordは、 宣言する変数が16ビットの変数であることを示します。 valueは、変数の名前です。 変数宣言文は、";"(セミコロン)で終わります。 残りの"converted value"(変換された値)と 記述された部分は、コメントです。

自動変数か、大域変数か?

変数を"main()"関数の外で宣言すると「大域変数」と言って、 すべての関数から参照可能になります。 小さいプログラムの場合には、問題にならないのですが、 多くのプログラムが絡み合うような場合には、 このファイルで宣言された変数を他のファイルのプログラムからは 見えないようにして保護しなくてはならない場合があります。

一方、"main()"関数の中で変数を宣言すると、「自動変数」と言って、 "main()"関数が呼び出された時に変数の場所が確保されて"main()"関数の 内部でしか参照できなくなります。

安全なのは、他のプログラムからの干渉を受けない自動変数の方です。 しかし、自動変数は、"main()"関数の実行まではアドレスが定まらないので、 デバッグの際には、場所を特定しづらくなります。

このアプリケーションでは、デバッグのしやすさを考えて、 「大域変数」として定義しているため、 プログラムがリンクされた時点でアドレスが決定します。

無限ループ

このプログラムの処理は、 繰り返し処理を続ける無限ループで出来ています。 無限ループを記述するには、for文を使います。

  /* Write your code here */
  for (;;) {
    :
  }

for(;;) 文」という構文は、無限ループを示します。 他に 「while(1) 文」という構文で記述する方法もありますが、 こちらの記述は、 「ループから抜ける事ができない」という警告が発せられてしまいます。

コードを書く場所は、 "Write your code here"(あなたのコードをここに書きなさい)と 書いてある行の下です。 これ以外の場所に書く事は、 プロセッサエキスパートに受け入れられません。

すでに有る無限ループを書き換えてはならない。

プログラムを良く見ると、 改造を加えようとしている場所のすぐ下にfor文による 無限ループがあります。 「ラッキー、ここに処理を書いちゃえ。」 と思ってこの部分を書き換えないようにしてください。 この無限ループは、「メインルーチンの最後を示す印」として プロセッサエキスパートが生成したコードです。

このため、この無限ループを書き換えてからコンパイルをさせると、 プロセッサエキスパートは元通りのコードに書き換えてくれます。 つまり、修正したコードは、きれいに消えてしまうのです。

その解決方法が、別の場所に無限ループを書く方法です。 このコードでは、二つ目の無限ループには絶対にたどり着けませんので、 エラーか警告が発せられると思っていたのですが、 私がやってみた限りでは、警告も出ないようです。

A/D変換開始指令

プロセッサエキスパートでのA/D変換は、 変換開始指令と結果の受け取りの二つの部分に分けて記述されます。 これは、変換を行っているときに 他の処理を行わせたい場合などに便利だからです。 このアプリケーションでは、変換開始指令と結果の受け取りを 続けて記述しています。

変換開始指令は、以下の部分で発せられます。

    (void)AD1_Measure(TRUE);  // wait for conversion.

プロセッサエキスパートが生成した関数を オブジェクト指向の流れから メソッドと呼んでいます。 この文書でもそれに習って、メソッドという言葉を使います。

このメソッドは、引数を一つ取ります。 この引数にTRUEを指定した場合、 変換開始指令をA/Dコンバータに発した後、 A/D変換が終わって結果が確定してからメソッドを抜けます。

反対にFALSEを指定した場合は、 変換開始指令をA/Dコンバータに発した直後に メソッドから戻ってきます。 この時には、A/D変換の結果が確定しているかどうかがわかりませんが、 A/D変換が終わるまで他の処理を行うことが出来ます。

今回の用途では、変換結果が確定するのを待つことによって、 確実に変換結果が得られるようにしています。

(void)は、なぜ必要か?

メソッド呼び出しの前に(void)という 記述があります。 これは、「メソッドから返ってきた値を使用しない」という 宣言です。

実は、AD1_Measureというメソッドは、 メソッドの実行結果から得られたエラーコードを返してきます。 もちろん、エラーコードを受け取って、 その値によってエラー処理をするのが良いプログラムに違いはないのですが、 このアプリケーションではエラーが発生しないことが あらかじめわかっているため、エラー処理を省略し、 返ってきた値を無視しています。

どんなエラーが返ってくるかは、 次のコラムを読むとわかります。

どんなメソッドが用意されているのか

自分ではコードを記述せず、 プロセッサエキスパートが生成した関数を使うのが この方法の長所です。 そのためには、プロセッサエキスパートがどんな関数を生成するのかを 知る必要が有ります。 この情報は、プロジェクトペインの中から得られます。 プロジェクトペインの "Beans → AD1:ADC"を開くとA/Dコンバータのために 生成されたメソッドが並んでいます。 それぞれのメソッドのそばにカーソルを移動すると メソッドについてのヘルプが現れます。

メソッドのヘルプ

ここでは、詳しくは説明しませんが、このヘルプには、 このメソッドの振る舞いと使い方が書いてあります。

また、プロジェクトペインのメソッドを「ドラッグ&ドロップ」して テキストエディタに落とすと、メソッドの記述が追加されます。 このような便利な機能を駆使すると、 ますますアプリケーション開発が早くなることでしょう。

A/D変換結果の受け取り

A/D変換の結果は、以下のメソッドで受け取ることができます。

    (void)AD1_GetValue16(&value);  // get converted value.

このメソッドは、A/D変換の値を16ビットの値として受け取ります。 値が戻ってくる場所は、引数で示されるアドレスです。 この例では、valueという変数の アドレスを示す"&value"という表現が使われているので、 value変数の中に変換結果が入ります。

このメソッドもエラーコードを返します。 ところが、A/D変換終了直後に呼び出されるため、 エラーになる可能性がありません。 このため、エラー処理を省略しています。

A/D入力の確認

以上で、A/D変換の結果を受け取るプログラムが出来ました。 受け取った結果を表示するプログラムまでは作成していませんが、 ここでプログラムを書き込んでみて、 A/D変換の動作をデバッガで調べてみます。

マイコンにプログラムを書き込む

さて、いよいよマイコンにプログラムを書き込みます。 使用する開発ツールは、 DEMO9S08QG8評価ボードにすでに搭載されています。

DEMO9S08QG8評価ボードを接続する

まず、DEMO9S08QG8評価ボードをUSBケーブルで接続します。

最初に評価ボードを接続したときには、 「新しいハードウェアの検索ウィザードの開始」 というダイアログが表示されます。 この時には、 「ソフトウェアを自動的にインストールする」を選択して "USB Multilink"のデバイスドライバをインストールします。

デバッガ兼書き込みプログラムを呼び出す

CodeWarriorのプログラム書き込み機能は、 デバッガやシミュレータと兼用のツールから利用します。

デバッガの呼び出し

ドロップダウンリストが"P&E Multilink/Cyclone Pro"になっているのを 確認して、 DEBUGアイコンをクリックすると コード生成、コンパイル、リンクの後、 デバッガが立ち上がります。

USBインターフェースの設定

デバッガの初期化が終わると "ICD - Connection Manager"(In-Circuit Debuggerの接続マネージャ) ウィンドウが現れます。 ここでは、USBインターフェースの設定を行います。

接続方法の指定

"Interface:"と"Port:"の項目は、 自動的に認識されて正しい値が入っているはずです。 "Port:"に"DEMO9S08QG8"が表示されているのを確認して、 "Connect"をクリックします。

マイコンに書き込む

先の画面でボタンをクリックすると、 "Erase and Program Flash?"(フラッシュを消去、書き込みするか?)という ウィンドウが現れます。

消去確認

今回は、プログラムの書き込みが目的ですので、 「Yes」をクリックします。 もし、デバッグだけの目的でしたら、 「No」をクリックします。

今度は、"CPROGHCS08 Programmer"(CPROGHCS08プログラマ)という ウィンドウが現れ、 瞬く間にフラッシュの消去、書き込み、確認を行い、 自動的に消滅します。

プログラマ

これで、マイコンへの書き込みは終了です。

A/D変換をステップ動作させる

マイコンへの書き込みが終わると、 デバッガの初期画面が現れます。

デバッガの配置を確認する

デバッガの初期画面は、このようになっています。

デバッガ初期画面

ソースコードウィンドウには、 プログラムのソースコードが表示され、 プログラムが停止している場所がハイライトされています。

ソースコードウィンドウ

この例では、 プログラムは、"PE_low_lecel_init()"という関数に入る手前で 止まっていることがわかります。

データウィンドウ1には、 大域変数とその値が表示されています。

データウィンドウ1

この例では、 valueというunsigned intで 宣言された変数があり、 その値が"0"であることがわかります。

デバッガのツールバーには、ツールボタンが並んでいます。

ツールボタン

ここには、ステップ動作などデバッグに使用される機能が並んでいます。

ステップ動作でプログラムを実行する

まずは、ステップ動作をさせてみましょう。 ツールボタンの Step Overボタンをクリックすると プログラムがソースコードの一行分進みます。

ステップ1

もう一度、 Step Overボタンをクリックすると プログラムはさらに一行分進みます。

ステップ2

この動作を繰り返すことで、プログラムの動きを調べることができます。

A/D変換の値を確認する

"AD1_GetValue16(&value)"の所で停止している時に ステップ動作を行うと、 A/D変換された値が変数valueに格納されます。 格納された値は、データウィンドウ1で確認することができます。

A/D変換値の確認

数値が赤くなっているのは、 ステップ動作の前後で値が変化したことを示しています。

この値は、フォトトランジスタが捕らえた光の強さを表しています。 明るくしたり、暗くしたりして、値の変化を確認してください。 私の評価ボードのフォトトランジスタは、 蛍光灯よりも白熱灯の方が感度が高いようです。 私が懐中電灯を照らしたときの値の変化は以下のようになりました。

明るい3712
:18560
暗い65344

この値は、LED表示プログラムを作成するときに使用しますので、 控えておいてください。

これで、A/Dコンバータの動作確認はおしまいです。 実験が終わったら、 デバッガを閉じてCodeWarriorに戻ります。 また、評価ボードからUSBコネクタを抜いて電源を切っておきます。

LED表示のプログラム

次は、表示プログラムを作成します。

仕様を決める

LEDの表示には、評価基板上に搭載された"LED1"と"LED2"を使用します。 これらのLEDは、以下のように配置されています。

評価ボードに搭載されたLED

これを使って、明るさを表す棒グラフ風の表示にするため、 以下のような表示にします。 また、その時に"Bits1"汎用出力ビーンに設定する値も決まります。

表示最小値代表値最小値 LED1LED2VDD Bits1の値
明るい037129999 11
:100001856029999 01
暗い300006534465535 00

最小値と最大値は、 A/D変換の値を確認したときに控えた値(代表値)をもとにして 調整された値になっています。 皆さんが、作成される場合には、個々の環境に従って、 値を調整してみてください。

再び、ソースコードの修正

上で決めた仕様に従って、プログラムを記述していきます。 書き加える場所は、 無限ループの中のA/Dコンバータから値を受け取った直後です。

LED表示ルーチンの追加

書き加えたルーチンでは、 A/D変換の値valueの値によって 三つの処理に分岐しています。

メソッド"Bits1_PutVal()"は、汎用出力ポートの値を決定します。 引数は、8ビットのbyte型ですが、 このうちLSBの2ビットしか効力をもちません。 2ビットのうち、上位1ビットがPTB7に、下位1ビットがPTB6に相当します。

アプリケーションの確認

プログラムが完成したら、いよいよ自律制御をさせます。

マイコンにプログラムを書き込む

先ほどと同じようにマイコンにプログラムを書き込みます。 手順は、ほとんど同じです。

DEMO9S08QG8評価ボードを接続する

DEMO9S08QG8評価ボードをUSBケーブルで接続します。

デバッガ兼書き込みプログラムを呼び出す

ドロップダウンリストが"P&E Multilink/Cyclone Pro"になっているのを 確認して、 DEBUGアイコンをクリックすると コンパイル、リンクの後、デバッガが立ち上がります。

デバッガの呼び出し

USBインターフェースの設定

接続方法の指定

USBインターフェースの設定を確認したら、 "Connect"をクリックします。

マイコンに書き込む

消去確認

「Yes」をクリックして、マイコンに書き込みます。

プログラムを実行させる

A/D入力の確認では、ステップ動作をさせましたが、 今回は、そのまま走らせて見ます。 ツールボタンの Start/Continueボタンをクリックすると マイコンは自律走行を始めます。

下の写真のように、 フォトダイオードにあたる光の強さによって LEDのバーの長さが変わったら、完成です。

明るいときの表示
ほの明るいときの表示
暗いときの表示

課題

マイコンを休ませながら使う

このプログラムは、無限ループの中で実行されているため、 常にフルスピードでプログラムを実行しています。

LEDの表示を見るのは人間なので、そんなに忙しくLEDの表示を 更新する必要はありません。 どのようにしたら、適当にサボりながら表示を更新していくことが できるでしょうか。

数値で表現する

このアプリケーションは、LED二つで三つの値を表現しています。 もっと、多くの状態を表現するためには、 数値を表示させたほうがわかりやすくなります。

2006-02-14 STEP1として再構成。
2006-01-23 発行。
Copyright (C) 2006 noritan.org ■