Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Interfacing with C plus plus-programing communication with microcontrolers (K. Bentley, 2006)

.pdf
Скачиваний:
192
Добавлен:
12.08.2013
Размер:
3.18 Mб
Скачать

8 DRIVING MOTORS - DC & STEPPER 255

BPFSStepperMotorPtr->SetSpeed(150); while(!kbhit()) BPFSStepperMotorPtr->Forward(); getch(); // clear keyboard buffer

BPFSStepperMotorPtr->SetSpeed(220); while(!kbhit()) BPFSStepperMotorPtr->Forward(); getch();

BPFSStepperMotorPtr->SetSpeed(250); while(!kbhit()) BPFSStepperMotorPtr->Reverse(); getch();

BPFSStepperMotorPtr->SetSpeed(255); while(!kbhit()) BPFSStepperMotorPtr->Reverse(); getch();

while(!kbhit()) BPFSStepperMotorPtr->Brake();

BPFSStepperMotorPtr->Off();

//BPFS Motor control part ends here

//Release memory occupied by the DCMotor object delete BPFSStepperMotorPtr;

break;

case 5: BPHSStepperMotorPtr = new StepperMotor(BPHS); if(BPHSStepperMotorPtr == NULL)

{

cout << "Memory allocation failed " << endl; 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();

cout << " KEYPRESS changes SPEED/ROTATION (& Braking)." << endl;

// BPHS Motor control part starts here BPHSStepperMotorPtr->SetSpeed(150); while(!kbhit()) BPHSStepperMotorPtr->Forward(); getch(); // clear keyboard buffer

256 8 DRIVING MOTORS - DC & STEPPER

BPHSStepperMotorPtr->SetSpeed(220); while(!kbhit()) BPHSStepperMotorPtr->Forward(); getch();

BPHSStepperMotorPtr->SetSpeed(250); while(!kbhit()) BPHSStepperMotorPtr->Reverse(); getch();

BPHSStepperMotorPtr->SetSpeed(255); while(!kbhit()) BPHSStepperMotorPtr->Reverse(); getch();

while(!kbhit()) BPHSStepperMotorPtr->Brake();

BPHSStepperMotorPtr->Off();

//BPHS Motor control part ends here

//Release memory occupied by the DCMotor object delete BPHSStepperMotorPtr;

break;

case 6: return;

default: cout << endl;

cout << " Unspecified Motor type...."; cout << " PRESS a key to END Program!"; getch();

exit(1); // Exits the program

}

}

As you can see, coding without the use of virtual functions can be quite inefficient. Note: the delete operator was used in Listing 8-10, Listing 8-13, and Listing 8-20 to relinquish the dynamically allocated memory that stored the ‘motor’ object.

8.7 Keyboard Controls

We can enhance control of the motor by making use of the PC keyboard. To do this the program must be able to detect each press of the keys used for motor control purposes. These key presses can be detected using several methods. The easiest method is to use the getch() or the getche() functions. Another option is to use the library function kbhit().

8 DRIVING MOTORS - DC & STEPPER 257

The functions getch() and getche() as their names imply, can be used to read the character corresponding to the key pressed. The function getche() has the extra capability of being able to display the character on-screen as it is read. This is known as echoing to the screen (the added ‘e’ stands for ‘echo’). However, there is a disadvantage to using these two functions being that they wait for a key press. Execution of a getch() function will not allow following statements to be executed until a key is pressed. This delay will prevent us from generating the fast changing signals needed for motor control.

The kbhit() function operates differently. It does not wait for a key press. It checks if a key has been pressed. If a key has been pressed, the function will return true, if not it will return 0, meaning false. Because it does not wait for a key press, the program will execute continuously as intended. Note that kbhit() does not clear the keyboard buffer (ready for the next time it needs to be used).

The built-in library also provides another function named bioskey() used to detect normal keys with an ASCII code (see Appendix B) or extended keys such as function keys, INS, DEL keys etc. Extended keys are identified by a two-byte key code whereas normal keys are identified by a one-byte key code.

The function bioskey() can operate in different modes depending on the parameter passed to it. It uses one integer parameter whose value determines if it will detect a key press like the kbhit() function or read the pressed key. Note that this function does clear the keyboard buffer when used to read a key.

We can read a special location in memory using the peekb() function to detect keys including Right Shift, Left Shift, Ctrl, Alt, Caps lock, Scroll lock, etc. Note that the peekb() function cannot detect some keys such as the arrow keys.

The byte read from this memory location has flags (bits, shown in Figure 8-27) that are used to indicate which keys are pressed at any given time. The peekb() function is the fastest to execute and will generate minimum disruption to the continuous execution of the program. Therefore, using peekb() will enable smooth operation of the motors. If slower functions were used to read the keyboard, motor control could be erratic.

We will use the peekb() function to add keyboard control to our program using the following combinations of keys:

ξ

Pressing the Ctrl key will drive the motor forward.

ξ

Pressing the Alt key will drive the motor in reverse.

ξ

Pressing the Right Shift key will increase speed.

ξ

Pressing the Left Shift key will decrease speed.

ξ

Pressing both Left Shift and Right Shift keys brakes the motor.

ξ

Pressing No keys will switch motor power off.

ξ

Pressing the Insert key will end the program.

The status of the Shift keys, Control key, Alt key and the Insert key can be determined by reading a special memory location using peekb(). This 8-bit

258 8 DRIVING MOTORS - DC & STEPPER

memory location is at the segment:offset address of 0x40:0x17. When the respective key is pressed, its bit will be 1. For an explanation of segment:offset addressing, see Technical Reference: Personal Computer AT by IBM Corporation.

Byte at 0x40:0x17

 

7

6

5

 

4

3

2

1

0

 

Insert

 

 

 

 

 

 

 

 

Right shift

Caps lock

 

 

 

 

 

 

 

 

Left shift

Num lock

 

 

 

 

 

 

 

 

Ctrl

 

 

Scroll lock

 

 

Alt

 

 

 

Figure 8-27 Memory byte at 0x40:0x17 used to store key status.

A while loop is implemented in the program segment shown in Listing 8-21 which will run continuously provided the variable Quit is 0. This listing can be viewed as a replacement for Listing 8-10.

Listing 8-21 Motor control using a keyboard.

Motor *MotorPtr;

int Quit = 0;

unsigned char key = 0; int SpeedLock = 1;

while(!Quit)

{

key = peekb(0x40,0x17); // Read control key byte. if(key & 0x80) // Test Insert key ON (MSBit '1').

Quit = 1; // Exit the program.

else

{

//If both shift keys are released SpeedLock is

//released

if(!(key & 0x01) && !(key & 0x02)) SpeedLock = 0;

key &= 0x0F; // Filter out bits corresponding to

8 DRIVING MOTORS - DC & STEPPER 259

// just SHIFT, ALT & CTRL keys.

switch(key)

{

case 0x04 : MotorPtr->Forward(); break;

case 0x08 : MotorPtr->Reverse(); break;

case 0x01 : if(!SpeedLock)

{

MotorPtr->SetSpeed(MotorPtr->GetSpeed()+4); SpeedLock = 1;

}

break;

case 0x02 : if(!SpeedLock)

{

MotorPtr->SetSpeed(MotorPtr->GetSpeed()-4); SpeedLock = 1;

}

break;

case 0x03 : MotorPtr->Brake(); break;

case 0x05 : if(!SpeedLock)

{

MotorPtr->SetSpeed(MotorPtr->GetSpeed()+4); SpeedLock = 1;

}

MotorPtr->Forward(); break;

case 0x06 : if(!SpeedLock)

{

MotorPtr->SetSpeed(MotorPtr->GetSpeed()-4);

260 8 DRIVING MOTORS - DC & STEPPER

SpeedLock = 1;

}

MotorPtr->Forward(); break;

case 0x09 : if(!SpeedLock)

{

MotorPtr->SetSpeed(MotorPtr->GetSpeed()+4); SpeedLock = 1;

}

MotorPtr->Reverse(); break;

case 0x0B : if(!SpeedLock)

{

MotorPtr->SetSpeed(MotorPtr->GetSpeed()-4); SpeedLock = 1;

}

MotorPtr->Reverse(); break;

case 0x00 : MotorPtr->Off();

}

}

delete MotorPtr;

The peekb() function is used within the while loop to read the contents of the memory location 0x40:0x17. This value is stored in the variable key. We first check if the Insert key has been pressed, used as input to end program operation. We can detect if the Insert key has been pressed by carrying out an AND operation with 0x80. If the Insert key has been pressed, the result will be a non-zero value and therefore we set Quit to 1. As a result, the while loop will end followed by normal program termination.

If the Insert key has not been pressed, then program operation will continue. Hence, we now only need to read the lower four bits of the byte shown in Figure 8-27. These bits represent the remaining keys assigned for use by the program since we are not using Caps lock, Num lock, or Scroll lock keys. By filtering out the unused upper four bits of key (setting them to zero), we will have unique byte values for our respective key-press combinations. These bits are filtered out using an AND operation of the byte with 0x0F. The resulting value is stored back in key and then tested in a switch statement. All cases that can be implemented are listed in the switch statement where appropriate actions are taken. The main()

8 DRIVING MOTORS - DC & STEPPER 261

function of Listing 8-19 has been modified as shown in Listing 8-22 to implement keyboard controls.

The program has been given a ‘speed-locking’ mechanism that uses the identifier SpeedLock to control changes in motor speed. This mechanism will only allow speed to be changed once by a small increment for each press of the respective control key. Repeated reading of the speed control key while it is held pressed is not allowed to produce further change in speed, hence the term ‘speed-locking’. Without this control in place, excessive changes in motor speed would occur during the many executions of the while loop when the key is pressed.

Motor speed can only be adjusted with the initial press of a speed control key (Shift keys). At this time the variable SpeedLock will be set. Once SpeedLock is set, no further changes in speed can be made until that speed control key has been released. Releasing the key frees or ‘unlocks’ the speed-locking mechanism by clearing the value of SpeedLock (i.e. !SpeedLock is now true) and allows another increment in speed to be effected.

Speed-locking is implemented in the program in all speed control statements inside the switch statement block. Each speed control statement requires SpeedLock to be false (SpeedLock = 0) before its respective if statement can be executed. SpeedLock will be false whenever both speed control keys are released. When one of the speed control keys is pressed, its associated speed control statement will be selected within its if statement. This speed control statement increments or decrements the value of Speed by 4. The next statement in this if block turns speed-locking back on by setting the value of SpeedLock. Speed-locking will remain in effect until the speed control key is again released.

IMPORTANT: Do not use the following program to drive any motor without first observing the power-up procedure and motor connections as explained in the Note Box on page 243. If the motor does not drive as expected, first check the motor is correctly wired.

Listing 8-22 The complete program with keyboard controls

//**************************************************

//Program implements virtual functions and keyboard

//controls to operate a Motor.

//**************************************************

#include <dos.h> #include <conio.h> #include <stdio.h> #include <stdlib.h> #include <iostream.h>

class ParallelPort

{

262 8 DRIVING MOTORS - DC & STEPPER

private:

unsigned int BaseAddress; unsigned char InDataPort1;

public:

ParallelPort(); ParallelPort(int baseaddress);

void WritePort0(unsigned char data); void WritePort2(unsigned char data); unsigned char ReadPort1();

virtual ~ParallelPort(){}

};

ParallelPort::ParallelPort()

{

BaseAddress = 0x378; InDataPort1 = 0;

}

ParallelPort::ParallelPort(int baseaddress)

{

BaseAddress = baseaddress; InDataPort1 = 0;

}

void ParallelPort::WritePort0(unsigned char data)

{

outportb(BaseAddress,data);

}

void ParallelPort::WritePort2(unsigned char data)

{

outportb(BaseAddress+2,data ^ 0x0B);

}

unsigned char ParallelPort::ReadPort1()

{

InDataPort1 = inportb(BaseAddress+1);

//Inverting Most significant bit to compensate

//for internal inversion by printer port hardware. InDataPort1 ^= 0x80;

//Filter to clear unused data bits D0, D1 and D2 to zero. InDataPort1 &= 0xF8;

return InDataPort1;

}

8 DRIVING MOTORS - DC & STEPPER 263

class AbstractMotor

{

private:

int Speed;

public:

AbstractMotor();

void SetSpeed(int speed); int GetSpeed();

virtual void Off()=0; virtual void Forward()=0; virtual void Reverse()=0; virtual void Brake()=0; virtual ~AbstractMotor(){}

};

AbstractMotor::AbstractMotor()

{

Speed =0;

}

void AbstractMotor::SetSpeed(int speed)

{

Speed = speed;

if(Speed > 255) Speed = 255; // Limit upper value if(Speed < 0) Speed = 0; // Limit lower value

}

int AbstractMotor::GetSpeed()

{

return Speed;

}

class Motor : public AbstractMotor, public ParallelPort

{

public:

Motor(int baseaddress=0x378); void Off();

virtual void Forward()=0; virtual void Reverse()=0; virtual void Brake()=0; virtual ~Motor(){}

};

264 8 DRIVING MOTORS - DC & STEPPER

Motor::Motor(int baseaddress):ParallelPort(baseaddress)

{

Off();

}

void Motor::Off()

{

WritePort0(0x00);

}

class DCMotor : public Motor

{

public:

DCMotor(int baseaddress=0x378); virtual void Forward();

virtual void Reverse(); virtual void Brake();

};

DCMotor::DCMotor(int baseaddress):Motor(baseaddress)

{

}

void DCMotor::Forward()

{

int j;

for(j = 0; j < GetSpeed(); j++) WritePort0(0x09);

for(;j < 256; j++) WritePort0(0x00);

}

void DCMotor::Reverse()

{

int j;

for(j = 0; j < GetSpeed(); j++) WritePort0(0x06);

for(;j < 256; j++) WritePort0(0x00);

}

void DCMotor::Brake()

{

WritePort0(0x0C);

}