Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

Controlling servo motor by ADC using PIC18F4520

Status
Not open for further replies.

Ecappp

New Member
Specifications:
Microcontroller: PIC18F4520
Crystal: 1 MHz
Language: C Programming (not assembly codes)
Compiler: MPLAB C18 C Compiler (MCC18)

I have come up with a program to control a servo motor by ADC (potentiometer) using PIC18F4520. The control is successful.

However, there are 2 main problems with the program.
1) The program is 4 pages long (too long).
2) The turning of the servo motor is not smooth. This means, when I turn my
potentiometer, it does not really turn accordingly and smoothly as when
how I turn the potentiometer. It turns, calculates and stops according to
the ranges I have set using ADC. In short, it turns until the next range and
stops, then continue to turn again as it approaches other ranges.

Here is my program:

#include <p18f4520.h>
#include <delays.h>
void ADC_Calculation(void);

unsigned int result = 0;

void main()
{
unsigned int y;
ADCON0 = 0b00000001;
ADCON1 = 0b00001110; // only AN0 channel and internal voltage referencing
ADCON2 = 0b10000100; // Result Right justified, manual acquisition time

TRISA = 0b11111111;
TRISC = 0b11111000;
PORTC = 0b00000000;

while(1)
{
ADC_Calculation();

while((result>=0)&&(result<78)) //0.6ms
{
PORTCbits.RC0 = 1; // RC0 is output to the servo
Delay10TCYx(15);
PORTCbits.RC0 = 0;
Delay100TCYx(48);
Delay10TCYx(5);

ADC_Calculation();
}

while((result>=78)&&(result<157)) //0.75ms
{
PORTCbits.RC0 = 1;
Delay10TCYx(18);
PORTCbits.RC0 = 0;
Delay100TCYx(48);
Delay10TCYx(1);

ADC_Calculation();
}

while((result>=157)&&(result<235)) //0.9ms
{
PORTCbits.RC0 = 1;
Delay10TCYx(23);
PORTCbits.RC0 = 0;
Delay100TCYx(47);
Delay10TCYx(7);

ADC_Calculation();
}

while((result>=235)&&(result<314)) //1.05ms
{
PORTCbits.RC0 = 1;
Delay10TCYx(26);
PORTCbits.RC0 = 0;
Delay100TCYx(47);
Delay10TCYx(4);

ADC_Calculation();
}

while((result>=314)&&(result<392)) //1.2ms
{
PORTCbits.RC0 = 1;
Delay100TCYx(3);
PORTCbits.RC0 = 0;
Delay100TCYx(47);

ADC_Calculation();
}

while((result>=392)&&(result<470)) //1.35ms
{
PORTCbits.RC0 = 1;
Delay10TCYx(34);
PORTCbits.RC0 = 0;
Delay100TCYx(46);
Delay10TCYx(6);

ADC_Calculation();
}

while((result>=470)&&(result<509)) //1.5ms
{
PORTCbits.RC0 = 1;
Delay10TCYx(38);
PORTCbits.RC0 = 0;
Delay100TCYx(46);
Delay10TCYx(3);

ADC_Calculation();
}

while((result>=509)&&(result<627)) //1.65ms
{
PORTCbits.RC0 = 1;
Delay10TCYx(41);
PORTCbits.RC0 = 0;
Delay100TCYx(45);
Delay10TCYx(9);

ADC_Calculation();
}

while((result>627)&&(result<706)) //1.8ms
{
PORTCbits.RC0 = 1;
Delay10TCYx(45);
PORTCbits.RC0 = 0;
Delay100TCYx(45);
Delay10TCYx(5);

ADC_Calculation();
}

while((result>=706)&&(result<784)) //1.95ms
{
PORTCbits.RC0 = 1;
Delay10TCYx(49);
PORTCbits.RC0 = 0;
Delay100TCYx(45);
Delay10TCYx(1);

ADC_Calculation();
}

while((result>=784)&&(result<863)) //2.1ms
{
PORTCbits.RC0 = 1;
Delay10TCYx(53);
PORTCbits.RC0 = 0;
Delay100TCYx(44);
Delay10TCYx(7);

ADC_Calculation();
}

while((result>=863)&&(result<941)) //2.25ms
{
PORTCbits.RC0 = 1;
Delay10TCYx(56);
PORTCbits.RC0 = 0;
Delay100TCYx(44);
Delay10TCYx(4);

ADC_Calculation();
}

while((result>=941)&&(result<1024)) //2.4ms
{
PORTCbits.RC0 = 1;
Delay10TCYx(60);
PORTCbits.RC0 = 0;
Delay100TCYx(44);

ADC_Calculation();
}
}
}

void ADC_Calculation()
{
Delay10TCYx(1);
ADCON0bits.GO=1;
while(ADCON0bits.DONE==1);
result=(ADRESH*256)+ADRESL;
}


According to the ADC calculations, when I turn the potentiometer to the max, the value or result is approximately 1023 or 1024. I have made a total of 13 ranges each for every approximately 13.85 degrees (corresponding to 0 - 180 degrees) in order for the servo to turn smoother but it apparently still needs a lot of work.

So, I would to ask anyone if there is any other methods (preferably much shorter) I can use besides this ranging method I applied for this servo, mainly to make it turn even more smoother (without turning and stopping repeatedly)?
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top