PICでPWM おべんきょう

 2013-08-17
手持ちのなかで二番目にちいさい? PIC12F683を使ってPWMのLED減光を試作してみました。
 
実際に取付けするかはともかく、目指す姿は自動車のルームランプかフットランプとします。


■目標(だいたいあってる)
点灯時にふわっとじわっと、LEDがONになり、消灯するときはさらに時間をかけてふわあっとじわあっとOFFになるようなものです。
イルミネーション電源がONになったとき等、状況に応じて輝度を可変にするとなお良し。(つまり、イルミON時は減光する、などの処理)
待機電力は小さくする。

■入出力
まずPWM出力が必要。負荷はまだ決まってないし出来ればあまり制約をきつくしたくないので12VでパワーMOSで出したい。
次に動作トリガーとなる入力が何本か要る。最低1本。端子数に余裕があるので3本までなら増やせる。
そして待機電力を小さくするため、PICの5V系電源を自分で殺せるようにしておく。そのための制御に出力1本使う。
(PIC12F683は8pinなので電源・GND除けば6本使える)

■ブロック図(だいたいあってる)
picpwmblock.png
12V系は赤、5V系は青で色分けしてある
12V常時電源は5Vreg殺し用Trで止められていて、トリガー電源かPICからの制御がないと動かない。
最初の火入れはトリガー電源が行い、PICが動作開始してからはPICからも自分でレギュレータの火を保つ。ダイオードを使ってワイヤードオアにする。
あとはトリガー電源をレベルシフトしてPICに入力、PICからのPWM出力はレベルシフトして12V出力MOS Trを駆動する。
だいたいあってる。

イルミネーション電源の入力を増やす場合は、上記のトリガー電源と同じようにレベルシフトしてPICにぶち込むだけ。

■プログラム
アセンブラは書きたくない(面倒)ので今回は(今回も)C言語でタラタラ書いた。

#include <xc.h>

#pragma config MCLRE= OFF // use GPIO3
#pragma config CP = OFF // not use code protection
#pragma config CPD = OFF // not use data protection
#pragma config WDTE = OFF // not use WDT
#pragma config FOSC = INTOSCIO //INTOSCIO ( use INTOSC and not use CLKOUT thru GP4)
#pragma config FCMEN= OFF // not use Fail-Safe Clock Monitor
#pragma config IESO = OFF // not use Internal-External swithover mode
#pragma config BOREN= ON // use BOR
#pragma config PWRTE= ON // use Power-up Timer

#define WAIT_MS 25
#define WAIT_DELAY 10
#define PWM_FAST_WAIT 100
#define PWM_FAST_STEP 10
#define PWM_SLOW_WAIT 100
#define PWM_SLOW_STEP 5
#define PWM_PERIOD 0xFF
int sysinit();
int pwminit();
int pwm0to100();
int pwm100to0();
int wait_ms(unsigned int);

/*
* PIN7 GP0 --> out
* PIN6 GP1 <-- in
* PIN5 GP2 --> PWMout
*/
int main(/*int argc, char** argv*/) {
sysinit(); // set clock, PIN IO
pwminit(); // enable PWM at 0%

while(1){
while( GP1 != 1 ){ ; } // wait GP1=1 : GP1=1 means move!
GP0=0b1; // set GP0=1 : hold ON 5V reg.
GP4=1;GP5=1; // not use. reserved.

pwm0to100(); // Power ON PWM 0 to 100

while( GP1 != 0 ){ ; } // wait GP1=0 : GP1=0 means go shutdown!

wait_ms(WAIT_DELAY); // finish wait

pwm100to0(); // Power OFF PWM 100 to 0

wait_ms(100); // final wait

if(GP1 != 1){ // check GP1=0 (means go shutdown)
GP0=0b0; // set GP0=0 : suicide, cutoff 5V reg.
while(1){ ; } //END
}
}

return (EXIT_SUCCESS);
}

