OutputCompare機能を使ってPWMを出力します。
前段:PWM(PluseWidthModulation)はLED照度やFANモータの回転数を制御するのに適した出力波形です。PWMとは。。。周期を一定とし、ON時間の幅(長さ)とOFF時間の幅(長さ)の比をDuty比と呼び、
その比を変更する方式です。
PWMの代表的な回路図とその制御波形を下図に示します。
負荷にLEDを接続したときを例に説明します。
スイッチング素子のON時間の間だけLEDは点灯状態になります。
OFF時間はLEDは消灯します。これを一定の周期で繰り返します。
周波数を100Hz以上にすると人間の目ではON/OFFをとらえることが出来ません。
ON時間を長くするとLEDは明るく見え、ON時間を短くするとLEDは暗く見えるようになります。
具体的にPICの設定をしていきます。
出力ポートの設定
PIC24FJ64GA002にはOutputCompareが1~5まであります。
PPS(PeripheralPinSelect)機能を使ってRB15にOC1(OutputCompare)を出力として割り当ててみます。
出力設定サンプルコードは↓
RPOR7bits.RP15R = 18;
RPOR7レジスタのRP15(14~12)の値を"18"にしています。”18"はOC1を意味しています。
詳細はデータシートDS39881Eのpage109のTable10-3の出力マップを参照。
周期を作成。1MHzのパルスを出力したい場合。
TIMER2をOutputCompareのクロックソースとして利用します。
1MHzの逆数は1μsecとなります。それに合わせて周期レジスタPR2の値を設定する必要があります。
PR2={1μsec/(Tcy×PS)}-1 ・・・①
PIC24FJ64GA002を内蔵クロックで最速駆動させた場合Fcyは16MHzとなります。
その逆数がTcy:0.0625μsecです。PS(ポストスケーラ)は"1"とします。
それぞれを式①に代入すると
PR2={1usec/(0.0625usec×1)}-1=15と求まります。
2で割り切れないのは都合が悪いのでPR2を"16"に修正します。
ON時間はOCxRレジスタで設定
OC1を使用しているのでOC1Rを使用しましょう。
レジスタに代入できる値の条件として
・PR2>OCxR。
・レジスタサイズは16bit。
以上から入力できる値は65535まで入るが16より小さい値にする必要があります。
今回はOC1Rは"8"とします。DUTY比は50%となります。
TMR2が"0"からカウントアップしてゆき、OC1Rで設定された値に達するとOC1ピンがLOWに切り替わります。
詳細はリファレンスマニュアルDS39706A_JPの16ページの図16-17を参照ください。
OCxCONレジスタでPWMモードに設定する。
OC1CONレジスタのOCMビットを"110"にするとPWMモードにすることが出来ます。
PWM設定サンプルコードは↓
OC1CONbits.OCM = 0B110;
回路図
RB15からパルス出力されるのを確認します。
RB15の出力をオシロスコープで確認します。
OC1R=6、DUTY比50%時の出力波形はこちら↓
ON時間とOFF時間が均等に繰り返されていることが確認できますね。
OC1Rを”2”に変更しています。Duty比は12.5%です。
OC1Rを"2"にするとON時間が短くなったことが確認できました。
全体のソースはこちら↓
// CONFIG2 #pragma config POSCMOD = NONE // Primary Oscillator Select (Primary oscillator disabled) #pragma config I2C1SEL = PRI // I2C1 Pin Location Select (Use default SCL1/SDA1 pins) #pragma config IOL1WAY = ON // IOLOCK Protection (Once IOLOCK is set, cannot be changed) #pragma config OSCIOFNC = ON // Primary Oscillator Output Function (OSC2/CLKO/RC15 functions as port I/O (RC15)) #pragma config FCKSM = CSDCMD // Clock Switching and Monitor (Clock switching and Fail-Safe Clock Monitor are disabled) #pragma config FNOSC = FRCPLL // Oscillator Select (Fast RC Oscillator with PLL module (FRCPLL)) #pragma config SOSCSEL = SOSC // Sec Oscillator Select (Default Secondary Oscillator (SOSC)) #pragma config WUTSEL = LEG // Wake-up timer Select (Legacy Wake-up Timer) #pragma config IESO = OFF // Internal External Switch Over Mode (IESO mode (Two-Speed Start-up) disabled) // CONFIG1 #pragma config WDTPS = PS32768 // Watchdog Timer Postscaler (1:32,768) #pragma config FWPSA = PR128 // WDT Prescaler (Prescaler ratio of 1:128) #pragma config WINDIS = OFF // Watchdog Timer Window (Windowed Watchdog Timer enabled; FWDTEN must be 1) #pragma config FWDTEN = OFF // Watchdog Timer Enable (Watchdog Timer is disabled) #pragma config ICS = PGx1 // Comm Channel Select (Emulator EMUC1/EMUD1 pins are shared with PGC1/PGD1) #pragma config GWRP = OFF // General Code Segment Write Protect (Writes to program memory are allowed) #pragma config GCP = OFF // General Code Segment Code Protect (Code protection is disabled) #pragma config JTAGEN = OFF // JTAG Port Enable (JTAG port is disabled) //== include #include "xc.h" int main(void) { //== CLOCK_setup ======================================================== CLKDIV = 0; //PLL_setup_1:1 //== AD1PCGF ========================================================== AD1PCFG = 0xffff; //all_digital //=== TRISA =========================================================== TRISA = 0x0000; //all_output //== TRISB ============================================================= TRISB = 0x0000; //all_output //== TIMER2 ========================================================= T2CONbits.TON = 0; //<15>Timer2_OFF T2CONbits.TSIDL = 1; //<13>idlemode_stop T2CONbits.TGATE = 0; //<6>gated_time_OFF T2CONbits.TCKPS = 0B00; //<5-4>PS1:1 T2CONbits.T32 = 0; //<3>32bitmode_off T2CONbits.TCS = 0; //<1>clock_source?internal IEC0bits.T2IE = 0; //<7>interrupt_disable IPC1bits.T2IP = 1; //<14-12>interrupt_priorty_0 TMR2 = 0x00; PR2 = 16; //<15-0>1usec/(0.0625u*1)-1=15 //== CompareOut(PWM) =================================== RPOR7bits.RP15R = 18; //<12-8>using_RP15_as_OC1(function_nunber_is_"18") OC1CONbits.OCTSEL = 0; //<3>Timer2_is_source_clock_OC1 OC1CONbits.OCM = 0B000; //<2-0>OS1_is_disable OC1R = 0; //<15-0>OC1R_zero //== timer2_start ========================================= T2CONbits.TON = 1; //<15>T2_enable OC1CONbits.OCM = 0B110; //<2-0>PWM_mode OC1R = 8; //<15-0>OC1_period_register while(1){ } }