?lang_form? ?lang_select? ?lang_submit? ?lang_endform?
{HEADER END}
{FILE START}

library

?curdirlinks? - Rev 6

?prevdifflink? - Blame - ?getfile?

/*! \file servo.c \brief Interrupt-driven RC Servo function library. */
//*****************************************************************************
//
// File Name    : 'servo.c'
// Title                : Interrupt-driven RC Servo function library
// Author               : Pascal Stang - Copyright (C) 2002
// Created              : 7/31/2002
// Revised              : 8/02/2002
// Version              : 1.0
// Target MCU   : Atmel AVR Series
// Editor Tabs  : 4
//
// This code is distributed under the GNU Public License
//              which can be found at http://www.gnu.org/licenses/gpl.txt
//
//*****************************************************************************

#ifndef WIN32
        #include <avr/io.h>
#endif

#include "global.h"
#include "servo.h"

// Program ROM constants

// Global variables
// servo channel registers
u16 ServoPosTics;
u16 ServoPeriodTics;
u08 ServoChannel;
ServoChannelType ServoChannels[SERVO_NUM_CHANNELS];

// functions

//! initializes software PWM system
void servoInit(void)
{
        u08 channel;
        // disble the timer1 output compare A interrupt
        cbi(TIMSK, OCIE1A);
        // set the prescaler for timer1
        timer1SetPrescaler(TIMER_CLK_DIV256);
        // attach the software PWM service routine to timer1 output compare A
        timerAttach(TIMER1OUTCOMPAREA_INT, servoService);
        // enable and clear channels
        for(channel=0; channel<SERVO_NUM_CHANNELS; channel++)
        {
                // set minimum position as default
                ServoChannels[channel].duty = SERVO_MIN;
                // set default port and pins assignments
                ServoChannels[channel].port = _SFR_IO_ADDR(SERVO_DEFAULT_PORT);
                //ServoChannels[channel].port = (unsigned char)&SERVO_DEFAULT_PORT;
                ServoChannels[channel].pin = (1<<channel);
                // set channel pin to output
                // THIS IS OBSOLETED BY THE DYNAMIC CHANNEL TO PORT,PIN ASSIGNMENTS
                //outb(SERVODDR, inb(SERVODDR) | (1<<channel));
        }
        // set PosTics
        ServoPosTics = 0;
        // set PeriodTics
        ServoPeriodTics = SERVO_MAX*9;
        // set initial interrupt time
        u16 OCValue;
        // read in current value of output compare register OCR1A
        OCValue =  inb(OCR1AL);         // read low byte of OCR1A
        OCValue += inb(OCR1AH)<<8;      // read high byte of OCR1A
        // increment OCR1A value by nextTics
        OCValue += ServoPeriodTics; 
        // set future output compare time to this new value
        outb(OCR1AH, (OCValue>>8));                     // write high byte
        outb(OCR1AL, (OCValue & 0x00FF));       // write low byte
        // enable the timer1 output compare A interrupt
        sbi(TIMSK, OCIE1A);
}

//! turns off software PWM system
void servoOff(void)
{
        // disable the timer1 output compare A interrupt
        cbi(TIMSK, OCIE1A);
        // detach the service routine
        timerDetach(TIMER1OUTCOMPAREA_INT);
}

//! set port and I/O pin for channel
void servoSetChannelIO(u08 channel, u08 port, u08 pin)
{
        ServoChannels[channel].port = port;
        ServoChannels[channel].pin = (1<<(pin&0x07));
}

//! set servo position on channel
void servoSetPosition(u08 channel, u08 position)
{
        // input should be between 0 and SERVO_POSITION_MAX
        u16 pos_scaled;
        // calculate scaled position
        pos_scaled = ((u16)position*(SERVO_MAX-SERVO_MIN)/SERVO_POSITION_MAX)+SERVO_MIN;
        // set position
        servoSetPositionRaw(channel, pos_scaled);
}

//! get servo position on channel
u08 servoGetPosition(u08 channel)
{
        return (u08)( ((servoGetPositionRaw(channel)-SERVO_MIN)*SERVO_POSITION_MAX)/(SERVO_MAX-SERVO_MIN) );
}

//! set servo position on channel (raw unscaled format)
void servoSetPositionRaw(u08 channel, u16 position)
{
        // bind to limits
        position = MAX(position, SERVO_MIN);
        position = MIN(position, SERVO_MAX);
        // set position
        ServoChannels[channel].duty = position;
}

//! get servo position on channel (raw unscaled format)
u16 servoGetPositionRaw(u08 channel)
{
        return ServoChannels[channel].duty;
}

void servoService(void)
{
        u16 nextTics;

        if(ServoChannel < SERVO_NUM_CHANNELS)
        {
                // turn off current channel
                outb(_SFR_IO8(ServoChannels[ServoChannel].port), inb(_SFR_IO8(ServoChannels[ServoChannel].port)) & ~(ServoChannels[ServoChannel].pin));
        }
        
        // next channel
        ServoChannel++;

        if(ServoChannel != SERVO_NUM_CHANNELS)
        {
                // loop to channel 0 if needed
                if(ServoChannel > SERVO_NUM_CHANNELS)   ServoChannel = 0;
                // turn on new channel
                outb(_SFR_IO8(ServoChannels[ServoChannel].port), inb(_SFR_IO8(ServoChannels[ServoChannel].port)) | (ServoChannels[ServoChannel].pin));
                // schedule turn off time
                nextTics = ServoChannels[ServoChannel].duty;
        }
        else //(Channel == SERVO_NUM_CHANNELS)
        {
                // ***we could save time by precalculating this
                // schedule end-of-period
                nextTics = ServoPeriodTics-ServoPosTics;
        }

        // schedule next interrupt
        u16 OCValue;
        // read in current value of output compare register OCR1A
        OCValue =  inb(OCR1AL);         // read low byte of OCR1A
        OCValue += inb(OCR1AH)<<8;      // read high byte of OCR1A
        // increment OCR1A value by nextTics
        OCValue += nextTics;
//      OCR1A+=nextTics;
        // set future output compare time to this new value
        outb(OCR1AH, (OCValue>>8));                     // write high byte
        outb(OCR1AL, (OCValue & 0x00FF));       // write low byte
        // set our new tic position
        ServoPosTics += nextTics;
        if(ServoPosTics >= ServoPeriodTics) ServoPosTics = 0;
}
{FILE END}
{FOOTER START}

Powered by WebSVN v2.8.3