Вы находитесь на странице: 1из 28

///---

PWM speed control

The principles

To control the speed of a d.c. motor we need a variable voltage d.c. power source. If we take a
12v motor and switch on the power to it, the motor will start to speed up: motors do not respond
immediately so it will take a small time to reach full speed. If we switch the power off sometime
before the motor reaches full speed, then the motor will start to slow down. If we switch the
power on and off quickly enough, the motor will run at some speed part way between zero and
full speed. This is exactly what a p.w.m. controller does: it switches the motor on in a series of
pulses. To control the motor speed it varies (modulates) the width of the pulses - hence Pulse
Width Modulation.

Consider the waveform above. If the motor is connected with one end to the battery positive and
the other end to battery negative via a switch (MOSFET, power transistor or similar) then if the
MOSFET is on for a short period and off for a long one, as in A above, the motor will only rotate
slowly. At B the switch is on 50% and off 50%. At C the motor is on for most of the time and
only off a short while, so the speed is near maximum. In a practical low voltage controller the
switch opens and closes at 20kHz (20 thousand times per second). This is far too fast for the poor
old motor to even realise it is being switched on and off: it thinks it is being fed from a pure d.c.
voltage. It is also a frequency above the audible range so any noise emitted by the motor will be
inaudible. It is also slow enough that MOSFETs can easily switch at this frequency. However the
motor has inductance. Inductance does not like changes in current. If the motor is drawing any
current then this current flows through the switch MOSFET when it is on - but where will it flow
when the MOSFET switches off? Read on and find out!

Consider the circuit above: this shows the drive MOSFET and the motor. When the drive
MOSFET conducts, current flows from battery positive, through the motor and MOSFET (arrow
A) and back to battery negative. When the MOSFET switches off the motor current keeps
flowing because of the motor's inductance. There is a second MOSFET connected across the
motor: MOSFETs act like diodes for reverse current, and this is reverse current through the
MOSFET, so it conducts. You can use a MOSFET like this (short its gate to its source) or you
can use a power diode. However a not so commonly understood fact about MOSFETs is that,
when they are turned on, they conduct current in either direction. A conducting MOSFET is
resistive to current in either direction and a conducting power MOSFET actually drops less
voltage than a forward biased diode so the MOSFET needs less heatsinking and wastes less
battery power.

You should see from the above that, if the drive MOSFET is on for a 50% duty cycle, motor
voltage is 50% of battery voltage and, because battery current only flows when the MOSFET is
on, battery current is only flowing for 50% of the time so the average battery current is only 50%
of the motor current!

Main Capacitor
There is a problem however: when the MOSFET switches off, it not only interrupts the motor
current but it also interrupts the current flowing from the battery. The wires from the battery
have inductance (so does the battery) so when this current is interrupted this inductance causes a
voltage spike: in the circuit the main capacitor absorbs (most of) this spike. When the drive
MOSFET turns on again, battery current is asked to flow quickly - which it cannot. The main
capacitor supplies current during the period battery current is re-establishing. In a controller
capable of giving 120 amps this capacitor is working very hard and, if high current is drawn for
too long (depending on the battery lead length) the main capacitor can explode! During the early
development work we once used standard wire ended capacitors and melted the wires of the
capacitor! Capacitors have copper plated steel leads and in motor control applications these leads
can get extremely hot!

It will be apparent from the above that the work this capacitor does is extremely dependant on
the loop inductance of the battery wires. Long wires will have a high inductance. Twisting the
battery wires reduces their inductance.

It should go without saying that resistance in the battery leads will have an effect similar to
inductance, so these wires should be thick.

Also, some people want to put an ammeter in the battery leads. The temptation should be
resisted: simple car type ammeters in particular are highly inductive!

Simple controllers (such as are used for motorised golf bags) usually omit the expensive main
capacitor and rely on the capacitance of the battery. You can get away with this - and the Eagle
and Egret are such controllers. However a brief explanation of the effects are in order. To
illustrate this, a graph of the battery voltage as it can be seen with an oscilloscope connected
directly across the battery supply at the controller terminals. The scope earth is on the negative
rail.
The top is a 'scope's eye view of battery positive, bottom is of the motor negative terminal
(which is being switched by the controller). The waveforms have been cleaned up a lot to
illustrate: in practise there is a lot of 'dirty' ringing on the waveform. The supply shown is 12v.

We join the waveform at a point where there is no battery current: the motor output is high and
current is re-circulating in the flywheel. At A, the controller drive MOSFET switches on,
diverting the motor current to flow from the battery. But the battery leads have inductance! The
battery current cannot start immediately, so the battery leads drop a full 12v and the controller
voltage extinguishes until the lead inductance can charge up, which it does by point B. The time
A-B depends on current and battery loop inductance, and can be a significant proportion of cycle
time!

Then, at point C, the bottom MOSFET turns sharply off, interrupting the current. Motor current
is no problem, it keeps on flowing and the flywheel device is there to make sure it does! But you
cannot suddenly stop the battery current - so it objects in the form of a large voltage spike. This
spike rises until something gives: in this case it reaches the MOSFET avalanche breakdown
voltage and the MOSFET clamps it. You can easily see the flat-topped clamping voltage with an
oscilloscope. MOSFETs are rated for repeat avalanche energy and you have to be sure that the
1/2Li² stored in the battery loop inductance is well below the safe repeatable avalanche energy.

