CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to support@ccsinfo.com

problem with variable ADC & RC servo motor
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
Guest








problem with variable ADC & RC servo motor
PostPosted: Tue Apr 22, 2008 1:02 am     Reply with quote

Hi.. my project is to control RC servo motor using ADC(0-5volts).. i use 10bit ADC and variable resistor.. in my simulation using proteus, the ADC is working but the servo motor only turn and stay at position 90 deg...

is my calculation in delay wrong? but the total freq is 50Hz=20,000us

OR it is not suitable using this methods or there are others way?

can anyone help me? thanks..

Code:

#include <16F877A.H>
#device ADC=10
#use delay (clock=20000000)
#use rs232 (baud=9600, xmit=PIN_C6, rcv=PIN_C7)
#FUSES HS, NOWDT, NOPROTECT, BROWNOUT, NOLVP

#define servo1 PIN_b0  //pin 38

#BYTE ADCON0 = 0x1F
int16 ch1_result;
double ADC;
int i;


void main()
{




   setup_adc_ports(ALL_ANALOG);     // SETTING ADC CHANNEL // A0 A1 A2 A3 A5 E0 E1 E2 Ref=Vdd
   setup_adc(ADC_CLOCK_DIV_32);





while(1)
     {

         set_adc_channel(1);  //A1
         ch1_result = read_adc();


         ADC=ch1_result;
         printf("\f ADC: %3.2f",ADC);   

         delay_ms(500);





         for (i=0;i<50;i++)
         {
         output_high(SERVO1);
         delay_us(450+((1023-ADC)*1.98));//initial 0deg
         output_low(SERVO1);
         delay_us(19550-((1023-ADC)*1.98)); //initial 0deg

         }

     }

}

 
Matro
Guest







PostPosted: Tue Apr 22, 2008 1:46 am     Reply with quote

In a first very quick review, I see something wrong.
You have to know that the 10-bit result of ADC is left-justified by default.
So the values will go from 0x0000 to 0xFFC0 with step of 0x0040.
So your calculations (based on a right-justified values) will be definitely wrong.
The 2nd thing is that it should be better to use timer interrupts for delay, but this code should work if you correct the calculations.

Matro.
Guest








Re: problem with variable ADC & RC servo motor
PostPosted: Tue Apr 22, 2008 1:52 am     Reply with quote

Code:

#include <16F877A.H>
#device ADC=10
#use delay (clock=20000000)
#use rs232 (baud=9600, xmit=PIN_C6, rcv=PIN_C7)
#FUSES HS, NOWDT, NOPROTECT, BROWNOUT, NOLVP

#define servo1 PIN_b0  //pin 38

#BYTE ADCON0 = 0x1F
#BIT ADFM = 0x9F.7    //used to choose ADC result justification

int16 ch1_result;
double ADC;
int i;

void main()
{
setup_adc_ports(ALL_ANALOG);     // SETTING ADC CHANNEL // A0 A1 A2 A3 A5 E0 E1 E2 Ref=Vdd
setup_adc(ADC_CLOCK_DIV_32);

ADFM = 1;      //1 for ADC result to be right-justified, 0 for left-justified

while(1)
     {
         set_adc_channel(1);  //A1
         ch1_result = read_adc();
         ADC=ch1_result;
         printf("\f ADC: %3.2f",ADC);   
         delay_ms(500);
         for (i=0;i<50;i++)
         {
         output_high(SERVO1);
         delay_us(450+((1023-ADC)*1.98));//initial 0deg
         output_low(SERVO1);
         delay_us(19550-((1023-ADC)*1.98)); //initial 0deg
         }
     }
}



In this code I added the tip that sets a right justification for ADC results.
That's one solution, the other is to change calculation appropriately and keeping the left justification as I already explained.

Matro.
Ttelmah
Guest







PostPosted: Tue Apr 22, 2008 2:46 am     Reply with quote

