PWM Servo Control with attiny85

Pursuing an idea to create a fully automated lightweight 360°  bracket that would work with pocket cameras I came across a challenge.


The starting point for the project was a 15kg torque mg995 servo powerful enough to move the camera when powered from a small 3v battery. I was planning to use an arduino programmed Attiny85 controller to drive the servo which is where I got stuck at first.

The Attiny85 wasn’t supporting the hardware servo library and the Software Servo library was producing pretty jerky and inconsistent movement. So I set out to write my own code for driving the servo with the Attiny85. First of I needed to know the specifications of servo control signal which I got from wikipedia


Easy right? Send a pulse every 20 ms that is in the range between 1000 and 2000 nanoseconds to tell the motor to move. So the only challenge now is getting the attiny85 to accurately pulse the signal which is tricky with the standard digitalWrite command because its just too slow. So the answer was to use assembler commands to change the port registers directly and here is the code:

unsigned long lastMicros = 0;
unsigned long lastMillis = 0;
int pos = 0;
void setup() {
pinMode(1, OUTPUT);

void loop() {
 unsigned long lastStepMillis = 0;
 for(pos = 300; pos < 900; pos += 1){ // control pulse duration while (lastStepMillis+300>millis()){ // move every 300 milliseconds
  while (lastMillis+20>millis()){ // repeat signal every 20 milliseconds
    while (lastMicros + pos > micros()){ // signal pulse
     PORTB |= _BV(PORTB1); // pulse high
    PORTB &= ~_BV(PORTB1); // pulse low
    lastMicros = micros(); // reset timer
   lastMillis = millis(); // reset timer
  lastStepMillis = millis(); // reset timer
 while (true){ // done! Lets run an endless loop so camera doesnt move again

3D models on Thingiverse:


3 thoughts on “PWM Servo Control with attiny85”

  1. Hi,
    I tried your code with a TowerPro SG90 Servo and when I plugged the data line into the analog pin 1 of the ATTiny, it would rotate smoothly but does not change speed. I am trying to understand your code but I do not understand what:

    while (lastStepMillis+300>millis()){ // move every 300 milliseconds

    is suppose to do. What I want is to be able to control 2 motors with 2 potentiometer. So I would like to modify your code to be able to respond to potentiometer values(after mapping from 0, 1023 to 0, 180). Could you please explain to me your code?

    1. Correction, I was using the FS90R Micro Continuous Rotation Servo. In fact, when I also tried the TowerPro SG90 Servo, which makes a high pitch sound and nothing moves. Another thing, I would like to ask is why did you choose pos to range from 300 to 900?

    2. Hi, apologies for the delay. The control pulse for the motor is based on the duration of the high pulse hence the delay ranging from 300 to 900 microseconds.

      The 300 millisecond while loop allows other code to run in between sending servo commands.

      You’ll have a pin free but you will have to be clever about your code.

Leave a Reply

Your email address will not be published. Required fields are marked *