View previous topic :: View next topic |
Author |
Message |
navajo
Joined: 21 Apr 2006 Posts: 4 Location: Spain
|
PWM: no way to move a servo |
Posted: Tue May 02, 2006 2:00 pm |
|
|
Hello everybody,
After check many post in this and other forums I still can not move my servo with the program I have written.
I have a breadboad with a PIC 16F877A and a 4MHz xtal. I
I want to move the servo left and right depending of the state of inputs RA0 and RA1. If I have the combination 01 the servo should move in one way and 01 in the other way.
I would appreciate if somebody could take a look into my code. It is built with 0 error and it is my first C program for a PIC.
#include <16F877A.h>
void main()
{
set_tris_a(0x03); // Input (0000 0011). Left-right control
set_tris_c(0x00);
setup_ccp1(CCP_PWM); // CCP as PWM
while (1)
{
switch (PIN_A0, PIN_A1)
{
case (PIN_A0==0) & (PIN_A1==1): // 01 turn right
{
output_low(PIN_C2);
setup_timer_2(T2_DIV_BY_4, 499, 1);
output_low(PIN_C2); // PIN C2=0 set_pwm1_duty(70);
output_high(PIN_C2); // PIN C2=1
}
case (PIN_A0==1) & (PIN_A1==0): // 10 turn left
{
output_low(PIN_C2);
setup_timer_2(T2_DIV_BY_4, 249, 1);
output_low(PIN_C2); // PIN C2=0
set_pwm1_duty(70);
output_high(PIN_C2); // PIN C2=1
}
default: // If 01 or 10 then STOP
{
output_low(PIN_C2);
setup_timer_2(T2_DIV_BY_4, 249, 1);
set_pwm1_duty(70);
output_high(PIN_C2);
} //default
} //switch
} //while
} //void
I have an old oscilloscope and I get a period signal but very different to what I am expecting to have.
Thank you for your help. |
|
|
andreluizeng
Joined: 04 Apr 2006 Posts: 117 Location: Brasil
|
|
Posted: Tue May 02, 2006 2:17 pm |
|
|
what kind of servo are you using ?
aeromodelling position servo ?
for a aeromodelling servo you have to respect the pulse periods if you want to move it to the right or to the left.
the periods is about 20ms and the pulse have to be between 1 and 2ms.
at 1ms it will move to the left, 2ms move to the right, and every step between 1 and 2ms is a position.
ex: a pulse with 1.5ms will position at the center.
got it ?
make sure that your pwm's period is in that range and if ur duty cicle corresponds of a 1~2ms pulse.
regards. _________________ Andre |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
|
navajo
Joined: 21 Apr 2006 Posts: 4 Location: Spain
|
|
Posted: Tue May 02, 2006 2:40 pm |
|
|
Hi,
Yes I am using a RC servo.
So andreluizeng you mean that to move the servo left I should use something like:
while (1)
{
output_low(PIN_C2);
setup_timer_2(T2_DIV_BY_4, 1(it refers to 1ms), 1);
set_pwm1_duty(70);
output_high(PIN_C2);
}
What I did was to calculate the value of PR2
PR2 = (f_osc / (4*f_pwm*(prediv_TMR2)))-1
using a f_pwm. of 1ms, that is, PR2=(4Mhz / (4*1000*4))-1
and set the result as period, that is why I have 249
About the set_pwm1_duty(70) I dont know how to calculate. I have read many manuals but no explanation.
Thank you andreluizeng |
|
|
andreluizeng
Joined: 04 Apr 2006 Posts: 117 Location: Brasil
|
|
Posted: Tue May 02, 2006 2:42 pm |
|
|
PCM Programmer is right, i forgot to talk about that,
you just use SWITCH if you want to teste the possible values to a variable not for constants.
example of code:
Code: |
char Var;
Var = getchar (); // value from rs232
switch (Var)
{
case 'a' : bla bla bla bla;
break;
case 'b' : ble ble ble ble;
break;
default : bli bli bli bli;
break;
}
|
regards.
[/code] _________________ Andre |
|
|
andreluizeng
Joined: 04 Apr 2006 Posts: 117 Location: Brasil
|
|
Posted: Tue May 02, 2006 2:53 pm |
|
|
You better write a specific routine for this, i dont like very much to use ccs's pwm to control this type of application.
try to use something like this:
Code: |
#define SERVO PIN_X (you choose which pin)
// values for Direction 1 to 3
void MoveServo (int Direction)
{
int i;
if (Direction == 1) // move to the left
{
// generate a pwm with period of 20ms and a pulse with 1ms
for (i = 0; i < 50; i++)
{
output_high (SERVO);
delay_ms (1);
output_low (SERVO);
delay_ms (19);
}
}
if (Direction == 2) // move to the center
{
// generate a pwm with period of 20ms and a pulse with 1,5ms
for (i = 0; i < 50; i++)
{
output_high (SERVO);
delay_ms (1);
delay_us (500); // note this is microseconds
output_low (SERVO);
delay_ms (18);
delay_us (500);
}
}
if (Direction == 3) // move to the right
{
// generate a pwm with period of 20ms and a pulse with 2ms
for (i = 0; i < 50; i++)
{
output_high (SERVO);
delay_ms (2);
output_low (SERVO);
delay_ms (18);
}
}
return;
}
|
regards. _________________ Andre |
|
|
Guest
|
|
Posted: Tue May 02, 2006 4:33 pm |
|
|
Thank you very much andreluizeng and PCM programmer, nice links and much much more easy to work with delay than wirh CCS applications functions.
I will try a new code version.
Thanks again |
|
|
tavioman
Joined: 22 Feb 2006 Posts: 65
|
|
Posted: Tue May 02, 2006 4:33 pm |
|
|
Very good tutorials.
Thanks for this links. |
|
|
navajo
Joined: 21 Apr 2006 Posts: 4 Location: Spain
|
Still no PWM signal generated |
Posted: Mon May 08, 2006 1:20 am |
|
|
Hello again people,
I was working in the idea of andreluizeng. I used his PWM function into my program. I think the main progam section fails. What I want to do is, if pins RA1 and RA0 have 0v or 5v, (that is what I call in the program PIN_A0==1 or PIN_A0==0), the servo should move left , right or stop.
I have check the .lst file and there is almost no code on it.
I would appreciate if you could take a look to ma code and tell me any idea to keep working.
Thanks a lot everybody
#include <16F877A.h>
#define SERVO PIN_C2
#use delay(clock=4000000)
void MoveServo (int Direction);
/*------------------ Main Program --------------------*/
void main(void)
{
while (1)
{
if (PIN_A0==1 && PIN_A1==0) //if pin RA0=1 and RA1=0 turn left
MoveServo(1);
if (PIN_A0==0 && PIN_A1==1) //if pin RA0=1 and RA1=1 turn right
MoveServo(3);
if (PIN_A0==0 && PIN_A1==0) //if pin RA0=0 and RA1=0 stop
MoveServo(2);
}
}
/*-------------------- FUNCTIONS ---------------------*/
void MoveServo (int Direction) // values for Direction 1 to 3
{
int i;
if (Direction == 1) // move to the left
{
// generate a pwm with period of 20ms and a pulse with 1ms
for (i = 0; i < 50; i++)
{
output_high (SERVO);
delay_ms (1);
output_low (SERVO);
delay_ms (19);
}
}
if (Direction == 2) // move to the center
{
// generate a pwm with period of 20ms and a pulse with 1,5ms
for (i = 0; i < 50; i++)
{
output_high (SERVO);
delay_ms (1);
delay_us (500); // note this is microseconds
output_low (SERVO);
delay_ms (18);
delay_us (500);
}
}
if (Direction == 3) // move to the right
{
// generate a pwm with period of 20ms and a pulse with 2ms
for (i = 0; i < 50; i++)
{
output_high (SERVO);
delay_ms (2);
output_low (SERVO);
delay_ms (18);
}
}
return;
}
[/code] |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Mon May 08, 2006 3:16 am |
|
|
Did you have a look at your compiler output messages? Compiling your program i got: Quote: | >>> Warning 203 "C:\Mijn progs\Test_0\main.c" Line 16(1,1): Condition always TRUE
>>> Warning 204 "C:\Mijn progs\Test_0\main.c" Line 18(1,1): Condition always FALSE
>>> Warning 204 "C:\Mijn progs\Test_0\main.c" Line 21(1,1): Condition always FALSE
>>> Warning 204 "C:\Mijn progs\Test_0\main.c" Line 24(1,1): Condition always FALSE |
All your if statements fail because you are comparing the constant value PIN_Ax instead of the value at the input pin. Change these lines to Code: | if ((input(PIN_A0)==1) && (input(PIN_A1)==0))
etc |
|
|
|
navajo
Joined: 21 Apr 2006 Posts: 4 Location: Spain
|
Working |
Posted: Mon May 08, 2006 3:34 am |
|
|
ckielstra, thank you very much to you and all people how helped me. The servo is now working.
Thank you very much. |
|
|
|