I'd like to share on the forum this little piece of code to control a servo with an ATtiny85 without any external library.
The code uses an interrpt on Timer0 to construct the PWM control to send to a servo, thus the timing for the PWM is expected to be robust and the main loop is free for other code.
/* PWM for servo control: period 20ms, pulse 1-2ms
- Using 1MHz internal clock, prescaler /8 for Timer0: the timer increments every 8us
- 1ms = 125counts, 2ms = 250counts, 20ms = 2500counts
*/
#define servo 0
#define switch 4
byte scaledcounter = 0; //this variable is used to count the number of interrupt calls, so to count 10*250counts. This is necessary because Timer0 is 8bits, thus it can't reach 2500 counts
byte pulse = 155; //this variable is used to set the lenght of the pulse (in multiples of 8us).
//Empirically: with a value of 148-163 my continous-rotation servo stops; 140 turns right
ISR(TIMER0_COMPA_vect){ // this is the interrupt routine
scaledcounter ++; // counts the number of calls
if (scaledcounter == 9) OCR0A = 250-pulse; // the servo pin remains low for 92508us + (250-pulse)8us
if (scaledcounter == 10){ // then the servo pin is high for pulse8us
digitalWrite(servo,1); // total = 92508us + (250-pulse)8us + pulse8us = 102508us = 20ms
OCR0A = pulse;
}
if (scaledcounter == 11){ // then a new period is started
digitalWrite(servo,0);
OCR0A = 250;
scaledcounter = 0;
}
}
void setup() {
pinMode(servo,OUTPUT);
pinMode(switch,INPUT_PULLUP);
TCCR0A = B00000010; // Timer0 is set to mode CTC
TCCR0B = B00000010; // the prescaler /8 is used
OCR0A = 250; // value to compare
TIMSK |= (1 << OCIE0A); // enables Timer0 Compare Match A Interrupt
}
void loop() {
if (digitalRead(switch)) pulse = 137; //just to exemply how to programatically change the value of the pulse duration
else pulse = 155;
}