Electronic Projects, forums and more.

Go Back   Electronic Circuits Projects Diagrams Free > Electronics Categories > Micro Controllers


Micro Controllers Discuss all aspects of micro controllers - building them, coding them, etc. All controllers are welcome - PIC, BASIC, Z8 Encore!, etc.

Reply
 
LinkBack Thread Tools Display Modes
Old 19th November 2007, 05:53 PM   (permalink)
Default Servo jitters

I have finally got my code working but my servo jitters really badly. I'm using a 20ms interrupt to start my pulse and then a second interrupt running at 100us and counting it 11 times before turning my pulse off. Is this the wrong way to go about it? I'm using a 20MHz crystal.

#include <p18f4620.h>
#include <timers.h>
#include <stdio.h>
#include <delays.h>


void power (void);
void signal (void);
void HandlerHigh (void);
void HandlerLow (void);

unsigned char clock = 0;
unsigned char clock2 = 0;
unsigned char delay = 0;
int servo_on = 0;

void main (void)
{
int Time = 0;

INTCON = 0x20; //disable global and enable TMR0 interrupt
INTCON2 = 0x84; //TMR0 high priority
IPR1 = 0x00; //TMR1 low priority
RCONbits.IPEN = 1; //enable priority levels
INTCONbits.GIEH = 1; //enable interrupts
INTCONbits.GIEL = 1; //enable low interrupts
TMR1H |= 0xfe;
TMR1L |= 0x10;
WriteTimer0(61);

power(); // Led output to show pic has power

OpenTimer0(TIMER_INT_ON & T0_8BIT & T0_SOURCE_INT & T0_PS_1_256);
OpenTimer1(TIMER_INT_ON & T1_8BIT_RW & T1_SOURCE_INT & T1_PS_1_1);
WriteTimer0(61);

while (1)
{
signal(); //send out servo signal
}
}

void signal (void)
{
if (servo_on == 1)
{
servo_on = 0;
PORTAbits.RA1 = 1;
delay = 1;
clock2 =0;
}

if ((delay == 1) && (clock2 == 11))
{
clock2 = 0;
delay = 0;
PORTAbits.RA1 = 0;
}

}

/*Set a Led to show PIC is running*/
void power (void)
{
ADCON1 = 0x0f;
TRISA = 0x00000110;
PORTA = 0;
PORTAbits.RA0 = 1;
}


//----------------------------------------------------------------------------
// High priority interrupt vector

#pragma code VectorHigh = 0x08
void VectorHigh (void)
{
_asm
goto HandlerHigh //jump to interrupt routine
_endasm
}

//----------------------------------------------------------------------------
// High priority interrupt routine

#pragma code
#pragma interrupt HandlerLow

void HandlerHigh (void)
{
if (INTCONbits.TMR0IF) //check for TMR0 overflow
{
INTCONbits.TMR0IF = 0; //clear interrupt flag
WriteTimer0(61);
clock++;
Nop();
}
if (clock > 1)
{
clock = 0;
servo_on = 1;
}

}
//----------------------------------------------------------------------------
// Low priority interrupt vector
#pragma code VectorLow = 0x18
void VectorLow (void)
{
_asm
goto HandlerLow
_endasm
}

//----------------------------------------------------------------------------
// High priority interrupt routine
#pragma code
#pragma interrupt HandlerHigh
void HandlerLow (void)
{
if (PIR1bits.TMR1IF) //check for TMR1 overflow
{
PIR1bits.TMR1IF = 0; //clear interrupt flag
TMR1H |= 0xfe;
TMR1L |= 0x10;
clock2++;
}
}
Wilko is offline  
Old 19th November 2007, 06:08 PM   (permalink)
Default

Gosh, there are many ways to produce a jitter free low-overhead hi-rez' Servo pulse with a 20.0 msec period without tying up two Timers.

Let me study your code and get back to you Sir.

Please tell us what Clock frequency you're using?

Mike

Last edited by Mike, K8LH; 19th November 2007 at 06:56 PM.
Mike, K8LH is offline  
Old 19th November 2007, 07:28 PM   (permalink)
Default

I'm using the PIC18F4620 but I've wired in a 20MHz oscillating crystal. This I believe gives me a 0.2us per instruction.
Wilko is offline  
Old 19th November 2007, 07:37 PM   (permalink)
Default

