|
太陽電池の充電回路の効率が悪いのでチョッパ方式の充電回路に切り替えたい妄想が広がりはじめました。手始めにAD入力の値に応じてPWMのデューティー比を変える実験を始めました。PSoCだと簡単に実装できそうですが、勉強も兼ねて8ピンの小さなPICを使ってみようと思います。
PICにはCCPと呼ばれる機能がありPWMを発生することができます。しかし、部品箱に転がっている12F675はCCP機能を持っていません。まぁそんなに精密な制御が目的ではないのでなんちゃってPWMでいくことにします。
◆内臓クロックを持った石は使いやすい
12F675は8ピンのDIPパッケージでなんともかわいらしいCPUです。タイマー、10ビットのADコンバータ、内臓クロックを備えています。内臓クロックを設定した場合は約4MHzで動作します。8ビットタイマーをPWM周期とした場合、周期T = 1/4MHz * 4 * 256 = 256(usec) となります。そのときの周波数F = 1/256(usec) = 3.9(kHz) です。
◆なんちゃってPWMのこそくな発生方法
タイマー割り込みを受けたら出力ピンをHIにして、n 秒後にLOWにすればPWMを作ることができます。しかし、この方式だとデューティー比が 1 に近づいていくと、まずいことに・・・
割り込み発生
↓
出力ピンをHI
↓
ウェイト処理
↓
出力ピンをLOW
↓
割り込み終了
デューティー比が 1 に近づくと処理時間の殆どをウェイト処理が食ってしまいAD変換の時間がなくなってしまいます。そこで、デューティー比が 0.5 を上回ったら、ピンのHI,LOWを逆にしてAD変換の時間を捻出するこそくなプログラムを作りました。
◆プログラム
プログラムはCCSのCコンパイラーを使います。これを使ってしまうとサイズと時間が許されるのであればアセンブラには戻れません。
#use delay(clock=3600000)
#use fast_io(a)
int1 f1=0;
int1 f2=0;
int8 d=0;
#int_TIMER0
void TIMER0_isr()
{
output_bit(PIN_A2,f1);
delay_us(d);
output_bit(PIN_A2,f2);
}
void main()
{
int8 buf;
setup_adc_ports(AN0_ANALOG|VSS_VDD);
setup_adc(ADC_CLOCK_INTERNAL);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1); // 1/4MHz*4*256=256(usec)
setup_timer_1(T1_DISABLED);
setup_comparator(NC_NC);
setup_vref(FALSE);
enable_interrupts(INT_TIMER0);
enable_interrupts(GLOBAL);
set_adc_channel(0);
set_tris_a(0x01); // 0=output 1=input
output_a(0x00);
while(1)
{
buf=read_adc(ADC_START_AND_READ)>>2;
if(buf<128)
{
f1=1;
if(buf==0) f1=0;
f2=0;
d=buf;
}else{
f1=0;
if(buf==255) f1=1;
f2=1;
d=255-buf;
}
}
}
|
AN0にアナログ入力、GP2にPWM出力をするようにしました。
◆内臓クロックはおおざっぱ
CCSのCで使われる delay_us() は単純な時間稼ぎループです。ループの回数はクロック周波数に依存します。今回は 4MHz を設定していますが、内臓のCR発振は精度が悪いのでデューティー比 0.5 付近の切り替えが発生したときにアナログ値とデューティー比が合わなくなります。そこで、#use delay(clock=3600000)
の値をカット&トライで書き換えてうまい位置を見つけ出します。使用する温度環境は変わると若干のズレが発生すると思われます。本当になんちゃってPWMですね。
◆8ピンのCCP付きPIC
12F675の強化版が12F683でしょうか、RAM、ROMが倍増されCCPが付いています。これいいですねぇ。ちゃんとやりたくなったらこれにしようかなぁ。
<PIC電圧計へ
|