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: