Introduction: Software PWM With Arduino/attiny

Hey guys this is an instructable on how use software PWM. The reason you may want to use software PWM is it allows for pwm to be used on any pin. Which is ok for arduino's which has like 6 (don't quote me on that) but its great for an attiny which only has 2 pwm ports but with software pwm you can have all the usable pins as pwm pins. In this instructable I will explain the code and working behind SPWM (software PWM) as I couldn't find it anywhere on the internet. So enjoy and Comment any problems you have. I won't cover how to upload sketches to an attiny and although will be using an arduino uno, if you change the pin numbers and upload this sketch to an attiny it should work absolutely fine.

Step 1: Step 1: How It Works

PWM stands for pulse width modulation and essentially it imitates an analogue signal. the best demo of this would be fading an led with a potentiometer, which is exactly what were doing, just with software pwm. PWM turns the voltage high and low for different amounts of time which is so fast that the human eye can't detect the changes and it looks to be fading, this is an example of persistence of vision. I used lots of different resources to find out how this worked and one of the most helpful was this youtube video (or at least the first 7 minutes).

The important thing that i took away from this is the duty cycle is the percentage of power needed and the length of the time the output is high, determines how much voltage is outputed. I hope that makes sense to you I will go a bit more in depth later on but feel free to ask me any questions you may have.

Step 2: Step 2: Wiring

The diagram is a bit unclear but here's what's going on

arduino 5V --> power rail

arduino GND --> ground rail

arduino pin 8 --> 220 ohm resistor --> led anode (positive/longer leg)

Led cathode (negative / shorter leg) --> ground rail

left pin of potentiometer --> power rail

arduino pin A2 --> wiper pin/ middle pin of potentiometer

right pin of potentiometer --> ground rail.

Step 3: Step 3: the Code

This is the longest step but I will explain how it works in the next step.

float frequency = 100; //the frequency of the cycle
float cycle_length; //how long each pwm cycle should be on for

float duty_cycle; //the percentage of power we want

int time_on; // how long the output should be high

int time_off; //how long the output should be low

float v_out; //the amount of voltage the led should draw

int pot_pin = 2; //pin with potentiometer

int pwm_pin = 8; // pin that will act like a pwm pin

void setup() {

// put your setup code here, to run once:


//set the pins

pinMode(pot_pin, INPUT);

pinMode(pwm_pin, OUTPUT);

digitalWrite(pwm_pin, LOW);

//calculate the length of the cycle

cycle_length = 1000000/frequency; //length of one pwm cycle in microseconds


void loop() {

// put your main code here, to run repeatedly:

int val = analogRead(pot_pin); //get the pwm value

v_out= map(val, 0, 1024, 0, 255); //gets the pot value from 0-1024 and turns it into a value from 0-255

duty_cycle = v_out/255; // percentage of power being drawn as decimal.

time_on = duty_cycle * cycle_length; // work out the time it should be on

time_off = cycle_length-time_on; // work out the time it should be off

if(time_on > 0)


digitalWrite(pwm_pin, HIGH);

delayMicroseconds(time_on); // turns led on for short anount of time


digitalWrite(pwm_pin, LOW);



Step 4: Step 4: How the Code Works

I decided to make this into another step as step 3 was already really long.

The picture above is what really helped me understand it

If we remember from the video in step 1 pwm needs 2 variables to be able to work out the on and off time, these are the cycle length/time period and the duty cycle. Using the picture above I will show you how to work these out.

cycle_length = 1000000/frequency

cycle_length is the equivalent of time period in the above picture but since we are using microseconds as we need it faster than the human eye can track and there are 1000000 microseconds in a second it makes is 1000000 instead of 1. you can also change the frequency but keep it above 60 as that causes problems.

duty_cycle = v_out/255

in the example above the duty cycle was already set but to find our duty cycle it is basically the percentage of the potentiometer turned = the percentage of led brightness e.g, 50% turned = 50% brightness = 50% of the voltage needed. And if we do some simple maths to find percentage its (value / total value)*100 but since we need it as a decimal we don't need to multiply by 100 so it is just value/total value.

And if we follow the example above

ton = duty cycle * time period

This mean is the percentage of time its on is proportionate to the percentage of power we need for the led brightness, which is the same in our code as is the last part of the example

toff = time period - duty cycle

This line is just pretty simple maths

if(time_on > 0)


digitalWrite(pwm_pin, HIGH);
delayMicroseconds(time_on); // turns led on for short anount of time


Simple code that says only if the time it should be on is greater than 0 turn the pin high for that amount of time.

Step 5: Step 6 : Your Ready

Thanks for reading and comment any problems you have or you can message me. Please spread the word about this as i would like to help as many people who are stuck with this as I can.

I decided to make this instructable as i couldn't find an easy to understand and well documented in depth tutorial on software PWM anywhere on the internet. I am also starting a new project using an attiny controlling RGB leds but it only has 2 pwm ports when i need 3 so software pwm was the only way, an instructable on this project will be coming soon so check back as I think you guys will enjoy it especially if you like saving money.

Here are a few links to sites that helped me out: (this is similar to my upcoming project but has a twist that I think you guys will like.)


judas79 made it!(author)2016-10-07

I found this very helpful, as I have trouble implementing code without understanding what exactly it does and also being an amateur at this.

DIY+Hacks+and+How+Tos made it!(author)2015-06-20

Nice tutorial. Thanks for sharing.