|
|
View previous topic :: View next topic |
Author |
Message |
sirius
Joined: 27 Jun 2009 Posts: 16 Location: Bulgaria
|
PIC16F88 - PWM resolution problem |
Posted: Tue Apr 27, 2010 11:36 am |
|
|
Hi, the MCU is running on 8Mhz internal oscillator, CCP module is configured as follows:
Code: | setup_timer_2(T2_DIV_BY_4,63,1);
setup_ccp1(CCP_PWM);
set_pwm1_duty(50); |
ASM:
Code: |
.................... setup_ccp1(CCP_PWM);
086C: BCF 06.0
086D: BCF 03.5
086E: BCF 06.0
086F: MOVLW 0C
0870: MOVWF 17
.................... set_pwm1_duty(50);
0871: MOVLW 32
0872: MOVWF 15 |
PWM frequency=7800Hz, pwm_duty =50dec. The actual duty cycle is 78,1%, frequency is OK. At this frequency, PWM resolution should be 10bit.
My first question is why compiler isn't also loading CCP1CON<5:4> bits (PWM LSBs)? Before switch to 16F88, I used 16F819, same project, the same problem there. Anyway, I solved this problem by loading values directly to CCPR1L and CCP1CON<5:4> bits. However, on 16F819, PWM resolution was 10bit, as should be, but on 16F88 it's not. Compiler ver.: 4.084
What's wrong? Thanks! |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Apr 27, 2010 11:40 am |
|
|
CCS uses 10-bit mode if you specify the duty cycle parameter as 16-bit.
For a constant, put an 'L' on the end of it. For a variable, declare it as 'int16'.
Then you will get the 10-bit mode that you want. |
|
|
sirius
Joined: 27 Jun 2009 Posts: 16 Location: Bulgaria
|
|
Posted: Tue Apr 27, 2010 11:54 am |
|
|
Thank You for the fast reply! After adding "L", everything with the loading of pwm_duty_cycle is fine:
Code: |
09A4: BCF 06.0
09A5: BCF 03.5
09A6: BCF 06.0
09A7: MOVLW 0C
09A8: MOVWF 17
.................... set_pwm1_duty(102L);
09A9: MOVLW 19
09AA: MOVWF 15
09AB: MOVF 17,W
09AC: ANDLW CF
09AD: IORLW 20
09AE: MOVWF 17 |
Nevertheless, 102L should be 10% duty_cycle(10-bit mode), but it's 39,8%. Just to remind,on 16F819 it's fine(10%). Is this a MCU-bug, I couldn't find any errata related topics? Thanks!
P.S. The actual resolution seems to be 8-bit, according to: 102L resulting in duty_cycle of 39.8%. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Apr 27, 2010 12:54 pm |
|
|
I'm using the test program shown below with vs. 4.084. I also get about
40% duty cycle measured on the scope. But that's correct, because the
duty cycle is not determined by 102 being 10% of 1024. It's determined
by 102 being a percentage of the Timer2 value. That's the middle value
in the setup_timer_2() function.
In 10-bit mode, the duty cycle equation is:
Code: |
16-bit Duty cycle Parameter 102L 102
--------------------------- = ------------ = ------ = 39.8%
(Middle value +1) * 4 (63 +1) * 4 256
|
Using the logic analyzer, I measure the high level pulse at 51.0 us,
and the total period at 128.1 us. This gives the following, which agrees
with the duty cycle equation:
Code: |
51.0
----- = .389
128.1
|
Test program:
Code: |
#include <16F88.h>
#fuses INTRC_IO,NOWDT,BROWNOUT,PUT,NOLVP
#use delay(clock=8000000)
//=======================
void main()
{
setup_timer_2(T2_DIV_BY_4,63,1);
setup_ccp1(CCP_PWM);
set_pwm1_duty(102L);
while(1);
} |
|
|
|
sirius
Joined: 27 Jun 2009 Posts: 16 Location: Bulgaria
|
|
Posted: Tue Apr 27, 2010 1:26 pm |
|
|
Problem solved . Seems to be a compiler issue, but don't want to investigate it profoundly. Manually configured PWM module, following PIC16F88 datasheet sequence:
Code: |
...............................................
#byte CCP1CON = 0x17
#byte T2CON = 0x12
#byte PR2 = 0x92
................................................
PR2=255;
T2CON=4;
CCP1CON=12;
set_pwm1_duty(102L); |
Now 102L gives 9.98%, as should be. Tested also with 512L - exactly 50% duty_cycle. All 10-bit of resolution are available now.
Could be a wrong initialization sequence of PWM-module, but don't want to dig any further. Thanks anyway for the interest in my topic! |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Apr 27, 2010 1:30 pm |
|
|
Right, but you've changed the PR2 setting. That's the middle value.
I can do the same thing you just did, and I can do it in CCS. All I do is
set the middle value to 255 in the setup_ccp1() function, as shown below.
Then I read 10% duty cycle on the logic analyzer. This is with vs. 4.084.
Tested in hardware.
Quote: |
#include <16F88.h>
#fuses INTRC_IO,NOWDT,BROWNOUT,PUT,NOLVP
#use delay(clock=8000000)
//=======================
void main()
{
setup_timer_2(T2_DIV_BY_4,255,1);
setup_ccp1(CCP_PWM);
set_pwm1_duty(102L);
while(1);
} |
|
|
|
sirius
Joined: 27 Jun 2009 Posts: 16 Location: Bulgaria
|
|
Posted: Tue Apr 27, 2010 1:42 pm |
|
|
setup_timer_2(T2_DIV_BY_4,63,1); - Defined by CCS Project Wizard.
setup_timer_2(T2_DIV_BY_4,255,1); - just tested it in hardware. You are right - duty_cycle=10%, but frequency is now 1,95KHz , not as supposed to be 7,8Khz.
P.S. Adjusting Timer2 Prescaler to 1 and now is fine:
Code: |
setup_timer_2(T2_DIV_BY_1,255,1); | -7,8Khz, full 10-bit resolution
A Project Wizard issue? |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Apr 27, 2010 2:33 pm |
|
|
I don't know. I never use the Wizard. I don't have that compiler version.
Changing the PR2 value will also affect the PWM frequency. So certainly
if the PR2 value is increased and nothing else is changed, the PWM
frequency will go down. You compensated for that by reducing the
prescaler. This post has the PWM frequency formula:
http://www.ccsinfo.com/forum/viewtopic.php?t=17993&start=1
If it's all working now, I'm happy. |
|
|
sirius
Joined: 27 Jun 2009 Posts: 16 Location: Bulgaria
|
|
Posted: Wed Apr 28, 2010 7:47 am |
|
|
Yes, everything is fine now . Thanks PCM |
|
|
slammer
Joined: 02 May 2010 Posts: 4
|
|
Posted: Sun May 02, 2010 7:35 am |
|
|
hi, I also have problem with PWM, I'm using Proteus 7.6 sp4 and PCWHD Compiler 4.106, the problem is pwm is not working, I don't know why, my code is like this
Code: | #include <16F877a.h>
#use delay(clock=20MHZ)
#fuses XT, NOWDT, NOPROTECT, PUT, BROWNOUT, NOLVP
main()
{
enable_interrupts(GLOBAL);
setup_ccp1(CCP_PWM);
setup_timer_2(T2_DIV_BY_16,100L,1);
set_pwm1_duty(30L);
while(1);
} |
but if I cancel the line
Code: | set_pwm1_duty(30L); |
it is working then how can I control the duty cycle ?
my aim is to build a controller for Dc-Dc converter, my pic will take some data from ADC which is connected to output of the converter and referring to this data it will change the duty cycle of my 100kHz pwm,
please help me what is the problem with this code ? is it because of proteus or version of CCS, If I try in real pic, will it work ?
thanks |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19505
|
|
Posted: Sun May 02, 2010 7:44 am |
|
|
It could be a proteus problem.
However there are two 'glaring' things that should be fixed:
1) Never _ever_ enable anything to do with interrupts without an interrupt handler present. If an interrupt does get enabled, this is a 'sure' way to crash code.
2) Set your fuses correctly for your clock. XT, does not support operation at 20MHz....
Best Wishes |
|
|
slammer
Joined: 02 May 2010 Posts: 4
|
|
Posted: Sun May 02, 2010 8:27 am |
|
|
the new code is like this, but still it's not working
I don't have the pic and the setup now so I have to simulate it :D that's why I used proteus, and if it's a proteus problem then how can I simulate it, I don't know CCS too much last year I was using pic with assembly however it's been 1 year and I don't remember...
Code: | #include <16F877a.h>
#use delay(clock=4MHZ)
#fuses XT, NOWDT, NOPROTECT, PUT, BROWNOUT, NOLVP
main()
{
setup_ccp1(CCP_PWM);
setup_timer_2(T2_DIV_BY_16,100L,1);
set_pwm1_duty(30L);
while(1);
} |
|
|
|
slammer
Joined: 02 May 2010 Posts: 4
|
|
Posted: Sun May 02, 2010 8:45 am |
|
|
I have also tried PIC Simulator IDE - Evaluation Copy v6.65 and still not working :S |
|
|
slammer
Joined: 02 May 2010 Posts: 4
|
|
Posted: Sun May 02, 2010 9:18 am |
|
|
I've found a patch for proteus and now it's working, thanks for help |
|
|
luismramirez
Joined: 17 Feb 2011 Posts: 8
|
|
Posted: Wed Apr 06, 2011 9:20 am |
|
|
Hi,
I have an 8Mhz, with T2 BY 16, 250;
I know what duty % I need, so, using the equation:
16bit value = % * (250 + 1) * 4
Then, for 100% and 50%:
100% = 10400
50% = 50200
Is that right?
I read some were that this 16bit value can't be bigger than the middle value from the timer_2 setup.
Thank you. |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|