A guy emailed me wanting to know how to write C code to do a servo slowdown device like this PICAXE one by Kevin Goom. So I started small and worked up to a full port of the PICAXE code in C. The only thing I left out is the indicator LED, but that's simple enough to add later.

I started out by just using the 12F683 to control a servo on GP4.

This code uses Timer1 in compare mode with special event trigger enabled. Special event trigger resets Timer1 and generates a CCP1 interrupt when the Timer1 counter value matches the value in CCPR1. Each time the interrupt is triggered it toggles the servo pin and sets CCPR1 to the next required value to generate a proper 20ms period servo pulse-train.

#include <system.h>

#pragma DATA _CONFIG, _INTOSCIO &_MCLRE_ON & _WDT_OFF
#pragma CLOCK_FREQ 8000000

volatile int servo;         //servo position

void main()
{
    int i;
    osccon = 0b01110001;    //set int osc to 8MHz
    cmcon0 = 7;             //disable comparator
    ansel = 0;              //disable A/D - digital I/O
    trisio = 0b00001000;    //set data directions
    ccp1con = 0b00001011;   //special event trigger
    t1con = 0b00010001;     //Timer1 enable, pre=2
    pie1.CCP1IE = 1;        //enable ccp1 interrupt
    intcon.PEIE = 1;        //enable peripheral interrupts
    intcon.GIE = 1;         //enable global interrupts

    servo = 260;
    while(1){
        delay_s(2);
        for(i=260;i<2150;i+=10){
            servo = i;
            delay_ms(35);
        }
        delay_s(1);
        servo = 260;
    }        
}

void interrupt(void)
{
    int i;
    if(gpio.GP4){
        gpio.GP4 = 0;
        i = 20000 - servo;
        LOBYTE(ccpr1l,i);
        HIBYTE(ccpr1h,i);
    }
    else{
        gpio.GP4 = 1;
        LOBYTE(ccpr1l,servo);
        HIBYTE(ccpr1h,servo);
    }
    pir1.CCP1IF = 0;        //clear interrupt flag
}
The code in action:



That was pretty easy, so I decided to rewrite to control the servo with Timer2, which is 8-bit (Timer1 is 16-bit). This took a bit more work in the ISR, but is necessary as I will be needing Timer1 for capture duties later. (Turns out I didn't end up using Timer2 in the final program, but learning how to control a servo with an 8-bit timer was entertaining.)

#include <system.h>

#pragma DATA _CONFIG, _INTOSCIO &_MCLRE_ON & _WDT_OFF
#pragma CLOCK_FREQ 8000000

bit longflag = 0;
unsigned char count = 0;
volatile unsigned char servo;

void main()
{
    int i,j;
    osccon = 0b01110001;    //set int osc to 8MHz
    cmcon0 = 7;             //disable comparator
    ansel = 0;              //disable A/D - digital I/O
    trisio = 0b00001000;    //set data directions
    t2con = 0b00000110;     //timer2 enable, pre 16
    pr2 = 187;              //timer2 period = 1.5ms
    pie1.TMR2IE = 1;        //enable timer2 match interrupt
    intcon.PEIE = 1;        //enable peripheral interrupts
    intcon.GIE = 1;         //enable global interrupts

    while(1){
        servo = 50;
        delay_s(1);
        servo = 250;
        delay_s(1);
    }        
}

void interrupt(void)
{
    unsigned char i;
    if((gpio.GP4 == 1) && (longflag == 0)){
        gpio.GP4 = 0;
        longflag = 1;
        count = 9;
        pr2 = 250;
    }
    else if(longflag){
        count -= 1;
        if(count == 0){
            pr2 = 255 - servo;
            longflag = 0;
        }
    }
    else{
        gpio.GP4 = 1;
        pr2 = servo;
    }
    pir1.TMR2IF = 0;           
}



The rest of this article is missing...

Next Post Previous Post