This is a problem: working out battery loop inductance is nigh on impossible - even for an
engineer. For a punter to do it is - well, difficult. So a manufacturer simply supplies controllers to
a known set of customers who use them in standard ways and sorts out problems as and when
they arise on a empirical basis. It's always a question of a non-technical customer trying to get
something for nothing: the main capacitor is needed. For some applications you can indeed get
away without! But it is definitely 'getting away with it'!

In controllers with a main capacitor, most (but not all) of the supply irregularities are smoothed
by the capacitor. Nevertheless you will see a positive overshoot and ringing as the battery current
is interrupted.

Regenerative braking

You may prefer to return to this bit after you have studied the two circuits below. The 'very
simple controller' does not include regen braking, the 'more sophisticated controller' does. This
description needs to be read in conjunction with the second circuit, but also refers to the diagram
above, so is inserted at this point to save you re-loading the diagram.

One of the well kept secrets of motor control seems to be regenerative braking. Yet it really is no
secret: the circuits that give regen braking are not uncommon, yet few people seem to realize
what happens. So here goes.
In the first circuit (above) is shown the output pair of MOSFETs, with the motor being driven. It
has also been pointed out that, to the motor, the output from the controller is a pure d.c. voltage
(because the motor's inductance keeps the current essentially constant during the switching
cycle). Now the motor will generate a back e.m.f. which is proportional to its speed of rotation.
At zero load this back e.m.f. will rise to be equal to the output from the controller.

We have already seen that the MOSFET is a bi-directional switch which conducts resistively
(when it is turned on) for both directions of current. So consider the situation when the current is
zero and the controller's output is now reduced. The motor's back e.m.f. is now higher than the
controller's output voltage - so the motor will try and feed current back into the controller. If it
succeeds in so doing the motor will be braked - we will have regenerative braking.

This type of circuit (where hi-side is turned on when the loside is off) is capable of sourcing
current or sinking it. The way this works is that the reversed motor current is now a forward
current to the flywheel MOSFET so when this is on it shorts out the motor - whose braking
current rises during this period (arrow B, reversed). The Flywheel MOSFET now turns off, but
this current must keep flowing - because of the motor's inductance. So it flows as reverse current
through the drive MOSFET, recharging the battery as is does so. The extra voltage for this is
derived from the energy stored in the motor's inductance. The process of switching from drive to
braking is entirely automatic. Moreover it is done entirely by the motor's speed exceeding the
drive voltage and without any change of state or switching within the controller. The regen
braking is, if you like, a by-product of the design of the controller and almost a complete
accident.

A very simple controller

The circuit below is about the simplest motor controller. For the benefit of anyone who knows
anything about motor controllers - 4QD did not design this circuit and we totally disown it, so
feel free to laugh or cry in disbelief. If you decide to make it - yes, it works, but since we did not
design it and don't like it - sorry, but you're on your own!

Nevertheless it is a circuit which we assembled at one time for a customer and we made several
thousands! There are a lot of them still trundling around UK golf courses - so it does work! It
also illustrates some of the things not to do!
The first three sections of the 4049 are arranged, with overall feedback via the 220K resistor and
a 22n capacitor on the input to give phase shift, as an oscillator. The output is a rectangular
waveform which is buffered by the other three stages of the 4049 to drive the MOSFET gates. As
the pot on the input is altered the average voltage on the 22n alters and this alters the mark-space
ratio (the duty cycle) of the oscillator. With the pot at minimum the oscillator stops with its
output low (i.e. the MOSFETs have no gate drive and are turned completely off) and with the pot
at maximum the oscillator stops with its output high - the MOSFETs are turned on all the time.
There are a few problems: firstly 'pulling' an oscillator like this varies its frequency. This doesn't
affect the working too much except that if the frequency gets too high the MOSFETs switch on
and off too quickly and get too hot. If it is too low the oscillator frequency becomes audible and
the motors whine. The other problem is that it is virtually impossible to pull an oscillator so that
it varies between a very high and a very low mark-space ratio! The 82K and 2n2 help in this
respect by introducing negative feedback to reduce the gain in the positive feedback loop so the
oscillator is only just oscillating: this is an addition 4QD made to the circuit and before this was
done the controller had a nasty jump from 80% to 100% full speed. Note that the IC is a 4049UB
(unbuffered) the buffered version will not work. Also certain makes of 4049UB do not work
properly (anyone got a use for some surplus Toshiba 4049UBs?) because they are too good!

The other nasty thing is that the pot only varies the oscillator over about 1/3 of its usable range:
this was OK in this application because the pot was used in a twist grip with only 90 degrees of
travel! But it was necessary to adjust the handle to get the range correct.

So much for the oscillator/modulator. But hands up anyone who has noticed the absence of the
main capacitor that I mentioned above. These are expensive components: golf caddies tend not to
use them for that reason. What happens is that when the MOSFETS turn off the battery loop
inductance causes a large voltage spike to build up across the drive MOSFET (which is turned
off - remember that the motor current is now (mainly) flowing through the diode). But there is a
36v zener diode between battery positive and MOSFET gate. The voltage spike is present across
this, so it conducts and the poor old MOSFET gets turned back on. In fact the zener limits the
turn-off rate of the MOSFET to that required to sustain a 40v pulse. MOSFETs are very rugged
devices and they will withstand this abuse (but there are more elegant ways of doing it). When
the MOSFET turns on again, the battery tries to push current through the battery loop inductance
- but cannot, so the voltage across the controller collapses in the attempt. But the MOSFET gate
has voltage present and if there were no diode in series with the zener the zener would be
forward biased, shorting the gate to the positive rail (now at zero voltage because of the
collapsed supply).

