無半音キーボード

DEMO9S08QG8評価ボードにタクトスイッチを拡張して、 キーボードを作ってみましょう。 まずは、半音の無いものからはじめます。 Processor Expertを使います。

完成写真 こげこげ君

アジェンダ

ハードウェア

このアプリケーションは、 DEMO9S08QG8評価ボードに圧電スピーカと抵抗、 それにタクトスイッチ9個を拡張して製作します。

回路図

アプリケーションに必要な部分の回路は、 以下のようになっています。

マイコンの以外のすべての部品が拡張部分です。 必要な部品は、以下の通りです。

オルガン(STEP1)部品表
品名型番個数調達先
評価ボードDEMO9S08QG81Freescale
ブレッドボードEIC-8011秋月電子
抵抗2.7kΩ 1/6W1-
圧電スピーカ-1梅澤無線
両端オスピンソケット6604P-20G-1212秋月電子
20芯フラットケーブル-25cm-
20Pフラットケーブルコネクタ-2-
片面ガラスエポキシユニバーサル基板95mm×72mm1秋月電子
ピンヘッダ1×102秋月電子
タクトスイッチ-9秋月電子

拡張部分は、ユニバーサル基板とブレッドボードに作りました。

ハードウェアの構成

このアプリケーションは、 ユニバーサル基板にタクトスイッチを配置したキーボード基板と DEMO9S08QG8評価ボードを 圧電スピーカと抵抗を配置したブレッドボードに接続して 構成しています。

ご覧のように、ブレッドボードは、評価ボードとキーボード基板および 圧電スピーカとの間の信号交換にしか使っていません。

このステップでは、 キーボード基板にはタクトスイッチしか配置していませんが、 別の製作記事でマイコンと圧電スピーカと電池を取り込んで 独立したアプリケーションに仕立てる計画です。 お楽しみに。

押しボタンスイッチからの入力のしくみ

このアプリケーションで入力装置として使用しているのは、 押しボタンスイッチの一種であるタクトスイッチです。 このスイッチには二つの電極があり、 押すとつながり、放すと切れるという簡単な構造になっています。

このスイッチをマイコンの入力端子に一つずつ接続します。 回路図には現れませんが、 マイコン内部には切り離し可能なプルアップ抵抗が内蔵されており、 下の図のようにしてスイッチのON/OFFを検出します。

スイッチを押すと、左の図の矢印のように電流が流れます。 そのため、マイコン内部の入力バッファは、低い電圧を検出し、 "0"信号が入力されたと判定します。

スイッチを放すと、右の図の矢印のように電流が流れますが、 電流が流れて行く先が無いため、 入力端子がVDDの電圧まで上昇すると 電流はとまります。 そのため、マイコン内部の入力バッファは、高い電圧を検出し、 "1"信号が入力されたと判定します。

ブレッドボードの準備

まず、最初にブレッドボードの準備をします。

評価ボードの接続位置

評価ボードには、2×16構成のコネクタが搭載されています。 このコネクタの奇数番のみを用いてブレッドボードと接続します。 コネクタの詳細は、太陽計の製作記事をご覧ください。

接続する位置は、ブレッドボードの下の端にある 1番から16番までの穴です。

評価ボードの接続位置

キーボード基板の接続位置

キーボード基板には、1×10構成のピンヘッダを配置し、 20芯フラットケーブルの一列だけを使ってブレッドボードとつなぎます。

接続する位置は、ブレッドボードの上から二段目の 4番から13番までの穴です。

キーボード基板の接続位置

ブレッドボード上の配線

ブレッドボードでは、 評価ボードとキーボード基板との間の配線を行います。 さらに圧電スピーカと抵抗を配置し、評価ボードと接続します。

ブレッドボード完成図

キーボード基板の準備

次にキーボード基板を用意します。

タクトスイッチの整形と配置

ユニバーサル基板にタクトスイッチを並べます。 実は、厳密にはタクトスイッチの端子の間隔は ユニバーサル基板の穴の間隔(0.1インチ)の倍数には なっていません。

出典

アルプス電気株式会社 http://www.alps.co.jp/
6mm角タクトスイッチ(スナップイン)SKHHシリーズ仕様書

そのため、ユニバーサル基板にタクトスイッチをそのまま差し込むと 端子に無理な力がかかって破壊する可能性があります。 また、破壊にまで至らなくても、 スイッチが傾いて取り付けられると見た目の美しさを損ないます。

そこで、ユニバーサル基板に差し込む前にあらかじめ端子を 整形してやります。 タクトスイッチは、最初は下の写真のように足が曲がっています。

買ったばかりのタクトスイッチ

この足をラジオペンチで挟んで開いてやります。

タクトスイッチの足を開く

