目次8章.機能が豊富なPICを使う(PIC12F683)>(7)PWM機能を使ってスピーカを鳴らす(ドレミ〜を演奏)

PWM機能を使ってスピーカを鳴らす (PIC12F683)
(ドレミ〜を演奏)

更新日2006.4.5

前のページでは、PIC12F683のPWM機能を使ってスピーカから単音を出す実験を行いました。

今回は、その応用で「ドレミファソラシド」を演奏します。

実験回路
今回の実験で使用する回路です。(前のページと同じです)
5番ピン(GP2/AN2/T0CKI/INT/COUT/CCP1)にスピーカを接続します。
2番ピン(GP5)のLEDは、0.5秒毎に点滅させます。

ブレッドボードの右端にあるLEDと抵抗は、回路図にはありませんが電源ランプとして使っています。

プログラムの仕様

今回作成するプログラムは、「ドレミファソラシド」を0.5秒間隔で演奏するというものです。

音は、前回と同じでPICのPWM機能を使用して矩形波を出力します。
また、0.5秒の時間はTMR0割り込みを使用して作ります。
クロックは、4MHzの内部クロックを使用しました。

プログラムの作成
「ドレミファソラシド」の音を出す

下図ように、周期を変えずにパルスの幅を変える方式を、PWM(Pulse Width Modulation:パルス幅変調)と言います。(前ページの繰り返し)

音の高さ(ドレミ・・)を変えるには、周波数を変える必要があります。周波数を変えるには、パルス幅ではなく周期を変える必要があります。

PIC12F683では、以下のようにPWMを実現しています。(前ページの繰り返し)

PR2レジスタで周期を指定し、CCPR1Lレジスタでデューティを指定します。

という事は、デューティを一定にして周期を可変にする事も可能です。
今回は、デューティは変えずに、周期を変えることで「ドレミ〜」を演奏します。

具体的には、以下の表のように周期をPR2レジスタに設定します。

音階周波数
(Hz)
波長(mS)PR2
レジスタ
261.63.823239
293.73.405213
329.63.034190
ファ349.22.864179
392.02.551159
440.02.273142
493.92.025126
523.21.911119
波長と周波数の関係は以下の式で表せます。
 波長(mS)=1000(mS)/周波数(Hz)

PR2レジスタへの設定値については、以下で説明します。

CCPR1Lレジスタには、PR2レジスタ設定値の1/2を設定します。

PR2レジスタ(周期)の設定値

PR2レジスタに設定する値は、TMR2のカウント数です。

TMR2は、「1命令サイクル×プリスケーラ倍率」毎にカウントアップされます。
プリスケーラは16倍としました。また、クロックは4MHzの内部クロックを使用しました。

この事からTMR2のカウントアップ間隔は以下のようになります。

クロック4MHz
1命令サイクル(1秒/4MHz)×4クロック=1uS(マイクロ秒)
TMR2プリスケーラ16倍
TMR2カウントアップ間隔1uS×16=16uS

PR2レジスタに設定する値は、TMR2のカウント数ですので、設定値は次の式で表せます。

PR2レジスタ設定値=波長(uS)/TMR2カウントアップ間隔(uS)
先ほどのドレミの表で、低い「ド」の波長は3.823mSですので、この式に当てはめてPR2レジスタの設定値を求めます。

PR2レジスタ設定値=3.823(mS)×1000(uS)/16(uS)=239
他の音階も同じように計算します。

0.5秒の時間を作る

0.5秒間隔で音階を変えますが、この時間はTMR0割込みを使います。

TMR0割込みの設定は以下の通りです。
TMR0レジスタ0(フリーラン:初期処理で0を設定するのみ)
プリスケーラ使用しない
TMR0割込み間隔は次のようになります。
クロック4MHz
1命令サイクル(1秒/4MHz)×4クロック=1uS(マイクロ秒)
TMR0割込み間隔1uS×1×256=256uS

TMR0割込みルーチンで、39回カウントすることで約10mS(9.984mS)の時間を作り、 10mSを50回カウントする事で約500mS(499.2mS)の時間を作ります。

プログラムの作成

今回のプログラムのフローです。

<メインルーチン><割込みルーチン(TMR0割込み)>

PICの初期化(使用するレジスタ)

今回のプログラムで初期設定するレジスタと、その設定値について説明します。
ここでは、今回設定する値を中心に説明します。
レジスタのもう少し詳しい説明は、「PIC12F683のレジスタ(特殊レジスタ:SFR)」を参照して下さい。

<GPIOレジスタ>
ビットBit7Bit6Bit5Bit4Bit3Bit2Bit1Bit0
記号--GP5GP4GP3GP2GP1GP0
設定値

ポート(GP0〜GP5)のON/OFFを制御するレジスタで、0をセットするとOFF(LEDは消灯),1をセットするとON(LEDは点灯)になります。
初期値としては、全て0にします。
Bit2(GP2/CCP1)はPWMの出力ですので、初期化した後は操作不要です。
Bit5(GP5)はLEDを接続しており、0.5秒毎にON/OFFします。

