Control the speed of a small DC motor with nothing but the serial port on your computer, a single MOSFET, and some trivial software. (The MOSFET and the serial port make up the "speed control"; you'll still need a motor and an appropriate power supply for that motor; while the serial port can provide the voltage to turn a mosfet on and off, it can't supply the current needed by a typical motor.)
Step 1: Look at the circuit
We're going to do Pulse Width Modulation using a generic N-channel power MOSFET connected to the Transmit data pin from the computer's rs232 port. When the serial port is idle, the pin will sit at the "1" state, which by the time it's translated to rs232, is something like -12V (depending on drivers, it might be closer to -9V or -5V), and the transistor will be quite OFF. When we transmit "0" bits on the serial port, the rs232 pin will go to +12V or so, which is enough to turn on most mosfets pretty well.
If we transmit a lot of "0" bis in a row, the motor will be close to fully ON and the motor will run fast. If we transmit mostly "1" bits, the motor will run more slowly.
Step 2: Wire it up
Since there's only a single component and only a few connections, you can just add wires "freeform."
MOSFETs are static sensitve, so be a little bit careful, but very little is critical.
Step 3: Set up files with PWM values
One way to control the motor without having to write ANY software is to prepare some files containing appropriate bytes (with more or less 0 bits), and simply COPY them to the COM port where you have the motor connected. I prepared several files (using emacs, but whatever works for you is fine):
- 0.pwm:: contains 5000 NULL characters (control-space on most keyboards)[br] This is about as close to "full speed" as we'll be able to get with this technique.
- 1.pwm:: contains 5000 control-A characters (ascii 01) (one "1" bit per char)
- 3.pwm:: contains 5000 control-C characters (ascii 03) (two "1" bits per char)
- 7.pwm:: contains 5000 control-G characters (ascii 07) (three "1" bits per char)
- 15.pwm:: contains 5000 control-O characters (ascii 15) (four "1" bits per char)
- 31.pwm:: contains 5000 control-_ characters (ascii 31) (five "1" bits per char)
- 63.pwm:: contains 5000 "?" characters (ascii 63) (six "1" bits per character)
- 127.pwm:: contains 5000 DEL characters (ascii 127) (seven "1" bits per character)
(Now that I've drawn pictures, you'll notice that the actual bit patterns aren't ideal. Since rs232 serial transmits LSB first, we really want to shift in zeros instead of ones. An excercise for the student!)
Step 4: Play with DOS: configure your COM port and copy the files
9600 bps is a common bitrate. It matches nicely to "about" one byte per millisecond, so in this case it corosponds to a PWM frequency of 1000Hz, which I think ought to be ok for smallish motors. You can experiment with different bit rates to see how things work, which is one of the advantages of this method.
Create a DOS (or "Command prompt") window (assuming you're using a windows OS), and configure
your com port like:
mode com1: 9600,n,7,1"
That tells the comm port to run at 9600bps, and send 7 bits in each character (to match up with our 7 different bit-lengths.) The "n" means NO parity, so those will be the only data bits. The "1" means there will be one "stop" bit, which will prevent us from turning the motor all the way on (oh well.)
So now you can turn on the motor with commands like:
copy 0.pwm com1:
Since we're sending 5000 characters at about 1 per millisecond, the motor should turn on at close to full speed for about 5 seconds. If you want less than 5 seconds, make a shorter file. Similarly, you can do:
copy 127.pwm com1:
to run the motor at the lowest possible speed. With the setup I had, the motor wouldn't turn at all with anything "slower" than 31.pwm, but YMMV (I think I had a 12V motor running off 5V of batteries.)
The COPY command lets you string files together, so if you want your motor to speed up and then slow down again, you can do something like:
copy 31.pwm+15.pwm+7.pwm+0.pwm+7.pwm+15.pwm+31.pwm com1:
Step 5: Control the motor from a program
If you're writing a program, you can probably open COM1: as a file and simply write to it as if it were any other file. Being able to time the periods that the motor is on by outputting a particular number of characters would seem to be very handy. Don't forget that the system is very likely to buffer the characters that you send to the serial port, so just because a WRITE call returns doesn't mean that the motor has finished doing whatever you told it to. Since we don't do anything "fancy" with the com port signals, you shouldn't have to investigate the arcane options that it might support. (although, if you can figure out how to send a BREAK sequence to the com port, that's a continuous "0" state, and will drive the motor ALL the way on; more than sending continuous 0 characters.)
If your programming language doesn't let you output to COM1:, you may still be able to control the motor by "calling" DOS to do copy commands.
(OK. I've downloaded Microsoft's Visual Basic Express 2005 (which is free) and managed to tie a horizontal scroll bar to the motor speed, controlled via the serial port. zip attached. It's probably got more than it needs to duplicate the program on your system, but I couldn't figure out exactly which bits were needed. The program is both simplified and made more difficult to understand (sorry) by being multi-threaded. One thread does nothing but output to the serial port, and the main thread reads the scroll bar and updates info used by the serial thread.)
Step 6: Experiment!
If things are basically working, this provides an awful lot of room for experimentation.
- Fix my bit patterns!
- Does the bitrate matter much?
- Do you have to control the width of "on" and "off" pulses, or is simply controling their ratio sufficient?
- If you only have to control the ratio, you can consider multi-character sequences at higher bit rates to get more speed levels. Outputing 0 followed by 127 would be about half on.
- This should work for dimming flashlight bulbs, too.