All you need to do in loop(); is to plug in your values for the desired servo position. In fact it runs fine with a completely empty loop(), perfectly streaming neutral pulses at 20ms intervals - not so useful !
Using the timer in Fast-PWM mode means that however busy the code in your loop() is, it has has no effect at all on the timing, the pulse stream continuing regardless of any long delays, display updates or whatever other distractions. Your loop() code can go for a picnic and all the while the pulses will be accurately generated in the background until your next servo position update.
The Arduino is running at 16mhz and the selected prescaler is "divide by 8" so the timer is running continuously at 2mhz. The basic time element therefore is half a microsecond, so the required servo position in uS is doubled and then loaded into OCR1B. For example, servo neutral is 1500uS so the corresponding value in OCR1B is 3000. Changing OCR1B to 2000 will give a 1000uS pulse
and the servo will drive to one end, and changing OCR1B to 4000 will give a 2000uS pulse and the servo will drive to the other end.
The value in OCR1B can be slowly incremented or decremented within the 2000-4000 range to give servo sweep, etc. Purely as an example I've shown it set by a pot on A2, but you can set it however you like, maybe have an array of positions to copy the movement of the old PIC servo exercser from many years ago!
It only drives one servo but its extremely accurate and the resolution is 0.5uS which is very tight
Cheers
Phil
Code: Select all
// Using the 16-bit timer in "Fast PWM mode" to drive a single servo on D10
// Runs in hardware, independently of any loop() code or interrupts
// Servo position in OCR1B=2000 to 4000 (1000 to 2000 doubled for .5uS clock)
// Framelength is in OCR1A=40000 (20ms doubled for .5uS clock)
void setup() {
TCCR1A = 0;
TCCR1B = 0;
TIFR1 |= (1 << OCF1A); // clear any pending interrupts;
TCCR1A |= (1 << COM1B1); // Toggle on B compare
TCCR1A |= (1 << WGM10) | (1 << WGM11); // Fast PWM mode, TOP = OCR1A
TCCR1B |= (1 << WGM12) | (1 << WGM13); // Fast PWM mode, TOP = OCR1A
TCCR1B |= (1 << CS11); // 8 prescaler
DDRB |= (1 << DDB2); //turn on output pin 10 = OC1B
OCR1A = 40000; // Frame rate 20ms - doubled for /8 prescaler
OCR1B = 3000; // initial servo pulse of 1500us - doubled for /8 prescaler
}
void loop(){
// in loop, all you need to do is to set OCR1B to double the required servo position,
// ie neutral=3000 for 1500uS. For example:
OCR1B=map(analogRead(2),0,1023,2000,4000);
}