View previous topic :: View next topic |
Author |
Message |
MAKInnovation
Joined: 16 Nov 2010 Posts: 61
|
PWM resolution |
Posted: Thu Dec 23, 2010 11:24 pm |
|
|
Following is the pwm routine of my code:
Code: |
INTS_PER_SECOND = 200;
#int_timer0
void servo_isr() {
PWM_count = --PWM_count;
if (PWM_count>=80 && PWM_count<=analog)
{
output_bit( PIN_B1, 1);
}
else
{
output_bit( PIN_B1, 0);
}
if(--int_count==0) {
++seconds;
output_toggle(PIN_B0);
int_count=INTS_PER_SECOND;
PWM_count=INTS_PER_SECOND;
}
}
|
This program gives a PWM output with the change of analog signal on AN0 pin of microcontroller.
It is working but with steps.
I want to increase the resolution of my steps, how could I do this?
Actually PWM_count is an 8bit integer and change the PWM at PIN B0 on change of discrete value that is 1.
But the analog value which comes from PIC analog pnp has a floating value and can have resolution of 0.1 or 0.2.
SO the question is simple, that is, I want to change PWM on PIN B0 with analog input at AN0 with resolution of 0.1 or 0.2.
Kindly help me with this problem. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sat Dec 25, 2010 5:18 pm |
|
|
I assume you mean that you want the PWM duty cycle to have 500
or 1000 steps, going from 0% duty cycle to 100%. Is that correct ?
What PWM frequency do you need ?
What PIC are you using ?
What is the oscillator frequency of the PIC ? |
|
|
MAKInnovation
Joined: 16 Nov 2010 Posts: 61
|
|
Posted: Wed Dec 29, 2010 1:24 am |
|
|
Actually I am driving a servo motor with timer0.
I have generated 20ms of waveform and looking it on oscilloscope.
You must know that the servo operates with 1ms to 2ms pwm.
Well timer 0 overflow with INTS_PER_SECOND = 400
and PWM can then be generated with some 30 steps for 1ms output.
as shown in my last code.
timer initialization value is:
setup_timer_0( RTCC_INTERNAL| RTCC_DIV_1 | RTCC_8_BIT);
which make the value of 51.2us with 20MH crystal.
I am using PIC16f877.
Suggest me with the suitable PIC, timer and coding method for driving the servo with at least more than 200 steps. i.e. almost analog in nature. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Dec 30, 2010 4:24 pm |
|
|
Here is a sample program that uses the CCP compare mode to generate
the servo pulse. It has over 600 steps to go from a 1ms pulse duration
to 2ms duration. If you run this program and look at pin B0 with an
oscilloscope, you will see the pulse width slowly increasing from 1 to 2 ms,
and then do it again, continuously.
Code: |
#include <16F877.h>
#fuses HS, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP
#use delay(clock = 20000000)
#define SERVO_PIN PIN_B0
// These pulse duration values are for a 20 MHz PIC oscillator
// frequency and a Timer1 divisor of 8.
#define PWM_PERIOD 12500L // Gives 20ms PWM period (50 Hz)
#define PULSE_1MS 625L // Gives 1ms high level pulse
#define PULSE_2MS 1250L // Gives 2ms high level pulse
int16 pulse_high_duration;
int8 pulse_done_flag;
//-----------------------------------
#int_ccp1
void ccp1_isr(void)
{
static int8 set_servo_pin_high = TRUE;
// If servo pin low level pulse time is finished,
// then do the high portion of the signal.
if(set_servo_pin_high)
{
output_high(SERVO_PIN);
set_servo_pin_high = FALSE;
CCP_1 += pulse_high_duration;
}
else // If high portion of signal is done, do the low part.
{
output_low(SERVO_PIN);
set_servo_pin_high = TRUE;
CCP_1 += (PWM_PERIOD - pulse_high_duration);
pulse_done_flag = TRUE;
}
}
//==========================================
void main()
{
int16 i;
setup_timer_1(T1_DIV_BY_8 | T1_INTERNAL);
set_timer1(0);
// Setup CCP to generate CCP1 interrupt when Timer1
// matches the value in the CCP1 registers.
setup_ccp1(CCP_COMPARE_INT);
output_low(SERVO_PIN);
// Initialize the variables and CCP1 to give a 1 ms servo pulse.
pulse_high_duration = PULSE_1MS;
CCP_1 = PWM_PERIOD - pulse_high_duration; // Pulse Off time
// This flag tells the main loop code (below) when it's OK
// to change the pulse_high_duration variable.
pulse_done_flag = FALSE;
clear_interrupt(INT_CCP1);
enable_interrupts(INT_CCP1);
enable_interrupts(GLOBAL);
while(1)
{
// Slowly increase the pulse from 1ms to 2ms.
for(i = PULSE_1MS; i < PULSE_2MS; i++)
{
while(!pulse_done_flag); // Wait until pulse is done
pulse_done_flag = FALSE;
disable_interrupts(GLOBAL);
pulse_high_duration = i;
enable_interrupts(GLOBAL);
}
}
}
|
|
|
|
MAKInnovation
Joined: 16 Nov 2010 Posts: 61
|
|
Posted: Sat Jan 01, 2011 6:36 am |
|
|
Thank you again for your help |
|
|
|