.
PIC作品紹介

PIC開発

PICリンク

アクセスカウンタ
今日 : 139
昨日 : 535
総計 : 364121

.

■PWM (Pulse Width Modulation) とは

 PICはプログラムの実行とは独立して、パルス波形を出力することが出来ます。つまり、プログラムでどんなに時間がかかった処理をしていても、PWMを使えば常時波形を出力し続けることが出来るのです。


 緑色の矢印で示した部分と周期Tで示した部分の比をデューティ比といいます。緑が赤のちょうど半分の時にデューティ比が50%(または0.5)と呼ばれます。
 PICは周期とデューティ比を変化させることが出来ますが、ほとんどがデューティ比の変更用にPWMが使われます。緑の部分は電気を流している時間を表しているため、この部分が大きければ(デューティ比が1に近づくほど)、LEDは明るく光り、DCモーターは早く回転するでしょう。

■デューティ比を変えてみる

             

0x1a

 

0x41

 

0x5e

 

0x80


 これは実際にPICから出力したPWMの波形です。右へいくほどデューティ比が大きくなっていきます。下に書かれた数値はデューティ比設定レジスタに書き込んだ値です。(あとから説明します)

■PWMを使うための必要最小限のプログラム

//
// PWM test
//           Version 1.0

#include <16F88.h>
#fuses INTRC_IO, NOLVP, NOWDT, PUT, NOPROTECT, NOBROWNOUT, NOMCLR,CCPB3
#use FAST_IO(B)
#use FAST_IO(A)
#use delay (clock=4000000) //内部クロックを使用した4MHzモード

main(){

  set_tris_b(0);
  setup_ccp1(CCP_PWM);
  setup_timer_2(T2_DIV_BY_16,0x90,1);
  set_pwm1_duty(50);
  
  while(1){
  }  

必要な関数は setup_ccp1 , setup_timer2 , set_pwm1_duty です。

setup_ccp1(CCP_PWM)
PICはCompare/Capture/PWM の3つの機能をCCP1に割り当てています。setup_ccp1 で CCP1 をPWMとして使うことを指定します。

setup_timer_2(プリスケール値,period,1)
PWM波形の周期を設定します。周期はPICの動作クロック、プリスケール値、periodの3つの値によって変化し、次の式で求めることが出来ます。最後の1はポストスケール値ですが、PWMの場合は使われない値ですので何を書いても問題ありません(無視されます)。しかし0を書くとエラーになりますので1を書いておいてください。

 周期=(period+1)×4÷(PICクロック)×プリスケール値
 
 上の波形は 4MHz , period=0x90 , プリスケール16 なので、(0x90+1)×4÷(4×106)×16=0.0023[s] , 1/0.0023=434[Hz] とになります。テスタは423.5[Hz]と表示していますので、だいたい合っていると思います。
 
  
 PICを8MHz駆動,プリスケール値16に設定した時の period と周波数の関係

 プリスケール値には下記の4つの定数を設定できます。
  T2_DISABLED : タイマー2 を使用しない
  T2_DIV_BY_1 : プリスケーラ設定 1/1
  T2_DIV_BY_4 :          〃  1/4
  T2_DIV_BY_16 :         〃  1/16

 periodは8ビットの数値/変数を設定します。実質、この値で周期を設定すると思えばいいでしょう。

set_pwm1_duty 
デューティを設定します。0x3FF(10ビット分)までの値を取ることが出来ます。一般的なデューティ比50%の波形を出力する場合には0x200をセットします。

#fuses
16F628/648/819などはCCP1端子がRB3に割り当てられているのですが、PIC16F88はCCP1をRB0またはRB3のどちらかへ割り当てることが出来ます。この指定を#fusesで行うのですが、何も設定しないときはRB0がCCP1になりますので注意してください。RB3をCCP1にする時は #fusesに CCPB3 を書き加えます。

■PWMで音階を!

それではPWMを使ってドレミファソラシドと演奏させてみます。プログラムは次のとおりです。

//
// PWM test
//           Version 1.1
#include <16F88.h>
#fuses INTRC_IO, NOLVP, NOWDT, PUT, NOPROTECT, NOBROWNOUT, NOMCLR,CCPB3
#use FAST_IO(B)
#use FAST_IO(A)
#use delay (clock=8000000)

main(){
  long duty=0x150;
  
  set_tris_b(0);
  setup_ccp1(CCP_PWM);
  set_pwm1_duty(duty);
  
  while(1){
    setup_timer_2(T2_DIV_BY_16,238,1); //C
  delay_ms(3000);  
    setup_timer_2(T2_DIV_BY_16,212,1); //D
  delay_ms(3000);
    setup_timer_2(T2_DIV_BY_16,189,1); //E
  delay_ms(3000);  
    setup_timer_2(T2_DIV_BY_16,178,1); //F
  delay_ms(3000);  
    setup_timer_2(T2_DIV_BY_16,159,1); //G
  delay_ms(3000);  
    setup_timer_2(T2_DIV_BY_16,142,1); //A
  delay_ms(3000);  
    setup_timer_2(T2_DIV_BY_16,130,1); //B
  delay_ms(3000);  
    setup_timer_2(T2_DIV_BY_16,119,1); //C
  delay_ms(3000);  
  
  }  

このようにsetup_timer_2を使って周期を変更するだけでOKです。
YouTubeのビデオで周期を変化させると音階が変化するのが確認できます。ただし、8MHzの内蔵発振器を使用しているためPWMの周期が早くなっています。そのため音階が高く、デジカメのマイクで拾い切れていないようです・・・。ボリュームを少し大きめにして再生してください。



. .