写真の左側の二本の足が開かれています。 右の未加工の足と比べると良くわかると思います。 左右両方の足を開いたら、ユニバーサル基板に差し込みます。

タクトスイッチを差し込む

タクトスイッチの足を開いても、 ユニバーサル基板の穴の間隔よりも多少狭いため、 差し込んだだけでは写真のように傾斜してしまいます。 そこで、タクトスイッチの肩の部分を押して基板に密着させます。

タクトスイッチを押し込む まっちょ君
密着したタクトスイッチ

この時に決して基板の裏側から足を引っ張ったりしないでください。 足を引っ張ると抜けてしまう可能性があります。

タクトスイッチの配置

9個のタクトスイッチを色の順番に並べます。

ピンヘッダの配置

次にピンヘッダを配置します。

ピンヘッダの配置

ボードの接続

評価ボードは、ボードに実装されたコネクタで ブレッドボードと接続します。 また、キーボード基板は、20芯のフラットケーブルで ブレッドボードと接続します。

ボードの接続

仕様の確認

ハードウェアができたらソフトウェアを作りましょう。 でも、その前にどんなソフトウェアにするか確認しておきます。

キーを押したら音が鳴る

基本的なコンセプトは、 「キーを押したら音が鳴る」ことです。 ただ、どのキーを押しても同じ音が鳴るのでは、 キーボードになりませんから、 どのキーが押されたか判断してキーによって異なる音程の音を出す 機能が必要です。

キーと周波数の関係

そこで、どのキーを押したらどんな周波数の音を出すかを決めます。 キーは、全部で9個あり、回路図上に名前をつけてあります。 このキーに対して音階を以下のように割り当てます。

キーと周波数の関係
キーポート音階周波数(Hz)
SW9PTB7523
SW8PTB6587
SW7PTB5659
SW6PTB4ファ698
SW5PTB3784
SW4PTB2880
SW3PTB1988
SW2PTB01047
SW1PTA11175

周波数は、「ラ」の音を基準にした平均率音階になっています。 これで、安心してソフトウェアにとりかかることができます。

プロジェクト作成

プログラムの開発には、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\Organ1"というディレクトリに "Organ1.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

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

C/C++オプションの設定
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」をクリックします。

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

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

新規プロジェクト完成

リソース設定

ここから、 プロセッサエキスパートのプロパティを設定していきます。 ここでは、設定箇所だけ示します。 設定方法の詳細は、三値デジタル太陽計を参照ください。

キー入力の設定

キーは、PORTBとPORTAにまたがって配置されています。 一つ一つのキーをBitIOビーンで定義することもできますが、 ここでは、PORTBをByteIOビーンで定義し、 PTA1をBitIOビーンで定義します。

PORTB入力の設定

PORTBには、ByteIOビーンを割り当てます。 "Bean Selector"から "CPU Internal Peripherals → Port I/O → ByteIO"を ダブルクリックで呼び出したら、 以下の項目を設定します。

PORTB入力の設定
項目名設定する値
Port(ポート) PTB
Pull Resitor(プル抵抗) pull up(プルアップ)
Direction(方向) Input(入力)

最終的に属性は以下のようになります。

PORTBの設定終了

PTA1入力の設定

PTA1には、BitIOビーンを割り当てます。 "Bean Selector"から "CPU Internal Peripherals → Port I/O → BitIO"を ダブルクリックで呼び出したら、 以下の項目を設定します。

PTA1入力の設定
項目名設定する値
Pin for I/O(入出力ピン) PTA1_KBIP1_ADP1_ACMPMINUS
Pull Resitor(プル抵抗) pull up(プルアップ)
Direction(方向) Input(入力)

最終的に属性は以下のようになります。

PTA1の設定終了

PPG出力の設定

このアプリケーションでは、 タイマチャネル0が接続されたPTA0から音を出力します。 音を出すときに使用するのがPPGという機能です。

ビーンの属性を設定する

まず、"Bean Selector"から "CPU Internal Peripherals → Timer → PPG"を ダブルクリックで呼び出したら、 以下の項目について設定します。

PPG出力の設定
項目名設定する値
Output pin(出力端子) PTA0_KBIP0_TPMCH0_ADP0_ACMPPLUS
Period(周期) 1ms
Starting pulse width(最初のパルス幅) 0.5ms

最終的に属性は以下のようになります。

PPGの設定終了

ここで設定した周期は、ダミーです。 プログラムが実行されるとすぐに書き換えられます。

メソッドの定義

このアプリケーションでは、PPGの出力を出したり止めたりする 必要があります。 この出したり止めたりする機能を持ったメソッドは、 Processor Expertによって準備はされていますが、 標準状態では、コードが生成されません。 そのため、メソッドのコード生成を行わせるための設定が必要になります。

