■>サンテックのホームページTOPへ       ■>サンおやじの工作室TOPへ
    工作室
       第4章 ブザーを鳴らす

<工作室に戻る
"CPU"と"プログラム"(初心者のために)
第1章 とりあえず動かす (H8Tiny入門その1)
第2章 LEDの点灯    (H8Tiny入門その2)
第3章 キーの読み込み  (H8Tiny入門その3)
■第4章 ブザーを鳴らす   (H8Tiny入門その4)

第4章 ブザーを鳴らす

タイマ機能を使ってブザーを鳴らしてみましょう

ブザーには、自励振と呼ばれる発信回路を内蔵したタイプと他励振と呼ばれる発信回路を内蔵していないタイプがあります。コンソールボードに使われているのは他励振タイプです。
このため、ブザーに接続されているポート端子から矩形波(パルス)を与えることで鳴らすことが出来ます。

CPU周辺機能のタイマ機能を使ってブザーを鳴らすことにします。
タイマとは、名前の通り時間を管理できるものです。基本となるクロックをカウントしそのクロック数(時間)を前もって指定しておけば、その時間が来れば知らせてくれたり、指定したイベントを発生させたりしてくれるものです。
今回は、パルスを発生させるわけですから、タイマWのアウトプットコンペア機能を使うことにします。
動作原理は、下の図のようになります。

カウント開始ビット(CTS)を1にすると、TCNTが0x0000からカウントアップし、GRDの値と同じになるとP84(FTIOD)端子の出力を反転(トグル)します。
また、その時GRA=GRDにしておくとTCNTの値を0x0000にリセットし、カウントアップ動作を再開します。
この動作を繰り返し、パルス波形を出力します。

縦軸にTCNTの値

タイマ部分のプログラムを考えてみましょう

タイマWの初期設定が完了する前に動作しないようにまず、カウンタを停止します。
またタイマWの割込も禁止にします。(リスト8−1の1〜2行目)
カウンタTCNTとGRAの値が同じでTCMTをクリアする設定(ビット7)、カウントソースを内部クロック8分周に設定(ビット6〜4)、FTIOD端子初期レベルをローレベルに設定(ビット3)、その他を0に設定します。(リスト8−1の3〜4行目)
ブザーとつながっているP84(FTIOD)端子をアウトプットコンペア出力に設定し、トグル出力となるように設定します。(リスト8−1の5〜6行目)
カウンタTCNTに初期値0x0000を設定し、トグルするタイミングとカウンタをリセットするタイミングをGRDとGRAにそれぞれ設定します。(リスト8−1の7〜10行目)
今回ブザーへのパルス周期を4KHzとするので、システムクロック0.625uSの8分周を250回カウントすれば、パルスのトグルタイミングになります。
GRA、GRDへセットする値250は、9行目の式から逆算します。
最後にCTSビットを1にするとブザーが鳴ります。(リスト8−1の11行目)

リスト8−1
TW.TMRW.BYTE = 0x00; // カウント停止、その他イニシャル
TW.TIERW.BYTE = 0x00; // タイマW割り込み禁止
TW.TCRW.BYTE = 0xb0; // コンペアマッチでTCNTクリア
               // φ/8、TOD=0
TW.TIOR0.BYTE = 0x00; // FTIOD以外通常ポートに設定
TW.TIOR1.BYTE = 0x30; // FTIODコンペアマッチトグル出力に設定
TW.TCNT = 0x0000; // カウンタTCNTに0(初期値)を設定
TW.GRD = 250; // トグル出力周期を設定
          // 250×8×0.625×2=250μS(4KHz) TW.GRA = 250; // TCNTをクリアする値を設定
TW.TMRW.BIT.CTS = 1; // タイマWスタート(ブザーON)

スイッチを押すとブザーが鳴るようにする

リスト8−1のままだと、電源を入れたとたんにブザーが鳴り始め、電源を切らない限り止まりません。
そこで前回スイッチを押すとLEDランプが点灯しましたが、LEDランプの代わりにブザーを鳴らしてみましょう。
但し、ブザーに直流電圧をかけるとブザーが正常に動作しなくなる事がありますので、ブザーをOFFする場合はブザーの両端に電圧がかからないようなプログラムにします。

LEDランプをシフトしながら点灯させたときに使ったリスト7のmain()関数の7〜10行目を、ブザーを鳴らす様に変更します。
さらに12行目にブザーを鳴らさないようにする部分を追加します。(リスト8−3)
変更部分では、基本的にCTSビットを操作するだけでブザーは制御できますが、OFFしたときにブザーの両端に直流電圧がかからないように、汎用ポートに戻します。
このためポートを前もってローレベルにする必要があります。この部分が、リスト8−2になります。

リスト8−2
IO.PCR8 = 0x00; // LED、ブザーポートを入力に設定
IO.PDR8.BYTE = 0x00; // LED、ブザー全ポートをOFF
IO.PCR8 = 0x1f; // LED、ブザーポートを出力に設定

