View previous topic :: View next topic |
Author |
Message |
beaker404
Joined: 24 Jul 2012 Posts: 163
|
PWM on 16F876 |
Posted: Thu Jan 11, 2018 9:12 am |
|
|
Windows 10
MPLAB 8.91.00.00
CCS PCM V5.064 xxxxx
PIC16F876 running at 4.0 MHz.
Developed some code that runs a PWM at 50% duty and 1000Hz.
This all works fine, wanted to make some code that set to other frequencies to test output with our test equipment. Below is my code snippet that sets the PWM up. I simply uncomment the line I want at that time for the test.
1000 Hz code works, others do not, the PWM channel just stays high for any frequency besides 1000Hz. Not sure what is going on as the math works for the equations or at least I think so.
Code: | if(input(MODE)) {
PWM_MODE = 1;
}
else {
PWM_MODE = 0;
}
output_low(PIN_C1); // Set CCP2 output low
output_low(PIN_C2); // Set CCP1 output low
output_low(VISIBLE_CNTRL); // visible LED is off
if(PWM_MODE) { // Set up CCP1 and CCP2
setup_ccp1(CCP_PWM); // Configure CCP1 as a PWM
setup_ccp2(CCP_PWM); // Configure CCP2 as a PWM
setup_timer_2(T2_DIV_BY_4, 249, 1); // 1000 Hz
//setup_timer_2(T2_DIV_BY_16, 124, 1); // 477 Hz
//setup_timer_2(T2_DIV_BY_4, 124, 1); // 2000 Hz
//setup_timer_2(T2_DIV_BY_4, 24, 1); // 10000 Hz
enable_interrupts(INT_TIMER2);
set_pwm1_duty(PWM_OFF); // 0% duty cycle on pin C2
set_pwm2_duty(PWM_OFF); // 0% duty cycle on pin C1
}
setup_port_a(NO_ANALOGS); |
|
|
![](templates/subSilver/images/spacer.gif) |
beaker404
Joined: 24 Jul 2012 Posts: 163
|
|
Posted: Thu Jan 11, 2018 9:14 am |
|
|
Just to clarify, the PWM_OFF is used to just turn the PWM off in the initialization stage. later in the code I turn it on at 50%. |
|
![](templates/subSilver/images/spacer.gif) |
temtronic
Joined: 01 Jul 2010 Posts: 9177 Location: Greensville,Ontario
|
|
Posted: Thu Jan 11, 2018 9:45 am |
|
|
PWM is a 10bit register, so pretty sure you have to 'cast' the number as a long
well that's my guess...
Jay |
|
![](templates/subSilver/images/spacer.gif) |
beaker404
Joined: 24 Jul 2012 Posts: 163
|
|
Posted: Thu Jan 11, 2018 9:51 am |
|
|
I was wondering about the need for casting, not sure why it works for the 1000 Hz situation though. |
|
![](templates/subSilver/images/spacer.gif) |
temtronic
Joined: 01 Jul 2010 Posts: 9177 Location: Greensville,Ontario
|
|
Posted: Thu Jan 11, 2018 10:14 am |
|
|
luck of the dice ??
I can't test, but there's a LOT of 'threads' about needing longs for 10bit devices....
Unless YOU specifically set a register it may come up as anything. Now thecompiler may 'preset' some of them, the PIC may 'powerup' in a certain config..but YOU should always be in control...kinda relates to reading the datasheets.....
edit: just had a look, table 8-4 xxxx xxxx LOTS of registers are 'unkown' on powerup ! Implies YOU need to set them up.
try casting long, see what happens. This PC is net only...NOT my eng PC.
Jay |
|
![](templates/subSilver/images/spacer.gif) |
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Jan 11, 2018 10:25 am |
|
|
Quote: | Developed some code that runs a PWM at 50% duty and 1000Hz. |
Your code fragment doesn't show the setup_pwm1_duty() and
set_pwm2_duty() calls that setup the 50% duty cycle. You only show
the lines that turn it off. |
|
![](templates/subSilver/images/spacer.gif) |
beaker404
Joined: 24 Jul 2012 Posts: 163
|
|
Posted: Thu Jan 11, 2018 10:51 am |
|
|
Here is the define for my PWM_50 variable.
#DEFINE PWM_50 128 //128 is 50%
below is a sample of how I use two discreet control lines to set which PWM is on.
Code: | if((INPUT(CNTRL_A))&&(!INPUT(CNTRL_B))) { // 265 on. Mode 1 265 ON
if(PWM_MODE) {
set_pwm1_duty(PWM_50);
set_pwm2_duty(PWM_OFF);
}
else {
output_high(PIN_C2);
output_low(PIN_C1);
}
output_low(VISIBLE_CNTRL);
} // end mode 1 if |
|
|
![](templates/subSilver/images/spacer.gif) |
beaker404
Joined: 24 Jul 2012 Posts: 163
|
|
Posted: Thu Jan 11, 2018 10:55 am |
|
|
some more setup code for the PIC:
Code: | #FUSES XT,NOWDT,NOPROTECT,PUT,NOBROWNOUT,NOLVP,NODEBUG
#use delay(clock=4000000)
|
|
|
![](templates/subSilver/images/spacer.gif) |
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Jan 11, 2018 11:12 am |
|
|
The 16F876 data sheet says:
Quote: | If the PWM duty cycle value is longer than the
PWM period, the CCP1 pin will not be cleared. |
The period is set by the middle number in the setup_timer2() function.
Note that your code only follows the above rule in the case of 1000 Hz.
In all other cases, your duty cycle value is higher than the middle number
and you are getting a continuous logic "1" out. That's what they mean
when they say "will not be cleared". |
|
![](templates/subSilver/images/spacer.gif) |
gaugeguy
Joined: 05 Apr 2011 Posts: 298
|
|
Posted: Fri Jan 12, 2018 7:43 am |
|
|
For 1000 Hz you are setting the duty cycle to 128/250 = 51.2%
For 477 Hz, 128/125 = 102.4%
For 2000 Hz, 128/125 = 102.4%
For 10000Hz, 25/128 = 512%
For any duty cycle over 100% you won't see any signal change. |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19382
|
|
Posted: Fri Jan 12, 2018 9:14 am |
|
|
Code: |
//routine to set pwm to a particular division
//(within the hardware limitations) 1 to 4096
int1 set_pwm_to(int16 division)
{
//feed this with the division you want.
//obviously limited accuracy
if (division>4096)
return FALSE; //can't be done....
if (division>1024)
{
//here we are going to have to use /16
division/=16;
setup_timer_2(T2_DIV_BY_16, division-1, 1);
set_pwm1_duty(division*2);
//using a 16 bit division so pwm counts to
//division * 4
}
else
{
if (division > 256)
{
//here /4
division/=4;
setup_timer_2(T2_DIV_BY_4, division-1, 1);
set_pwm1_duty(division*2);
}
else
{
setup_timer_2(T2_DIV_BY_1, division-1, 1);
set_pwm1_duty(division*2);
}
}
return TRUE;
}
|
|
|
![](templates/subSilver/images/spacer.gif) |
|