|
|
View previous topic :: View next topic |
Author |
Message |
fxfifi
Joined: 11 Apr 2008 Posts: 6
|
why my servo motor did not work |
Posted: Fri Apr 11, 2008 9:07 pm |
|
|
I'm using pic16F877A. i only have one input (temperature sensor - LM335) and one output (servo motor). i tried to control servo motor direct without sensor, its work. but when i tried to control servo with input (temperature sensor) my servo did not work. my printf appear (normal/suam/sedang/panas) but my servo did not move. why? anyone can help me? here is my source code...
Code: | #include <16F877A.H>
#device ADC=10 //10bit Analog digital conveter
#use delay (clock=20000000) // 20MHz
#use rs232 (baud=9600, xmit=PIN_C6, rcv=PIN_C7) //serial
#FUSES HS,NOWDT, NOPROTECT, BROWNOUT, NOLVP
#define SERVO1 PIN_b0 // motor RC servo //pin 33
#define led_hijau PIN_b6 // pin 39
#define led_merah PIN_b7 //pin 40
int i; // looping
//////////////////////////////////////////////////////////
////////////////////// ADC ///////////////////////////////
//////////////////////////////////////////////////////////
#BYTE ADCON0 = 0x1F
int16 ch1_result,ch2_result;
float volt;
#int_AD
AD_isr()
{
if (((ADCON0 & 0x38) >>3) == 1)
{
ch1_result = read_adc();
set_adc_channel(2);
}
else
{
ch2_result=read_adc();
set_adc_channel(1);
}
ADCON0 |= 0x4;
}
/////////////////////////////////////////////////////////////////////////////
////////////////////////////// function() ///////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
void suam()
{
for (i=0;i<30;i++) //60 deg
{
output_high(SERVO1);
delay_us(1900);
output_low(SERVO1);
delay_us(18100);
}
}
void sedang() //30 deg
{
for (i=0;i<30;i++)
{
output_high(SERVO1);
delay_us(1600);
output_low(SERVO1);
delay_us(18400);
}
}
void panas()
{
for (i=0;i<30;i++) // 0 deg
{
output_high(SERVO1);
delay_us(1300);
output_low(SERVO1);
delay_us(18700);
}
}
void normal()
{
for (i=0;i<30;i++) // 90 deg
{
output_high(SERVO1);
delay_us(2200);
output_low(SERVO1);
delay_us(17800);
}
}
/////////////////////////////////////////////////////////////////////////////
////////////////////////////////// main() ///////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
void main()
{
setup_adc_ports(ALL_ANALOG); // SETTING ADC CHANNEL
setup_adc(ADC_CLOCK_DIV_32);
enable_interrupts(INT_AD);
enable_interrupts(global);
set_adc_channel(1);
ADCON0 |= 0x4;
set_tris_b(0x00);
while(1)
{
volt=(float)((ch1_result)/1023.0*5); // ADC pin A1
printf("\f Volt: %3.2f",volt); // current volt
delay_ms(500);
if ((volt > 3.0)&&(volt<3.3))
{
printf("\f suam");
output_high(led_merah);
suam();
}
else if ((volt > 3.3)&&(volt<3.5))
{
printf("\f sedang");
output_high(led_merah);
sedang();
}
else if ((volt > 3.5))
{
printf("\f panas");
output_high(led_merah);
panas();
}
else
{
printf("\f normal");
normal();
output_high(led_hijau);
}
}
}
////////////////////////////////////////////////////
///////////////////////////////////////////////////
////////////////////////////////////////////////////
////////////////////////////////////////////////////
///////////////////test servo without sensor///////////////////////
////////////////////////////////////////////////////
/*
main()
{
while(1)
{
for (i=0;i<30;i++)
{
output_high(SERVO1);
delay_us(1700);
output_low(SERVO1);
delay_us(18300);
}
for (i=0;i<30;i++)
{
output_high(SERVO1);
delay_us(2200);
output_low(SERVO1);
delay_us(17800);
}
for (i=0;i<30;i++) // 180 deg
{
output_high(SERVO1);
delay_us(2400);
output_low(SERVO1);
delay_us(17600);
}
for (i=0;i<30;i++) // 90 deg
{
output_high(SERVO1);
delay_us(1500);
output_low(SERVO1);
delay_us(18500);
}
}
}
*/
////////////////////////////////////////////////////
////////////////test servo without sensor//////////////////////
////////////////////////////////////////////////////
/*
main()
{
while(1)
{
suam();
sedang();
panas();
normal();
}
}
*/
////////////////////////////////////////////////////
////////////////////////////////////////////////////
////////////////////////////////////////////////////
|
|
|
|
Guest
|
|
Posted: Sat Apr 12, 2008 2:32 am |
|
|
Your problem, is using INT_AD.
You trigger the ADC to convert. Then 96 instruction times latter, the ADC finishes it's conversion, and triggers the ADC interrupt. It takes about 30 instruction times to arrive in the interrupt. You use perhaps another dozen instructions performing the test to find which channel to read. Then call the 'read_adc' function, _which used without a value, triggers another conversion_. 96 instruction times latter, this value is available, and is read (another perhaps 8 instructions). You then trigger another ADC conversion to start, and exit the interrupt (about another 28 instructions tl you get back into your main code). About 74 instructions latter, the whole ADC cycle starts again. So your processor, ends up spending about 74 instructions in the 'main' code, and about 176 instructions in the interrupt handler. Time delays are _only_ done in 'main' time, so an instruction like 'delay_us(1900)', will take about 6400uSec to execute. Hence your servo timing goes completely screwed, and the servo stops working.
The serial code keeps working, because the timing for this is done in hardware.
Do a search here on INT_ADC. You will find a lot of posts by me, on why this really should _not_ be used. Even if you used the 'read_adc(ADC_READ_ONLY)' call, which is the correct way to read the ADC inside an interrupt loop, you would still spend nearly as lng, calling the interrupt, reading the value, and returning, as the ADC conversion itself takes.
For your code, it'll be simpler, and work better, to just use read_adc, to get the value, select the next channel to read, perform the servo update, and loop, without using the interrupt at all.
Best Wishes |
|
|
fxfifi
Joined: 11 Apr 2008 Posts: 6
|
|
Posted: Sat Apr 12, 2008 11:37 am |
|
|
thank you for your co-operation. so what should i do with my source code? |
|
|
fxfifi
Joined: 11 Apr 2008 Posts: 6
|
|
Posted: Sat Apr 12, 2008 9:08 pm |
|
|
please somebody help me...i got stuck with my source code..i don't know what modification i should do with my coding. i don't know how to setting adc/interupt. |
|
|
umka
Joined: 28 Aug 2007 Posts: 99 Location: New Zealand
|
|
Posted: Sat Apr 12, 2008 9:49 pm |
|
|
do you have to use an interrupt for the adc? why not just read it in the main routine.
do you have to use a floating point number why not use an integer like 55 represents 5.5V and 30 represent 3.0V coz as far as i understand floating point numbers take a lot longer deal with. |
|
|
fxfifi
Joined: 11 Apr 2008 Posts: 6
|
|
Posted: Sat Apr 12, 2008 10:34 pm |
|
|
so how the coding you suggest? |
|
|
fxfifi
Joined: 11 Apr 2008 Posts: 6
|
still cannot work |
Posted: Sun Apr 13, 2008 12:56 am |
|
|
ok.. i have change a little bit of my program.. i dont understand how to read adc without interrupt..
my summary project is like this... i want to control water valve using RC servo motor.. i have set if temperature between certain volt the motor will turn.. there are 4 condition normal, minimum, warm and hot..
when i run my project, the temperature rise and the LED change but the motor still not move..
i have search and ask my friend.. but still cannot work.. so i ask the expert in this forum.. hehe~ can any one help me adjust my program.. i am new in programming.. thanks
Code: | Code:
#include <16F877A.H>
#device ADC=10 //10bit Analog digital conveter
#use delay (clock=20000000) // 20MHz
#use rs232 (baud=9600, xmit=PIN_C6, rcv=PIN_C7) //serial
#FUSES HS,NOWDT, NOPROTECT, BROWNOUT, NOLVP
#define SERVO1 PIN_b0 // motor RC servo //pin 33
#define led_green PIN_b6 // pin 39
#define led_red PIN_b4 //pin 37
#define led_pink PIN_b7 //pin 40
#define led_blue PIN_b5 //pin 38
int i; // looping
//////////////////////////////////////////////////////////
////////////////////// ADC ///////////////////////////////
//////////////////////////////////////////////////////////
#BYTE ADCON0 = 0x1F
int16 ch1_result,ch2_result;
float volt;
#int_ad
AD_isr()
{
{
ch1_result = read_adc();
set_adc_channel(1);
}
ADCON0 |= 0x4;
}
/////////////////////////////////////////////////////////////////////////////
////////////////////////////// function() ///////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
void warm()
{
printf("\f temperature warm");
delay_ms(100);
for (i=0;i<30;i++) //0 deg
{
output_low(led_blue);
output_low(led_pink);
output_low(led_red);
output_high(led_green;
output_high(SERVO1);
delay_us(1900);
output_low(SERVO1);
delay_us(18100);
}
}
void minimun() //30 deg
{
printf("\f temperature minimum");
delay_ms(100);
for (i=0;i<30;i++)
{
output_low(led_green);
output_low(led_pink);
output_low(led_red);
output_high(led_blue);
output_high(SERVO1);
delay_us(1600);
output_low(SERVO1);
delay_us(18400);
}
}
void hot()
{
printf("\f stemperature hot");
delay_ms(100);
for (i=0;i<30;i++) // 60 deg
{
output_low(led_blue);
output_low(led_pink);
output_low(led_green);
output_high(led_red);
output_high(SERVO1);
delay_us(1300);
output_low(SERVO1);
delay_us(18700);
}
}
void normal()
{
printf("\f temperature normal ");
delay_ms(100);
for (i=0;i<30;i++) // 90 deg
{
output_low(led_blue);
output_low(led_red);
output_low(led_green);
output_high(led_pink);
output_high(SERVO1);
delay_us(2200);
output_low(SERVO1);
delay_us(17800);
}
}
/////////////////////////////////////////////////////////////////////////////
////////////////////////////////// main() ///////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
void main()
{
setup_adc_ports(ALL_ANALOG); // SETTING ADC CHANNEL
setup_adc(ADC_CLOCK_DIV_32);
enable_interrupts(INT_AD);
enable_interrupts(global);
set_adc_channel(1);
ADCON0 |= 0x4;
set_tris_b(0x00);
while(1)
{
volt=(float)((ch1_result)/1023.0*5); // ADC pin A1
printf("\f Volt: %3.2f",volt); // reading
delay_ms(500);
if ((volt > 3.0)&&(volt<3.3))
{
warm();
}
else if ((volt > 3.3)&&(volt<3.5))
{
minimum();
}
else if ((volt > 3.5))
{
hot();
}
else
{
normal();
}
}
}
| [/code] |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
|
fxfifi
Joined: 11 Apr 2008 Posts: 6
|
|
Posted: Sun Apr 13, 2008 1:54 am |
|
|
ok thanks... after trail n error.. my project wok!! thanks~~
code]
#include <16F877A.H>
#device ADC=10 //10bit Analog digital conveter
#use delay (clock=20000000) // 20MHz
#use rs232 (baud=9600, xmit=PIN_C6, rcv=PIN_C7) //serial
#FUSES HS,NOWDT, NOPROTECT, BROWNOUT, NOLVP
#define SERVO1 PIN_b0 // motor RC servo //pin 33
#define led_hijau PIN_b6 // pin 39
#define led_merah PIN_b4 //pin 37
#define led_pink PIN_b7 //pin 40
#define led_biru PIN_b5 //pin 38
int i; // looping
//////////////////////////////////////////////////////////
////////////////////// ADC ///////////////////////////////
//////////////////////////////////////////////////////////
#BYTE ADCON0 = 0x1F
int16 ch1_result;
float volt;
/////////////////////////////////////////////////////////////////////////////
////////////////////////////// function() ///////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
void suam()
{
printf("\f suhu output suam sekarang");
delay_ms(100);
for (i=0;i<30;i++) //0 deg
{
output_low(led_biru);
output_low(led_pink);
output_low(led_merah);
output_high(led_hijau);
output_high(SERVO1);
delay_us(1900);
output_low(SERVO1);
delay_us(18100);
}
}
void sedang() //30 deg
{
printf("\f suhu output sedang sekarang");
delay_ms(100);
for (i=0;i<30;i++)
{
output_low(led_hijau);
output_low(led_pink);
output_low(led_merah);
output_high(led_biru);
output_high(SERVO1);
delay_us(1600);
output_low(SERVO1);
delay_us(18400);
}
}
void panas()
{
printf("\f suhu output panas sekarang");
delay_ms(100);
for (i=0;i<30;i++) // 60 deg
{
output_low(led_biru);
output_low(led_pink);
output_low(led_hijau);
output_high(led_merah);
output_high(SERVO1);
delay_us(1300);
output_low(SERVO1);
delay_us(18700);
}
}
void normal()
{
printf("\f suhu output normal sekarang");
delay_ms(100);
for (i=0;i<30;i++) // 90 deg
{
output_low(led_biru);
output_low(led_merah);
output_low(led_hijau);
output_high(led_pink);
output_high(SERVO1);
delay_us(2200);
output_low(SERVO1);
delay_us(17800);
}
}
/////////////////////////////////////////////////////////////////////////////
////////////////////////////////// main() ///////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
void main()
{
setup_adc_ports(ALL_ANALOG); // SETTING ADC CHANNEL
setup_adc(ADC_CLOCK_DIV_32);
while(1)
{
set_adc_channel(1);
ch1_result = read_adc();
volt=(float)((ch1_result)/1023.0*5); // ADC pin A1
printf("\f Volt: %3.2f",volt); // BACAAN SEMASA
delay_ms(500);
if ((volt > 3.1)&&(volt<3.3))
{
suam();
}
else if ((volt > 3.3)&&(volt<3.5))
{
sedang();
}
else if ((volt > 3.5))
{
panas();
}
else
{
normal();
}
}
}
[/code] |
|
|
umka
Joined: 28 Aug 2007 Posts: 99 Location: New Zealand
|
|
Posted: Sun Apr 13, 2008 2:08 am |
|
|
you can try this i just finished working on it. i think it should work.
Code: | #include <16F877A.H>
#device ADC=8 // can change to 10bit if you want to increase accuracy
#use delay (clock=20000000) // 20MHz
#FUSES HS,NOWDT, NOPROTECT, BROWNOUT, NOLVP
#use rs232 (baud=9600, xmit=PIN_C6, rcv=PIN_C7) //serial
#define SERVO1 PIN_b0 // motor RC servo //pin 33
#define led_green PIN_b6 // pin 39
#define led_red PIN_b4 //pin 37
#define led_pink PIN_b7 //pin 40
#define led_blue PIN_b5 //pin 38
int8 i; // looping
unsigned int8 Volt; // Stores adc value 0-255
void warm()
{
printf("\f temperature warm");
for (i=0;i<30;i++) //0 deg
{
output_low(led_blue);
output_low(led_pink);
output_low(led_red);
output_high(led_green);
output_high(SERVO1);
delay_us(1900);
output_low(SERVO1);
delay_ms(18); // dont need to be exactly 200 Hz frequency only the high part is important as far as i know
}
}
void minimum() //30 deg
{
printf("\f temperature minimum");
for (i=0;i<30;i++)
{
output_low(led_green);
output_low(led_pink);
output_low(led_red);
output_high(led_blue);
output_high(SERVO1);
delay_us(1600);
output_low(SERVO1);
delay_ms(18); // dont need to be exactly 200 Hz frequency only the high part is important as far as i know
}
}
void hot()
{
printf("\f temperature hot");
for (i=0;i<30;i++) // 60 deg
{
output_low(led_blue);
output_low(led_pink);
output_low(led_green);
output_high(led_red);
output_high(SERVO1);
delay_us(1300);
output_low(SERVO1);
delay_ms(18); // dont need to be exactly 200 Hz frequency only the high part is important as far as i know
}
}
void normal()
{
printf("\f temperature normal ");
for (i=0;i<30;i++) // 90 deg
{
output_low(led_blue);
output_low(led_red);
output_low(led_green);
output_high(led_pink);
output_high(SERVO1);
delay_us(2200);
output_low(SERVO1);
delay_ms(18); // dont need to be exactly 200 Hz frequency only the high part is important as far as i know
}
}
void main()
{
setup_adc( ADC_CLOCK_INTERNAL );
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
set_adc_channel(1); // set up so sensor is on pin a1
delay_ms(15);
while(1)
{
Delay_ms(1000); // delay so it only check temp every second.
// can put whatever sample rate you want here.
Volt = read_adc(); //reads the adc result
// so will output int8 where 255 = 5V and so on assuming 5V supply
// actual voltage at sensor = 5V * (Volt/255)
printf("\f Volt int: %u",volt); // reading 0 to 255 for voltage factor
if ((volt > 153) && (volt < 168)) // int8 values for 3V and 3.3V
{ warm(); }
else if ((volt > 168) && (volt < 178)) // int8 values for 3.3V and 3.5V
{ minimum(); }
else if ((volt > 178)) //// int8 values for 3.5V
{ hot(); }
else
{ normal(); }
}
} |
|
|
|
|
|
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
|