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)?
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)?