Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

PWM duty cycle change: PIC16F690

Status
Not open for further replies.

tyassin

Advanced Member level 1
Advanced Member level 1
Joined
Jul 22, 2004
Messages
467
Helped
86
Reputation
170
Reaction score
41
Trophy points
1,308
Activity points
3,818
Hello,

When your PWM is running and you want to change the duty cycle:

I would just write a new value to the CCPR1L register and then I guess it changes on the next instruction in the PIC?
But how will the transistion look like? will it automaticlly wait until the next period or just change abruptly?
Or is there an "elegant" way of programming this?

Thank you
 
Last edited:

Hi,
I'm not very sure of this, but what I think happens is, after you load the value into CCPR1L, the value is considered at the beginning of the next PWM period, otherwise, it might causes glitches in the output. I say so, because, it says in the datasheet (page 119):

All control registers are double buffered and are loaded at the beginning of a new PWM cycle (the period boundary when Timer2 resets) in order to prevent glitches on any of the outputs. The exception is the PWM delay register, which is loaded at either the duty cycle boundary or the period boundary (whichever comes first). Because of the buffering, the module waits until the timer resets, instead of starting immediately. This means that enhanced PWM waveforms do not exactly match the standard PWM waveforms, but are instead offset by
one full instruction cycle (4 TOSC).
However, what I usually do is, wait for the timer to overflow (at the end of the period when timer rolls on to 0), and then update the value.

Hope this helps.
Tahmid.
 
Hi,

However, what I usually do is, wait for the timer to overflow (at the end of the period when timer rolls on to 0), and then update the value.

How would you write this in C?

Thank you
 

Hi,
Enable timer interrupt. In the ISR, load the new value. I hope you understand how to do it.

Or you can poll to check if flag has been raised, once this is done, then reload the value. The first option is, however, better because, in this method you may miss a few overflows if you are carrying out some other task.

Hope this helps.
Tahmid.
 

Hi

Enable timer interrupt. In the ISR, load the new value. I hope you understand how to do it.

I am not really sure how to do this.

This is my PWM setup

Code:
TRISC=0xFF;
CCP1CON=0;
PR2 = 255;
CCPR1L = 0;	//Init PWM duty cycle to 0 Hz
TMR2IE=0;
T2CKPS0=0;		//Prescaler=1:1
T2CKPS1=0;		//Prescaler=1:1
CCP1CON = 0b00001100;	//Two LSB(bit 4 & 5) of PWM duty cycle = 00

TMR2ON=1;

while(TMR2IF==0)
{}

Sorry this is still new area for me...but learning:)

Thank you
 
Last edited:

Hi,
This is not really necessary since you're running in "Single Ended PWM Mode". It would have been necessary if you used the compare module.
For PWM mode, the new duty cycle is loaded when TMR2 matches PR2:

When TMR2 is equal to PR2, the following three events occur on the next increment cycle:
• TMR2 is cleared
• The appropriate PWM pin toggles. In Dual PWM mode, this occurs after the dead band delay expires (exception: if PWM duty cycle = 0%, the pin will not be set)
• The PWM duty cycle is latched from CCPR1L into
CCPR1H

Hope this helps.
Tahmid.

---------- Post added at 18:53 ---------- Previous post was at 18:53 ----------

Basically, what I stated, it happens on its own.
 

OK

So when ever I change the CCPR1L register or the DC1B0 and DC1B1 bits, it automatically takes care of adjusting the duty cycle?
 

Yes. It is updated at the end of the period (when TMR2 equals PR2).

Hope this helps.
Tahmid.

---------- Post added at 22:28 ---------- Previous post was at 20:52 ----------

Hi,
I haven't done anything to the code, but just as a pointer, if you use mikroC, the bits must be used with a _bit at the end. eg. instead of TMR2IE, it should be TMR2IE_bit, same for TMR2IF_bit, etc.

Hope this helps.
Tahmid.
 
Hello Tahmid,

Regarding changing the PWM duty cycle, I have another question.

I would like to use the full 10bit resolution of the PWM. I have written this code that is supposdly to put the duty cycle bits into an "int" variable increment it 1 and then put the bits back into its respectively places.
The variable PWM_inc1 is an "int" variable.

Code:
PWM_inc1=(CCPR1L<<2)+(CCP1CON>>4);
PWM_inc1+=1;
CCPR1L=PWM_inc1>>2;
DC1B1=PWM_inc1>>1;
DC1B0=PWM_inc1;

Will this work?

Thank you
 

I made PWM soft start for light (bulb or led) with PIC16f877a. Send you code.

********************************
********************************
;********************************************************************************************
;
; PWMv2 01-2011
;
; 25KHZ generation. DC change 10%-90% for power regulation
;
;
;
;
;
;
; 1 - PWM period = [(PR2) + 1] • 4 • TOSC • (TMR2 prescale value)
; 2 - PWM duty cycle =(CCPR1L:CCP1CON<5:4>) • TOSC • (TMR2 prescale value)
;
; SETUP FOR PWM OPERATION
; The following steps should be taken when configuring
; the CCP module for PWM operation:
; 1. Set the PWM period by writing to the PR2
; register.
; 2. Set the PWM duty cycle by writing to the
; CCPR1L register and CCP1CON<5:4> bits.
; 3. Make the CCP1 pin an output by clearing the
; TRISC<2> bit.
; 4. Set the TMR2 prescale value and enable Timer2
; by writing to T2CON.
; 5. Configure the CCP1 module for PWM operation.
;
; TMR2 - T2CON - bit 1-0
; 00 = Prescaler is 1
; 01 = Prescaler is 4
; 1x = Prescaler is 16

;
;
;
;
LIST P=16F877A
#INCLUDE "P16F877A.INC"
;
RC2 EQU 2
W EQU 0
F EQU 1
RP0 EQU 5
PR2 EQU 92
CCPR1L EQU 15
CCP1CON EQU 17
T2CON EQU 12
TMR2ON EQU 2
TMR2 EQU 11
T0IF EQU 2
Z EQU 2
;
VREME EQU 20
FLAG EQU 21
;
;
;
;
ORG 0
;
;
NOP ; ICD2
NOP
NOP
;
POCETAK
;
; example 1:
; T= 40usec (F=25KHz)
; PR2=200, TMR2pre=00 :)1)
; XT - 20MHZ
;
; CCPR1CON=00
; change CCPR1L = 190 --- "1"=1,8sec
; = 10 -> "1"=39usec
;
;
;
;
; example 2:
; T= 40usec (F=25KHz)
; PR2=200, TMR2pre=00 :)1)
; XT - UZETO 3579545HZ
;
; CCPR1CON=00
; change CCPR1L = 30 ------- "1"=3,35sec
; = 1 -> "1"=36,87usec
;
;********************************************************************************************
;
;
;
;
SETUP
CLRF FLAG
MOVLW 5
MOVWF VREME ; 73,2ms * 5 = 366ms
CALL SETUP73MS ;
;
;********************************************************************************************
; ; define T (PR2)
BSF STATUS,RP0 ;B1
MOVLW D'34' ;
MOVWF PR2
;********************************************************************************************
; ;define DUTYCYCLE (CCPR1L, CCP1CON<5,4>)
BCF STATUS,RP0 ;B0
MOVLW D'1' ;-
MOVWF CCPR1L
BCF CCP1CON,5
BCF CCP1CON,4
;********************************************************************************************
; ; RC2 OUTPUT for CCP1
BSF STATUS,RP0 ;B1
BCF TRISC,RC2 ;RC2 OUTPUT
;********************************************************************************************
; ;CCP1 is PWM
BCF STATUS,RP0 ;B0
BSF CCP1CON,2
BSF CCP1CON,3
;
;********************************************************************************************
; ; define TIMER2
MOVLW B'00000100' ;POSTSCALE is not used, TMR2ON<2>,
MOVWF T2CON
BSF T2CON,TMR2ON ;TMR2 is ON
;;;;BCF T2CON,TMR2ON ;TMR2 is OFF
;
;**********************************************************************************************
;
MOVLW D'0' ;tmr2 not in use
MOVWF TMR2
OUT_0
BTFSS INTCON,T0IF ; 73ms passed?
GOTO OUT0 ;No
CALL POVECANJE
BTFSC FLAG,0 ; 100% power
GOTO KRAJ ;yes
OUT0 ; no
BTFSS PORTC,RC2 ;
GOTO OUT0 ;
OUT11
CLRF TMR2 ;not use TMR2
OUT1
BTFSC PORTC,RC2 ;VREDNOST NA RC2=1
GOTO OUT1
GOTO OUT_0
;
;**********************************************************************************************
;
; incrising F - decrising T == incrising P == SOFT START
; change CCPR1L OD 1-30 - 30 steps, step= 366msec (73,2ms * 5= 366) =>total= 11SEC
;
POVECANJE
BCF INTCON,T0IF
DECFSZ VREME,F ;366ms ?
RETURN ;No
MOVLW 5 ;Y
MOVWF VREME
INCF CCPR1L,F
MOVLW D'31'
XORWF CCPR1L,W ;power = 100%
BTFSS STATUS,Z
RETURN ;No
BSF PORTC,RC2 ;Y,
BSF FLAG,0 ;end SOFT START
RETURN
;
;***************************************************************************************************
;
;
SETUP73MS
BCF STATUS,RP0
MOVLW 0 ;256 X 256 X 1,117=73,2MS
MOVWF TMR0
BSF STATUS,RP0 ;01=BANK1
MOVLW B'11010111'
MOVWF OPTION_REG ;PSA=256, TIMER MODE
BCF INTCON,T0IF
BCF STATUS,RP0 ;
RETURN
;
;
;***************************************************************************************************
;
;