Notice also the power diode as flyback. If you look at the specs on the STP60N06 and the
25JPF40 you will see that this is some overkill (brute force and a lot of ignorance) but this
combination was arrived at by the customer simply by using a fatter device until he got no more
failures! No finesse whatsoever! To add insult to injury, the controller had virtually no
heatsinking and was housed in a plastic box. From an electronics designer's viewpoint there was
very little right with the circuit - except that it worked and the customer was quite happy with it!
I must admit that these are in fact the two most important criteria!

There also is nothing at all to limit the current flowing through the MOSFETs - except that the
MOSFETs are 2 x 60 amp devices and the stalled motor current was about 60 amps.

A slightly more sophisticated controller

The second circuit is, in a way, connected to the first. When I saw the first circuit I did not like it
and I quickly knocked together the second circuit to show the customer what could be done. It
actually works quite well but we only made a few prototypes. The Issue 2 became the first
production version of our 2QD series. You may safely assume that the current controllers have
advanced quite a long way beyond this early controller! Nevertheless it is a simple circuit which
does the job well (within its limitations). It well illustrates the principles.
The circuit uses a 3524, a 'regulating pulse width modulator' so a brief description of the IC
seems to be in order. The chip is aimed at power supplies and it has dual alternating outputs (pins
11 & 14) each of which can be on from 0% to 45% of the cycle time. But these outputs can be
connected together as we have done here. Connected thus the output is a regular pwm output (as
described at the top of this page) with a fixed frequency and an on time variable from 0% to
90%. Which, incidentally, is one of the chip's main shortcomings - a 90% on time means that
you can only get 90% of full speed, not 100%. This is the main reason 4QD stopped using it.

Oscillator

The oscillator frequency is controlled by the resistor and capacitor connected to pins 6 & 7. The
oscillator's output, as well as being internally connected, is available on pin 3. The oscillator
output is used to drive a voltage doubler for the hi-side MOSFET gate supply. More about that
later.

Regulator

There is also an on-board regulator: power input is to pin 15 (pin 8 is 0v), pin 16 is a regulated
reference voltage output of 5v. This is used to drive the speed control pot (the 3 pin connector). It
is also used to drive under-voltage shutdown into pin 10. More on that later!

Comparator

The oscillator's ramp is internally connected to a comparator which compares it to the speed
control signal. The output of this comparator is the pwm signal.

The demand speed input from the slider of the pot is fed to pin 2. This is the input of a
conventional op-amp, output from pin 9 and negative feedback is taken via a preset to pin 1: the
preset then adjusts the gain. However this op-amp is unconventional in that its output is also
connected to a second 'op-amp' in such a way that the second can over-ride the first and pull the
its output down. The second then is used for current limiting. Its positive input is on pin 4 and its
inverting input is pin 5 (which is connected to 0v).

The PWM output signal from the 3524 is fed to a pair of emitter followers to give adequate gate
drive. The 47R gate resistors slow down the rise (switch-on) time and the diodes give fast
switch-off. The 150pf also slows down the rise time. However this same 150pf also speeds up
the switch off of the hi-side (flywheel) drive. Hiside should be turned on only when loside
(drive) MOSFET is off and, ideally, there should be a small 'underlap' - a period during the
switching (both on and off) when neither MOSFET has gate voltage. If both are on
simultaneously a large punch-though current occurs which will cause heating and, in the
extreme, could be destructive.

MOSFETs

Because this uses the MOSFETs to sense their own current, it will accept a wide range of
MOSFETs. However - it is designed for standard MOSFETs. The high side in particular is
unlikely to work properly with logic level MOSFETs unless you change the values somewhat.

Be aware also that the MOSFET gates are driven from the battery line. It's an old circuit and
when designed MOSFETs had a gate breakdown voltage of around 30v. With modern MOSFETs
that voltage is getting lower and if you use a MOSFET with a 20v maximum gate voltage -
running the drive from a 24v battery is likely to result in smoke!

Hi-side gate drive


The hi-side MOSFET requires its gate to be raised above the +ve supply rail as, when it is
conducting, both its gate and source are, in effect, shorted to each other and to the supply rail. To
make it do this its gate must be at least 7 volts above its source, and therefore above the supply.

To accomplish this, the 3524's oscillator output is used to drive a pump circuit. The 3 transistors
at left amplify the oscillator to a squarewave which is fed to the 100n pump capacitor and to the
two diodes in a voltage doubler configuration. The output of the doubler is fed to the 12v zener.
Now, when the loside MOSFET is turned on, the bottom on this zener is connected to the
negative supply rail so there would be a direct current path from +24, through both diodes and
the zener. The 470R resistor in series with the pump diodes limits the current through this path.

This raises another point about hi-side pumps. As well as the voltage doubler there also exists a
'bootstrap' circuit. Ignore the pump circuit. When the loside MOSFET conducts, the zener (as we
have seen) will have current flowing through it so the capacitor across the zener will charge up.
When the hi-side switches on, this capacitor will retain this charge which will supply the hi-side
gate drive. We therefore don't really need the pump circuit. The hiside supply on this capacitor
will decay when the output stops switching with the lo-side switched off. This is at very slow
motor speeds as (or after) the motor stops so the lack of drive is not a problem. The only reason
the 2QD has the hiside pump is that is is possible to use two of them back-to-back in a bridge
configuration. In this particular configuration the hiside drive must not collapse when the output
stops switching.

