シリアル通信を使った外部記憶装置の拡張第二弾です。 外部記憶の内容に従って、4桁の7セグメントLEDを点灯させます。
このアプリケーションは、 MC9S08QG8マイコンがシリアル通信の命令に従って、 4桁の7セグメントLEDを駆動します。
このアプリケーションの回路と基板のアートワークは、 以下のようになっています。
必要な部品は、以下の通りです。
品名 | 型番 | 個数 | 調達先 |
---|---|---|---|
マイコン | MC9S08QG8 | 1 | Freescale |
汎用ロジック | MC74HC164N | 1 | 手持在庫 |
7セグメントLED | LN516RA | 4 | 秋月電子 |
トランジスタ | 2SA1015 | 4 | 千石電商 |
トランジスタ | 2SC1815 | 1 | 千石電商 |
抵抗 | 220Ω 1/6W | 8 | 秋月電子 |
抵抗 | 1kΩ 1/6W | 4 | 秋月電子 |
抵抗 | 4.7kΩ 1/6W | 1 | 秋月電子 |
抵抗 | 47kΩ 1/6W | 2 | 秋月電子 |
積層セラミックコンデンサ | 0.1µF | 2 | 秋月電子 |
片面ガラスユニバーサル基板 | 95mm × 72mm | 1 | 秋月電子 |
ICソケット | 16P | 1 | 手持在庫 |
ICソケット | 14P | 1 | 手持在庫 |
ピンヘッダ | 1×4 | 1 | 秋月電子 |
ピンヘッダ | 1×3 | 1 | 秋月電子 |
今までの作品と比べると、かなり部品数が多くなっています。
回路図の左側にあるCOMと書かれたコネクタが シリアル通信を行うための端子です。 今までの外部記憶装置では、評価ボードに搭載されていた RS-232Cインターフェースを使用していましたが、 このアプリケーションでは、 この後の拡張を考えて、オープンコレクタによる 入出力構成としています。
オープンコレクタについての技術的なお話は、 姉妹サイト「マイコンクラブ勉強会資料」の 008 オープンコレクタの使い方を 参照してください。
COMコネクタの1番端子がシリアル入力です。 入力端子には、他の機器のオープンコレクタ出力が接続されるため、 47kΩのプルアップ抵抗だけが付加されています。
同じく、 COMコネクタの3番端子がシリアル出力です。 出力端子は、NPNトランジスタを使用した単純な半導体スイッチで 構成されています。 トランジスタをエミッタ接地で使用するため、 このままでは入出力の論理が反転してしまいますが、 MC9S08QG8マイコンには、シリアル出力を反転する機能を持っているため、 ビーンの設定を変更するだけで対応することが出来ます。
この3ピンのシリアルインターフェースは、 GND端子を真ん中に挟んで入出力端子を配置しています。 このため、コネクタを180度回転させると入出力を交換することができます。 この機能を使って、一種類のケーブルで 外部記憶装置同士の様々な組み合わせに対応させることができます。
このシリアルインターフェースは、このままでは、 PCと直接接続することはできません。 PCと接続する際には、評価ボードなどに搭載されている RS-232Cインターフェース回路が必要です。
このアプリケーションのLED表示部は、 7セグメントLED付き外部記憶装置の LEDを単に2桁から4桁に拡張したものです。 そのため、 追加されたLEDのコモンアノードを制御する出力信号さえ追加すれば、 実現することができます。 ところが、 前回の回路図を見てわかるように、 すでにMC9S08QG8には、PTA4とPTA5だけしか空きピンが残されていません。 しかも、PTA5は、入力専用端子なので、 使用可能な端子はPTA4だけです。 したがって、4桁のLEDを駆動するための出力信号は調達できません。 さて、困った。
色々と解決方法はあると思いますが、ここでは、 別のICを追加して出力ポートを増やしてやることにしました。 このICを駆動するために使用した端子は、 PTA2とPTA3の二本の出力端子だけです。
このアプリケーションで使用しているのは、 74HC164という型番のシフトレジスタと呼ばれるICです。 このICは、 シリアルに到着するデータをパラレルに変換してくれる動作を行います。
もちろん、このICの代わりにマイコンを追加することも出来ますが、 ここでは汎用ロジックICを使用しています。
ここで使用しているシフトレジスタは、 シリアルデータをパラレルデータに変換してくれる素子です。 入力に使用しているのはシフトクロックとシフトデータという 二本の信号だけです。 二本の信号線でシフトレジスタからの8本の出力を制御するのが 目的です。
シフトレジスタの動作は、以下のようになっています。
これら三つの動作を使用して出力を決定してやります。
それでは、どうやったら、 希望の値をすべての出力から出すことができるのでしょうか。
シフトクロックとシフトデータの二つの入力で決定できる シフトレジスタの出力は、QAだけです。 従って、このままでは、 他の出力、QBからQHまでの値を 決定することはできないように思われます。
ところが、QA出力にシフトデータの値を入れたのと同時に QB出力には、それまでQAに出力されていた 値がシフトされます。 つまり、QB出力の値を決めるためには、 QA出力に出したい値を指定する前に QB出力に出したい値をシフトデータから入れてやれば 良いということになります。
これをQH出力まで拡張していくと、 QHからQAまでの順番に 出したい値をシフトデータに入れてやればすべての出力を決定することが できます。
以上のようにシフトレジスタは、 たった二つの信号だけで多くの出力の値を決定することができます。 ただし、いくつか問題点がないわけではないのです。
このアプリケーションは、以下のような仕様で動作します。
基本的なコンセプトは、今までと同じ 「シリアル通信で会話が出来、記憶した内容がLEDに表示される」ことです。 会話の内容は、 STEP1 と同じ文法を使います。
このアプリケーションでは、 左端のLEDから順にアドレス"0"から"3"までの内容を表示します。
各ビットとLEDのセグメントの関係は、 数値表示太陽計と 同じとします。
最初にCodeWarriorで新規プロジェクトを以下の手順で作成します。 表示されるダイアログなどの詳細は、 外部記憶装置を 参照してください。 ここでは、V5.0を使って説明します。
デバイス | HCS08 → HCS08QG Family → MC9S08QG8 |
---|---|
デフォルトの接続方法 | P&E Multilink/Cyclone Pro |
「次へ」ボタンをクリックします。
使用する言語 | "C" |
---|---|
Project Name(プロジェクト名) | Extmemory3.mcp |
Location(プロジェクトを作成するディレクトリ) | C:\Projects\CW\Extmemory3 |
「次へ」ボタンをクリックします。
追加するファイルは無いので、そのまま「次へ」ボタンをクリックします。
"Processor Expert"を選んで「次へ」ボタンをクリックします。
startup code | ANSI startup code |
---|---|
memory model | Small |
floating point format | None |
「次へ」ボタンをクリックします。
以上で、プロセッサエキスパートを使用する 新規プロジェクトができました。
このアプリケーションは、 7セグメントLED付き外部記憶装置を 改造することで実現します。
まず、 7セグメントLED付き外部記憶装置で 作成したリソースを再現します。
シリアル通信は、以下の手順で設定します。
項目名 | 設定する値 |
---|---|
Baud rate(ボーレート) | 9600 |
セグメントドライバは、以下の手順で設定します。
項目名 | 設定する値 |
---|---|
Bean Name(ビーン名) | SegHi |
Port(ポート) | PTB |
Pins(ピン数) | 6 |
Pin0 → Pin(0番目のピン) | PTB2_KBIP6_SPSCK_ADP6 |
Pin1 → Pin(1番目のピン) | PTB3_KBIP7_MOSI_ADP7 |
Pin2 → Pin(2番目のピン) | PTB4_MISO |
Pin3 → Pin(3番目のピン) | PTB5_TPMCH1_SS |
Pin4 → Pin(4番目のピン) | PTB6_SDA_XTAL |
Pin5 → Pin(5番目のピン) | PTB7_ACL_EXTAL |
Direction(信号の方向) | Output(出力) |
項目名 | 設定する値 |
---|---|
Bean Name(ビーン名) | SegLo |
Port(ポート) | PTA |
Pins(ピン数) | 2 |
Pin0 → Pin(0番目のピン) | PTA0_KBIP0_TPMCH0_ADP0_ACMPPLUS |
Pin1 → Pin(1番目のピン) | PTA1_KBIP1_ADP1_ACMPMINUS |
Direction(信号の方向) | Output(出力) |
桁ドライバは、以下の手順で設定します。
項目名 | 設定する値 |
---|---|
Bean Name(ビーン名) | Dig1 |
Pin for I/O(端子名) | PTA3_KBIP3_SCL_ADP3 |
Direction(信号の方向) | Output(出力) |
Initialization → Init. value(初期値) | 1 |
項目名 | 設定する値 |
---|---|
Bean Name(ビーン名) | Dig2 |
Pin for I/O(端子名) | PTA2_KBIP2_SDA_ADP2 |
Direction(信号の方向) | Output(出力) |
Initialization → Init. value(初期値) | 1 |
周期割り込みタイマは、以下の手順で設定します。
項目名 | 設定する値 |
---|---|
Timer(使用するタイマ) | RTIfree(RTIをフリーランニングで使用) |
Interrupt period(割り込みの周期) | 8ms |
ビーンの設定が終わったら、 Processor Expertにソースコードを生成させます。
最後にプログラムを再現します。
最初に"Extmemory3.c"ファイルの編集を行います。
まず、 "Project Panel"ウィンドウの "User Modules → Extmemory3.c:main"を ダブルクリックして、"Extmemory3.c"ファイルの テキストエディタを開きます。
次に関数部分を転記するのですが、 ここでは、簡単に再現するために以下のリンクに 7セグメントLED付き外部記憶装置の プログラムを用意しました。 このファイルの内容をvoid main(void)の宣言の 前にコピー&ペーストします。
最後に
void main(void)関数の中身を転記します。
以下のプログラムを
/* Write your code here */
と書いてある
下に書き込みます。
for (;;) { interpret(); }
次に"Events.c"ファイルの編集を行います。
まず、 "Project Panel"ウィンドウの "User Modules → Events.c:main"を ダブルクリックして、"Events.c"ファイルの テキストエディタを開きます。
そして、
void TI1_OnInterrupt(void)関数の中身を転記します。
以下のプログラムを
/* Write your code here ... */
と書いてある
下に書き込みます。
extern void showLED(void); showLED();
以上でプログラムは、再現できました。 コード生成で行った時と同様に ボタンを クリックするとコードが生成されます。 ここで、コンパイルエラーなどが発生しなければ 7セグメントLED付き外部記憶装置の 再現は完了です。
ここからは、四桁の7セグメントLED出力を扱うための改造を行います。 まずは、"Processor Expert"のリソースの再設定からです。
ハードウェアで説明したように このアプリケーションでは、シリアルインターフェースを オープンコレクタ出力で受け渡しします。 そのため、シリアル出力の位相を反転させなくてはなりません。
位相の反転は、"Processor Expert"を使っている場合には、 ビーンのプロパティを変更するだけなので、極めて簡単です。
非同期シリアルビーン(AS1)の設定を以下のように変更します。
項目名 | 設定する値 |
---|---|
Baud rate(ボーレート) | 9600 |
Transmitter Output(送信器出力) | Inverted |
7セグメントLED付き外部記憶装置では マイコンの出力をそのまま使って2桁のLEDを制御していました。 これを ハードウェアで説明しましたが、 シフトレジスタ74HC164APで間接的に4桁のLEDを制御することにしました。 そのため、従来は桁ドライバとして使用していた出力ポートを シフトレジスタ制御用の信号として再設定します。
シフトレジスタの制御に必要な信号は、 シフトクロックとシフトデータの二本です。
十の位ドライバ(Dig1)ビーンの設定を以下のように変更します。
項目名 | 設定する値 |
---|---|
Bean Name(ビーン名) | SClock |
Pin for I/O(端子名) | PTA3_KBIP3_SCL_ADP3 |
Direction(信号の方向) | Output(出力) |
Initialization → Init. value(初期値) | 0 |
一の位ドライバ(Dig2)ビーンの設定を以下のように変更します。
項目名 | 設定する値 |
---|---|
Bean Name(ビーン名) | SData |
Pin for I/O(端子名) | PTA2_KBIP2_SDA_ADP2 |
Direction(信号の方向) | Output(出力) |
Initialization → Init. value(初期値) | 0 |
これらの制御信号の使い方は、 のちほどプログラミングと一緒に説明します。
ビーンの再設定が出来たので、 コードを生成させます。 ボタンを クリックするとコードが生成されます。 コンパイルエラーなどが無ければ、いよいよプログラミングです。
上の作業では、桁ドライバビーンの名前を変更しました。 このままでは、プログラムで使用されている関数名と整合が取れなくなって、 コンパイルエラーが発生するはずなのですが、 実際には、コンパイルエラーは発生しません。
"Processor Expert"が生成したコードを見るとわかるのですが、 ビーンの名前を変更すると、たとえば以下の例のように そのビーンに関連した関数名なども自動的に修正してくれます。
case 1: // (A) Process digit-1 SData_SetVal(); // (A1) Turn digit-2 off. // (A2) Set segements for digit-1. SegHi_PutVal(~(memory[0] >> 2)); SegLo_PutVal(~(memory[0] & 0x03)); SClock_ClrVal(); // (A3) Turn digit-1 on. digit = 2; // (A4) Process digit-2 next. break; // (B) End of digit-1 processing.
ビーンの名前を変更したい場合にはありがたい機能なのですが、 今回の場合には、端子の使用目的まで変更しているので、 プログラムの意味という面では正しくありません。 ただ、今回は、説明を簡単にするために名前を変更しただけに とどめました。
本来は、"Dig1"ビーンと"Dig2"ビーンを削除した上で、 新たに"SClock"ビーンと"SData"ビーンを定義するのが 正しい方法です。 そうすれば適切にコンパイルエラーが発生するので、 修正すべき箇所が明確になります。
ここから、表示プログラムを4桁表示ができるように変更していきます。 このアプリケーションでは、 シリアルインターフェースを使った会話機能には変更がないので、 "void showLED(void)"関数だけを変更することになります。
表示プログラムは、一定時間間隔を知らせてくれる RTIの発生によって、以下のような状態遷移を起こします。
7セグメントLED付き外部記憶装置では 二つだった状態が四つに増えましたが、 状態を表現するためのbyte型変数digitは そのまま使用します。。
この関数は、 変数digitによって決定された桁の LEDを表示します。 4桁表示にするために全面的に入れ替えています。
/************************************************************** * Show a digit of LEDs. **************************************************************/ void showLED(void) { byte pattern; // Pattern data in a memory. // turn off all LEDs SData_SetVal(); // (A1) Set SData to 1. SClock_SetVal(); // (A2) Set SClock to 1. SClock_ClrVal(); // (A3) Set SClock to 0. // Set segment pattern. pattern = memory[digit]; // (B1) Get a segment pattern. SegHi_PutVal(~(pattern >> 2)); // (B2) Set Hi-side segment. SegLo_PutVal(~(pattern & 0x03));// (B3) Set Lo-side segment. // Turn on a LED if (digit == 0) { // (C1) First digit ? SData_ClrVal(); // (C2) Set SData to 0. } SClock_SetVal(); // (C3) Set SClock to 1. SClock_ClrVal(); // (C4) Set SClock to 0. // process next digit. digit++; // (D1) Determine next digit. if (digit >= 4) { // (D2) Out of bound ? digit = 0; // (D3) Return to first digit. } }
この関数は、四つの部分から構成されています。
LEDの表示内容を更新する間、LEDには消灯してもらいます。 シフトデータに"1"を設定し、 シフトクロックに正極性のパルスを送ります。
// turn off all LEDs SData_SetVal(); // (A1) Set SData to 1. SClock_SetVal(); // (A2) Set SClock to 1. SClock_ClrVal(); // (A3) Set SClock to 0.
こうすると、シフトデータの値"1"がQA、つまり千の桁ドライバに設定され、 千の桁のLEDは消灯します。 他の桁ドライバへは、QB,QD,QFの値が設定されますが、 今はこれらの値はすべて"1"であると思ってください。
この部分は、 7セグメントLED付き外部記憶装置で 作成したプログラムを一般的な書き方に改めたものです。
// Set segment pattern. pattern = memory[digit]; // (B1) Get a segment pattern. SegHi_PutVal(~(pattern >> 2)); // (B2) Set Hi-side segment. SegLo_PutVal(~(pattern & 0x03));// (B3) Set Lo-side segment.
表示しようとしているセグメントの情報を SegHiビーンとSegHiビーンから 出力します。
桁ドライバを一つだけ動作させてLEDを点灯します。
// Turn on a LED if (digit == 0) { // (C1) First digit ? SData_ClrVal(); // (C2) Set SData to 0. } SClock_SetVal(); // (C3) Set SClock to 1. SClock_ClrVal(); // (C4) Set SClock to 0.
シフトデータに千の桁を表示させる場合には"0"を設定し、 そうでない場合には(A1)で設定した"1"のままにします。 そして、シフトクロックに正極性パルスをあたえると、 digitで指定した桁の出力だけが"0"になります。
LEDの表示が開始されたら、 次の表示に備えて、状態変数digitの値を一つ進めます。
// process next digit. digit++; // (D1) Determine next digit. if (digit >= 4) { // (D2) Out of bound ? digit = 0; // (D3) Return to first digit. }
状態変数digitは、0から3までの値を順にとります。 (D1)で変数をインクリメントしたら、 (D2)で変数の値が0から3までの範囲を超えていないかを調べます。 もし、超えていれば、変数の値を"0"に戻します。
このアプリケーションでは、 シフトレジスタをシフトしただけで LEDが消灯したり点灯したりするように作られています。 ここでは、その仕組みについて説明しましょう。
下の図は、変数digitが0から3まで変化したときの シフトデータとシフトクロックの動きを示しています。
この図からわかるように、シフトレジスタの8出力は、 常に一つだけが"0"になるように制御されています。 このため、桁ドライバが一つだけ動作するというわけです。
さらに、それぞれのステートメントと信号の動きを詳細に対比させたのが 以下の図です。
このように、ある桁が点灯しているときには、 セグメントデータが安定するように設計されているため、 桁の切り替え時に不要な表示が出ることはありません。
このアプリケーションで行った方法では、 8出力のシフトレジスタの4出力しか使用していません。 もったいないので、全部使う方法も考えてみました。
上のプログラムでは、桁ドライバを制御してLEDを消灯させていましたが、 セグメントドライバを制御してLEDを消灯させることもできるはずです。 そこで、表示の更新を以下の手順で行います。
以上の手順を使えば、 同じシフトレジスタで最大8個のLEDを制御することができます。
プログラムが完成したら、テストしてみます。
マイコンをアプリケーションボードに載せたら、 プログラムを書き込みます。 使用する書き込みツールは、DEMO9S08QG8評価ボードです。 DEMO9S08QG8評価ボードを開発ツールとして使うも 参照してください。
評価ボードとアプリケーションボードを接続します。
今回は、開発ツールを接続するコネクタに DEMO9S08QG8評価ボードを開発ツールとして使うで 使ったSBDM規格のコネクタを使っています。 今にして思えば、標準のBDM規格でも良かったみたいですね。
このアプリケーションで使用したボタン電池ケースは、 ボタン電池が入っていない状態では、プラス・マイナスの両端子が 接触する構造になっています。 このまま評価ボードを接続すると、評価ボードから過大な電流が流れて、 破損してしまう恐れがあります。 デバッグの間は、電池ケースに厚紙をはさんでおくと、 このような事故を防ぐことができます。
DEMO9S08QG8評価ボードをUSBケーブルでPCに接続します。
ドロップダウンリストが"P&E Multilink/Cyclone Pro"になっているのを 確認して、 アイコンを クリックするとコンパイル、リンクの後、デバッガが立ち上がります。
USBインターフェースの設定ダイアログが現れます。
USBインターフェースの設定を確認したら、 "Connect"をクリックします。
「Yes」をクリックして、マイコンに書き込みます。
出来上がった装置をPCに接続したいのですが、 実は、このままでは接続することはできません。 それは、ハードウェアで書いたように、 シリアルインターフェース部分をオープンコレクタ構成にしたためです。 RS-232Cインターフェースを作成しなくては。
そこで、作成したのが、この「RS-232C通信アダプタ」です。
この装置があれば、RS-232Cインターフェースと オープンコレクタインターフェースをつなぐことができます。 実際の製作記事は、次回の RS-232C通信アダプタで 紹介します。
ターミナルソフトは、 外部記憶装置で作成した設定ファイルが そのまま使えます。 設定ファイルは、 WindowsXPでは、 「スタート → すべてのプログラム → アクセサリ → 通信 → ハイパーターミナル → 9600-8N1」 に残っています。 これを選択するとハイパーターミナルが起動します。
次にRS-232C通信アダプタにRS232Cケーブルをつなぎます。
次にアプリケーションボードとRS-232C通信アダプタを シリアルケーブルでつなぎます。 ここで使用したシリアルケーブルは、 単純な3線式のコネクタです。
方向を示すために片側だけ白い色をつけてあります。 このケーブルを使って、二つのボードを接続します。
次にRS-232C通信アダプタの電源である乾電池を入れます。
これで、すべての準備が整いました。
ここから、LEDの表示の様子をテストしていきます。
ツールボタンの アイコンを クリックして、マイコンのプログラムを起動します。 すると、プロンプト*が表示されます。
*
LEDは、消灯したままです。
次に、アドレス"0"に"76"を書き込むため、 W0:76<Enter>とタイプします。
*W0:76 0:76 *
すると、左のLEDに"H"が表示されます。
続けて、アドレス"1"に"39"を書き込むため、 W1:39<Enter>とタイプします。
*W1:39 1:39 *
すると、右のLEDに"C"が表示されます。
更に、 アドレス"2"に"5C"を アドレス"3"に"7F"を書き込みます。
*W2:5C 2:5C *W3:7F 3:7F *
すると、LEDには、"08"が表示されます。
最後に D<Enter>とタイプして ダンプコマンドを実行し、 LEDの表示がちらつかないことを確認しましょう。
*D :5C:7F:00:00:00:00:00:00:00:00:00:00:00:00:00:00 *
シフトレジスタのかわりにマイコンを使うこともできます。 4桁のLEDを制御するだけなら、8ピンのマイコンが使えるはずです。
このアプリケーションのテストでは、 ターミナルソフトから人の手によってデータを入れています。 この作業を別のマイコンにやらせたら、 自動的に表示が変わるアプリケーションができます。
2006-11-20 写真がないけど発行。
Updated: $Date: 2006/11/20 13:38:04 $
Copyright (C) 2006 noritan.org ■