;
; Y 100% == end SOFT START
;
KRAJ
BCF STATUS,RP0
BSF PORTC,RC2
BCF T2CON,TMR2ON
GOTO KRAJ
;
;
;
;
END


********************************
********************************
 

Thanks DraganM...unfortunately I do not understand assembler....
 

If you want I can give you simple explanation what I doing in program.
 

// define
//==========================================================================
#define BUTTON1 RA1
#define BUTTON2 RA2
#define BUTTON3 RA3
#define BUTTON4 RA4
#define CCW RB1
#define CW RB2

// function prototype
//==========================================================================
void delay(unsigned long data);

// global variable
unsigned char temp=50;

// main function
//==========================================================================
void main(void)
{

ADCON1 = 0x06; //Configure Poart A as digital I/O

TRISA = 0b11111111; //Set pin RA1 to RA4 as input for press button switch
TRISB = 0b00000000; //Set pin RB1 & RB2 as output for MD10A
TRISC = 0b11000000; //Set pin RC2 as output for PWM

CCP1CON = 0b00001100; //PWM Mode

//PWM frequecy set as 4.88KHz
PR2 = 0xFF; //PWM Period Setting
T2CON = 0b00000101; //Timer2 On, prescale 4

//Motor stop
CCPR1L = 0; //No PWM Duty Cycle
CW = 0;
CCW = 0;

while(1) //Infinity Loop
{
if(BUTTON1==0) //Brake
{
CCPR1L=0;
CW=0;
CCW=0;
}

else if(BUTTON2==0) //Change the Rotational Direction
{
while(BUTTON2==0)continue;
CCPR1L=temp;
CW=!CW;
CCW=!CW;
}

else if(BUTTON3==0) //Speed Increment
{
if(temp<255)temp+=1;
CCPR1L=temp;
delay(5000);
}

else if(BUTTON4==0) //Speed Decrement
{
if(temp>0)temp-=1;
CCPR1L=temp;
delay(5000);
}
}
}

// functions
//==========================================================================
void delay(unsigned long data)
{
for( ;data>0;data-=1);
}

- - - Updated - - -

This program was pwm vary by using input Switches.
 

    V

    Points: 2
    Helpful Answer Positive Rating
Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top