Under-voltage cut-back.

If you discharge a lead-acid battery too much you permanently shorten its life. So this circuit
measures the supply and compares it with the 5v reference supply. If the battery voltage falls too
low the transistor inhibits the pwm circuit by feeding a signal to pin 10.

This feature is actually not as necessary as some people think: with every 'feature' such as this,
there are trade-offs. See our Guide Tour of Controller features for more.

Current limit

I have covered MOSFET mirror current sensing elsewhere. Here is an application. The 3524's
sense input is designed for this type of current sensing: it has a 200mV offset built in so when the
signal on pin 4 exceeds 200mV the 3524 reduces the on-time, turning down the motor speed. The
330R and 100R sense ¼ of the MOSFET voltage so with theses values the limit will be about
800mV across the MOSFET. Adjust the 100R for different MOSFETs. This current sensing
works quite well with the 3524 but the chip itself gives variable current limiting, depending on
the length of the on pulse, so the sensed current is somewhat dependant on the motor
characteristics.

Shortcomings
Although this circuit works, and is a practical controller, there are several shortcomings. We are
not going into details here, but almost all of these are explained and remedies given to members
of The Electronics Club but if you want to learn how, you will need to subscribe to 4QD-TEC,
see foot of this page.

 As previously stated, the 3524 circuit will not give more than 90% full speed.
 The circuit is current limited in drive mode but if you were to start a vehicle at the top of
a hill and go in to regen braking downhill, there is nothing to limit the regenerated
current. It is quite possible to add limiting to the regen braking and 4QD have a uniquely
simple and efficient way of doing this - the like of which I have seen nowhere else. You'll
have to join 4QD-TEC to get detail!
 Regenerated overvoltage. If the battery gets disconnected when you are braking, energy
regenerated cannot be fed back into it: instead the regenerated energy pumps up the
voltage across the controller until the MOSFETs break down: if they cannot absorb the
energy being regenerated then you have an expensive smoke generator. The cure is easy.
 One thing which destroys MOSFET controllers is reversing the battery: the two
MOSFETs are now two forward biased diodes connected across the battery. See our FAQ
sheet for a cure.
 Another thing that destroys all known MOSFET controllers is towing the vehicle they are
installed in. If the motor back EMF exceeds the battery voltage the drive MOSFET
becomes a forward biased diode feeding the motor's generated output straight to the
battery. There is no way of limiting this current so the MOSFET objects with a flash and
a puff of smoke. Fortunately this failure mode is quite rare, but there really is no simple
protection against it.

PWM and motor Heating

A popular 'old wife's tale' is that PWM causes the motor to heat more than pure d.c. Like most
old wives' tales, this springs from a partial truth nurtured by misunderstanding. The 'myth' comes
about because, if the frequency is too low, the current is discontinuous (or at least variable over
the pwm waveform) because the motor's inductance cannot maintain the current properly during
the off period of the waveform. So the motor current will be pulsed - not continuous. The
average current will determine the torque but heating will be an integral of the current squared
(heating is proportional to I²R)- the 'form factor' of the current will be greater than unity. The
lower the frequency, the higher the ripple current and the greater the heating.

So consider an oversimplified case where the current is either on or off. If the current flows for,
say, 1/3 of the time and you require a torque from the motor equivalent to that given by 1 amp
continuous, them you clearly need an average current of 1 amp. To do this with a 33% duty cycle
you must have 3 amps (the current flows for for 1/3 of the time).

Now a current of 3 amps will give 9 times (I squared) the heating effect of 1 amp continuous.
But if 3 amps is flowing for only 1/3 the total time - so the heating in the motor is 9 times for 1/3
the time - or a factor of 3 greater than the steady 1 amp! This waveform is said to have a 'form-
factor' of 3 (or is it 33% - no doubt someone will put me right!)

However - if the pulse repetition frequency is high enough, the motor's inductance will cause a
flywheel effect and the current will become stable. For instance the Lynch motor has an
inductance of only 39 microhenrys (being one of the lowest inductance motors I know of) and a
resistance of 0.016 Ohms. The 'Time constant' for an L-R circuit is L/R which (for the Lynch
motor) gives 2.4 mSec. For an SEM DPM40P4 (1kW) the inductance is 200 microhenries and
the resistance 40 milliohms - giving a time constant of 5mSec.

As a rule of thumb and to avoid too much maths, the pulse repetition period must be significantly
shorter than the motor's time constant.

Other factors that affects PRF are:


