Saturday, November 30, 2013

Menggerakan Multiple Servo pada mikrokontroler Atmega644p

Dexter / / 0
Servo merupakan salah satu jenis motor dc. terdapat dua jenis servo yaitu continues servo dan standard servo, pada continues servo motor dapat terus berputar tanpa terhenti. pada standard servo, motor berputar dengan sudut antara 0 - 180 derajat. Servo bergerak melalui sinyal pulsa pwm dengan frekuensi 50Hz, rentang kerja servo adalah 900us sampai 2100us pulsa high dari 20000us.

Mikrokontroler dapat mengatur sudut servo dengan memberikan sinyal pwm, contoh jika kita memberikan sinyal 900us maka servo akan berada pada sudut 0 derajat. dan jika kita memberikan sinyal 1500us maka servo akan bergerak pada posisi 90derajat.begitupun dengan sinyal 2100us maka servo akan beraa pada posisi 180 derajat.

berikut source code untuk menggerakan servo dengan menggunakan interupt sehingga dapat menggerakan banyak servo pada 1 port mikrokontroler(8buah pin).

//File servo.h

 #include

#define SERVO_PORT  PORTB
#define SERVO_DDR   DDRB

// Upto 8 servos (since pulses are generated in
// sequence + only one port is used).
#define N_SERVOS    8

// Servo times (this is Futaba timing).
#define SERVO_MIN    920 // microseconds
#define SERVO_MAX   2120 // microseconds
#define SERVO_MID   (SERVO_MIN + SERVO_MAX) / 2

// Time between servo pulses.
#define SERVO_FRAME 20000 // microseconds (50Hz)

// Time slot available for each servo.
#define SERVO_TIME_DIV (SERVO_FRAME / N_SERVOS)

#if (SERVO_TIME_DIV < SERVO_MAX + 50)
#warning "Output fewer servo signals or increase SERVO_FRAME"
#endif
#if ((SERVO_TIME_DIV * (F_CPU / 1000000UL)) >= 0xFF00)
#warning "Output more servo signals or decrease SERVO_FRAME (or use the prescaler)"
#endif

// Computing timer ticks given microseconds.
// Note, this version works out ok with even MHz F_CPU (e.g., 1, 2, 4, 8, 16 MHz).
// (Not a good idea to have this end up as a floating point operation)
#define US2TIMER1(us) ((us) * (uint16_t)(F_CPU / 1E6))

// Servo times - to be entered as timer1 ticks (using US2TIMER1).
// This must be updated with interrupts disabled.
volatile uint16_t servoTime[N_SERVOS];
uint16_t servoData[10];
uint8_t tmpCRC[2] ;
// Servo output allocation (on a single port currently).
const static uint8_t servoOutMask[N_SERVOS] = {
    0b00000001, // PX0
    0b00000010, // PX1
    0b00000100, // PX2
    0b00001000, // PX3
    0b00010000, // PX4
    0b00100000, // PX5
    0b01000000, // PX6
    0b10000000, // PX7
};
// Servo mask is just the above masks ored.
#define SERVO_MASK 0xff




















file servo.c

#include "servo.h"

//Copied From Paparazzy
//for dxAutoPilot URO



void servoStart(void)
{
    // Outputs
    SERVO_DDR |= SERVO_MASK;
    // Setupt a first compare match
    OCR1A = TCNT1 + US2TIMER1(100);
    // start timer 1 with no prescaler
    TCCR1B = (1 << CS10);     
    // Enable interrupt
    TIMSK1 |= (1 << OCIE1A);
}

void servoSet(uint8_t servo, uint16_t time /* microseconds */)
{
    uint16_t ticks = US2TIMER1(time);
    cli();
    servoTime[servo] = ticks;
    sei();
}


void servo_init()
{
     uint8_t i;
    for(i = 0; i < N_SERVOS; i++) {
        servoTime[i] = US2TIMER1(SERVO_MID);
    }
    #if N_SERVOS > 2  
    servoTime[2] = US2TIMER1(SERVO_MIN);
    #endif
    servoTime[N_SERVOS-1] = US2TIMER1(SERVO_MAX);  
    servoStart();
    sei();


}
ISR(TIMER1_COMPA_vect)
{
    static uint16_t nextStart;
    static uint8_t servo;
    static bool outputHigh = true;
    uint16_t currentTime = OCR1A;
    uint8_t mask = servoOutMask[servo];
  
    if (outputHigh) {
        SERVO_PORT |= mask;
        // Set the end time for the servo pulse
        OCR1A = currentTime + servoTime[servo];
        nextStart = currentTime + US2TIMER1(SERVO_TIME_DIV);
    } else {
        SERVO_PORT &= ~mask;
        if (++servo == N_SERVOS) {
            servo = 0;
        }
        OCR1A = nextStart;
    }
    outputHigh = !outputHigh;
}

uint8_t degreeServo(unsigned char degree)
{    int min_pulse = 900;
    int max_pulse = 2100;
    int deg = min_pulse+((max_pulse-min_pulse)*degree*1.0/180); // for 0 - 180
//    int deg = min_pulse+((max_pulse-min_pulse)*(degree+90)*1.0/180);
    return deg;
}


untuk menggerakan servo pada sudut tertentu maka cukup memanggil fungsi degreServo(sudut)
contoh : degreeServo(45) -> maka akan bergerak pada posisi 45 derajat.




0 comments:

Latest