目次>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.6 | 3.823 | 239
| レ | 293.7 | 3.405 | 213
| ミ | 329.6 | 3.034 | 190
| ファ | 349.2 | 2.864 | 179
| ソ | 392.0 | 2.551 | 159
| ラ | 440.0 | 2.273 | 142
| シ | 493.9 | 2.025 | 126
| ド | 523.2 | 1.911 | 119
|
|
波長と周波数の関係は以下の式で表せます。
波長(mS)=1000(mS)/周波数(Hz)
PR2レジスタへの設定値については、以下で説明します。
|
CCPR1Lレジスタには、PR2レジスタ設定値の1/2を設定します。
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秒間隔で音階を変えますが、この時間は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割込み)>
| | |
|
今回のプログラムで初期設定するレジスタと、その設定値について説明します。
ここでは、今回設定する値を中心に説明します。
レジスタのもう少し詳しい説明は、「PIC12F683のレジスタ(特殊レジスタ:SFR)」を参照して下さい。
- <GPIOレジスタ>
-
ビット | Bit7 | Bit6 | Bit5 | Bit4 | Bit3 | Bit2 | Bit1 | Bit0
| 記号 | - | - | GP5 | GP4 | GP3 | GP2 | GP1 | GP0
| 設定値 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
|
ポート(GP0〜GP5)のON/OFFを制御するレジスタで、0をセットするとOFF(LEDは消灯),1をセットするとON(LEDは点灯)になります。
初期値としては、全て0にします。
Bit2(GP2/CCP1)はPWMの出力ですので、初期化した後は操作不要です。
Bit5(GP5)はLEDを接続しており、0.5秒毎にON/OFFします。
- <TRISIOレジスタ>
-
ビット | Bit7 | Bit6 | Bit5 | Bit4 | Bit3 | Bit2 | Bit1 | Bit0
| 記号 | - | - | TRISIO5 | TRISIO4 | TRISIO3 | TRISIO2 | TRISIO1 | TRISIO0
| 設定値 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
|
ポート(GP0〜GP5)を入力で使うか出力で使うかを指定します。
-
全て0をセットします。(尚、Bit3,6,7は設定が無視されます。)
- <CMCON0レジスタ>
-
ビット | Bit7 | Bit6 | Bit5 | Bit4 | Bit3 | Bit2 | Bit1 | Bit0
| 記号 | - | COUT | - | CINV | CIS | CM2 | CM1 | CM0
| 設定値 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1
|
コンパレータの動作を設定するために使用しますが、今回はGP0〜2をデジタル入出力として使用しますので、CM0〜CM2には1を設定します。
- <ANSELレジスタ>
-
ビット | Bit7 | Bit6 | Bit5 | Bit4 | Bit3 | Bit2 | Bit1 | Bit0
| 記号 | - | ADCS2 | ADCS1 | ADCS0 | ANS3 | ANS2 | ANS1 | ANS0
| 設定値 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
|
ANSELレジスタでは、アナログ入力(A/D変換)の設定を行います。
今回は、AN0〜AN3(GP0,1,2,4)はデジタル入出力で使用しますので、全て0にします。
- <OSCCONレジスタ>
-
ビット | Bit7 | Bit6 | Bit5 | Bit4 | Bit3 | Bit2 | Bit1 | Bit0
| 記号 | - | IRCF2 | IRCF1 | IRCF0 | OSTS | HTS | LTS | SCS
| 設定値 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 0
|
OSCCONレジスタでは、オシレータの動作モードを設定します。
今回は4MHzで動作させますので、IRCF2,IRCF1に1を設定します。
- <PR2レジスタ>
-
ビット | Bit7 | Bit6 | Bit5 | Bit4 | Bit3 | Bit2 | Bit1 | Bit0
| 記号 | PWM周期
| 設定値 | 239(十進数)
|
PR2レジスタでは、PWMの周期を指定します。初期設定では、低い「ド」の音である239を設定します。
- <CCPR1Lレジスタ>
-
ビット | Bit7 | Bit6 | Bit5 | Bit4 | Bit3 | Bit2 | Bit1 | Bit0
| 記号 | PWMデューティ
| 設定値 | 119(十進数)
|
CCPR1Lレジスタでは、PWMのデューティ(パルス幅)を指定します。周期(PR2レジスタ設定値)の1/2を設定します。
初期値は、119を設定します。
- <CCP1CONレジスタ>
-
ビット | Bit7 | Bit6 | Bit5 | Bit4 | Bit3 | Bit2 | Bit1 | Bit0
| 記号 | - | - | DC1B1 | DC1B0 | CCP1M3 | CCP1M2 | CCP1M1 | CCP1M0
| 設定値 | 0 | 0 | 0 | 0 | 1 | 1 | 0 | 0
|
CCP1CONレジスタでは、CCPモジュールの動作を指定します。
今回は、PWMモードで使用しますので、CCP1Mxに1100を設定します。
- <T2CONレジスタ>
-
ビット | Bit7 | Bit6 | Bit5 | Bit4 | Bit3 | Bit2 | Bit1 | Bit0
| 記号 | - | TOUTPS3 | TOUTPS2 | TOUTPS1 | TOUTPS0 | TMR2ON | T2CKPS1 | T2CKPS0
| 設定値 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1
|
T2CONレジスタでは、TMR2のプリスケーラ(T2CKPSx)とTMR2動作開始(TMR2ON)を設定します。
- <OPTIONレジスタ>
-
ビット | Bit7 | Bit6 | Bit5 | Bit4 | Bit3 | Bit2 | Bit1 | Bit0
| 記号 | ^GPPU | INTEDG | T0CS | T0SE | PSA | PS2 | PS1 | PS0
| 設定値 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0
|
TMR0のクロックソースは内部クロックですので、T0CSには0を設定します。
また、TMR0のプリスケーラは使用しませんので、PSAに1を設定します。
他は0をセットします。
- <INTCONレジスタ>
-
ビット | Bit7 | Bit6 | Bit5 | Bit4 | Bit3 | Bit2 | Bit1 | Bit0
| 記号 | GIE | EEIE | T0IE | INTE | GPIE | T0IF | INTF | GPIF
| 設定値 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 0
|
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_OFF | EEPROMメモリコードプロテクトしない
| _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」を選択して下さい。
|