最近おサボりして、なかなか進展の無かった自宅PVシステムについて久しぶりに検討状況を記録する。サボっていたと言っても、あれやこれやと頭の中では思考をしており、ようやく整理できてきたのできちんと書き留めておこうと思った次第。
DCDCコンバータにおいてPWMを用いて電圧を制御している。電圧や電流の測定値をフィードバックしてスイッチングデバイスのパルス幅を制御する方法。PWMクロックはインダクタのサイズがあまり大きくならないよう40kHzとしている。クロック周期は25μsと言うことになる。
利用しているPICマイコンは、80~90円と安価なものであり、AD変換機能はマルチプレクサタイプである。AD変換モジュールは高速でないため、入力ラインをADモジュールに接続してから安定するまで8μs待たねばならず、AD変換するのに12μsかかり、ひとつの測定値を得るために最低20μsの時間を要する。
現在開発中のDCDCコンバータには、計測ポイントは3~4ヶ所ある。厳密な制御をしようとすれば、全てのポイントを同時に計測しなければならないが、そんな機能のチップは高価で個人で利用するためにほいほい買えるものではない。諸々の事情でチップを壊してしまった場合に激しく落ち込むのは避けたい。
そのような背景もあり、PWMクロックと同期して計測する方法は、AD変換の速度を厳密に計測してPWMサイクル内に確実に収まるよう処理を設計しなければならないため少々面倒くさい。これまでは、そんなことは考慮しなくても良い方法に逃げてきた。
先日、とあるデジタル電源制御のセミナに参加して、PWM同期制御方式に大きなメリットがあることにはたと気付いてしまった。
これまでのPWMクロックに非同期で定期的に計測する方法では、図1のピンクの矢印のように、たまにノイズ部分に当たってしまうことがある。そのため、先ずはノイズを最大限抑制するように回路を改善し、更に、計測値は連続した複数の値の移動平均を取り、ノイズの影響を抑制するように処理してきた。
しかし、発想を逆転させ、ノイズは在ることを前提とし、ノイズのないタイミングで計測すれば、ノイズが多少大きくても正しく制御する事ができるのではないか。つまり、ノイズは、PWMパルスの立上がり時に発生し1μs程度で収束するため、収束した後のタイミングで計測すれば、ノイズがあったとしても制御においてノイズの影響を回避できるはずであると。
今まで苦労して作り上げた、少ないメモリを駆使し、連続4ポイントの移動平均を計算するロジックは、それはそれで完成されたものであり、捨てがたい愛着がある。しかし、どう考えても、今後のことを考えれば、新しいロジックの方が汎用性は高そうである。
意を決して、新しいロジックでプログラムを再構成することにした。
以上が、ここしばらく、頭の中であれやこれやと思考をめぐらしてたどり着いた結論である。
結論が出たからには、さっそく設計。しかし、PWMに同期させて計測するには、確実にPWM周期内に処理が終了するようプログラムを組まねばならない。理論的には1命令4クロックで処理するCPUということは分かっているが、Cでプログラムして、コンパイルした結果の速度となるので、コンパイル結果の機械語のプログラムでクロック数をカウントしなければならない。
う~~~む。。。。面倒だ。。。
こんなときのためにオシロスコープを購入したのだった。処理の開始時、終了時でポートのON/OFFをしてやれば、視覚的にタイミングを確認することができるはず。さっそく、PWMクロックと、同期させたAD変換の様子を確認してみた。
1ポイントの計測値を得るのにAD変換で約12μsかかる。取得した値を変数に格納するなどの処理を合わせると概ね16μsとなる。マルチプレクサ切換え後のウェイトが8μs必要な部分と合わせると、24μsとなってしまい、PWM周期25μs以内に収まるか微妙なところとなる。
そこで、計測した直後に、次のチャネルに切換える処理を行えば、次のPWMクロック立上がりまで8μs以上の時間が確保できるはず。そのようにロジックを組んでみた。結果が図2のとおり。
青いグラフがPWM、赤いグラフがAD変換の様子である。PWMの立上りからノイズが収束するまで4μs程度待って、計測開始している様子がよくわかる。
先日、追加で購入したPIC16F1823はリビジョンが8であり、AD変換終了フラグが立ち上がらないことがあるバグは改修されたものであることが分かり、すっきりとしたプログラムを書けることがちょっと嬉しい。
基本動作は確認できたので、これで、ガッツリとロジックを記述してみよう。
ちなみに、PWM立上り時に割込みをかけてAD変換するハンドラ部はこんな感じでとてもシンプル。RA4ポートのON/OFFをオシロの赤いグラフで確認している。
void interrupt handler( void ){
static unsigned char disp_count; // 表示タイミングカウンタ
static unsigned char ad_ch; // ADコンバータチャネル
// TMR2割込み(PWMクロック立上りに同期)(25us周期)の場合
// ADコンバータで電圧電流値測定
if(TMR2IE&&TMR2IF) { // 表示タイミング(TMR2)だったら
TMR2IF = 0; // TMR2割込みフラグクリア
// 値計測
__delay_us(2); // 立上がりから安定するまでウェイト
RA4=1;
GO_nDONE = 1; // AD変換開始
while(GO_nDONE); // AD変換完了を待つ
ad_ch++;
if(ad_ch==CH_NUM) ad_ch=0;
ADCON0 = (ad_ch<<2)+1; // 次チャネルをマルチプレクサに接続
advalue[ad_ch]=(ADRESH<<8)+(ADRESL); // 変換結果を読込み
RA4=0;
}
// TMR1割込み8.192ms周期)の場合
// モードに応じたPWM制御(割込みでなくてもTMR0IFはセットされる)
else if(TMR1IE&&TMR1IF) { // 表示タイミング(TMR1)だったら
TMR1IF = 0; // TMR1割込みフラグクリア
// 状態表示処理
disp_count++; // カウントアップし4なら0に
disp_count&=DISP_CYCLE; // カウントアップし32なら0に
if(!disp_count) { // 262ms周期
display(); // LCD表示
}
}
}