Introduction: A Simple Introduction to Transistors and PWM (Pulse-Width Modulation)

The silicon transistor was invented in 1954 and has been considered one of the greatest inventions in the history of technology. Its invention practically spawned the field of electronics and contributed to all of our modern computers, iPods, phones, etc. If you've ever asked what a transistor is or does, you probably were told that it is like a switch. However, it is a bit more complicated than that.

This Instructable will detail a basic transistor and what it can be used for. I am making this because I have had a box of assorted transistors for a while and never really knew how to use them in circuits. After reading some tutorials online I combined some ideas together and figured out how to use transistors in basic circuits.

I will demonstrate the use of transistors by controlling PC fans from a computer's LPT (parallel) port. Then I will implement a simple form of PWM (pulse-width modulation) to control the fan's speed. This demonstrates the ability of transistors to use low-voltage, low-current signal lines (such as a parallel port or microcontroller IO line) to control higher voltage, higher current devices like motors (in this case, PC fans).

Step 1: How a Transistor Works

In this instructable I will be focusing on NPN transistors. A transistor has three terminals: Base, Emitter, and Collector. The base terminal is connected to the signal voltage, the collector is connected to the load, and the emitter is connected to negative (ground). Whenever the base voltage is zero, the collector voltage is also zero. Applying a small current to the base causes a proportionately larger current to flow through the collector. By doing this, a tiny amount of current from a signal can be used to drive larger currents to power heavier loads such as relays and motors.

Note that the load and the signaling devices must share a common ground. In the case of a fan (running from an external power supply) and a computer's LPT port, you can connect the ground terminal of the power supply to the ground pin on the LPT port to achieve this. For a microcontroller you can use the same ground for the chip and the load.

For my examples I soldered three NPN transistors to a small PCB and wired all of the emitters together to form a common ground. I did this to make connecting things easier. In the following examples I am only using one of the transistors. The other two are not affecting anything and can be disregarded entirely. The transistors are "MPS A06" labeled. According to the datasheet they can control up to 300mA and have a voltage limit at 80V. On my PCB, the brown wires are common ground, blue is collector (load), and white is base (signal).

Step 2: Programming for the Parallel Port

To generate the signal current for this experiment, I used the easiest thing that I already had access to. Since I don't have any microcontrollers or other cool devices, I resorted to my old laptop's LPT port. If you're using Windows you can try programs that are designed to flash LED's connected to the LPT port. However, I wanted to have a little more control so I wrote a little program in C++. I'm running Ubuntu Linux 9.04 on my laptop. Windows has an annoying restriction that prevents programs from directly using the legacy ports (LPT and serial) and having to use drivers to get around it is confusing and annoying, so I just used Linux, where it is easy to access the LPT port if you have root access.

