PIC18F26K22でLEDちかちか PWM編

 2013-08-23
1Hzのちかちかができたので次は同じくタイマーを使ったPWMで輝度を変更してみます。

 
もともと10kΩの抵抗を挟んであるのでLEDの輝度はかなり低いのですが、PWMを使ってもっともっと低輝度にしてみます。

PWMはパルス幅を変えることが出来る発振機能です(語弊があるけど)。
たとえば、0.1秒間5Vを出力し続く0.9秒間を0Vにし、これを繰り返すと、ONの期間が10%のPWM信号、と言えます。 言えます。 はい。
このようなONの期間とOFFの期間の比をデューティー比と言います。

そんなことせんでも、可変抵抗でいいじゃん、と思うかも知れませんが、モーターなどはある程度の電圧が無いと最初の一滑りが起らないため、PWM制御が向いています。 いわゆる、インバーター制御も似たような発想です。(もちろん似てるだけで異なる技術なのですが)

また、PICで簡単に電流制御をやろうとおもったら、やはりPWMのほうが外付け回路が少なくて済んだりとメリットがあるのです。




何はなくともブロック図を見ましょう。
pic18f26k22_pwm.jpg
PICのPWMはCCPモジュールとTMRモジュールを組み合わせて使います。組み合わせは任意ではなく、用意された組から選択するので、使用する場合は要注意です。


pic18f26k22_pwm2.jpg
今回はTMR4,CCP3を使うことにします。
PR4、CCPR3L,DC3Bの比でPWMのデューティー比を設定します。
クロックに同期してどんどんカウントアップされるTMR4が、PR4と一致すると、TMR4が初期化されます。これがPWMの一周期になります。
TMR4が、CCPR3L,DC3Bと一致すると出力が反転します。そのあとPR4と一致するまで出力は維持されます。これでPWMのデューティー比を変化させています。




そしてこれがコード

#include <xc.h>

#pragma config FCMEN = OFF // not use Fail-Safe Clock Monitor
#pragma config IESO = OFF // not use Internal-External swithover mode
#pragma config PRICLKEN=ON // Primary Clock is always enabled
#pragma config PLLCFG= ON // PLL is ON
#pragma config FOSC = INTIO67 // INTOSCIO ( use INTOSC )
#pragma config BORV = 250 // Vbor set 2.5V
#pragma config PWRTEN= ON // USE Power-up Timer
#pragma config WDTPS = 32768 // WDT postscaler 1:32768
#pragma config WDTEN = OFF // WDT hardware disabled
#pragma config MCLRE = INTMCLR // use RE3 input
#pragma config P2BMX = PORTC0 // CCP2MUX is on RC0(wtf?)
#pragma config T3CMX = PORTC0 // T3CKI is on RC0(wtf?)
#pragma config HFOFST= OFF // wait for HFINTOSC is stable
#pragma config CCP3MX= PORTC6 // CCP3 in/out is multiplexed with RC6(wtf?)
#pragma config PBADEN= OFF // ANSELB resets to 0(PORTB set as GPIO on reset)
#pragma config DEBUG = OFF // USE RB6,7 as GPIO
#pragma config LVP = ON // Single-Supply ICSP enabled
#pragma config STVREN= ON // Stack Full/Underflow Reset enable
#pragma config CP3 = OFF // NOT USE CodeProtection
#pragma config CP2 = OFF // NOT USE CodeProtection
#pragma config CP1 = OFF // NOT USE CodeProtection
#pragma config CP0 = OFF // NOT USE CodeProtection
#pragma config CPD = OFF // NOT USE DataProtection
#pragma config CPB = OFF // NOT USE BootblockProtection
#pragma config WRT3 = OFF // NOT USE WriteProtection
#pragma config WRT2 = OFF // NOT USE WriteProtection
#pragma config WRT1 = OFF // NOT USE WriteProtection
#pragma config WRT0 = OFF // NOT USE WriteProtection
#pragma config WRTD = OFF // NOT USE WriteDataProtection
#pragma config WRTB = OFF // NOT USE WriteBootblockProtection
#pragma config WRTC = OFF // NOT USE WriteConfigurationregisterProtection

#define WAIT_MS 500
#define TMR6INT 245/2

int sysinit();
int tmrinit();
int tmr6int();
int wait_ms(unsigned int);

unsigned int TMR6INTcnt=0;
unsigned int PWMwidth=0x03FF;
unsigned char cnt=0;

void interrupt interhandler(){
if(PIR5bits.TMR6IF==1){
PIR5bits.TMR6IF=0; //flush Interrupt Flag
tmr6int(); //TMR6 Interrupt work
}
}

/*
*
*/
int main() {
sysinit();
tmrinit();

while(1){;}

return (EXIT_SUCCESS);
}

int tmr6int(){
TMR6INTcnt++;
if(TMR6INTcnt>=TMR6INT){
TMR6INTcnt=0;

cnt=~(cnt);
PORTA=cnt;

if(cnt!=0x00){
CCPR3L=((0x3FF-PWMwidth)>>2)&0xFF; //set PWM width
CCP3CONbits.DC3B=(0x3FF-PWMwidth)&0x3; //set PWM width
PWMwidth=PWMwidth>>1; //chenge next width
if(PWMwidth<=0x0){ PWMwidth=0x03FF; } //change next width
}
}
return( EXIT_SUCCESS);
}

int tmrinit(){
//TIMER6(interval interrupt)
// FOSC[64MHz]-->FOSC/4[16MHz]-->Prescaler(1:16)[1MHz]-->
// TMR6=PR6(0xFF)[3.92KHz]-->Postscaler(1:16)[245Hz]-->TMR6Interrupt
T6CONbits.TMR6ON=0; // TMR6 off
T6CONbits.T6OUTPS=0b1111; // 1:16 Postscaler
T6CONbits.T6CKPS=0b11; // 1:16 Prescaler
PR6 =0xFF; // TMR6 period
TMR6=0x00; // flush TMR6
INTCONbits.GIE=1; // Enable Global Interrupt
INTCONbits.PEIE=1; // Enable Peripheral Interrupt
PIE5bits.TMR6IE=1; // Enable TMR6=PR6 match Interrupt
PIR5bits.TMR6IF=0; // flush flag of TMR6 Interrupt

//TIMER4,CCP3(PWM)
CCPTMRS0bits.C3TSEL=0b01; //CCP3 PWM modes use TMR4
T4CONbits.T4OUTPS=0b0000; //Postscaler 1:1
T4CONbits.TMR4ON =0b0; //TMR4 off
T4CONbits.T4CKPS =0b11; //Prescaler 16
PR4=0xFF; //PWM period
CCPR3L=0xFF; //PWM width MSB[9-2]
CCP3CONbits.DC3B=0b11; //PWM width LSB[1-0]
CCP3CONbits.CCP3M=0b1111; //PWM mode


T6CONbits.TMR6ON=1; // TMR6 on
T4CONbits.TMR4ON=1; // TMR4 on

return( EXIT_SUCCESS);
}

int sysinit(){
//setting CLK
OSCCONbits.IRCF = 0b111; // INTOSC 16MHz
OSCCONbits.SCS = 0b00; // USE PLL
OSCTUNEbits.PLLEN = 0b1; // PLL enable

//setting PORTA
PORTA=0x0; //PORTA init
ANSELA=0x0; //NOT USE ANALOGINPUT
CM1CON0=0x0; //NOT USE CMP1
CM2CON0=0x0; //NOT USE CMP2
VREFCON1=0x0; //NOT USE VREF(setting to Vref=Vdd,Vss)
VREFCON2=0x0; //NOT USE VREF
HLVDCON=0x0A; //set default(HLVDL=0b1010, HLVD=3.65V)
SLRCON=0x1F; //set default(PORTA,B,C slew at a limited rate)
SRCON0=0x0; //NOT USE SR latch
SSP1CON1=0x0; //NOT USE SPI
T0CS=0b0; //NOT USE T0CKI as TMR0 CLK source
TRISA=0x0; //PORTA set all output

//setting PORTB
PORTB=0x0; //PORTB init
ANSELB=0x0; //NOT USE ANALOGINPUT
ECCP2AS&=0b1100;//NOT USE CCP2
CCP2CON=0; //NOT USE CCP2
ECCP3AS&=0b1100;//NOT USE CCP3
CCP3CON=0; //NOT USE CCP3
INTCON=0; //DISABLE INT
INTCON2=0; //DISABLE INT
INTCON3=0; //DISABLE INT
IOCB=0; //DISABLE INT
T1GCON=0; //NOT USE TMR1
T3CON=0; //NOT USE TMR3
T5GCON=0; //NOT USE TMR5
TRISB=0; //PORTB set all output
WPUB=0; //DISABLE pullup

//setting PORTC
PORTC=0x0; //PORTC init
ANSELC=0x0; //NOT USE ANALOGINPUT
ECCP1AS&=0b1100;//NOT USE CCP1
CCP1CON=0; //NOT USE CCP1
CTMUCONH=0; //NOT USE CTMU
RCSTA1=0; //Serial port disabled
T1CON=0; //NOT USE TMR1
T3CON=0; //NOT USE TMR3
T3GCON=0; //NOT USE TMR3
T5CON=0; //NOT USE TMR5
TRISC=0; //PORTB set all output

return(EXIT_SUCCESS);
}

int wait_ms(unsigned int wait){
unsigned int cnt=0;
unsigned int i =0;
for(cnt=0; cnt <= wait ; cnt++){
for(i=0; i <= WAIT_MS; i++){ ; }
}
}



PWM100%から、点滅毎に半分、半分、半分、、、と輝度を下げていきます。0%になったら100%にまた戻ります。
PIC12F683でPWMは味見していたのでスムーズにPWMの波形を観ることが出来ました。

PWMの出力は2SC1815に入力し、LED群のGNDを制限してます。


動画



 
コメント












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