The ADC value, is not 'left justified by default'. In CCS, if you select 'ADC=10', the chip is setup to give a right justified result. Selecting 'ADC=16', gives a left justified result.
Look at the table, in the 'read_adc' section of the manual, for how the value is returned.
Now, first thing. When you select on ADC channel, you _must_ wait for Tacq, _after_ this, before reading the ADC result. Move your delay down to between selecting the channel, and reading the ADC. This shouldn't mtter in your case (since once you have 'selected' the channel the first time, the selection remains the same on subsequent loops. In fact, move the selection outside the loop entirely (never do anything you don't have to in a loop!).
Now, get rid of the floating point arithmetic. Treat 'FP', as something you only use if you must. In your original example, you take a integer value of '1023' max, and convert it to a float value of '1023' max, then print it displaying decimal points. This does nothing, since the number is integer. Unfortunately, if you print using a FP number, this takes a lot of time, since the printf, has to perform successive FP divisions.
Big thing missing, is that you are not disabling the internal comparators. On the 'A' chip, the analog sources _default_ to connecting to this, rather than the ADC.
Code:

#include <16F877A.H>
#device ADC=10
#use delay (clock=20000000)
#use rs232 (baud=9600, xmit=PIN_C6, rcv=PIN_C7)
#FUSES HS, NOWDT, NOPROTECT, BROWNOUT, NOLVP

#define servo1 PIN_b0  //pin 38

int16 ch1_result;
int32 time;
int i;

void main()  {
    setup_adc_ports(ALL_ANALOG);     // SETTING ADC CHANNEL // A0
    //A1 A2 A3 A5 E0 E1 E2 Ref=Vdd
    setup_adc(ADC_CLOCK_DIV_32);

    set_adc_channel(1); //Put outside the loop
    setup_comparator(NC_NC_NC_NC); //Probably the problem
    while(1) {
         ch1_result = read_adc();
         time=((1023-ch1_result)*99)/50; //This generates the required
         //time in uSec, without using FP.
         printf("\f Time: %5.3Lw",time);   //Display the time in mSec
         //Shows if the maths is right.
         //delay_ms(500); //This risks making the servo hiccup between
         //the loops. If the gap between servo pulses is too long, some
         //servos will shift. Why have it?.
         for (i=0;i<50;i++) {
            output_high(SERVO1);
            delay_us(450+time);//initial 0deg
            output_low(SERVO1);
            delay_us(19550-time); //initial 0deg
         }
     }
}

Hopefully you will find this gets close to what you want.

Best Wishes
arawana



Joined: 06 Apr 2008
Posts: 19
Location: SINGAPORE

View user's profile Send private message

still cannot work..
PostPosted: Tue Apr 22, 2008 6:55 am     Reply with quote

huhu~ i try both program, but it still same.. the ADC change but the motor still stay at 90 degree position..

for program Ttelmah write;

Code:
 printf("\f Time: %5.3Lw",time);   //Display the time in mSec


when i compile, an error occur.. it said --> print (%) format invalid
so i just // that line and it can compile.. but the motor still dont move.. the PWM signal also cannot see from oscilloscope


for program Matro write;

it can be compile.. but motor still cannot work.. stay at 90 deg..

here is the picture of simulation using Proteus 7.1..




if i try the program without ADC, the RC motor can turn to the position i want...
Matro
Guest







PostPosted: Tue Apr 22, 2008 7:16 am     Reply with quote

Try to replace
Code:

         output_high(SERVO1);
         delay_us(450+((1023-ADC)*1.98));//initial 0deg
         output_low(SERVO1);
         delay_us(19550-((1023-ADC)*1.98)); //initial 0deg

By
Code:

         output_high(SERVO1);
         delay_us(450+((1024-ADC)*2));//initial 0deg
         output_low(SERVO1);
         delay_us(19550-((1024-ADC)*2)); //initial 0deg

To see if it works.

Matro.
arawana



Joined: 06 Apr 2008
Posts: 19
Location: SINGAPORE

View user's profile Send private message

signal
PostPosted: Tue Apr 22, 2008 7:21 am     Reply with quote

from the signal i see in oscilloscope.. i use program matro write..

the frequency is change when the ADC change..

from what i learn, the position of RC motor only change due to the change of duty cycle and the freq still remain same (50Hz)

here is a picture at 0V=1 (ADC value)




here is a picture at 5V=1023 (ADC value)



but for Telmah program [i double slash the printf("\f Time: %5.3Lw",time);]
..the PWM signal i get .. when the duty cycle getting bigger n bigger suddenly it will turn small again and then bigger and bigger again when i increase the voltage... same when i decrease the voltage...
Ttelmah
Guest







