今回は、基礎編で製作したタイマープログラムにPWM機能を実装します。
実装する内容
前回までに、PWM制御方法を二通り確認しました。一つは、__delay_us()を使用して時間制御を含めて全てプログラムで制御する方法、もう一つは、PICマイコンのPWM制御機能を使って制御する方法です。
タイマープログラムにPWM機能を実装するのは、ちょっと無理矢理感がありますが、そこをなんとか実装してみようと思います。
実装は「タイマーで時間が来たらブザーを鳴らすと同時にLEDをスムーズに点滅させる」という内容にします。
基礎編で製作したタイマーは、時間が来るとブザーを鳴らし、LEDを点灯させる、という動作でした。この「LEDを点灯させる」という部分を「PWM機能を使ってスムーズに点滅させる」という動作に変更します。
実装仕様
せっかくPICマイコンのPWM制御方法を確認しましたので、その方法で実装します。実装仕様としては以下のように点滅制御させることにします。
- PWMの周期は1ms
- LEDの明るさの制御は、デューティ比を5%〜100%の間で変えることにより行う
- デューティ比は1ms毎に0.1%ずつ変える。5%→100%まで1ms毎に0.1%ずつ大きくし、100%→5%まで1ms毎に0.1%ずつ小さくする、という動作を繰り返す
なお、デューティー比は0%〜100%で変化させても良いと思います。5%から開始しているのは特に意味はありませんので、一度動作させてみてご自分の好きな点灯パターンで調整してみてください。
プログラム
前回、PWM制御方法を詳しく説明しましたので、この動作プログラムは特に詳しい説明は必要ないと思います。特にデューティ比の設定、
/* * File: main.c * 変更履歴 * 2016.11.20: スイッチ制御部分を追加 * 2016.12.05: 時間計測とブザー制御部分を追加 * 2017.01.15: 設定時間が来たらLEDをPWM制御に変更 */ #include <xc.h> // PIC12F1822 Configuration Bit Settings // CONFIG1 #pragma config FOSC = INTOSC // Oscillator Selection (INTOSC oscillator: I/O function on CLKIN pin) #pragma config WDTE = OFF // Watchdog Timer Enable (WDT disabled) #pragma config PWRTE = OFF // Power-up Timer Enable (PWRT disabled) #pragma config MCLRE = OFF // MCLR Pin Function Select (MCLR/VPP pin function is digital input) #pragma config CP = OFF // Flash Program Memory Code Protection (Program memory code protection is disabled) #pragma config CPD = OFF // Data Memory Code Protection (Data memory code protection is disabled) #pragma config BOREN = ON // Brown-out Reset Enable (Brown-out Reset enabled) #pragma config CLKOUTEN = OFF // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin) #pragma config IESO = OFF // Internal/External Switchover (Internal/External Switchover mode is disabled) #pragma config FCMEN = OFF // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor is disabled) // CONFIG2 #pragma config WRT = OFF // Flash Memory Self-Write Protection (Write protection off) #pragma config PLLEN = OFF // PLL Enable (4x PLL disabled) #pragma config STVREN = OFF // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will not cause a Reset) #pragma config BORV = LO // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.) #pragma config LVP = OFF // Low-Voltage Programming Enable (High-voltage on MCLR/VPP must be used for programming) // クロック周波数指定 // __delay_ms()関数が使用する #define _XTAL_FREQ 1000000 void main(void) { // PICマイコン設定 OSCCON = 0b01011010; // 内部クロック周波数を1MHzに設定 ANSELA = 0b00000000; // すべてのピンをデジタルモードに設定 TRISA = 0b00001000; // すべてのピンを出力モードに設定(ただしRA3ピンは常に入力モード) // 変数宣言 unsigned short timer; // 時間計測 unsigned short duty; // PWMのデューティーサイクル // LEDを点灯する LATA5 = 1; // ブザーをOFFにする LATA4 = 0; // スイッチが押されるまで待つ while(RA3){ } // LED点滅処理(3秒間繰り返す) for(timer=0; timer<3; timer++){ // LEDを950ms消灯する LATA5 = 0; __delay_ms(950); // LEDを50ms点灯する LATA5 = 1; __delay_ms(50); } // ブザーをONにする LATA4 = 1; // LEDをPWM制御してスムーズな点滅制御をする // PWM機能のピン割り当て設定 APFCONbits.CCP1SEL = 1; // PWM機能をRA5ピンに設定 CCP1CONbits.CCP1M = 0b1100; // PWM機能を有効、active-highに設定 CCP1CONbits.P1M = 0b00; // RA2ピンはGPIOに設定 // 周期(1ms)とデューティーサイクル(0.5ms)の設定 T2CONbits.T2CKPS = 0b00; // プリスケーラを1:1に設定 PR2 = 249; // 周期を1msに設定 (249 + 1) x 4 x 1us = 1000us = 1ms CCPR1L = 500/4; // デューティーサイクルを0.5msに設定 CCP1CONbits.DC1B = 500; // PWM制御スタート T2CONbits.TMR2ON = 1; // LEDをPWM制御 // デューテー比は10%〜100%の制御にする while(1) { // 5% -> 100%の制御 for(duty=50; duty<=1000; duty++) { CCPR1L = duty / 4; // 上位8ビット CCP1CONbits.DC1B = duty; // 下位2ビット __delay_ms(1); } // 100% -> 5%の制御 for(duty=1000; duty>=50; duty--) { CCPR1L = duty / 4; // 上位8ビット CCP1CONbits.DC1B = duty; // 下位2ビット __delay_ms(1); } } // 以下の命令は実行されない return; }
動作確認
プログラムをビルドしてPICマイコンに書き込んで動作確認しましょう。
ところで、LEDの明るさの変化をよくみると、確かにLEDの発光がだんだん明るくなったり暗くなったりしていますが、なんとなく、すぐに明るくなって、しばらく明るい期間が続き、急に暗くなる、というような動作に見えるかもしれません。
これは、例えばデューティー比が50%の場合、確かに明るさは半分になっているはずなのですが、人間の目にはLEDの明るさが半分になったようには見えないためです。人間の目は明るい方の変化はそれほど感じませんが、暗い方の変化は敏感に感じるようになっています(数学的に説明すると、対数的な感度を持っていて、これは視覚だけではなく、聴覚も同じです)。
LEDのPWM制御は1次関数でデューティー比を制御していますが、人間の目の感度は対数関数であるため、ズレが生じています。
動作確認するとは言っても、目視では正しくPWM制御できているかわかりません。そこで、今回もオシロスコープ(電圧の波形の測定装置)でRA5ピンの電圧を確認しました。
PWM制御ではデューティー比を1ms毎に変えていますので、どのように変化しているか、今回は動画をアップしますので確認してみてください。
更新履歴
日付 | 内容 |
---|---|
2017.1.19 | 新規投稿 |
2018.11.30 | プログラムテンプレートをMPLABX IDE v5.10に更新 |