まず、画面左の"Project Panel"の "Beans → PPG1:PPG"を開きます。 ここには、使用可能なメソッドの一覧があります。 この中から"Enable"メソッドを右クリックしてコンテキストメニューを呼び出し、 "Enable"(有効化)を選びます。

メソッドの有効化

すると、"Enable"メソッドのアイコンが、 メソッドが使用可能であることを示す緑のチェックになります。 同様に"Disable"メソッドも"Enable"します。

有効になったメソッド

以上で必要なビーンの宣言は終わりました。

キー入力プログラム

プロセッサエキスパートの設定が終わったら、 プログラムのコーディングを行います。

コードの生成

CodeWarriorのウィンドウの左側にあるプロジェクトペインの Makeボタンを クリックして、ソースコードを生成させます。

Makeボタン

キー入力ルーチンの実装

コード生成では、"Organ1.c"というファイルも同時に生成されています。 左端の"Project Panel"ウィンドウに"Organ1.c"というファイルが見えます。

Organ1.cファイル

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

テキストエディタを開く

まずは、このファイルにキー入力を行う関数を定義します。

キー入力関数

どうです。 簡単でしょ。

"getKey(void)"関数の宣言

この"getKey(void)"関数は、 押されたキーに対応するbyte型のコードを 返すように作られています。

byte getKey(void) {
  :
}

コードは、左端のスイッチから順に1から9までの数値が割り当てられます。 if文の行列が押されたスイッチを探す部分です。

  if (Byte1_GetBit(7) == FALSE) return 1;
  if (Byte1_GetBit(6) == FALSE) return 2;
  if (Byte1_GetBit(5) == FALSE) return 3;
  if (Byte1_GetBit(4) == FALSE) return 4;
  if (Byte1_GetBit(3) == FALSE) return 5;
  if (Byte1_GetBit(2) == FALSE) return 6;
  if (Byte1_GetBit(1) == FALSE) return 7;
  if (Byte1_GetBit(0) == FALSE) return 8;

最初に調べられるのはPTB7につながったスイッチです。 このスイッチの状態を知らせるのが Byte1_GetBit(7)関数(メソッド)で、 引数の"7"は、調べるポート番号を示します。 もし、スイッチが押されていたら、 この関数は、FALSEを返します。 もし、FALSEが返されたら そのキーに対応するコードを返します。 たとえば、PTB7につながっている左端のスイッチが押されていたら、 "getKey(void)"関数は、"1"を返します。 以下、PORTBのすべてのスイッチについて検査します。

  if (Bit1_GetVal()   == FALSE) return 9;

次に検査されるのは、PTA1につながったスイッチです。 "BitIO"ビーンの場合には、 Bit1_GetVal()というメソッドを使います。 この関数は、FALSEを返します。 もし、FALSEが返されたら そのキーに対応するコード、ここでは"9"を返します。

  return 0;

また、どのキーも押されていなければ、 "getKey(void)"関数は、"0"を返します。

キー入力関数のテストプログラム

まず、"getKey(void)"関数のテストを行います。 テストを行うために、以下のようなプログラムを用意します。

キー入力関数テストプログラム
byte code;  // Key code value.
  for (;;) {
    code = getKey();
  }

ご覧のように、テストプログラムは簡単です。 "getKey(void)"関数から値を受け取って変数に入れる動作を 無限ループで延々と繰り返すだけです。 表示も何もしていないのは、 受け取った値をデバッガから読み込もうとしているためです。

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

テストを行うためにマイコンにプログラムを書き込みます。

DEMO9S08QG8評価ボードをPCに接続する

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

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

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

デバッガの呼び出し

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

接続方法の指定

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

マイコンに書き込む

消去確認

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

プログラムを実行させる

ツールボタンの Start/Continueボタンを クリックするとマイコンは自律走行を始めます。 ですが、この状態では、キーをいくら押しても何も反応が返ってきません。 反応を確認するにはどのようにしたら良いでしょうか。

変数の変化をリアルタイムに観測する

このデバッガには、変数をリアルタイムに観測する機能があります。 変数が表示されるのは、"Data:1"という名前のついたサブウィンドウです。

Data:1サブウィンドウ

このサブウィンドウの中で右クリックすると コンテキストメニューが現れます。

Data:1コンテキストメニュー

このメニューから"Mode → Periodical..."を選択すると "Update Rate"(更新頻度)というウィンドウが開きます。

更新頻度の設定

この数値を小さくすると、 変数の変化を頻繁に検査してくれます。 ここでは、デフォルトの"10"を指定して、"OK"ボタンをクリックします。

Data:1定期更新

