Menggerakkan servo dengan mikrokontroler AVR/atmega biasanya menggunakan PWM (Timer) namun. Namun pada chip AVR seperti ATmega8 hanya memliki 3 pin OC (output dari comparator) juga ATmega16, 32 memiliki 4 pin OC, ATmega328 5 pin OC.
Untuk menggerakkan servo lebih banyak (multi servo) dari ketersediaan pin OC, bisa digunakan metode dua timer interrupt, yaitu :
- Timer1 berfungsi membangkitkan frekuensi 50Hz (periode 2ms) yang ditetapkan spesifikasi servo umum.
- Timer0 berfungsi mengatur lebar pulsa untuk masing-masing servo.
pengaturan
Servo memiliki sensor resistansi (potensio) untuk mendeteksi posisi dari aktuator. Terkadang ada servo yang nilai resistansinya berbeda-beda. untuk itu perlu diatur nilai offset dan tick-nya. berikut ini bebera variabel yang harus diatur sebelum digunakan:
Mengatur servo dengan atmega / AVR menggunakan codevision/Atmel studio harus memperhatikan bilangan pecahan, jadi pastikan hasil perhitungan posisi servo tepat.
#define F_CPU 16000000L #define jumlahServo 8 //Servo 1 = pin 0, servo 2 = pin 1 #define portServo PORTD //kalibrasi #define servoTickOffset 1200 #define servoTickMinimum 0 #define servoTickMaksimum 4000L
berikut listing programnya: (AVR Studio 6.2, ATmega32A)
#define F_CPU 16000000L #include <stdint.h> #include <avr/interrupt.h> #include <util/delay.h> #define jumlahServo 8 //Servo 1 = pin 0, servo 2 = pin 1 #define portServo PORTD //kalibrasi #define servoTickOffset 1200 #define servoTickMinimum 0 #define servoTickMaksimum 4000L volatile uint16_t servo[jumlahServo]; #define servoPortMask 0xFF >> (8-jumlahServo) ISR(TIMER1_COMPA_vect) { portServo = 0xFF; TCCR0 = (1<<WGM01) | (1<<CS00); // CTC, prescale 1, top ocr1a } ISR(TIMER0_COMP_vect) { uint8_t nilaiPort = 0x00; uint8_t byteNilai; for(uint8_t i=0;i<jumlahServo;i++) { uint16_t tick = servo[i] * (uint8_t)((servoTickMaksimum - servoTickMinimum) / 180); if(tick + servoTickOffset < TCNT1) { byteNilai = 0x00; } else { byteNilai = 0x80; } nilaiPort = byteNilai | (nilaiPort >> 1); } nilaiPort >>= (8 - jumlahServo); nilaiPort &= servoPortMask; portServo = nilaiPort ; if(TCNT1 > servoTickOffset + servoTickMaksimum) { TCCR0 = 0; } } int main (void) { (*(&portServo - 1)) = 0xFF; //port sebagai output OCR0 = 88 - 1; TIMSK = (1<<OCIE0); TCCR1A = 0; TCCR1B = (1<<WGM12) | (1<<CS11); // CTC, prescale 8, top ocr1a OCR1A = 20000 - 1;//50Hz TIMSK |= (1<<OCIE1A); sei(); while(1) { for(uint8_t i=0;i<180;i++) { servo[7] = i; _delay_ms(10); } for(uint8_t i=180;i != 0;i--) { servo[7] = i; _delay_ms(10); } } }