|
|
View previous topic :: View next topic |
Author |
Message |
montypaul
Joined: 08 May 2008 Posts: 3
|
4 KHz PWM without CCP module - help |
Posted: Mon Jun 16, 2008 12:07 pm |
|
|
I am a beginner with pic, i am trying to make a device that generate a 4 KHz PWM with variable duty cycle (controlled via a potentiometer) using a device that does not have hardware pwm inside.
I wrote this code, it works but the duty cycle changes only by 4 steps. I guess it cannot withstands all the instructions in the main program. Does anybody can suggest a simple routine for generate the pwm even with a lower resolution, with 4 khz frequency?
Thanks to all!
Code: |
#include <12f675.h>
#DEVICE ADC=8
#use delay(clock=4000000)
#fuses XT, NOPROTECT, NOPUT, NOWDT, NOBROWNOUT, NOCPD, NOMCLR
int8 duty;
void main()
{
setup_adc(ADC_CLOCK_INTERNAL); //enables the a/d module and sets the clock to internal adc clock
setup_adc_ports(sAN0); //sets all the adc pins to analog
set_adc_channel(0);
delay_us(10);
OUTPUT_LOW ( PIN_A2 );
OUTPUT_LOW ( PIN_A3 );
setup_timer_0 ( RTCC_INTERNAL | RTCC_8_BIT | RTCC_DIV_1 );
enable_interrupts ( INT_RTCC );
enable_interrupts ( GLOBAL );
set_timer0 ( 0 );
while(1)
{
duty=read_adc();
if (duty<=5) //bicolor led
{
duty=0;
OUTPUT_HIGH ( PIN_A2 );
OUTPUT_LOW ( PIN_A3 );
}
if (duty>=250) //bicolor led
{
duty=255;
OUTPUT_LOW ( PIN_A2 );
OUTPUT_HIGH ( PIN_A3 );
}
if ((duty!=255)&&(duty!=0))
{
OUTPUT_LOW ( PIN_A2 );
OUTPUT_LOW ( PIN_A3 );
}
if ((get_timer0()<=duty)&&(duty!=0)) // pwm
{
OUTPUT_HIGH ( PIN_A1 );
}
else
{
OUTPUT_LOW ( PIN_A1 );
}
}
}
/*****************************************************************************************************/
#INT_RTCC
void TIMER_INTERRUPT ( void )
{
set_timer0 ( 0 );
}
|
_________________ Paul |
|
|
John P
Joined: 17 Sep 2003 Posts: 331
|
|
Posted: Mon Jun 16, 2008 5:33 pm |
|
|
OK, here's an idea, not complete but perhaps it's a starting point.
With a 4MHz oscillator, you're executing 1 instruction per microsecond. That gives you 250 instructions (or 256 if you're willing to be inaccurate) per 1/4000 seconds. It's way too slow to do much with interrupts, so don't use them.
Start the timer but don't enable interrupts.
Set up the ADC for left-justified output, and start a loop like this:
Code: |
while (1)
{
if (tmr0 < adresh) // Counter high enough to turn off the output?
{
OUTPUT_LOW ( PIN_A2 ); // Yes
OUTPUT_HIGH ( PIN_A3 );
}
else
{
OUTPUT_HIGH ( PIN_A2 ); // No
OUTPUT_LOW ( PIN_A3 );
}
if (!bit_test(adcon0, 1)) // Last ADC reading done?
bit_set(adcon0, 1); // Yes, start a new one
}
|
This is very much rough-and-ready code, and in particular you won't see an output that's always 0 for a zero ADC reading, but it should show a reasonable change in duty cycle. The key point is that the counter runs whether it triggers an interrupt or not, and you can use its value to compare with the desired duty cycle, and set the output accordingly. Actually I said "triggers an interrupt", and it will always trigger the interrupt flag, but your program doesn't need to respond to that flag or even look at it. Note also that the ADC output is used directly as the desired duty cycle, in the interests of saving time.
I hope this is sane, even if it's not exactly correct! |
|
|
|
|
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
|