すると、"Data:1"ウィンドウは、定期的に更新されるようになります。 上の図は、左から4番目のキーを押したときの表示です。 赤い色は、前回表示した値から変更があったことを示しますから、 変化の様子がよくわかります。

このリアルタイム観測機能を使って、 キーと"code"変数の関係を確認したら、 キー入力関数のテストは終了です。

音出力プログラム

キー入力関数が出来たので、 今度は、キーのコードにしたがって音を出す関数を作ります。

音出力ルーチンの実装

音出力関数は、以下のようになっています。

音出力関数

ちょっと、長いですか?

周期テーブル

音出力関数では、与えられたコードに従って、 音階を選び"PPG"を設定します。 この設定で使用されるのは、音の周期なので、 それぞれのコードに対応する周期をテーブルにしておきます。

const word period[] = {
  0,
  4000000 /  523, // DO
  4000000 /  587, // RE
  4000000 /  659, // MI
  4000000 /  698, // FA
  4000000 /  784, // SO
  4000000 /  880, // RA
  4000000 /  988, // SI
  4000000 / 1047, // DO
  4000000 / 1175  // RE
};

このテーブルでは、周期をマイコンのバスクロック数で表現しています。 そのため、マイコンのバスクロック周波数を音階の周波数で割った値を 計算させてテーブルに格納しています。 このテーブルは、constで宣言されているので、 ROM上に展開されます。

インデックス"0"の値は、キーのコードが"1"から始まっている ためのダミーであり、実際には使用しません。

"playSound(byte)"関数の宣言

"playSound(byte)"関数は、与えられたキーコードに対応する音の周期を "PPG"に設定します。

void playSound(byte code) {
  :
}

処理は、"code"が"0"であるか否かによって二つに分かれます。

  if (code == 0) {
    :
  } else {
    :
  }

まず、"code"が"0"の場合、 どのキーも押されていないことを示しますので、 "PPG"の波形を停止させます。 これには、PPG1_Disable()メソッドを使います。

    (void)PPG1_Disable();

このメソッドは、その内部で"PPG"の動作状態を把握する機能を 持っているため、 "PPG"が停止している状態で呼び出されても正しく動作します。

次に"code"が"0"でない場合、 いずれかのキーが押されたことを示しますので、 音の周期を設定して、 PPG1_Enable()メソッドで"PPG"を動作させます。

    TPMC0V = period[code] / 2;
    TPMMOD = period[code];
    (void)PPG1_Enable();

ここで、メソッドではない記述が現れます。 "TPMC0V"と"TPMMOD"は、タイマモジュールのレジスタを意味します。 本来であれば、"Processor Expert"が準備したメソッドを呼び出して 音の周期を決定するのですが、あいにく、それらのメソッドを使用するための ライセンスは、無償版では提供されていません。 そのため、苦肉の策として、直接タイマモジュールのレジスタを 操作しています。

PPG1_Enable()メソッドも、 その内部で"PPG"の動作状態を把握する機能を持っているため、 "PPG"が動作している状態で呼び出されても正しく動作します。

メイン関数

これで、キー入力をする関数と音を出す関数が揃いましたので、 これらの関数を呼び出してデータを引き渡すメイン関数を 準備します。

メイン関数

キーコードを受け取る部分は、 すでにキー入力関数のテストで使いましたから、 必要なのは、キーコードを"playSound(byte)"関数に渡す プログラム一行の追加だけです。

    playSound(code);

これで、キーコードをもとに音を出力する事ができます。

アプリケーションの確認

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

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

アプリケーションの実行のために マイコンにプログラムを書き込みます。

DEMO9S08QG8評価ボードをPCに接続する

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

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

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

デバッガの呼び出し

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

接続方法の指定

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

マイコンに書き込む

消去確認

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

プログラムを実行させる

ツールボタンの Start/Continueボタンを クリックするとマイコンは自律走行を始めます。 キーを押すとキーに対応した音が出てきます。 これで完成です。

完成写真 こげこげ君

課題

ビブラートが聞こえる

キーを押すと微妙に音程が動いてしまいます。 詳しい原因は不明ですが、 おそらくキーのチャタリングなどが発生して 周期が激しく変化するためであろうと推定しています。

これを防ぐには、キーに対する反応速度を落としてやると 頻繁に周期が変化することはなくなるでしょう。

音階を増やしたい

このアプリケーションでは、9個の音階しか出すことができません。 もっと多くの音階を出すためには、もっと多くのスイッチが 必要ですが、MC9S08QG8には、そんなに多くのスイッチをつなぐ端子は 残っていません。 さて、どのようにしたらもっと多くのスイッチをつなぐことができるように なるのでしょうか。

2006-03-01 発行。

2006-06-15 XHTML版発行。

Copyright (C) 2006 noritan.org ■