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

Help! - crazy problem driving 2 servos with a PIC

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
stumax



Joined: 16 May 2008
Posts: 2

View user's profile Send private message

Help! - crazy problem driving 2 servos with a PIC
PostPosted: Fri May 16, 2008 6:04 pm     Reply with quote

I'm trying to drive 2 servos to actuate some stuff. The PIC is a 16F877 running at 20MHz. There's a bunch of stuff going on whilst the servos are being driven so I'm doing the driving using 2 timers and interrupts. The method is:

1. Timer1 is setup to roll over every 26ms to give me the frame rate.
2. When it rolls over, its ISR resets Timer1 to 0 for next frame, then loads Timer0 with the value to allow it to roll over and interrupt for the correct pulse for servo1, enables that interrupt and sends the line for servo1 high.
3.When Timer0 interrupts it checks to see which channel we're working with:

For channel1 it sends the line for servo1 low, servo2 high then loads Timer0 with the value to allow it to roll over and interrupt for the correct pulse width for servo2. It also sets active channel to the next channel.

For channel2 it sends the line for servo2 low, resets the channel back to channel1 and disables the interrupt for Timer0.

Here's the code for the ISR's:
Code:
#int_TIMER0
void TIMER0_isr(void)
{
if (channel < 1)
{
output_low(SERVO_1);
output_high(SERVO_2);
set_timer0(128); //just a test value gives a 1.6ms pulse width
channel = 1;
}
else
{
output_low(SERVO_2);
channel = 0;
disable_interrupts(int_timer0);
}
//output_low(SERVO_1); //for testing servo1 by itself - works fine without the other stuff in this ISR
}

#int_TIMER1
void TIMER1_isr(void)
{
set_timer1(0);
set_timer0(128);
output_high(SERVO_1);
enable_interrupts(int_timer0);

}


Here's the setups for the timers:
Code:
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_64); //12.8us resolution, 3.2ms o'flow - for servo pulse width
setup_timer_1(T1_INTERNAL|T1_DIV_BY_2); //0.4us resolution, 26.2ms o'flow - for frame rate


Sounds OK so far. However, when it runs, the pulse for servo1 is always about 17us, regardless of what value I load into Timer0. The pulsed width for servo2 is perfect, as is the frame rate. You'll notice in Timer0's ISR there is a line commented out. This is a test line to see if it will work fine with only 1 servo being driven, I comment out the rest of the ISR. It works fine like this, so I know that in Timer1's ISR the correct value is being loaded into Timer0.

Any ideas? I've tried a bunch of things like changing the order in which things happen in each ISR, changing the pins being driven, changing timer setup values. BTW, Timer2 is being used to generate pulses for a stepper so it can't be used. I'm considering setting up Timer1 to roll over twice as often, once for each servo. This would affect the synchronising of the servos but it won't be a problem for this machine, however I would like to know what's wrong with this code. Thanks!
_________________
Stu Maxwell
newguy



Joined: 24 Jun 2004
Posts: 1903

View user's profile Send private message

PostPosted: Fri May 16, 2008 6:35 pm     Reply with quote

I see what you're trying to do, but you missed something. It's not enough to enable/disable an interrupt whenever you wish. You also have to ensure that the interrupt isn't already set when you re-enable it. Just because an interrupt is disabled doesn't mean that the hardware that is responsible for generating it isn't chugging along in the background. This is a long-winded way of saying that timer 0 is still running and still generating interrupts even when you have its interrupt disabled. Disabling an interrupt doesn't mean that the interrupt isn't stopped from being created - it just forces the PIC into ignoring it when it does get set.

You have to alter your re-enable of timer 0 to also clear its interrupt flag in addition to resetting it to 0. The proper order would be 1. set to 0, 2. clear timer 0 interrupt flag, 3. re-enable timer 0's interrupt.
stumax



Joined: 16 May 2008
Posts: 2

View user's profile Send private message

PostPosted: Fri May 16, 2008 6:45 pm     Reply with quote

Thanks for the reply. Actually I did this just after posting (ie cleared the interrupt for Timer0 before enabling it) and now it works fine.
_________________
Stu Maxwell
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
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