The input and output functions are in a header called sys/io.h (some sites say asm/io.h, this is outdated and doesn't work in 9.04). The function ioperm() gives you access to the LPT port and the function outb() outputs binary to the port. The base address for the port is 0x378 and we are going to control all the outputs together, so writing a 255 to the port turns on all 8 output pins, writing a 0 turns them all off. Other combinations involve converting the number to binary which isn't going to be described in this Instructable.

Here is a sample program that will turn on the signal lines for 10 seconds and then turn them off. Compile it with g++ in the form "g++ lptfan.cpp -o lptfan.o" replacing lptfan with whatever you save it as.

//lpt controlled fan


Step 3: Connecting the Transistor, Fan, and Computer

Be careful! Drawing too much current from the LPT port or connecting higher voltage to the LPT port will destroy it. Only connect signal pins!

For this step, I'm using a PC fan (12V), a 9V transformer, and my transistor board to connect the fan to the PC. I have the base (white wire) connected to pin 2 on the LPT port, the collector (blue wire) connected to the fan's negative wire, the fan's positive wire connected to the power supply's positive wire, the brown wire to one of the LPT port's ground pins, and the other brown wire to the power supply's negative wire.

Step 4: Turn on the Power!

After double checking your connections to make sure that the LPT port is connected ONLY to the base of the transistor and ground, you can plug in the transformer or turn on the power supply to the circuit. The fan may or may not start spinning because some PC's or operating systems may leave the data pins on after booting. The fan should stop if you remove the white signal wire from the LPT port.

With everything connected, run the program you wrote in step 2. You'll have to use sudo and enter your password because port access is restricted. Start it by typing "sudo ./lptfan.o" (again typing whatever you called your program instead of lptfan) and hitting enter.

The fan should start spinning at full speed, run for 10 seconds, and then turn off.

Step 5: Write a Program for PWM

If you've gotten this far and the fan starts and stops correctly using the simple on-off program, you are now free to play with the code to make it do other things. Probably the most useful thing you can do at this point is write a PWM generator so that you can change the fan's speed. For this example, I am going to use a percentage to change the speed. For instance, inputting 10 percent makes the fan run at 10 percent speed and (if done right) approximately 10 percent of the input voltage. In this code I used a function to make it a little cleaner, you don't have to use functions.

As this is a quick program I threw together, there is no good way to exit it, just do CTRL+C to kill it.

//LPT-controlled fan

#include <iostream>
#include <sys/io.h>

#define base 0x378
using namespace std;

void runFan(int powerLevel)

//Turn the fan to 100% for 1 second to get it spinning

//Loop to generate PWM at a given percentage

int main()
int powerLevel = 0;
cout << "Power level %: ";
cin >> powerLevel;

Step 6:

After you compile the PWM example, you can run it like you did the first, using sudo. Type in any value from 1 to 100 to vary the fan's speed. You can experiment with low values to find the slowest speed that the fan can run at without stopping. This depends on the fan itself as well as the power supply. You will probably notice that the fan makes a buzzing sound even if it is stopped. This is because PWM uses high frequency pulses to create lower voltages and these pulses cause the coils in the motor to vibrate (similar to how speakers work) and produce sound. Adding a small capacitor across the fan's positive and negative wires will reduce this buzzing sound because the capacitor absorbs and smooths the pulses.


usbg3rd made it!(author)2011-04-23

What is the code if i use c++ aur visual basic 2008? Can any one help me

ARJOON made it!(author)2011-04-06

how can i use it to produce a square wave current. that will then be amplified by mosfets. the frequency must be variable

luckyvictor made it!(author)2010-05-31

 how to set up the experiment for the fan speed testing please?

CalcProgrammer1 made it!(author)2010-05-31

Look at the diagram in Step 3, it shows how to wire the fan, power supply, transistor, and parallel port.  On the software side you need to produce a pulse-width modulation signal (turning on and off really fast) with a specific duty cycle (duty cycle is the ratio of time on to time off, a 10% duty cycle has the switch on for 1/10th of the full cycle time, so 0.1ms if you are using a 1 millisecond cycle time).

In code, you can use a loop from 1 to 100 that sleeps a constant amount of time each iteration and turns off the pin when the counter hits the desired duty cycle percentage.  Put that loop in an infinite loop that first turns the pin on before starting to count.

C++ example:

  //turn lpt on
  for(int i = 0; i < 100; i++)
     if(i == duty_cycle)
         //turn lpt off

profpat made it!(author)2010-04-24

 this is a cool experiment, i will be doing this! thanks

CalcProgrammer1 made it!(author)2009-09-29

Awesome, going to order an Arduino this weekend. This method works for any general signal-level output (microcontroller, parallel port, arduino, etc). I ported my PWM generator to regular AVR code over the weekend and tested it on a board I borrowed, seems to work better on the AVR since it has a steady clock and output. You can also use PWM output to control hobby and robotics servos. Their signal pins can be driven via parallel port or microcontroller as long as you connect the ground from the motor to your parallel port's ground or microcontroller's ground. I have some continuous rotation motors from a Vex robotics kit that I want to use with an Arduino or standalone AVR (the Vex controller isn't open source and is based on PIC's, I like AVR's more).

About This Instructable



Bio: I finally graduated from Missouri University of Science and Technology (Missouri S&T, formerly University of Missouri Rolla) with a computer engineering degree. Originally from ... More »
More by CalcProgrammer1:Cheap and Easy Tachometer (RPM Sensor) for Brushed DC MotorsCheap Home Automation using Wireless Outlet ModulesATTiny USI I2C Introduction - A powerful, fast, and convenient communication interface for your ATTiny projects!
Add instructable to: