Файл: Interfacing with C plus plus-programing communication with microcontrolers (K. Bentley, 2006).pdf
ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 14.06.2025
Просмотров: 3565
Скачиваний: 1
8 DRIVING MOTORS - DC & STEPPER 231
Switching[3] = 0x96; break;
case BPHS: MaxIndex = 8; Switching[0] = 0x99; Switching[1] = 0x09; Switching[2] = 0x69; Switching[3] = 0x60; Switching[4] = 0x66; Switching[5] = 0x06; Switching[6] = 0x96; Switching[7] = 0x90;
}
}
void StepperMotor::Forward()
{
if(++CycleIndex == MaxIndex) CycleIndex = 0; WritePort0(Switching[CycleIndex]); delay(259-GetSpeed());
}
void StepperMotor::Reverse()
{
if(--CycleIndex == -1) CycleIndex = MaxIndex -1; WritePort0(Switching[CycleIndex]); delay(259-GetSpeed());
}
void StepperMotor::Brake()
{
switch(MotorType)
{
case UPFS: case UPHS: WritePort0(0x11); break;
case BPFS: case BPHS: WritePort0(0x99);
}
}
As usual, the constructor initialises the private data members of the class. If a motor type is specified in the actual argument for the parameter motortype, it will be assigned to the private data member MotorType. The CycleIndex is always initialised to 0. The MaxIndex is either set to 4 or to 8 depending on full-
232 8 DRIVING MOTORS - DC & STEPPER
step control or half-step control. The array Switching is initialised depending on the motor type and the operating mode, explained as follows.
The MotorType is tested in a switch statement which is used to fill the array Switching with appropriate values for that combination of stepper motor and drive mode depending on the case value. The values that are written into the array Switching control the sequential switching of the H-bridges to drive a given stepper motor through its sequence of steps. Note that the stepper motors will use both H-bridges and have almost full supply voltage applied to their respective windings during each step. Their speed/position is controlled by the rate/number of steps. As such they do not use pulse width modulation for speed or torque control.
The Forward() function of the StepperMotor class operates in a similar manner as the Reverse() function, and so only the Forward() function is explained (see Figure 8-24).
void StepperMotor::Forward() |
||
{ |
||
if(++CycleIndex == MaxIndex) |
CycleIndex is incremented |
|
CycleIndex = 0; |
and tested for exceeding its limit. |
|
If exceeded it will be reset. |
||
WritePort0(Switching[CycleIndex]); |
delay(257-GetSpeed());
}
Contents of the array Switching
Speed is controlled by inserting a controlled delay between consecutive writes to the port.
are written to the port, one element per step delay.
Figure 8-24 Operation of the Forward() function.
The Brake() function implements a switch statement to apply braking appropriate to the motor type; a unipolar stepper motor or a bipolar stepper motor. Dynamic braking is applied uniquely for two of the four cases by closing and opening the required switches of the H-bridge. Note that in the configuration we have used for unipolar stepper motors, the armature cannot be short-circuited. Instead, voltage is not applied to the armature windings.
The H-bridge connections for Bipolar and Unipolar Stepper Motors are shown in Figure 8-25 and Figure 8-26 respectively. All the classes have been defined and the definitions of all member functions have been provided. The implementation of the class hierarchy is now complete. We now need to develop a main() function to make use of these classes.
8 DRIVING MOTORS - DC & STEPPER 233
Vm1 Vm2
A |
H-bridge 1 |
B |
H-bridge 2 |
||||
A |
B |
||||||
(D0) |
I M1 |
M2 |
(D1) |
(D4) |
I M1 |
M2 |
(D5) |
+ |
+ |
|||
Coil (Phase) 1 |
I |
D |
Coil (Phase) 2 |
I |
C |
C |
D |
||
(D2) |
(D3) |
(D6) |
(D7) |
Figure 8-25 H-bridge connections for a Bipolar Stepper Motor.
Vm1 Vm2
M1 |
+ |
M2 |
M1 |
+ |
M2 |
||
_ |
_ |
||||||
Coil (Phase) 1 |
I |
Coil (Phase) 2 |
I |
||||
C |
C |
||||||
Lower half of |
D |
Lower half of |
D |
||||
(D0) |
(D1) |
(D4) |
(D5) |
||||
H-bridge 1 |
H-bridge 2 |
Figure 8-26 H-bridge connections for a Unipolar Stepper Motor.
8.6 Virtual Functions - Application
We are now ready to develop an application that makes use of virtual functions. This application will enable any of the types of motor accommodated in our class hierarchy developed earlier to be driven:
1.DC motors.
2.Unipolar stepper motors with dual-phase full-step control.
3.Unipolar stepper motors with half-step control.
4.Bipolar stepper motors with dual-phase full-step control.
5.Bipolar stepper motors with half-step control.
We will initially develop that part of the application that controls a ‘motor’ using the mechanism of virtual functions. Then we will add code to the program that allows a user to select a motor type to be driven.
The principal advantage of using virtual functions is the ability to write programs that can automatically bind a function to its associated object type at run-time. This allows us to write a very generic program. We start writing such a program by selecting a variable that can represent any of the objects in the hierarchy. The ideal
234 8 DRIVING MOTORS - DC & STEPPER
variable will be associated with the Motor class; the base class for all the real motor classes in the hierarchy. A pointer (which is a variable) to this class can point to any of the objects of its derived classes as explained below.
C++ |
Base Class Pointers |
A base class pointer can point to objects of its class or it can point to any objects
of its derived classes. When we use a base class pointer to point to an object
from a derived class and a virtual function is called through this pointer, the
corresponding member function of that derived class will be selected and called.
Therefore, we can create a pointer to the Motor class as shown below and use it to point to any of the real motor classes derived from it:
Motor *MotorPtr;
Our particular program will carry out the following steps:
1.Drive the motor forward at a speed of 150 until a key is pressed.
2.Drive the motor forward at a speed of 255 until a key is pressed.
3.Reverse the motor at a speed of 150 until a key is pressed.
4.Reverse the motor at a speed of 255 until a key is pressed.
5.Stop the motor (braking).
6.Turn off power to the motor.
The code that implements these requirements is shown in Listing 8-10. Here we use the function kbhit() to detect a key press and the function getch() to clear the keyboard buffer after the key press.
Listing 8-10 Generic code to control 'a Motor'.
Motor *MotorPtr;
// Insert statements to choose a specific motor here
//..... Motor control part starts here .....
MotorPtr->SetSpeed(150); while(!kbhit()) MotorPtr->Forward(); getch(); // clear keyboard buffer
MotorPtr->SetSpeed(255); while(!kbhit()) MotorPtr->Forward(); getch();
MotorPtr->SetSpeed(150);
8 DRIVING MOTORS - DC & STEPPER 235
while(!kbhit()) MotorPtr->Reverse(); getch();
MotorPtr->SetSpeed(255); while(!kbhit()) MotorPtr->Reverse(); getch();
cout << endl << " Braking Applied!" << endl; while(!kbhit()) MotorPtr->Brake();
getch();
MotorPtr->Off();
//..... Motor control part ends here .....
The user must be given a list of motor types to be able to choose a motor to operate. The code to implement this task is given in Listing 8-11.
Listing 8-11 Statements to display a menu of Motors on the screen.
int Selection;
clrscr(); |
|||
cout << endl << " |
MOTOR MENU"; |
||
cout << endl << " |
~~~~~~~~~~" << endl; |
||
cout << " |
1 |
DC Motor" << endl; |
|
cout << " |
2 |
UPFS" << endl; |
|
cout << " |
3 |
UPHS" << endl; |
|
cout << " |
4 |
BPFS" << endl; |
|
cout << " |
5 |
BPHS" << endl; |
|
cout << " |
6 |
QUIT" << endl; |
|
cout << endl; |
|||
cout << " |
Select the MOTOR Number: "; |
||
cin >> Selection;
Having selected the motor, we need to use dynamic memory allocation to create the object type that corresponds to the motor selected. Listing 8-12 shows the dynamic memory allocation segment of the program.
Listing 8-12 Dynamic memory allocation for the selected Motor.
switch(Selection)
{
236 8 DRIVING MOTORS - DC & STEPPER
case 1: MotorPtr = new DCMotor; break;
case 2: MotorPtr = new StepperMotor(UPFS); break;
case 3: MotorPtr = new StepperMotor(UPHS); break;
case 4: MotorPtr = new StepperMotor(BPFS); break;
case 5: MotorPtr = new StepperMotor(BPHS); break;
case 6: return;
default: cout << endl;
cout << " Unspecified Motor type...."; cout << " PRESS a key to END Program!"; getch();
exit(1); // Exits the program
}
if(MotorPtr == NULL)
{
cout << "Memory allocation failed " << endl; getch();
exit(1);
}
At the end of this program segment, the pointer MotorPtr should be initialised to point to a valid object in memory. If not, the program will exit because a matching motor type could not be found, or memory allocation has failed. Once the pointer is initialised, the program segment given in Listing 8-10 can be executed. The complete main() function is given in Listing 8-13.
Listing 8-13 The main() function to control 'a Motor'.
void main()
{
Motor *MotorPtr; int Selection;
clrscr();
cout << endl << " MOTOR MENU";
cout << endl << " ~~~~~~~~~~" << endl; cout << " 1 DC Motor" << endl;
8 DRIVING MOTORS - DC & STEPPER 237
cout << " |
2 |
UPFS" << endl; |
cout << " |
3 |
UPHS" << endl; |
cout << " |
4 |
BPFS" << endl; |
cout << " |
5 |
BPHS" << endl; |
cout << " |
6 |
QUIT" << endl; |
cout << endl; |
||
cout << " |
Select the MOTOR Number: "; |
|
cin >> Selection;
switch(Selection)
{
case 1: MotorPtr = new DCMotor; break;
case 2: MotorPtr = new StepperMotor(UPFS); break;
case 3: MotorPtr = new StepperMotor(UPHS); break;
case 4: MotorPtr = new StepperMotor(BPFS); break;
case 5: MotorPtr = new StepperMotor(BPHS); break;
case 6: return;
default: cout << endl;
cout << " Unspecified Motor type...."; cout << " PRESS a key to END Program!"; getch();
exit(1); // Exits the program
}
if(MotorPtr == NULL)
{
cout << "Memory allocation failed " << endl; getch();
exit(1);
}
cout << "**********************************" << endl; cout << "* CONNECT BOARD POWER SUPPLY NOW *" << endl;
cout << "**********************************" << endl; cout << endl;
cout << " After connecting power,”;
cout << “ press a key to continue " << endl; getch();
238 8 DRIVING MOTORS - DC & STEPPER
cout << " Keypress changes Speed/Rotation (& Braking)." << endl;
//..... Motor control part starts here .....
MotorPtr->SetSpeed(150); while(!kbhit()) MotorPtr->Forward(); getch(); // clear keyboard buffer
MotorPtr->SetSpeed(255); while(!kbhit()) MotorPtr->Forward(); getch();
MotorPtr->SetSpeed(150); while(!kbhit()) MotorPtr->Reverse(); getch();
MotorPtr->SetSpeed(255); while(!kbhit()) MotorPtr->Reverse(); getch();
cout << endl << " Braking Applied!" << endl; while(!kbhit()) MotorPtr->Brake();
getch();
MotorPtr->Off();
//..... Motor control part ends here .....
// Free the memory occupied by the 'Motor' object delete MotorPtr;
}
The compiler should have seen the definition of the entire class hierarchy and the definition of all member functions when it comes time to compile the main() function in Listing 8-13. We will defer explaining the complete program until virtual destructors have been discussed.
8.6.1 Virtual Destructors
The destructor of the class is called indirectly whenever the delete operator is used on an object of the class as discussed in Section 5.3.8. Since we have not declared any destructors in our motor class hierarchy, the only destructors available to our classes are the default destructors generated by the compiler for each class in the hierarchy. The selected motor has a corresponding ‘motor’ object instantiated in the body of the program’s switch statement (Listing 8-13). When the program is finished using the ‘motor’ object, it frees the memory occupied by the ‘motor’ object using the following statement: