University of Regina Electronic Systems Engineering ENEL487 Real

advertisement
University of Regina
Electronic Systems Engineering
ENEL487 Real Time Control
Winter 2004
Lab #4
1
Objective
To gain familiarity with the interrupt system on the Intel PC architecture,
and to implement interrupt driven, pulse width modulated speed control of
a servo-motor.
2
Background
In this lab, motor speed control is the final goal once again, however, rather
than using the D/A to produce an analog control voltage, a technique known
as pulse width modulation (PWM) will be used. In the previous lab, it was
noticed that the control range for the amplifier ranged over a relatively small
range. This produced a relatively small number of control values to precisely
set the motor’s speed. This problem could be fixed by designing an amplifier
with the appropriate gain and offset, or setting the output sensitivity, such
that the D/A’s output swing corresponded to the speed control range on the
motor.
There exists another problem with this technique. When a midrange
power setting is desired, a large proportion of the power is dissipated by the
drive amplifier. If the motor has an equivalent load of 15 ohms, then the
power dissipated in the motor is V 2 /15. If the desired speed setting required
10W be delivered to the motor then the voltage is set to (10∗15)1/2 = 12.25V
and the current is 820 mA. If the power supply voltage is 24 volts, the drive
transistor is biased such that a 11.75 voltage drop appears across the collector
1
emitter junction. This transistor is therefore dissipating energy in the form
of heat (11.75*.820)=9.6 Watts.
PWM circumvents this problem by forcing the drive amplifier to be either
completely on, or completely off. Clearly, when the transistor is off, no
current flows and no power is dissipated. When it is completely on, the
drive transistor is saturated and the voltage drop across it is about 0.2 V.
The current flowing into the motor will be ((24-0.2)/15) = 1.59A. The power
dissipated in the drive transistor will be (0.2*1.59) = 318 mW and the power
to the motor will be 23.8*1.59=37.8 Watts. If the amount of power provided
to the motor is too high, (i.e. the speed is too high) then the drive transistor
can be rapidly switched off and on such that the average power is the correct
amount for the appropriate speed. Increasing the percentage of time that the
drive transistor is saturated will increase the speed.
Note that speed control can be provided by varying the duty cycle of the
drive waveform. The goal of this lab is to implement the PWM drive in
software by toggling a digital output at an appropriate rate and duty cycle,
thereby providing the closed loop speed control similar to the previous lab.
3
Procedure
3.1
Phase 1: Reprogramming the Motherboard Timer
The motherboard contains an Intel 82C54 timer, which is used to generate
the sytem clock. Essentially all timing functions on the PC are controlled
by this chip. (In actuality there is no such chip in modern machines, the
function of an 82C54 is incorporated into the PC’s chipset.)
The data sheet for the 82C54 timer is available on WebCT and at
ftp://download.intel.com/design/periphrl/datashts/23124406.pdf
There is also an application note, at
http://developer.intel.com/design/periphrl/technote/7203.htm
All the registers on the 82C54 are accessed through an 8-bit port. Thus
you must use 8 bit I/O instructions ( inp and outp) to access this device.
There are three counters on the 82C54, numbered 0, 1 and 2. Note
that these are count down timers. Counter 0 is clocked via an onboard
crystal running at 1,193,180Hz. This counter is running in mode 2 (rate
generator mode) so it’s simply a divide by N counter. By default the counter
is programmed with 0, so it effectively divides by 216 = 65, 536, resulting in
a signal at 18.206481Hz. This signal is tied to interrupt level 8, and this is
the source for the computer’s system clock.
2
The counter can be loaded with any value from 0 to 65535, but doing so
naively will result in the system clock running too fast.
However, we can correct for this in our ISR. Here’s how: suppose you want
to speed up the interrupt rate by a factor of 64 (power of 2 is not required, just
cleaner). You would program counter 0 with the number 65536/64 = 1024.
Then inside the ISR, you keep track of the interrupts, calling the old dos
interrupt once every 64 times. In this way the system clock can continue to
run at the proper rate.
To implement the PWM the drive voltage is set high for a certain length
of time th , then set low for a time tl . The duty cycle is determined by
the ratio th /(th + tl ). Suppose you have set the ISR to be called every ∆t
seconds. Then both th and tl must be multiples of ∆t. If we arrange it so
+tl
0 < th /∆t < 100 and th∆t
= 100 then we can set the duty cycle directly in
percent.
So a crude way of getting this to work would be to set the value of th in
the background task. The foreground (ISR) task would then read this value
and set the high and low durations accordingly. Then th could be changed
by the user to achieve any speed from zero to the maximum.
The 82C54 can be found at the base address 0x40.
Address
TIMER +
TIMER +
TIMER +
TIMER +
0
1
2
3
Access
R/W
R/W
R/W
W
Ctr
0
1
2
—
Function
System clock timer
Memory Refresh
Unused
Control
We note that an 8 bit I/O port is assigned to a 16 bit counter. In order
to load 16 bits we have to perform two successive 8-bit output instructions.
The LSB is loaded first. Thus a routine which performs a counter load might
look like:
void counterLoad(int counterId, unsigned int counterValue)
{
if (counterId < 0 || counterId >= 3) // counter_id = 0..2
return;
// error
_outp(TIMER + counterId, counterValue&0xff);
_outp(TIMER + counterId, counterValue>>8);
}
This routine will only work if the control register has been configured
properly, which we can assume is the case. For information purposes only,
the control register layout is as follows:
3
D7
SC1
D6
SC0
D5
D4
RW1 RW0
D3
M2
D2 D1
M1 M0
D0
BCD
• BCD selects binary or decimal counting, we want binary, BCD=0
• M2,M1,M0 select a variety of modes. We want the rate generator
mode=010 for counter 0.
• RW1,RW0 controls the read/load operation. We want LSB, followed
by MSB, so RW1:RW0 = 11
• SC1,SC0 selects the counter (0, 1, or 2) we are configuring.
• We would configure counter 0 with 00110100 = 0x34.
The routine to perform this configuration is (which, again, we shouldn’t
have to do):
void counterConfig()
{
outp(TIMER + 3, 0x34);
}
To perform the PWM code in s/w we must first select a frequency to
drive the motors. We select a frequency that is sufficiently high as to provide
smooth motor operation, but not so high that the interrupt service routine
can’t keep up. Somewhere around 10 Hz is about as low as we can go. (That
means that a single PWM cycle will be 100ms.) The counter load value is
determined by this frequency. We want our ∆t to be 1/100 of the PWM
cycle time. So we set the 82C54 counter 0 value accordingly. What value do
you think would be appropriate?
3.2
Phase 2: PWM Logic
The interior of the ISR is still a mysterious beast. How can we accomplish
all the things that are required? The ISR must:
• keep calling the old dos interrupt at 18.206Hz
• track a global variable, th , which is a number between 0 and 100 and
which represents the duty cycle percentage.
4
• hold the motor voltage at a maximum for th seconds and hold it at zero
for tl seconds, keeping the sum th + tl a constant (100ms in the above
example, but you’ll pick your own).
• keep reading the motor speed using the A/D so it can be controlled. A
reasonable idea is to read the A/D once every PWM cycle.
You should now come up with some program logic which will do this.
3.2.1
The EOI Command
Up to now, we’ve always chained our interrupt service routine onto the preexisting dos ISR. In doing this we obscured a small detail about the PC’s
interrupt hardware. As mentioned in class, the programmable interrupt controller (Intel 8059) feeds several interrupt lines into the CPU’s single interrupt
input. When the 8059 receives an interrupt it informs the CPU of this fact
and the CPU can then jump to the appropriate vector address (15 in the
case of a timer interrupt). At the end of the ISR, the CPU must reset the
8059 by sending it a non-specific End of Interrupt (EOI) command. This is
accomplished by writing the value 0x20 to the 8059’s base address. This base
address happens to be 0x20, as well. So you must write the number 0x20 to
I/O address 0x20, at the end of your ISR. If you don’t do this the system
will hang.
3.3
Phase 3: Speed control
The speed control algorithm is not much different in this lab than in lab #2.
The A/D value is read, but instead of reading directly from the hardware,
the background task reads it from the memory location stored by the ISR.
Based on the read value and user input to set the value, a % duty cycle is
determined.
The duty cycle is stored with the speed set() command, a function that
sets the value of th . When an interrupt occurs, the new speed value is used
in determining the timer load value. Write the background routine which
takes the user input and the A/D value to determine a % duty cycle thereby
producing closed loop speed control. You may find that one PWM cycle
every 100ms is too slow and results in a noticable oscillation. How would
you speed up the PWM cycle to improve this situation?
3.4
Phase 4: Questions to answer
We note that the there are only 101 speed settings: from 0% to maximum
at 100%.
5
• If higher precision is required, how should the code be modified to
achieve this?
• How would you shorten the duration between interrupts?
• Is there a minimum possible time between interrupts? If so, what
happened when you went beyond the limit?
6
Download