View previous topic :: View next topic |
Author |
Message |
stevenkrn
Joined: 13 Apr 2008 Posts: 2
|
PWM |
Posted: Sun Apr 13, 2008 11:13 pm |
|
|
Hi,
i am new to CCS and have spent some trying to get an ir tx working, all i want to do at the moment is get a 38kHz PWM at 50% duty out of a 12F683. I have done this quite easily with mikroc but strugling with PICC. can anyone point me in the right direcion?
Thanks. |
|
|
umka
Joined: 28 Aug 2007 Posts: 99 Location: New Zealand
|
|
Posted: Sun Apr 13, 2008 11:28 pm |
|
|
have a look at the examples that come with CCS. the one named EX_PWM should explain all you need to know |
|
|
Guest
|
|
Posted: Mon Apr 14, 2008 1:02 am |
|
|
I have looked thorugh that code already and tried to modify it but i have no idea why i cant get a LED to it least come when i am mucking around with values, my code is:
Code: | #include <12F683.h>
#device adc=8
#FUSES NOWDT //No Watch Dog Timer
#FUSES INTRC_IO //Internal RC Osc, no CLKOUT
#FUSES NOCPD //No EE protection
#FUSES NOPROTECT //Code not protected from reading
#FUSES NOMCLR //Master Clear pin used for I/O
#FUSES NOPUT //No Power Up Timer
#FUSES BROWNOUT //Reset when brownout detected
#FUSES IESO //Internal External Switch Over mode enabled
#FUSES FCMEN //Fail-safe clock monitor enabled
#use delay(clock=4000000)
void main()
{
setup_adc_ports(NO_ANALOGS|VSS_VDD);
setup_adc(ADC_OFF);
//setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
setup_timer_1(T1_DISABLED);
setup_comparator(NC_NC);
//setup_vref(FALSE);
//setup_oscillator(False);
setup_ccp1(CCP_PWM);
setup_timer_2(T2_DIV_BY_1, 128, 1); // The cycle time will be (1/clock)*4*t2div*(period+1)
// clock=4000000 and period=127 (below)
// (1/8000000)*4*1*128 = 0.000064s or 15.625 khz
set_pwm1_duty(100);
} |
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Apr 14, 2008 1:08 am |
|
|
Look at the .LST file after you compile your program. What do you see ?
CCS places a Sleep instruction at the end of main(). Your PIC is going
into sleep (power-down) mode. PWM doesn't work in power-down mode.
Quote: |
... set_pwm1_duty(100);
0036: MOVLW 64
0037: BCF STATUS.RP0
0038: MOVWF CCPR1L
0039: SLEEP |
You can prevent your program from executing the Sleep instruction
by placing a continuous loop at the end of main(). Example:
Quote: | setup_ccp1(CCP_PWM);
setup_timer_2(T2_DIV_BY_1, 128, 1);
set_pwm1_duty(100);
while(1);
} |
|
|
|
Matro Guest
|
|
Posted: Mon Apr 14, 2008 1:44 am |
|
|
Moreover you have to parameter the timer 2 with a "long int" if you want to use whole the range from 0 to 128.
As it is currently, the range is from 0 to 128/4 = 32
Code: |
setup_timer_2(T2_DIV_BY_1, 128L, 1);
|
Matro. |
|
|
Guest
|
|
Posted: Mon Apr 14, 2008 1:57 am |
|
|
Ok great it works thanks. Also i am having difficuty understanding how the following instructions below actually work and how to get 38kHz at 50% duty?
setup_timer_2(T2_DIV_BY_1, 128, 1);
set_pwm1_duty(100); |
|
|
Matro Guest
|
|
Posted: Mon Apr 14, 2008 2:06 am |
|
|
Anonymous wrote: | Ok great it works thanks. Also i am having difficuty understanding how the following instructions below actually work and how to get 38kHz at 50% duty?
setup_timer_2(T2_DIV_BY_1, 128, 1);
set_pwm1_duty(100); |
The first set the timer 2 prescaler, overflow value, and postscaler.
The frequency will depend on each of these values and on the µC frequency.
The second set the pwm value, that "corresponds" to duty.
Duty cycle has to be calculate according to the timer 2 value.
In your case :
Code: |
setup_timer_2(T2_DIV_BY_1,25,1); //timer 2 will count to 26
set_pwm1_duty(5); //to use for 8-bit resolution ; duty = 50%
set_pwm1_duty(20L); //to use for 10-bit resolution ; duty = 50%
|
As you see I mistaken in my previous post. The "L" to say "long int" shall be placed in the set_pwm1_duty() (if a 10-bit resolution is needed) and not in timer 2 setup.
Matro. |
|
|
Guest
|
|
Posted: Mon Apr 14, 2008 3:23 am |
|
|
ok i think i almost have it so with the flowing example:
setup_timer_2(T2_DIV_BY_1,25,1); //timer 2 will count to 26
set_pwm1_duty(5); //to use for 8-bit resolution ; duty = 50%
set_pwm1_duty(20L); //to use for 10-bit resolution ; duty = 50%
(1/4000000)*4*1*26=26us = 38kHz
50% duty = 26us/2 = 13us ????
how did you get 5 and 20L for 50% duty?
and what would one need to change T2_DIV_BY_1 to say 4 or 16 and what is the value 1 on the end of setup_timer_2() for?
Thanks. |
|
|
Matro Guest
|
|
Posted: Mon Apr 14, 2008 3:41 am |
|
|
Anonymous wrote: | ok i think i almost have it so with the flowing example:
setup_timer_2(T2_DIV_BY_1,25,1); //timer 2 will count to 26
set_pwm1_duty(5); //to use for 8-bit resolution ; duty = 50%
set_pwm1_duty(20L); //to use for 10-bit resolution ; duty = 50%
(1/4000000)*4*1*26=26us = 38kHz
50% duty = 26us/2 = 13us ????
how did you get 5 and 20L for 50% duty?
|
Indeed this value seems not correct. That was the one given by PCW wizard.
A correct thing should be :
Code: |
set_pwm1_duty(13); // 8-bit resolution
|
or
Code: |
set_pwm1_duty(52L); // 10-bit resolution
|
Quote: |
and what would one need to change T2_DIV_BY_1 to say 4 or 16 and what is the value 1 on the end of setup_timer_2() for?
Thanks. |
The T2_DIV_X value is the prescaler, so it will change the frequency, but will keep the same duty and resolution.
The last value is the postscaler of the timer.
Matro.[/code] |
|
|
Guest
|
|
Posted: Mon Apr 14, 2008 4:25 am |
|
|
ok thanks i got it. One other question, i would like the LED to change brightness in the way of a sine wave i have tries the code below but the LED stays on?
Code: | long int value, x;
float i;
void main()
{
setup_adc_ports(NO_ANALOGS|VSS_VDD);
setup_adc(ADC_OFF);
//setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
setup_timer_1(T1_DISABLED);
setup_comparator(NC_NC);
//setup_vref(FALSE);
//setup_oscillator(False);
while(1){
setup_ccp1(CCP_PWM);
setup_timer_2(T2_DIV_BY_1, 25, 1);
for(i=0;i<3100;i=i++)
x=104*sin(i);
value=abs(x);
set_pwm1_duty(x);
delay_ms(2);
}}
|
|
|
|
Guest
|
|
Posted: Mon Apr 14, 2008 4:27 am |
|
|
Sorry wrong code:
Code: | long int value, x;
float i;
void main()
{
setup_adc_ports(NO_ANALOGS|VSS_VDD);
setup_adc(ADC_OFF);
//setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
setup_timer_1(T1_DISABLED);
setup_comparator(NC_NC);
//setup_vref(FALSE);
//setup_oscillator(False);
while(1){
setup_ccp1(CCP_PWM);
setup_timer_2(T2_DIV_BY_1, 25, 1);
for(i=0;i<3.18;i=i=i+0.01)
x=104*sin(i);
set_pwm1_duty(value);
delay_ms(2);
}} |
|
|
|
Ttelmah Guest
|
|
Posted: Mon Apr 14, 2008 8:01 am |
|
|
Two problems.
First, remember that 'sin', will return -ve values as well as +ve ones. Your conversion to a PWM width, needs to handle this as well ((sin(i) * 52) + 52).
Second, think how long this all takes. Under 1 second for the whole cycle. You need to increase your delay quite a bit, if the cycle is going to be comfortably visible.
The first is probably what is stopping the change being seen. The -ve results, will result in a 'wrap' in the arithmetic, and +ve results that will turn the LED permanently 'on' through half the cycle. Given the speed of the whole cycle, the short dimmer periods are probably just not visible.
Best Wishes |
|
|
stevenkrn
Joined: 13 Apr 2008 Posts: 2
|
|
Posted: Tue Apr 15, 2008 8:53 pm |
|
|
Hi its me again thanks for all your help.
I have spent the last 2 frustrating days to get this to work lol. I am trying to make the jar of fire flie: http://www.instructables.com/id/Jar-of-Fireflies/ and thought it was easier than first. My code so far is:
Code: |
#include <math.h>
#define RAND_MAX 50
#include <stdlib.h>long int value;
unsigned int r1;
int r;
int val;
void main()
{
setup_adc_ports(sAN1|VSS_VDD);
setup_adc(ADC_CLOCK_INTERNAL);
set_adc_channel(1);
setup_comparator( NC_NC_NC_NC );
setup_timer_1(T1_DISABLED);
setup_ccp1(CCP_PWM);
setup_timer_2(T2_DIV_BY_1, 25, 1);
while(1){
int i=0;
float x=0;
int y=0;
r=rand(); //generate a random number each cycle
output_a(r); //output a random number to port a
do{
i=i+0.01;
delay_ms(10);
x=50*sin(i); // 27 is the least value that can be used ?? why not 0?
y=abs(x);
set_pwm1_duty(y);
}while(i<3.14);} //3.14(pi) one cycle
}
} |
I have 3 LEDS connected to PINA0, PIN_A4, PIN_A5 with the grounds connected to CCP1. What i am trying to do at this point is for random LED/LEDs to gradually turn on then off like a sine wave. This does happen for some bazzaar reason for eg sometimes one LED gradually turns on then turns straight off without gradually decreasing brightness, as soon as this LED turns off another takes its place and this one gradually decreases. Another problem is i made x=r*sin(i); but r cannot be less than 27?? and when r of r*sin(i) changes so does the frequency? Its got me baffled.
Please help. |
|
|
|