int pwm0to100(){
volatile unsigned int cnt=0; // pwm 0%

while(cnt<0x03FF){
CCPR1L=cnt>>2; // set
CCP1CONbits.DC1B=cnt&0b11; // PWM width
wait_ms(PWM_FAST_WAIT); // wait
cnt+=PWM_FAST_STEP; // set next width
}

CCPR1L=0xFF; // set
CCP1CONbits.DC1B=0b11; // PWM 100%
wait_ms(PWM_FAST_WAIT); // wait

return(EXIT_SUCCESS);
}

int pwm100to0(){
volatile unsigned int cnt=0x3FF; // PWM 100%(10bit)

while(cnt>PWM_SLOW_STEP){
CCPR1L=cnt>>2; // set
CCP1CONbits.DC1B=cnt&0b11; // PWM width
wait_ms(PWM_SLOW_WAIT); // wait
cnt-=PWM_SLOW_STEP; // set next width
}

CCPR1L=0x00; // set
CCP1CONbits.DC1B=0b00; // PWM width
wait_ms(PWM_SLOW_WAIT); // wait

return(EXIT_SUCCESS);
}

int pwminit(){
PR2 =PWM_PERIOD; // PWM period
CCPR1L =0b00000000; // PWM 0%
CCP1CONbits.DC1B=0b00; // PWM 0%
CCP1CONbits.CCP1M=0b1100; // CCP1M<3:0>=110x PWM mode active-high
PIR1bits.TMR2IF=0b0; // clear PIR1.TMR2IF (interrupt flag)
T2CONbits.T2CKPS=0b11; // T2CKPS=11(Prescaler 16)
T2CONbits.TMR2ON=0b1; // TMR2 enable

while(PIR1bits.TMR2IF){ ; } // wait TMR2 overflow(PIR1.TMR2IF is set)
TRISIObits.TRISIO2=0b0; // enable PWM output PIN5(GP2)
return(EXIT_SUCCESS);
}

int sysinit(){
//INIT CLOCK
OSCCONbits.IRCF=0b110; // IRCF=110 (Fosc=4MHz)
OSCCONbits.SCS=0b1; // Internal osc is used for system clock

OPTION_REGbits.nGPPU=0; // GPPU=0 GPIO pullup is enable
OPTION_REGbits.T0CS =0; // TMR0 Clock source Internal(Fosc/4)


//INIT INT,ANALOG
IOC =0b00000000; // Not use Interrupt
ANSELbits.ADCS=0b110; // A/D conv Clock(Fosc/64)
ANSELbits.ANS=0b0000; // Not use Analog input
CMCON0bits.CM=0b111; // Not use CMP

//INIT PORT
GPIO =0b00000000; // clear GPIO
WPU =0b00000000; // Not use pullup
TRISIObits.TRISIO0=0b0; // set GP0 output
TRISIObits.TRISIO1=0b1; // set GP1 input
TRISIObits.TRISIO2=0b0; // set GP2 output
TRISIObits.TRISIO4=0b0; // set GP4 output
TRISIObits.TRISIO5=0b0; // set GP5 output

return(EXIT_SUCCESS);
}

これで正しいかはわからんが、とにかく動いたので正解!



■動画





5Vレギュレータの消費電流は馬鹿にならないのでTrで遮断しています。
待機中は消費電流はほぼゼロです。(たぶんね)

PICを使った理由は、まず一つにPICのお勉強のため。次に点灯・消灯を両方ともイイカンジに設定しようとすると割と面倒だということ(私がアナログ回路ほぼ出来ない)。そしてPICで作ってしまえば今後の拡張も可能だしソフトウェアの変更で動作を換えることが出来るから。です。
最初はアナログな回路で考えてspiceでごにょごにょやっていたのですがどうにも面倒になってしまって、それならばPICのお勉強がてら味見してみましょう、というわけです。

PICは文献が多いのですが今回のようなpin数の少ない小規模なものだと、アセンブラの例が半分以上な感じですね。さもありなん。別のCPUでアセンブラは書いたことはあるのですが、PICの命令セットを覚えてゴリゴリする気力は・・・ないので、いつもC言語でタラタラしてます。

コメント












管理者にだけ表示を許可する
トラックバック
トラックバックURL:
http://wbbwbb.blog83.fc2.com/tb.php/128-2f97943a
≪ トップページへこのページの先頭へ  ≫