PostPosted: Tue Apr 22, 2008 7:37 am     Reply with quote

It sounds as if you must have a very old compiler. The '%w' format as existed for a couple of years...
This might be part of the problem, since some older compiler have major issues with the initialisation of some parts of particular chips.

What is the compiler version?.

Just substitute:
printf("\f Time: %5Ld",time); //Display the time in uSec

And see what numbers you are getting.

Best Wishes
Ttelmah
Guest







PostPosted: Tue Apr 22, 2008 7:46 am     Reply with quote

Mine is hiccuping, because of a missing cast. The maths line needs to be:

time=((int32)(1023-ch1_result)*99)/50; //This generates the required

With this, and using the normal numeric output, it should work.

Best Wishes
arawana



Joined: 06 Apr 2008
Posts: 19
Location: SINGAPORE

View user's profile Send private message

PostPosted: Tue Apr 22, 2008 7:51 am     Reply with quote

i use ide version 3.4 PCB PCM PCH 3.18

after i change %5Ld , the value i get,

0.00V = 712
0.51V = 508
1.02V = 302
1.53V = 97
2.03V = 1201
2.54V = 995
3.05V = 790
3.56V = 584
4.07V = 378
4.58V = 172
5.08V = 0
Ttelmah
Guest







PostPosted: Tue Apr 22, 2008 7:59 am     Reply with quote

Yes. The error will be at 1.796 volts, 'going downwards', without the arithmetic cast given.

Best Wishes
arawana



Joined: 06 Apr 2008
Posts: 19
Location: SINGAPORE

View user's profile Send private message

still cannot work..
PostPosted: Tue Apr 22, 2008 8:00 am     Reply with quote

i have change this line but still the duty cycle increase and turn small again and increase again..

Code:

time=((int32)(1023-ch1_result)*99)/50; //This generates the required


RC servo not move.. only stay at 90deg...

is your simulation work Ttelmah? or u have try it on hardware?
Matro
Guest







PostPosted: Tue Apr 22, 2008 8:03 am     Reply with quote

Matro wrote:
Try to replace
Code:

         output_high(SERVO1);
         delay_us(450+((1023-ADC)*1.98));//initial 0deg
         output_low(SERVO1);
         delay_us(19550-((1023-ADC)*1.98)); //initial 0deg

By
Code:

         output_high(SERVO1);
         delay_us(450+((1024-ADC)*2));//initial 0deg
         output_low(SERVO1);
         delay_us(19550-((1024-ADC)*2)); //initial 0deg

To see if it works.

Matro.

Did you try this tip?
To be applied on the original code I gave. ;-)

Matro.
arawana



Joined: 06 Apr 2008
Posts: 19
Location: SINGAPORE

View user's profile Send private message

PostPosted: Tue Apr 22, 2008 8:13 am     Reply with quote

yes i have change the code that Matro gave..

The ADC change but the the RC motor stay at 90deg..
Matro
Guest







PostPosted: Tue Apr 22, 2008 8:21 am     Reply with quote

I think there is a mistake in your calculation.
Could you try this code :
Code:


#include <16F877A.H>
#device ADC=10
#use delay (clock=20000000)
#use rs232 (baud=9600, xmit=PIN_C6, rcv=PIN_C7)
#FUSES HS, NOWDT, NOPROTECT, BROWNOUT, NOLVP

#define servo1 PIN_b0  //pin 38

#BYTE ADCON0 = 0x1F
#BIT ADFM = 0x9F.7    //used to choose ADC result justification

int16 ch1_result;
double ADC;
int i;

void main()
{
setup_adc_ports(ALL_ANALOG);     // SETTING ADC CHANNEL // A0 A1 A2 A3 A5 E0 E1 E2 Ref=Vdd
setup_adc(ADC_CLOCK_DIV_32);

ADFM = 1;      //1 for ADC result to be right-justified, 0 for left-justified

while(1)
     {
         set_adc_channel(1);  //A1
         ch1_result = read_adc();
         ADC=ch1_result;
         printf("\f ADC: %3.2f",ADC);   
         delay_ms(500);
         for (i=0;i<50;i++)
         {
         output_high(SERVO1);
         delay_us(2000+ADC));//initial 0deg
         output_low(SERVO1);
         delay_us(3024-ADC)); //initial 0deg
         }
     }
}


Matro
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
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