<TRISIOレジスタ>
ビットBit7Bit6Bit5Bit4Bit3Bit2Bit1Bit0
記号--TRISIO5TRISIO4TRISIO3TRISIO2TRISIO1TRISIO0
設定値

ポート(GP0〜GP5)を入力で使うか出力で使うかを指定します。

:該当ポートは出力
:該当ポートは入力

全て0をセットします。(尚、Bit3,6,7は設定が無視されます。)

<CMCON0レジスタ>
ビットBit7Bit6Bit5Bit4Bit3Bit2Bit1Bit0
記号-COUT-CINVCISCM2CM1CM0
設定値

コンパレータの動作を設定するために使用しますが、今回はGP0〜2をデジタル入出力として使用しますので、CM0〜CM2には1を設定します。

<ANSELレジスタ>
ビットBit7Bit6Bit5Bit4Bit3Bit2Bit1Bit0
記号-ADCS2ADCS1ADCS0ANS3ANS2ANS1ANS0
設定値

ANSELレジスタでは、アナログ入力(A/D変換)の設定を行います。
今回は、AN0〜AN3(GP0,1,2,4)はデジタル入出力で使用しますので、全て0にします。

<OSCCONレジスタ>
ビットBit7Bit6Bit5Bit4Bit3Bit2Bit1Bit0
記号-IRCF2IRCF1IRCF0OSTSHTSLTSSCS
設定値

OSCCONレジスタでは、オシレータの動作モードを設定します。
今回は4MHzで動作させますので、IRCF2,IRCF1に1を設定します。

<PR2レジスタ>
ビットBit7Bit6Bit5Bit4Bit3Bit2Bit1Bit0
記号PWM周期
設定値239(十進数)

PR2レジスタでは、PWMの周期を指定します。初期設定では、低い「ド」の音である239を設定します。

<CCPR1Lレジスタ>
ビットBit7Bit6Bit5Bit4Bit3Bit2Bit1Bit0
記号PWMデューティ
設定値119(十進数)

CCPR1Lレジスタでは、PWMのデューティ(パルス幅)を指定します。周期(PR2レジスタ設定値)の1/2を設定します。
初期値は、119を設定します。

<CCP1CONレジスタ>
ビットBit7Bit6Bit5Bit4Bit3Bit2Bit1Bit0
記号--DC1B1DC1B0CCP1M3CCP1M2CCP1M1CCP1M0
設定値

CCP1CONレジスタでは、CCPモジュールの動作を指定します。
今回は、PWMモードで使用しますので、CCP1Mxに1100を設定します。

<T2CONレジスタ>
ビットBit7Bit6Bit5Bit4Bit3Bit2Bit1Bit0
記号-TOUTPS3TOUTPS2TOUTPS1TOUTPS0TMR2ONT2CKPS1T2CKPS0
設定値

T2CONレジスタでは、TMR2のプリスケーラ(T2CKPSx)とTMR2動作開始(TMR2ON)を設定します。

<OPTIONレジスタ>
ビットBit7Bit6Bit5Bit4Bit3Bit2Bit1Bit0
記号^GPPUINTEDGT0CST0SEPSAPS2PS1PS0
設定値

TMR0のクロックソースは内部クロックですので、T0CSには0を設定します。
また、TMR0のプリスケーラは使用しませんので、PSAに1を設定します。
他は0をセットします。

<INTCONレジスタ>
ビットBit7Bit6Bit5Bit4Bit3Bit2Bit1Bit0
記号GIEEEIET0IEINTEGPIET0IFINTFGPIF
設定値

INTCONレジスタでは、割込みに関する設定を行います。
TMR0割込みを有効にするため、GIEとT0IEに1を設定します。

コンフィグレーションビット(__CONFIG命令の設定)

__CONFIG命令では以下の記述をします。

__CONFIG _CP_OFF & _CPD_OFF & _WDT_OFF & _BOD_ON & _IESO_OFF& _PWRTE_ON & _INTOSCIO & _MCLRE_OFF

_CP_OFFプログラムメモリコードプロテクトしない
_CPD_OFFEEPROMメモリコードプロテクトしない
_WDT_OFFウォッチドックタイマ使用しない
_BOD_ON電源電圧低下監視を有効にする
_IESO_OFF内部・外部切り替えモード無効
_PWRTE_ONパワーアップタイマ有効
_INTOSCIOオシレータは内部クロック使用(2番ピン:GP5,3番ピン:GP4)
_MCLRE_OFFマスタクリア無効(4番ピンをGP3として使用)

プログラム全体
上記の処理を組み込んだプログラムはこちらです。
メモ帳などのテキストエディタに取り込んで、P683PWM2.ASMという名で保存し、MPLABでアセンブル&PICライタでPICに書き込んで動かしてみて下さい。

今まで、PIC16F84Aを使用していた場合は、MPLABのプロジェクトウィザードで「PIC12F683」を選択して下さい。
また、PICライタでも同様に「PIC12F683」を選択して下さい。