リスト8−3
while(SW_Read() == 0); // スイッチが押されるまで待つ
TW.TIOR1.BYTE = 0x30; // FTIODコンペアマッチトグル出力に設定      リスト7からの変更部分
TW.TMRW.BIT.CTS = 1; // タイマWスタート(ブザーON)             リスト7からの変更部分
while(SW_Read() == 1); // スイッチが放されるまで待つ  
TW.TIOR1.BYTE = 0x00; // タイマ出力端子を通常ポートに設定         リスト7からの変更部分
TW.TMRW.BIT.CTS = 0; // タイマWストップ(ブザーOFF)            リスト7からの変更部分

それでは、整理してみます。

まず、LEDとブザーポートを初期設定(リスト8−2)し、タイマWの初期設定(リスト8−1)を行い、次にスイッチのON/OFFによりブザーを鳴らす部分(リスト7から変更したリスト8−3)を加えます。
これで目的のプログラムになりました。
これにCPUの初期設定やポートのイニシャライズを含めたプログラムがリスト8です。
BUZZER_TEST.c”をビルドして書き込んで動作させてみましょう。

リスト8
#include "iodefine.h"
// プロトタイプ宣言
void main(void);
void IOinit(void);
int SW_Read(void);
void wait(int);
void wait1mS(void);
void main(void)
{
 IOinit(); // I/Oの初期化
 while(1){ // 無限ループ
  while(SW_Read() == 0); // スイッチが押されるまで待つ
  TW.TIOR1.BYTE = 0x30; // FTIODコンペアマッチトグル出力に設定
  TW.TMRW.BIT.CTS = 1; // タイマWスタート(ブザーON)
  while(SW_Read() == 1); // スイッチが放されるまで待つ
  TW.TIOR1.BYTE = 0x00; // タイマ出力端子を通常ポートに設定
  TW.TMRW.BIT.CTS = 0; // タイマWストップ(ブザーOFF)
 }
}
// I/Oの初期化
void IOinit(void)
{
 IO.PDR1.BYTE = 0x00; // ポート1に0x00を設定
 IO.PDR2.BYTE = 0x00; // ポート2に0x00を設定
 IO.PDR5.BYTE = 0x00; // LCDデータセット(ポート5に0x00を設定)
 IO.PDR7.BYTE = 0xff; // LCD信号全てHigh
 IO.PMR1.BYTE = 0x00; // ポート1を汎用ポートに設定
 IO.PUCR1.BYTE = 0x00; // ポート1 プルアップしない
 IO.PCR1 = 0x00; // ポート1を入力に設定
 IO.PCR2 = 0x00; // ポート2を入力に設定
 IO.PMR5.BYTE = 0x00; // ポート5を汎用ポートに設定
 IO.PUCR5.BYTE = 0x00; // ポート5 プルアップしない
 IO.PCR5 = 0xff; // LCDデータ出力端子に設定
 IO.PCR7 = 0x70; // LCD信号出力端子に設定
 IO.PCR8 = 0x00; // LED、ブザーポートを入力に設定
 IO.PDR8.BYTE = 0x00; // LED、ブザー全ポートをOFF
 IO.PCR8 = 0x1f; // LED、ブザーポートを出力に設定
 IO.PDR1.BYTE = 0x67; // ポート1をハイレベルに設定
 IO.PCR1 = 0x67; // ポート1の必要なビットを出力に設定
 AD.CSR.BYTE = 0x03; // アナログ入力チャネルを端子3に設定
 TW.TMRW.BYTE = 0x00; // カウント停止、その他イニシャル
 TW.TIERW.BYTE = 0x00; // タイマW割り込み禁止
 TW.TCRW.BYTE = 0xb0; // コンペアマッチでTCNTクリア
                 // φ/8、TOD=0
 TW.TIOR0.BYTE = 0x00; // タイマ出力端子を通常ポートに設定
 TW.TIOR1.BYTE = 0x00; //
 TW.TCNT = 0x0000; // カウンタTCNTに0(初期値)を設定
 TW.GRD = 250; // トグル出力周期を設定
           // 250×8×0.625×2=250μS(4KHz)
 TW.GRA = 250; // TCNTをクリアする値を設定
}
// スイッチの状態読み込み
int SW_Read(void)
{
 int sw1,sw2;
 sw1 = IO.PDRB.BIT.B0; // スイッチが状態読み込み1回目
 wait(10); // 10mS待つ
 sw2 = IO.PDRB.BIT.B0; // スイッチが状態読み込み2回目
 return(sw1 & sw2); // 2回とも押されていれば1を返す
}
// nミリ秒待つウェイト関数
void wait(int time)
{
 int i; // ループカウンタ
 for(i = 0 ; i < time ; i++) // time回数分ループ
  wait1mS(); // 1ミリ秒のウェイト関数を呼び出す
}
// 1ミリ秒待つウェイト関数
void wait1mS(void)
{
 int i; // ループカウンタ
 for(i = 0 ; i < 2662 ; i++); // 1ミリ秒の間ループする
}


この文章は、“H8Tinyコンソールボードを動かしてみよう(C言語編)“からの抜粋です。
"CPU"と"プログラム"(初心者のために)
第1章 とりあえず動かす (H8Tiny入門その1)
第2章 LEDの点灯    (H8Tiny入門その2)
第3章 キーの読み込み  (H8Tiny入門その3)
■第4章 ブザーを鳴らす   (H8Tiny入門その4)