If is it is in the audio band the motor can emit a whine (caused by a phenomenon known as
'magnetostriction', so keep above the audio band.
A MOSFET circuit dissipates most while switching from one state to the other so the frequency
should not be too high - MOSFETs can be used upto 100kHz with care, but this is getting a bit
high.
RF emissions: these increase with increasing frequency, so keep the frequency as low as
possible!

It is clearly difficult to chose a 'best' compromise between these but an optimum frequency
would seem to be around 20kHz.

Afterword

Obviously this script only covers a little of the technology involved: have a look at the
specification of our Pro-120. This has linear acceleration and deceleration ramps, over-discharge
limiting, high pedal lockout, dual-ramp reversing, regen current limit, reverse polarity protection
as well as all the points mentioned herein. We also quote 110 amps for 1 minute: the real truth is
that we get about 120 amps for one minute. We also know of no 'fair' way of destroying it: even
shorting the motor out won't blow it. Reversing at full speed is safe. Reversing the battery is safe.
Disconnecting the battery at full speed is safe (for the controller - but don't expect it to brake the
machine). Then we have tried to protect it against all the things that non-technical customers may
do to it. We think we have succeeded - until of course we find a customer who is cleverer than
we are! Even if I was prepared to try, there is to way I could put into words all the experience
needed to design such a controller - let alone to make a profit from selling it at the price we do. If
you don't believe that then try asking the one off price of any similar controller.

###

///---
Parallel Port Programming (Part 2): with Visual C++
We can easily program the parallel port in DOS. But as we know, DOS programs have
their own limitations. So, if you want to move from DOS to Windows, go through this
article. This is an introduction to program the parallel port in VC++. You need not have
much knowledge about VC++. This article is designed for one who know basics of
parallel port and beginners of VC++. If you don't know anything about parallel port, read
my first article "Parallel port programming with C (Part 1)". There you get basic
information about parallel port and programming the port in Turbo C or Borland C.

Now, you are knowing the pins and registers of parallel port. You know how to
access them in DOS. If you want to run your program in Windows 95 or 98, you are
having access to the port in the similar way. You need to know how to use dialog boxes
and windows materials with it. But your program should also run in Windows XP, NT or
higher versions, then there is another issue. Higher versions of Windows do not allow to
access the hardware directly for security reasons. But still, there are ways, I will explain
later. First we will start programming which will work only in lover versions of Windows.

Direct Access:

If you want to program the port in VB, there is no direct access to the port. Still you
can access the port using DLL files created with VC++. You can use the next method
Access using inpout32.

If you are familiar with Visual C++, then create a dialog based application named
ParallelPort and skip this section, go to adding controls.

Creating the application:

 Start Visual C++, Select File->New.


 In the tab 'Projects', Select "MFC AppWizard (exe)", give project name as
"ParallelPort" and click OK.
 In the next window, select radio button "Dialog based" and click next leaving all
other options default.
 Click Finish, then OK to get a window with two buttons and one sentence
"TODO: Place Dialog controls here.", select and delete that sentence. Click to
select the button "Cancel" and delete it.
 Right click on button labeled OK, select Properties from the drop down menu.
Change the value of Caption to "&EXIT" from "OK".
 Resize the dialog box to get a window as shown below. If you run the application

by clicking this icon: , it should give 0 errors and 0 warnings, and you will get
the following window.

figure(2.1)

Adding controls:

Now, you should see a tool bar as shown here, it is called Control toolbar. If not, select
it from view menu->toolbars. Icon marked here with red color is the Check Box. If you click
the check box icon and draw in the window, You will have the check box placed in the
window. You need to place 17 such check boxes in the window. You can use copy-past to
make your work easy. After that, Group then using 3 group boxes. Group box icon is there
above the check box in the figure. After doing this much, your design should look like
figure(2.2)
figure(2.3). So, re arrange your dialog components to look like that. Again run the
application and make sure that there is no error.

Figure(2.3)

Next, right click on the Group Box labeled Static and go to properties. Change the
captions to Data, Status and Control respectively. Right click on the first Check box
Check 1, Change the caption to "Pin 2" and ID to IDC_Pin2. Similarly change the
captions of check boxes in data group to Pin 2 to Pin 9; status port Pin 10, Pin 11, Pin
12, Pin 13 and Pin 15; Control Port Pin 1, Pin 14, Pin 16 and Pin 17. Change the ID's
correspondingly(IDC_Pin2, IDC_Pin3...).

Window designing is over. Next part is coding. We have placed some controls in the
dialog box. To get the values of these controls, we need to have variables associated
with then. To do that, right click and select "ClassWizard" from drop down menu. Select
tab "Member Variables". You will get a list of Control IDs. Select each IDs separately
and click Add Variable. Type variable name as m_pin1. m_pin10, m_pin11... and retain
Category Value and Variable type BOOL. Refer following figure.
Figure(2.4)

In the Workspace, Select ClassView tab, under ParallelPort classes, right click on
CParallelPortDlg, click Add Member Function. Give function type as void and function
name as UpdatePins(). It will take you to the new function created. Edit the code as
follows.

void CParallelPortDlg::UpdatePins()
{
int reg;
reg=_inp(STATUS);

if((reg & 0x40)==0) m_pin10=0; else m_pin10=1;


if((reg & 0x80)==0) m_pin11=0; else m_pin11=1;
if((reg & 0x20)==0) m_pin12=0; else m_pin12=1;
if((reg & 0x10)==0) m_pin13=0; else m_pin13=1;
if((reg & 0x08)==0) m_pin15=0; else m_pin15=1;
//////////
reg=_inp(DATA);

if((reg & 0x01)==0) m_pin2=0; else m_pin2=1;


if((reg & 0x02)==0) m_pin3=0; else m_pin3=1;
if((reg & 0x04)==0) m_pin4=0; else m_pin4=1;
if((reg & 0x08)==0) m_pin5=0; else m_pin5=1;
if((reg & 0x10)==0) m_pin6=0; else m_pin6=1;
if((reg & 0x20)==0) m_pin7=0; else m_pin7=2;
if((reg & 0x40)==0) m_pin8=0; else m_pin8=1;
if((reg & 0x80)==0) m_pin9=0; else m_pin9=1;
//////
reg = _inp(CONTROL);

if((reg & 0x01)==0) m_pin1=0; else m_pin1=1;


if((reg & 0x02)==0) m_pin14=0; else m_pin14=1;
if((reg & 0x04)==0) m_pin16=0; else m_pin16=1;
if((reg & 0x08)==0) m_pin17=0; else m_pin17=1;

UpdateData(FALSE);
}

Now scroll to the top of the page and add these lines before class declarations.

#define DATA 0x378


#define STATUS 0x379
#define CONTROL 0x37a

The function CParallelPortDlg::UpdatePins() is used to display values of all pins


initially. Here, we have used _inp() function to get the values of registers associated
with the ports. _inp(PORT) will return the data present in PORT. Depending on the
status of the pins, we are making Check boxes checked or unchecked. When we
change the value of member variable and call the function UpdateData(FALSE), the
values in the member variables will be updated in the corresponding controls in the
window. Similarly if you call UpdateData(TRUE), Values which are there in the
corresponding controls will sit in the member variables. Here, The values from the
variables should be updated in the window. So, UpdateWindow(FALSE). If you have
read my first article, you will understand all other things done here.

To make run this code when the dialog is initialized, we need to call it. So, go to
function OnInitdialog() in the file CParallelPortDlg. (In the class view tab of the
workspace, under ParallelPort Classes, expand CParallelPortDlg, you will get the
function name, double click it.) Add the following code to it. This code will call the
function UpdatePins() and set a timer to scan the port pins. You can change the second
parameter to change the frequency at which ports are needed to be scanned. I have
used 200 milli seconds. _outp(CONTROL, 0xDF) will reset the control register bit 5 low
so that data pins will act as output. _outp(PORT, DATA) sends the byte DATA to the
address PORT.

BOOL CParallelPortDlg::OnInitDialog()
{
//App.Wiz generated code
// TODO: Add extra initialization here
SetTimer(1,200,NULL);
_outp(CONTROL, _inp(CONTROL) & 0xDF);
UpdatePins();
return TRUE; // return TRUE unless you set the focus to a
control
}

Next part is Updating the pin contents for each timer tics. For that, we need to
handle the windows message WM_TIMER. Now since we have set the timer for 200
ms, for every 200 ms, Windows returns WM_TIMER message. To write a handler, write
click on the CParallelPortDlg in the class view tab, select "Add Windows Message
Handler...". In "New Windows messages/events", select WM_TIMER and click Add and
Edit. It will take you to the newly created function CParallelPortDlg::OnTimer(UINT
nIDEvent). Add the following code to it.

void CParallelPortDlg::OnTimer(UINT nIDEvent)


{
// TODO: Add your message handler code here and/or call
default
int status_reg;
status_reg=_inp(STATUS);

if((status_reg & 0x40)==0) m_pin10=0; else m_pin10=2;


if((status_reg & 0x80)==0) m_pin11=0; else m_pin11=1;
if((status_reg & 0x20)==0) m_pin12=0; else m_pin12=1;
if((status_reg & 0x10)==0) m_pin13=0; else m_pin13=1;
if((status_reg & 0x08)==0) m_pin15=0; else m_pin15=1;

UpdateData(FALSE);
CDialog::OnTimer(nIDEvent);
}

Here, we have refreshed only input pins. Output pins have to be changed when
user clicks on the check boxes. To find any change of value in check boxes, we can use
BN_CLICKED message handler. But for all the check boxes we have to repeat the
process. It is easy to use ON_COMMAND_RANGE. For that, scroll up to the position in
the file ParallelPortDlg.cpp where you find BEGIN_MESSAGE_MAP(CParallelPortDlg,
CDialog). (Do not confuse between CParallelPortDlg and CAboutDlg.) Add the
following code to it.

BEGIN_MESSAGE_MAP(CParallelPortDlg, CDialog)
//{{AFX_MSG_MAP(CParallelPortDlg)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_WM_TIMER()
//}}AFX_MSG_MAP
//Code added by me from here.
ON_COMMAND_RANGE(IDC_Pin2, IDC_Pin9, ChangePin)
ON_COMMAND(IDC_Pin14, ChangeControl)
ON_COMMAND(IDC_Pin16, ChangeControl)
ON_COMMAND(IDC_Pin17, ChangeControl)
ON_COMMAND(IDC_Pin1, ChangeControl)
//Code added by me till here
END_MESSAGE_MAP()

Above code will call the function ChangePin() when buttons in the range IDC_Pin2
to IDC_Pin9 are changed and ChangeControl() when chack buttons with ID IDC_Pin14,
IDC_Pin16, IDC_Pin17 or IDC_Pin1 are changed. Now we need those two functions.
Add two new functions to CParllelPortDlg: void 'ChangePin()' and 'void
ChangeControl()' using the method explained earlier. Write codes to them as follows:

void CParallelPortDlg::ChangePin(int pin)


{

int data_register, new_register;

UpdateData(TRUE);
data_register=_inp( DATA );
new_register=0;
if( m_pin2==TRUE ) new_register |= 0x01;
if( m_pin3==TRUE ) new_register |= 0x02;
if( m_pin4==TRUE ) new_register |= 0x04;
if( m_pin5==TRUE ) new_register |= 0x08;
if( m_pin6==TRUE ) new_register |= 0x10;
if( m_pin7==TRUE ) new_register |= 0x20;
if( m_pin8==TRUE ) new_register |= 0x40;
if( m_pin9==TRUE ) new_register |= 0x80;

_outp(DATA, new_register);

void CParallelPortDlg::ChangeControl()
{

int control_register, new_register;

UpdateData(TRUE);

control_register = _inp( CONTROL );


new_register = control_register;

if( m_pin1== 0 ) new_register &= 0xFE;


else new_register |= 0x01;
if( m_pin14==0 ) new_register &= 0xFD;
else new_register |= 0x02;
if( m_pin16==0 ) new_register &= 0xFB;
else new_register |= 0x04;
if( m_pin17==0 ) new_register &= 0xF7;
else new_register |= 0x08;

_outp(CONTROL, new_register);

If everything is OK, you should get the following window when you run the program.
To test the program, run this program without connecting anything to the port. Change
some of the pins and close the window. If you run the program again you should get the
values which was there before closing the window in the output pins.
You can always use this program to test the parallel port. Now, make a circuit
connecting all the input pins to switches, all the output pins to LEDs with 2.2K or 10K
resisters. If you press switch, corresponding pin value should change in the screen, If
you change state of any output pin, corresponding LED should glow.

Every thing is ok. But as you know, this program will run only in win9x. If your
program is needed to run in windows xp and higher versions, you need to write a kernel
mode device driver. Do not worry if you are not up to that level. There are DLL files
available freely for such drivers. You can use those files and call them from your
program.

Access using inpout32

If you do not want to use driver and test the above program in Windows XP as it is, use
my post in the ElectroSofts Forum

InpOut32 is a DLL file which can send a data to parallel port and which can return
the data in the parallel port. You can download this file with source code for free from
http://logix4u.net. You can use this file in any windows programming language like
Visual basic, C#, C++ etc. If you know how to use DLL files, download the file from
http://logix4u.net and use Inp32() and Out32() functions instead of _inp() and _outp().
To know how to use DLL file in VC++, let us now convert our previous project to XP
enabled program.

 Add these two lines in the file ParallelPortDlg.cpp after pre processor directives.

short _stdcall Inp32(short portaddr);


void _stdcall Out32(short portaddr, short datum);

 Where ever _inp() comes, change them to Inp32() and where ever outp() comes,
change them to Out32().
 Copy DLL file inpout32.dll and lib file inpout32.lib got by compiling the source
code available at logix4u.net to the project folder.
 From project menu, select settings, go to tab link, in object/ library modules write
inpout32.lib
 Now your program should run without any errors.

###

DC motor control using C++


This is a demo program written in C++ so that can be known how computer is used to take
control action on DC Motor. Total motion control of DC motor is given here (speed control as
well as direction change). Also total GUI (Graphical User Interface) is provided (buttons, mouse
interface etc.). Program controls motion of motor through LPT port with very small hardware
connected to it.

In this project the DC motor with following ratings

max rated voltage: 12 VDC

max rated current: 2 Amp

max rated RPM: 3000

The Controller is actually a combination of two circuits-

Controller = Driver + Switching circuit


Driver is the actual circuit that drives DC motor and switching circuit decides how DC
motor should be driven. Actually switching circuit is the main circuit that controls the
motor. Now there are two parameters of DC motor that we can control

1. Speed

2. Direction

Changing the direction of DC motor is very simple just reverse the supply given to DC
motor.

For varying speed of motor you have to vary the applied DC voltage. One well known
method to vary voltage is to use resistance (rheostat or potentiometer) in series with
DC supply. Another method is to apply pulse width modulated (PWM) wave to DC
motor. As the width of pulse varies average voltage applied to motor varies and so the
speed of motor also varies.

In this project I have used standard H-Bridge circuit as a DC motor driver and software
program (written in C++) as a PWM generator. Program generates PWM wave to vary
the speed of motor as well as change the direction of it depending upon user
command.

H-Bridge is standard, well known circuit and widely used as DC motor driver. Its
schematic is as shown below. The circuit is made up of three major components opt
coupler MCT2E, NPN Darlington pair TIP122, PNP Darlington pair TIP127. This is very
standard circuit and can be used to drive any industrial motor DC motor with
maximum voltage of 100V and maximum current of 5A.
NPN and PNP Darlington pairs are connected in bridge configuration as shown. DC
motor is connected as a load to bridge circuit. Bases of all four darlington pairs are
connected to 25 pin D-type connector through opto-couplers. Function of opto-
coupler is to provide good isolation between PC and H-bridge circuit. In all opto-
couplers, anode of LED and collector of phototransistor is tied to Vcc. cathodes are
connected with respective data pins D0 to D3. Emitters of phototransistor are
connected to bases of respective Darlington pair through current limiting resistor
220E. All the Darlington pairs have inbuilt reverse diode that is for freewheeling
action.

Now when you apply low logic to pin pins 2 & 3 and high logic to pins 4 & 5, U1A and
U2B will start conducting and provide high logic to bases of Q1 & Q3. U1B and U3A
won’t conduct so bases of Q2 & Q4 will be on low logic. this will turn on Q1 &
Q4 current will flow from supply - Q1 – (+Ve) terminal of motor – (-Ve) terminal of
motor - Q4 – Ground. So motor will rotate in one direction. For this we have to apply
HEX data word 0C (0000 1100) on LPT port.

Same way when you give low logic to pin no. 4-5 and high logic to pins 2-3, Q2 and Q3
will turn on and current will flow from supply – Q2 – (-Ve) terminal of motor – (+Ve)
terminal of motor – Q3 – Ground. So motor will rotate in another direction. For this
we have to apply HEX data word 03 (0000 0011)on LPT port.

Thus simply by switching the logic from high to low and low to high in between these
four pins (2, 3, 4, and 5) you can change the direction of motor.
Now rather then directly giving high logic to pins if we apply PWM wave to it then
during ON period of wave both transistors are closed switch (conducts) and during OFF
period they are open switch (do not conduct) so every time average voltage is fed to
motor. As you go on increasing pulse width (increasing ON period and decreasing OFF
period) of PWM wave the avg. Voltage given to motor is increased and so the speed
also increases. Same way if you decrease pulse width (increase OFF period and
decrease ON period) of PWM waves the avg. voltage decreases and so the speed also
decreases.

Here in this project, generating PWM wave on these pins (2, 3, 4 and 5) as well as
switching the transistors to change the direction of motor is done by software
program which is written in C++ programming language.

Software

Main function of this software is to

· Switch between transistors T1-T4 and T2-T3 to change direction of motor

· Generate PWM on pins (either on 2-3 or on 4-5) to vary speed of motor

Software is mainly divided in three parts

1. Graphics

2. PWM generation

3. Mouse interfacing

Graphics

This part generates complete view of control panel. It draws buttons like clockwise,
anticlockwise, speed increase/decrease, displays instructions, draws borderline,
writes text like “Speed”, “Speed factor”, displays speed factor etc. That means it
prepares whole appearance of program screen.

PWM Generation

Generating PWM on parallel (LPT) port data pins (D0-D7) using C++ is very simple. For
ON period you have to apply high logic (1 means 3.49V) on that data pin and low logic
(0 means 0.09V) for OFF period of pulse. The base frequency over which PWM is
generated is 200Hz. So the time period is 50 millisecond (ms). First when speed factor
(d) is zero, program generates square wave of 50% duty cycle (25ms ON period and
25ms OFF period) on two parallel port pins (either on pin no. 2 &3 or on pin no. 4 &
5). This speed factor is added to the ON time period (25 + d) and subtracted from OFF
time period (25 - d). So as you increase this factor the ON time period will increase
and with the same factor OFF time period will decrease (suppose d=5 then ON time is
30 and off time is 20) so the base frequency 200Hz will not change. Same manner
when you decrease speed factor ON time will decrease and OFF time will increase
again frequency remains same. This you can easily understood with these waveforms.

You can increase the speed factor till you reach to min limit of OFF time period (5
ms). After that there won’t be any further increment in speed factor and program will
display a message “Max Speed”. In same manner you can’t further decrease speed
factor when you reach min limit of ON period (5 ms). When you reach this limit
program will display message “Min Speed”.

Mouse interfacing

This is the most interesting part in whole program. User can do his/her all task by
mouse click. To understand how mouse is interfaced in this program you have to go
through whole theory of hardware interfacing using C++. In this program there are
four functions that handles mouse event

1. initmouse()

2. resmptr(int p, int q, int r, int s)

3. showmptr()

4. getmpos(int *t, int *u, int *v)

initmouse function loads mouse driver in to the program. In this function we are
passing 0 value through input union REGS to int86( ) function. This function will return
some nonzero value through output union REGS to main program. If this function
returns value zero (0), it means mouse driver is not loaded. So program displays
message “mouse driver is not loaded” and also it shuts the program screen off using
exit( ) function.

Resmptr(int p, int q, int r, int s) function restrict mouse movement within the
boundary specified by the four variables passed to it. We pass all these boundary
limits through input union REGS to int86 () function. So int86( ) function will restrict
the mouse movement out of this boundary.

Showmptr( ) function displays mouse pointer on program screen. For this just we have
to pass the value 1 through input union REGS to int86 ( ) function. And int86 function
will shows mouse pointer on screen

Getmpos (int *t, int *u, int *v) performs two tasks. It determines whether mouse
button is pressed or not and it captures current mouse pointer position from screen.
We have to pass the value 3 through input union REGS to int86 () function. This
function will returns the x and y co-ordinates of mouse pointer and also returns value
1 if mouse button (left) is pressed or 0 if button is not pressed.

Until and unless you press any key you can see the program screen displaying control
panel for DC-Motor speed and direction control. Program continuously checks for
mouse click event. Whenever there is a mouse click instantly getmpos() function
captures x and y co-ordinates of mouse pointer and pass it to the main program. Main
program decides on which position click event has happened and if it happened on
any button (clockwise, anticlockwise etc.) Then performs the desired task. For
example you click on speed increase button, program gets the co-ordinate and
directly switch to that IF loop, increase the speed factor and also displays it on
screen.

First prepare the hardware as shown in schematic. You can prepare it even on bread
board also (no need to solder) because there are only 8 components (4 optocouplers
and 4 darlington pairs). Connect DB25 connector with PC’s LPT port. Apply 12V supply
to supply terminals and connect the DC motor with its terminals. Now run “DC-
Speed.exe” on your computer. You will see control panel on your screen. Now switch
on the 12V supply. Move your mouse pointer to any button.

To rotate motor clockwise/anticlockwise press and hold clockwise/anticlockwise


button with left mouse button. Motor will rotate in desired direction till the button is
pressed and you will also hear a sound. Motor will stop rotating when you release
button. If you press clockwise button and motor rotates anticlockwise then just
reverse the terminals of motor

To increase/decrease the speed of motor just press speed increase/decrease button


with left mouse button once. Sweet sound is generated and speed factor will be
incremented/decremented and displayed on screen. Pressing these buttons more then
one time will increase/decrease the speed factor by same amount.

###

Вам также может понравиться