PIC16F1938でソフトPWMの周波数が合わない理由と対策(ハードPWMとの比較)

PWM

今回は、ハードPWMとソフトPWMを作って比較してみたところ
想像以上に大きな違いが出ました。

特にソフトPWMでは、周波数が思った通りに出ず、
試行錯誤することになりました。

ソフトPWMでは、
タイマー設定や割り込みの影響を強く受けるため
思った通りの周波数にならないことがあります。

その原因と対策についてもまとめます。

今回の回路

前回使っていたPINとは違うPINにしました。
PINを変えるという面倒な作業を入れることで、
もう一度データシートを見返して、
レジスタの設定を見返すためです。
(コピペだと勉強にならないので)

回路のポイントは、

入力
①VOL1_ADC:RA1 (AN1)
②VOL2_ADC:RA2 (AN2)
③OFFSET_SAVE_SW:RB4 ←今回は未使用

出力
①LED1 : RC2 (CCP1) → ハードPWM用
②LED2 : RB1 → ソフトPWM用

使うのはこれだけです。

VOL1_ADCを回してハードPWMを使用しLED1を調光させる。
VOL2_ADCを回してソフトPWMを使用しLED2を調光させる。
という感じです。

今回のコード

今まではコード全部を載せていたのですが、
さすがに長いと思うので、ポイントだけを抑えたいと思います。

ハードPWM制御部は前回と同じです。
もちろんADCのPINが変わっているので、
そこだけ回路に合わせて変更しました。

c

void SOFT_PWM_Init(void){
    TRISBbits.TRISB1 = 0;      //RB1を出力に設定
  LATBbits.LATB1 = 0;      //RB1の出力をLOWにする

    OPTION_REGbits.TMR0CS = 0;   //Timer0のクロック源を内部クロックに設定
    OPTION_REGbits.PSA = 0;    //プリスケーラをTimer0モジュールに割り当てる
    OPTION_REGbits.PS = 0b000;  //Timer0のプリスケーラを1:2に設定

    TMR0 = 246;          //TMR0のカウントを246からスタート
    INTCONbits.TMR0IF = 0;     //Timer0割り込みフラグをクリア
    INTCONbits.TMR0IE = 1;     //TMR0を使用
    INTCONbits.PEIE = 1;      //周辺機器の割り込みをイネーブル(今回は不要)
    INTCONbits.GIE = 1;        //グローバルな割り込みをイネーブル
}
c

void SOFT_PWM_SET(void){
    ADCON0bits.CHS = 0b00010;         //AN2選択(VOL2_ADC 読み取り用)
    __delay_us(10);                   //コンデンサの充電待ち(回路の安定)
    ADCON0bits.GO_nDONE = 1;     //A/D変換中
    while(ADCON0bits.GO_nDONE);       //A/D変換終了待ち

// A/D変換した値を16bitのadcに格納
    unsigned int adc = (unsigned int) ADRESH << 8 | ADRESL;

// 100段階にスケーリング
    soft_duty = (adc * 99UL) / 1023UL;        
}


void __interrupt() isr(void){
    if(INTCONbits.TMR0IF == 1){     //Timer0のオーバーフローフラグの確認
        TMR0 = 246;           //TMR0を246にセット(246から256まで数える)
        count++;                        //グローバルで設定済みの変数countを+1する
        if(count >= 100) count = 0;   //countが100以上でクリア
        
//countがsoft_duty未満でRB1をHigh、以上でLowにする
//つまり、countの比率でデューティ比を作っています
        if(count < soft_duty){
            LATBbits.LATB1 = 1;
        }else{
            LATBbits.LATB1 = 0;
        }
        
        INTCONbits.TMR0IF = 0;            //
        
    }
}

今回のソフトPWMは、
Timer0のオーバーフローの回数を
変数countで数え、
countの値がADCの値になるまではHigh、
countの値がADCを超えたらLow
という仕組みです。

TMR0 = 246 にした根拠

Fosc = 8MHz

Fosc / 4 = 2MHz ⇒ 1命令サイクル = 0.5μs

プリスケーラ 1:2なら
Timer0 1カウント = 1μs

TMR0 = 246から始めると、
8bit(28 = 256) の Timer0 がオーバーフローするまで、
256 – 246 = 10カウント = 10μs

分解能100 ステップであるので (count が Timer0 のオーバーフローを 100まで数える)
10μs × 100 = 1000μs = 1ms

周波数 1kHz = 1000Hz は、
1/1000 秒 = 1ms
である。

すなわち、TMR0 = 246とすることによって、
周波数を1kHzにすることを目的としている。


これで、ハードPWMもソフトPWMも共に
周波数1kHzで動いてくれるはず!
でもCPUを使ってPWMを生成するため、
割り込み処理の時間や処理内容によって
周波数がズレる可能性はありと思います。

オシロスコープの確認

いやズレすぎ…
36Hzて…

分かると思いますが、上の青がソフトPWM、下のピンクがハードPWMです。
下のピンクは約1kHzとなっていました。

ちなみに
36Hzでも、肉眼ではチラついているようには見えません。

ただし、カメラで見るとチラつきが確認できるため、
用途によっては問題になる可能性があります。

(舞台照明や撮影用途では特に注意が必要です。)

ここからできるだけ1kHzにできるように試行錯誤しました。

割り込み関数の中身を

c

void __interrupt() isr(void){
    if(INTCONbits.TMR0IF == 1){
        TMR0 = 246;
        count++;
        if(count >= 100) count = 0;
        
        INTCONbits.TMR0IF = 0;
        
    }
}

だけにして、下のコードはmainのなかに入れました。

c

if(count < soft_duty){
            LATBbits.LATB1 = 1;
}else{
            LATBbits.LATB1 = 0;
}

結果は、オシロスコープを見るまでもなくNG。
目で見て点滅していました。

また上の if 文を __interrupt()に戻し、以下のことを行いました。

TMR0 = 10 ⇒  39Hz
TMR0 = 100 ⇒  61Hz
TMR0 = 200 ⇒  154Hz
TMR0 = 250 ⇒  37Hz

一番最後だけ腑に落ちません。
でもこれはカウントが 6 や 10だと,
6 × 1μs = 6μs
10 × 1μs = 10μs
となります。
おそらく、割り込み処理そのものの実行時間や、
LATの書き換え処理などの
オーバーヘッドが加わることで、
理論値よりも周期が長くなっていると考えられます。

プリスケーラ設定を変更するにもこれ以上早くはできません。
そのため、分解能を下げることにしました。
つまり、count変数の値をいろいろと試し、
一番1kHzに近づけたのは次の条件でした。

c

TMR0 = 235;
if(count >= 34) count = 0;

黄色がソフトPWM、水色がハードPWMです。

でも、やはり分解能が小さいので、
LEDの付き始めがかなり明るかったです。

ハードPWMの分解能は500、
一報ソフトPWMの分解能は34。

この差が、LEDの立ち上がりの滑らかさの違いとして体感できました。

やはり、ハードPWMの方が設定は楽だし、
調光もきれい。

ただし、ソフトPWMはピンの自由度が高く
(すべてのI/Oピンが使える)、
専用モジュールを使わずに
PWMを生成できるというメリットもあります。

そのため、
・出力ピンに制約がある場合
・複数チャンネルを柔軟に扱いたい場合
などでは、ソフトPWMが有効になる場合もあります。

今日の学び

ソフトPWMは設定値の選定が大変。

ソフトPWMでは、理論計算通りに周波数が出ないことがある。

もしここにさらにmainの中にいろいろな処理を増やすとなると、
さらに数値の変更が必要になる可能性もあるでしょうし、
ハードPWMのありがたさを肌で感じました。

でも、今回頑張ったことで、
PWMの分解能と周波数がトレードオフであることは
よくわかりました。

ソフトPWMは、タイマー設定と割り込み処理の影響を強く受けます。
周波数と分解能のバランス設計が非常に重要だと分かりました。

コメント

タイトルとURLをコピーしました