Blatant AVR plug =)
Just use an AVR at 20mhz, get a 50ns instruction clock =)
Can't help you with the code I'm afraid, it's C. Timeing sensative applications (even interupt based) Are best done in assembly.
__________________
"Because I be what I be. I would tell you what you want to know if I
could, mum, but I be a cat, and no cat anywhere ever gave anyone a
straight answer, har har."
Sceadwian is offline  
Old 19th November 2007, 08:22 PM   (permalink)
Default

Sceadwian,

Yes, AVR devices have some incredibly nice features. You can get 50 nsec Servo pulse width resolution with a 20-MHz PIC by using the PWM module to develop the Servo pulse but I'm not certain that kind of Servo pulse width resolution is really necessary or perhaps even desirable.

Wilco,

I suspect there may be a few problems with your code and method.

One thing I noticed is you're trying to use 'or' instructions in the ISR to update the TMR1 register pair and you're probably not getting the result you're expecting. You might temporarily turn off Timer 1, write your 16 bit value to the TMR1 register pair, then turn Timer 1 back on but this still leaves you with screwed up 100 usec timing. You might want to consider using set-and-forget Timer 2 interrupts for your 100 usec timing or investigate the Timer 1 "special event trigger". Both methods could provide the reliable 100 usec timing you're looking for.

I suspect a Timer 0 problem in your code too. When you write the TMR0 register it clears the prescaler and you loose counts.

Have you considered using a single 100 usec Timer 2 interrupt and a counter in your ISR instead of your current method?

Increment the counter each interrupt and reset the counter to 0 after 200 interrupts (20 msecs). Set the Servo pin in the ISR when the counter is 0 and clear the pin in the ISR when the interrupt counter = 11.
Code:
//
//  pseudo ISR code
//
void ISR ()
{
    Counter++;            // bump 100 usec counter
    If (Counter = 200)    //
    {
      Counter = 0;        // new 20-msec period
      LATAbits.RA0 = 1;   // pulse on
    }
    if (Counter = 11)     //
    {
      LATAbits.RA0 = 0;   // pulse off
    }
    PIR1bits.TMR2IF = 0;  // clear Timer 2 interrupt flag
}
If you absolutely must use Timer 0 then you should use a 1:1 prescaler and add the period value to the free running TMR0 register to keep from losing counts;

Code:
//
//  pseudo ISR code
//
void ISR()
{
    INTCONbits.TMR0IF = 0;  // clear timer 0 interrupt flag
    TMR0 += 256-250;        // 250 x 200 nsecs = 50 usec interrupts
    Counter++;              // bump counter (integer)
    If (Counter = 400)      // if end of 20 msec period
    {
      Counter = 0;          // new 20-msec period
      LATAbits.RA0 = 1;     // turn on pulse
    }
    If (Counter = 22)       // if 1100 usecs
    {
      LATAbits.RA0 = 0;     // turn off pulse
    }
}
Good luck with your project.

Mike

Last edited by Mike, K8LH; 19th November 2007 at 08:58 PM.
Mike, K8LH is offline  
Old 20th November 2007, 01:27 AM   (permalink)
Default

BRILLIANT :-)

Works perfectly. Thank you very much Mike. I used timer 2 and copied your code example.
Wilko is offline  
Old 20th November 2007, 04:08 AM   (permalink)
Default

Cool. Glad to help.

Are you really only using ten steps for the entire 1.0 to 2.0 msec swing range of the Servo?
Mike, K8LH is offline  
Reply

Bookmarks

Thread Tools
Display Modes



Similar Threads
Title Starter Forum Replies Latest
Servo problems bananasiong Micro Controllers 0 16th September 2007 03:16 AM
Servo Controll... In reverse? savage Micro Controllers 9 1st December 2006 04:11 PM
Replacing RC Servo w/ Custom PCB (Open Servo) dknguyen Electronic Projects Design/Ideas/Reviews 3 29th May 2006 03:48 AM
Help required with servo motor controller mayhem Robotics Chat 3 26th May 2006 05:21 PM
Servo Motor Help Needed!!!! potpotpotpot Robotics Chat 10 10th May 2006 08:54 PM



All times are GMT. The time now is 01:37 AM.


Electronic Circuits  |  Learning Electronics
Powered by vBulletin® Version 3.7.0
Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.

eXTReMe Tracker