View previous topic :: View next topic |
Author |
Message |
LearningPIC Guest
|
PWM - Pulse Width Modulation issues |
Posted: Fri Jun 15, 2007 8:13 pm |
|
|
I'm trying to get PWM working. I am using a Tower Hobbies system 3000 (STD TS-53) servo motor. I figure this should be easy enough to do. I tried two ways to do this. One I used the code below which should correspond to 50Hz and 7% duty cycle. However the motor just grinds for a few seconds, then squeeks and doesn't do much. I tried varrying the frequencies and duty cycles. But according to the datasheet and other people that used this motor 50Hz and 7% should work.
I even tried using a delay of 2ms for outputing PIN_B7 on and then a delay of 18ms for leaving PIN_B7 low. But once again, does not work and the worst part is that I can't produce consistent results. Anyone have an idea what might be wrong?
#include <16F877A.h>
#fuses HS
#use delay(clock=20000000)
void main()
{
setup_timer_2(T2_DIV_BY_1, 99999, 1);
set_pwm1_duty(28000);
setup_ccp1(CCP_PWM);
while(1)
{
} // Prevent PIC from going to sleep.
} |
|
|
RA Guest
|
|
Posted: Fri Jun 15, 2007 8:32 pm |
|
|
In PWM mode the pic16f877A is only capable of 10 bits of PWM resolution
(0-1023).
Your values exceed that of the hardware.
Also, at 20Mhz and div/16 prescaler the lowest possible repetition rate is 1.22Khz.
You could possibly use an interrupt driven software PWM or substantially lower your clock frequency if you wish to use the hardware PWM with 10 bit of resolution.
-Richard |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Jun 15, 2007 8:33 pm |
|
|
Quote: | setup_timer_2(T2_DIV_BY_1, 99999, 1);
set_pwm1_duty(28000); |
Download the CCS manual and look at the allowable size of the
parameters that can be used with the setup_timer_2() function
and the set_pwm1_duty() function. Link to CCS manual:
http://www.ccsinfo.com/downloads/ccs_c_manual.pdf
A key point is: This compiler is used with small microcontrollers.
The typical data type is an unsigned 8-bit number. This is not MSVC++.
Sometimes larger data types are used, but not often, with the PIC
hardware modules. If you keep that in mind, you will do well. |
|
|
LearningPIC Guest
|
|
Posted: Fri Jun 15, 2007 9:17 pm |
|
|
Ok so I can't get the hardware to count high enough unless I maybe cascade more than one timer together?
My other question is, couldn't I just use the following code:
Code: |
#include <16F877A.h>
#fuses HS
#use delay(clock=20000000)
void main()
{
set_tris_b(0);
while(1)
{
output_high(PIN_B7);
delay_ms(2);
output_high(PIN_B7);
delay_ms(18);
}
}
|
That should be enough to make the motor have a 2ms pulse with 20ms period (50 Hz frequency). Or is there something about using delays that won't make this work as I intend? |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
|
Guest
|
|
Posted: Fri Jun 15, 2007 11:15 pm |
|
|
I'm assuming this code should give me a frequency of 50Hz and a duty cycle of 8.2%. However when I run it, it does not produce the result I am expecting. Motor is trying to turn, but it can't. If only I could get my hands on an oscilliscope.
Code: |
#include <16F877A>
#fuses HS
#use delay(clock = 20000000)
#define PWM_PIN PIN_B1
#define LOOPCNT 390
int8 width;
//-------------------------------
#INT_RTCC
void tick_interrupt(void);
//====================================
main()
{
width = 32;
setup_counters(RTCC_INTERNAL | RTCC_8_BIT, RTCC_DIV_1);
enable_interrupts(INT_RTCC);
enable_interrupts(GLOBAL);
while(1);
}
//====================================
#INT_RTCC
void tick_interrupt(void)
{
static int8 loop = LOOPCNT;
static int8 pulse;
if(--loop == 0)
{
loop = LOOPCNT;
pulse = width;
}
if(pulse)
{
output_high(PWM_PIN);
pulse--;
}
else
{
output_low(PWM_PIN);
}
}
|
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sat Jun 16, 2007 2:05 am |
|
|
Quote: | #define LOOPCNT 390
static int8 loop = LOOPCNT; |
You need to learn your data types. What's the largest value an
unsigned 8-bit integer (int8) can hold ?
Also, you need to add NOLVP to your #fuses statement.
Without it, you risk having random lockups of the PIC. |
|
|
LearningPIC Guest
|
|
Posted: Sat Jun 16, 2007 8:46 am |
|
|
I modified static int8 loop = LOOPCNT; to static int16 loop = LOOPCNT; I added NOLVP. However the motor has the same problems as before, just jittering in the same spot. Thanks for all your help.
I guess the only thing left for me to do is to find an oscilliscope to make sure that I'm getting the correct output. If that is not the problem, then maybe try and find a function generator.
Code: |
#include <16F877A>
#fuses HS, NOLVP
#use delay(clock = 20000000)
#define PWM_PIN PIN_B1
#define LOOPCNT 390
int8 width;
//-------------------------------
#INT_RTCC
void tick_interrupt(void);
//====================================
main()
{
width = 20;
setup_counters(RTCC_INTERNAL | RTCC_8_BIT, RTCC_DIV_1);
enable_interrupts(INT_RTCC);
enable_interrupts(GLOBAL);
while(1);
}
//====================================
#INT_RTCC
void tick_interrupt(void)
{
static int16 loop = LOOPCNT;
static int8 pulse;
if(--loop == 0)
{
loop = LOOPCNT;
pulse = width;
}
if(pulse)
{
output_high(PWM_PIN);
pulse--;
}
else
{
output_low(PWM_PIN);
}
}
|
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sun Jun 17, 2007 2:33 pm |
|
|
I tested your latest code posted above, on a PicDem2-Plus board.
I get an approximately 50 Hz waveform, with a 5% duty-cycle positive
pulse (1 ms). I tested this with vs. 4.041 of the compiler. So, it is
working. |
|
|
Guest
|
LearningPIC |
Posted: Mon Jun 18, 2007 12:53 pm |
|
|
I just checked on the oscilliscope and it worked fine. I also learned out why it wouldn't work properly I'm so dumb. The motor I used I received from a friend and didn't know it wasn't a continuous rotation motor. I never even imagined anything else. But once I realized that, I found out that it does work properly. Thanks for your help PCM Programmer. |
|
|
LearningPIC Guest
|
|
Posted: Mon Jun 18, 2007 4:42 pm |
|
|
I spoke too soon. When I try it with the PIC it still doesn't work properly. I'm guessing that the way I have it setup the frequency is 50.08Hz, and this thing need an exact frequency to work properly. I'll have to find a way to increase the resolution. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Jun 18, 2007 5:04 pm |
|
|
I guess I didn't read your initial post very carefully. You're actually
just trying to drive a servo.
This is the TS-53 servo:
http://www2.towerhobbies.com/cgi-bin/wti0001p?&I=LXUK84
Here is a project page which shows how use that servo.
It has oscillscope waveforms.
http://www.dprg.org/projects/2003-05a/
CCS has a servo driver program. Here's the filename and location:
Quote: | c:\Program Files\Picc\Drivers\Servos.c |
Here's a demo program for it. The servo output pins are defined
near the start of the Servos.c file. The default pins are D6 and D7.
I tested the program below with PCM vs. 4.041 and it works.
You can see the servo pulses on pins D6 and D7 of the PIC.
Code: |
#include <16F877.h>
#fuses XT, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP
#use delay(clock = 4000000)
#include <servos.c>
//======================================
void main()
{
init_servos();
while(1)
{
set_servo(LEFT, FORWARD, 2);
set_servo(RIGHT, FORWARD, 3);
delay_ms(500);
set_servo(LEFT, FORWARD, 1);
set_servo(RIGHT, FORWARD, 2);
delay_ms(500);
}
} |
|
|
|
|