software development for microprocessor control systems

378
Software Development for Microprocessor Control Systems by Frans Nicolaas Snyman A Thesis submitted in partial fulfilment of the requirements for the degree of Master of Engineering Department of Electrical and Electronic Engineering University of Auckland New Zealand June 1998

Upload: f-n-snyman

Post on 01-Dec-2015

93 views

Category:

Documents


4 download

DESCRIPTION

Master of Engineering Thesis on designing and running control algorithms on embedded microprocessor-based automation systems.

TRANSCRIPT

Page 1: Software Development for Microprocessor Control Systems

Software Development for Microprocessor Control Systems

by

Frans Nicolaas Snyman

A Thesis submitted in partial fulfilment of the requirements for the degree of

Master of Engineering

Department of Electrical and Electronic Engineering University of Auckland

New Zealand

June 1998

Page 2: Software Development for Microprocessor Control Systems

iii

Abstract

This thesis concerns the development and application of a user-friendly microprocessor-based digital controller. Microprocessor programming is a specialized, time-consuming and labor-intensive step in the design process for digital control systems. The user-friendly control system software will allow control engineers to execute real-time microprocessor control algorithms on a system in a cost-effective manner without having to deal with any microprocessor software coding. This will result in shorter design and prototyping cycle times for microprocessor-based control systems. A Windows-based software program has been developed that will allow the user to select a controller from a finite list of controller designs and to specify the control parameters for the particular controller. The program will generate, compile and download the complete control algorithm to a microcontroller on which the control program will be executed. Controller performance data can be monitored in real-time while further data analysis is possible with offline plotting and saving features. The controller software was tested on control applications such as DC motor speed control and multivariable temperature control. The results from these tests were found to be in agreement with corresponding numerical models and verified the correct functionality of the controller software.

Page 3: Software Development for Microprocessor Control Systems

v

Acknowledgements

I would like to thank some of the people who helped me to make this thesis possible. First, I would like to thank my supervisors, Associate Professor Paul Austin, Dr. Bruce Macdonald and Dr. Sing Kiong Nguang for their contribution to this thesis in terms of ideas, comments and technical advice. Their friendliness and professional working approach was invaluable to the successful completion of this thesis. It was a pleasure working with them. I would also like to thank Sunita Bhide, Leonid Ostrovsky and Slavek Przepiorski for assisting me with some of the necessary hardware. Finally, I would like to thank my parents for their love and support and for giving me the opportunity for tertiary education. Their interest and involvement in my work was a big inspiration for me during all my years of studying.

Page 4: Software Development for Microprocessor Control Systems

vii

Contents Abstract . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . iii Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . v Contents . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . vii Glossary of Terms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xii Chapter 1

Introduction 1.1 Background . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1

1.1.1 Implementation of Digital Control Systems . . . . . . . . . . . . . . . 4 1.1.2 Commercially Available Control System Software . . . . . . . . . . 5

1.2 Thesis Objectives . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 1.3 Thesis Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11

Chapter 2

Digital Controller Fundamentals 2.1 The z-Transform . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13

2.1.1 The Ideal Sampler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14

2.1.2 The z-Transformation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 2.2 Digital Filtering . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16

2.2.1 Digital Filter Realization . . . . . . . . . . . . . . . . . . . . . . . . . . . 18

2.2.2 Digital Filter Sensitivity and Realizable Considerations . . . . . . 19

2.3 The PID Controller. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21 2.3.1 Numerical Approximation of the PID Controller . . . . . . . . . . . 22

2.3.2 Digital PID Control . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24

Page 5: Software Development for Microprocessor Control Systems

viii

2.4 Multivariable Digital Control. . . . . . . . . . . . . . . . . . . . . . . . . . 26

Chapter 3

Hardware Overview 3.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 3.2 Overview of the M68HC11 Microcontroller. . . . . . . . . . . . . . . 32

3.2.1 The Analog to Digital (A/D) Converter System . . . . . . . . . . . . 35 3.2.2 Asynchronous Serial Data Transmission . . . . . . . . . . . . . . . . . 37

3.2.3 The Timer System . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39 3.2.4 The Interrupt System . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41

3.3 The Memory Expansion Board. . . . . . . . . . . . . . . . . . . . . . . . . 43 3.3.1 The MC6821 Peripheral Interface Adapter (PIA) . . . . . . . . . . . 43

Chapter 4

The Windows-Based Software 4.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45 4.2 Adding Parameters to the Microcontroller Code. . . . . . . . . . . 48 4.3 Downloading S-record Code to the Microcontroller. . . . . . . . 52 4.4 Starting the Microcontroller Control Algorithm . . . . . . . . . . . 54 4.5 Decoding the Incoming Controller Data . . . . . . . . . . . . . . . . 55 4.6 Monitoring, Recording, Plotting and Saving

the Controller Performance Data . . . . . . . . . . . . . . . . . . . . . . 58

Chapter 5

The Microcontroller-Based Software 5.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61 5.2 The Test Input/Output Software Structure . . . . . . . . . . . . . . . . 63 5.3 The SISO Digital Controller Software Structure . . . . . . . . . . . 68 5.4 The MIMO Digital Controller Software Structure . . . . . . . . . 73

Page 6: Software Development for Microprocessor Control Systems

ix

5.5 Interfacing with Peripheral Equipment . . . . . . . . . . . . . . . . . . 78 5.5.1 Analog Input . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78

5.5.2 Frequency Input . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79

5.5.3 8-Bit Parallel Output . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85

5.5.4 PWM Output . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85 5.6 Clearing Timer Flags. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88 5.7 Sample Frequency Regulation . . . . . . . . . . . . . . . . . . . . . . . . . 89 5.8 Compiling and Linking Source Code. . . . . . . . . . . . . . . . . . . . 91

Chapter 6

Using the Windows-Based Software 6.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93 6.2 The Test Input/Output Section . . . . . . . . . . . . . . . . . . . . . . . . . 95 6.3 The SISO Digital Controller . . . . . . . . . . . . . . . . . . . . . . . . . . 96 6.4 The MIMO Digital Controller . . . . . . . . . . . . . . . . . . . . . . . . . 97 6.5 The PID Controller . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99 6.6 Program Operation and Commands . . . . . . . . . . . . . . . . . . . . 101

6.6.1 Downloading the Control Algorithm . . . . . . . . . . . . . . . . . . . 101

6.6.2 Start Executing the Control Algorithm . . . . . . . . . . . . . . . . . 104

6.6.3 Recording Controller Performance Data . . . . . . . . . . . . . . . . 105

6.6.4 Plotting and Saving the Recorded Data . . . . . . . . . . . . . . . . . 106

Chapter 7

Application Example: DC Motor Speed Control 7.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109 7.2 The DC Motor / Microcontroller Interface . . . . . . . . . . . . . . . 110

7.2.1 DC Motor Power Supply Regulation . . . . . . . . . . . . . . . . . . . 110 7.2.2 Speed Feedback . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111

7.3 System Modeling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112 7.4 Controller Implementation . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117

Page 7: Software Development for Microprocessor Control Systems

x

Chapter 8

Application Example: Digital Filtering 8.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121 8.2 Digital Filter Implementation . . . . . . . . . . . . . . . . . . . . . . . . . 123

Chapter 9

Application Example: Multivariable Temperature Control 9.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127 9.2 Analytical System Modeling . . . . . . . . . . . . . . . . . . . . . . . . . . . 129 9.3 The Process / Microcontroller Interface . . . . . . . . . . . . . . . . . 131

9.3.1 Temperature Measurement . . . . . . . . . . . . . . . . . . . . . . . . . . 131 9.3.2 Fan Speed Regulation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132 9.3.3 Heater Power Regulation . . . . . . . . . . . . . . . . . . . . . . . . . . . 133

9.4 Experimental System Modeling . . . . . . . . . . . . . . . . . . . . . . . . 134 9.5 Controller Implementation . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138

9.5.1 Temperature Control With Constant Airflow . . . . . . . . . . . . . . 138

9.5.2 Multivariable Controller Implementation . . . . . . . . . . . . . . . . 142

Chapter 10

Conclusions and Recommendations

10.1 Conclusions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147 10.2 Recommendations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149

References . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .151

Page 8: Software Development for Microprocessor Control Systems

xi

Appendix A ANSI/IEEE Standard 754 Floating-Point Representation . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153 Appendix B S-record Information . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159 Appendix C Ziegler-Nichols Tuning of PID Controllers . . . . . . . . . . . . . . . . 163

Appendix D Circuit Schematics and PCB Layouts . . . . . . . . . . . . . . . . . . . . . . 167 Appendix E Application Example Images . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171 Appendix F The Windows-Based Software Source Code . . . . . . . . . . . . . . . . 175 Appendix G The Microcontroller Software Source Code . . . . . . . . . . . . . . . . 319

Page 9: Software Development for Microprocessor Control Systems

xii

Glossary of Terms

A/D Analog to Digital ADCTL Analog to Digital Control Status ANSI American National Standards Institute ASCII American Standard Code for Information Interchange BUFFALO Bit User Fast Friendly Aid to Logical Operations CFF Conversions Complete Flag CMOS Complementary Metal Oxide Semiconductor COFF Common Object File Format CRA Control Register A CRB Control Register B CSEL Clock Select DIP Dual In-line Package DRA Data Register A DRB Data Register B DSP Digital Signal Processor EBLP Evaluation Board Low Power EEPROM Electrically Erasable Programmable Read Only Memory GUI Graphical User Interface I/O Input/Output IEEE Institute of Electrical and Electronics Engineers, Inc. ISR Interrupt Service Routine MCU Microcontroller Unit MIMO Multi-Input-Multi-Output MIPS Million Instructions Per Second MSB Most Significant Bit OTPROM One Time Programmable Read Only Memory PA Port A PB Port B PC Personal Computer PCB Printed Circuit Board PI Proportional + Integral

Page 10: Software Development for Microprocessor Control Systems

xiii

PIA Peripheral Interface Adapter PID Proportional + Integral + Derivative PLCC Plastic Leadless Chip Carrier PWM Pulse Width Modulation RAD Rapid Application Development RAM Random Access Memory RE Receive Enable RIDE Real-time Integrated Development Environment ROM Read Only Memory S/N Signal/Noise SCI Serial Communications Interface SISO Single-Input-Single-Output T Sample Period (seconds) TC Transmit Complete TDRE Transmit Data Register Empty TE Transmit Enable TIC Timer Input Compare TOC Timer Output Compare TOF Timer Overflow UART Universal Asynchronous Receiver Transmitter VRH Voltage Reference High VRL Voltage Reference Low

Page 11: Software Development for Microprocessor Control Systems

1

Chapter 1 Introduction 1.1 Background Feedback control is having, and will have in the future, a significant impact on all aspects of modern society. In recent years significant progress has been made in microcomputer control of dynamic systems as the price and performance of digital computers has improved dramatically. Many automatic control functions such as decision-making, self-tuning and adaptive control are now possible with the use of digital controllers. Digital controllers are less sensitive to noise and disturbance, more reliable, more flexible and less susceptible to aging and environmental variations than their analog counterparts [1]. The chemical and process industries were one the first users of computer-based control systems mainly because of the relatively inert dynamic characteristics of most chemical processes [2]. Recent advances in microprocessor technology made it possible to implement many new digital control applications such as aircraft automatic pilot, automotive antilock braking systems, radar positioning control and

Page 12: Software Development for Microprocessor Control Systems

Chapter 1 - Introduction

2

power plant turbine speed control [3]. Modern digital controllers are also used for less obvious control applications such as the control of water height and spin speed in modern washing machines and the control of blood flow in artificial hearts [4]. The basic structure of a digital control system can be illustrated through an example of an automatic aircraft landing system as illustrated in Figure 1.2. The system can be divided into four basic parts: the aircraft, the radar unit, the controller unit and the transmitter unit. The radar unit will measure variables such as lateral position, vertical position and range. The measured data will be sent to the controller unit and the appropriate pitch and bank commands will be calculated and transmitted back to the on-board automatic flight control system. The on-board automatic flight control system will then do the necessary adjustments to the flight controls to keep the aircraft on the correct glide slope and extended runway centerline.

Figure 1.1 The flight deck for the new Boeing 717 features the latest in digital control technology. The dual Flight Management System and the Category IIIa standard automatic landing capability integrates navigation, guidance, and performance data functions. The Flight Management System provides accurate engine thrust settings and flight-path guidance during all phases of flight from takeoff to final approach and landing. The system can predict the speeds and altitudes that will result in the best fuel consumption and command the airplane to follow the most economical flight path. (Courtesy of The Boeing Company)

Page 13: Software Development for Microprocessor Control Systems

Chapter 1 – Introduction

3

It is necessary to know the mathematical relationship between all the parts of the system before any control algorithm can be programmed into the aircraft controller. This mathematical relationship is referred to as the system mathematical model. The dynamic response of most aircraft can be modeled in the form of a ninth-order nonlinear differential equation [5]. Once the system’s mathematical model is known, a control system can be designed that will keep the aircraft stable on its proper descent path. The task of the control engineer is to design and specify the most effective processing algorithm to be accomplished in the digital controller. There is normally a compromise between the swiftness of the aircraft response and its position stability. The processing algorithm in the controller computer has to correct any error in the aircraft’s position as rapidly and effectively as possible while the system’s sensitivity to external disturbances such as wind and radar noise must kept to a minimum.

Lateral position

Range

Vertical position

Transmitter Positioncommand

Phased array Radar unit

Figure 1.2 Basic structure of an Automatic Aircraft Landing System

Vertical digital compensator

Lateral digital compensator

Controller Computer

Page 14: Software Development for Microprocessor Control Systems

Chapter 1 - Introduction

4

1.1.1 Implementation of Digital Control Systems Processors suitable for digital control systems range from standard microprocessors to special-purpose Digital Signal Processors (DSPs). In recent years, high-performance DSPs have been developed, which is significantly faster than standard microprocessors. The high performance and low cost of modern DSPs together with the use of powerful rapid prototyping software tools, allows engineers to design and program controllers much faster and with less cost than conventional controller board designs. DSPs are rapidly becoming the industry standard for control system implementation. Many powerful software tools are available for modeling, analyzing and simulating modern control systems. Many of these software packages provide the user with a block diagram interface, which allow the user to model and design a control system graphically. Once a system has been designed with the modeling software, rapid prototyping DSP software tools can generate, cross-compile and download the control algorithms to a DSP directly from the control system graphical models in the modeling software. This rapid prototyping technique allows engineers to execute real-time DSP control algorithms on a system without having to deal with any DSP software coding. This will result in shorter design cycle times and will decrease the total design and prototyping costs of modern control systems.

Figure 1.3 The Quattro62 Multiple Processor DSP Board is based on Texas InstrumentsTMS320C6201 DSP and is capable of sustained total computational throughput of 6400MIPS. (Source: Innovative Integration)

Page 15: Software Development for Microprocessor Control Systems

Chapter 1 – Introduction

5

1.1.2 Commercially Available Control System Software MathWorks DSP Workshop® The MathWorks Inc. provides a fully integrated set of software tools for modeling, designing and implementing a wide range of embedded control systems. MATLAB® from The MathWorks, Inc. has become the premier integrated technical computing environment for numerous engineering and scientific applications and is a powerful tool to express DSP algorithms. MATLAB combines advanced numeric computation, graphics, visualization, and a high-level programming language. Simulink® is an interactive environment that is integrated with MATLAB. Simulink provides a graphical user interface for constructing block diagram models for modeling, analyzing, and simulating a wide variety of applications. MathWorks DSP Workshop is a new product suite from The MathWorks, Inc. that is based on MATLAB and Simulink®. DSP Workshop provides a powerful development environment for control algorithm design, block diagram simulation, code generation and rapid prototyping of real-time DSP software. Real Time Workshop® ,which is part of the MathWorks DSP Workshop suite, provides real-time C code generation from Simulink models to perform rapid prototyping of embedded control systems. The generated real-time C code is compatible with most floating-point embedded processors and DSPs. VisSim/DSP® VisSim from Visual Solutions, Inc. provides a fully integrated Windows-based control system design environment for the modeling and simulation of a wide variety of control systems. VisSim incorporates a visual block diagram user interface that offers a simple method for constructing, modifying and analyzing complex system models. VisSim/DSP is a completely integrated Windows program for the rapid prototyping of control systems targeted for DSPs and embedded systems. VisSim/DSP includes integrated modules for automatic C code generation, downloading and real-time DSP validation & optimization.

Page 16: Software Development for Microprocessor Control Systems

Chapter 1 - Introduction

6

Hypersignal® RIDE™ Hyperception's Real-time Integrated Development Environment (RIDE) is a visual graphical environment for the design, implementation, and analysis of real-time DSP algorithms. Hypersignal RIDE supports numerous industry-standard plug-in DSP boards. The system can also export DSP Object code exported to a standard Common Object File Format (COFF) object file for embedded DSP applications. The user interface of Hypersignal RIDE is the same for both simulated and real-time DSP block functions, which allows convenient conversions between design simulations and real-time implementations. Hypersignal RIDE can also generate ANSI C source code, which may then be cross-compiled for use in other environments.

Figure 1.4 The VisSim/DSP Development Environment

Page 17: Software Development for Microprocessor Control Systems

Chapter 1 – Introduction

7

ECP Turn-Key Systems Educational Control Products (ECP) provides integrated equipment for the study of feedback control and system dynamics. The Turn-Key Systems from ECP consists of user-friendly interface software, a DSP controller, I/O electronics and a plant. The primary purpose of the Turn-Key systems from ECP is to provide students with user-friendly system interface software so that control systems and dynamics principles can be studied in an effective and convenient way. ECP provides various predefined experiments that can be performed on the Turn-Key systems. The ECP Executive system interface program allows the user to specify and implement a controller design on any of ECP’s family of electromechanical plants. The Executive system interface program can also perform various other operations such as real-time plotting and export of data to other software packages. The DSP

Figure 1.5 The Hypersignal RIDE development environment

Page 18: Software Development for Microprocessor Control Systems

Chapter 1 - Introduction

8

board is a version of PMAC technology provided through Delta Tau Data Systems and will be used in conjunction with the I/O electronics unit.

Figure 1.6 Turn-Key Systems from ECP (Reproduced from http://www.ecpsystems.com/aturnkey/aturnkey.htm)

Page 19: Software Development for Microprocessor Control Systems

Chapter 1 – Introduction

9

1.2 Thesis Objectives Programming a microprocessor or a DSP is a specialized and time-consuming process. Often underestimated, software development is usually the most labor- intensive step in the design process for digital control systems [6]. The aim of this project is to design and build a user-friendly microprocessor-based controller out of widely available resources so that control engineers can implement and test their controller design in a cost-effective manner without having to deal with extensive microcontroller programming. The Motorola 68HC11 microcontroller is sufficient for numerous medium performance control applications and was selected as the controller for this project. The reason for selecting the Motorola 68HC11 microcontroller over a DSP is that the M68HC11 microcontroller is a widely available, affordable and well-known microcontroller in the industry. The basic requirements for the software system is to provide: • A user-friendly interface between the control engineer and the microcontroller. • Easy implementation of limited order Single-Input-Single-Output (SISO)

microcontroller-based controller designs. • Easy implementation of limited order Multi-Input-Multi-Output (MIMO)

microcontroller-based controller designs. • User-specified sampling frequencies • Easy graphical analysis of plant and controller performance. • Saturation of controller I/O ports without incorporating any control wind-up. Figure 1.7 shows the basic layout of the M68HC11 based control system. The type of controller and its control parameters will be specified by the user on the PC. The software on the PC will then generate, compile and download the control algorithm to the M68HC11 microcontroller. The microcontroller will execute the control algorithm on a plant while the PC will only monitor the system performance. The data received from the microcontroller can be plotted or stored on disk for further analysis.

Page 20: Software Development for Microprocessor Control Systems

Chapter 1 - Introduction

10

Microcontroller

Monitor Signals

Process

Control Algorithm

Figure 1.7 The microcontroller-based control system

User Specify Control Parameters

Control Signals

Feedback Signals

Control Process

Page 21: Software Development for Microprocessor Control Systems

Chapter 1 – Introduction

11

1.3 Thesis Overview This thesis is concerned with the development and application of the microprocessor-based controller as described in section 1.2. This thesis will also assist anyone who wishes to use, improve or alter the current software system. Chapter 2 presents the mathematical fundamentals of the digital controller used in this project. Topics such as the z-transform theory, Single-Input-Single-Output (SISO) digital filtering, Multi-Input-Multi-Output (MIMO) digital filtering and PID (Proportional + Integral + Derivative) control are covered. Chapter 3 discusses the essential hardware needed by the software system. A brief overview of the M68HC11 microcontroller and the memory expansion board is given with some emphasis on the microcontroller features used by the software system in this project. Chapter 4 contains a detailed explanation of the Windows-based software structure. Aspects such as the graphical user interface and the interface between the Windows-based software and the microcontroller-based software are discussed. Chapter 5 contains a detailed explanation of the different microcontroller-based software modules and how this software structure interacts with the Windows-based software system. In Chapter 6, the Windows-based software is discussed from a user’s point of view. This chapter will discuss the user interface and will provide useful information on all the operations and commands of the Windows-based software. In Chapter 7, Chapter 8 and Chapter 9, some application examples for the software system in this project are presented. Applications such as DC motor speed control, low-pass digital filtering and multivariable temperature acquisition and control are demonstrated with the developed software system. Conclusions and recommendations for further development work are summarized in Chapter 10. The essential hardware diagrams and the Windows-based and microcontroller-based software source code is grouped together in the appendices.

Page 22: Software Development for Microprocessor Control Systems

Chapter 1 - Introduction

12

Page 23: Software Development for Microprocessor Control Systems

13

Chapter 2 Digital Controller Fundamentals 2.1 The z-Transform A digital computer can only perform arithmetic calculations at discrete time intervals [1]. It is assumed that the numbers that enter or leave the computer will do so at a fixed period T, which is called the sampling period. The operation of a discrete-time system is most logically described by a set of difference equations in the form

( ) ( ) ( ) ( ) ( )nkeb...kebkebnkua...kua)k(ua nn −++−+=−++−+ 11 1010

where ( )ke and ( )ku are the respective input and output numbers of the computer at

time t. The values ( )nke − and ( )nku − are the respective input and output numbers of the computer at time nTt − . The z-Transform method will transform a system whose operation is described by a set of differential equations in the Laplace domain to a system whose operation is described by a set of difference equations in the z-domain. The z-Transform is

(2.1)

Page 24: Software Development for Microprocessor Control Systems

Chapter 2 – Digital Controller Fundamentals

14

therefore a useful transformation to find a convenient way of representing the operation of digital control systems.

2.1.1 The Ideal Sampler Consider an ideal sampler as shown in Figure 2.1. An ideal sampler is defined as a sampler which closes and opens every T seconds for a zero time duration [1]. The continuous input is ( )tr and the discrete sampler output is ( )t*r . The current

sample time is kT and the current value of ( )t*r is ( )kTr . The impulse function, ( )tTδ is defined as

( ) ( )∑∞

=

−=0k

T kTtt δδ

The output of the ideal sampler can therefore be expressed as

( ) ( ) ( ) ( )∑∞

=

=−=0k

T ttrkTt)kT(rt*r δδ

2.1.2 The z-Transformation The Laplace transform of the output of the ideal sampler can be written as

£ [ ] ( ) ( )∑∞

=

−==0k

kTsekTrs*R)t(*r

(2.2)

(2.4)

(2.3)

Figure 2.1 Representation of the Ideal Sampler with input ( )tr and output ( )t*r

Sampler

Continuous Signal Discrete Signal

( )tr ( )t*r

time time

Page 25: Software Development for Microprocessor Control Systems

Chapter 2 – Digital Controller Fundamentals

15

Equation 2.4 represents an infinite series that involves factors of sTe and its powers. The transformation between s an z can be defined as

Tsez = Equation 2.5 can also be written in terms of z as

zlnT

s 1=

Equation 2.5 and 2.6 is defined as the z-transformation. The z-transform of r(t) can therefore be written as.

( ) ( )∑∞

=

−=0k

kzkTrzR

(2.5)

(2.6)

(2.7)

Page 26: Software Development for Microprocessor Control Systems

Chapter 2 – Digital Controller Fundamentals

16

2.2 Digital Filtering The use of a digital filter is the most versatile way of compensating a discrete-data control system [1]. Digital filters can be realized with digital networks, microprocessors or digital signal processors (DSPs). The major advantage of using digital a filter is that the control algorithm can easily be adjusted by changing the software program of the digital filter whereas the continuous-time filter is rather difficult to change and will often require changing of hardware components. In continuous-time systems, signal filtering is associated with RC, LC or RLC type of circuits [8]. These circuits are described in continuous-time by differential equations while digital filter structures are described by discrete-time difference equations as illustrated in section 2.1. The relationship between a continuous-time filer and its equivalent discrete-time representation can be illustrated by considering a typical second-order continuous-time RLC filter. The differential equation for the second-order RLC filter is

xydtdy

dtyd 2

0202

2

2 ωωσ =++

where

LC

LR

12

20 =

=

ω

σ

C

RL

y x

Figure 2.2 The RLC Filter

(2.8)

(2.9)

Page 27: Software Development for Microprocessor Control Systems

Chapter 2 – Digital Controller Fundamentals

17

The second-order transfer function of the RLC circuit can be obtained by taking the Laplace transform of Equation 2.8.

( )( ) 2

02

20

2 ωσω

++=

sssXsY

By using the backward difference rule as shown by Bozic (1979), the discrete-time form of Equation 2.10 can be written as

)Tt(*yb)Tt(*yb)t(*xa)t(*y 2210 −+−+=

The solution for the parameter gains using backward difference rule is

T

T

ebTcoseb

a

σ

σ ω2

2

111

0

21

−=

=

=

where T is the sampling period. The digital equivalent of the RLC filter illustrated in Figure 2.2 can thereforre be implemented by the digital filter structure illustrated in Figure 2.3.

+ +

+ y*(t)

1−z1−zy*(t-T) y*(t-2T)

x*(t) x(t) 0a

2b 1b

Figure 2.3 Digital filter equivalent for the RLC filter

(2.10)

(2.11)

(2.12)

Page 28: Software Development for Microprocessor Control Systems

Chapter 2 – Digital Controller Fundamentals

18

2.2.1 Digital Filter Realization The discrete-time digital transfer function can be defined as

( ) ( )( ) ∑

=

=

== M

m

mm

N

n

nn

za

zb

xXzYzH

0

0

This digital transfer function is only valid for zero initial conditions, which are satisfied for the cases considered in this text [8]. By taking 10 =a , Equation 2.13 can be expressed as

( ) ( ) ( )∑∑=

=

− −=M

m

nm

N

n

nn zYzazXzbzY

10

The equivalent time-domain equation from Equation 2.14 is

( ) ( ) ( )∑ ∑= =

−−−=N

n

M

mmn mTt*yanTt*xbt*y

0 1

which is the difference equation that realizes H(z). Difference Equation 2.15 can also be directly implemented in any computational algorithm to realize a digital filter [8]. Two basic microcomputer operations are required to implement the difference equation. The first operation is data storage. Past samples of the filter input and output are normally used in the computation of the output y*(t). The second operation involves arithmetic operations such as add and multiply.

(2.13)

(2.14)

(2.15)

Page 29: Software Development for Microprocessor Control Systems

Chapter 2 – Digital Controller Fundamentals

19

2.2.2 Digital Filter Sensitivity and Realizable Consideration Parameter Sensitivity Considerations The digital filter realization shown in Equation 2.15 is known as a direct digital filter structure. The major disadvantage of the direct digital filter structure is that it suffers a large coefficient sensitivity for large values of m and n [5]. This problem can be avoided by implementing a cascade of second-order digital filter modules of the form.

1−z( )Tt*x −( )t*x

1−z 1−z

0

0

ab

0

1

ab

0

2

ab

( )Tt*x 2−

0abn

( )nTt*x −

( )t*y

1−z( )Tt*y −

1−z 1−z

0

1

aa

0

2

aa

( )Tt*y 2− ( )nTt*y −

0aan

+ +

+ +

+ +

+

+

+ + +

+

Figure 2.4 Block diagram for the direct digital filter

Page 30: Software Development for Microprocessor Control Systems

Chapter 2 – Digital Controller Fundamentals

20

( )2

21

1

22

110

1 −−

−−

++++

=zazazbzbb

zD

The transfer function H(z) can be written in factorized form as follow.

( ) ( )zDzHp

kk∏

=

=1

Physical Realizability Considerations The digital filter transfer function, H(z) can only be realized if H(z) is physical realizable [1] . This implies that no output signal of the digital filter will appear before an input signal is applied. For the transfer function in Equation 2.13 to be physically realizable, the highest power of the denominator must be greater or equal than the highest power of the numerator. This implies that mn ≥ . Also, for the difference Equation 2.15 to be physical realizable, 0a may not be zero.

( )zD1 ( )zD2 ( )zD p

( )t*x ( )t*y

Figure 2.5. Block diagram for the cascade digital filter

(2.16)

(2.17)

Page 31: Software Development for Microprocessor Control Systems

Chapter 2 – Digital Controller Fundamentals

21

2.3 The PID Controller The PID (Proportional + Integral + Derivative) controller is one of the most common forms of Single-Input-Single-Output (SISO) closed-loop control [1]. The popularity of this controller can be attributed to their robust performance in a wide range of operating conditions [3]. It is therefore sensible to consider the digital implementation of the PID controller. The mathematical model for the PID controller in the time domain is

∫ ++= )t(edtdKdt)t(eK)t(eK)t(u DIP

where

plantfromsignalError/InputController)t(e = planttosignalControl/OutputController)t(u =

ttanConsoportionalPrKP = ttanConsIntegralKI =

ttanConsDeravitiveK D = By taking the Laplace transform, the PID controller can be represented in the s-domain as follow

)s(EsKs

KK)s(U D

IP ⎟

⎠⎞

⎜⎝⎛ ++=

pK

+( )sE )s(Us

K I

sK D

Figure 2.6 The continuous-time PID controller

(2.18)

(2.19)

Page 32: Software Development for Microprocessor Control Systems

Chapter 2 – Digital Controller Fundamentals

22

2.3.1 Numerical Approximation of the PID Controller The sampled-data transformation methods [5] will be used to obtain a numerical representation of the PID controller, which can be implemented on a digital computer. This technique is useful when a continuos system in the s-domain need to be transformed to the z-domain. Approximation of the Derivative Part The backward difference approximation technique can be used to approximate the derivative part of the PID controller.

T)Tt(e)t(e)t(e

dtd)t(uD

−−≈=

where T is the sampling period of the controller. Approximation of the Integral Part The right-side rectangular technique can be used to approximate the integral part of the PID controller. Figure 2.7 illustrates the use of this technique.

∫=t

II dtteKtu0

)()(

Assume that the upper limit of the integral is nTt = . Hence

∑∫=

==n

i

nT

I )iT(eTdt)t(e)nT(u10

t

)(te

Figure 2.7 The right-side rectangular rule T T T T

(2.20)

(2.21)

(2.22)

Page 33: Software Development for Microprocessor Control Systems

Chapter 2 – Digital Controller Fundamentals

23

)()(

)()()()(1

1

1

TnTTenTu

TnTTeiTeTiTeTTnTu

I

n

i

n

iI

++=

++==+ ∑∑=

+

=

Let 1−= nn , then:

)()()( nTTeTnTunTu II +−=

The numerical representation of the PID controller can therefore be written as:

)nT(uK)nT(uK)nT(uK)nT(u DDIIPP ++=

where:

)nT(e)nT(uP =

)nT(Te)TnT(u)nT(u II +−=

T)TnT(e)nT(e)nT(uD

−−=

Derivation of a Discrete-data Mapping Function An alternative sampled-data mapping function can now be derived which will make manual transformations between the s-plane and the z-plane easier. The equivalent Laplace domain approximation for Equation 2.26 is:

)(yT

)s(Ye)s(Y)s(sYsT

++−

≈ 0

If )(y +0 is small, then Equation 2.27 can be written as

Tes

sT−−≈

1

Equation 2.5 defines the mapping function of the standard z-transform as

sTez =

(2.23)

(2.24)

(2.25)

(2.26)

(2.27)

(2.28)

(2.29)

Page 34: Software Development for Microprocessor Control Systems

Chapter 2 – Digital Controller Fundamentals

24

By substituting sTe with z in Equation 2.28, the sampled-data mapping function for the backward difference approximation can be written as

Tzs

11 −−=

This mapping function will make manual transformations between the s-plane and the z-plane easier. The major disadvantage of this mapping function lies in its frequency response contour [5]. Small values for T will however improve this approximation. 2.3.2 Digital PID Control The discrete transfer function of the PID controller can be represented as

( ) ⎟⎠⎞

⎜⎝⎛ −

+⎟⎠⎞

⎜⎝⎛

−+

+=z

zT

KzzTK

KzD DIP

111

2

This transfer function can be directly implemented by the digital filter structure illustrated in Figure 2.8. Arithmetic operations for the proportional, integral and differential terms are kept separately until the terms are summed at the output.

e*(t) + 1−z

+

+

+ 2TK I

1−z+

TK D

PK

+ +

+

u*(t)

Figure 2.8 Direct digital implementation of the PID controller

(2.30)

(2.31)

Page 35: Software Development for Microprocessor Control Systems

Chapter 2 – Digital Controller Fundamentals

25

An alternative method to implement the digital PID controller is to find the second-order transfer function of Equation 2.31.

( )( )( ) ( )( ) ( )( )

( )( )zz

zzT

KzzTKzzKzD

DIP

1

1112

1

−−+++−=

( ) ( ) ( )zz

zzT

KzzTKzzK DIP

+−+++−= 2

222 122

zzT

KzTKTKKz

TKTKK DDI

PDI

P

+⎟⎠⎞

⎜⎝⎛ −+−+⎟

⎠⎞

⎜⎝⎛ ++

= 2

2 222

22

110

22

110

−−

−−

++++

=zazaazbzbb

where

TKTK

Kb DIP ++=

20

TKTK

Kb DIP

221 −+−=

TK

b D=2

10 =a

11 −=a

02 =a

Consequently, a digital PID controller can be implemented by any second-order direct digital filter structure as discussed in section 2.2.1.

(2.32)

(2.33)

Page 36: Software Development for Microprocessor Control Systems

Chapter 2 – Digital Controller Fundamentals

26

2.4 Multivariable Digital Control In section 2.2 the Single-Input-Single-Output (SISO) digital filter was introduced and the difference equation, which can be directly implemented in any computational algorithm, were derived. This section is based on Multi-Input-Multi-Output (MIMO) digital filtering where the input and output signals are vector quantities. A double-input-double-output system will be considered as illustrated in Figure 2.9. The transfer function of the system illustrated in Figure 2.9 can be described as

⎥⎦

⎤⎢⎣

⎥⎥⎥⎥

⎢⎢⎢⎢

=⎥⎦

⎤⎢⎣

2

1

22

22

21

21

12

12

11

11

2

1

ee

AB

AB

AB

AB

uu

The second-order transfer function of each element can be described as

22

11

22

110

1 −−

−−

++

++=

zazazbzbb

AB

xyxy

xyxyxy

xy

xy

(2.34)

(2.35)

Multivariable Digital Filter 2e

1u

2u

Figure 2.9 Double-Input-Double-Output digital filter representation

1e

Page 37: Software Development for Microprocessor Control Systems

Chapter 2 – Digital Controller Fundamentals

27

Rewriting Equation 2.34 gives

212

121

11

111 e

ABe

ABu +=

222

221

21

212 e

ABe

ABu +=

By getting a common denominator, Equation 2.36 can be written as

212111121111211 eBAeABuAA +=

222211222122221 eBAeABuAA +=

Let

441

331

221

11111211 1 −−−− ++++== zpzpzpzpPAA

441

331

221

1110111211

−−−− ++++== zqzqzqzqqQAB 4

413

312

211

110111211−−−− ++++== zrzrzrzrrRBA

442

332

222

11222221 1 −−−− ++++== zpzpzpzpPAA

442

332

222

1120222221

−−−− ++++== zqzqzqzqqQAB 4

423

322

221

120222221−−−− ++++== zrzrzrzrrRBA

so that Equation 2.37 can be written as

⎥⎦

⎤⎢⎣

⎡⎥⎦

⎤⎢⎣

⎡=⎥

⎤⎢⎣

⎡⎥⎦

⎤⎢⎣

2

1

22

11

2

1

2

1

00

ee

RQRQ

uu

PP

(2.36)

(2.37)

(2.39)

(2.38)

Page 38: Software Development for Microprocessor Control Systems

Chapter 2 – Digital Controller Fundamentals

28

Expanding Equation 2.39 gives

( )( )( )( )( )

( )( )( )( )( )⎥

⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥

⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢

−−−−

−−−−

⎥⎦

⎤⎢⎣

Tt*uTt*uTt*u

Tt*ut*u

Tt*uTt*uTt*u

Tt*ut*u

pppppppp

432

432

100000000001

2

2

2

2

2

1

1

1

1

1

42322212

41312111

( )( )( )( )( )

( )( )( )( )( )⎥

⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥

⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢

−−−−

−−−−

⎥⎦

⎤⎢⎣

⎡=

Tt*eTt*eTt*e

Tt*et*e

Tt*eTt*eTt*e

Tt*et*e

rrrrrqqqqqrrrrrqqqqq

432

432

2

2

2

2

2

1

1

1

1

1

42322212024232221202

41312111014131211101

(2.40)

Page 39: Software Development for Microprocessor Control Systems

Chapter 2 – Digital Controller Fundamentals

29

Equation 2.40 can be rearranged as

( )( )

( )( )( )( )( )

( )( )( )( )( )⎥

⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥

⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢

−−−−

−−−−

⎥⎦

⎤⎢⎣

⎡=⎥

⎤⎢⎣

Tt*eTt*eTt*e

Tt*et*e

Tt*eTt*eTt*e

Tt*et*e

rrrrrqqqqqrrrrrqqqqq

t*ut*u

432

432

2

2

2

2

2

1

1

1

1

1

42322212024232221202

41312111014131211101

2

1

( )( )( )( )( )( )( )( )⎥

⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥

⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢

−−−−−−−−

⎥⎦

⎤⎢⎣

⎡−

Tt*uTt*uTt*u

Tt*uTt*uTt*uTt*u

Tt*u

pppppppp

432

432

00000000

2

2

2

2

1

1

1

1

32322212

41312111

Consequently, Equation 2.41 can be directly implemented in any computational algorithm to realize the transfer function of the second-order double-input-double-output digital filter described in Equation 2.34.

(2.41)

Page 40: Software Development for Microprocessor Control Systems

Chapter 2 – Digital Controller Fundamentals

30

Page 41: Software Development for Microprocessor Control Systems

31

Chapter 3 Hardware Overview 3.1 Introduction This chapter contains a brief overview and discussion of the hardware needed by the software in this project. The M68EBLP11 Evaluation Board Low Power (EBLP), which incorporates an MC68B11E9 resident microcontroller, was used as the development platform in this project. The monitoring and debugging program, BUFFALO (Bit User Fast Friendly Aid to Logical Operations), which resides in the microcontroller ROM, is used to load S-record code into the microcontroller memory. The M68EBLP11 evaluation board was operated in expanded mode due to insufficient on-chip RAM. A custom-designed memory expansion board was added to the M68EBLP11 evaluation board to form the complete development platform for the software system. The schematic and PCB diagrams for this memory expansion board is listed in Appendix D.

Page 42: Software Development for Microprocessor Control Systems

Chapter 3 – Hardware Overview

32

3.2 Overview of the M68HC11 Microcontroller. Since microprocessors made their first appearance in the early 1970s, embedded systems were developed that could replace hundreds of discrete logic components[10]. The M68HC11 microcontroller is one of the most popular and most powerful 8-bit microcontrollers used in embedded systems today. The instruction set of the 68HC11 is similar to the older 68xx (6801, 6805, 6809) parts. Depending on the variety, the 68HC11 has built-in EEPROM/OTPROM, RAM, digital I/O, timers, A/D converter, PWM generator, and synchronous and asynchronous communications channels. It also uses high-speed CMOS transistors. This is what the letters HC stand for. These features make the M68HC11 an ideal tool for different types control applications. The traditional architecture of the M68HC11, which is more traditional than other competing products, such as the 8051 and PIC, makes is easier to develop different kinds of control applications. The M68HC11 is also inexpensive and has a wide range of development tools available. The M68HC11 is also optimized for low power consumption at bus frequencies up to 4 MHz. The M68HC11 microcontroller is architectural compatible with the M68HC05 family of 8-bit microcontrollers. It is also compatible with the more powerful 16-bit M68HC16 and M68HC12 family of microcontrollers. This means that the system can be upgraded without any major changes in the software for the microcontroller. The difference between a microcontroller and a microprocessor is in the completeness of the machine. A microcontroller consists out of a microprocessor, memory, I/O etc. The microcontroller can therefore be used as a stand-alone computer to perform specified tasks. Several versions of the 68HC11 are available. The different versions contain varying amounts of RAM and ROM and different I/O capabilities. The M68HC11E9 and the M68HC11A8 are amongst the most popular versions of the 68HC11 microcontroller. The 68HC11 come in one of two packages: a Plastic Leadless Chip Carrier (PLCC) and a Dual In-line Package (DIP). These two packages are shown in Figure 3.1. Figure 3.2 shows the block diagram of the 68HC11 microcontroller. It shows the major subsystems and how they relate to the different pins.

Page 43: Software Development for Microprocessor Control Systems

Chapter 3 – Hardware Overview

33

It is important to note the only the microcontroller features that are significant for this project were emphasized in this chapter. Various texts, such as the M68HC11 Reference Manual are available which will provide a detailed description of the M68HC11 family of microcontrollers. Programming a microcontroller is different than programming a large PC. Although most programming is done in a high level language, some control bits in the microcontroller still has to be adjusted using low level assembly language to ensure proper operation of the device. It is absolutely necessary for the programmer to fully understand the microcontroller when writing code for it. Aspects such as I/O, time management and memory management are handled by the operating system on larger machines. There is no such operating system present on a M68HC11 microcontroller.

Figure 3.1 MC68HC11E9 52 pin PLCC and 65 pin SDIP pin assignments. (Reproduced from the M68HC11 reference manual)

Page 44: Software Development for Microprocessor Control Systems

Chapter 3 – Hardware Overview

34

The C programming language was used for writing programs for the M68HC11. The reason for choosing C over assembly language for writing programs on the M68HC11, is that it is faster and easier to construct larger programs in C than in assembly language. C is also portable to other microprocessors. This means that by using a different C compiler, the same C program can be used on a different microprocessor. C compilers for the 68HC11 are widely available. The Archimedes ANSI C 68HC11 Compiler was used to compile the C programs for the 68HC11 in this project.

Figure 3.2 The M68HC11 E-series block diagram (Reproduced from the M68HC11 reference manual)

Page 45: Software Development for Microprocessor Control Systems

Chapter 3 – Hardware Overview

35

3.2.1 The Analog to Digital (A/D) converter system This section describes how to interface analog signals to the microcontroller. A lot of physical variables such as temperature and pressure are analog in nature and need to be converted to a digital value before the variable can be processed by the microcontroller. Port E is connected to the analog to digital converter on the 68HC11. Port E can either serve as general purpose input pins or it can be used for input signals to the A/D converter. Input range and resolution The analog input range for the 68HC11 microcontroller is between ground and 5.12V [12]. The voltage difference between the Voltage Reference Low (VRL) and the Voltage Reference High (VRH) pin will determine the analog input range. Any input voltages on the A/D converter input outside the specified range will result in incorrect A/D conversion and may even permanently damage the A/D converter inputs. The analog interface must therefore scale the transducer signal to fit between these two voltages. The resolution is the analog voltage represented by each digital increment and is represented as follow:

n2rangeinputAnalogResolution = (3.1)

where n is the number of bits. The 68HC11 microcontroller support only 8-bit A/D conversion. The maximum resolution for the 68HC11 A/D converter can therefore be calculated as follow:

mV/bit202

V5.122

rangeinputAnalogResolution 8n === (3.2)

A/D Registers and memory map locations for Port E. Table 3-1 shows all the address locations associated with Port E. The OPTION register will control the A/D conversion process. Only the ADPU bit and the CSEL (Clock Select) bit in the OPTION register will affect the A/D conversion. The ADPU bit must be set before A/D conversion can take place and the CSEL bit should remain clear for microcontroller clock speeds above 750 kHz.

Page 46: Software Development for Microprocessor Control Systems

Chapter 3 – Hardware Overview

36

Register name

Memory Address

Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0

PORTE $100A Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0 ADCTL $1030 CCF - SCAN MULT CD CC CB CA ADR1 $1031 Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0 ADR2 $1032 Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0 ADR3 $1033 Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0 ADR4 $1034 Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0

OPTION $1039 ADPU CSEL IRQE DLY CME - CR1 CR0 Table 3-1 Registers associated with the A/D conversion system. The contents of the A/D control-status (ADCTL) register will control all the A/D conversions. A/D conversions are initiated by writing to the CFF (conversions complete flag) in the ADCTL register. The CFF flag will set every time an A/D conversion is complete. The SCAN bit will determine whether the A/D inputs are continuously scanned for updated values. If the SCAN bit is 0, A/D conversion will take place and the CFF flag will be set. If the SCAN bit is 1, A/D conversion will continually take place and the newer result will overwrite previous results. The MULT bit in the ADCTL register will determine whether A/D conversion will be performed in single channel mode or multiple channel mode. If the MULT bit is clear, only the analog input on a single channel will be converted. Four successive conversions will be performed, and the four results will be written in the four A/D result (ADR) registers. If the MULT bit is set, A/D conversion will be performed on each channel in a four-channel group. Table 3-2 shows the A/D channel assignments available to the user. The CD, CC, CB and CA bits are set in the ADCTL register.

Page 47: Software Development for Microprocessor Control Systems

Chapter 3 – Hardware Overview

37

CD CC CB CA A/D

Channel ADRx result for

MULT=1

0 0 0 0 PE0 ADR1

0 0 0 1 PE1 ADR2

0 0 1 0 PE2 ADR3

0 0 1 1 PE3 ADR4

0 1 0 0 PE4 ADR1

0 1 0 1 PE5 ADR2

0 1 1 0 PE6 ADR3

0 1 1 1 PE7 ADR4 Table 3-2 A/D conversion channel assignments

3.2.2 Asynchronous Serial Data Transmission Serial asynchronous data transmission can be used send different parameter values such as control effort and plant feedback to an external PC for monitoring and analyzing purposes. The method of asynchronous data transmission can be visualized in Figure 3.3. The character to be sent is shifted into a transmit-data register. It is then sent to the transmit-shift register and the transmit-data register is emptied so that it can receive another character. The serial communication interface (SCI) of the 68HC11 is a UART (Universal Asynchronous Receiver Transmitter) built into the 68HC11. The five registers associated with the SCI are: • The BAUD register • The SCCR1 register • The SCI Control Register (SCCR2). • The SCI Status Register (SCSR2). • The SCI Data Register (SCDR). The bit contents and the memory locations of these registers are listed in Table 3-3.

Page 48: Software Development for Microprocessor Control Systems

Chapter 3 – Hardware Overview

38

The contents of the BAUD register will determine the data transmission speed for both data transmission and reception. If the crystal frequency is 8 MHz, the SCP0 and SCP1 registers must be set and all the other bits in the BAUD register should be clear to ensure a data transmission speed 9600 bits per second. The Motorola reference manual can be consulted for other data transfer rates. In the SCCR1 register only the M bit and the T8 bit is used by the SCI. These bits are normally left alone. The M bit determines the length of the character to be transmitted. If the M bit is clear, the character transmitted will consist of a START bit, eight data bits and one STOP bit. The T8 bit will determine the number of STOP bits which will be used for data transmission. The default is one STOP bit which correspond to T8=0. Bits 0 and 1 of Port D are associated with the SCI. Bit 0 is the Rx data line which receive serial data and bit 1 is the Tx data line which transmit serial data. The TE (Transmit Enable) and RE (Receive Enable) bits in the SCCR2 register will determine whether bits 0 and 1 of Port D are used for serial communication or simple I/O. Serial communication will be enabled if the TE and RE bits in the SCCR2 register are set. The SCI status register, SCSR2, contains two bits that are associated to the SCI. The TDRE (Transmit Data Register Empty) bit will be set whenever the transmit data register is empty, which will inform the microprocessor of the status. If the transmit data register is full, TDRE will be set to 0 and data may not be send to the transmit

Clock TxD

Transmit shift register

Transmit data register

8-bit Characters to be transmitted

Figure 3.3 Asynchronous serial data transmission on the M68HC11

Page 49: Software Development for Microprocessor Control Systems

Chapter 3 – Hardware Overview

39

data register until the TDRE bit is 1 again. The TC (Transmit Complete) bit will be set to 1 if no data is being transmitted by the SCI. The SCI Data Register, SCDR will contain the data transmitted or received through the SCI. In the case of data reception, characters will arrive one bit at a time through PD0 and are shifted into the SCDR where the complete received byte can be read. In the case of data transmission, a character is placed into the SCDR, and it will be send through PD1 one bit at a time. It is also important to note that the SCDR is write-only for characters transmitted and read only for characters received through the SCI. Register

name Memory Address

Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0

BAUD $102B TCLR 0 SCP1 SCP0 RCKB SCR2 SCR1 SCR0 SCCR1 $102C R8 T8 0 M WAKE 0 0 0 SCCR2 $102D TIE TCIE RIE ILIE TE RE RWU SBK SCSR2 $102E TDRE TC RDRF IDLE OR NF FE 0 SCDR $102F T7/R7 T6/R6 T5/R5 T4/R4 T3/R3 T2/R2 T1/R1 T0/R0

Table 3-3 Registers associated with asynchronous serial communication on the 68HC11.

3.2.3 The Timer System Timing is an essential part for most digital control applications and it is therefore important to fully understand the timing system of the 68HC11 when creating control applications for it. Timing is determined by a crystal oscillator, which normally oscillates at 8 MHz for most 68HC11 applications. The E clock determines the time of each instruction cycle on the 68HC11 is one quarter of the crystal frequency. The E clock is therefore 2 MHz if the crystal frequency is 8 MHz. The output of the E clock is connected to a 16-bit counter. The output of the 16-bit counter is connected to the TCNT register at memory locations $100E and $100F. Memory location $100E forms the upper 8 bits of the counter and memory location $100F forms the lower 8 bits of the counter. The resolution (the smallest time interval) of the TCNT counter is the inverse of the E clock frequency, which is 0.5 μs. Table 3-3 shows the registers associated with the main timer system. The timer interrupt subsystems are discussed in section 3.2.4. The TOF (timer overflow) bit in

Page 50: Software Development for Microprocessor Control Systems

Chapter 3 – Hardware Overview

40

the TFLG2 register will set every time the 16-bit TCNT counter overflows. The TCNT will overflow every 32.77 ms if the resolution of the TCNT counter is 0.5 μs. The TOF bit will therefore set every 32.77 ms. The TOI (Timer Overflow Interrupt) bit in the TMSK2 register will determine whether a timer overflow interrupt will occur every time the timer overflows. Interrupts are discussed in section 3.2.4

Register name

Memory Address

Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0

TMSK2 $1024 TOI RTII PAOVI PAII 0 0 PR1 PR0 TFLG2 $1025 TOF RTIF PAOVF PAIF 0 0 0 0

Table 3-3 Registers associated with the main timing system on the 68HC11.

Input Capture and Output Compare registers The input capture system is very useful for measuring periodic data such as rotation speed. The input capture registers (TIC1, TIC2, and TIC3) are 16-bit read-only registers and are connected to pins PA0, PA1 and PA2 respectively. When a signal edge occurs on one of these input pins, the contents of the timer counter TCNT will be copied into the corresponding register and the corresponding flag in the TFLG1 register will set. The ICxI bits in the TMSK1 register will determine whether the corresponding input capture interrupt is enabled. The EDGxA and EDGxB bits in the TCTL2 register will determine how the input signal on pins PA0, PA1 and PA2 will affect the input capture registers.

EDGxB EDGxA Configuration 0 0 Capture disabled 0 1 Capture rising edges only 1 0 Capture falling edged only 1 1 Capture on rising and falling edges

Table 3-4 TCTL2 Input capture configuration

The output compare system is useful for generating complex timing waveforms, driving stepper motors or for creating accurate PWM waveforms. The output compare system consists of five 16-bit registers. They are labeled TOC1 to TOC5. Whenever

Page 51: Software Development for Microprocessor Control Systems

Chapter 3 – Hardware Overview

41

the value in the TCNT counter equals the value in one of the output compare registers, a flag for the corresponding output compare register will be set. The corresponding interrupt service routine will be called if the flag in the TMSK1 register associated with the output compare are set. Output pins PA7 to PA3 can be controlled by the five output compare registers. The contents of the TCTL1 register will determine how the output pins PA3 to PA6 will be affected by TOC2 to TOC5 respectively. Output compare register 1 (TOC1) is different from the other four output compare registers and can be set to affect all of the output pins (PA3 to PA7).

3.2.4 The Interrupt System It is sometimes desirable to run a subroutine program, which will do some dedicated instructions every time a certain event occurs on the 68HC11. An example of such an event is when input data is available for processing or when the TCNT counter overflows and the timer overflow flag need to be reset. These subroutine programs are known as interrupt service routines. Interrupt service routines forms an integral part of the control programs on the 68HC11 and is associated with many of the I/O and timer functions. Each event, such as time overflow, is associated with an interrupt vector. The vector table is an address table in memory that points to the addresses at which each interrupt service routine will start. Since the interrupt vectors are written in ROM, they are inflexible and cannot be changed. The addresses, to which the interrupt vectors points to, are therefore also fixed. These addresses to which the interrupt vector table points to are called the interrupt vector jump table or the pseudo vector table. The pseudo vector table resides in the internal RAM area of the 68HC11 and its contents can be changed. Each entry in the pseudo vector table is 3 bytes long. The first byte should be the JUMP (Op code 7E) instruction and the next two bytes should be the 2-byte memory address at which the interrupt service routine will start. Table 3-5 shows some of the interrupt pseudo vectors with their corresponding memory address field.

Page 52: Software Development for Microprocessor Control Systems

Chapter 3 – Hardware Overview

42

Pseudo Interrupt Vector Memory Address Field

Serial communications interface (SCI) $00C4-$00C6 Serial peripheral interface (SPI) $00C7-$00C9 Pulse accumulator input edge $00CA-$00CC Pulse accumulator overflow $00CD-$00CF Clock counter (TCNT) overflow $00D0-$00D2 Timer output compare 5 (TOC5) $00D3-$00D5 Timer output compare 4 (TOC4) $00D6-$00D8 Timer output compare 3 (TOC3) $00D9-$00DB Timer output compare 2 (TOC2) $00DC-$00DE Timer output compare 1 (TOC1) $00DF-$00E1 Timer input capture 3 (TIC3) $00E2-$00E4 Timer input capture 2 (TIC2) $00E5-$00E7 Timer input capture 1 (TIC1) $00E8-$00EA Real Time Interrupt $00EB-$00ED IRQ $00EE-$00F0 XIRQ $00F1-$00F3 Software interrupt (SWI) $00F4-$00F6 Illegal Op code $00F7-$00F9 Computer operating properly $00FA-$00FC Clock monitor $00FD-$00FF Table 3-5 Pseudo vector table for the 68HC11 (Reproduced from Greenfield, 1992)

Page 53: Software Development for Microprocessor Control Systems

Chapter 3 – Hardware Overview

43

3.3 The Memory Expansion Board The only memory available on the M68EBLP11 Evaluation Board, is the internal memory on the MC68B11E9 microcontroller, which is 322 bytes of internal RAM and 512 bytes of internal EEPROM (Electrically Erasable Programmable Read Only Memory). For the purpose of this project, the M68EBLP11 is being operated in expansion mode in conjunction with a 32Kb custom-built memory expansion board. The addressable RAM of the memory expansion board is 0x2000 to 0x9FFF. The schematic diagram and the PCB layout of the memory expansion board is shown in Appendix D.

3.3.1 The MC6821 Peripheral Interface Adapter (PIA) The Motorola MC6821 Peripheral Interface Adapter (PIA), which is part of the memory expansion board, provides two bi-directional 8-bit busses for interface to peripheral equipment since the two 8-bit data ports on the M68HC11 are occupied for interfacing with the external memory. The PIA is addressable at memory location 0xA100 to 0xA103. Each bi-directional 8-bit bus consists of three 8-bit registers. These registers are • Data Register (DRA / DRB) • Data Direction Register (DDRA / DDRB) • Control Registers (CRA / CRB)

Register Name Corresponding Address

Data register A (DRA) 0xA100

Data Direction Register A (DDRA) 0xA100

Control Register A (CRA) 0xA101

Data register B (DRB) 0xA102

Data Direction Register B (DDRB) 0xA102

Control Register B (CRB) 0xA103 Table 3-6 MC6821 PIA Register addresses

Page 54: Software Development for Microprocessor Control Systems

Chapter 3 – Hardware Overview

44

Only the B part of the MC6821 PIA will be considered since the A and B part of the PIA is almost identical. The data register is essentially a buffer between the PIA I/O pins and the system data bus [11]. The direction of each bit in the data register is determined by the data direction register configuration. A ‘0’ on a bit in the data direction register will make the corresponding data register bit an input, and vice versa for a ‘1’ on the data direction register bit. The data register and the data direction register share the same address at 0xA102. Bit 2 in the control register (CRB2) will determine whether the data register or the data direction register will be activated when memory location 0xA102 is addressed. If CRB2=1 then memory address 0xA102 applies to the data register. The B section peripheral data lines (PB0-PB7) of can be programmed to act as inputs or outputs. For the purpose of this project, PB0-PB7 are programmed to act as output lines. The C code segment below will initialize the MC6821 to use PB0-PB7 as output lines. #define PIAPB (*(volatile unsigned char*)(0xA102))

(unsigned char ) 0xA102;

(unsigned char ) 0xA103;

*(unsigned char ) 0xA103=0x00; /*Clear CRB*/

*(unsigned char *) 0xA102=0xFF; /*Set bits in DDRB*/

*(unsigned char *) 0xA103=0x04; /*Set DDRB bit for output*/

Page 55: Software Development for Microprocessor Control Systems

45

Chapter 4 The Windows-Based Software 4.1 Introduction A Windows95 based digital control program was developed, which provides a user-friendly interface for implementing a wide variety of digital controller designs on the M68HC11 microcontroller. The Windows program, which is called HC11Control, will allow the user to select a digital controller design and to specify the control parameters for the particular controller. HC11Control will compile and download the complete control algorithm to the M68HC11 evaluation board on which the control program will be executed. The input and output ports can be saturated without incorporating any control wind-up. HC11Control can also monitor, record, plot and save the control system performance data for further analysis. It was decided to develop the GUI program to run under Windows 95, while C++ was selected as the programming language to be used for this project. The reason for

Page 56: Software Development for Microprocessor Control Systems

Chapter 4 – The Windows-Based Software

46

choosing the Windows 95 operating system is that Windows 95 is intended to operate PCs for many years to come [13]. Windows 95 is also a 32-bit operating system that makes windows programming easier. The C++ programming language was selected because it combines the elements of high-level programming languages with the functionalism of assembly language [13]. Consequently, C and C++ are one of the most powerful and most popular programming languages in use today. Borland C++Builder was used as the development environment for the Windows-based software. Borland C++Builder is an object-oriented, visual programming environment for Rapid Application Development (RAD) for Microsoft Windows 95 and Windows NT. Using the Borland C++ rapid application development environment, application development time can significantly be reduced by reusing various predefined software components. The software structure for the Windows-based program is completely event-driven. The program exists out of a number of functions, which is called by the appropriate events. These event-driven functions are called event handlers. Each event handler will perform a specific task, such as downloading control parameters, monitor incoming serial data, etc. The Windows-based program will contain the predefined control algorithms for each controller type. The predefined control algorithms for the different types of controllers in the is already compiled and linked by the ANSI C 68HC11 Compiler, Linker and Burner from Archimedes Software Inc. The microcontroller control algorithms is stored in the S-record format in HC11Control. The user interface consists of four integrated modules. The four modules are: • Test Input/Output • Single-Input-Single-Output Digital Controller • Double-Input-Double-Output Digital Controller • PID Controller The PID Controller uses the same software structure as the Single-Input-Single-Output Digital Controller. The three PID controller parameters, PK , IK and DK are

converted to the a and b vectors as described in section 2.3.2 before downloading the controller parameters to the microcontroller.

Page 57: Software Development for Microprocessor Control Systems

Chapter 4 – The Windows-Based Software

47

Serial communication with the microcontroller forms an essential part of the software system. Serial communications in Windows 95 is also significantly different from serial communications in the older 16-bit versions of Windows. The ZComm component for C++Builder provided by ZBuilder Software was used to create the asynchronous serial communication between the PC and the microcontroller. Only the essential concepts behind the Windows-based software are covered in this chapter. Software aspects such as the user interface and error handling will not be discussed. The complete program source code for the Windows-based software is listed in Appendix F. The following software concepts will be discussed in this chapter: • Adding control parameters to the microcontroller code. • Downloading the control algorithm to the microcontroller. • Starting the control program on the microcontroller. • Decoding the incoming controller performance data from the microcontroller. • Monitor, record, plot and save the controller performance data to disk.

Page 58: Software Development for Microprocessor Control Systems

Chapter 4 – The Windows-Based Software

48

4.2 Adding Parameters to the Microcontroller Code The Microcontroller control program is developed to read the user-entered parameter values from a specified location in the microcontroller memory. It is therefore necessary for the main program on the PC to download these parameter values to this specified memory location on the microcontroller. The procedure starts by converting the text in the textbox to an integer or floating-point number, depending on the type of parameter. The textbox in which the user enters the parameter value, is in the form of a C++Builder MaskEdit component. The text in the textbox is stored in the C++Builder MaskEdit->Text property. Two types of parameters are used for downloading purposes. The first parameter conversion- and download routine will convert the text in the textbox to an 8-bit unsigned value and will link this value to the predefined control algorithm. Any value larger than 255 in the text box will be ignored. The second type of parameter is a floating-point value, which will be converted from text in the textbox to a 32-bit ANSI/IEEE 754 floating point number. This 32-bit (or 4-byte) floating-point number will later be added to the predefined control algorithm in the form of a S-record line. (The ANSI/IEEE 754 standard is discussed in Appendix A) After the user-entered control parameters were converted to hexadecimal format, other S-record information such as the S-record length, S-record memory address and the checksum has to be added to the hexadecimal control parameters to form the complete S-record line as shown in Figure 4.1. The complete S-record information can be found in Appendix B.

Page 59: Software Development for Microprocessor Control Systems

Chapter 4 – The Windows-Based Software

49

10 11

“09” “0A” “0B”

Convert entered control parameters to hexadecimal format

Collate the hexadecimalcharacters to a single string

“090A0B”

Add S-record length and memory location information to the string

“S1060000090A0B”

Calculate the checksum and add thechecksum byte to the string

“S1060000090A0BDB”

“S03098B . . . S111B6005 . . . S112B6005 . . . S113B6007 . . . S940000B5 . . .”

Predefined Control Algorithm

Add the single S-record line to the predefined control algorithm

“S03098B . . . S1060000090A0BDB S111B6005 . . . S112B6005 . . . S113B6007 . . . S940000B5 . . .”

Final Control Algorithm

Figure 4.1 Schematic representation of adding control parameters to the microcontroller code

9

Page 60: Software Development for Microprocessor Control Systems

Chapter 4 – The Windows-Based Software

50

The following program segment shows an example which will convert the value entered in the DigitalSetpointEdit textbox to an 8-bit unsigned character, which is placed in variable[0]. char variable[10];

char *psetpoint;

int setpoint;

psetpoint=DigitalSetpointEdit->Text.c_str();

setpoint=atoi(psetpoint);

variable[0]=setpoint;

The next program segment is an example that will convert a real number entered in DigitalA0Edit text box to a ANSI/IEEE 754 floating point value stored in A0. The four bytes which represent the 32-bit floating point number will then be stored in variable[1], variable[2], variable[3] and variable[4]. The variable array will later be used to construct the S-record line, which will be added to the predefined microcontroller control algorithm. char variable[10];

char *pstrA0;

float A0;

unsigned int adrA0;

float *pA0;

unsigned char A0_byte0;

unsigned char A0_byte1;

unsigned char A0_byte2;

unsigned char A0_byte3;

AnsiString ansiA0=DigitalA0Edit->Text;

pstrA0=ansiA0.c_str();

A0=atof(pstrA0);

pA0=&A0;

adrA0=(int)pA0;

(char *) adrA0;

(char *) (adrA0+1);

(char *) (adrA0+2);

(char *) (adrA0+3);

A0_byte3=*(char *) adrA0;

A0_byte2=*(char *) (adrA0+1);

A0_byte1=*(char *) (adrA0+2);

A0_byte0=*(char *) (adrA0+3);

variable[1]=A0_byte0;

variable[2]=A0_byte1;

Page 61: Software Development for Microprocessor Control Systems

Chapter 4 – The Windows-Based Software

51

variable[3]=A0_byte2;

variable[4]=A0_byte3;

It is important to note that the pointer, pA0 is a pointer to a float type. If the current value of pA0 is 2000 for example, the result of the expression pA0+1 will be 2005 and not 2001. Each time pA0 is incremented, it points to the next floating-point number and not to the next byte in the floating-point number. It is necessary though, to point to the next byte in the 4-byte floating-point number. One way to get around this problem is to declare an integer variable, adrA0, which acts as a substitute pointer to the floating-point number. The expression adrA0+1 will then point to the next byte of the floating-point number.

Page 62: Software Development for Microprocessor Control Systems

Chapter 4 – The Windows-Based Software

52

4.3 Downloading S-record Code to the Microcontroller After the S-record line has been created and added to the predefined control algorithm, the complete control algorithm is ready to be downloaded to the microcontroller. The download form will prompt the user to reset the microcontroller. The reason for this is that the state of the microcontroller is unknown before the reset action. A reset action will exit the current microcontroller program being executed, force the microcontroller unit to undertake a set of initial conditions and begin executing instructions from a predetermined starting address. The CommReceiveDataAvailable event-handler will monitor the incoming serial data from the microcontroller and will activate the download procedure when the characters, which correspond to a reset action is received from the microcontroller. If any other characters are received from the microcontroller, the program will call the ErrorDownloadStartMessage form in which the user will be prompted that a running program on the microcontroller has to be stopped before the download procedure can continue. It was found that the download procedure halts all other event-handlers and functions in the Windows program. The solution was to use thread-based multitasking for the download procedure. The download procedure was programmed in such a way so that it will run in different thread. A thread is a dispatchable unit of code, which can be executed concurrently with other program operations. The ZComm1DataAvailable event handler monitors the characters received from the microcontroller for a ‘done’ message while a different thread is downloading the control algorithm to the microcontroller. If a ‘done’ message is received from the microcontroller, a ‘run’ button will be enabled, which will allow the user to start the control algorithm on the microcontroller. If no ‘done’ message is received from the microcontroller, an error message will be displayed and the download procedure will be cancelled.

Page 63: Software Development for Microprocessor Control Systems

Chapter 4 – The Windows-Based Software

53

Start the download procedure

Prompt the user to resetthe microcontroller

Was a reset action detectedfrom the microcontroller?

Enable serial communication betweenthe PC and the microcontroller.

Is serial data available in theinput buffer?

Yes

No

No

Yes

Initialize the microcontroller toreceive program data from the serial communication interface.

Download the control algorithm to themicrocontroller in a separate thread.

Display error message

End the download procedure

Is all the data downloaded tothe microcontroller?

Yes

Was a “done” message receivedfrom the microcontroller?

No

No Display error message

End the download procedure Enable the user to start the controlalgorithm on the microcontroller

End the download procedure

Yes

Figure 4.2. Control algorithm download procedure

Page 64: Software Development for Microprocessor Control Systems

Chapter 4 – The Windows-Based Software

54

4.4 Starting the Microcontroller Control Algorithm After the downloaded procedure is successfully completed, a ‘run’ button will be enabled, which will allow the user to start the control algorithm on the microcontroller. The run control algorithm form will prompt the user to reset the microcontroller. The reason for this is the same as for the download procedure in section 4.2. The state of the microcontroller is unknown before the reset action. A reset action will exit the current microcontroller program being executed, force the microcontroller unit to undertake a set of initial conditions and begin executing instructions from a predetermined starting address. The CommReceiveDataAvailable event-handler monitors the characters received from the microcontroller and will start the program on the microcontroller when the characters, which correspond to a reset action, is received from the microcontroller. If any other character is received from the microcontroller, the program will call the ErrorDownloadStartMessage form in which the user will be prompted that a running program on the microcontroller has to be stopped before the program on the microcontroller can be started.

Page 65: Software Development for Microprocessor Control Systems

Chapter 4 – The Windows-Based Software

55

4.5 Decoding the Incoming Controller Data The program on the microcontroller transmits essential controller performance data such as the control effort, plant input and sample frequency back to the Windows program. This data is transmitted over a single serial line and need to be decoded into the different parameters. The MonitorCommDataAvailable event-handler will store all incoming serial data from the microcontroller in an input buffer. The data in the input buffer consists of identifiers and controller performance data. Incoming data, valued between 251 and 255 are designated as identifiers. Serial data will be received from the microcontroller in the following format: For a Single-Input-Single-Output System: 251 Sample Frequency 252 Input from plant 253 Output to plant

For a Double-Input-Double-Output System: 251 Sample Frequency 252 Analog Input from plant 253 Frequency Input from plant 254 8-bit Output to plant 255 PWM Output to Plant

Page 66: Software Development for Microprocessor Control Systems

Chapter 4 – The Windows-Based Software

56

The consecution of the data may start and end at any point, but the data always have to be in the same order, for example: the following set of data is also valid for the single-input-single-output system: Input from plant 253 Output to plant 251 Sample Frequency 252 A set of data will be received at every sample period. The sample frequency data will be used to calculate the period between each sample. The controller input and output values can therefore be represented as a function of time. The following code segment will decode the input serial data from for the double-input-double-output system into meaningful data. All the input data will be stored in the Databuffer array. The data in the Databuffer array will then be decoded in to the time, analoginput, freqinput, _8bitoutput and PWMoutput arrays respectively. unsigned int len=strlen((char *)Databuffer); for (int scandata=0;scandata<10;scandata++) { if (Databuffer[scandata]==251) { for (unsigned int count=1+scandata;count<len;count=count+10) { samplefrequency=Databuffer[count]; float period=(float) 1/Databuffer[count]; if (timeindex==0) { time[timeindex]=0; } else { time[timeindex]=time[timeindex-1]+period; } timedisplay=time[timeindex]; timeindex++; } } else if (Databuffer[scandata]==252) {

Page 67: Software Development for Microprocessor Control Systems

Chapter 4 – The Windows-Based Software

57

for (unsigned int count=1+scandata;count<len;count=count+10) { analoginputdisplay=Databuffer[count]; analoginput[analoginputindex]=Databuffer[count]; analoginputindex++; } } else if (Databuffer[scandata]==253) { for (unsigned int count=1+scandata;count<len;count=count+10) { freqinputdisplay=Databuffer[count]; freqinput[freqinputindex]=Databuffer[count]; freqinputindex++; } } else if (Databuffer[scandata]==254) { for (unsigned int count=1+scandata;count<len;count=count+10) { _8bitoutputdisplay=Databuffer[count]; _8bitoutput[_8bitoutputindex]=Databuffer[count]; _8bitoutputindex++; } } else if (Databuffer[scandata]==255) { for (unsigned int count=1+scandata;count<len;count=count+10) { PWMoutputdisplay=Databuffer[count]; PWMoutput[PWMoutputindex]=Databuffer[count]; PWMoutputindex++; } }

}

Page 68: Software Development for Microprocessor Control Systems

Chapter 4 – The Windows-Based Software

58

4.6 Monitoring, Recording, Plotting and Saving the Controller Performance Data.

After the control algorithm has been started on the microcontroller, the user will be able to monitor, record, plot and save the controller performance data. The Borland C++ Builder Timer component will be used to display the incoming data from the microcontroller at regular intervals. The Timer component will call the DisplayTimer event-handler, which will display the latest valid incoming data from the microcontroller. The recording process works on the principle of filling an array sequentially with the incoming data from the microcontroller. The MonitorCommDataAvailable event-handler, which was discussed in section 4.5, will continuously fill the data arrays with incoming serial data. The array index is a 16-bit number, which will overflow to zero every 65536 counts. The data in the array will therefore be overwritten after every 65536 data entries. If the user samples incoming serial data at a rate of 50Hz, then it is possible to record approximately 22 minutes of controller performance data. It is important to note that the recording of controller performance data can utilize a lot of memory. The stack is of a limited size and cannot be changed as the program runs. It is therefore necessary to use dynamic memory allocation for the data arrays since these arrays are of a substantial size. Dynamic allocation means that the memory utilized by large data arrays is allocated from the heap. The heap amounts to all the free physical RAM plus all the free hard disk space on the PC. In C++, memory is allocated dynamically by using the new[] operator. The line of code below illustrates how an array can by allocated dynamically. double* analoginput = new double[65536];

All memory allocated with the new[] operator must be released by using the delete[] operator before closing the program. The line of code below illustrates the use of the delete[] operator. delete[] analoginput;

Page 69: Software Development for Microprocessor Control Systems

Chapter 4 – The Windows-Based Software

59

The data array index will simply be reset to zero if the user activates the recording process. The data array will then be sequentially filled from zero. When the user stops the recording process, the array index number will be saved. All the data in the array up to the point of the saved index number will be copied into a new data array, which represents the recorded data. The recorded data can be saved in the form of a normal text file. This data can be loaded by any data processing or spreadsheet program for further analyzing purposes. The SaveButtonClick event-handler will determine whether an existing file will. If a text file is to be overwritten, the FileOverwriteDiaolgBox will be called and will prompt the user whether the save procedure may continue or not. Recorded data, such as plant feedback and control effort can be plotted versus time for quick control system analysis. The TXYPlot component was used for plotting the controller performance data from the provided data arrays. TXYPlot is a Borland C++ Builder VCL plotting component for graphing the recorded data. It is capable of displaying an arbitrary number of plots simultaneously, each with its own x and y data.

Page 70: Software Development for Microprocessor Control Systems

Chapter 4 – The Windows-Based Software

60

Page 71: Software Development for Microprocessor Control Systems

61

Chapter 5 The Microcontroller-Based Software 5.1 Introduction The microcontroller-based software will handle all interfacing to peripheral equipment and will execute the control algorithms for the different digital controller designs, which is discussed in Chapter 2. The plant- and controller states and other essential controller data, such as sampling frequency will be transmitted back to the host PC for monitoring purposes.

The essential concepts behind the microcontroller-based software are discussed in this chapter. This software system consists of three independent modules, which falls into the following categories: • Test Input/Output • Single-Input-Single-Output (SISO) Digital Controller • Multi-Input-Multi-Output (MIMO) Digital Controller

Page 72: Software Development for Microprocessor Control Systems

Chapter 5 – The Microcontroller-Based Software

62

The MIMO Digital Controller is also capable of performing single-input-single-output (SISO) control. The SISO Digital Controller is however faster and easier to implement and is therefore not redundant. It is possible to embed the different program modules into one single program. The three categories of programs were kept separate for simplicity reasons. An embedded program will also be much bigger which will lead to more required microcontroller memory and longer download times from the PC. The major disadvantage of this individual program module scheme is that any software changes in one of the modules will affect only that specific module. It will therefore be more time-consuming to make any global changes to a specific category of programs.

Page 73: Software Development for Microprocessor Control Systems

Chapter 5 – The Microcontroller-Based Software

63

5.2 The Test Input/Output Software Structure The Test Input/Output program module was originally written for development and debugging purposes and was found to be very useful for control system development. The program will generate a known output signal and will read an input signal to the microcontroller at the same time. The user can configure the output signal as illustrated in Figure 5.1. The output signal can range from a ramp signal to a multi-step signal. These program modules will be used in conjunction with the Test Input/Output section of HC11Control and can be used in a wide variety of applications such as: • Testing the microcontroller’s interface to peripheral equipment. • Testing a system’s response to known input signals • Data acquisition. • Pulse signal generation The user can choose between four different input/output combinations as listed in Table 5-1. Section 5.5 provides a detailed description of the microcontroller’s interface to peripheral equipment while the complete program source code can be found in Appendix G.

Mic

roco

ntro

ller O

utpu

t

Time

Step delay time Step size

Output Upper Limit

Output Lower Limit

Figure 5.1 Output signal configuration for the Test Input/Output category of programs.

Page 74: Software Development for Microprocessor Control Systems

Chapter 5 – The Microcontroller-Based Software

64

I/O

Combination Associated Input Associated Output

1 Analog voltage input on pin PE5 8-Bit parallel output on pins PB0-PB7 on the MC6821 PIA

2 Frequency input on pin PA0 8-Bit parallel output on pins PB0-PB7 on the MC6821 PIA

3 Frequency input on pin PA0 PWM output on pin PA5

4 Analog voltage input on pin PE5 PWM output on pin PA5

Table 5-1. Input/Output port configuration for the four Test Input/Output program

The interrupt service routines for frequency input measurement and PWM signal generation are discussed in detail in section 5.5.2 and section 5.5.4 respectively.

Page 75: Software Development for Microprocessor Control Systems

Chapter 5 – The Microcontroller-Based Software

65

Begin

Assign parameter variable names to thedownloaded parameter data

Initialize the serial communicationinterface to transmit serial data.

Yes

No

Figure 5.2. Test Input/Output Flow diagram (Sheet 1 of 3)

Initialize the timer-overflow interrupt

Input/Outputcombination = 1?

Input/Outputcombination = 2?

Initialize theanalog-to-digital converter

Input/Outputcombination = 3?

No

No

Initialize pins PB0-PB7 onthe M6821 Peripheral Interface Adapter to serve as an 8-bit output port.

Initialize pins PB0-PB7 onthe M6821 Peripheral Interface Adapter to serve as an 8-bit output port.

Initialize the input capture 3(IC3) PA0 pin to set the IC3F flag of falling edges

Initialize the input capture 3(IC3) PA0 pin to set the IC3F flag of falling edges

1A 1B 1C

Yes

Yes

Page 76: Software Development for Microprocessor Control Systems

Chapter 5 – The Microcontroller-Based Software

66

1B

Initialize the OC1 and OC3output to produce a PWM signal

1C 1A

Initialize theanalog-to-digital converter

Save sample start-time and calculatethe desired sample end-time.

Output = Output Lower Limit

Did the output step-time elapse?

Yes Output = Output + Stepsize

Output > Output Upper Limit?

Output = Output Lower Limit

Yes

No

Yes

No Input/Outputcombination = 1 or 4 ?

Read the latest frequency-input period from memory, which was calculated by the frequency- input interrupt service routine.

2A

Figure 5.2 Test Input/Output Flow diagram (Sheet 2 of 3)

2B 2C

Page 77: Software Development for Microprocessor Control Systems

Chapter 5 – The Microcontroller-Based Software

67

2A

Yes

No

Input/Outputcombination = 1 or 2 ?

Send Output the peripheral interface adapter

2B

Read the input on theAnalog-to-Digital converter

Calculate the desired PWMon-time and write this value to memory.

Send Input, Output and SampleFrequency values to the Serial Communication Interface (SCI).

Did the desired sampleend-time elapse ?

Calculate the real sample periodand save this value

No

Yes

2C

Figure 5.2 Test Input/Output Flow diagram (Sheet 3 of 3)

Page 78: Software Development for Microprocessor Control Systems

Chapter 5 – The Microcontroller-Based Software

68

5.3 The SISO Digital Controller Software Structure The Single-Input-Single-Output (SISO) controller incorporates a fourth-order digital filter and a summing junction as shown in Figure 5.3. This program module will be used in conjunction with the Digital Controller and PID Controller sections in HC11Control. The digital filter is implemented using a fourth-order difference equation with floating point arithmetic. The input and output ranges of the controller can be specified by the user. The input and output will then be saturated without any control wind-up. Some of the possible applications for the Digital Controller category of programs are: • A PID Controller with anti-windup. • A fourth-order SISO anti windup digital controller. • Digital filtering Basic signal conversion can also be performed by the Digital Controller program module, such as: • Analog to PWM conversion • Analog to Digital conversion • Frequency to PWM conversion • Frequency to Digital conversion

44

33

22

110

44

33

22

110

−−−−

−−−−

++++

++++

zazazazaazbzbzbzbb

Setpoint

+ ±

Microcontroller

OutputInput

Figure 5.3 Schematic layout of the microcontroller-based digital controller software system

Fourth-Order Digital Filter

Serial Communication Interface

Serial data to PC

Saturation Saturation

Page 79: Software Development for Microprocessor Control Systems

Chapter 5 – The Microcontroller-Based Software

69

The Input/Output configuration of the SISO Digital Controller is the same the Test Input/Output section. The user can choose between four different input/output combinations as listed in Table 5-1. The software structure for the SISO Digital Controller module is illustrated in the flow diagrams shown in Figure 5.4. The complete program source code is listed in Appendix G.

Figure 5.4 SISO Digital Controller Flow diagram (Sheet 1 of 4)

Begin

Assign parameter variable names to thedownloaded parameter data

Initialize the serial communicationinterface to transmit serial data.

Yes

No

Initialize the timer-overflow interrupt

Input/Outputcombination = 1?

Input/Outputcombination = 2?

Initialize theanalog-to-digital converter

No

Initialize pins PB0-PB7 onthe M6821 Peripheral Interface Adapter to serve as an 8-bit output port.

Initialize the input capture 3(IC3) PA0 pin to set the IC3F flag of falling edges

Yes

1A 1B 1C

Page 80: Software Development for Microprocessor Control Systems

Chapter 5 – The Microcontroller-Based Software

70

Input/Output combination = 3?

No

Initialize pins PB0-PB7 onthe M6821 Peripheral Interface Adapter to serve as an 8-bit output port.

Initialize the input capture 3(IC3) PA0 pin to set the IC3F flag of falling edges

Yes

1A 1B 1C

Initialize the OC1 and OC3output to produce a PWM signal

Initialize the analog-to-digital converter

Save sample start-time and calculate thedesired sample end-time, which corresponds to the desired sample frequency.

Yes

No Input/Output combination = 1 or 4?

Read the latest frequency-input period from memory, which was calculated by the frequency- input interrupt service routine.

2A 2B

Figure 5.4 SISO Digital Controller Flow diagram (Sheet 2 of 4)

4

Page 81: Software Development for Microprocessor Control Systems

Chapter 5 – The Microcontroller-Based Software

71

Read the input on theAnalog-to-Digital converter

2B2A

Yes

No No Input < Input Lower Limit? Input > Input Upper Limit?

Input = Input Lower Limit Input = Input Upper Limit

Yes

Feedback mode = NegativeFeedback?

No

Yes

Error = Setpoint - Input Error = Setpoint + Input

Calculate Output byusing the digital filter difference equation

3A

Figure 5.4 SISO Digital Controller Flow diagram (Sheet 3 of 4)

Page 82: Software Development for Microprocessor Control Systems

Chapter 5 – The Microcontroller-Based Software

72

Yes

No No Output < Output Lower Limit? Output > Output Upper Limit?

Output = Input Lower Limit Output = Output Upper Limit

Yes

3A

Save the current input and outputvalues for the next difference equation calculations

Input/Output combination = 1 or 2?

Send Output the peripheralinterface adapter

Calculate the PWM on-time and write this value to memory.

Yes

No

Send Input, Output and SampleFrequency values to the Serial Communication Interface (SCI).

Did the desired sampleend-time elapse ?

Calculate the real sample periodand save this value

No

Yes

4

Figure 5.4 SISO Digital Controller Flow diagram (Sheet 4 of 4)

Page 83: Software Development for Microprocessor Control Systems

Chapter 5 – The Microcontroller-Based Software

73

5.4 The MIMO Digital Controller Software Structure Multi-Input-Multi-Output (MIMO) controller incorporates a fourth-order MIMO digital filter and a summing junction as shown in Figure 5.5. The mathematical model for the MIMO digital filter is discussed in section 2.4. The MIMO Digital Controller module will be used in conjunction with the Double-Input-Double-Output Digital Controller section in HC11Control. The digital filter is implemented using two fourth-order difference equations with floating point arithmetic while the input and output saturation ranges can be specified without incorporating any control wind-up.

The software structure for the MIMO Digital Controller module is illustrated in the flow diagram shown in Figure 5.6. The complete program source code is listed in Appendix G.

Setpoint 1

+

±

Microcontroller

Output 1Input 1

Multivariable Digital Filter

Serial Communication Interface

Serial data to PC

Saturation Saturation

Setpoint 2 +

±

Output 2Input 2

Saturation Saturation

⎥⎥⎥⎥⎥

⎢⎢⎢⎢⎢

++

++

++

++++

++

++

++

−−

−−

−−

−−

−−

−−

−−

−−

2212

1211

22

110

2212

1211

2212

1211210

2122

1121

2122

1121120

2112

1111

2112

1111110

11

11

zazazbzbb

zazazbzbb

zazazbzbb

zazazbzbb

xyxyxy

Figure 5.5 Schematic layout of the double-input-double-output digital controller

Page 84: Software Development for Microprocessor Control Systems

Chapter 5 – The Microcontroller-Based Software

74

Begin

Assign parameter variable names to thedownloaded parameter data

Initialize the serial communicationinterface to transmit serial data.

Figure 5.6 MIMO Digital controller Flow diagram (Sheet 1 of 4)

Initialize the timer-overflow interrupt

Initialize theanalog-to-digital converter

Initialize pins PB0-PB7 onthe M6821 Peripheral Interface Adapter to serve as an 8-bit output port.

Initialize pins PB0-PB7 onthe M6821 Peripheral Interface Adapter to serve as an 8-bit output port.

Initialize the input capture 3(IC3) PA0 pin to set the IC3F flag of falling edges

Save sample start-time and calculate thedesired sample end-time, which corresponds to the desired sample frequency.

Read the latest frequency-input period from memory, which was calculated by the frequency- input interrupt service routine.

1A 4

Page 85: Software Development for Microprocessor Control Systems

Chapter 5 – The Microcontroller-Based Software

75

Read the input on the

Analog-to-Digital converter

Yes

No No Frequency Input < FrequencyInput Lower Limit?

Frequency Input = FrequencyInput Lower Limit

Yes

Frequency Input > Frequency Input Upper Limit?

Frequency Input = Frequency Input Upper Limit

Yes

No No Analog Input < Analog InputLower Limit?

Analog Input = Analog InputLower Limit

Yes

Analog Input > Analog Input Upper Limit?

Analog Input = AnalogInput Upper Limit

Frequency Feedback mode= Negative Feedback?

No

Yes

Frequency Error = Frequency Setpoint– Frequency Input

Frequency Error = Frequency Setpoint + Frequency Input

Figure 5.6 MIMO Digital controller Flow diagram (Sheet 2 of 4)

1A

2A

Page 86: Software Development for Microprocessor Control Systems

Chapter 5 – The Microcontroller-Based Software

76

Analog Feedback mode =Negative Feedback?

No

Yes

Analog Error = Analog Setpoint –Analog Input

Analog Error = Analog Setpoint + Analog Input

Calculate the 8-Bit output by using a digital filter difference equation.

Calculate the PWM outputby using a digital filter difference equation.

Calculate the PWM on-time andwrite this value to memory.

Yes

No No 8-Bit Output < 8-Bit OutputLower Limit?

8-Bit Output = Frequency Output Lower Limit

Yes

8-Bit Output > 8-Bit OutputUpper Limit?

8-Bit Output = 8-BitOutput Upper Limit

Yes

No No PWM Output < PWM Output Lower Limit?

Yes

PWM Output > PWMOutput Upper Limit?

2A

3A 3B 3C

Figure 5.6 MIMO Digital controller Flow diagram (Sheet 3 of 4)

Page 87: Software Development for Microprocessor Control Systems

Chapter 5 – The Microcontroller-Based Software

77

PWM Output = PWM Output Lower Limit

PWM Output = PWMOutput Upper Limit

3A 3B 3C

Save the current input and outputvalues for the next difference equation calculations

Send the 8-Bit Output value the peripheral interface adapter

Calculate the PWM on-time and write this value to memory.

Send Input, Output and SampleFrequency values to the Serial Communication Interface (SCI).

Did the desired sample end-time elapse ?

Calculate the real sample periodand save this value

No

4

Yes

Figure 5.6 MIMO Digital controller Flow diagram (Sheet 4 of 4)

Page 88: Software Development for Microprocessor Control Systems

Chapter 5 – The Microcontroller-Based Software

78

5.5 Interfacing with Peripheral Equipment The microcontroller software system was designed to use two different input ports and two different output ports for interfacing with peripheral equipment. This section will discuss the software interface to peripheral equipment, which is also known as drivers. The Test Input/Output, SISO Digital Controller and MIMO Digital Controller uses the same set of drivers. The Test Input/Output and SISO Digital Controller modules can utilize only one input port and one output port at a time while the MIMO Digital Controller uses all four ports simultaneously. The controller ports are configured as follow.

Input ports: Associated pins Feasible Range

Analog input PE5 0 - 5.12 V

Frequency input PA0 0 – 256 Hz

Output ports:

PWM output PA5 40 – 256 Hz

8-Bit Parallel output PB0-PB7 on MC6821 PIA 00000000 – 11111111 binary Table 5-2 Input/Output port characteristics for the microcontroller software system.

5.5.1 Analog Input Many sensors for physical variables such as temperature and pressure are analog in nature and will produce an analog signal which need to be converted to a digital value before the variable can be processed by the microcontroller. The initadc function will enable A/D conversion by setting bit 7 in the OPTION register. The adc function will start the A/D conversion sequence, wait for a valid A/D conversion result and return the 8-bit converted value. The A/D conversion sequence begins one E-clock cycle after a write to the ADCTL register, which is known as the A/D control/status register. This analog input driver will perform a single-channel A/D conversion, with the SCAN bit in the A/D control/status register set to zero. Consequently, the A/D

Page 89: Software Development for Microprocessor Control Systems

Chapter 5 – The Microcontroller-Based Software

79

conversion result will be stored in the four A/D result registers, ADR1 – ADR3. The contents of the four A/D result registers can expected to be nearly identical. It is therefore only necessary to read one of the four A/D result registers. The following program segment shows the functions associated with A/D conversion.

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

/* Function to initialize the analog-to-digital */

/* converter system */

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

void initadc(void)

{

OPTION=0x80; /* Set bit 7 in OPTION high for A/D conversion */

}

unsigned char adc(void)

{

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

/* Analog to Digital conversion routine */

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

unsigned char temp;

ADCTL=0x5; /* Set analog inputs on PE5 (pin 46) */

while (ADCTL<128); /* Wait for input */

temp=ADR1;

return temp;

}

5.5.2 Frequency Input Many systems in which angular or lateral velocity is present, such as rotational shafts, can be set up to generate pulse signals which frequency is proportional to their velocity. The frequency measurement subroutine is interrupt driven and will be activated by a falling voltage on pin PA0. The time difference between consecutive falling edges, which represent the period of a waveform input on pin PA0, are then calculated. Timer overflows must be considered when measuring the period of a waveform. An 8-bit software counter, named timeroverflows keeps track of the counter overflows. The range of the timer is effectively extended to 24 bits, which enables the timer

Page 90: Software Development for Microprocessor Control Systems

Chapter 5 – The Microcontroller-Based Software

80

system to measure waveform periods up to 8 seconds with a bus speed of 2 MHz and a prescale factor of one. It is necessary to decide whether or not to count an overflow when an input capture occurs very close to a timer overflow. The software will handle this decision by looking at the MSB of the captured value. It is assumed that the timer-overflow interrupt service routine will be completed before the MSB of the free-running counter sets again. (The MSB of the counter will be set after 32768 TCNT counts, which correspond to 16.384 milliseconds.) If the timer overflow (TOF) bit and the input capture flag (IC3F) are both set and the captured value has a one in its MSB, then the capture occurred before the overflow. Conversely, if the TOF bit and IC3F are both set and the captured value has a zero in its MSB, then the capture occurred after the overflow and the case can be treated accordingly. It is also assumed that if an input capture and a timer-overflow happen in the vicinity of each other, the input capture will be serviced before the overflow. This assumption is confirmed by the interrupt priority resolution of the M68HC11, in which the input captures are handled prior to the timer overflow. The only way a timer overflow can be serviced before an input capture is if the timer overflow happened long enough before the input capture for the stacking and vector selection to be completed before any input capture is detected. The input capture interrupt service routine will check if a timer overflow occurred just after a leading edge or just before a trailing edge of a measurement period. If such an overflow is detected, the contents of the MSB of the captured value will then determine whether to include or exclude the overflow. The inittic3 function will initialize the microcontroller to react on a leading edge in the pulse input on pin PA0. The inputcapture function is the actual interrupt service routine, which will be activated when a leading edge on the input is detected. The inittimerinterrupt function will initialize the clock counter (TCNT) overflow interrupt and the timeroverflow function is the interrupt service routine which will be activated every time the TCNT clock counter overflows, which is every 32.768 ms.

Page 91: Software Development for Microprocessor Control Systems

Chapter 5 – The Microcontroller-Based Software

81

Start Interrupt service routine

Reset the IC3F flag by writing 1 to it

Calculate the difference between the start-time ofthe current interrupt service route and the start-time of the previous interrupt service routine.

Save the start-time of this interrupt serviceroutine for the calculations in the next input capture service routine.

Return to the main program

Figure 5.7 Frequency measurement interrupt service routine flow diagram

Did the timer-overflow (TOF) bit set?

Did the MSB in thecaptured TIC3 value set?

No

No Yes

Yes

Increment the timeroverflow variable with 1.

Reset the timer-overflow (TOF) flag by writing 1 to it

Reset the timeroverflowvariable to zero.

Page 92: Software Development for Microprocessor Control Systems

Chapter 5 – The Microcontroller-Based Software

82

It is not necessary to use the lower 8-bits of the TCNT timer. The resolution of the upper 8-bits of the TCNT counter is 256×0.5 μs = 0.000128 seconds which is still high enough to provide accurate timing. Because the 68HC11 is an 8-bit microcontroller, processing speed will significantly increase by leaving the lower 8-bits of the counter out of the calculations. The period variable, which represents all the TCNT counts between two consecutive pulses, have to be a 32-bit long integer if the program uses all the 16 bits of the TCNT counter. Unknown problems with the compiler were also experienced when performing arithmetic operations with 32-bit long integers. The solution for this problem was to use only the upper 8-bits of the TIC3 register in the arithmetic operations. The upper 8-bits of the TIC3 register was defined as TIC3UP in the hc11e9.h header file. The following program segment shows the functions associated with the frequency measurement system. The global variables are declared as shown in the complete program listing in Appendix G. The hc11e9.h header file must also be included for register name definitions.

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

/* Routine to initialize the timer overflow interrupt */

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

void inittimerinterrupt(void)

{

TMSK2.bit7=1; /* Enable the timer overflow interrupt */

asm

{

PSHA /* Save the contents of accumulator A */

LDAA #0x80 /* Load accumulator A with the mask data */

STAA 0x1025 /* Reset TOF Flag by writing 1 to it */

PULA /* Retrieve the saved contents of accumulator A */

}

/* Memory locations D0-D2 is a 3 byte pseudo interrupt vector for

the timer overflow */

(char *) 0x00D0;

/* Place jump instruction (op code 7E) in 00D0 */

*(char *) 0x00D0=0x7E;

(int * ) 0x00D1;

/* Place starting address of interrupt routine in D1&D2 */

*(int *) 0x00D1 = (int)timeroverflow;

}

Page 93: Software Development for Microprocessor Control Systems

Chapter 5 – The Microcontroller-Based Software

83

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

/* Routine to initialize the input capture 3 (IC3) */

/* interrupt service routine. */

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

void initic3(void)

{

/* Set input capture in TIC3(PA0) on rising edges only */

/* (For falling edges, TCTL2=0x02) */

TCTL2=0x01;

TMSK1.bit0=1; /* Enable the interrupt mask for IC3 (PA0) */

asm

{

PSHA /* Save the contents of accumulator A */

LDAA #0x01 /* Load accumulator A with the mask data */

STAA 0x1023 /* Reset input flag IC3F by writing 1 to it */

PULA /* Retrieve the saved contents of accumulator A */

}

/* Memory locations E2-E4 is a 3 byte */

/* pseudo interrupt vector for IC3(PA0) */

/* Place jump instruction (op code 7E) in 00E2 */

(char *) 0x00E2;

*(char *) 0x00E2 = 0x7E;

/* Place starting address of interrupt routine in E3&E4 */

(int * ) 0x00E3;

*(int *) 0x00E3 = (int)inputcapture;

}

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

/* TCNT counter overflow interrupt service routine */

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

void timeroverflow(void)

{

timeroverflows++; /* Timeroverflow counter for inputcapture */

sampletimeroverflows++; /* Counter for sample period regulation */

asm

{

PSHA /* Save the contents of accumulator A */

LDAA #0x80 /* Load accumulator A with the mask data */

STAA 0x1025 /* Reset the timer overflow flag (TOF) */

PULA /* Retrieve the saved contents of accumulator A */

RTI /* Return from Interrupt Service Routine */

}

}

Page 94: Software Development for Microprocessor Control Systems

Chapter 5 – The Microcontroller-Based Software

84

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

/* Frequency Measurement Interrupt Service Routine */

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

void inputcapture(void)

{

asm /* Reset input flag IC3F by writing 1 to it */

{

PSHA /* Save the contents of accumulator A */

LDAA #0x01 /* Load accumulator A with the mask data */

STAA 0x1023 /* Reset TOF flag by writing 1 to it */

PULA /* Retrieve the saved contents of accumulator A */

}

if (TFLG2BYTE>=0x80 && TIC3UP<=0x80)

{

timeroverflows++;

asm

{

PSHA /* Save the contents of accumulator A */

LDAA #0x80 /* Load accumulator A with the mask data */

STAA 0x1025 /* Reset IC3F flag by writing 1 to it */

PULA /* Retrieve the saved contents of accumulator A */

}

}

overflow=(unsigned int) timeroverflows*0x100;

/* Copy upper 8-bits of the TIC3 register into tic3upint */

tic3upint=(unsigned int)TIC3UP;

/* The overflow variable is the number of the upper 8-bit counts of

the TNCT counter that correspond to the amount of TNCT overflows

recorded in the timeroverflows variable */

period=(unsigned int) (overflow+tic3upint-time1);

/* The period variable is the total number of TCNT upper 8-bit

counts between this interrupt service routine and the

previous one.*/

time1=(unsigned int)TIC3UP; /* Save the endtime of this ISR */

timeroverflows=0; /* Reset the timeroverflows variable */

asm RTI; /* Return to main program */

}

Page 95: Software Development for Microprocessor Control Systems

Chapter 5 – The Microcontroller-Based Software

85

5.5.3 8-Bit Parallel Output The 8-Bit parallel output port is useful for interfacing to peripheral computer systems and can also be connected to a digital-to-analog converter for analog output. The Motorola MC6821 Peripheral Interface Adapter (PIA), which is part of the memory expansion board, are used for 8-bit parallel output since the two 8-bit data ports on the M68HC11 are occupied for interfacing with the external memory. The PIA is addressable at memory location 0xA100 to 0xA103. The 8-bit output register, called MEMPORTB, is defined as an unsigned 8-bit character at memory location 0xA102. The initportb function is listed in the code segment below. This function will initialize pins PB0-PB7 on the MC6821 PIA to act as output lines. /*****************************************************************/

/* Initialize Port B on the MC6821 on the Memory extension board */

/* to serve as an 8-bit output port at memory address 0xA102 */

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

void initportb(void)

{

(unsigned char *) 0xA102;

(unsigned char *) 0xA103;

*(unsigned char ) 0xA103=0x00; /*Clear CRB*/ *(unsigned char *) 0xA102=0xFF; /*Set bits in DDRB*/ *(unsigned char *) 0xA103=0x04; /*Set DDRB bit for output*/

} The variable named PIAPORTB can be defined as follow: #define PIAPORTB (*(volatile unsigned char*)(0xA102))

Assigning an 8-bit value to PIAPORTB can therefore access Port B on the MC6821 PIA.

5.5.4 PWM Output PWM waveforms are compatible with a wide range of devices and are often used for driving stepper or dc motors. The initpwm function will initialize the PWM interrupt service routine. The oc3interrupt function is the interrupt service routine, which will

Page 96: Software Development for Microprocessor Control Systems

Chapter 5 – The Microcontroller-Based Software

86

create the PWM waveform. pwmperiod and pwmtimeon are 16-bit unsigned integers which will determine the period and on-time of the PWM waveform. The value of pwmtimeon must be smaller than pwmperiod. The code segment below shows the initpwm and oc3interrupt functions. The global variables are declared as shown in the complete program listing in Appendix G. The hc11e9.h header file must also be included for register name definitions. /************************************************/

/* Routine to initialize the microcontroller to */

/* generate a PWM signal on OC3 (PA5) */

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

void initpwm(void)

{

/* Memory locations D9-DB is a 3 byte pseudo */

/* interrupt vector for TOC3(PA5) */

(char *) 0x00D9;

/* Place jump instruction (op code 7E) in 00D9 */

*(char *) 0x00D9 = 0x7E;

/* Place starting address of interrupt routine in DA&DB */

(int * ) 0x00DA;

*(int *) 0x00DA = (int)oc3interrupt;

OC1M.OC1M5=1; /* couple OC1 to OC3 */

TMSK1.OC3I=1; /* enable the OC3 interrupt */

OC1D.OC1D5=1; /* turn on OC3 when OC1 occurs */

TCTL1.OL3=1; /* toggle OC3 when OC3 occurs */

TOC1=TCNT+50000; /* initialize OC1 */

TOC3=TOC1+1; /* initialize OC3 */

}

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

/* OC3 Interrupt Service Routine. This routine will */

/* generate a PWM signal on OC3 (PA5) */

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

void oc3interrupt(void)

{

asm

{

PSHA /* Save the contents of accumulator A */

LDAA #0x20 /* Load accumulator A with the mask data */

STAA 0x1023 /* Reset OC3F flag by writing 1 to it */

Page 97: Software Development for Microprocessor Control Systems

Chapter 5 – The Microcontroller-Based Software

87

PULA /* Retrieve the saved contents of accumulator A */

}

toc1=TOC1+pwmperiod;

TOC1=toc1;

toc3=toc1+pwmtimeon;

TOC3=toc3;

asm RTI /* Return from Interrupt Service Routine */

}

The desired PWM on-time and PWM period can be changed in the main program loop by changing the pwmtimeon and pwmperiod variables. These variables are 16-bit integers. There is a possibility that the OC3 interrupt service routine can be called while changing the pwmtimeon or pwmperiod variable so that only one of the two bytes in the pwmtimeon or pwmperiod variable are updated. Consequently, the 16-bit variable will be corrupt while executing the 0C3 interrupt service routine. It is therefore important to disable the system interrupts while any changes are made to the pwmtimeon and pwmperiod variables.

Page 98: Software Development for Microprocessor Control Systems

Chapter 5 – The Microcontroller-Based Software

88

5.6 Clearing Timer Flags The method used for clearing a status flag bit in the timer flag registers was to load an accumulator with a mask that has a one in the bits, which correspond to the flags to be cleared. The content of the accumulator is then written to the appropriate flag registers. It was found that the bit-field feature of the Archimedes ANSI C compiler is not appropriate for clearing a status flag bit in the timer flag registers. For example: the following code line is not appropriate for clearing the IC3F flag:

TFLG1.bit0=1; /* Reset input flag IC3F by writing 1 to it */ The reason why this is the wrong way of clearing timer flags is that the Archimedes ANSI C compiler generates a bit set (BSET) instruction from the bit-field feature. The BSET instruction is a read-modify-write instruction that reads the operand, performs an OR operation with a mask having ones in the bits to be set, and writes the resulting value back to the operand address. Using the BSET instruction on the TFLG1 and TFLG2 registers will clear all flags that are set at the time the operand is read. The correct way of clearing the IC3F flag in C is illustrated in the following code segment. asm

{

PSHA /* Save the contents of accumulator A */

LDAA #0x01 /* Load accumulator A with the mask data */

STAA 0x1023 /* Reset IC3F by writing 1 to it */

PULA /* Retrieve the saved state of accumulator A */

} An alternative way of clearing timer flags is by using the BCLR instruction.

Page 99: Software Development for Microprocessor Control Systems

Chapter 5 – The Microcontroller-Based Software

89

5.7 Sample Frequency Regulation The clock (TCNT) counter is used by the software system to regulate the desired sample period. The user specifies the desired sample frequency in HC11Control. The clock counter (TCNT) overflow will be handled by the timeroverflows interrupt service routine in which the sampletimeroverflows variable will be increased by 1. The pseudo code below shows the framework of how the sample period is maintained in the software system. Start program

Initialize all the I/O ports and interrupt service routines.

Enable the system interrupts

Start infinite loop.

Save the current value of the timer-counter.

Calculate the required value of the clock counter and the

required number of timer overflows at which the next

sample period is due to start.

Read a sample from the input port.

Perform all the digital controller calculations.

Write the output sample to the output port.

While the number of timer overflows < required timer

overflows.

While the value of the clock counter < the required

value of the clock counter.

Calculate the actual sample duration.

Return to the start of the loop.

Page 100: Software Development for Microprocessor Control Systems

Chapter 5 – The Microcontroller-Based Software

90

The actual sampling period will by slightly longer than the desired sampling period due to the calculation of the actual sample period after the sample period has elapsed. The calculation of the actual sample period was found to be 48 time-steps long, which correspond to 24 microseconds on the M68HC11 with a bus speed of 2 MHz. The actual sample period will only be significantly larger than the desired sampling period when the desired sample period cannot be met due to insufficient processing speed of the main program loop. In such a case, the program will not enter a wait state at the two while loops, but will jump immediately to the next instruction, which is the calculation of the actual sample period. The timeroverflow interrupt service routine used for the sample frequency regulation is the same interrupt service routine used for measuring the input frequency on pin PA0.

Page 101: Software Development for Microprocessor Control Systems

Chapter 5 – The Microcontroller-Based Software

91

5.8 Compiling and Linking Source Code The Archimedes ANSI C 68HC11 Compiler and Linker was used to compile and link the C programs for the M68HC11 in this project. The Archimedes Compiler, Linker and Burner is used as shown in Figure 5.8 to create an executable S-record file form the source code files. This S-record file is ready to be downloaded to the M68HC11 microcontroller.

Start11.c Lustart.h Non_bank.sgm

Compiler

Start11.o

Program.c Hc11e9.h

Compiler

Program.o Program.prm Ansi.lib

Linker

Program.abs

Burner

Program.s19

Figure 5.8 The process for creating an executable S-record file from the C source code.

Page 102: Software Development for Microprocessor Control Systems

Chapter 5 – The Microcontroller-Based Software

92

The following files are needed for compiling and linking a C program. The contents of Start11.c, Lustart.h, Hc11e9.h and Non_bank.sgm are listed in Appendix G. Start11.c Default startup code for the 68HC11. Program.c Main control algorithm source code. Program.prm Linker parameter file. Lustart.h Header file which defines the startup description. Hc11e9.h Header file for the 68HC11 register definitions. Non_bank.sgm HC11 Small and medium memory model. Ansi.lib ANSI C libraries.

Page 103: Software Development for Microprocessor Control Systems

93

Chapter 6 Using the Windows-Based Software 6.1 Introduction The Windows-based software, which is called HC11Control, will provide the control engineer with a user-friendly interface for implementing a controller design on the M68HC11 microcontroller. This chapter will discuss HC11Control from a user’s point of view. No microcontroller programming knowledge is required by the user. HC11Control will automatically generate and download the control algorithm to a microcontroller from the specified control parameters. It is still the responsibility of the user to determine and specify the correct control parameters for a specific control application. HC11Control is started the same way as any other Windows-based application. Figure 6.1 shows the startup window of HC11Control.

Page 104: Software Development for Microprocessor Control Systems

Chapter 6 – Using the Windows-Based Software

94

The startup window provides a choice between four different program modules: • Test Input/Output. • Single-Input-Single-Output (SISO) Digital Controller. • Multi-Input-Multi-Output (MIMO) Digital Controller. • PID Controller. Each module will provide the user with a controller panel, which incorporates all the appropriate controls and edit boxes unique to that particular controller design.

Figure 6.1 The startup window of HC11Control.

Page 105: Software Development for Microprocessor Control Systems

Chapter 6 – Using the Windows-Based Software

95

6.2 The Test Input/Output Section The Test Input/Output section will generate a known output signal and will read an input signal to the microcontroller at the same time. This section can be used for data acquisition, testing the microcontroller interface to peripheral equipment and testing a system’s response to a known input signal.

Two input ports and two output ports are available for the user. The user can configure the output signal to the plant as illustrated in Figure 6.3. The corresponding input signal from the plant can then be monitored, recorded, plotted and saved.

Figure 6.2 The Test Input/Output Panel

Mic

roco

ntro

ller O

utpu

t

Time

Step delay time Step size

Output Upper Limit

Output Lower Limit

Figure 6.3 Output signal configuration for the Test Input/Output category of programs.

Page 106: Software Development for Microprocessor Control Systems

Chapter 6 – Using the Windows-Based Software

96

6.3 The SISO Digital Controller. The Single-Input-Single-Output (SISO) controller can be visualized as a fourth-order digital filter and a summing junction as illustrated in Figure 6.4. The input and output ports are saturated with the Upper Limit and Lower Limit values in HC11Control. The summing junction can be toggled between positive and negative, which adds more flexibility to the controller.

44

33

22

110

44

33

22

110

−−−−

−−−−

++++

++++

zazazazaazbzbzbzbb

Setpoint

+ ±

Controller

Output Input

Figure 6.4 Schematic layout of the SISO digital controller.

Fourth-Order Digital Filter Saturation Saturation

Figure 6.5 The Single-Input-Single-Output Digital Controller panel

Page 107: Software Development for Microprocessor Control Systems

Chapter 6 – Using the Windows-Based Software

97

6.4 The MIMO Digital Controller. Multi-Input-Multi-Output (MIMO) controller can be visualized as a second-order Double-Input-Double-Output digital filter and a summing junction as illustrated in Figure 6.6. The multivariable digital filter transfer function can be described as follow:

⎥⎦

⎤⎢⎣

⎥⎥⎥⎥

⎢⎢⎢⎢

=⎥⎦

⎤⎢⎣

2

1

22

22

21

21

12

12

11

11

2

1

ee

AB

AB

AB

AB

uu

where

22

11

22

110

1 −−

−−

++

++=

zazazbzbb

AB

xyxy

xyxyxy

xy

xy

Analog Setpoint

+

±

Controller

8-BitOutput

Analog Input

Multivariable Digital Filter

Saturation Saturation

Frequency Setpoint +

±

PWM Output

Frequency Input

Saturation Saturation ⎥⎥⎥⎥⎥

⎢⎢⎢⎢⎢

++

++

++

++++

++

++

++

−−

−−

−−

−−

−−

−−

−−

−−

2212

1211

22

110

2212

1211

2212

1211210

2122

1121

2122

1121120

2112

1111

2112

1111110

11

11

zazazbzbb

zazazbzbb

zazazbzbb

zazazbzbb

xyxyxy

Figure 6.6 Double-Input-Double-Output digital controller

1e

2e

1u

2u

(6.1)

(6.2)

Page 108: Software Development for Microprocessor Control Systems

Chapter 6 – Using the Windows-Based Software

98

The six parameter vectors 1P , 1Q , 1R , 2P , 2Q and 2R are defined as

4

413

312

211

1112111 1 −−−− ++++== zpzpzpzpAAP 4

413

312

211

110112111−−−− ++++== zqzqzqzqqABQ

441

331

221

1110112111

−−−− ++++== zrzrzrzrrBAR 4

423

322

221

1222212 1 −−−− ++++== zpzpzpzpAAP 4

423

322

221

120222212−−−− ++++== zqzqzqzqqABQ

442

332

222

1120222212

−−−− ++++== zrzrzrzrrBAR

It is the responsibility of the user to calculate the six parameter vectors 1P , 1Q , 1R ,

2P , 2Q and 2R from the transfer function shown in Equation 6.1. The vectors 1P , 1Q ,

1R , 2P , 2Q and 2R vectors can then be directly implemented on the double-input-

double-output controller as illustrated in Figure 6.7. A more complete description of the double-input-double-output system can be found in section 2.4.

(6.3)

Figure 6.7 Double-Input-Double-Output digital controller panel

Page 109: Software Development for Microprocessor Control Systems

Chapter 6 – Using the Windows-Based Software

99

6.5 The PID Controller The structure of the PID controller can be represented as illustrated in Figure 6.8. The input and output saturation are specified by the Upper Limit and Lower Limit values for the input and output respectively. The input summing junction can be toggled between positive and negative with the Feedback Mode option. The three PID parameters, PK , IK and DK can be any floating-point values, while

the sample period, T is determined by the Sample Frequency value.

Figure 6.8 Schematic layout of the digital PID controller.

Setpoint

+ ±

PID Controller

Output Input

Saturation Saturation

PK

⎟⎠⎞

⎜⎝⎛ −

zz

TKD 1

Proportional Term

⎟⎠⎞

⎜⎝⎛

−+

11

2 zzTK I

Integral Term

Derivative Term

+ +

+

Page 110: Software Development for Microprocessor Control Systems

Chapter 6 – Using the Windows-Based Software

100

Figure 6.9 The PID Controller panel.

Page 111: Software Development for Microprocessor Control Systems

Chapter 6 – Using the Windows-Based Software

101

6.6 Program Operation and Commands Each controller panel has a toolbar as shown in Figure 6.10. The buttons on the toolbar will be enabled and disabled automatically, depending on which operations and commands are possible to execute.

6.6.1 Downloading the Control Algorithm

The download-button on the HC11Control toolbar will activate the control algorithm download procedure. The user will be prompted to reset the microcontroller as shown in Figure 6.11. If an executing program is active on the microcontroller, an error message as shown in Figure 6.12 will prompt the user to stop the executing program before downloading the new control algorithm to the microcontroller. The user will be able to view the complete S-record code, which is to be downloaded to the microcontroller as shown in Figure 6.11. The second line in the code will contain the control parameter S-record line. This line will contain the microcontroller memory location information and the controller parameter values, which is to be downloaded to the microcontroller. The S-record format is discussed in Appendix B.

Download code to the microcontroller

Start the program on the microcontroller

Monitor the controller performance data

Disable serial communication with the microcontroller

Record the controller performance data

Stop recording Plot the recorded controller performance data

Save the recorded controller performance data

Figure 6.10 HC11Control toolbar

Page 112: Software Development for Microprocessor Control Systems

Chapter 6 – Using the Windows-Based Software

102

A reset action on the microcontroller will force the microcontroller unit to undertake a set of initial conditions and begin executing instructions from a predetermined starting address and will start downloading the control algorithm from the PC. After the downloading procedure is finished, the user will be prompted whether the downloading procedure was successful or not as shown in Figure 6.13.

Figure 6.11 Window to display the S-record code which is to be downloaded to the microcontroller

Figure 6.12 Window to prompt the user that the downloadingprocedure cannot continue due to a running program on the microcontroller

Page 113: Software Development for Microprocessor Control Systems

Chapter 6 – Using the Windows-Based Software

103

A reset signal is detected from the microcontroller

Download procedure finished

Download successful Download error

Figure 6.13 The control algorithm download procedure

Page 114: Software Development for Microprocessor Control Systems

Chapter 6 – Using the Windows-Based Software

104

6.6.2 Start Executing the Control Algorithm After the control algorithm has been downloaded successfully to the microcontroller, the run button on the HC11Control toolbar will be enabled which will allow the user start executing the control algorithm. If an executing program is active on the microcontroller, an error message as shown in Figure 6.14 will prompt the user to stop the executing program before restarting the control algorithm. The user will be prompted to reset the microcontroller as shown in Figure 6.15. A reset action on the microcontroller will force the microcontroller to undertake a set of initial conditions. HC11Control will react on a reset signal and will send a run command to the microcontroller unit, which will start executing the control algorithm.

Figure 6.14 Window to prompt the user that a program on the microcontroller is currently being executed and that the new program cannot be started.

Figure 6.15 Window to prompt the user to reset the microcontroller before starting to execute the new control algorithm.

Page 115: Software Development for Microprocessor Control Systems

Chapter 6 – Using the Windows-Based Software

105

6.6.3 Recording Controller Performance Data After the control algorithm has been started on the microcontroller, HC11Control will display the incoming data from the microcontroller in real-time on the controller panel. The record button on the HC11Control toolbar will also be enabled which will allow the user to record the controller performance data. The maximum allowed recording time depends on the sample frequency of the controller performance data. The maximum number of samples that can be recorded is 65536. The maximum allowed recording time in seconds can be calculated as follow:

FrequencySampleTimeRecordingMaximum 65536

=

If data is recorded at a sample rate of 50Hz, the maximum allowed recording time will be 1310 seconds, which is approximately 22 minutes. If the Record data when program starts option under the Options menu is checked, the data recording procedure will start immediately after the control algorithm has been started. The stop button on the HC11Control toolbar, which allows the user to stop the recording process, will be enabled while controller data is being recorded.

Page 116: Software Development for Microprocessor Control Systems

Chapter 6 – Using the Windows-Based Software

106

6.6.4 Plotting and Saving the Recorded Data The plot and save buttons on the HC11Control toolbar will be enabled after the recording process has been stopped. These buttons will allow the user to plot and save the recorded controller performance data. Figure 6.16 shows the plotting windows on which the recorded controller data is plotted. If the Plot Lines option under the Options menu is checked, the data-points on the plot will be linked by lines as shown in Figure 6.16. The value-boxes at the left side and at the bottom of each plot display the cursor position on the plot. The plot can be drag-zoomed by using the alt key and the mouse button simultaneously or can be zoomed the conventional way by using the on-form

Figure 6.16 HC11Control plotting windows

Page 117: Software Development for Microprocessor Control Systems

Chapter 6 – Using the Windows-Based Software

107

buttons. The ctrl key and the mouse button can be used to select a box in which the plot will be zoomed. The plot can be dragged or scrolled by using the on-form buttons or by dragging the mouse over the plot while keeping the mouse button down. The save button on the HC11Control toolbar will allow the user to save the recorded controller performance data in standard ASCII format. Each parameter data series will be saved in a separate column. Any standard data analysis or spreadsheet program will be able to retrieve the saved data.

Page 118: Software Development for Microprocessor Control Systems

Chapter 6 – Using the Windows-Based Software

108

Page 119: Software Development for Microprocessor Control Systems

109

Chapter 7 Application Example: DC Motor Speed Control 7.1 Introduction Servomotors form an important part of many modern control systems where lateral or rotational motion of a system is to be controlled. Various techniques for DC motor speed control have been developed. One of the most common methods for measuring rotational motion is by measuring the time duration for each complete revolution. The power supplied to the DC motor can be varied with a variable analog input signal or by using a Pulse Width Modulation (PWM) supply as demonstrated in this Chapter. The functionality of the Windows-based software system was demonstrated by modeling and controlling the speed of a permanent magnet DC motor. Some images of this application example can be found in Appendix E

Page 120: Software Development for Microprocessor Control Systems

Chapter 7 – Application Example: DC Motor Speed Control

110

7.2 The DC Motor / Microcontroller Interface

7.2.1 DC Motor Power Supply Regulation The Pulse Width Modulation (PWM) output port was used to vary the supply current to the DC motor. Figure 7.1 shows the general concept of a Darlington circuit. This circuit can be used for controlling currents up to 2A with a PWM signal. The diode protects the transistors against large back voltage (back emf) created by the motor when turned on. An alternative way of driving the DC motor is by using the 8-bit parallel output port on the microcontroller in conjunction with a Digital to Analog (D/A) converter. Most D/A converters are however not appropriate for relatively high-current applications such as DC motor speed control.

PWM Signal from microcontroller

1k2

68Ω

12 V

2N3904TIP31

Permanent Magnet DC Motor

Figure 7.1 DC Motor speed control with the PWM Darlington Circuit

Page 121: Software Development for Microprocessor Control Systems

Chapter 7 – Application Example: DC Motor Speed Control

111

7.2.2 Speed Feedback The motor rotational speed was measured with an optical interrupt system as shown in Figure 7.2 and Figure 7.3. The optical interrupt circuit consists of an ultraviolet LED and a phototransistor. An interrupt service routine on the microcontroller will be activated on every leading edge in the pulse signal. The period between the leading edges of the pulse signal, which represents the DC motor speed are then calculated in the microcontroller program. The effect of switch bounce, which can provide measurement errors, can be neglected for this application [14].

LED Phototransistor DC Motor

Aluminum disk

Figure 7.3 The optical speed sensor

5 k 6 10 k

1 k 2

5 V

Pulse Output

Figure 7.2 The optical interrupt circuit

Phototransistor

LED

Page 122: Software Development for Microprocessor Control Systems

Chapter 7 – Application Example: DC Motor Speed Control

112

7.3 System Modeling Many physical processes can be modeled as a first-order system. Such a system has a balance between damping forces, restoring forces and externally applied forces [15]. It is assumed for this example that the DC motor can also be modeled as a first-order system. The first step into designing a speed controller for the DC motor is to establish the first-order parameters for the DC motor. This is done by measuring the DC motor response to a completely defined and known step input signal. It is not necessary to perform a frequency response test, since the order of the DC motor model is already known. It is necessary though to perform a frequency response test on a more complex system in order to find its transfer function. A step input will yield useful information about the DC motor time-constant and rise time. The linearity between the PWM input and the speed output of the DC motor was tested by using the Test Input/Output section in the HC11Control program. The Test Input/Output section is useful for testing the interface between the controller and plant

Figure 7.4 HC11Control setup for generating a PWM ramp signal on PA5 and to measure a frequency input on PA0

Page 123: Software Development for Microprocessor Control Systems

Chapter 7 – Application Example: DC Motor Speed Control

113

and to establish the steady-state input/output characteristics of the plant. The Test Input/Output section can also be used to produce a known step input to the plant and to measure the corresponding plant response to the step input. At first, HC11Control was set up as shown in Figure 7.4 to generate a linear output signal (also known as a ramp signal) to the DC motor. The corresponding rotational speed of the DC motor was recorded in HC11Control and saved to disk. Figure 7.5 shows the recorded result. It can be seen from Figure 7.5 that the relation between the motor speed and the PWM input is not linear. This non-linear characteristic between the motor speed and the PWM input is to be expected mainly because of higher motor friction at high speed. It is important to note that the PWM input is proportional to the power supplied to the DC motor. The relationship between the PWM input and the motor torque at a constant motor speed can be expected to be linear. The open-loop transfer function for a step input between 8-bit PWM values of 40 and 90 was obtained by setting the HC11Control program as in Figure 7.6. The program setup shown in Figure 7.6 will generate a PWM step input between 8-bit values of 40 and 90 at a 5-second interval. This means that the pulse width will toggle between 15.6% and 35.2% every 5 seconds. (A 100% pulse width, which means that the PWM signal will remain high, correspond to a PWM value of 256.)

Figure 7.5 Steady state Input/Output characteristics of the DC motor when subjected to a PWM input. The percentage pulse width is the PWM value÷2.56.

Motor Speed vs PWM Input

05

101520253035404550

30 40 50 60 70 80 90 100 110 120 130DC motor PWM input (8-bit unsigned value)

Mot

or S

peed

(Hz)

Page 124: Software Development for Microprocessor Control Systems

Chapter 7 – Application Example: DC Motor Speed Control

114

Figure 7.7 shows the recorded results obtained from HC11Control. This result represents the open-loop step response of the DC motor.

DC Motor Step Response with 40 to 90 PWM input

7

12

17

22

27

32

37

0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1 1.1 1.2Time (seconds)

Mot

or S

peed

(Hz)

63.2 % Line

Time Constant

Figure 7.7 DC Motor step response for a PWM step between 8-bit values of 40 and 90.

Figure 7.6 HC11Control setup for generating a PWM step between 8-bit values of 40 and 90 and to measure a frequency input on PA0

Page 125: Software Development for Microprocessor Control Systems

Chapter 7 – Application Example: DC Motor Speed Control

115

The transfer function of the DC motor speed can be modeled as a first-order transfer function. Thus, the transfer function of the DC motor can be written as

( )bs

KbsG+

=

where K is the DC motor steady-state gain constant and b is the inverse of the motor time-constant. The value of K can be obtained by calculating the average gradient of the PWM input versus the motor speed in Figure 7.7. The average gradient between a PWM input of 40 and 90 were calculated as follow

5604090634 .

InputPWMSpeedMotorK =

−−

==ΔΔ

The DC motor time-constant is the time required for the motor speed to reach 63.2% of its final value. The motor time-constant is calculated as shown in Figure 7.7. The final value is 35Hz and the starting value is 6Hz. 63.2% of this range is 24Hz. The time to reach 24 Hz is 0.2 seconds. The small delay of 0.04 seconds is not integrated into the DC motor model, but is kept separately as shown in Figure 7.8. The b parameter is then calculated.

520

11===

.b

(7.1)

(7.2)

(7.3)

output.mat

To File

Step Input Saturation1

Quantizer1

+ +

-28 Offset

Graph Delay

2.8 s+5

DC Motor

Saturation2

Figure 7.8 Simulink model for the DC motor open-loop step response

Page 126: Software Development for Microprocessor Control Systems

Chapter 7 – Application Example: DC Motor Speed Control

116

The DC motor transfer function can therefore be written as

( )5

825

5560+

=+×

=+

=s

.s.

bsKbsG

This transfer function was verified with a Simulink model shown in Figure 7.8. The comparison between Simulink model and the actual motor step response is shown in Figure 7.9.

(7.4)

DC Motor Step Response with 40 to 90 PWM input

5

10

15

20

25

30

35

40

0 0.2 0.4 0.6 0.8 1 1.2Time (seconds)

Mot

or S

peed

(Hz)

Actual MotorSimulink model

Figure 7.9 DC Motor step response for a PWM step between 8-bit values of 40 and 90.

Page 127: Software Development for Microprocessor Control Systems

Chapter 7 – Application Example: DC Motor Speed Control

117

7.4 Controller Implementation The DC motor speed was controlled with a PI (Proportional + Integral) controller and the controller output was limited to the region in which the open-loop response was calculated in the section 7.3. The differential term was set to zero mainly because of the amplifying effect it has on signal noise. The proportional and integral constants were obtained by using the Ziegler-Nichols tuning of PID controllers. A detailed description on the Ziegler-Nichols tuning of PID controllers is given in Appendix C. The Ziegler-Nichols method yielded proportional and integral gains of 4 and 16 respectively. It was found that the control action was slightly rugged with the proportional and integral gains of 4 and 16 respectively. The proportional term was reduced to 2 for a smoother control action. The PI controller can be implemented by any second-order, direct digital filter structure as shown in Equation 2.15. The PID controller section in HC11Control simply transforms the pK , IK and DK terms into the a and b vectors of the

difference equation as follow.

01

1

22

2

2

1

0

2

1

0

=−=

=

=

−+−=

++=

aaa

TKb

TKTKKb

TKTKKb

D

DIP

DIP

The PID controller can therefore be implemented by specifying the a and b vectors in the Digital Controller section or by specifying the pK , IK and DK terms in the PID

Controller section of HC11Control. The PWM output value, which represents the pulse width of the PWM signal, is limited between 8-bit values of 40 and 90. The DC motor control system was simulated in Simulink as illustrated in Figure 7.10 and implemented in HC11Control as shown in Figure 7.11.

(7.5)

Page 128: Software Development for Microprocessor Control Systems

Chapter 7 – Application Example: DC Motor Speed Control

118

Figure 7.11 HC11Control setup for implementing a PID controller on a DC Motor.

+ -

2.16-1.84z -1

1-z -1

Digital Controller Quantizer1

+ +

Saturation2 Delay

2.8 s+5

DC Motor

-28 Offset

Step Input Input Graph Output Graph

Saturation3 Quantizer2 Zero-Order Hold

Saturation1

Figure 7.10 Simulink model for PI speed control of a DC motor.

Page 129: Software Development for Microprocessor Control Systems

Chapter 7 – Application Example: DC Motor Speed Control

119

The control algorithm was downloaded from the PC to the microcontroller and the control program was started. The record data when control program starts option in the Options menu must be checked to ensure that incoming data from the microcontroller will be recorded by HC11Control as soon as the control algorithm starts. Figure 7.12 and Figure 7.13 compares the control system step response between the Simulink model and the data logged from HC11Control. The overall comparison is good. The only area of significant difference between the Simulink model and the real system is in the first 0.1 seconds. This difference may be a result of different initial conditions between the two systems or due to the starting friction of the DC motor, which is not modeled in the Simulink model. The DC motor speed in the Simulink model is also approximated as a linear model, which is slightly different from the real DC motor. The constant difference in controller output as shown in Figure 7.13 is a result of the linear approximation of the DC motor speed in the Simulink model. The graph shown in Figure 7.5 shows the decrease in the motor-speed gradient as the PWM output increases. The result shown in Figure 7.13 indicates that the steady state gain of the real DC motor is still higher at an 8-bit PWM output value of around 70 than the linear approximation in the Simulink model.

Figure 7.12 DC motor speed step response when controlled with a PID controller.

DC Motor speed step response

5

10

15

20

25

30

35

0 0.2 0.4 0.6 0.8 1 1.2 1.4Time

Mot

or S

peed

(Hz)

Actual Motor

Simulink model

Page 130: Software Development for Microprocessor Control Systems

Chapter 7 – Application Example: DC Motor Speed Control

120

Figure 7.13 PID Controller output to the DC motor

PID Controller output to the DC motor

40

50

60

70

80

90

0 0.2 0.4 0.6 0.8 1 1.2 1.4Time

Con

trolle

r Out

put

Actual ControllerOutputSimulink model

Page 131: Software Development for Microprocessor Control Systems

121

Chapter 8 Application Example: Digital Filtering 8.1 Introduction Low-pass filtering is often used in low-frequency measurement systems where high frequency noise in the measurement signal has to be filtered out before the measurement signal can be processed by a computer system. PID controllers in particular require extensive noise filtering mainly because of the noise- amplifying characteristics of the differential term in the PID controller. This example will demonstrate the application of a fourth-order low-pass digital Chebyshev type I filter with a cutoff frequency of 5Hz. The Chebyshev type I filter is equiripple in the passband and monotonic in the stopband and provides a relative steep rolloff characteristic for the specific filter order [16]. The cutoff frequency is the frequency at which the filter’s magnitude response is equal to –3dB [3].

Page 132: Software Development for Microprocessor Control Systems

Chapter 8 – Application Example: Digital Filtering

122

Figure 8.1 illustrates a typical measurement system that is used by numerous control applications. Most processes and their sensors are analog in nature. The sensor usually produces a relatively low output voltage and picks up high-frequency electrical noise from nearby electrical lines and equipment. The low voltage output characteristics of the sensor will normally result in low signal/noise (S/N) ratios. The low-pass filter will act as a signal conditioner by eliminating the unwanted noise in the measured signal.

Plant

Sensor Noise

Amplifier

Low-pass Filter

xt

t mV

V

V

t

t

Computer System

Figure 8.1 A measuring system composed of several system elements including a low-pass filter. The signal is shown as it leaves each element.

Page 133: Software Development for Microprocessor Control Systems

Chapter 8 – Application Example: Digital Filtering

123

8.2 Digital Filter Implementation The digital controller program on the microcontroller is structured as shown in Figure 8.2. The conventional control program has a built-in negative summing junction and a setpoint added to the input for use in negative-feedback control applications. HC11Control allow the user to select between a positive or negative summing junction, which add more flexibility to the microcontroller program. The cheby1 function in the Matlab Signal and Systems Toolbox was used to find the a and b vectors for the Chebyshev type I digital filter. For data sampled at 50Hz, with 3 dB of ripple in the passband, and a cutoff frequency of 5Hz, the a and b vectors of the fourth-order low-pass Chebyshev type I digital filter are calculated in Matlab as follow: order=4; passband_ripple=3; cutoff_frequency=5; sample_frequency=50; pi=3.141592654; [b,a] = cheby1(order,passband_ripple, (2*pi*cutoff_frequency)/(pi*sample_frequency));

44

33

22

110

44

33

22

110

−−−−

−−−−

++++

++++

zazazazaazbzbzbzbb

Setpoint

+ ±

Microcontroller

Output Input

Figure 8.2 Schematic layout of the microcontroller-based digital filter.

Fourth-Order Digital Filter

Serial Communication Interface

Serial data to PC

Saturation Saturation

Page 134: Software Development for Microprocessor Control Systems

Chapter 8 – Application Example: Digital Filtering

124

The Matlab cheby1 function yields the following a and b vectors for the fourth-order low-pass Chebyshev type I digital filter for data sampled at 50Hz, with 3 dB of ripple in the passband, and a cutoff frequency of 5Hz.

10 =a 001100 .b =

269231 .a −= 004201 .b =

340342 .a = 006302 .b =

741923 .a −= 004203 .b =

694604 .a = 001104 .b = The frequency response of this filter is shown in Figure 8.3. Note that the unit of the frequency axis is radians per second and not Hz.

10 0 10 1 10 2 10 3 -100

-50

0

Frequency (rad/sec)

Gai

n dB

10 0 10 1 10 2 10 3

-180

-360

-540

0

Frequency (rad/sec)

Pha

se d

eg

Figure 8.3 Frequency response of a fourth-order low-pass Chebyshev type I digital filter

Page 135: Software Development for Microprocessor Control Systems

Chapter 8 – Application Example: Digital Filtering

125

The a and b vectors for the fourth-order low-pass Chebyshev type I digital filter are entered into the HC11Control program as shown in Figure 8.4. The low-pass digital filter was tested by connecting the microcontroller analog input to a function generator. The function generator was configured to produce a frequency sweep between 0.01 and 10 Hz. Figure 8.5 shows the results obtained from this test. This digital filter performed as expected and corresponds well with the bode diagram shown in Figure 8.3. This filter was also tested with a very noisy 2Hz sine wave. A Gaussian noise generator was used to add noise to the sine wave. Figure 8.6 illustrates the noise-filtering abilities of this digital filter.

Figure 8.4 HC11Control setup for implementing the 5Hz cut-off Chebyshev type I digital filter.

Page 136: Software Development for Microprocessor Control Systems

Chapter 8 – Application Example: Digital Filtering

126

I/O Performance: Low-pass Chebyshev type I digital filter

20

40

60

80

100

120

140

160

180

0 0.25 0.5 0.75 1 1.25 1.5

Time (seconds)

8-B

it va

lue Filter Input

Filter Output

Figure 8.6 Noise-filtering with the low-pass Chebyshev type I digital filter

Figure 8.5 Frequency response results obtained from HC11Control for the 5Hz cutoff frequency Chebyshev type I digital filter

Frequency Response of the 5Hz Cutoff Chebyshev type I Digital Filter

50

70

90

110

130

0 1 2 3 4 5 6 7Frequency (Hz)

Dig

ital F

ilter

Out

put (

8-bi

t val

ue)

Page 137: Software Development for Microprocessor Control Systems

127

Chapter 9 Application Example: Multivariable Temperature Control 9.1 Introduction This example will demonstrate temperature control of an open system in which the system mass flow rate and the heat input rate can be regulated by the microcontroller. The Multi-Input-Multi-Output section in HC11Control will be used for implementing a multivariable controller on the system. The controller will be configured read a single temperature input and to generate two independent outputs. The two controller outputs will regulate a heating coil and a DC fan respectively. The image of this application example can be found in Appendix E

Page 138: Software Development for Microprocessor Control Systems

Chapter 9 – Application Example: Multivariable Temperature Control

128

Two system modeling approaches will be discussed in this example:

i. Analytical System modeling ii. Experimental System Modeling.

The analytical modeling approach will be based on the principle of conservation of energy, which is known as the first law of thermodynamics. A state-space model will be derived that will contain all the different system parameters such as the system volume, airflow rate, heat input rate, thermal conductivity etc. Accurate system parameters are sometimes difficult to obtain. Experimental system modeling is often the most effective way of obtaining an accurate system model. The interface between the microcontroller and the plant will be discussed before any experimental modeling will be discussed. Once the interface is established, the system‘s transient response data can be obtained from step inputs. The system’s transient response data is relatively easy to obtain and is sufficient for modeling first-order systems experimentally. A more complex multivariable system can be identified by using offline least squares techniques from the system input and output data. The least squares technique will only yield a useful solution if either a white noise random sequence or a pseudo random binary sequence (PRBS) is applied to the plant input [17]. The system will be modeled in Simulink as a SISO system with a heat input and constant airflow. The PI controller parameters for the SISO heating process will be verified with the Simulink model. The same PI controller parameters will then be implemented on the fan, which will be used for the cooling process. Consequently, the system will be controlled by two independent PI algorithms: One PI algorithm for heating and one PI algorithm for cooling.

Page 139: Software Development for Microprocessor Control Systems

Chapter 9 – Application Example: Multivariable Temperature Control

129

9.2 Analytical System Modeling Figure 9.1 illustrates the open system to be controlled. The system boundary is relatively thin and heat loss by means of conduction will be taken into account. A heating coil will be used for the system heat input while a fan will be used to regulate the flow rate of the air. The system described in Figure 9.1 can be modeled analytically by using the first law

of thermodynamics. The first law is based on the principle of conservation of energy,

which is a basic law of physics [18].

It is assumed that the system contains a fixed mass of air, Vρ and that the gas constant

pc is constant for all the temperatures considered. It is also assumed that the energy

effect of the difference in the input and output heights are negligible. Thus the first law of thermodynamics give:

RateonAccumulatiHeatRateOutputHeatRateInputHeat =−

[ ] [ ]dt

dhVhmQhmQ eecii ρ=+−+ &&&& (9.1)

m&,hi

iQ&,he m&

cQ&

Figure 9.1 Application of the energy conservation principle to an open system

( )WLossHeatQc =&

( )WInputHeatQi =&

( )skgateRlowFassMm =&

( )kgJEnthalpyOutputSpecifiche =

( )kgJEnthalpyInputSpecifichi =

Page 140: Software Development for Microprocessor Control Systems

Chapter 9 – Application Example: Multivariable Temperature Control

130

Given that pc is constant for all the temperatures considered, we can write

Tch p=

where

K)kgJ(heatspecificpressureonstantCc p =

T = Temperature (K) The heat loss across the walls occurs by means of conduction and can be defined as

kALTT

Q iec

−=&

where

L = Wall Thickness (m)

k = Thermal Conductivity (W/m K)

A = Wall Surface Area ( 2m )

( )KetemperaturairInletTi =

( )KetemperaturairletOutTe =

Substituting Equations 9.2 and 9.3 into Equation 9.1 gives

[ ]dt

dTVcTcm

kALTT

TcmQ epep

ieipi ρ=⎥

⎤⎢⎣

⎡+

−−+ &&&

Rearranging Equation 9.4 gives the system state-space representation in the form

BuAxx +=& .

⎟⎠

⎞⎜⎝

⎛ ++⎥⎥⎦

⎢⎢⎣

⎡+

⎥⎥⎥⎥

⎢⎢⎢⎢

⎡ −−=

LkAT

TcmQVc

TVc

LkAcm

dtdT i

ipip

ep

pe &&

&

ρρ1

(9.2)

(9.3)

(9.4)

(9.5)

Page 141: Software Development for Microprocessor Control Systems

Chapter 9 – Application Example: Multivariable Temperature Control

131

9.3 The Process / Microcontroller Interface

9.3.1 Temperature Measurement A LM35 Precision Centigrade Temperature Sensor was used in conjunction with a LM324 Operational Amplifier as illustrated in Figure 9.2. The LM35 temperature sensor output voltage is linearly proportional to the Celsius temperature. The temperature sensor output is linear at 10mV/°C. The operational amplifier section will amplify the sensor output signal to 110mV/°C. The Voltage Reference Low (VRL) pin is connected to ground and the Voltage Reference High (VRH) pin is connected to the supply voltage, which is 5V. The A/D converter on the M68HC11 microcontroller will then convert analog signals in the range of 0-5V. A temperature range of 45°C can therefore be measured by the microcontroller. The input resolution can be calculated as follow

bitCCResolution /178.02

458

°=°

=

The 0-5V output form the temperature measurement circuit was connected directly to the M68HC11 analog input (pin PE5). The A/D input can be permanently damaged by applying a negative voltage to the input pin, especially if the negative voltage is from a low impedance source [19]. The 1K resistor is included to protect the A/D converter input against excessive input currents.

5V

LM35 LM324

+-

10K 5V

100K

0-5V

Figure 9.2 The Temperature Measurement Circuit

1K

(9.6)

Page 142: Software Development for Microprocessor Control Systems

Chapter 9 – Application Example: Multivariable Temperature Control

132

9.3.2 Fan Speed Regulation The fan speed was regulated with a 0-9V analog signal. The 8-bit parallel output was used in conjunction with a Digital-to-Analog (D/A) converter to generate a variable analog output to the fan. The DAC0808 D/A converter was used in conjunction with an ICL7660 voltage inverter and a L272 Power Operational Amplifier. Figure 9.3 shows the D/A converter system which was used to regulate the fan speed.

10μF 5 V

9 V

+

10μF +

0.1μF

ICL7

660

DA

C08

08

5 k 6

5 k 6

LSB

MSB

Dig

ital I

nput

s

5 k 6

-

+

5 k

9 V

Analog Output (To Fan)

1

8

7

2

4

2

1

3

4

5

6

7

8

15

16

14

13

12

11

10

9

1

2

3

4 5

6

7

8

L272

5 k

Figure 9.3 8-Bit Digital-to-Analog (D/A) converter for fan speed control

Page 143: Software Development for Microprocessor Control Systems

Chapter 9 – Application Example: Multivariable Temperature Control

133

9.3.3 Heater Power Regulation The power supply to the heating coil was regulated with a PWM signal as illustrated in Figure 9.4. This circuit design, which is known as a Darlington circuit, can be used for controlling currents up to 2A with a PWM signal.

PWM Signal from microcontroller 1k2

68Ω

12 V

2N3904TIP31

Figure 9.4 Heating coil power supply regulation with the PWM Darlington Circuit

Heating Coil

Page 144: Software Development for Microprocessor Control Systems

Chapter 9 – Application Example: Multivariable Temperature Control

134

9.4 Experimental System Modeling The system model which was derived in section 9.2 can be used to develop a multivariable controller design that will meet the steady-state and transient specifications for a command input. Accurate system parameter values are however difficult to obtain. An experimental technique will be more appropriate to obtain the system transfer function. The physical system was set up as illustrated in Figure 9.5.

The heating coil and the fan were modeled as two separate systems. It is assumed for this application that • When the system temperature is lower than the desired system temperature, the

fan will be running at minimum speed while the heating coil will be controlled by the microcontroller.

• When the system temperature is higher than the desired system temperature,

power supply to the heating coil will be disabled while the fan will be controlled by the microcontroller.

Air In Air Out

Fan

Heating Coil Temperature Sensor

Figure 9.5 Schematic representation of the temperature system setup

Page 145: Software Development for Microprocessor Control Systems

Chapter 9 – Application Example: Multivariable Temperature Control

135

The heater transfer function was determined by subjecting the heating element to a step input while the fan speed was kept at its minimum speed. HC11Control was configured as shown in Figure 9.6. The result obtained from a step in the heating power is shown in Figure 9.7. The y-axis in Figure 9.7 shows the 8-bit analog input. The corresponding temperature in °C is the 8-bit value times 0.178 as shown in Equation 9.6

Figure 9.6 HC11Control setup for generating a PWM step on the heating coil

Figure 9.7 Open-loop temperature step response for the open system

Time Constant

63.2% Line

Page 146: Software Development for Microprocessor Control Systems

Chapter 9 – Application Example: Multivariable Temperature Control

136

The first-order transfer function of the heating process can be written as

( )bs

KbsG+

=

where K is the steady-state gain constant and b is the inverse of the process time-constant.

The steady-state gain for the heating process can be calculated as follow:

SizeStepPWMeTemperaturInitialeTemperaturFinal

K−

=

( ) 05460150

1131591780 ..=

−×=

The time-constant for the heating process can be determined from Figure 9.7 as approximately 111 seconds. The b parameter can be calculated as follow.

009010111

1 .ConstantTimeProcess

1b ===

The heating process transfer function can therefore be expressed as

( )009010

000490009010

00901005460.s

..s

..bs

KbsG+

=+

×=

+=

(9.7)

(9.8)

(9.10)

(9.11)

0.00049 s+0.00901

Open System

Saturation1

20.5

Ambient Temperature

Delay

+ +

Sum Graph

Quantizer1

Step Input

output.mat

To File

Figure 9.8 Simulink model for the heating process open-loop step response

Page 147: Software Development for Microprocessor Control Systems

Chapter 9 – Application Example: Multivariable Temperature Control

137

The transfer function for the heating process was verified with the Simulink model as shown in Figure 9.8. The comparison between the Simulink model and the actual heating process is shown in Figure 9.9.

Open Loop Step Response

2021222324252627282930

0 50 100 150 200 250 300Time (Seconds)

Tem

pera

ture

(°C

)

Simulink ModelActual System

Figure 9.9 Open loop step response for the heating process

Page 148: Software Development for Microprocessor Control Systems

Chapter 9 – Application Example: Multivariable Temperature Control

138

9.5 Controller Implementation

9.5.1 Temperature Control With Constant Airflow The temperature of the open system was controlled by two independent PI algorithms: One PI algorithm for heating and one PI algorithm for cooling. The fan speed and consequently the airflow were kept constant at first while the heating process was controlled by a PI control algorithm. The proportional and integral constants were obtained from the system’s stability boundary parameters by using the Ziegler-Nichols tuning of PID controllers. The Ziegler-Nichols tuning of PID controllers is discussed in Appendix C and yields proportional and integral parameters of 2 and 0.08 respectively. The heating process control scheme was simulated in Simulink as shown in Figure 9.10 and implemented in HC11Control as shown in 9.11. The fan speed was kept constant at its minimum value, which correspond to an 8-bit output of 100. The proportional, integral and derivative parameters ( PK , IK and DK ) for the PID

controller are converted to the a and b vectors for the direct digital filter structure as shown in Equation 9.12. The convention for the subscripts of the a and b vectors are discussed in section 6.4. A sample rate of 20Hz was chosen, which corresponds to a sample period of 0.05 seconds.

0

11

00500

99812

05008022

2

00222

05008022

212

211

210

212

211

210

=

−=

=

===

−=×

+−=−+−=

+=++=

a

aa

.TK

b

...TKTK

Kb

...T

KTKKb

D

DIP

DIP

(9.12)

Page 149: Software Development for Microprocessor Control Systems

Chapter 9 – Application Example: Multivariable Temperature Control

139

Once the values of the a and b vectors are known, the multivariable P,Q and R vectors can be calculated as described in section 6.4. Equation 6.3 yields the following P, Q and R vectors for a PI control action on the heating process.

11 =P

01 =Q

01 =R 1

2 1 −−= zP 1

2 99810022 −−= z..Q

02 =R

Figure 9.10 HC11Control setup for implementing a PI control scheme on the heating coil and keeping the fan speed constant.

(9.13)

Page 150: Software Development for Microprocessor Control Systems

Chapter 9 – Application Example: Multivariable Temperature Control

140

Figure 9.11 shows the closed-loop system temperature step response. The y-axis shows the 8-bit analog input form the temperature sensor. The corresponding temperature in °C is the 8-bit value times 0.178 as shown in Equation 9.6. Figure 9.12 shows the control effort, which corresponds to the PWM current supplied to the heating coil. The y-axis in Figure 9.12 shows the 8-bit PWM value, which range from 0% to 100% heating power.

The results shown in Figure 9.11 and Figure 9.12 was verified with the Simulink model shown in Figure 9.13. Figure 9.14 and 9.15 shows the comparison between the results from the Simulink model and the experiment. The comparison between the experimental data and the Simulink model is good. This result is a good indication that the microcontroller-based controller performs as expected.

Figure 9.11 Closed-loop temperature step response for a PI control action

Figure 9.12 Closed-loop control effort step response for a PI control action

Page 151: Software Development for Microprocessor Control Systems

Chapter 9 – Application Example: Multivariable Temperature Control

141

Quantizer1 0.00052

s+0.00901

Open System

Delay

+ +

Sum

19.4

Ambient Temperature

2.002-1.998z-1

1-z -1

Digital Filter

Step Input

Saturation3 Quantizer2 Zero-Order Hold

Saturation1

Control Effort

Temperature Out

output.mat

To File

5.618

Gain

+ -

Sum1

Figure 9.13 Simulink model for PI control of the heating process

Temperature step response for a closed-loop PI control action

18

19

20

21

22

23

24

25

26

27

28

0 100 200 300 400 500 600 700 800Time (Seconds)

Tem

pera

ture

(°C

)

Simulink ModelExperiment

Figure 9.14 Temperature step response comparison between the Simulink model and the experiment for a PI control action on the heating process .

Page 152: Software Development for Microprocessor Control Systems

Chapter 9 – Application Example: Multivariable Temperature Control

142

9.5.2 Multivariable Controller Implementation

The fan, which regulates the system airflow rate, was kept at constant speed for the control purposes in section 9.5.1. In this section, an additional PI control action will be applied to the fan for regulating the cooling process. The same proportional and integral constants were used for the cooling process as for the heating process, which was described in section 9.5.1. The proportional sign and the integral sign for the cooling process has to be inverted to respond on any positive temperature errors, which indicates that the system’s temperature is higher than the desired system temperature. The PI control parameters for the multivariable control application are as follow: Heating Process: 2=PK , 080.K I =

Cooling Process: 2−=PK , 080.K I −=

Control effort step response for a closed-loop PI control action

0

50

100

150

200

0 100 200 300 400 500 600 700 800Time (seconds)

8-B

it P

WM

out

put v

alue

Simulink ModelExperiment

Figure 9.15 Control effort step response comparison between the Simulink model and the experiment for a PI control action on the heating process .

Page 153: Software Development for Microprocessor Control Systems

Chapter 9 – Application Example: Multivariable Temperature Control

143

The a and b vectors for the heating process will remain unchanged and will be the same as in section 9.5.1. The a vector for the cooling process will be the same as the a vector for the heating process while the b vector of the cooling process will be the negative of the b vector for the heating process. As in section 9.5.1, the PI control parameters for the heating process are expressed as follow:

0

11

00500

99812

05008022

2

00222

05008022

212

211

210

212

211

210

=

−=

=

===

−=×

+−=−+−=

+=++=

a

aa

.TK

b

...TKTK

Kb

...T

KTKKb

D

DIP

DIP

The PI control parameters for the cooling process are expressed as follow:

0

11

00500

99812

05008022

2

00222

05008022

112

111

110

112

111

110

=

−=

=

==−=

−=+−=

−=×

−−=−−−=

a

aa

.TK

b

...TKTK

Kb

...T

KTKKb

D

DIP

DIP

The convention for the subscripts of the a and b vectors are discussed in section 6.4. Equation 6.3 yields the following multivariable P, Q and R vectors from the a and b vectors.

(9.14)

(9.15)

Page 154: Software Development for Microprocessor Control Systems

Chapter 9 – Application Example: Multivariable Temperature Control

144

11 1 −−= zP

11 99810022 −+−= z..Q

01 =R 1

2 1 −−= zP 1

2 99810022 −−= z..Q

02 =R

These P, Q and R vectors can be directly implemented in HC11Control as shown in Figure 9.16. The 8-bit output value, which corresponds to the fan speed, is limited between 8-bit values of 100 and 250. This will ensure that the fan will keep running at all times.

(9.16)

Figure 9.16 HC11Control setup for implementing a multivariable temperature controller in which the 8-bit output and the PWM output are controlled with two independent PI routines.

Page 155: Software Development for Microprocessor Control Systems

Chapter 9 – Application Example: Multivariable Temperature Control

145

The results for the multivariable control scheme are shown in Figures 9.17, 9.18 and 9.19.

Figure 9.17 Temperature step response for the multivariable control scheme

Figure 9.18 Heating power step response for the multivariable control scheme

Figure 9.19 Fan speed step response for the multivariable control scheme

Page 156: Software Development for Microprocessor Control Systems

Chapter 9 – Application Example: Multivariable Temperature Control

146

Figure 9.17 shows the temperature step response of the system, which is more damped than the temperature step response in section 9.5.1. The y-axis in Figure 9.17 shows the 8-bit analog input. The corresponding temperature in °C is the 8-bit value times 0.178 as shown in Equation 9.6 Figure 9.18 shows the heating control effort to the plant while Figure 9.19 shows the cooling control effort to the plant. It can be seen from Figures 9.18 and 9.19 that there is a tradeoff between the heating power and the fan speed to keep the system on the desired temperature. The balance between the heating power and the fan speed is marginally stable. It is possible however to alter the control algorithm to minimize the power consumption while keeping system stable on the desired temperature.

Page 157: Software Development for Microprocessor Control Systems

147

Chapter 10 Conclusions and Recommendations 10.1 Conclusions The user-friendly microcontroller-based controller software has been developed in this thesis to such an extent so that control engineers can implement a wide range of SISO and MIMO discrete-time controller designs based on the M68HC11 microcontroller. Control engineers can rapidly implement a prototype controller design without having to deal with any microcontroller software coding. The controller can be implemented in a cost-effective manner by using widely available resources. The only equipment needed for implementing the user-friendly digital controller are: • A PC with a Windows 95 environment • M68EBLP11 Evaluation Board • M68HC11 Memory Expansion Board

Page 158: Software Development for Microprocessor Control Systems

Chapter 10 – Conclusions and Recommendations

148

Controller performance data can be monitored in real-time while the control algorithm is being executed on the microcontroller. An offline plotting feature will allow the user of the control software to evaluate the system performance graphically. The controller performance data can also be saved to disk for further analysis. The functionality of the controller software was verified by testing the system on control applications such as DC motor speed control and multivariable temperature control. These control system applications were also numerically modeled in Simulink. The comparison between the experimental results and the results obtained from the Simulink models were found to be in agreement and verified the correct functionality of the controller software that was developed in this thesis.

Page 159: Software Development for Microprocessor Control Systems

Chapter 10 – Conclusions and Recommendations

149

10.2 Recommendations This thesis provides a powerful foundation for further software development for rapid prototyping of embedded control systems. Higher-order controllers The SISO and MIMO controllers are limited to fourth-order direct digital filter structures in this thesis. Higher-order digital filters are however possible to implement by altering the software system slightly. The main constraint was the lack of processing speed on the M68HC11 microcontroller, which can be overcome by using a more powerful processor. Alternative Hardware There are many types of microcontrollers on the market, and a variety of manufacturers to choose from. Microcontrollers are cost-effective and sufficient for numerous medium performance control applications. Other devices such as the 16-bit M68HC12 microcontroller or the PC32 DSP card can also be used as an alternative to the 68HC11 microcontroller. The M68HC12 is Motorola’s latest developed 16-bit microcontroller. The M68HC12 is completely source code compatible with the M68HC11 family of 8-bit microcontrollers. Current 68HC11 based applications can therefore easily be upgraded to 16-bit performance with increased functionality and more on-chip memory. The primary difference between a standard microcontroller and a DSP is in the instruction sets and the speed of the particular instructions [1]. The instruction sets for DSP’s are rich in math capabilities and most DSP’s have a build in multiplier-accumulator (MAC) which is dedicated to multiplying instructions and fast floating-point arithmetic. A DSP-class processor is therefore the correct choice for demanding control applications. DSPs can provide filter characteristics with very sharp cutoff rates that are impossible to obtain with conventional microprocessors [1].

Page 160: Software Development for Microprocessor Control Systems

Chapter 10 – Conclusions and Recommendations

150

The PC32 from Innovative Integration is an example of a low cost 32-bit DSP card with hardware floating-point. The PC32 DSP is also coupled with analog and digital peripherals for plant interfacing. An ANSI C compiler is also available for DSP code generation. A wider variety of controller Input/Output ports. Plant interfacing is limited to two input ports and two output ports that are configured as follow:

Input ports • Analog input • Frequency input

Output ports • PWM output • 8-Bit Parallel output It is possible to implement additional input and output ports by altering the microcontroller and the Windows software slightly. This will result in more flexibility in controller/plant interface and will allow more input and output possibilities for multivariable control applications. More controller features Many other software features that can be added to the current software. • A lag term can be incorporated in the control algorithm, which will allow the user

to implement a controller delay on a system. • The system can be modified to interact with other software packages such as

MATLAB for real-time plotting and data analysis. • Serial communication between the PC and the microcontroller can be improved to

optimize the controller performance while monitoring the controller performance data.

Page 161: Software Development for Microprocessor Control Systems

151

References [1] Kuo, B.C. (1992) Digital Control Systems Second Edition. Saunders College

Publishing, London. [2] Stoecker, W.F. and Stoecker, P.A. (1989) Microcomputer Control of

Thermal and Mechanical Systems. Van Nostrand Reinhold, New York, pp 3-4.

[3] Dorf, R.C and Bishop, R.H. (1995) Modern Control Systems. Addison-

Wesley, New York, pp 240-242. [4] Liu, Yu-Gheng and Gibson, A. (1986) Microcomputer Systems: The

8086/8088 Family 2nd edition. Prentice Hall, New Jersey, pp 2. [5] Phillips, C.L. and Nagle, H.T. (1995) Digital Control System Analysis and

Design Third Edition. Prentice Hall, New Jersey. [6] Franklin, G.F.,Powel, J.D. and Workman, M.L. (1990) Digital Control of

Dynamic Systems. Addison-Wesley, New York, pp 641-666. [7] Greenfield, J.D. (1992) The 68HC11 Microcontroller. Saunders College

Publishing, London, pp 303-306. [8] Bozic, S.M. (1979) Digital and Kalman filtering. Edward Arnorld, London. [9] Kuo, B.C. (1991) Automatic Control Systems 6th edition. Prentice Hall, New

Jersey. [10] Lefkon D. and Payne B. (1998) Making embedded systems year 2000

compliant. IEEE Spectrum. 35, 74-79. [11] Beards, P.H. (1991) Analog and Digital Electronics. Prentice Hall, New

York, pp 564-567.

Page 162: Software Development for Microprocessor Control Systems

152

[12] Driscoll, F.D., Coughlin, R.F. and Villanucci, R.S. (1994) Data Acquisition and Process Control with the M68HC11 Microcontroller. Prentice Hall, New Jersey, pp 131.

[13] Schildt, H. (1997) Borland C++: The Complete Reference. Osborne

McGraw-Hill, New York. [14] Van Sickle, T. (1994) Programming Microcontrollers in C. HighText, CA,

pp 228-231. [15] Beckwith, T.G., Marangoni, R.D. and Lienhard, J.H. (1993) Mechanical

Measurements Fifth Edition. Addison-Wesley, New York, pp 179-204. [16] The Student Edition of Matlab User’s Guide, Prentice Hall, Englewood

Cliffs, NJ, pp 273-274. [17] Austin, P.C. (1998) Lecture Handout, 660.704 FC Advanced Control

Systems, The University of Auckland. [18] Mills, A. F. (1995) Basic Heat and Mass Transfer. IRWIN, Chicago, pp 4. [19] Motorola M68HC11 Reference Manual, Motorola, Phoenix, AZ, 1990 [20] Gatland, B. (1998) A better tuning method?. Automation & Control.

March 98, 30-31.

Page 163: Software Development for Microprocessor Control Systems

153

Appendix A ANSI/IEEE Standard 754 Floating-Point Representation A1. Introduction There are several ways to represent real numbers on computers. The Floating-point representation is the most common representation for real numbers on Intel-based PCs, Macintoshes, Unix platforms and Motorola microcontrollers. Floating-point representation was standardized by the Institute for Electrical and Electronic Engineers (IEEE) and the American National Standards Institute (ANSI) on 26 July 1985. The four floating-point formats specified by ANSI/IEEE 754 are: • Basic single-precision • Basic double-precision • Extended single-precision • Extended double-precision

Page 164: Software Development for Microprocessor Control Systems

Appendix A - ANSI/IEEE Standard 754 Floating-Point Representation

154

A2. ANSI/IEEE 754 Floating-Point Layout The Basic single-precision floating-point number is 32 bits wide and has an 8-bit exponent and a 24-bit mantissa. Both the mantissa and the exponent are signed numbers, but neither is represented in the two’s-complement format. The Sign Bit A Zero in the sign bit denotes a positive number and a one denotes a negative number. The Exponent The exponent is stored in biased form (also know as the excess-n form). The bias is 127 for the basic single precision ANSI/IEEE 754 floating point number. For example, to represent an exponent of 0, the 8-bit exponent will contain the number 127. To represent –120, the exponent will contain the number 7. And so forth. The exponent bias is 1023 for ANSI/IEEE 754 double precision floating point numbers.

1 bit sign 8-bit exponent + 127 bias 23-bit mantissa with leading one removed

1 bit sign 11-bit exponent + 1023 bias 52-bit mantissa with leading one removed

Figure A.1 ANSI/IEEE 754 Basic Single-Precision floating-point format

Figure A.2 ANSI/IEEE 754 Basic Double-Precision floating-point format

22 - 030 - 23 31

51 - 062 - 52 63

Page 165: Software Development for Microprocessor Control Systems

Appendix A - ANSI/IEEE Standard 754 Floating-Point Representation

155

The Mantissa The mantissa (also known as the significand) represents the precision bits of the number. Floating points are stores in normalized form. The normalized form will put the radix point after the first non-zero digit. For example, twelve is represented as

11021 ×. and not as 01012× . Since the only non-zero digit in binary format is one, the leading one can be removed. The mantissa has therefore effectively 24 bits of resolution.

A3. Floating-Point Number Range The range of floating-point numbers consists out of normalized and denormalized numbers. Normalized numbers preserve the full precision of the mantissa. If the exponent is all zeros, but the mantissa is not, then the value is interpreted as a denormalized number. Table A1 gives the ranges of the floating-point representation.

Normalized Denormalized Corresponding Approximate Decimal

Single Precision Minimum

1492 −± 1262−± 854410 .−±

Single Precision Maximum

( ) 12623 221 −− ×−± ( ) 12723 221 ×−± − 533810 .−±

Double Precision Minimum

10742−± 10222−± 332310 .−±

Double Precision Maximum

( ) 102252 221 −− ×−± ( ) 102352 221 ×−± − 330810 .±

Table A1 Ranges of the floating-point representation.

Page 166: Software Development for Microprocessor Control Systems

Appendix A - ANSI/IEEE Standard 754 Floating-Point Representation

156

A4. ANSI/IEEE 754 Floating-Point Special Values Zero Zero can not be represented directly in the in the straight ANSI/IEEE 754 Floating-Point format due to the leading one concept. Zero is a special value denoted with an exponent and mantissa field of 0. The sign bit is not significant. Denormalized floating-point numbers A floating-point number is a denormalized number if the exponent is all zeros, but the mantissa is not. A denormalized number does not have an assumed leading one before the binary point. Single precision denormalized numbers are represented as

( ) 126201 −××− m.s , where s is the sign bit and m is the mantissa. Double precision

denormalized numbers are represented as ( ) 1022201 −××− m.s .

Infinity The values ± infinity are represented with an exponent of all ones and a mantissa of all zeros. The sign bit distinguishes between positive and negative infinity. All arithmetic operations with infinite values are defined in IEEE. Indeterminate An indeterminate value is used to represent results from arithmetic operations from which the result is indeterminate, such as infinity-infinity or infinity × 0. An indeterminate value is represented by an exponent of all ones, a mantissa with a leading one followed by all zeros, and a sign bit of one. Not a Number The value NaN is used to represent a floating-pint value that is an error of some form. The NaN value is represented with an exponent field of all ones and a sign bit of zero.

Page 167: Software Development for Microprocessor Control Systems

Appendix A - ANSI/IEEE Standard 754 Floating-Point Representation

157

A5. ANSI/IEEE 754 Floating-Point Special Operations All arithmetic operations on special numbers are defined by IEEE as follow:

Operation Result

n ÷ ± Infinity 0

± Infinity × ± Infinity ± Infinity

± n ÷ 0 ± Infinity

Infinity + Infinity Infinity

Infinity – Infinity Indeterminate

± Infinity ÷ ± Infinity Indeterminate

± Infinity × 0 Indeterminate Table A2 Floating-Point Special Operations

Page 168: Software Development for Microprocessor Control Systems

Appendix A - ANSI/IEEE Standard 754 Floating-Point Representation

158

Page 169: Software Development for Microprocessor Control Systems

159

Appendix B S-record Information B1. Introduction All the parameters entered by the user in the Graphical User Interface (GUI) program on the PC will be transformed to a s-record line. That line will be added to the predefined control algorithm, which is already in s-record format. The complete S-record file is then ready to be downloaded to the microcontroller. It is therefore necessary for the reader to have some background on the S-record format. An S-record file is an ASCII text file that consists of a number of character strings in hexadecimal format. Each character string starts with the letter S and consists of the following data fields: record type, record length, memory address, data and checksum. The record length and checksum fields ensure accuracy of transmission between the different hardware devices. Each byte of data is encoded as a two-character hexadecimal number. All the programs for the microcontroller are stored and downloaded in S-record format.

Page 170: Software Development for Microprocessor Control Systems

Appendix B – S-record Information

160

S-record Field Number of characters

Contents

Type 2 S-record type: S0-S9 Record length 2 Number of character pairs in the character

string, excluding type and record length pairs. Address 4, 6, or 8 The 2-4 byte starting address at which the

code/data field is to be loaded into memory. Code/ Data 0-n The executable program code and data in

machine code, which will be loaded into the memory of the microcontroller.

Checksum 2 The checksum is the least significant byte of the complement of the sum of all the bytes in the record length, code/data s-record line.

S-record types There are eight types of s-records. Only three S-record types namely S0, S1 and S9 are significant for using with the 68HC11 microcontroller. S0 type The S0 type is the header for each block of character strings of S-records. The address is normally zeros and the code/data field may contain any information regarding the following block of S-record lines. S1 type The S1 type contains a 2-byte memory address followed by the code/data which is to be loaded into the microcontroller memory. S9 type The S9 line terminates the S-record file. There is no code/data field in the S9 type.

Page 171: Software Development for Microprocessor Control Systems

Appendix B – S-record Information

161

B2. S-record example The following example shows a typical s-record file in normal ASCII text format. The file consists of one S0, twelve S1, and one S9 records. S00600004844521B S123B6000F7EB72C0000B62A0000000000320001B61A0000B622B61EB6200010000200003F S105B620FFFF26 S123B62A3C345F4F30ED01D600E700C60F37CC8480BDB65C3130E6004FE301ED01E602BD4B S123B64AB6B8FC0010C30004188F30E60218E70020D937363CFC0010C3000E8FEC0030E3D0 S123B66A02ED00FC0010C3000E188FEC0018A30024026C06FC0010C300258F2017FC001044 S123B68AC300258FE600C18025F3306A06FC0010C300258FC680E700306D0622E0FC0010E5 S123B6AAC3000E8FEC0030A30225F23838393734FC0010C3002E8FE60030E700FC0010C3D8 S123B6CA002F8FE60030E700FC0010C3002E8F6D0027F5FC0010C3002F188F30E60118E7D1 S123B6EA003839FEB61018FEB60E27163CEC02EE006F0008C3FFFF26F83808080808180909

S123B70A26EAFEB614EC00271808081AEE00080837E60018E70033081808C3FFFF26F12081 S118B72AE439FCB6042604FEB60C358DB6FEB606AD0020EE3923 S10BB6220002001010000000FA S903B60046

The first line is a S0 type S-record and consists of the following character pairs: S0 The line is a type S0 S-record. 06 This character pair / byte is the record length. Hexadecimal 06 indicates that

six character pairs / bytes will follow. 00 The four character address field which is zeros. 00 44 48 The data field, ASCII H, D and R. The data field can contain any descriptive 52 information regarding the block of S-record data which follows. 1B The last character pair is the checksum of this S0 record. This checksum can be verified as follow: Checksum = FF- (06 + 48 + 44 + 52) = FF-E4 = 1B The second line and the following eleven S-record lines can be explained as follow: S1 This means that this line is a type S1 record.

Page 172: Software Development for Microprocessor Control Systems

Appendix B – S-record Information

162

23 Hexadecimal 23 (decimal 35) indicates that 35 character pairs / bytes of data

will follow B6 B600 is the 2-byte memory starting-address at which the code/data field will 00 be loaded into. The next 35 character pairs are the actual code/data, which will be loaded into the memory. The last character pair namely 3F is the checksum of the first S1 type S-record. The last S-record line is a S9 type S-record and can be explained as follow: S9 The S9 indicates that the line is an S9 type S-record. 03 Hexadecimal 03 (decimal 3) indicates that 3 character pairs / bytes of data will

follow B6 These two character pairs is the 2-byte address of the instruction to which the 00 control is passed. 46 This is the checksum of the S9 record.

Page 173: Software Development for Microprocessor Control Systems

163

Appendix C Ziegler-Nichols Tuning of PID Controllers Sophisticated modeling and design methods are available to develop a controller that will compensate a system to meet transient and steady-state specifications. These methods require complete mathematical models of the process to be controlled in the form of state equations or transfer functions. It is often difficult to obtain accurate system parameters, which make PID controller tuning rather difficult. Fifty years ago a breakthrough came with the Ziegler-Nichols method[20]. Ziegler and Nichols recognized that most process systems have the general S-shaped step response shown in Figure C1. This S-shaped curve is known as the process reaction curve and can be generated experimentally or obtained from a dynamic simulation of the process [6].

Page 174: Software Development for Microprocessor Control Systems

Appendix C – Ziegler-Nichols Tuning of PID Controllers

164

The response of most plants my be approximated by

( ) ( )( ) 1+

==−

sKe

sUsYsG

sd

τ

τ

which is simply a first-order system plus a transportation lag. Ziegler and Nichols provided two methods for tuning the PID controller. In the first method, the controller parameters are selected so that the plant output decays to a quarter of its value after one period of oscillation as illustrated in Figure C2. A quarter decay corresponds to a damping ratio of 0.21, which is a good compromise between quick response and adequate stability. The PID controller parameters suggested by Ziegler and Nichols are shown in Table C-1.

dτ τ

K

t

( )ty

Figure C1. Typical process response curve

(C.1)

( )ty

t

0.25 1

Period

Figure C2. Quarter decay ratio

Page 175: Software Development for Microprocessor Control Systems

Appendix C – Ziegler-Nichols Tuning of PID Controllers

165

Type of Controller Optimum Gain

P d

P KK

ττ

=

PI d

P K.Kττ90

= , 2

270

dI K

.Kττ

=

PID d

P K.Kττ21

= , 2

60

dI K

.Kττ

= , K.KDτ60

=

In the second method for tuning the PID controller, the criteria for adjusting the controller parameters are based on evaluating the system at the limit of stability. The proportional gain is increased until the system produces continuous oscillations. The corresponding gain uK , which is known as the ultimate gain and the period of

oscillation uP , which is known as the ultimate period can be determined as illustrated

in Figure C3. The PID controller parameters suggested by Ziegler and Nichols, in terms of uK and

uP , are shown in Table C-2. The final tuning of the controller parameters can be done

manually to obtain the most desirable control system response.

Table C-1. Ziegler-Nichols PID controller tuning for a decay ratio of 0.25

+ r uK Process

- uP

Figure C3. Determination of the ultimate gain and ultimate period

Page 176: Software Development for Microprocessor Control Systems

Appendix C – Ziegler-Nichols Tuning of PID Controllers

166

Type of Controller Optimum Gain

P uP K.K 50=

PI uP K.K 450= , u

uI P

K.K 540=

PID uP K.K 60= , u

uI P

K.K 21= , uuD PK.K 0750=

Table C-2. Ziegler-Nichols PID controller tuning based on the stability

boundary parameters.

Page 177: Software Development for Microprocessor Control Systems

167

Appendix D Circuit Schematics and PCB Layouts The only memory available on the M68EBLP11 Evaluation Board, is the internal memory on the MC68B11E9 microcontroller, which is 322 bytes of internal RAM and 512 bytes of internal EEPROM (Electrically Erasable Programmable Read Only Memory). For the purpose of this project, the M68EBLP11 is being operated in expansion mode in conjunction with a 32Kb custom-built memory expansion board. The addressable RAM of the memory expansion board is 0x2000 to 0x9FFF.This section contains the schematic and PCB layout of the memory expansion board.

Page 178: Software Development for Microprocessor Control Systems

Appendix D – Schematic and PCB Layouts

168

Figure D1 Schematic layout of the 68HC11 Memory Expansion Board

Page 179: Software Development for Microprocessor Control Systems

Appendix D – Schematic and PCB Layouts

169

Figure D2 PCB layout of the 68HC11 Memory Expansion Board (Top View)

Page 180: Software Development for Microprocessor Control Systems

Appendix D – Schematic and PCB Layouts

170

Figure D3 PCB layout of the 68HC11 Memory Expansion Board (Bottom View)

Page 181: Software Development for Microprocessor Control Systems

171

Appendix E Application Example Images This section contains images from the DC motor speed control and multivariable temperature control application examples.

Page 182: Software Development for Microprocessor Control Systems

Appendix E – Application Example Images

172

Figure E1. The M68EBLP11 evaluation board, the memory expansion board, the DC Motor and the inteface electronics for the DC motor speed control application example.

Figure E2. Detailed view of the DC motor and the optical speed sensor

Page 183: Software Development for Microprocessor Control Systems

Appendix E – Application Example Images

173

Figure E3. The M68EBLP11 evaluation board, the memory expansion board, the heating system and the inteface electronics for the multivariable temperature control application example.

Page 184: Software Development for Microprocessor Control Systems

Appendix E – Application Example Images

174

Page 185: Software Development for Microprocessor Control Systems

175

Appendix F The Windows-Based Software Source Code HC11Control was developed in the Borland C++ Builder development environment This section contains all the necessary Windows-based software source code for HC11Control.

The different software modules will be listed as follow:

Comsettings.cpp Communication settings form sourcce code Comsettings.h Communication settings form header file Download.cpp Download form source code Download.h Download form header file Download thread.cpp Download thread source code Download thread.h Download thread header file Downloadstarterror.cpp Downloadstarterror form source code Downloadstarterror.h Downloadstarterror form header file InsufficientDataFormFile.cpp InsufficientDataForm source code InsufficientDataFormFile.h InsufficientDataForm header file

Page 186: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

176

Main.cpp Main form source code Main.h Main form header file Mainmenu.cpp Startup menu source code Mainmenu.h Startup menu header file Max250min1.cpp Error-message form source code Max250min1.h Error-message form header file Max255.cpp Error-message form source code Max255.h Error-message form header file Min40.cpp Error-message form source code Min40.h Error-message form header file Plot1.cpp Plotform1 source code Plot1.h Plotform1 header file Plot2.cpp Plotform2 source code Plot2.h Plotform2 header file Plot3.cpp Plotform3 source code Plot3.h Plotform3 header file Plot4.cpp Plotform4 source code Plot4.h Plotform4 header file Runcontrolprogram.cpp Runform source code Runcontrolprogram.h Runform header file Savedata.cpp Savedata form source code Savedata.h Savedata form header file

Page 187: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

177

Comsettings.cpp – Communication Settings Form source code //--------------------------------------------------------------------

#include <vcl\vcl.h>

#pragma hdrstop

#include "Commsettings.h"

#include "main.h"

#include "download.h"

#include "Runcontrolprogram.h"

//--------------------------------------------------------------------

#pragma resource "*.dfm"

TCommunicationSettingsForm *CommunicationSettingsForm;

//--------------------------------------------------------------------

__fastcall TCommunicationSettingsForm::TCommunicationSettingsForm

(TComponent* Owner)

: TForm(Owner)

{

}

//--------------------------------------------------------------------

void __fastcall TCommunicationSettingsForm::OkButtonClick(

TObject *Sender)

{

// This section closes the form on which the user will specify the

// communication port.

CommunicationSettingsForm->Close();

}

//--------------------------------------------------------------------

// The follwoing three event handlers will adjust the settings in the

// program to use the selected communications port.

//--------------------------------------------------------------------

void __fastcall TCommunicationSettingsForm::RadioButton1Click(

TObject *Sender)

{

MonitorForm->DigitalComm->Port="COM1";

MonitorForm->TestDACADCComm->Port="COM1";

MonitorForm->PIDMonitorComm->Port="COM1";

MonitorForm->MultiComm->Port="COM1";

Download1->CommReceive->Port="COM1";

Download1->ZComm1->Port="COM1";

RunProgramForm->CommReceive->Port="COM1";

RunProgramForm->RunComm->Port="COM1";

Page 188: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

178

}

//--------------------------------------------------------------------

void __fastcall TCommunicationSettingsForm::RadioButton2Click(

TObject *Sender)

{

MonitorForm->DigitalComm->Port="COM2";

MonitorForm->TestDACADCComm->Port="COM2";

MonitorForm->PIDMonitorComm->Port="COM2";

MonitorForm->MultiComm->Port="COM2";

Download1->CommReceive->Port="COM2";

Download1->ZComm1->Port="COM2";

RunProgramForm->CommReceive->Port="COM2";

RunProgramForm->RunComm->Port="COM2";

}

//--------------------------------------------------------------------

void __fastcall TCommunicationSettingsForm::RadioButton3Click(

TObject *Sender)

{

MonitorForm->DigitalComm->Port="COM3";

MonitorForm->TestDACADCComm->Port="COM3";

MonitorForm->PIDMonitorComm->Port="COM3";

MonitorForm->MultiComm->Port="COM3";

Download1->CommReceive->Port="COM3";

Download1->ZComm1->Port="COM3";

RunProgramForm->CommReceive->Port="COM3";

RunProgramForm->RunComm->Port="COM3";

}

//--------------------------------------------------------------------

Page 189: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

179

Comsettings.h - Communication Settings Form header file //--------------------------------------------------------------------

#ifndef CommsettingsH

#define CommsettingsH

//--------------------------------------------------------------------

#include <vcl\Classes.hpp>

#include <vcl\Controls.hpp>

#include <vcl\StdCtrls.hpp>

#include <vcl\Forms.hpp>

//--------------------------------------------------------------------

class TCommunicationSettingsForm : public TForm

{

__published: // IDE-managed Components

TRadioButton *RadioButton1;

TRadioButton *RadioButton2;

TRadioButton *RadioButton3;

TLabel *Label1;

TButton *OkButton;

void __fastcall OkButtonClick(TObject *Sender);

void __fastcall RadioButton1Click(TObject *Sender);

void __fastcall RadioButton2Click(TObject *Sender);

void __fastcall RadioButton3Click(TObject *Sender);

private: // User declarations

public: // User declarations

__fastcall TCommunicationSettingsForm(TComponent* Owner);

};

//--------------------------------------------------------------------

extern TCommunicationSettingsForm *CommunicationSettingsForm;

//--------------------------------------------------------------------

#endif

Page 190: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

180

Download.cpp - Download Form source code // File: download.cpp //------------------------------------------------------------------- #include <vcl\vcl.h> #pragma hdrstop #include "download.h" #include "Download thread.h" #include "main.h" #include "Downloadstarterror.h" //------------------------------------------------------------------- #pragma link "zcomm" #pragma resource "*.dfm" TDownload1 *Download1; TDownloadThread *DownloadThread; void delay(int ms); void delay(int ms) { DWORD time1 = GetTickCount(); while(GetTickCount()<time1+ms); } //------------------------------------------------------------------- __fastcall TDownload1::TDownload1(TComponent* Owner) : TForm(Owner) { } //------------------------------------------------------------------- void __fastcall TDownload1::CancelClick(TObject *Sender) { // This event handler and will close the download form. Download1->Close(); } //------------------------------------------------------------------- //------------------------------------------------------------------- void __fastcall TDownload1::CommReceiveDataAvailable(TObject *Sender) // This event handler monitors the characters received from the // microcontroller and will activate the download procedure when the // characters which correspond to a reset action is received from // the microcontroller. If any other characters is received // from the microcontroller, the program will call the // ErrorDownloadStartMessage form in which the user will be prompted

Page 191: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

181

// that a running program on the microcontroller has to be stopped // before the download procedure can continue. // It was found that the download procedure halts all other event // handlers and functions in the program. The solution was to program // the download procedure in such a way so that it will run in a // separate thread from the main program. { unsigned char *buffer,data[10]; buffer=data; // Clear the input buffer by writing zero's to it for (int n=0;n<=10;n++) {data[n]=0;} CommReceive->ReadComm(buffer,4); // The next line can also be: // "if (data[0]==13 && data[1]==10 && data[2]==66 && data[3]==85)" // A reset action on the microcontroller will send the abovementioned // characters in the specefic order to the PC. This program will // continue if the first character received is 13. if (data[0]==13) // if reset is detected { BlinkTimer->Enabled=false; Download1->CommReceive->CloseConnection(); delay(10); DownloadThread = new TDownloadThread(false); //Start the download //seperate thread. DownloadThread->Priority=tpHighest; } else { // The next six lines of program code will disable serial // communication between the PC and the microcontroller // and will activate the ErrorDownloadStartMessage form in which // the user will be prompted that a running program on the // microcontroller has to be stopped before the download // procedure can continue. BlinkTimer->Enabled=false; Download1->CommReceive->CloseConnection(); Download1->Close(); ErrorDownloadStartMessage->Label3->Caption= "downloding the new program."; ErrorDownloadStartMessage->ShowModal(); } } //------------------------------------------------------------------- void __fastcall TDownload1::ZComm1DataAvailable(TObject *Sender) // This procedure monitors the characters received from the // microcontroller while a different thread is downloading the

Page 192: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

182

// control algorithm to the microcontroller. The thread which // downloads the control algorihm to the microcontroller is listed // in the "Download thrad.cpp" unit. If the download procedure is // successfull, a 'done' message will be received from the // microcontroller. //------------------------------------------------------------------- { unsigned char *buffer,data[20]; buffer=data; // Clear the input buffer by writing zero's to it for (int n=0;n<=20;n++) { data[n]=0; } ZComm1->ReadComm(buffer,8); int len=strlen(data); if (len>20) len=20; //Limit the input buffer length to 20 characters. for (int tel=0;tel<len;tel++) { if (data[tel]=='d' && data[tel+1]=='o') // Monitor the output of { Download1->ErrorTimer->Enabled=false; // Disable the ErrorTimer Download1->Messagebox->Left=130; Download1->Messagebox->Caption="Download Successful"; Download1->ZComm1->CloseConnection(); delete DownloadThread;// Deallocate DownloadThread in the memory OK->Visible=true; OK->SetFocus(); Cancel->Visible=false; // if the Digital Control program was selected if (MonitorForm->DigitalController1->Checked) { MonitorForm->DigitalSaveButton->Enabled=false; MonitorForm->DigitalRunButton->Enabled=true; MonitorForm->DigitalDisconnectButton->Enabled=false; MonitorForm->DigitalMonitorButton->Enabled=false; MonitorForm->DigitalPlotButton->Enabled=false; } else if (MonitorForm->PIDController1->Checked) { MonitorForm->SaveButton->Enabled=false; MonitorForm->PIDRunButton->Enabled=true; MonitorForm->PIDDisconnectButton->Enabled=false; MonitorForm->PIDMonitorButton->Enabled=false; MonitorForm->PIDPlotButton->Enabled=false; } else if (MonitorForm->TestDACADC1->Checked) { MonitorForm->TestDACADCSaveButton->Enabled=false; MonitorForm->TestDACADCRunButton->Enabled=true; MonitorForm->TestDACADCDisconnectButton->Enabled=false;

Page 193: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

183

MonitorForm->TestDACADCMonitorButton->Enabled=false; MonitorForm->TestDACADCPlotButton->Enabled=false; } else if (MonitorForm->MultiController1->Checked) { MonitorForm->MultiSaveButton->Enabled=false; MonitorForm->MultiRunButton->Enabled=true; MonitorForm->MultiDisconnectButton->Enabled=false; MonitorForm->MultiMonitorButton->Enabled=false; MonitorForm->MultiPlotButton->Enabled=false; } } } } //------------------------------------------------------------------- //------------------------------------------------------------------- void __fastcall TDownload1::OKClick(TObject *Sender) { CancelClick(Sender); // Same as CancelClick } //------------------------------------------------------------------- void __fastcall TDownload1::ErrorTimerTimer(TObject *Sender) //------------------------------------------------------------------- // The ErrorTimer will be enabled in the EndDownload class member // function in the "Download thread.cpp" unit when the downloading // procedure to the microcontroller is finished. The interval of the // ErrorTimer is 2 seconds. The ZComm1DataAvailable component will // monitor for a 'done' message and will disable the ErrorTimer if // a 'done' message was received from the microcontroller. If no // 'done' message is recieved from the microcontroller within 2 // seconds after completion of the download procedure, the // ErrorTimerTimer event handler will be called which will prompt // the user that a download error occured. //------------------------------------------------------------------- { Download1->Messagebox->Left=170; Download1->Messagebox->Caption="Download Error"; Download1->ZComm1->CloseConnection(); delete DownloadThread; // Free the memory allocated by DownloadThread OK->Visible=true; Cancel->Visible=false; ErrorTimer->Enabled=false; } //------------------------------------------------------------------- void __fastcall TDownload1::ViewHideClick(TObject *Sender) // This event hander will display the complete s-record code which

Page 194: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

184

// is to be downloaded to the microcontroller { if (Download1->Memo1->Visible==false) { Download1->Height=458; Download1->ViewHide->Caption="Hide Code"; Memo1->Visible=true; } else { Download1->Height=171; ViewHide->Caption="View Code"; Memo1->Visible=false; } } //------------------------------------------------------------------- void __fastcall TDownload1::FormActivate(TObject *Sender) { // This event handler initialise all the buttons and controls // for the Download form and enable the serial communication // between the PC and the microcontroller. Cancel->Enabled=true; OK->Visible=false; Cancel->Visible=true; Messagebox->Left=120; Messagebox->Caption="Reset The Microcontroller"; BlinkTimer->Enabled=true; ProgressBar1->Position=0; Download1->Height=171; ViewHide->Caption="View Code"; Download1->CommReceive->OpenConnection(); Download1->Height=176; Download1->Memo1->Visible=false; } //------------------------------------------------------------------- void __fastcall TDownload1::FormClose(TObject *Sender, TCloseAction &Action) // This event handler will check whether serial communication // between the PC and the microcontroller is enabled when the // Download form closes and will disconnect the serail port before // the program closes. { if (CommReceive->Connected==true) CommReceive->CloseConnection(); if (ZComm1->Connected==true) ZComm1->CloseConnection(); }

Page 195: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

185

//------------------------------------------------------------------- void __fastcall TDownload1::BlinkTimerTimer(TObject *Sender) // This event handler will display a blinking message in which the // user will be prompted to reset the microcmontroller. { if (Download1->Messagebox->Caption=="") { Messagebox->Caption="Reset The Microcontroller"; } else Messagebox->Caption=""; } //-------------------------------------------------------------------

Page 196: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

186

Download.h - Download Form header file //------------------------------------------------------------------- #ifndef downloadH #define downloadH //------------------------------------------------------------------- #include <vcl\Classes.hpp> #include <vcl\Controls.hpp> #include <vcl\StdCtrls.hpp> #include <vcl\Forms.hpp> #include "zcomm.h" #include <vcl\ComCtrls.hpp> #include <vcl\ExtCtrls.hpp> //------------------------------------------------------------------- class TDownload1 : public TForm { __published: // IDE-managed Components TButton *Cancel; TZComm *ZComm1; TMemo *Memo1; TProgressBar *ProgressBar1; TLabel *Messagebox; TZComm *CommReceive; TButton *OK; TTimer *ErrorTimer; TButton *ViewHide; TTimer *BlinkTimer; void __fastcall CancelClick(TObject *Sender); void __fastcall CommReceiveDataAvailable(TObject *Sender); void __fastcall ZComm1DataAvailable(TObject *Sender); void __fastcall OKClick(TObject *Sender); void __fastcall ErrorTimerTimer(TObject *Sender); void __fastcall ViewHideClick(TObject *Sender); void __fastcall FormActivate(TObject *Sender); void __fastcall FormClose(TObject *Sender, TCloseAction &Action); void __fastcall BlinkTimerTimer(TObject *Sender); private: // User declarations public: // User declarations __fastcall TDownload1(TComponent* Owner); }; //-------------------------------------------------------------------- extern TDownload1 *Download1; //-------------------------------------------------------------------- #endif

Page 197: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

187

Download thread.cpp - Download thread source code // File: Download thread.cpp //------------------------------------------------------------------- #include <vcl\vcl.h> #pragma hdrstop #include "Download thread.h" #include "download.h" //------------------------------------------------------------------- // Methods and properties of objects in VCL can only be // used in a method called using Synchronize, for example: // // Synchronize(UpdateCaption); // // where UpdateCaption could look like: // // void __fastcall TDownloadThread::UpdateCaption() // { // Form1->Caption = "Updated in a thread"; // } //------------------------------------------------------------------- int len,tel; char text[20000]; void delayt(int ms); void delayt(int ms) { DWORD time1 = GetTickCount(); while(GetTickCount()<time1+ms); } __fastcall TDownloadThread::TDownloadThread(bool CreateSuspended) : TThread(CreateSuspended) { } //------------------------------------------------------------------- // This procedure will download the control algorithm to the // microcontroller in a seperate thread. //------------------------------------------------------------------- void __fastcall TDownloadThread::Execute() { Synchronize(Downloading); delayt(50); // The following lines is the actual downloading procedure // All the 'Line feed' (character 10) and 'Carriage return' // (character 13) characters in the text which contain the // control algorithm are ignored. for (tel=0;tel<len;tel++)

Page 198: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

188

{ if(!(text[tel]==10)&&!(text[tel]==13)) // Ignore characters 10&13 { Synchronize(SendCharacter); // Send the character to the } //delayt(5); // Delay for 5 ms between each character. } Synchronize(EndDownload); } //------------------------------------------------------------------- void __fastcall TDownloadThread::Downloading() // This class member function will initialise the microcontroller // to receive s-record data from the serial communication interface. { Download1->Messagebox->Left=104; Download1->Messagebox->Caption="Downloading Control Algorithm"; Download1->Cancel->Enabled=false; Download1->ZComm1->OpenConnection(); char *ptext[20000]; *ptext=Download1->Memo1->Lines->GetText(); strcpy(text,*ptext); //Copy the characters to be downloaded to the len=strlen(text); // The next lines will perform a "load t" instruction. The "load t" // instruction will initiate the microcontroller to receive the // control algorithm which will follow unsigned char c=13; // 13 is the keyboard code for the Enter key Download1->ZComm1->WriteCommByte(c); delayt(500); char loadt[]="load t"; for (int cnt=0;cnt<=5;cnt++) { Download1->ZComm1->WriteCommByte(loadt[cnt]); delayt(50); } c=13; Download1->ZComm1->WriteCommByte(c); //End of "load t" instruction Download1->ProgressBar1->Min=0; Download1->ProgressBar1->Max=len; Download1->ProgressBar1->Step=1; } //------------------------------------------------------------------ void __fastcall TDownloadThread::SendCharacter()

Page 199: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

189

// This class member function will send one character at a time from // the s-record file to the microcontroller. { Download1->ProgressBar1->Position=tel; Download1->ZComm1->WriteCommByte(text[tel]); } //------------------------------------------------------------------ void __fastcall TDownloadThread::EndDownload() // This class member function will Enable the ErrorTimer and prompt // the user that the downloading procedure is complete. // A detail description of the ErrorTimer is listed at the // ErrorTimerTimer event handler in the "download.cpp" unit. { Download1->ErrorTimer->Enabled=true; // Enable the ErrorTimer. Download1->Messagebox->Left=192; Download1->Messagebox->Caption="Done"; } //------------------------------------------------------------------

Page 200: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

190

Download thread.h - Download thread header file //-------------------------------------------------------------------- #ifndef Download threadH #define Download threadH //-------------------------------------------------------------------- #include <vcl\Classes.hpp> //-------------------------------------------------------------------- class TDownloadThread : public TThread { private: protected: void __fastcall Execute(); public: __fastcall TDownloadThread(bool CreateSuspended); void __fastcall Downloading(); void __fastcall SendCharacter(); void __fastcall EndDownload(); }; //-------------------------------------------------------------------- #endif

Page 201: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

191

Downloadstarterror.cpp - Downloadstarterror Form source code

/-------------------------------------------------------------------- #include <vcl\vcl.h> #pragma hdrstop #include "Downloadstarterror.h" //-------------------------------------------------------------------- #pragma resource "*.dfm" TErrorDownloadStartMessage *ErrorDownloadStartMessage; //-------------------------------------------------------------------- // This unit will display the ErrorDownloadStartMessage form in // which the user will be prompted that a running program on the // microcontroller has to be stopped before the download procedure // can continue. //-------------------------------------------------------------------- __fastcall TErrorDownloadStartMessage::TErrorDownloadStartMessage (TComponent* Owner) : TForm(Owner) { } //-------------------------------------------------------------------- void __fastcall TErrorDownloadStartMessage::OKButtonClick( TObject *Sender) { ErrorDownloadStartMessage->Close(); } //--------------------------------------------------------------------

Page 202: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

192

Downloadstarterror.h - Downloadstarterror form header file //-------------------------------------------------------------------- #ifndef DownloadstarterrorH #define DownloadstarterrorH //-------------------------------------------------------------------- #include <vcl\Classes.hpp> #include <vcl\Controls.hpp> #include <vcl\StdCtrls.hpp> #include <vcl\Forms.hpp> #include <vcl\ExtCtrls.hpp> //-------------------------------------------------------------------- class TErrorDownloadStartMessage : public TForm { __published: // IDE-managed Components TLabel *Label1; TLabel *Label2; TLabel *Label3; TButton *OKButton; TImage *Image1; void __fastcall OKButtonClick(TObject *Sender); private: // User declarations public: // User declarations __fastcall TErrorDownloadStartMessage(TComponent* Owner); }; //-------------------------------------------------------------------- extern TErrorDownloadStartMessage *ErrorDownloadStartMessage; //-------------------------------------------------------------------- #endif

Page 203: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

193

InsufficientDataFormFile.cpp-InsufficientDataForm source code //-------------------------------------------------------------------- #include <vcl\vcl.h> #pragma hdrstop #include "InsufficientDataFormFile.h" //-------------------------------------------------------------------- #pragma resource "*.dfm" TInsufficientDataForm *InsufficientDataForm; //-------------------------------------------------------------------- // This unit will display the InsufficientDataForm in which the user // will be propmted that one of the data entry fields is empty when // trying to download the control algorithm to the microcontroller. //-------------------------------------------------------------------- __fastcall TInsufficientDataForm::TInsufficientDataForm (TComponent* Owner) : TForm(Owner) { } //-------------------------------------------------------------------- void __fastcall TInsufficientDataForm::OKClick(TObject *Sender) { InsufficientDataForm->Close(); } //--------------------------------------------------------------------

Page 204: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

194

InsufficientDataFormFile.h - InsufficientDataForm header file //-------------------------------------------------------------------- #ifndef InsufficientDataFormFileH #define InsufficientDataFormFileH //-------------------------------------------------------------------- #include <vcl\Classes.hpp> #include <vcl\Controls.hpp> #include <vcl\StdCtrls.hpp> #include <vcl\Forms.hpp> #include <vcl\ExtCtrls.hpp> //-------------------------------------------------------------------- class TInsufficientDataForm : public TForm { __published: // IDE-managed Components TButton *OK; TLabel *Label1; TImage *Image1; TLabel *Label2; TLabel *Label3; void __fastcall OKClick(TObject *Sender); private: // User declarations public: // User declarations __fastcall TInsufficientDataForm(TComponent* Owner); }; //-------------------------------------------------------------------- extern TInsufficientDataForm *InsufficientDataForm; //-------------------------------------------------------------------- #endif

Page 205: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

195

Main.cpp - Main Form source code // File: main.cpp //-------------------------------------------------------------------- #include <vcl\vcl.h> #pragma hdrstop #include "stdlib.h" #include "main.h" #include "iostream.h" #include "fstream.h" #include "Savedata.h" #include "Runcontrolprogram.h" #include "InsufficientDataFormFile.h" #include "download.h" #include "Download thread.h" #include "Max255.h" #include "Commsettings.h" #include "Plot1.h" #include "Plot2.h" #include "Testdacadcselectinput.h" #include "Testdacadcselectoutput.h" #include "Min40.h" #include "Max250min1.h" #include "Plot3.h" #include "Plot4.h" #include "mainmenu.h" //-------------------------------------------------------------------- #pragma link "zcomm" #pragma link "thdtimer" #pragma link "XYPlot" #pragma link "Grids" #pragma link "DigitBox" #pragma resource "*.dfm" TMonitorForm *MonitorForm; //-------------------------------------------------------------------- // Multi Section global variables //-------------------------------------------------------------------- unsigned char Multidata1[300],Multidata2[300], Multidata3[300],Multidata4[300], Multidata5[300],Multidata6[300], Multidata7[300],Multidata8[300], Multidata9[3000]; unsigned short int Multitimeindex=0,Multitimeindexstop=0; double* Multitime = new double[65536]; double* Multitimerecorded = new double[65536]; unsigned char Multisamplefrequency; unsigned int Multitimedisplay; unsigned short int Multianaloginputindex=0;

Page 206: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

196

double* Multianaloginput = new double[65536]; double* Multianaloginputrecorded = new double[65536]; unsigned char Multianaloginputdisplay; unsigned short int Multifreqinputindex=0; double* Multifreqinput = new double[65536]; double* Multifreqinputrecorded = new double[65536]; unsigned char Multifreqinputdisplay; unsigned short int Multi8bitoutputindex=0; double* Multi8bitoutput = new double[65536]; double* Multi8bitoutputrecorded = new double[65536]; unsigned char Multi8bitoutputdisplay; unsigned short int MultiPWMoutputindex=0; double* MultiPWMoutput = new double[65536]; double* MultiPWMoutputrecorded = new double[65536]; unsigned char MultiPWMoutputdisplay; unsigned char Multibuffercount=0; //-------------------------------------------------------------------- // Digital Section global variables //-------------------------------------------------------------------- unsigned char Digitaldata1[300],Digitaldata2[300], Digitaldata3[300],Digitaldata4[300],Digitaldata5[1800]; unsigned short int Digitaltimeindex=0,Digitaltimeindexstop=0; double Digitaltime[65536],Digitaltimerecorded[65536]; unsigned char Digitalsamplefrequency; unsigned int Digitaltimedisplay; unsigned short int Digitalinputindex=0; double Digitalinput[65536],Digitalinputrecorded[65536]; unsigned char Digitalinputdisplay; unsigned short int Digitaloutputindex=0; double Digitaloutput[65536],Digitaloutputrecorded[65536]; unsigned char Digitaloutputdisplay; unsigned char Digitalbuffercount=0; unsigned char digitalinoutcombination=1; //-------------------------------------------------------------------- // PID Section global variables //-------------------------------------------------------------------- unsigned char PIDdata1[300],PIDdata2[300], PIDdata3[300],PIDdata4[300],PIDdata5[1800]; unsigned short int PIDtimeindex=0,PIDtimeindexstop=0; double PIDtime[65536],PIDtimerecorded[65536]; unsigned char PIDsamplefrequency; unsigned int PIDtimedisplay;

Page 207: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

197

unsigned short int PIDinputindex=0; double PIDinput[65536],PIDinputrecorded[65536]; unsigned char PIDinputdisplay; unsigned short int PIDoutputindex=0; double PIDoutput[65536],PIDoutputrecorded[65536]; unsigned char PIDoutputdisplay; unsigned char PIDbuffercount=0; unsigned char pidinoutcombination=1; //-------------------------------------------------------------------- // TestDACADC Section global variables //-------------------------------------------------------------------- unsigned char TestDACADCdata1[300],TestDACADCdata2[300], TestDACADCdata3[300],TestDACADCdata4[300], TestDACADCdata5[1800]; unsigned short int TestDACADCtimeindex=0,TestDACADCtimeindexstop=0; double TestDACADCtime[65536],TestDACADCtimerecorded[65536]; unsigned char TestDACADCsamplefrequency; unsigned int TestDACADCtimedisplay; unsigned short int TestDACADCinputindex=0; double TestDACADCinput[65536],TestDACADCinputrecorded[65536]; unsigned char TestDACADCinputdisplay; unsigned short int TestDACADCoutputindex=0; double TestDACADCoutput[65536],TestDACADCoutputrecorded[65536]; unsigned char TestDACADCoutputdisplay; unsigned char TestDACADCbuffercount=0; unsigned char testdacinoutcombination=1; //-------------------------------------------------------------------- __fastcall TMonitorForm::TMonitorForm(TComponent* Owner) : TForm(Owner) { } //-------------------------------------------------------------------- void __fastcall TMonitorForm::FormClose(TObject *Sender, TCloseAction &Action) // This event handler will check whether serial communication between // the PC and the microcontroller is enabled when the program closes // and will disconnect the serail port before the program closes. { if (PIDMonitorComm->Connected==true) PIDMonitorComm->CloseConnection(); if (TestDACADCComm->Connected==true) TestDACADCComm->CloseConnection(); delete[] Multitime;

Page 208: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

198

delete[] Multitimerecorded; delete[] Multianaloginput; delete[] Multianaloginputrecorded; delete[] Multifreqinput; delete[] Multifreqinputrecorded; delete[] Multi8bitoutput; delete[] Multi8bitoutputrecorded; delete[] MultiPWMoutput; delete[] MultiPWMoutputrecorded; } //-------------------------------------------------------------------- void __fastcall TMonitorForm::PIDController1Click(TObject *Sender) { // This event handler will enable and display the PID controller // panel on which all the controls and editboxes for the PID // controller are displayed. MonitorForm->Caption="HC11Control - PID Controller"; PIDController1->Checked=true; MonitorForm->PIDPanel->Visible=true; MonitorForm->PIDPanel->Enabled=true; MonitorForm->N68HC11Programs1->Enabled=false; MonitorForm->New1->Enabled=true; // Load microcontroller code from s-record file AnsiString s19filename="digital.s19"; MonitorForm->DigitalCode->Lines->LoadFromFile(s19filename); } //-------------------------------------------------------------------- void __fastcall TMonitorForm::TestDACADC1Click(TObject *Sender) { MonitorForm->Caption="HC11Control - Test Input/Output"; TestDACADC1->Checked=true; MonitorForm->TestDACADCPanel->Visible=true; MonitorForm->TestDACADCPanel->Enabled=true; MonitorForm->N68HC11Programs1->Enabled=false; MonitorForm->New1->Enabled=true; // Load microcontroller code from s-record file AnsiString s19filename="testio.s19"; MonitorForm->TestDACADCCode->Lines->LoadFromFile(s19filename); } //-------------------------------------------------------------------- void __fastcall TMonitorForm::New1Click(TObject *Sender) // The New1Click event handler will reset all current control // applications. { DigitalController1->Checked=false; MultiController1->Checked=false; PIDController1->Checked=false; TestDACADC1->Checked=false; MonitorForm->New1->Enabled=false;

Page 209: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

199

MonitorForm->N68HC11Programs1->Enabled=true; MonitorForm->PIDPanel->Visible=false; MonitorForm->PIDPanel->Enabled=false; MonitorForm->TestDACADCPanel->Visible=false; MonitorForm->TestDACADCPanel->Enabled=false; MonitorForm->DigitalPanel->Visible=false; MonitorForm->DigitalPanel->Enabled=false; MonitorForm->MultiPanel->Visible=false; MonitorForm->MultiPanel->Enabled=false; MenuForm->ShowModal(); } //-------------------------------------------------------------------- void __fastcall TMonitorForm::Exit1Click(TObject *Sender) { MonitorForm->Close(); // Close the program } //-------------------------------------------------------------------- void __fastcall TMonitorForm::Communicationsettings1Click( TObject *Sender) // This event handler will call the form on which the user will // specify the communication port. { CommunicationSettingsForm->ShowModal(); } //-------------------------------------------------------------------- void __fastcall TMonitorForm:: Recorddatawhencontrolprogramstarts1Click(TObject *Sender) // This eventhandler will set or reset the flag which will // determine whether incoming data from the microcontroller // will be logged when the program on the microcontroller starts. // If Recorddatawhencontrolprogramstarts1->Checked=true then // incoming data will be logged as soon as the program on // the microcontroller starts. { if (Recorddatawhencontrolprogramstarts1->Checked) { Recorddatawhencontrolprogramstarts1->Checked=false; } else { Recorddatawhencontrolprogramstarts1->Checked=true; } } //-------------------------------------------------------------------- void __fastcall TMonitorForm::SaveButtonClick(TObject *Sender)

Page 210: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

200

{ // This event handler will determine whether an existing file will // be overwritten and will be used by the PID and TestDACADC saection. // If a file is to be overwritten, the FileOverwriteDiaolgBox will // be called and will prompt the user whether the save procedure // may continue or not. SaveDialog->Title = "Save As"; if (SaveDialog->Execute()) { char *filename=SaveDialog->FileName.c_str(); ifstream checkfile(filename); if(checkfile) { checkfile.close(); FileOverwriteDialogBox->Label3->Caption=filename; FileOverwriteDialogBox->ShowModal(); } else { SaveNowHiddenButtonClick(Sender); } } } //-------------------------------------------------------------------- void __fastcall TMonitorForm::SaveNowHiddenButtonClick( TObject *Sender) // This event handler will be called by the SaveButtonClick() event // handler if FileName does not exist in the specified directory and // by the YesButtonClick event handler in FileOverwriteDialogBox if // the file exists. All the recorded data and the corresponding time // will be saved in a ASCII file named by FileName. { char temp[100]; char *filename=SaveDialog->FileName.c_str(); ofstream outfile; outfile.open(filename, ios::trunc); // If the Multi controller was selected if (MultiController1->Checked) { sprintf(temp,"%7s %8s %8s %8s %8s","Seconds","Input1","Input2","Output1","Output2"); outfile << temp << endl << endl; for(int count=0;count<Multitimeindexstop;count++) { sprintf(temp,"%7.2f %8.0f %8.0f %8.0f %8.0f", Multitimerecorded[count], Multianaloginputrecorded[count], Multifreqinputrecorded[count], Multi8bitoutputrecorded[count],

Page 211: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

201

MultiPWMoutputrecorded[count]); outfile << temp << endl; } } // If the Digital controller was selected if (DigitalController1->Checked) { sprintf(temp,"%7s %8s %8s","Seconds","Input","Output"); outfile << temp << endl << endl; for(int count=0;count<Digitaltimeindexstop;count++) { sprintf(temp,"%7.2f %8.0f %8.0f",Digitaltimerecorded[count], Digitalinputrecorded[count],Digitaloutputrecorded[count]); outfile << temp << endl; } } // If the PID controller was selected if (PIDController1->Checked) { sprintf(temp,"%7s %8s %8s","Seconds","Input","Output"); outfile << temp << endl << endl; for(int count=0;count<PIDtimeindexstop;count++) { sprintf(temp,"%7.2f %8.0f %8.0f",PIDtimerecorded[count], PIDinputrecorded[count],PIDoutputrecorded[count]); outfile << temp << endl; } } // If the TestDACADC program was selected if (TestDACADC1->Checked) { sprintf(temp,"%7s %8s %8s","Seconds","Input","Output"); outfile << temp << endl << endl; for(int count=0;count<TestDACADCtimeindexstop;count++) { sprintf(temp,"%7.2f %8.0f %8.0f",TestDACADCtimerecorded[count], TestDACADCinputrecorded[count],TestDACADCoutputrecorded[count]); outfile << temp << endl; } } outfile.close(); } //-------------------------------------------------------------------- //-------------------------------------------------------------------- // The following section are the event handlers accociated with the // PID controller section. This includes all the edit boxes in which // the controller parameters are entered and the events and buttons // accociated with it. //--------------------------------------------------------------------

Page 212: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

202

void __fastcall TMonitorForm::PIDMonitorCommDataAvailable(TObject *Sender) // // This event handler will store all incoming data received from // the microcontroller in the 'data' array. The variable named // 'output' is a global variable which will be used for display // and recording purposes in other event handlers. // { unsigned char *buffer,data[300]; buffer=data; // Clear the input buffer by writing zero's to it for (int n=0;n<=300;n++) { data[n]=0; } PIDMonitorComm->ReadComm(buffer,300); // The idea of PIDbuffercount is to ensure that there are at least // six characters of incoming data available before processing it. PIDbuffercount++; if (PIDbuffercount>6) { PIDbuffercount=1; } switch (PIDbuffercount) { case 1: strcpy((char *)PIDdata5,(char *)data); break; case 2: strcpy((char *)PIDdata4,(char *)data); break; case 3: strcpy((char *)PIDdata3,(char *)data); break; case 4: strcpy((char *)PIDdata2,(char *)data); break; case 5: strcpy((char *)PIDdata1,(char *)data); break; case 6: strcat((char *)PIDdata5,(char *)PIDdata4); strcat((char *)PIDdata5,(char *)PIDdata3); strcat((char *)PIDdata5,(char *)PIDdata2); strcat((char *)PIDdata5,(char *)PIDdata1); strcat((char *)PIDdata5,(char *)data); int len=strlen((char *)PIDdata5);

Page 213: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

203

// The following lines will decode the data pattern into the // different arrays. Data will be received from the // microcontroller in the following format // [251, Sample Frequency, 252, Input from plant, 253, // Output to plant] // The array may start and end at any point, but the data always // have to be in the same order, for example: the following array // is also a valid data array // [Input from plant, 253, Output to plant, 251, // Sample Frequency] for (int scandata=0;scandata<6;scandata++) { if (PIDdata5[scandata]==251) { for (int count=1+scandata;count<len;count=count+6) { PIDsamplefrequency=PIDdata5[count]; float period=(float) 1/PIDdata5[count]; // The if statement ignores the first period value // since it is not significant. // The first meaningful period value will be available // after one sample cycle on the microcontroler is // finished. if (PIDtimeindex==0) { PIDtime[PIDtimeindex]=0; } else { PIDtime[PIDtimeindex]=PIDtime[PIDtimeindex-1]+period; } PIDtimedisplay=PIDtime[PIDtimeindex]; PIDtimeindex++; } } else if (PIDdata5[scandata]==252) { for (int count=1+scandata;count<len;count=count+6) { PIDinputdisplay=PIDdata5[count]; PIDinput[PIDinputindex]=PIDdata5[count]; PIDinputindex++; } } else if (PIDdata5[scandata]==253) { for (int count=1+scandata;count<len;count=count+6) { PIDoutputdisplay=PIDdata5[count]; PIDoutput[PIDoutputindex]=PIDdata5[count]; PIDoutputindex++; } }

Page 214: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

204

}// end for scandata break; }// end switch } //-------------------------------------------------------------------- void __fastcall TMonitorForm::PIDDisplayTimerTimer(TObject *Sender) { // // This event handler will display the data received from the // microcontroller with every time interval of the timer. // The time interval can be set with the 'interval' property // of the timer component. // PIDInputDigitBox->Target=PIDinputdisplay; PIDInputDigitBox->Value=PIDinputdisplay; PIDOutputDigitBox->Target=PIDoutputdisplay; PIDOutputDigitBox->Value=PIDoutputdisplay; PIDSamplefreqDigitBox->Target=PIDsamplefrequency; PIDSamplefreqDigitBox->Value=PIDsamplefrequency; // The stopbutton will only be enabled when recording // in in progress. if (PIDStopButton->Enabled==true) { PIDTimeDigitBox->Target=PIDtimedisplay; PIDTimeDigitBox->Value=PIDtimedisplay; } } //-------------------------------------------------------------------- void __fastcall TMonitorForm::PIDStopButtonClick(TObject *Sender) { // This routine will stop data recording process and will enable // and disable all the appropriate buttons related to this stopping // action. PIDtimeindexstop=min(PIDtimeindex,PIDinputindex); PIDtimeindexstop=min(PIDoutputindex,PIDtimeindexstop); PIDDisconnectButton->Enabled=true; SaveButton->Enabled=true; PIDPlotButton->Enabled=true; SaveButton->Enabled=true; PIDStopButton->Enabled=false; PIDRecordButton->Enabled=true; for (int count=0;count<PIDtimeindexstop;count++) { PIDtimerecorded[count]=PIDtime[count]; PIDinputrecorded[count]=PIDinput[count]; PIDoutputrecorded[count]=PIDoutput[count]; } }

Page 215: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

205

//-------------------------------------------------------------------- void __fastcall TMonitorForm::PIDRecordButtonClick(TObject *Sender) { // This routine will start the data recording process and will enable // and disable all the appropriate buttons related to this recording // action. PIDDisconnectButton->Enabled=false; PIDPlotButton->Enabled=false; SaveButton->Enabled=false; PIDStopButton->Enabled=true; PIDRecordButton->Enabled=false; PlotForm1->XYPlot1->RemovePlot(1); PlotForm1->XYPlot1->RemovePlot(2); // Clear the current plot. PIDoutputindex=0; PIDinputindex=0; PIDtimeindex=0; } //-------------------------------------------------------------------- void __fastcall TMonitorForm::PIDPlotButtonClick(TObject *Sender) { // TXYPlot is a Borland C++ Builder VCL plotting component for // graphing x,y data. It is used to plot the recorded data // versus time. PlotForm1->Show(); PlotForm1->Caption="Input From Plant"; PlotForm1->XYPlot1->XAutoScale=true; PlotForm1->XYPlot1->YAutoScale=true; if (MonitorForm->PlotLines1->Checked) { PlotForm1->XYPlot1->XYPlot(PIDtimerecorded, PIDinputrecorded,PIDtimeindexstop,1, clBlue,LinesFilledPoints); } else { PlotForm1->XYPlot1->XYPlot(PIDtimerecorded, PIDinputrecorded,PIDtimeindexstop,1, clBlue,FilledPoints); } PlotForm2->Show(); PlotForm2->Caption="Output to Plant"; PlotForm2->XYPlot1->XAutoScale=true; PlotForm2->XYPlot1->YAutoScale=true; if (MonitorForm->PlotLines1->Checked) { PlotForm2->XYPlot1->XYPlot(PIDtimerecorded, PIDoutputrecorded,PIDtimeindexstop,1, clBlue,LinesFilledPoints); }

Page 216: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

206

else { PlotForm2->XYPlot1->XYPlot(PIDtimerecorded, PIDoutputrecorded,PIDtimeindexstop,1, clBlue,FilledPoints); } } //-------------------------------------------------------------------- void __fastcall TMonitorForm::PIDMonitorButtonClick(TObject *Sender) // This event handler will enable serial communication between the // microcontroller and the PC and will enable and disable all the // appropriate buttons on the main form. // When data is available from the serial port, an OnDataAvailable // event will be triggered and the MonitorCommDataAvailable event // handler will be called which will handle the incomming data // received from the microcontroller. { PIDMonitorComm->OpenConnection(); PIDRecordButton->Enabled=true; PIDMonitorButton->Enabled=false; PIDDisconnectButton->Enabled=true; PIDDownloadButton->Enabled=false; PIDRunButton->Enabled=false; } //-------------------------------------------------------------------- void __fastcall TMonitorForm::PIDDisconnectButtonClick(TObject *Sender) // This event handler will disable serial communication between the // microcontroller and the PC and will enable and disable all the // appropriate buttons on the main form. { PIDMonitorComm->CloseConnection(); PIDRecordButton->Enabled=false; PIDMonitorButton->Enabled=true; PIDDisconnectButton->Enabled=false; PIDDownloadButton->Enabled=true; PIDRunButton->Enabled=true; } //-------------------------------------------------------------------- void __fastcall TMonitorForm::PIDRunButtonClick(TObject *Sender) { // This event handler will call the RunProgramForm which will // prompt the user to reset the microcontroller. The reason for this // is that it is not possible for this program to determine the // microcontroller's current state. // // The Recorddatawhencontrolprogramstarts1->Checked // is a flag which will determine whether the PIDMonitorButtonClick // event handler will be called after the run instruction is

Page 217: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

207

// completed. If Recorddatawhencontrolprogramstarts1->Checked=false, // the program on the microcontroller will be started but the serial // communication between the pc and the microcontroller have to be // enabled manually. RunProgramForm->ShowModal(); } //-------------------------------------------------------------------- void __fastcall TMonitorForm::PIDSetpointEditEnter(TObject *Sender) { PIDSetpointEdit->SelStart=0; } //-------------------------------------------------------------------- void __fastcall TMonitorForm::PIDKpEditEnter(TObject *Sender) { PIDKpEdit->SelStart=0; } //-------------------------------------------------------------------- void __fastcall TMonitorForm::PIDKiEditEnter(TObject *Sender) { PIDKiEdit->SelStart=0; } //-------------------------------------------------------------------- void __fastcall TMonitorForm::PIDKdEditEnter(TObject *Sender) { PIDKdEdit->SelStart=0; } //-------------------------------------------------------------------- void __fastcall TMonitorForm::PIDSamplefreqEditEnter(TObject *Sender) { PIDSamplefreqEdit->SelStart=0; } //-------------------------------------------------------------------- void __fastcall TMonitorForm::PIDDownloadButtonClick(TObject *Sender) // This event handler will check whether all the editboxes in the // PID controller section is filled with data by the user. If all // the editboxes are filled with data, the text will be converted to // integer numbers. The integer numbers will then be converted to // hexadecimal numbers which will be converted into a s-record line. // The s-record line which contain the control parameters is added // to the predefined control algorithm which will form the complete // control algorim. The download procedure will then be called. { if (PIDSetpointEdit->EditText==" " || PIDKpEdit->EditText==" " || PIDKiEdit->EditText==" " || PIDKdEdit->EditText==" " || PIDSamplefreqEdit->EditText==" " || PIDPWMEdit->EditText==" " || PIDInputupperlimitEdit->EditText==" " || PIDInputlowerlimitEdit->EditText==" " || PIDOutputupperlimitEdit->EditText==" " ||

Page 218: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

208

PIDOutputlowerlimitEdit->EditText==" ") { InsufficientDataForm->ShowModal(); // An error message will be // displayed if any of the // data entry fields is empty. } else { unsigned char chksum; unsigned char vars[50]; char *psetp; int setp; psetp=PIDSetpointEdit->Text.c_str(); setp=atoi(psetp); vars[0]=(unsigned char)setp; // Convert the variables //from text to float char *pstrkp; float kp; AnsiString ansikp=PIDKpEdit->Text; pstrkp=ansikp.c_str(); kp=atof(pstrkp); char *pstrki; float ki; AnsiString ansiki=PIDKiEdit->Text; pstrki=ansiki.c_str(); ki=atof(pstrki); char *pstrkd; float kd; AnsiString ansikd=PIDKdEdit->Text; pstrkd=ansikd.c_str(); kd=atof(pstrkd); char *psamplefreq; int samplefreq; psamplefreq=PIDSamplefreqEdit->Text.c_str(); samplefreq=atoi(psamplefreq); float T = (float) 1/samplefreq; // Calculate the coeficients A0,A1,B0,B1 and B2 for the // second-order transfer function from kp, ki and kd. float A0=1; float A1=-1; float A2=0; float A3=0; float A4=0; float B0=kp+(ki*T/2)+(kd/T); float B1=(-kp)+(ki*T/2)-(2*kd/T); float B2=kd/T; float B3=0; float B4=0;

Page 219: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

209

float *pA0; unsigned int adrA0; unsigned char A0_byte0; unsigned char A0_byte1; unsigned char A0_byte2; unsigned char A0_byte3; pA0=&A0; adrA0=(int)pA0; (char *) adrA0; (char *) (adrA0+1); (char *) (adrA0+2); (char *) (adrA0+3); A0_byte3=*(char *) adrA0; A0_byte2=*(char *) (adrA0+1); A0_byte1=*(char *) (adrA0+2); A0_byte0=*(char *) (adrA0+3); vars[1]=A0_byte0; vars[2]=A0_byte1; vars[3]=A0_byte2; vars[4]=A0_byte3; float *pA1; unsigned int adrA1; unsigned char A1_byte0; unsigned char A1_byte1; unsigned char A1_byte2; unsigned char A1_byte3; pA1=&A1; adrA1=(int)pA1; (char *) adrA1; (char *) (adrA1+1); (char *) (adrA1+2); (char *) (adrA1+3); A1_byte3=*(char *) adrA1; A1_byte2=*(char *) (adrA1+1); A1_byte1=*(char *) (adrA1+2); A1_byte0=*(char *) (adrA1+3); vars[5]=A1_byte0; vars[6]=A1_byte1; vars[7]=A1_byte2; vars[8]=A1_byte3; float *pA2; unsigned int adrA2; unsigned char A2_byte0; unsigned char A2_byte1; unsigned char A2_byte2; unsigned char A2_byte3; pA2=&A2; adrA2=(int)pA2; (char *) adrA2; (char *) (adrA2+1); (char *) (adrA2+2);

Page 220: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

210

(char *) (adrA2+3); A2_byte3=*(char *) adrA2; A2_byte2=*(char *) (adrA2+1); A2_byte1=*(char *) (adrA2+2); A2_byte0=*(char *) (adrA2+3); vars[9]=A2_byte0; vars[10]=A2_byte1; vars[11]=A2_byte2; vars[12]=A2_byte3; float *pA3; unsigned int adrA3; unsigned char A3_byte0; unsigned char A3_byte1; unsigned char A3_byte2; unsigned char A3_byte3; pA3=&A3; adrA3=(int)pA3; (char *) adrA3; (char *) (adrA3+1); (char *) (adrA3+2); (char *) (adrA3+3); A3_byte3=*(char *) adrA3; A3_byte2=*(char *) (adrA3+1); A3_byte1=*(char *) (adrA3+2); A3_byte0=*(char *) (adrA3+3); vars[13]=A3_byte0; vars[14]=A3_byte1; vars[15]=A3_byte2; vars[16]=A3_byte3; float *pA4; unsigned int adrA4; unsigned char A4_byte0; unsigned char A4_byte1; unsigned char A4_byte2; unsigned char A4_byte3; pA4=&A4; adrA4=(int)pA4; (char *) adrA4; (char *) (adrA4+1); (char *) (adrA4+2); (char *) (adrA4+3); A4_byte3=*(char *) adrA4; A4_byte2=*(char *) (adrA4+1); A4_byte1=*(char *) (adrA4+2); A4_byte0=*(char *) (adrA4+3); vars[17]=A4_byte0; vars[18]=A4_byte1; vars[19]=A4_byte2; vars[20]=A4_byte3; float *pB0; unsigned int adrB0;

Page 221: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

211

unsigned char B0_byte0; unsigned char B0_byte1; unsigned char B0_byte2; unsigned char B0_byte3; pB0=&B0; adrB0=(int)pB0; (char *) adrB0; (char *) (adrB0+1); (char *) (adrB0+2); (char *) (adrB0+3); B0_byte3=*(char *) adrB0; B0_byte2=*(char *) (adrB0+1); B0_byte1=*(char *) (adrB0+2); B0_byte0=*(char *) (adrB0+3); vars[21]=B0_byte0; vars[22]=B0_byte1; vars[23]=B0_byte2; vars[24]=B0_byte3; float *pB1; unsigned int adrB1; unsigned char B1_byte0; unsigned char B1_byte1; unsigned char B1_byte2; unsigned char B1_byte3; pB1=&B1; adrB1=(int)pB1; (char *) adrB1; (char *) (adrB1+1); (char *) (adrB1+2); (char *) (adrB1+3); B1_byte3=*(char *) adrB1; B1_byte2=*(char *) (adrB1+1); B1_byte1=*(char *) (adrB1+2); B1_byte0=*(char *) (adrB1+3); vars[25]=B1_byte0; vars[26]=B1_byte1; vars[27]=B1_byte2; vars[28]=B1_byte3; float *pB2; unsigned int adrB2; unsigned char B2_byte0; unsigned char B2_byte1; unsigned char B2_byte2; unsigned char B2_byte3; pB2=&B2; adrB2=(int)pB2; (char *) adrB2; (char *) (adrB2+1); (char *) (adrB2+2); (char *) (adrB2+3); B2_byte3=*(char *) adrB2; B2_byte2=*(char *) (adrB2+1);

Page 222: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

212

B2_byte1=*(char *) (adrB2+2); B2_byte0=*(char *) (adrB2+3); vars[29]=B2_byte0; vars[30]=B2_byte1; vars[31]=B2_byte2; vars[32]=B2_byte3; float *pB3; unsigned int adrB3; unsigned char B3_byte0; unsigned char B3_byte1; unsigned char B3_byte2; unsigned char B3_byte3; pB3=&B3; adrB3=(int)pB3; (char *) adrB3; (char *) (adrB3+1); (char *) (adrB3+2); (char *) (adrB3+3); B3_byte3=*(char *) adrB3; B3_byte2=*(char *) (adrB3+1); B3_byte1=*(char *) (adrB3+2); B3_byte0=*(char *) (adrB3+3); vars[33]=B3_byte0; vars[34]=B3_byte1; vars[35]=B3_byte2; vars[36]=B3_byte3; float *pB4; unsigned int adrB4; unsigned char B4_byte0; unsigned char B4_byte1; unsigned char B4_byte2; unsigned char B4_byte3; pB4=&B4; adrB4=(int)pB4; (char *) adrB4; (char *) (adrB4+1); (char *) (adrB4+2); (char *) (adrB4+3); B4_byte3=*(char *) adrB4; B4_byte2=*(char *) (adrB4+1); B4_byte1=*(char *) (adrB4+2); B4_byte0=*(char *) (adrB4+3); vars[37]=B4_byte0; vars[38]=B4_byte1; vars[39]=B4_byte2; vars[40]=B4_byte3; // samplefreq declared earlier to calculate A0,A1,B0,B1,B2 vars[41]=(unsigned char)samplefreq; char *ppwmhz; int pwmhz;

Page 223: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

213

ppwmhz=PIDPWMEdit->Text.c_str(); pwmhz=atoi(ppwmhz); vars[42]=(unsigned char)pwmhz; // Check whether positive or feedback or negative feedback was // selected. // A 1 will be transmitted to the microcontroller for negative // feedback and a 2 will be transmitted for positive feedback. if (PIDNegativeFeedbackSelect->Checked) { vars[43]=1; //Negative feedback } else { vars[43]=2; //Positive feedback } char *poutputupperlimit; int outputupperlimit; poutputupperlimit=PIDOutputupperlimitEdit->Text.c_str(); outputupperlimit=atoi(poutputupperlimit); vars[44]=(unsigned char)outputupperlimit; char *poutputlowerlimit; int outputlowerlimit; poutputlowerlimit=PIDOutputlowerlimitEdit->Text.c_str(); outputlowerlimit=atoi(poutputlowerlimit); vars[45]=(unsigned char)outputlowerlimit; char *pinputupperlimit; int inputupperlimit; pinputupperlimit=PIDInputupperlimitEdit->Text.c_str(); inputupperlimit=atoi(pinputupperlimit); vars[46]=(unsigned char)inputupperlimit; char *pinputlowerlimit; int inputlowerlimit; pinputlowerlimit=PIDInputlowerlimitEdit->Text.c_str(); inputlowerlimit=atoi(pinputlowerlimit); vars[47]=(unsigned char)inputlowerlimit; vars[48]=pidinoutcombination; // The checksum byte will be added to the s-record line. // The checksum is the complement of the 8-bit sum of all the // bytes in the s-record line. int lenvars=49; unsigned char sum=0; for (int count1=0;count1<lenvars;count1++) { sum=sum+vars[count1]; } chksum=255-52-sum; // The second term indicates the number // of bytes which will be transmitted plus three (2 byte memory

Page 224: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

214

// location and 1 byte checksum). char addline[100]="S1340000"; // Hex 33 indicates the number of int count; for (count=0;count<lenvars;count++) // Convert the decimal variables // into hexadecimal values { char temp[3]; if (vars[count]<16) sprintf(temp,"0%X",vars[count]); // Add a '0' if the // hexidecimal value is a // single digit value. else sprintf(temp,"%X",vars[count]); strcat(addline,temp); // Add the hexideciml value to the // s-record line. } char temp[3]; if (chksum<16) sprintf(temp,"0%X",chksum); // Add a '0' if the hexidecimal // value is a single digit value else sprintf(temp,"%X",chksum); strcat(addline,temp); // add the 8-bit checksum value // to the s-record line Download1->Memo1->Lines->Text=DigitalCode->Lines->Text; Download1->Memo1->Lines->Insert(1,addline); // Add the complete // existing control //algorithm. Download1->ShowModal(); // Start download procedure } } //-------------------------------------------------------------------- // The following four event handlers will be activated whenever the // user exits the particular editbox and will check whether the // values in the editboxes exeed 255 which is the maximum value for // an unsigned 8-bit number. An errormessage named Max255Form will // be displayed if the value in the editbox is higher than 255. //-------------------------------------------------------------------- void __fastcall TMonitorForm::PIDSetpointEditExit(TObject *Sender) { char *psetp; psetp=MonitorForm->PIDSetpointEdit->EditText.c_str(); int setp=atoi(psetp); if (setp>255) { Max255Form->ShowModal(); MonitorForm->PIDSetpointEdit->SetFocus(); } } //-------------------------------------------------------------------- void __fastcall TMonitorForm::PIDKpEditExit(TObject *Sender)

Page 225: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

215

{ char *pkp; pkp=MonitorForm->PIDKpEdit->EditText.c_str(); int kp=atoi(pkp); if (kp>255) { Max255Form->ShowModal(); MonitorForm->PIDKpEdit->SetFocus(); } } //-------------------------------------------------------------------- void __fastcall TMonitorForm::PIDKiEditExit(TObject *Sender) { char *pki; pki=MonitorForm->PIDKiEdit->EditText.c_str(); int ki=atoi(pki); if (ki>255) { Max255Form->ShowModal(); MonitorForm->PIDKiEdit->SetFocus(); } } //-------------------------------------------------------------------- void __fastcall TMonitorForm::PIDKdEditExit(TObject *Sender) { char *pkd; pkd=MonitorForm->PIDKdEdit->EditText.c_str(); int kd=atoi(pkd); if (kd>255) { Max255Form->ShowModal(); MonitorForm->PIDKdEdit->SetFocus(); } } //-------------------------------------------------------------------- void __fastcall TMonitorForm::PIDSamplefreqEditExit(TObject *Sender) { char *psamplefreq; psamplefreq=MonitorForm->PIDSamplefreqEdit->EditText.c_str(); int samplefreq=atoi(psamplefreq); if (samplefreq>255) { Max255Form->ShowModal(); MonitorForm->PIDSamplefreqEdit->SetFocus(); } } //-------------------------------------------------------------------- // TestDACADC Section. //-------------------------------------------------------------------- void __fastcall TMonitorForm::TestDACADCDownloadButtonClick( TObject *Sender)

Page 226: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

216

// This event handler will check whether all the data entry boxes in // the TestDACADC section is filled with data by the user. If all // the editboxes are filled with data, the text will be converted to // integer numbers. The integer numbers will then be converted to // hexadecimal numbers which will be converted into a s-record line. // The s-record line which contain the control parameters is added // to the predefined microcontroller code. // The download procedure will then be called. { if (TestDACADCStepsizeEdit->EditText==" " || TestDACADCDelayEdit->EditText==" " || TestDACADCSamplefreqEdit->EditText==" " || TestDACADCPWMEdit->EditText==" " || TestADCDACOutputupperlimitEdit->EditText==" " || TestADCDACOutputlowerlimitEdit->EditText==" ") { InsufficientDataForm->ShowModal(); // An error message will be // displayed if any of the // data entry fields is empty. } else { unsigned char chksum; unsigned char vars[20]; char *pstepsize; int stepsize; pstepsize=TestDACADCStepsizeEdit->Text.c_str(); stepsize=atoi(pstepsize); vars[0]=(unsigned char)stepsize; // Convert the variables //from text to integer char *pstepdelay; int stepdelay; pstepdelay=TestDACADCDelayEdit->Text.c_str(); stepdelay=atoi(pstepdelay); vars[1]=(unsigned char)stepdelay; char *psamplefreq; int samplefreq; psamplefreq=TestDACADCSamplefreqEdit->Text.c_str(); samplefreq=atoi(psamplefreq); vars[2]=(unsigned char)samplefreq; char *ppwmfreq; int pwmfreq; ppwmfreq=TestDACADCPWMEdit->Text.c_str(); pwmfreq=atoi(ppwmfreq); vars[3]=(unsigned char)pwmfreq; char *plowerlimit; int lowerlimit; plowerlimit=TestADCDACOutputlowerlimitEdit->Text.c_str();

Page 227: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

217

lowerlimit=atoi(plowerlimit); vars[4]=(unsigned char)lowerlimit; char *pupperlimit; int upperlimit; pupperlimit=TestADCDACOutputupperlimitEdit->Text.c_str(); upperlimit=atoi(pupperlimit); vars[5]=(unsigned char)upperlimit; vars[6]=testdacinoutcombination; // The checksum byte will be added to the s-record line. // The checksum is the least significant byte of the complement // of the sum of all the bytes in the s-record line. // The addline array forms the first // part of the s-record line. The first two characters which is chksum=255-10-(vars[0]+vars[1]+vars[2]+vars[3]+vars[4]+ vars[5]+vars[6]); char addline[9]="S10A0000"; int count; for (count=0;count<7;count++) // Convert the decimal variables // into hexadecimal values { char temp[3]; if (vars[count]<16) sprintf(temp,"0%X",vars[count]); // Add a '0' if the // hexidecimal value is a // single digit value. else sprintf(temp,"%X",vars[count]); strcat(addline,temp); // Add the hexideciml value to the // s-record line. } char temp[3]; if (chksum<16) sprintf(temp,"0%X",chksum); // Add a '0' if the hexidecimal // value is a single digit value else sprintf(temp,"%X",chksum); strcat(addline,temp); // add the 8-bit checksum value // to the s-record line Download1->Memo1->Lines->Text=TestDACADCCode->Lines->Text; Download1->Memo1->Lines->Insert(1,addline); // Add the complete // the existing code Download1->ShowModal(); // Start download procedure } } //-------------------------------------------------------------------- void __fastcall TMonitorForm::TestDACADCMonitorButtonClick( TObject *Sender) // This event handler will enable serial communication between the

Page 228: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

218

// microcontroller and the PC and will enable and disable all the // appropriate buttons on the main form. // When data is available from the serial port, an OnDataAvailable // event will be triggered and the MonitorCommDataAvailable event // handler will be called which will handle the incomming data // received from the microcontroller. { TestDACADCComm->OpenConnection(); TestDACADCRecordButton->Enabled=true; TestDACADCMonitorButton->Enabled=false; TestDACADCDisconnectButton->Enabled=true; TestDACADCDownloadButton->Enabled=false; TestDACADCRunButton->Enabled=false; } //-------------------------------------------------------------------- void __fastcall TMonitorForm::TestDACADCDisconnectButtonClick( TObject *Sender) // This event handler will disable serial communication between the // microcontroller and the PC and will enable and disable all the // appropriate buttons on the main form. { TestDACADCComm->CloseConnection(); TestDACADCRecordButton->Enabled=false; TestDACADCMonitorButton->Enabled=true; TestDACADCDisconnectButton->Enabled=false; TestDACADCDownloadButton->Enabled=true; TestDACADCRunButton->Enabled=true; } //-------------------------------------------------------------------- void __fastcall TMonitorForm::TestDACADCDisplayTimerTimer( TObject *Sender) { // // This event handler will display the data received from the // microcontroller with every time interval of the timer. // The time interval can be set with the 'interval' property // of the timer component. // TestDACADCInputDigitBox->Target=TestDACADCinputdisplay; TestDACADCInputDigitBox->Value=TestDACADCinputdisplay; TestDACADCOutputDigitBox->Target=TestDACADCoutputdisplay; TestDACADCOutputDigitBox->Value=TestDACADCoutputdisplay; TestDACADCSamplefreqDigitBox->Target=TestDACADCsamplefrequency; TestDACADCSamplefreqDigitBox->Value=TestDACADCsamplefrequency; // The stopbutton will only be enabled when recording // in in progress. if (TestDACADCStopButton->Enabled==true)

Page 229: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

219

{ TestDACADCTimeDigitBox->Target=TestDACADCtimedisplay; TestDACADCTimeDigitBox->Value=TestDACADCtimedisplay; } } //-------------------------------------------------------------------- void __fastcall TMonitorForm::TestDACADCStepsizeEditEnter( TObject *Sender) { TestDACADCStepsizeEdit->SelStart=0; TestDACADCRunButton->Enabled=false; } //-------------------------------------------------------------------- void __fastcall TMonitorForm::TestDACADCStepsizeEditExit( TObject *Sender) { char *pTestDACADCStepsize; pTestDACADCStepsize=MonitorForm->TestDACADCStepsizeEdit-> EditText.c_str(); int TestDACADCStepsize=atoi(pTestDACADCStepsize); if (TestDACADCStepsize>255) { Max255Form->ShowModal(); MonitorForm->TestDACADCStepsizeEdit->SetFocus(); } } //-------------------------------------------------------------------- void __fastcall TMonitorForm::TestDACADCRecordButtonClick( TObject *Sender) { // This routine will start the data recording process and will enable // and disable all the appropriate buttons related to this recording // action. TestDACADCDisconnectButton->Enabled=false; TestDACADCPlotButton->Enabled=false; TestDACADCSaveButton->Enabled=false; TestDACADCStopButton->Enabled=true; TestDACADCRecordButton->Enabled=false; PlotForm1->XYPlot1->RemovePlot(1); PlotForm1->XYPlot1->RemovePlot(2); // Clear the current plot. TestDACADCoutputindex=0; TestDACADCinputindex=0; TestDACADCtimeindex=0; } //-------------------------------------------------------------------- void __fastcall TMonitorForm::TestDACADCStopButtonClick( TObject *Sender) { // This routine will stop data recording process and will enable // and disable all the appropriate buttons related to this stopping // action.

Page 230: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

220

TestDACADCtimeindexstop=min(TestDACADCtimeindex,TestDACADCinputindex); TestDACADCtimeindexstop=min(TestDACADCoutputindex, TestDACADCDisconnectButton->Enabled=true; TestDACADCSaveButton->Enabled=true; TestDACADCPlotButton->Enabled=true; TestDACADCSaveButton->Enabled=true; TestDACADCStopButton->Enabled=false; TestDACADCRecordButton->Enabled=true; for (int count=0;count<TestDACADCtimeindexstop;count++) { TestDACADCtimerecorded[count]=TestDACADCtime[count]; TestDACADCinputrecorded[count]=TestDACADCinput[count]; TestDACADCoutputrecorded[count]=TestDACADCoutput[count]; } } //-------------------------------------------------------------------- void __fastcall TMonitorForm::TestDACADCPlotButtonClick( TObject *Sender) { // TXYPlot is a Borland C++ Builder VCL plotting component for // graphing x,y data. It is used to plot the recorded data // versus time. PlotForm1->Show(); PlotForm1->XYPlot1->XAutoScale=true; PlotForm1->XYPlot1->YAutoScale=true; if (MonitorForm->PlotLines1->Checked) { PlotForm1->XYPlot1->XYPlot(TestDACADCtimerecorded, TestDACADCinputrecorded,TestDACADCtimeindexstop,1, clBlue,LinesFilledPoints); } else { PlotForm1->XYPlot1->XYPlot(TestDACADCtimerecorded, TestDACADCinputrecorded,TestDACADCtimeindexstop,1, clBlue,FilledPoints); } PlotForm2->Show(); PlotForm2->XYPlot1->XAutoScale=true; PlotForm2->XYPlot1->YAutoScale=true; if (MonitorForm->PlotLines1->Checked) { PlotForm2->XYPlot1->XYPlot(TestDACADCtimerecorded, TestDACADCoutputrecorded,TestDACADCtimeindexstop,1, clBlue,LinesFilledPoints); } else

Page 231: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

221

{ PlotForm2->XYPlot1->XYPlot(TestDACADCtimerecorded, TestDACADCoutputrecorded,TestDACADCtimeindexstop,1, clBlue,FilledPoints); } } //-------------------------------------------------------------------- void __fastcall TMonitorForm::TestDACADCCommDataAvailable( TObject *Sender) { unsigned char *buffer,data[300]; buffer=data; // Clear the input buffer by writing zero's to it for (int n=0;n<=300;n++) { data[n]=0; } TestDACADCComm->ReadComm(buffer,300); // The idea of TestDACADCbuffercount is to ensure that there are at // least six characters of incoming data available before processing // it. TestDACADCbuffercount++; if (TestDACADCbuffercount>6) { TestDACADCbuffercount=1; } switch (TestDACADCbuffercount) { case 1: strcpy((char *)TestDACADCdata5,(char *)data); break; case 2: strcpy((char *)TestDACADCdata4,(char *)data); break; case 3: strcpy((char *)TestDACADCdata3,(char *)data); break; case 4: strcpy((char *)TestDACADCdata2,(char *)data); break; case 5: strcpy((char *)TestDACADCdata1,(char *)data); break; case 6: strcat((char *)TestDACADCdata5,(char *)TestDACADCdata4); strcat((char *)TestDACADCdata5,(char *)TestDACADCdata3); strcat((char *)TestDACADCdata5,(char *)TestDACADCdata2); strcat((char *)TestDACADCdata5,(char *)TestDACADCdata1); strcat((char *)TestDACADCdata5,(char *)data); int len=strlen((char *)TestDACADCdata5);

Page 232: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

222

// The following lines will decode the data pattern into the // different arrays. Data will be received form the // microcontroller in the following format // [251, Sample Frequency, 252, Input from plant, 253, // Output to plant] // The array may start and end at any point, but the data always // have to be in the same order, for example: the following array // is also a valid data array // [Input from plant, 253, Output to plant, 251, // Sample Frequency] for (int scandata=0;scandata<6;scandata++) { if (TestDACADCdata5[scandata]==251) { for (int count=1+scandata;count<len;count=count+6) { TestDACADCsamplefrequency=TestDACADCdata5[count]; float period=(float) 1/TestDACADCdata5[count]; // The if statement ignores the first period value // since it is not significant. // The first meaningful period value will be available // after one sample cycle on the microcontroler is // finished. if (TestDACADCtimeindex==0) { TestDACADCtime[TestDACADCtimeindex]=0; } else { TestDACADCtime[TestDACADCtimeindex]= TestDACADCtime[TestDACADCtimeindex-1]+period; } TestDACADCtimedisplay=TestDACADCtime[TestDACADCtimeindex]; TestDACADCtimeindex++; } } else if (TestDACADCdata5[scandata]==252) { for (int count=1+scandata;count<len;count=count+6) { TestDACADCinputdisplay=TestDACADCdata5[count]; TestDACADCinput[TestDACADCinputindex]= TestDACADCdata5[count]; TestDACADCinputindex++; } } else if (TestDACADCdata5[scandata]==253) { for (int count=1+scandata;count<len;count=count+6) { TestDACADCoutputdisplay=TestDACADCdata5[count]; TestDACADCoutput[TestDACADCoutputindex] =TestDACADCdata5[count];

Page 233: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

223

TestDACADCoutputindex++; } } }// end for scandata break; }// end switch } //-------------------------------------------------------------------- void __fastcall TMonitorForm::TestDACADCDelayEditEnter( TObject *Sender) { TestDACADCDelayEdit->SelStart=0; TestDACADCRunButton->Enabled=false; } //-------------------------------------------------------------------- void __fastcall TMonitorForm::TestDACADCDelayEditExit(TObject *Sender) { char *pTestDACADCDelay; pTestDACADCDelay=MonitorForm->TestDACADCDelayEdit-> EditText.c_str(); int TestDACADCDelay=atoi(pTestDACADCDelay); if (TestDACADCDelay>255) { Max255Form->ShowModal(); MonitorForm->TestDACADCDelayEdit->SetFocus(); } } //-------------------------------------------------------------------- void __fastcall TMonitorForm::TestDACADCSamplefreqEditExit( TObject *Sender) { char *pTestDACADCSamplefreq; pTestDACADCSamplefreq=MonitorForm->TestDACADCSamplefreqEdit-> EditText.c_str(); int TestDACADCSamplefreq=atoi(pTestDACADCSamplefreq); if (TestDACADCSamplefreq>255) { Max255Form->ShowModal(); MonitorForm->TestDACADCSamplefreqEdit->SetFocus(); } } //-------------------------------------------------------------------- void __fastcall TMonitorForm::TestDACADCSamplefreqEditEnter( TObject *Sender) { TestDACADCSamplefreqEdit->SelStart=0; TestDACADCRunButton->Enabled=false; } //-------------------------------------------------------------------- void __fastcall TMonitorForm::TestDACADCPWMEditEnter(TObject *Sender) { TestDACADCPWMEdit->SelStart=0; TestDACADCRunButton->Enabled=false; }

Page 234: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

224

//-------------------------------------------------------------------- void __fastcall TMonitorForm::TestDACADCPWMEditExit(TObject *Sender) { char *pTestDACADCPWM; pTestDACADCPWM=MonitorForm->TestDACADCPWMEdit-> EditText.c_str(); int TestDACADCPWM=atoi(pTestDACADCPWM); if (TestDACADCPWM>255) { Max255Form->ShowModal(); MonitorForm->TestDACADCPWMEdit->SetFocus(); } if (TestDACADCPWM<40) { Min40Form->ShowModal(); MonitorForm->TestDACADCPWMEdit->SetFocus(); } } //-------------------------------------------------------------------- void __fastcall TMonitorForm::TestDACADCPortBSelectClick( TObject *Sender) // TestDACADCCode1 : Input=Analog on PE5, Output=8-bit (PB0-PB7) // TestDACADCCode2 : Input=Frequency on IC3, Output=8-bit (PB0-PB7) // TestDACADCCode3 : Input=Frequency on IC3, Output=PWM on OC3 (PA5) // TestDACADCCode4 : Input=Analog on PE5, Output=PWM on OC3 (PA5) { PWMLabel->Enabled=false; TestDACADCPWMEdit->Enabled=false; TestDACADCRunButton->Enabled=false; TestDACADCOutputLabel->Caption="8-bit parallel output"; //AnsiString s19filename; if (TestDACADCFrequencySelect->Checked) { //s19filename="testdac2.s19"; testdacinoutcombination=2; } else { //s19filename="testdac1.s19"; testdacinoutcombination=1; } //MonitorForm->TestDACADCCode->Lines->LoadFromFile(s19filename); } //-------------------------------------------------------------------- void __fastcall TMonitorForm::TestDACADCPWMSelectClick( TObject *Sender) // TestDACADCCode1 : Input=Analog on PE5, Output=8-bit (PB0-PB7) // TestDACADCCode2 : Input=Frequency on IC3, Output=8-bit (PB0-PB7) // TestDACADCCode3 : Input=Frequency on IC3, Output=PWM on OC3 (PA5) // TestDACADCCode4 : Input=Analog on PE5, Output=PWM on OC3 (PA5) { PWMLabel->Enabled=true; TestDACADCPWMEdit->Enabled=true; TestDACADCRunButton->Enabled=false;

Page 235: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

225

TestDACADCOutputLabel->Caption="PWM Output on OC3(PA5)"; //AnsiString s19filename; if (TestDACADCFrequencySelect->Checked) { //s19filename="testdac3.s19"; testdacinoutcombination=3; } else { //s19filename="testdac4.s19"; testdacinoutcombination=4; } //MonitorForm->TestDACADCCode->Lines->LoadFromFile(s19filename); } //-------------------------------------------------------------------- void __fastcall TMonitorForm::TestDACADCAnalogSelectClick( TObject *Sender) // TestDACADCCode1 : Input=Analog on PE5, Output=8-bit (PB0-PB7) // TestDACADCCode2 : Input=Frequency on IC3, Output=8-bit (PB0-PB7) // TestDACADCCode3 : Input=Frequency on IC3, Output=PWM on OC3 (PA5) // TestDACADCCode4 : Input=Analog on PE5, Output=PWM on OC3 (PA5) { TestDACADCRunButton->Enabled=false; MonitorForm->TestDACADCInputLabel->Caption="Analog Input on PE5"; //AnsiString s19filename; if (TestDACADCPortBSelect->Checked) { //s19filename="testdac1.s19"; testdacinoutcombination=1; } else { //s19filename="testdac4.s19"; testdacinoutcombination=4; } //MonitorForm->TestDACADCCode->Lines->LoadFromFile(s19filename); } //-------------------------------------------------------------------- void __fastcall TMonitorForm::TestDACADCFrequencySelectClick( TObject *Sender) // TestDACADCCode1 : Input=Analog on PE5, Output=8-bit (PB0-PB7) // TestDACADCCode2 : Input=Frequency on IC3, Output=8-bit (PB0-PB7) // TestDACADCCode3 : Input=Frequency on IC3, Output=PWM on OC3 (PA5) // TestDACADCCode4 : Input=Analog on PE5, Output=PWM on OC3 (PA5) { TestDACADCRunButton->Enabled=false; MonitorForm->TestDACADCInputLabel-> Caption="Frequency input on IC3 (PA0)"; //AnsiString s19filename; if (TestDACADCPortBSelect->Checked) { //s19filename="testdac2.s19";

Page 236: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

226

testdacinoutcombination=2; } else { //s19filename="testdac3.s19"; testdacinoutcombination=3; } //MonitorForm->TestDACADCCode->Lines->LoadFromFile(s19filename); } //-------------------------------------------------------------------- void __fastcall TMonitorForm::PIDPWMEditEnter(TObject *Sender) { PIDPWMEdit->SelStart=0; } //-------------------------------------------------------------------- void __fastcall TMonitorForm::PIDPWMEditExit(TObject *Sender) { char *pPIDPWM; pPIDPWM=MonitorForm->PIDPWMEdit->EditText.c_str(); int PIDPWM=atoi(pPIDPWM); if (PIDPWM>255) { Max255Form->ShowModal(); MonitorForm->PIDPWMEdit->SetFocus(); } if (PIDPWM<40) { Min40Form->ShowModal(); MonitorForm->PIDPWMEdit->SetFocus(); } } //-------------------------------------------------------------------- void __fastcall TMonitorForm::PIDPortBSelectClick(TObject *Sender) // PIDCode1 : Input=Analog on PE5, Output=8-bit (PB0-PB7) // PIDCode2 : Input=Frequency on IC3, Output=8-bit (PB0-PB7) // PIDCode3 : Input=Frequency on IC3, Output=PWM on OC3 (PA5) // PIDCode4 : Input=Analog on PE5, Output=PWM on OC3 (PA5) { PIDPWMLabel->Enabled=false; PIDPWMEdit->Enabled=false; PIDRunButton->Enabled=false; PIDOutputLabel->Caption="8-bit parallel output"; //AnsiString s19filename; if (PIDFrequencySelect->Checked) { pidinoutcombination=2; //s19filename="digital2.s19"; } else { pidinoutcombination=1; //s19filename="digital1.s19"; }

Page 237: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

227

//MonitorForm->DigitalCode->Lines->LoadFromFile(s19filename); } //-------------------------------------------------------------------- void __fastcall TMonitorForm::PIDPWMSelectClick(TObject *Sender) // PIDCode1 : Input=Analog on PE5, Output=8-bit (PB0-PB7) // PIDCode2 : Input=Frequency on IC3, Output=8-bit (PB0-PB7) // PIDCode3 : Input=Frequency on IC3, Output=PWM on OC3 (PA5) // PIDCode4 : Input=Analog on PE5, Output=PWM on OC3 (PA5) { PIDPWMLabel->Enabled=true; PIDPWMEdit->Enabled=true; PIDRunButton->Enabled=false; PIDOutputLabel->Caption="PWM Output on OC3(PA5)"; //AnsiString s19filename; if (PIDFrequencySelect->Checked) { pidinoutcombination=3; //s19filename="digital3.s19"; } else { pidinoutcombination=4; //s19filename="digital4.s19"; } //MonitorForm->DigitalCode->Lines->LoadFromFile(s19filename); } //-------------------------------------------------------------------- void __fastcall TMonitorForm::PIDAnalogSelectClick(TObject *Sender) // PIDCode1 : Input=Analog on PE5, Output=8-bit (PB0-PB7) // PIDCode2 : Input=Frequency on IC3, Output=8-bit (PB0-PB7) // PIDCode3 : Input=Frequency on IC3, Output=PWM on OC3 (PA5) // PIDCode4 : Input=Analog on PE5, Output=PWM on OC3 (PA5) { PIDRunButton->Enabled=false; MonitorForm->PIDInputLabel->Caption="Analog Input on PE5"; //AnsiString s19filename; if (PIDPortBSelect->Checked) { pidinoutcombination=1; //s19filename="digital1.s19"; } else { pidinoutcombination=4; //s19filename="digital4.s19"; } //MonitorForm->DigitalCode->Lines->LoadFromFile(s19filename); } //-------------------------------------------------------------------- void __fastcall TMonitorForm::PIDFrequencySelectClick(TObject *Sender) // PIDCode1 : Input=Analog on PE5, Output=8-bit (PB0-PB7)

Page 238: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

228

// PIDCode2 : Input=Frequency on IC3, Output=8-bit (PB0-PB7) // PIDCode3 : Input=Frequency on IC3, Output=PWM on OC3 (PA5) // PIDCode4 : Input=Analog on PE5, Output=PWM on OC3 (PA5) { PIDRunButton->Enabled=false; MonitorForm->PIDInputLabel->Caption="Frequency input on IC3 (PA0)"; //AnsiString s19filename; if (PIDPortBSelect->Checked) { pidinoutcombination=2; //s19filename="digital2.s19"; } else { pidinoutcombination=3; //s19filename="digital3.s19"; } //MonitorForm->DigitalCode->Lines->LoadFromFile(s19filename); } //-------------------------------------------------------------------- void __fastcall TMonitorForm::DigitalDownloadButtonClick( TObject *Sender) { if (DigitalSetpointEdit->EditText==" " || DigitalA0Edit->EditText==" " || DigitalA1Edit->EditText==" " || DigitalA2Edit->EditText==" " || DigitalA3Edit->EditText==" " || DigitalA4Edit->EditText==" " || DigitalB0Edit->EditText==" " || DigitalB1Edit->EditText==" " || DigitalB2Edit->EditText==" " || DigitalB3Edit->EditText==" " || DigitalB4Edit->EditText==" " || DigitalSamplefreqEdit->EditText==" " || DigitalPWMEdit->EditText==" ") { InsufficientDataForm->ShowModal(); // An error message will be // displayed if any of the // data entry fields is empty. } else { unsigned char chksum; unsigned char vars[50]; // ! char *psetp; int setp; psetp=DigitalSetpointEdit->Text.c_str(); setp=atoi(psetp); vars[0]=(unsigned char)setp; // Convert the variables //from text to float

Page 239: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

229

char *pstrA0; float A0; unsigned int adrA0; float *pA0; unsigned char A0_byte0; unsigned char A0_byte1; unsigned char A0_byte2; unsigned char A0_byte3; AnsiString ansiA0=DigitalA0Edit->Text; pstrA0=ansiA0.c_str(); A0=atof(pstrA0); pA0=&A0; adrA0=(int)pA0; (char *) adrA0; (char *) (adrA0+1); (char *) (adrA0+2); (char *) (adrA0+3); A0_byte3=*(char *) adrA0; A0_byte2=*(char *) (adrA0+1); A0_byte1=*(char *) (adrA0+2); A0_byte0=*(char *) (adrA0+3); vars[1]=A0_byte0; vars[2]=A0_byte1; vars[3]=A0_byte2; vars[4]=A0_byte3; char *pstrA1; float A1; unsigned int adrA1; float *pA1; unsigned char A1_byte0; unsigned char A1_byte1; unsigned char A1_byte2; unsigned char A1_byte3; AnsiString ansiA1=DigitalA1Edit->Text; pstrA1=ansiA1.c_str(); A1=atof(pstrA1); pA1=&A1; adrA1=(int)pA1; (char *) adrA1; (char *) (adrA1+1); (char *) (adrA1+2); (char *) (adrA1+3); A1_byte3=*(char *) adrA1; A1_byte2=*(char *) (adrA1+1); A1_byte1=*(char *) (adrA1+2); A1_byte0=*(char *) (adrA1+3); vars[5]=A1_byte0; vars[6]=A1_byte1; vars[7]=A1_byte2; vars[8]=A1_byte3; char *pstrA2; float A2;

Page 240: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

230

unsigned int adrA2; float *pA2; unsigned char A2_byte0; unsigned char A2_byte1; unsigned char A2_byte2; unsigned char A2_byte3; AnsiString ansiA2=DigitalA2Edit->Text; pstrA2=ansiA2.c_str(); A2=atof(pstrA2); pA2=&A2; adrA2=(int)pA2; (char *) adrA2; (char *) (adrA2+1); (char *) (adrA2+2); (char *) (adrA2+3); A2_byte3=*(char *) adrA2; A2_byte2=*(char *) (adrA2+1); A2_byte1=*(char *) (adrA2+2); A2_byte0=*(char *) (adrA2+3); vars[9]=A2_byte0; vars[10]=A2_byte1; vars[11]=A2_byte2; vars[12]=A2_byte3; char *pstrA3; float A3; unsigned int adrA3; float *pA3; unsigned char A3_byte0; unsigned char A3_byte1; unsigned char A3_byte2; unsigned char A3_byte3; AnsiString ansiA3=DigitalA3Edit->Text; pstrA3=ansiA3.c_str(); A3=atof(pstrA3); pA3=&A3; adrA3=(int)pA3; (char *) adrA3; (char *) (adrA3+1); (char *) (adrA3+2); (char *) (adrA3+3); A3_byte3=*(char *) adrA3; A3_byte2=*(char *) (adrA3+1); A3_byte1=*(char *) (adrA3+2); A3_byte0=*(char *) (adrA3+3); vars[13]=A3_byte0; vars[14]=A3_byte1; vars[15]=A3_byte2; vars[16]=A3_byte3; char *pstrA4; float A4; unsigned int adrA4; float *pA4;

Page 241: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

231

unsigned char A4_byte0; unsigned char A4_byte1; unsigned char A4_byte2; unsigned char A4_byte3; AnsiString ansiA4=DigitalA4Edit->Text; pstrA4=ansiA4.c_str(); A4=atof(pstrA4); pA4=&A4; adrA4=(int)pA4; (char *) adrA4; (char *) (adrA4+1); (char *) (adrA4+2); (char *) (adrA4+3); A4_byte3=*(char *) adrA4; A4_byte2=*(char *) (adrA4+1); A4_byte1=*(char *) (adrA4+2); A4_byte0=*(char *) (adrA4+3); vars[17]=A4_byte0; vars[18]=A4_byte1; vars[19]=A4_byte2; vars[20]=A4_byte3; char *pstrB0; float B0; unsigned int adrB0; float *pB0; unsigned char B0_byte0; unsigned char B0_byte1; unsigned char B0_byte2; unsigned char B0_byte3; AnsiString ansiB0=DigitalB0Edit->Text; pstrB0=ansiB0.c_str(); B0=atof(pstrB0); pB0=&B0; adrB0=(int)pB0; (char *) adrB0; (char *) (adrB0+1); (char *) (adrB0+2); (char *) (adrB0+3); B0_byte3=*(char *) adrB0; B0_byte2=*(char *) (adrB0+1); B0_byte1=*(char *) (adrB0+2); B0_byte0=*(char *) (adrB0+3); vars[21]=B0_byte0; vars[22]=B0_byte1; vars[23]=B0_byte2; vars[24]=B0_byte3; char *pstrB1; float B1; unsigned int adrB1; float *pB1; unsigned char B1_byte0; unsigned char B1_byte1;

Page 242: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

232

unsigned char B1_byte2; unsigned char B1_byte3; AnsiString ansiB1=DigitalB1Edit->Text; pstrB1=ansiB1.c_str(); B1=atof(pstrB1); pB1=&B1; adrB1=(int)pB1; (char *) adrB1; (char *) (adrB1+1); (char *) (adrB1+2); (char *) (adrB1+3); B1_byte3=*(char *) adrB1; B1_byte2=*(char *) (adrB1+1); B1_byte1=*(char *) (adrB1+2); B1_byte0=*(char *) (adrB1+3); vars[25]=B1_byte0; vars[26]=B1_byte1; vars[27]=B1_byte2; vars[28]=B1_byte3; char *pstrB2; float B2; unsigned int adrB2; float *pB2; unsigned char B2_byte0; unsigned char B2_byte1; unsigned char B2_byte2; unsigned char B2_byte3; AnsiString ansiB2=DigitalB2Edit->Text; pstrB2=ansiB2.c_str(); B2=atof(pstrB2); pB2=&B2; adrB2=(int)pB2; (char *) adrB2; (char *) (adrB2+1); (char *) (adrB2+2); (char *) (adrB2+3); B2_byte3=*(char *) adrB2; B2_byte2=*(char *) (adrB2+1); B2_byte1=*(char *) (adrB2+2); B2_byte0=*(char *) (adrB2+3); vars[29]=B2_byte0; vars[30]=B2_byte1; vars[31]=B2_byte2; vars[32]=B2_byte3; char *pstrB3; float B3; unsigned int adrB3; float *pB3; unsigned char B3_byte0; unsigned char B3_byte1; unsigned char B3_byte2; unsigned char B3_byte3;

Page 243: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

233

AnsiString ansiB3=DigitalB3Edit->Text; pstrB3=ansiB3.c_str(); B3=atof(pstrB3); pB3=&B3; adrB3=(int)pB3; (char *) adrB3; (char *) (adrB3+1); (char *) (adrB3+2); (char *) (adrB3+3); B3_byte3=*(char *) adrB3; B3_byte2=*(char *) (adrB3+1); B3_byte1=*(char *) (adrB3+2); B3_byte0=*(char *) (adrB3+3); vars[33]=B3_byte0; vars[34]=B3_byte1; vars[35]=B3_byte2; vars[36]=B3_byte3; char *pstrB4; float B4; unsigned int adrB4; float *pB4; unsigned char B4_byte0; unsigned char B4_byte1; unsigned char B4_byte2; unsigned char B4_byte3; AnsiString ansiB4=DigitalB4Edit->Text; pstrB4=ansiB4.c_str(); B4=atof(pstrB4); pB4=&B4; adrB4=(int)pB4; (char *) adrB4; (char *) (adrB4+1); (char *) (adrB4+2); (char *) (adrB4+3); B4_byte3=*(char *) adrB4; B4_byte2=*(char *) (adrB4+1); B4_byte1=*(char *) (adrB4+2); B4_byte0=*(char *) (adrB4+3); vars[37]=B4_byte0; vars[38]=B4_byte1; vars[39]=B4_byte2; vars[40]=B4_byte3; char *psamplefreq; int samplefreq; psamplefreq=DigitalSamplefreqEdit->Text.c_str(); samplefreq=atoi(psamplefreq); vars[41]=(unsigned char)samplefreq; char *ppwmhz; int pwmhz; ppwmhz=DigitalPWMEdit->Text.c_str(); pwmhz=atoi(ppwmhz);

Page 244: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

234

vars[42]=(unsigned char)pwmhz; // Check whether positive or feedback or negative feedback was // selected. // A 1 will be transmitted to the microcontroller for negative // feedback and a 2 will be transmitted for positive feedback. if (DigitalNegativeFeedbackSelect->Checked) { vars[43]=1; //Negative feedback } else { vars[43]=2; //Positive feedback } char *poutputupperlimit; int outputupperlimit; poutputupperlimit=DigitalOutputupperlimitEdit->Text.c_str(); outputupperlimit=atoi(poutputupperlimit); vars[44]=(unsigned char)outputupperlimit; char *poutputlowerlimit; int outputlowerlimit; poutputlowerlimit=DigitalOutputlowerlimitEdit->Text.c_str(); outputlowerlimit=atoi(poutputlowerlimit); vars[45]=(unsigned char)outputlowerlimit; char *pinputupperlimit; int inputupperlimit; pinputupperlimit=DigitalInputupperlimitEdit->Text.c_str(); inputupperlimit=atoi(pinputupperlimit); vars[46]=(unsigned char)inputupperlimit; char *pinputlowerlimit; int inputlowerlimit; pinputlowerlimit=DigitalInputlowerlimitEdit->Text.c_str(); inputlowerlimit=atoi(pinputlowerlimit); vars[47]=(unsigned char)inputlowerlimit; vars[48]=digitalinoutcombination; // The checksum byte will be added to the s-record line. // The checksum is the complement of the 8-bit sum of all the // bytes in the s-record line. int lenvars=49; unsigned char sum=0; for (int count1=0;count1<lenvars;count1++) { sum=sum+vars[count1]; } chksum=255-52-sum; // The second term indicates the number // of bytes which will be transmitted plus three (2 byte memory // location and 1 byte checksum). char addline[100]="S1340000"; // Hex 34 indicates the number of

Page 245: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

235

int count; for (count=0;count<lenvars;count++) // Convert the decimal variables // into hexadecimal values { char temp[3]; if (vars[count]<16) sprintf(temp,"0%X",vars[count]); // Add a '0' if the // hexidecimal value is a // single digit value. else sprintf(temp,"%X",vars[count]); strcat(addline,temp); // Add the hexideciml value to the // s-record line. } char temp[3]; if (chksum<16) sprintf(temp,"0%X",chksum); // Add a '0' if the hexidecimal // value is a single digit value else sprintf(temp,"%X",chksum); strcat(addline,temp); // add the 8-bit checksum value // to the s-record line Download1->Memo1->Lines->Text=DigitalCode->Lines->Text; Download1->Memo1->Lines->Insert(1,addline); // Add the complete // existing control //algorithm. Download1->ShowModal(); // Start download procedure } } //-------------------------------------------------------------------- void __fastcall TMonitorForm::DigitalMonitorButtonClick( TObject *Sender) // This event handler will enable serial communication between the // microcontroller and the PC and will enable and disable all the // appropriate buttons on the main form. // When data is available from the serial port, an OnDataAvailable // event will be triggered and the MonitorCommDataAvailable event // handler will be called which will handle the incomming data // received from the microcontroller. { DigitalComm->OpenConnection(); DigitalRecordButton->Enabled=true; DigitalMonitorButton->Enabled=false; DigitalDisconnectButton->Enabled=true; DigitalDownloadButton->Enabled=false; DigitalRunButton->Enabled=false; } //-------------------------------------------------------------------- void __fastcall TMonitorForm::DigitalDisconnectButtonClick(

Page 246: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

236

TObject *Sender) // This event handler will disable serial communication between the // microcontroller and the PC and will enable and disable all the // appropriate buttons on the main form. { DigitalComm->CloseConnection(); DigitalRecordButton->Enabled=false; DigitalMonitorButton->Enabled=true; DigitalDisconnectButton->Enabled=false; DigitalDownloadButton->Enabled=true; DigitalRunButton->Enabled=true; } //-------------------------------------------------------------------- void __fastcall TMonitorForm::DigitalRecordButtonClick( TObject *Sender) { // This routine will start the data recording process and will enable // and disable all the appropriate buttons related to this recording // action. DigitalDisconnectButton->Enabled=false; DigitalPlotButton->Enabled=false; DigitalSaveButton->Enabled=false; DigitalStopButton->Enabled=true; DigitalRecordButton->Enabled=false; PlotForm1->XYPlot1->RemovePlot(1); PlotForm1->XYPlot1->RemovePlot(2); // Clear the current plot. Digitaloutputindex=0; Digitalinputindex=0; Digitaltimeindex=0; } //-------------------------------------------------------------------- void __fastcall TMonitorForm::DigitalStopButtonClick(TObject *Sender) { // This routine will stop data recording process and will enable // and disable all the appropriate buttons related to this stopping // action. Digitaltimeindexstop=min(Digitaltimeindex,Digitalinputindex); Digitaltimeindexstop=min(Digitaloutputindex,Digitaltimeindexstop); DigitalDisconnectButton->Enabled=true; SaveButton->Enabled=true; DigitalPlotButton->Enabled=true; DigitalSaveButton->Enabled=true; DigitalStopButton->Enabled=false; DigitalRecordButton->Enabled=true; for (int count=0;count<Digitaltimeindexstop;count++) { Digitaltimerecorded[count]=Digitaltime[count]; Digitalinputrecorded[count]=Digitalinput[count]; Digitaloutputrecorded[count]=Digitaloutput[count];

Page 247: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

237

} } //-------------------------------------------------------------------- void __fastcall TMonitorForm::DigitalPlotButtonClick(TObject *Sender) { // TXYPlot is a Borland C++ Builder VCL plotting component for // graphing x,y data. It is used to plot the recorded data // versus time. PlotForm1->Show(); PlotForm1->Caption="Input From Plant"; PlotForm1->XYPlot1->XAutoScale=true; PlotForm1->XYPlot1->YAutoScale=true; if (MonitorForm->PlotLines1->Checked) { PlotForm1->XYPlot1->XYPlot(Digitaltimerecorded, Digitalinputrecorded,Digitaltimeindexstop,1, clBlue,LinesFilledPoints); } else { PlotForm1->XYPlot1->XYPlot(Digitaltimerecorded, Digitalinputrecorded,Digitaltimeindexstop,1, clBlue,FilledPoints); } PlotForm2->Show(); PlotForm2->Caption="Output to Plant"; PlotForm2->XYPlot1->XAutoScale=true; PlotForm2->XYPlot1->YAutoScale=true; if (MonitorForm->PlotLines1->Checked) { PlotForm2->XYPlot1->XYPlot(Digitaltimerecorded, Digitaloutputrecorded,Digitaltimeindexstop,1, clBlue,LinesFilledPoints); } else { PlotForm2->XYPlot1->XYPlot(Digitaltimerecorded, Digitaloutputrecorded,Digitaltimeindexstop,1, clBlue,FilledPoints); } } //-------------------------------------------------------------------- void __fastcall TMonitorForm::UsersManual1Click(TObject *Sender) { Application->HelpContext(0); } //-------------------------------------------------------------------- void __fastcall TMonitorForm::DigitalController1Click(TObject *Sender) { // This event handler will enable and display the PID controller // panel on which all the controls and editboxes for the PID

Page 248: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

238

// controller are displayed. MonitorForm->Caption= "HC11Control - Single-Input-Single-Output Digital Controller"; DigitalController1->Checked=true; MonitorForm->DigitalPanel->Visible=true; MonitorForm->DigitalPanel->Enabled=true; MonitorForm->N68HC11Programs1->Enabled=false; MonitorForm->New1->Enabled=true; // Load microcontroller code from s-record file AnsiString s19filename="digital.s19"; MonitorForm->DigitalCode->Lines->LoadFromFile(s19filename); } //-------------------------------------------------------------------- void __fastcall TMonitorForm::DigitalCommDataAvailable( TObject *Sender) { unsigned char *buffer,data[300]; buffer=data; // Clear the input buffer by writing zero's to it for (int n=0;n<=300;n++) { data[n]=0; } DigitalComm->ReadComm(buffer,300); // The idea of Digitalbuffercount is to ensure that there are at least // six characters of incoming data available before processing it. Digitalbuffercount++; if (Digitalbuffercount>6) { Digitalbuffercount=1; } switch (Digitalbuffercount) { case 1: strcpy((char *)Digitaldata5,(char *)data); break; case 2: strcpy((char *)Digitaldata4,(char *)data); break; case 3: strcpy((char *)Digitaldata3,(char *)data); break; case 4: strcpy((char *)Digitaldata2,(char *)data); break; case 5: strcpy((char *)Digitaldata1,(char *)data); break; case 6: strcat((char *)Digitaldata5,(char *)Digitaldata4); strcat((char *)Digitaldata5,(char *)Digitaldata3); strcat((char *)Digitaldata5,(char *)Digitaldata2);

Page 249: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

239

strcat((char *)Digitaldata5,(char *)Digitaldata1); strcat((char *)Digitaldata5,(char *)data); unsigned int len=strlen((char *)Digitaldata5); // The following lines will decode the data pattern into the // different arrays. Data will be received form the // microcontroller in the following format // [251, Sample Frequency, 252, Input from plant, 253, // Output to plant] // The array may start and end at any point, but the data always // have to be in the same order, for example: the following array // is also a valid data array // [Input from plant, 253, Output to plant, 251, // Sample Frequency] for (int scandata=0;scandata<6;scandata++) { if (Digitaldata5[scandata]==251) { for (unsigned int count=1+scandata;count<len;count=count+6) { Digitalsamplefrequency=Digitaldata5[count]; float period=(float) 1/Digitaldata5[count]; // The if statement ignores the first period value // since it is not significant. // The first meaningful period value will be available // after one sample cycle on the microcontroler is // finished. if (Digitaltimeindex==0) { Digitaltime[Digitaltimeindex]=0; } else { Digitaltime[Digitaltimeindex]= Digitaltime[Digitaltimeindex-1]+period; } Digitaltimedisplay=Digitaltime[Digitaltimeindex]; Digitaltimeindex++; } } else if (Digitaldata5[scandata]==252) { for (unsigned int count=1+scandata;count<len;count=count+6) { Digitalinputdisplay=Digitaldata5[count]; Digitalinput[Digitalinputindex]=Digitaldata5[count]; Digitalinputindex++; } } else if (Digitaldata5[scandata]==253) { for (unsigned int count=1+scandata;count<len;count=count+6)

Page 250: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

240

{ Digitaloutputdisplay=Digitaldata5[count]; Digitaloutput[Digitaloutputindex]=Digitaldata5[count]; Digitaloutputindex++; } } }// end for scandata break; }// end switch } //-------------------------------------------------------------------- void __fastcall TMonitorForm::DigitalDisplayTimerTimer( TObject *Sender) { // // This event handler will display the data received from the // microcontroller with every time interval of the timer. // The time interval can be set with the 'interval' property // of the timer component. // DigitalInputDigitBox->Target=Digitalinputdisplay; DigitalInputDigitBox->Value=Digitalinputdisplay; DigitalOutputDigitBox->Target=Digitaloutputdisplay; DigitalOutputDigitBox->Value=Digitaloutputdisplay; DigitalSamplefreqDigitBox->Target=Digitalsamplefrequency; DigitalSamplefreqDigitBox->Value=Digitalsamplefrequency; // The stopbutton will only be enabled when recording // in in progress. if (DigitalStopButton->Enabled==true) { DigitalTimeDigitBox->Target=Digitaltimedisplay; DigitalTimeDigitBox->Value=Digitaltimedisplay; } } //-------------------------------------------------------------------- void __fastcall TMonitorForm::DigitalPortBSelectClick(TObject *Sender) // DigitalCode1 : Input=Analog on PE5, Output=8-bit (PB0-PB7) // DigitalCode2 : Input=Frequency on IC3, Output=8-bit (PB0-PB7) // DigitalCode3 : Input=Frequency on IC3, Output=PWM on OC3 (PA5) // DigitalCode4 : Input=Analog on PE5, Output=PWM on OC3 (PA5) { DigitalPWMLabel->Enabled=false; DigitalPWMEdit->Enabled=false; DigitalRunButton->Enabled=false; DigitalOutputLabel->Caption="8-bit Parallel Output"; if (DigitalFrequencySelect->Checked) { digitalinoutcombination=2;

Page 251: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

241

} else { digitalinoutcombination=1; } } //-------------------------------------------------------------------- void __fastcall TMonitorForm::DigitalPWMSelectClick(TObject *Sender) // Combination1 : Input=Analog on PE5, Output=8-bit (PB0-PB7) // Combination2 : Input=Frequency on IC3, Output=8-bit (PB0-PB7) // Combination3 : Input=Frequency on IC3, Output=PWM on OC3 (PA5) // Combination4 : Input=Analog on PE5, Output=PWM on OC3 (PA5) { DigitalPWMLabel->Enabled=true; DigitalPWMEdit->Enabled=true; DigitalRunButton->Enabled=false; DigitalOutputLabel->Caption="PWM Output on OC3(PA5)"; if (DigitalFrequencySelect->Checked) { digitalinoutcombination=3; } else { digitalinoutcombination=4; } } //-------------------------------------------------------------------- void __fastcall TMonitorForm::DigitalAnalogSelectClick( TObject *Sender) // Combination1 : Input=Analog on PE5, Output=8-bit (PB0-PB7) // Combination2 : Input=Frequency on IC3, Output=8-bit (PB0-PB7) // Combination3 : Input=Frequency on IC3, Output=PWM on OC3 (PA5) // Combination4 : Input=Analog on PE5, Output=PWM on OC3 (PA5) { DigitalRunButton->Enabled=false; MonitorForm->DigitalInputLabel->Caption="Analog Input on PE5"; if (DigitalPortBSelect->Checked) { digitalinoutcombination=1; } else { digitalinoutcombination=4; } } //-------------------------------------------------------------------- void __fastcall TMonitorForm::DigitalFrequencySelectClick( TObject *Sender) // Combination1 : Input=Analog on PE5, Output=8-bit (PB0-PB7) // Combination2 : Input=Frequency on IC3, Output=8-bit (PB0-PB7) // Combination3 : Input=Frequency on IC3, Output=PWM on OC3 (PA5)

Page 252: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

242

// Combination4 : Input=Analog on PE5, Output=PWM on OC3 (PA5) { DigitalRunButton->Enabled=false; MonitorForm->DigitalInputLabel-> Caption="Frequency Input on IC3 (PA0)"; if (DigitalPortBSelect->Checked) { digitalinoutcombination=2; } else { digitalinoutcombination=3; } } //-------------------------------------------------------------------- void __fastcall TMonitorForm::DigitalSetpointEditClick( TObject *Sender) { DigitalSetpointEdit->SelStart=0; } //-------------------------------------------------------------------- void __fastcall TMonitorForm::DigitalSetpointEditExit(TObject *Sender) { char *psetp; psetp=MonitorForm->DigitalSetpointEdit->EditText.c_str(); int setp=atoi(psetp); if (setp>255) { Max255Form->ShowModal(); MonitorForm->DigitalSetpointEdit->SetFocus(); } } //-------------------------------------------------------------------- void __fastcall TMonitorForm::DigitalB0EditClick(TObject *Sender) { DigitalB0Edit->SelStart=0; } //-------------------------------------------------------------------- void __fastcall TMonitorForm::DigitalB1EditClick(TObject *Sender) { DigitalB1Edit->SelStart=0; } //-------------------------------------------------------------------- void __fastcall TMonitorForm::DigitalB2EditClick(TObject *Sender) { DigitalB2Edit->SelStart=0; } //-------------------------------------------------------------------- void __fastcall TMonitorForm::DigitalB3EditClick(TObject *Sender) { DigitalB3Edit->SelStart=0; } //--------------------------------------------------------------------

Page 253: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

243

void __fastcall TMonitorForm::DigitalB4EditClick(TObject *Sender) { DigitalB4Edit->SelStart=0; } //-------------------------------------------------------------------- void __fastcall TMonitorForm::DigitalA0EditClick(TObject *Sender) { DigitalA0Edit->SelStart=0; } //-------------------------------------------------------------------- void __fastcall TMonitorForm::DigitalA1EditClick(TObject *Sender) { DigitalA1Edit->SelStart=0; } //-------------------------------------------------------------------- void __fastcall TMonitorForm::DigitalA2EditClick(TObject *Sender) { DigitalA2Edit->SelStart=0; } //-------------------------------------------------------------------- void __fastcall TMonitorForm::DigitalA3EditClick(TObject *Sender) { DigitalA3Edit->SelStart=0; } //-------------------------------------------------------------------- void __fastcall TMonitorForm::DigitalA4EditClick(TObject *Sender) { DigitalA4Edit->SelStart=0; } //-------------------------------------------------------------------- void __fastcall TMonitorForm::DigitalSamplefreqEditClick( TObject *Sender) { DigitalSamplefreqEdit->SelStart=0; } //-------------------------------------------------------------------- void __fastcall TMonitorForm::DigitalSamplefreqEditExit( TObject *Sender) { char *psamplefreq; psamplefreq=MonitorForm->DigitalSamplefreqEdit->EditText.c_str(); int samplefreq=atoi(psamplefreq); if (samplefreq>255) { Max255Form->ShowModal(); MonitorForm->DigitalSamplefreqEdit->SetFocus(); } } //-------------------------------------------------------------------- void __fastcall TMonitorForm::DigitalOutputupperlimitEditClick( TObject *Sender) { DigitalOutputupperlimitEdit->SelStart=0; }

Page 254: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

244

//-------------------------------------------------------------------- void __fastcall TMonitorForm::DigitalOutputupperlimitEditExit( TObject *Sender) { char *ptemp; ptemp=MonitorForm->DigitalOutputupperlimitEdit->EditText.c_str(); int temp=atoi(ptemp); if (temp>250 || temp<1) { Max250min1Form->ShowModal(); MonitorForm->DigitalOutputupperlimitEdit->SetFocus(); } } //-------------------------------------------------------------------- void __fastcall TMonitorForm::DigitalOutputlowerlimitEditClick( TObject *Sender) { DigitalOutputlowerlimitEdit->SelStart=0; } //-------------------------------------------------------------------- void __fastcall TMonitorForm::DigitalOutputlowerlimitEditExit( TObject *Sender) { char *ptemp; ptemp=MonitorForm->DigitalOutputlowerlimitEdit->EditText.c_str(); int temp=atoi(ptemp); if (temp>250 || temp<1) { Max250min1Form->ShowModal(); MonitorForm->DigitalOutputlowerlimitEdit->SetFocus(); } } //-------------------------------------------------------------------- void __fastcall TMonitorForm::DigitalInputupperlimitEditExit( TObject *Sender) { char *ptemp; ptemp=MonitorForm->DigitalInputupperlimitEdit->EditText.c_str(); int temp=atoi(ptemp); if (temp>250 || temp<1) { Max250min1Form->ShowModal(); MonitorForm->DigitalInputupperlimitEdit->SetFocus(); } } //-------------------------------------------------------------------- void __fastcall TMonitorForm::DigitalInputupperlimitEditClick( TObject *Sender) { DigitalInputupperlimitEdit->SelStart=0; } //-------------------------------------------------------------------- void __fastcall TMonitorForm::DigitalInputlowerlimitEditExit( TObject *Sender)

Page 255: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

245

{ char *ptemp; ptemp=MonitorForm->DigitalInputlowerlimitEdit->EditText.c_str(); int temp=atoi(ptemp); if (temp>250 || temp<1) { Max250min1Form->ShowModal(); MonitorForm->DigitalInputlowerlimitEdit->SetFocus(); } } //-------------------------------------------------------------------- void __fastcall TMonitorForm::DigitalInputlowerlimitEditClick( TObject *Sender) { DigitalInputlowerlimitEdit->SelStart=0; } //-------------------------------------------------------------------- void __fastcall TMonitorForm::PIDInputupperlimitEditClick( TObject *Sender) { PIDInputupperlimitEdit->SelStart=0; } //-------------------------------------------------------------------- void __fastcall TMonitorForm::PIDInputupperlimitEditExit( TObject *Sender) { char *ptemp; ptemp=MonitorForm->PIDInputupperlimitEdit->EditText.c_str(); int temp=atoi(ptemp); if (temp>250 || temp<1) { Max250min1Form->ShowModal(); MonitorForm->PIDInputupperlimitEdit->SetFocus(); } } //-------------------------------------------------------------------- void __fastcall TMonitorForm::PIDInputlowerlimitEditClick( TObject *Sender) { PIDInputlowerlimitEdit->SelStart=0; } //-------------------------------------------------------------------- void __fastcall TMonitorForm::PIDInputlowerlimitEditExit( TObject *Sender) { char *ptemp; ptemp=MonitorForm->PIDInputlowerlimitEdit->EditText.c_str(); int temp=atoi(ptemp); if (temp>250 || temp<1) { Max250min1Form->ShowModal(); MonitorForm->PIDInputlowerlimitEdit->SetFocus(); } }

Page 256: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

246

//-------------------------------------------------------------------- void __fastcall TMonitorForm::PIDOutputupperlimitEditClick( TObject *Sender) { PIDOutputupperlimitEdit->SelStart=0; } //-------------------------------------------------------------------- void __fastcall TMonitorForm::PIDOutputupperlimitEditExit( TObject *Sender) { char *ptemp; ptemp=MonitorForm->PIDOutputupperlimitEdit->EditText.c_str(); int temp=atoi(ptemp); if (temp>250 || temp<1) { Max250min1Form->ShowModal(); MonitorForm->PIDOutputupperlimitEdit->SetFocus(); } } //-------------------------------------------------------------------- void __fastcall TMonitorForm::PIDOutputlowerlimitEditClick( TObject *Sender) { PIDOutputlowerlimitEdit->SelStart=0; } //-------------------------------------------------------------------- void __fastcall TMonitorForm::PIDOutputlowerlimitEditExit( TObject *Sender) { char *ptemp; ptemp=MonitorForm->PIDOutputlowerlimitEdit->EditText.c_str(); int temp=atoi(ptemp); if (temp>250 || temp<1) { Max250min1Form->ShowModal(); MonitorForm->PIDOutputlowerlimitEdit->SetFocus(); } } //-------------------------------------------------------------------- void __fastcall TMonitorForm::MultiController1Click( TObject *Sender) { // This event handler will enable and display the Double-Input- // Double-Output controller panel on which all the controls and // editboxes for this controller are displayed. MonitorForm->Caption= "HC11Control - Double-Input-Double-Output Digital Controller"; MultiController1->Checked=true; MonitorForm->MultiPanel->Visible=true; MonitorForm->MultiPanel->Enabled=true; MonitorForm->N68HC11Programs1->Enabled=false; MonitorForm->New1->Enabled=true;

Page 257: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

247

// Load microcontroller code from s-record file AnsiString s19filename="Multi.s19"; MonitorForm->MultiCode->Lines->LoadFromFile(s19filename); } //-------------------------------------------------------------------- void __fastcall TMonitorForm::MultiMonitorButtonClick(TObject *Sender) // This event handler will enable serial communication between the // microcontroller and the PC and will enable and disable all the // appropriate buttons on the main form. // When data is available from the serial port, an OnDataAvailable // event will be triggered and the MonitorCommDataAvailable event // handler will be called which will handle the incomming data // received from the microcontroller. { MultiComm->OpenConnection(); MultiRecordButton->Enabled=true; MultiMonitorButton->Enabled=false; MultiDisconnectButton->Enabled=true; MultiDownloadButton->Enabled=false; MultiRunButton->Enabled=false; } //-------------------------------------------------------------------- void __fastcall TMonitorForm::MultiDisconnectButtonClick( TObject *Sender) // This event handler will disable serial communication between the // microcontroller and the PC and will enable and disable all the // appropriate buttons on the main form. { MultiComm->CloseConnection(); MultiRecordButton->Enabled=false; MultiMonitorButton->Enabled=true; MultiDisconnectButton->Enabled=false; MultiDownloadButton->Enabled=true; MultiRunButton->Enabled=true; } //-------------------------------------------------------------------- void __fastcall TMonitorForm::MultiRecordButtonClick(TObject *Sender) { // This routine will start the data recording process and will enable // and disable all the appropriate buttons related to this recording // action. MultiDisconnectButton->Enabled=false; MultiPlotButton->Enabled=false; MultiSaveButton->Enabled=false; MultiStopButton->Enabled=true; MultiRecordButton->Enabled=false; PlotForm1->XYPlot1->RemovePlot(1); PlotForm1->XYPlot1->RemovePlot(2); // Clear the current plot.

Page 258: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

248

Multianaloginputindex=0; Multifreqinputindex=0; Multi8bitoutputindex=0; MultiPWMoutputindex=0; Multitimeindex=0; } //-------------------------------------------------------------------- void __fastcall TMonitorForm::MultiStopButtonClick(TObject *Sender) { // This routine will stop data recording process and will enable // and disable all the appropriate buttons related to this stopping // action. Multitimeindexstop=Multitimeindex; MultiDisconnectButton->Enabled=true; SaveButton->Enabled=true; MultiPlotButton->Enabled=true; MultiSaveButton->Enabled=true; MultiStopButton->Enabled=false; MultiRecordButton->Enabled=true; for (int count=0;count<Multitimeindexstop;count++) { Multitimerecorded[count]=Multitime[count]; Multianaloginputrecorded[count]=Multianaloginput[count]; Multifreqinputrecorded[count]=Multifreqinput[count]; Multi8bitoutputrecorded[count]=Multi8bitoutput[count]; MultiPWMoutputrecorded[count]=MultiPWMoutput[count]; } } //-------------------------------------------------------------------- void __fastcall TMonitorForm::MultiPlotButtonClick(TObject *Sender) { // TXYPlot is a Borland C++ Builder VCL plotting component for // graphing x,y data. It is used to plot the recorded data // versus time. PlotForm1->Show(); PlotForm1->Caption="Analog Input From Plant"; PlotForm1->XYPlot1->XAutoScale=true; PlotForm1->XYPlot1->YAutoScale=true; if (MonitorForm->PlotLines1->Checked) { PlotForm1->XYPlot1->XYPlot(Multitimerecorded, Multianaloginputrecorded,Multitimeindexstop,1, clBlue,LinesFilledPoints); } else { PlotForm1->XYPlot1->XYPlot(Multitimerecorded, Multianaloginputrecorded,Multitimeindexstop,1, clBlue,FilledPoints); }

Page 259: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

249

PlotForm2->Show(); PlotForm2->Caption="Frequency Input From Plant"; PlotForm2->XYPlot1->XAutoScale=true; PlotForm2->XYPlot1->YAutoScale=true; if (MonitorForm->PlotLines1->Checked) { PlotForm2->XYPlot1->XYPlot(Multitimerecorded, Multifreqinputrecorded,Multitimeindexstop,1, clBlue,LinesFilledPoints); } else { PlotForm2->XYPlot1->XYPlot(Multitimerecorded, Multifreqinputrecorded,Multitimeindexstop,1, clBlue,FilledPoints); } PlotForm3->Show(); PlotForm3->Caption="8-Bit Output to Plant"; PlotForm3->XYPlot1->XAutoScale=true; PlotForm3->XYPlot1->YAutoScale=true; if (MonitorForm->PlotLines1->Checked) { PlotForm3->XYPlot1->XYPlot(Multitimerecorded, Multi8bitoutputrecorded,Multitimeindexstop,1, clBlue,LinesFilledPoints); } else { PlotForm3->XYPlot1->XYPlot(Multitimerecorded, Multi8bitoutputrecorded,Multitimeindexstop,1, clBlue,FilledPoints); } PlotForm4->Show(); PlotForm4->Caption="PWM Output to Plant"; PlotForm4->XYPlot1->XAutoScale=true; PlotForm4->XYPlot1->YAutoScale=true; if (MonitorForm->PlotLines1->Checked) { PlotForm4->XYPlot1->XYPlot(Multitimerecorded, MultiPWMoutputrecorded,Multitimeindexstop,1, clBlue,LinesFilledPoints); } else { PlotForm4->XYPlot1->XYPlot(Multitimerecorded, MultiPWMoutputrecorded,Multitimeindexstop,1, clBlue,FilledPoints); } } //-------------------------------------------------------------------- void __fastcall TMonitorForm::MultiDownloadButtonClick( TObject *Sender)

Page 260: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

250

{ if (MultiAnalogSetpointEdit->EditText==" " || MultiFrequencySetpointEdit->EditText==" " || MultiP10Edit->EditText==" " || MultiP11Edit->EditText==" " || MultiP12Edit->EditText==" " || MultiP13Edit->EditText==" " || MultiP14Edit->EditText==" " || MultiP20Edit->EditText==" " || MultiP21Edit->EditText==" " || MultiP22Edit->EditText==" " || MultiP23Edit->EditText==" " || MultiP24Edit->EditText==" " || MultiQ10Edit->EditText==" " || MultiQ11Edit->EditText==" " || MultiQ12Edit->EditText==" " || MultiQ13Edit->EditText==" " || MultiQ14Edit->EditText==" " || MultiQ20Edit->EditText==" " || MultiQ21Edit->EditText==" " || MultiQ22Edit->EditText==" " || MultiQ23Edit->EditText==" " || MultiQ24Edit->EditText==" " || MultiR10Edit->EditText==" " || MultiR11Edit->EditText==" " || MultiR12Edit->EditText==" " || MultiR13Edit->EditText==" " || MultiR14Edit->EditText==" " || MultiR20Edit->EditText==" " || MultiR21Edit->EditText==" " || MultiR22Edit->EditText==" " || MultiR23Edit->EditText==" " || MultiR24Edit->EditText==" " || MultiSamplefreqEdit->EditText==" " || MultiPWMEdit->EditText==" ") { InsufficientDataForm->ShowModal(); // An error message will be // displayed if any of the // data entry fields is empty. } else { unsigned char chksum; unsigned char vars[134]; // ! char *panalogsetp; int analogsetp; panalogsetp=MultiAnalogSetpointEdit->Text.c_str(); analogsetp=atoi(panalogsetp); vars[0]=(unsigned char)analogsetp; char *pfreqsetp; int freqsetp; pfreqsetp=MultiFrequencySetpointEdit->Text.c_str();

Page 261: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

251

freqsetp=atoi(pfreqsetp); vars[1]=(unsigned char)freqsetp; // Convert the variables //from text to float char *pstrP10; float P10; unsigned int adrP10; float *pP10; unsigned char P10_byte0; unsigned char P10_byte1; unsigned char P10_byte2; unsigned char P10_byte3; AnsiString ansiP10=MultiP10Edit->Text; pstrP10=ansiP10.c_str(); P10=atof(pstrP10); pP10=&P10; adrP10=(int)pP10; (char *) adrP10; (char *) (adrP10+1); (char *) (adrP10+2); (char *) (adrP10+3); P10_byte3=*(char *) adrP10; P10_byte2=*(char *) (adrP10+1); P10_byte1=*(char *) (adrP10+2); P10_byte0=*(char *) (adrP10+3); vars[2]=P10_byte0; vars[3]=P10_byte1; vars[4]=P10_byte2; vars[5]=P10_byte3; char *pstrP11; float P11; unsigned int adrP11; float *pP11; unsigned char P11_byte0; unsigned char P11_byte1; unsigned char P11_byte2; unsigned char P11_byte3; AnsiString ansiP11=MultiP11Edit->Text; pstrP11=ansiP11.c_str(); P11=atof(pstrP11); pP11=&P11; adrP11=(int)pP11; (char *) adrP11; (char *) (adrP11+1); (char *) (adrP11+2); (char *) (adrP11+3); P11_byte3=*(char *) adrP11; P11_byte2=*(char *) (adrP11+1); P11_byte1=*(char *) (adrP11+2); P11_byte0=*(char *) (adrP11+3); vars[6]=P11_byte0; vars[7]=P11_byte1; vars[8]=P11_byte2;

Page 262: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

252

vars[9]=P11_byte3; char *pstrP12; float P12; unsigned int adrP12; float *pP12; unsigned char P12_byte0; unsigned char P12_byte1; unsigned char P12_byte2; unsigned char P12_byte3; AnsiString ansiP12=MultiP12Edit->Text; pstrP12=ansiP12.c_str(); P12=atof(pstrP12); pP12=&P12; adrP12=(int)pP12; (char *) adrP12; (char *) (adrP12+1); (char *) (adrP12+2); (char *) (adrP12+3); P12_byte3=*(char *) adrP12; P12_byte2=*(char *) (adrP12+1); P12_byte1=*(char *) (adrP12+2); P12_byte0=*(char *) (adrP12+3); vars[10]=P12_byte0; vars[11]=P12_byte1; vars[12]=P12_byte2; vars[13]=P12_byte3; char *pstrP13; float P13; unsigned int adrP13; float *pP13; unsigned char P13_byte0; unsigned char P13_byte1; unsigned char P13_byte2; unsigned char P13_byte3; AnsiString ansiP13=MultiP13Edit->Text; pstrP13=ansiP13.c_str(); P13=atof(pstrP13); pP13=&P13; adrP13=(int)pP13; (char *) adrP13; (char *) (adrP13+1); (char *) (adrP13+2); (char *) (adrP13+3); P13_byte3=*(char *) adrP13; P13_byte2=*(char *) (adrP13+1); P13_byte1=*(char *) (adrP13+2); P13_byte0=*(char *) (adrP13+3); vars[14]=P13_byte0; vars[15]=P13_byte1; vars[16]=P13_byte2; vars[17]=P13_byte3;

Page 263: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

253

char *pstrP14; float P14; unsigned int adrP14; float *pP14; unsigned char P14_byte0; unsigned char P14_byte1; unsigned char P14_byte2; unsigned char P14_byte3; AnsiString ansiP14=MultiP14Edit->Text; pstrP14=ansiP14.c_str(); P14=atof(pstrP14); pP14=&P14; adrP14=(int)pP14; (char *) adrP14; (char *) (adrP14+1); (char *) (adrP14+2); (char *) (adrP14+3); P14_byte3=*(char *) adrP14; P14_byte2=*(char *) (adrP14+1); P14_byte1=*(char *) (adrP14+2); P14_byte0=*(char *) (adrP14+3); vars[18]=P14_byte0; vars[19]=P14_byte1; vars[20]=P14_byte2; vars[21]=P14_byte3; char *pstrP20; float P20; unsigned int adrP20; float *pP20; unsigned char P20_byte0; unsigned char P20_byte1; unsigned char P20_byte2; unsigned char P20_byte3; AnsiString ansiP20=MultiP20Edit->Text; pstrP20=ansiP20.c_str(); P20=atof(pstrP20); pP20=&P20; adrP20=(int)pP20; (char *) adrP20; (char *) (adrP20+1); (char *) (adrP20+2); (char *) (adrP20+3); P20_byte3=*(char *) adrP20; P20_byte2=*(char *) (adrP20+1); P20_byte1=*(char *) (adrP20+2); P20_byte0=*(char *) (adrP20+3); vars[22]=P20_byte0; vars[23]=P20_byte1; vars[24]=P20_byte2; vars[25]=P20_byte3; char *pstrP21; float P21;

Page 264: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

254

unsigned int adrP21; float *pP21; unsigned char P21_byte0; unsigned char P21_byte1; unsigned char P21_byte2; unsigned char P21_byte3; AnsiString ansiP21=MultiP21Edit->Text; pstrP21=ansiP21.c_str(); P21=atof(pstrP21); pP21=&P21; adrP21=(int)pP21; (char *) adrP21; (char *) (adrP21+1); (char *) (adrP21+2); (char *) (adrP21+3); P21_byte3=*(char *) adrP21; P21_byte2=*(char *) (adrP21+1); P21_byte1=*(char *) (adrP21+2); P21_byte0=*(char *) (adrP21+3); vars[26]=P21_byte0; vars[27]=P21_byte1; vars[28]=P21_byte2; vars[29]=P21_byte3; char *pstrP22; float P22; unsigned int adrP22; float *pP22; unsigned char P22_byte0; unsigned char P22_byte1; unsigned char P22_byte2; unsigned char P22_byte3; AnsiString ansiP22=MultiP22Edit->Text; pstrP22=ansiP22.c_str(); P22=atof(pstrP22); pP22=&P22; adrP22=(int)pP22; (char *) adrP22; (char *) (adrP22+1); (char *) (adrP22+2); (char *) (adrP22+3); P22_byte3=*(char *) adrP22; P22_byte2=*(char *) (adrP22+1); P22_byte1=*(char *) (adrP22+2); P22_byte0=*(char *) (adrP22+3); vars[30]=P22_byte0; vars[31]=P22_byte1; vars[32]=P22_byte2; vars[33]=P22_byte3; char *pstrP23; float P23; unsigned int adrP23; float *pP23;

Page 265: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

255

unsigned char P23_byte0; unsigned char P23_byte1; unsigned char P23_byte2; unsigned char P23_byte3; AnsiString ansiP23=MultiP23Edit->Text; pstrP23=ansiP23.c_str(); P23=atof(pstrP23); pP23=&P23; adrP23=(int)pP23; (char *) adrP23; (char *) (adrP23+1); (char *) (adrP23+2); (char *) (adrP23+3); P23_byte3=*(char *) adrP23; P23_byte2=*(char *) (adrP23+1); P23_byte1=*(char *) (adrP23+2); P23_byte0=*(char *) (adrP23+3); vars[34]=P23_byte0; vars[35]=P23_byte1; vars[36]=P23_byte2; vars[37]=P23_byte3; char *pstrP24; float P24; unsigned int adrP24; float *pP24; unsigned char P24_byte0; unsigned char P24_byte1; unsigned char P24_byte2; unsigned char P24_byte3; AnsiString ansiP24=MultiP24Edit->Text; pstrP24=ansiP24.c_str(); P24=atof(pstrP24); pP24=&P24; adrP24=(int)pP24; (char *) adrP24; (char *) (adrP24+1); (char *) (adrP24+2); (char *) (adrP24+3); P24_byte3=*(char *) adrP24; P24_byte2=*(char *) (adrP24+1); P24_byte1=*(char *) (adrP24+2); P24_byte0=*(char *) (adrP24+3); vars[38]=P24_byte0; vars[39]=P24_byte1; vars[40]=P24_byte2; vars[41]=P24_byte3; char *pstrQ10; float Q10; unsigned int adrQ10; float *pQ10; unsigned char Q10_byte0; unsigned char Q10_byte1;

Page 266: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

256

unsigned char Q10_byte2; unsigned char Q10_byte3; AnsiString ansiQ10=MultiQ10Edit->Text; pstrQ10=ansiQ10.c_str(); Q10=atof(pstrQ10); pQ10=&Q10; adrQ10=(int)pQ10; (char *) adrQ10; (char *) (adrQ10+1); (char *) (adrQ10+2); (char *) (adrQ10+3); Q10_byte3=*(char *) adrQ10; Q10_byte2=*(char *) (adrQ10+1); Q10_byte1=*(char *) (adrQ10+2); Q10_byte0=*(char *) (adrQ10+3); vars[42]=Q10_byte0; vars[43]=Q10_byte1; vars[44]=Q10_byte2; vars[45]=Q10_byte3; char *pstrQ11; float Q11; unsigned int adrQ11; float *pQ11; unsigned char Q11_byte0; unsigned char Q11_byte1; unsigned char Q11_byte2; unsigned char Q11_byte3; AnsiString ansiQ11=MultiQ11Edit->Text; pstrQ11=ansiQ11.c_str(); Q11=atof(pstrQ11); pQ11=&Q11; adrQ11=(int)pQ11; (char *) adrQ11; (char *) (adrQ11+1); (char *) (adrQ11+2); (char *) (adrQ11+3); Q11_byte3=*(char *) adrQ11; Q11_byte2=*(char *) (adrQ11+1); Q11_byte1=*(char *) (adrQ11+2); Q11_byte0=*(char *) (adrQ11+3); vars[46]=Q11_byte0; vars[47]=Q11_byte1; vars[48]=Q11_byte2; vars[49]=Q11_byte3; char *pstrQ12; float Q12; unsigned int adrQ12; float *pQ12; unsigned char Q12_byte0; unsigned char Q12_byte1; unsigned char Q12_byte2; unsigned char Q12_byte3;

Page 267: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

257

AnsiString ansiQ12=MultiQ12Edit->Text; pstrQ12=ansiQ12.c_str(); Q12=atof(pstrQ12); pQ12=&Q12; adrQ12=(int)pQ12; (char *) adrQ12; (char *) (adrQ12+1); (char *) (adrQ12+2); (char *) (adrQ12+3); Q12_byte3=*(char *) adrQ12; Q12_byte2=*(char *) (adrQ12+1); Q12_byte1=*(char *) (adrQ12+2); Q12_byte0=*(char *) (adrQ12+3); vars[50]=Q12_byte0; vars[51]=Q12_byte1; vars[52]=Q12_byte2; vars[53]=Q12_byte3; char *pstrQ13; float Q13; unsigned int adrQ13; float *pQ13; unsigned char Q13_byte0; unsigned char Q13_byte1; unsigned char Q13_byte2; unsigned char Q13_byte3; AnsiString ansiQ13=MultiQ13Edit->Text; pstrQ13=ansiQ13.c_str(); Q13=atof(pstrQ13); pQ13=&Q13; adrQ13=(int)pQ13; (char *) adrQ13; (char *) (adrQ13+1); (char *) (adrQ13+2); (char *) (adrQ13+3); Q13_byte3=*(char *) adrQ13; Q13_byte2=*(char *) (adrQ13+1); Q13_byte1=*(char *) (adrQ13+2); Q13_byte0=*(char *) (adrQ13+3); vars[54]=Q13_byte0; vars[55]=Q13_byte1; vars[56]=Q13_byte2; vars[57]=Q13_byte3; char *pstrQ14; float Q14; unsigned int adrQ14; float *pQ14; unsigned char Q14_byte0; unsigned char Q14_byte1; unsigned char Q14_byte2; unsigned char Q14_byte3; AnsiString ansiQ14=MultiQ14Edit->Text; pstrQ14=ansiQ14.c_str();

Page 268: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

258

Q14=atof(pstrQ14); pQ14=&Q14; adrQ14=(int)pQ14; (char *) adrQ14; (char *) (adrQ14+1); (char *) (adrQ14+2); (char *) (adrQ14+3); Q14_byte3=*(char *) adrQ14; Q14_byte2=*(char *) (adrQ14+1); Q14_byte1=*(char *) (adrQ14+2); Q14_byte0=*(char *) (adrQ14+3); vars[58]=Q14_byte0; vars[59]=Q14_byte1; vars[60]=Q14_byte2; vars[61]=Q14_byte3; char *pstrQ20; float Q20; unsigned int adrQ20; float *pQ20; unsigned char Q20_byte0; unsigned char Q20_byte1; unsigned char Q20_byte2; unsigned char Q20_byte3; AnsiString ansiQ20=MultiQ20Edit->Text; pstrQ20=ansiQ20.c_str(); Q20=atof(pstrQ20); pQ20=&Q20; adrQ20=(int)pQ20; (char *) adrQ20; (char *) (adrQ20+1); (char *) (adrQ20+2); (char *) (adrQ20+3); Q20_byte3=*(char *) adrQ20; Q20_byte2=*(char *) (adrQ20+1); Q20_byte1=*(char *) (adrQ20+2); Q20_byte0=*(char *) (adrQ20+3); vars[62]=Q20_byte0; vars[63]=Q20_byte1; vars[64]=Q20_byte2; vars[65]=Q20_byte3; char *pstrQ21; float Q21; unsigned int adrQ21; float *pQ21; unsigned char Q21_byte0; unsigned char Q21_byte1; unsigned char Q21_byte2; unsigned char Q21_byte3; AnsiString ansiQ21=MultiQ21Edit->Text; pstrQ21=ansiQ21.c_str(); Q21=atof(pstrQ21); pQ21=&Q21;

Page 269: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

259

adrQ21=(int)pQ21; (char *) adrQ21; (char *) (adrQ21+1); (char *) (adrQ21+2); (char *) (adrQ21+3); Q21_byte3=*(char *) adrQ21; Q21_byte2=*(char *) (adrQ21+1); Q21_byte1=*(char *) (adrQ21+2); Q21_byte0=*(char *) (adrQ21+3); vars[66]=Q21_byte0; vars[67]=Q21_byte1; vars[68]=Q21_byte2; vars[69]=Q21_byte3; char *pstrQ22; float Q22; unsigned int adrQ22; float *pQ22; unsigned char Q22_byte0; unsigned char Q22_byte1; unsigned char Q22_byte2; unsigned char Q22_byte3; AnsiString ansiQ22=MultiQ22Edit->Text; pstrQ22=ansiQ22.c_str(); Q22=atof(pstrQ22); pQ22=&Q22; adrQ22=(int)pQ22; (char *) adrQ22; (char *) (adrQ22+1); (char *) (adrQ22+2); (char *) (adrQ22+3); Q22_byte3=*(char *) adrQ22; Q22_byte2=*(char *) (adrQ22+1); Q22_byte1=*(char *) (adrQ22+2); Q22_byte0=*(char *) (adrQ22+3); vars[70]=Q22_byte0; vars[71]=Q22_byte1; vars[72]=Q22_byte2; vars[73]=Q22_byte3; char *pstrQ23; float Q23; unsigned int adrQ23; float *pQ23; unsigned char Q23_byte0; unsigned char Q23_byte1; unsigned char Q23_byte2; unsigned char Q23_byte3; AnsiString ansiQ23=MultiQ23Edit->Text; pstrQ23=ansiQ23.c_str(); Q23=atof(pstrQ23); pQ23=&Q23; adrQ23=(int)pQ23; (char *) adrQ23;

Page 270: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

260

(char *) (adrQ23+1); (char *) (adrQ23+2); (char *) (adrQ23+3); Q23_byte3=*(char *) adrQ23; Q23_byte2=*(char *) (adrQ23+1); Q23_byte1=*(char *) (adrQ23+2); Q23_byte0=*(char *) (adrQ23+3); vars[74]=Q23_byte0; vars[75]=Q23_byte1; vars[76]=Q23_byte2; vars[77]=Q23_byte3; char *pstrQ24; float Q24; unsigned int adrQ24; float *pQ24; unsigned char Q24_byte0; unsigned char Q24_byte1; unsigned char Q24_byte2; unsigned char Q24_byte3; AnsiString ansiQ24=MultiQ24Edit->Text; pstrQ24=ansiQ24.c_str(); Q24=atof(pstrQ24); pQ24=&Q24; adrQ24=(int)pQ24; (char *) adrQ24; (char *) (adrQ24+1); (char *) (adrQ24+2); (char *) (adrQ24+3); Q24_byte3=*(char *) adrQ24; Q24_byte2=*(char *) (adrQ24+1); Q24_byte1=*(char *) (adrQ24+2); Q24_byte0=*(char *) (adrQ24+3); vars[78]=Q24_byte0; vars[79]=Q24_byte1; vars[80]=Q24_byte2; vars[81]=Q24_byte3; char *pstrR10; float R10; unsigned int adrR10; float *pR10; unsigned char R10_byte0; unsigned char R10_byte1; unsigned char R10_byte2; unsigned char R10_byte3; AnsiString ansiR10=MultiR10Edit->Text; pstrR10=ansiR10.c_str(); R10=atof(pstrR10); pR10=&R10; adrR10=(int)pR10; (char *) adrR10; (char *) (adrR10+1); (char *) (adrR10+2);

Page 271: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

261

(char *) (adrR10+3); R10_byte3=*(char *) adrR10; R10_byte2=*(char *) (adrR10+1); R10_byte1=*(char *) (adrR10+2); R10_byte0=*(char *) (adrR10+3); vars[82]=R10_byte0; vars[83]=R10_byte1; vars[84]=R10_byte2; vars[85]=R10_byte3; char *pstrR11; float R11; unsigned int adrR11; float *pR11; unsigned char R11_byte0; unsigned char R11_byte1; unsigned char R11_byte2; unsigned char R11_byte3; AnsiString ansiR11=MultiR11Edit->Text; pstrR11=ansiR11.c_str(); R11=atof(pstrR11); pR11=&R11; adrR11=(int)pR11; (char *) adrR11; (char *) (adrR11+1); (char *) (adrR11+2); (char *) (adrR11+3); R11_byte3=*(char *) adrR11; R11_byte2=*(char *) (adrR11+1); R11_byte1=*(char *) (adrR11+2); R11_byte0=*(char *) (adrR11+3); vars[86]=R11_byte0; vars[87]=R11_byte1; vars[88]=R11_byte2; vars[89]=R11_byte3; char *pstrR12; float R12; unsigned int adrR12; float *pR12; unsigned char R12_byte0; unsigned char R12_byte1; unsigned char R12_byte2; unsigned char R12_byte3; AnsiString ansiR12=MultiR12Edit->Text; pstrR12=ansiR12.c_str(); R12=atof(pstrR12); pR12=&R12; adrR12=(int)pR12; (char *) adrR12; (char *) (adrR12+1); (char *) (adrR12+2); (char *) (adrR12+3); R12_byte3=*(char *) adrR12;

Page 272: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

262

R12_byte2=*(char *) (adrR12+1); R12_byte1=*(char *) (adrR12+2); R12_byte0=*(char *) (adrR12+3); vars[90]=R12_byte0; vars[91]=R12_byte1; vars[92]=R12_byte2; vars[93]=R12_byte3; char *pstrR13; float R13; unsigned int adrR13; float *pR13; unsigned char R13_byte0; unsigned char R13_byte1; unsigned char R13_byte2; unsigned char R13_byte3; AnsiString ansiR13=MultiR13Edit->Text; pstrR13=ansiR13.c_str(); R13=atof(pstrR13); pR13=&R13; adrR13=(int)pR13; (char *) adrR13; (char *) (adrR13+1); (char *) (adrR13+2); (char *) (adrR13+3); R13_byte3=*(char *) adrR13; R13_byte2=*(char *) (adrR13+1); R13_byte1=*(char *) (adrR13+2); R13_byte0=*(char *) (adrR13+3); vars[94]=R13_byte0; vars[95]=R13_byte1; vars[96]=R13_byte2; vars[97]=R13_byte3; char *pstrR14; float R14; unsigned int adrR14; float *pR14; unsigned char R14_byte0; unsigned char R14_byte1; unsigned char R14_byte2; unsigned char R14_byte3; AnsiString ansiR14=MultiR14Edit->Text; pstrR14=ansiR14.c_str(); R14=atof(pstrR14); pR14=&R14; adrR14=(int)pR14; (char *) adrR14; (char *) (adrR14+1); (char *) (adrR14+2); (char *) (adrR14+3); R14_byte3=*(char *) adrR14; R14_byte2=*(char *) (adrR14+1); R14_byte1=*(char *) (adrR14+2);

Page 273: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

263

R14_byte0=*(char *) (adrR14+3); vars[98]=R14_byte0; vars[99]=R14_byte1; vars[100]=R14_byte2; vars[101]=R14_byte3; char *pstrR20; float R20; unsigned int adrR20; float *pR20; unsigned char R20_byte0; unsigned char R20_byte1; unsigned char R20_byte2; unsigned char R20_byte3; AnsiString ansiR20=MultiR20Edit->Text; pstrR20=ansiR20.c_str(); R20=atof(pstrR20); pR20=&R20; adrR20=(int)pR20; (char *) adrR20; (char *) (adrR20+1); (char *) (adrR20+2); (char *) (adrR20+3); R20_byte3=*(char *) adrR20; R20_byte2=*(char *) (adrR20+1); R20_byte1=*(char *) (adrR20+2); R20_byte0=*(char *) (adrR20+3); vars[102]=R20_byte0; vars[103]=R20_byte1; vars[104]=R20_byte2; vars[105]=R20_byte3; char *pstrR21; float R21; unsigned int adrR21; float *pR21; unsigned char R21_byte0; unsigned char R21_byte1; unsigned char R21_byte2; unsigned char R21_byte3; AnsiString ansiR21=MultiR21Edit->Text; pstrR21=ansiR21.c_str(); R21=atof(pstrR21); pR21=&R21; adrR21=(int)pR21; (char *) adrR21; (char *) (adrR21+1); (char *) (adrR21+2); (char *) (adrR21+3); R21_byte3=*(char *) adrR21; R21_byte2=*(char *) (adrR21+1); R21_byte1=*(char *) (adrR21+2); R21_byte0=*(char *) (adrR21+3); vars[106]=R21_byte0;

Page 274: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

264

vars[107]=R21_byte1; vars[108]=R21_byte2; vars[109]=R21_byte3; char *pstrR22; float R22; unsigned int adrR22; float *pR22; unsigned char R22_byte0; unsigned char R22_byte1; unsigned char R22_byte2; unsigned char R22_byte3; AnsiString ansiR22=MultiR22Edit->Text; pstrR22=ansiR22.c_str(); R22=atof(pstrR22); pR22=&R22; adrR22=(int)pR22; (char *) adrR22; (char *) (adrR22+1); (char *) (adrR22+2); (char *) (adrR22+3); R22_byte3=*(char *) adrR22; R22_byte2=*(char *) (adrR22+1); R22_byte1=*(char *) (adrR22+2); R22_byte0=*(char *) (adrR22+3); vars[110]=R22_byte0; vars[111]=R22_byte1; vars[112]=R22_byte2; vars[113]=R22_byte3; char *pstrR23; float R23; unsigned int adrR23; float *pR23; unsigned char R23_byte0; unsigned char R23_byte1; unsigned char R23_byte2; unsigned char R23_byte3; AnsiString ansiR23=MultiR23Edit->Text; pstrR23=ansiR23.c_str(); R23=atof(pstrR23); pR23=&R23; adrR23=(int)pR23; (char *) adrR23; (char *) (adrR23+1); (char *) (adrR23+2); (char *) (adrR23+3); R23_byte3=*(char *) adrR23; R23_byte2=*(char *) (adrR23+1); R23_byte1=*(char *) (adrR23+2); R23_byte0=*(char *) (adrR23+3); vars[114]=R23_byte0; vars[115]=R23_byte1; vars[116]=R23_byte2;

Page 275: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

265

vars[117]=R23_byte3; char *pstrR24; float R24; unsigned int adrR24; float *pR24; unsigned char R24_byte0; unsigned char R24_byte1; unsigned char R24_byte2; unsigned char R24_byte3; AnsiString ansiR24=MultiR24Edit->Text; pstrR24=ansiR24.c_str(); R24=atof(pstrR24); pR24=&R24; adrR24=(int)pR24; (char *) adrR24; (char *) (adrR24+1); (char *) (adrR24+2); (char *) (adrR24+3); R24_byte3=*(char *) adrR24; R24_byte2=*(char *) (adrR24+1); R24_byte1=*(char *) (adrR24+2); R24_byte0=*(char *) (adrR24+3); vars[118]=R24_byte0; vars[119]=R24_byte1; vars[120]=R24_byte2; vars[121]=R24_byte3; char *psamplefreq; int samplefreq; psamplefreq=MultiSamplefreqEdit->Text.c_str(); samplefreq=atoi(psamplefreq); vars[122]=(unsigned char)samplefreq; char *ppwmhz; int pwmhz; ppwmhz=MultiPWMEdit->Text.c_str(); pwmhz=atoi(ppwmhz); vars[123]=(unsigned char)pwmhz; // Check whether positive or feedback or negative feedback was // selected. // A 1 will be transmitted to the microcontroller for negative // feedback and a 2 will be transmitted for positive feedback. if (MultiAnalogNegFeedbackSelect->Checked) { vars[124]=1; //Negative feedback } else { vars[124]=2; //Positive feedback } if (MultiFreqNegFeedbackSelect->Checked)

Page 276: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

266

{ vars[125]=1; //Negative feedback } else { vars[125]=2; //Positive feedback } char *panaloginputupperlimit; int analoginputupperlimit; panaloginputupperlimit= MultiAnalogInputupperlimitEdit->Text.c_str(); analoginputupperlimit=atoi(panaloginputupperlimit); vars[126]=(unsigned char)analoginputupperlimit; char *panaloginputlowerlimit; int analoginputlowerlimit; panaloginputlowerlimit= MultiAnalogInputlowerlimitEdit->Text.c_str(); analoginputlowerlimit=atoi(panaloginputlowerlimit); vars[127]=(unsigned char)analoginputlowerlimit; char *pfreqinputupperlimit; int freqinputupperlimit; pfreqinputupperlimit= MultiFreqInputupperlimitEdit->Text.c_str(); freqinputupperlimit=atoi(pfreqinputupperlimit); vars[128]=(unsigned char)freqinputupperlimit; char *pfreqinputlowerlimit; int freqinputlowerlimit; pfreqinputlowerlimit= MultiFreqInputlowerlimitEdit->Text.c_str(); freqinputlowerlimit=atoi(pfreqinputlowerlimit); vars[129]=(unsigned char)freqinputlowerlimit; char *p8bitoutputupperlimit; int _8bitoutputupperlimit; p8bitoutputupperlimit= Multi8BitOutputupperlimitEdit->Text.c_str(); _8bitoutputupperlimit=atoi(p8bitoutputupperlimit); vars[130]=(unsigned char)_8bitoutputupperlimit; char *p8bitoutputlowerlimit; int _8bitoutputlowerlimit; p8bitoutputlowerlimit= Multi8BitOutputlowerlimitEdit->Text.c_str(); _8bitoutputlowerlimit=atoi(p8bitoutputlowerlimit); vars[131]=(unsigned char)_8bitoutputlowerlimit;

Page 277: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

267

char *pPWMoutputupperlimit; int PWMoutputupperlimit; pPWMoutputupperlimit= MultiPWMOutputupperlimitEdit->Text.c_str(); PWMoutputupperlimit=atoi(pPWMoutputupperlimit); vars[132]=(unsigned char)PWMoutputupperlimit; char *pPWMoutputlowerlimit; int PWMoutputlowerlimit; pPWMoutputlowerlimit= MultiPWMOutputlowerlimitEdit->Text.c_str(); PWMoutputlowerlimit=atoi(pPWMoutputlowerlimit); vars[133]=(unsigned char)PWMoutputlowerlimit; // The checksum byte will be added to the s-record line. // The checksum is the complement of the 8-bit sum of all the // bytes in the s-record line. int lenvars=134; unsigned char sum=0; for (int count1=0;count1<lenvars;count1++) { sum=sum+vars[count1]; } chksum=255-(137+1+sum); // The second term indicates the number // of bytes which will be transmitted plus three (2 byte memory // location and 1 byte checksum). // The third byte indicates the memory value in the second byte // of the S-record line. char addline[276]="S1890100"; // Hex 89 indicates the number of // The last four characters // specifies the memory location // in which the parameters will // be stored. int count; for (count=0;count<lenvars;count++) // Convert the decimal variables // into hexadecimal values { char temp[3]; if (vars[count]<16) sprintf(temp,"0%X",vars[count]); // Add a '0' if the // hexidecimal value is a // single digit value. else sprintf(temp,"%X",vars[count]); strcat(addline,temp); // Add the hexideciml value to the // s-record line. } char temp[3]; if (chksum<16) sprintf(temp,"0%X",chksum); // Add a '0' if the hexidecimal // value is a single digit value else sprintf(temp,"%X",chksum);

Page 278: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

268

strcat(addline,temp); // add the 8-bit checksum value // to the s-record line Download1->Memo1->Lines->Text=MultiCode->Lines->Text; Download1->Memo1->Lines->Insert(1,addline); // Add the complete // existing control //algorithm. Download1->ShowModal(); // Start download procedure } } //-------------------------------------------------------------------- void __fastcall TMonitorForm::MultiCommDataAvailable(TObject *Sender) { unsigned char *buffer,data[300]; buffer=data; // Clear the input buffer by writing zero's to it for (int n=0;n<=300;n++) { data[n]=0; } MultiComm->ReadComm(buffer,300); // The idea of Multibuffercount is to ensure that there are at least // ten characters of incoming data available before processing it. Multibuffercount++; if (Multibuffercount>10) { Multibuffercount=1; } switch (Multibuffercount) { case 1: strcpy((char *)Multidata9,(char *)data); break; case 2: strcpy((char *)Multidata8,(char *)data); break; case 3: strcpy((char *)Multidata7,(char *)data); break; case 4: strcpy((char *)Multidata6,(char *)data); break; case 5: strcpy((char *)Multidata5,(char *)data); break; case 6: strcpy((char *)Multidata4,(char *)data); break; case 7: strcpy((char *)Multidata3,(char *)data); break; case 8: strcpy((char *)Multidata2,(char *)data);

Page 279: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

269

break; case 9: strcpy((char *)Multidata1,(char *)data); break; case 10: strcat((char *)Multidata9,(char *)Multidata8); strcat((char *)Multidata9,(char *)Multidata7); strcat((char *)Multidata9,(char *)Multidata6); strcat((char *)Multidata9,(char *)Multidata5); strcat((char *)Multidata9,(char *)Multidata4); strcat((char *)Multidata9,(char *)Multidata3); strcat((char *)Multidata9,(char *)Multidata2); strcat((char *)Multidata9,(char *)Multidata1); strcat((char *)Multidata9,(char *)data); unsigned int len=strlen((char *)Multidata9); // The following lines will decode the data pattern into the // different arrays. Data will be received form the // microcontroller in the following format // [251, Sample Frequency, 252, Analog Input from plant, 253, // Frequency Input from plant, 254, 8-Bit Output to Plant, 255, // PWM Output to Plant] // The array may start and end at any point, but the data always // have to be in the same order. for (int scandata=0;scandata<10;scandata++) { if (Multidata9[scandata]==251) { for (unsigned int count=1+scandata;count<len;count=count+10) { Multisamplefrequency=Multidata9[count]; float period=(float) 1/Multidata9[count]; // The if statement ignores the first period value // since it is not significant. // The first meaningful period value will be available // after one sample cycle on the microcontroler is // finished. if (Multitimeindex==0) { Multitime[Multitimeindex]=0; } else { Multitime[Multitimeindex]= Multitime[Multitimeindex-1]+period; } Multitimedisplay=Multitime[Multitimeindex]; Multitimeindex++; } } else if (Multidata9[scandata]==252) {

Page 280: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

270

for (unsigned int count=1+scandata;count<len;count=count+10) { Multianaloginputdisplay=Multidata9[count]; Multianaloginput[Multianaloginputindex]=Multidata9[count]; Multianaloginputindex++; } } else if (Multidata9[scandata]==253) { for (unsigned int count=1+scandata;count<len;count=count+10) { Multifreqinputdisplay=Multidata9[count]; Multifreqinput[Multifreqinputindex]=Multidata9[count]; Multifreqinputindex++; } } else if (Multidata9[scandata]==254) { for (unsigned int count=1+scandata;count<len;count=count+10) { Multi8bitoutputdisplay=Multidata9[count]; Multi8bitoutput[Multi8bitoutputindex]=Multidata9[count]; Multi8bitoutputindex++; } } else if (Multidata9[scandata]==255) { for (unsigned int count=1+scandata;count<len;count=count+10) { MultiPWMoutputdisplay=Multidata9[count]; MultiPWMoutput[MultiPWMoutputindex]=Multidata9[count]; MultiPWMoutputindex++; } } }// end for scandata break; }// end switch } //-------------------------------------------------------------------- void __fastcall TMonitorForm::MultiDisplayTimerTimer(TObject *Sender) { // // This event handler will display the data received from the // microcontroller with every time interval of the timer. // The time interval can be set with the 'interval' property // of the timer component. // MultiAnalogInputDigitBox->Target=Multianaloginputdisplay; MultiAnalogInputDigitBox->Value=Multianaloginputdisplay; MultiFreqInputDigitBox->Target=Multifreqinputdisplay; MultiFreqInputDigitBox->Value=Multifreqinputdisplay;

Page 281: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

271

Multi8bitOutputDigitBox->Target=Multi8bitoutputdisplay; Multi8bitOutputDigitBox->Value=Multi8bitoutputdisplay; MultiPWMOutputDigitBox->Target=MultiPWMoutputdisplay; MultiPWMOutputDigitBox->Value=MultiPWMoutputdisplay; MultiSamplefreqDigitBox->Target=Multisamplefrequency; MultiSamplefreqDigitBox->Value=Multisamplefrequency; // The stopbutton will only be enabled when recording // in in progress. if (MultiStopButton->Enabled==true) { MultiTimeDigitBox->Target=Multitimedisplay; MultiTimeDigitBox->Value=Multitimedisplay; } } //-------------------------------------------------------------------- void __fastcall TMonitorForm::PlotLines1Click(TObject *Sender) { if (PlotLines1->Checked) { PlotLines1->Checked=false; } else { PlotLines1->Checked=true; } } //-------------------------------------------------------------------- void __fastcall TMonitorForm::menutimerTimer(TObject *Sender) { menutimer->Enabled=false; MenuForm->ShowModal(); } //------------------------------------------------------------------

Page 282: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

272

Main.h - Main Form header file //-------------------------------------------------------------------- #ifndef mainH #define mainH //-------------------------------------------------------------------- #include <vcl\Classes.hpp> #include <vcl\Controls.hpp> #include <vcl\StdCtrls.hpp> #include <vcl\Forms.hpp> #include "zcomm.h" #include <vcl\ExtCtrls.hpp> #include <vcl\Dialogs.hpp> #include <vcl\Menus.hpp> #include "thdtimer.h" #include <vcl\DBTables.hpp> #include <vcl\DB.hpp> #include "XYPlot.h" #include <vcl\ComCtrls.hpp> #include <vcl\Mask.hpp> #include <vcl\Buttons.hpp> #include <vcl\DBCtrls.hpp> #include <vcl\DBGrids.hpp> #include "Grids.hpp" #include "DigitBox.h" //-------------------------------------------------------------------- class TMonitorForm : public TForm { __published: // IDE-managed Components TZComm *PIDMonitorComm; TTimer *PIDDisplayTimer; TSaveDialog *SaveDialog; TMainMenu *MainMenu1; TMenuItem *N68HC11Programs1; TMenuItem *TestDACADC1; TPanel *PIDPanel; TMenuItem *File1; TMenuItem *New1; TMenuItem *Exit1; TMenuItem *Settings1; TMenuItem *Communicationsettings1; TMenuItem *N1; TButton *SaveNowHiddenButton; TPanel *TestDACADCPanel; TZComm *TestDACADCComm; TTimer *TestDACADCDisplayTimer; TPanel *TestDACADCParameterPanel; TLabel *Label11; TPanel *TestDACADCIncomingDataPanel; TLabel *Label13; TPanel *TestDACADCRecordingMessagePanel; TPanel *Panel2;

Page 283: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

273

TPanel *InputDataPanel; TPanel *Panel3; TPanel *PIDParameterPanel; TPanel *Panel1; TLabel *Label17; TMenuItem *Options1; TMenuItem *Recorddatawhencontrolprogramstarts1; TMemo *TestDACADCCode; TPanel *Panel4; TRadioButton *TestDACADCPortBSelect; TLabel *Label21; TPanel *Panel5; TLabel *Label22; TPanel *Panel6; TMaskEdit *TestDACADCStepsizeEdit; TMaskEdit *TestDACADCSamplefreqEdit; TMaskEdit *TestDACADCDelayEdit; TMaskEdit *TestDACADCPWMEdit; TLabel *PWMLabel; TLabel *Label18; TLabel *Label12; TLabel *Label8; TLabel *Label7; TRadioButton *TestDACADCPWMSelect; TRadioButton *TestDACADCAnalogSelect; TRadioButton *TestDACADCFrequencySelect; TPanel *Panel7; TLabel *Label1; TMaskEdit *PIDSetpointEdit; TMaskEdit *PIDKpEdit; TLabel *Label2; TLabel *Label3; TMaskEdit *PIDKiEdit; TMaskEdit *PIDKdEdit; TLabel *Label4; TLabel *Label15; TMaskEdit *PIDSamplefreqEdit; TMaskEdit *PIDPWMEdit; TLabel *PIDPWMLabel; TLabel *Label16; TPanel *Panel8; TRadioButton *PIDPortBSelect; TRadioButton *PIDPWMSelect; TLabel *Label23; TPanel *Panel9; TRadioButton *PIDAnalogSelect; TRadioButton *PIDFrequencySelect; TLabel *Label24; TPanel *Panel10; TLabel *PIDInputLabel; TLabel *PIDOutputLabel; TLabel *PIDSampleFrequencyLabel; TMenuItem *Help1; TPanel *PIDToolbar;

Page 284: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

274

TSpeedButton *PIDDownloadButton; TSpeedButton *SaveButton; TSpeedButton *PIDRecordButton; TSpeedButton *PIDMonitorButton; TSpeedButton *PIDRunButton; TSpeedButton *PIDStopButton; TSpeedButton *PIDDisconnectButton; TSpeedButton *PIDPlotButton; TPanel *DigitalPanel; TPanel *DigitalToolbar; TSpeedButton *DigitalDownloadButton; TSpeedButton *DigitalSaveButton; TSpeedButton *DigitalRecordButton; TSpeedButton *DigitalMonitorButton; TSpeedButton *DigitalRunButton; TSpeedButton *DigitalStopButton; TSpeedButton *DigitalDisconnectButton; TSpeedButton *DigitalPlotButton; TPanel *DigitalParameterPanel; TLabel *Label5; TLabel *Label6; TLabel *Label14; TPanel *Panel12; TLabel *Label20; TLabel *DigitalA0Label; TLabel *Label28; TLabel *DigitalPWMLabel; TMaskEdit *DigitalA0Edit; TMaskEdit *DigitalSetpointEdit; TMaskEdit *DigitalSamplefreqEdit; TMaskEdit *DigitalPWMEdit; TPanel *Panel13; TRadioButton *DigitalPortBSelect; TRadioButton *DigitalPWMSelect; TPanel *Panel14; TRadioButton *DigitalAnalogSelect; TRadioButton *DigitalFrequencySelect; TMaskEdit *DigitalA1Edit; TMaskEdit *DigitalA2Edit; TMaskEdit *DigitalA3Edit; TMaskEdit *DigitalA4Edit; TMaskEdit *DigitalB0Edit; TMaskEdit *DigitalB1Edit; TMaskEdit *DigitalB2Edit; TMaskEdit *DigitalB3Edit; TMaskEdit *DigitalB4Edit; TMemo *DigitalCode; TPanel *Panel11; TLabel *Label25; TPanel *Panel15; TLabel *DigitalInputLabel; TLabel *DigitalOutputLabel; TLabel *DigitalSampleFrequencyLabel; TLabel *Label31;

Page 285: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

275

TLabel *Label32; TLabel *Label33; TLabel *Label34; TLabel *Label35; TLabel *Label36; TLabel *Label37; TLabel *Label38; TLabel *Label39; TZComm *DigitalComm; TTimer *DigitalDisplayTimer; TMenuItem *PIDController1; TMenuItem *DigitalController1; TMenuItem *UsersManual1; TMenuItem *About1; TPanel *Panel16; TPanel *Panel17; TPanel *TestDACADCToolbar; TSpeedButton *TestDACADCDownloadButton; TSpeedButton *TestDACADCSaveButton; TSpeedButton *TestDACADCRecordButton; TSpeedButton *TestDACADCMonitorButton; TSpeedButton *TestDACADCRunButton; TSpeedButton *TestDACADCStopButton; TSpeedButton *TestDACADCDisconnectButton; TSpeedButton *TestDACADCPlotButton; TPanel *Panel18; TLabel *TestDACADCSampleFrequencyLabel; TLabel *TestDACADCOutputLabel; TLabel *TestDACADCInputLabel; TMaskEdit *TestADCDACOutputupperlimitEdit; TMaskEdit *TestADCDACOutputlowerlimitEdit; TLabel *Label27; TLabel *Label29; TPanel *Panel19; TLabel *Label26; TMaskEdit *DigitalInputlowerlimitEdit; TLabel *Label19; TMaskEdit *DigitalInputupperlimitEdit; TLabel *Label10; TMaskEdit *DigitalOutputlowerlimitEdit; TMaskEdit *DigitalOutputupperlimitEdit; TLabel *Label9; TLabel *Label43; TPanel *Panel20; TLabel *Label44; TLabel *Label45; TLabel *Label46; TLabel *Label47; TMaskEdit *PIDInputlowerlimitEdit; TMaskEdit *PIDInputupperlimitEdit; TMaskEdit *PIDOutputlowerlimitEdit; TMaskEdit *PIDOutputupperlimitEdit; TLabel *Label30; TPanel *Panel21;

Page 286: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

276

TRadioButton *DigitalNegativeFeedbackSelect; TRadioButton *DigitalPositiveFeedbackSelect; TLabel *Label40; TPanel *Panel22; TRadioButton *PIDNegativeFeedbackSelect; TRadioButton *PIDPositiveFeedbackSelect; TLabel *Label41; TPanel *MultiPanel; TPanel *Panel23; TSpeedButton *MultiDownloadButton; TSpeedButton *MultiSaveButton; TSpeedButton *MultiRecordButton; TSpeedButton *MultiMonitorButton; TSpeedButton *MultiRunButton; TSpeedButton *MultiStopButton; TSpeedButton *MultiDisconnectButton; TSpeedButton *MultiPlotButton; TPanel *Panel24; TPanel *Panel25; TPanel *Panel27; TLabel *Label42; TLabel *Label50; TLabel *Label51; TPanel *Panel28; TLabel *Label52; TLabel *Label53; TLabel *Label54; TLabel *Label55; TLabel *Label56; TLabel *Label57; TLabel *Label58; TLabel *Label59; TLabel *Label60; TLabel *Label61; TLabel *Label62; TLabel *Label63; TLabel *Label64; TMaskEdit *MultiQ10Edit; TMaskEdit *MultiAnalogSetpointEdit; TMaskEdit *MultiPWMEdit; TMaskEdit *MultiQ11Edit; TMaskEdit *MultiQ12Edit; TMaskEdit *MultiQ13Edit; TMaskEdit *MultiQ14Edit; TMaskEdit *MultiP10Edit; TMaskEdit *MultiP11Edit; TMaskEdit *MultiP12Edit; TMaskEdit *MultiP13Edit; TMaskEdit *MultiP14Edit; TMemo *MultiCode; TPanel *Panel31; TLabel *Label65; TLabel *Label66; TLabel *Label67;

Page 287: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

277

TLabel *Label68; TMaskEdit *MultiAnalogInputlowerlimitEdit; TMaskEdit *MultiAnalogInputupperlimitEdit; TMaskEdit *MultiFreqInputlowerlimitEdit; TMaskEdit *MultiFreqInputupperlimitEdit; TPanel *Panel32; TRadioButton *MultiAnalogNegFeedbackSelect; TRadioButton *MultiAnalogPosFeedbackSelect; TPanel *Panel29; TRadioButton *MultiFreqNegFeedbackSelect; TRadioButton *MultiFreqPosFeedbackSelect; TLabel *Label48; TMaskEdit *MultiPWMOutputlowerlimitEdit; TLabel *Label49; TLabel *Label69; TMaskEdit *MultiPWMOutputupperlimitEdit; TMaskEdit *Multi8BitOutputlowerlimitEdit; TLabel *Label70; TLabel *Label71; TMaskEdit *Multi8BitOutputupperlimitEdit; TMaskEdit *MultiR14Edit; TMaskEdit *MultiR13Edit; TMaskEdit *MultiR12Edit; TMaskEdit *MultiR11Edit; TMaskEdit *MultiR10Edit; TLabel *Label72; TMaskEdit *MultiFrequencySetpointEdit; TLabel *Label73; TLabel *Label74; TLabel *Label75; TLabel *Label76; TLabel *Label77; TLabel *Label78; TLabel *Label79; TLabel *Label80; TLabel *Label81; TLabel *Label82; TLabel *Label83; TLabel *Label84; TLabel *Label85; TLabel *Label86; TLabel *Label87; TLabel *Label88; TLabel *Label89; TLabel *Label90; TLabel *Label91; TLabel *Label92; TLabel *Label93; TLabel *Label94; TLabel *Label95; TLabel *Label96; TLabel *Label97; TLabel *Label98; TMaskEdit *MultiP24Edit;

Page 288: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

278

TMaskEdit *MultiP23Edit; TMaskEdit *MultiP22Edit; TMaskEdit *MultiP21Edit; TMaskEdit *MultiP20Edit; TMaskEdit *MultiQ24Edit; TMaskEdit *MultiQ23Edit; TMaskEdit *MultiQ22Edit; TMaskEdit *MultiQ21Edit; TMaskEdit *MultiQ20Edit; TMaskEdit *MultiR24Edit; TMaskEdit *MultiR23Edit; TMaskEdit *MultiR22Edit; TMaskEdit *MultiR21Edit; TMaskEdit *MultiR20Edit; TPanel *Panel30; TLabel *Label99; TPanel *Panel33; TLabel *Label100; TLabel *Label101; TLabel *Label102; TLabel *Label103; TLabel *Label104; TMaskEdit *MultiSamplefreqEdit; TZComm *MultiComm; TTimer *MultiDisplayTimer; TMenuItem *MultiController1; TMenuItem *PlotLines1; TDigitBox *PIDSamplefreqDigitBox; TDigitBox *PIDOutputDigitBox; TDigitBox *PIDInputDigitBox; TDigitBox *PIDTimeDigitBox; TDigitBox *MultiAnalogInputDigitBox; TDigitBox *MultiFreqInputDigitBox; TDigitBox *Multi8bitOutputDigitBox; TDigitBox *MultiPWMOutputDigitBox; TDigitBox *MultiSamplefreqDigitBox; TDigitBox *MultiTimeDigitBox; TDigitBox *DigitalTimeDigitBox; TDigitBox *DigitalInputDigitBox; TDigitBox *DigitalOutputDigitBox; TDigitBox *DigitalSamplefreqDigitBox; TDigitBox *TestDACADCInputDigitBox; TDigitBox *TestDACADCTimeDigitBox; TDigitBox *TestDACADCOutputDigitBox; TDigitBox *TestDACADCSamplefreqDigitBox; TTimer *menutimer; void __fastcall PIDMonitorCommDataAvailable(TObject *Sender); void __fastcall PIDDisplayTimerTimer(TObject *Sender); void __fastcall PIDStopButtonClick(TObject *Sender); void __fastcall PIDRecordButtonClick(TObject *Sender); void __fastcall SaveButtonClick(TObject *Sender);

Page 289: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

279

void __fastcall PIDPlotButtonClick(TObject *Sender); void __fastcall SaveNowHiddenButtonClick(TObject *Sender); void __fastcall PIDMonitorButtonClick(TObject *Sender); void __fastcall PIDDisconnectButtonClick(TObject *Sender); void __fastcall PIDRunButtonClick(TObject *Sender); void __fastcall FormClose(TObject *Sender, TCloseAction &Action); void __fastcall PIDSetpointEditEnter(TObject *Sender); void __fastcall PIDKpEditEnter(TObject *Sender); void __fastcall PIDKiEditEnter(TObject *Sender); void __fastcall PIDKdEditEnter(TObject *Sender); void __fastcall PIDDownloadButtonClick(TObject *Sender); void __fastcall PIDController1Click(TObject *Sender); void __fastcall New1Click(TObject *Sender); void __fastcall Exit1Click(TObject *Sender); void __fastcall PIDSetpointEditExit(TObject *Sender); void __fastcall PIDKpEditExit(TObject *Sender); void __fastcall PIDKiEditExit(TObject *Sender); void __fastcall PIDKdEditExit(TObject *Sender); void __fastcall Communicationsettings1Click(TObject *Sender); void __fastcall TestDACADCDownloadButtonClick(TObject *Sender); void __fastcall TestDACADCMonitorButtonClick(TObject *Sender); void __fastcall TestDACADCDisconnectButtonClick(TObject *Sender); void __fastcall TestDACADC1Click(TObject *Sender); void __fastcall TestDACADCDisplayTimerTimer(TObject *Sender); void __fastcall TestDACADCStepsizeEditEnter(TObject *Sender); void __fastcall TestDACADCStepsizeEditExit(TObject *Sender); void __fastcall TestDACADCRecordButtonClick(TObject *Sender); void __fastcall TestDACADCStopButtonClick(TObject *Sender); void __fastcall TestDACADCPlotButtonClick(TObject *Sender); void __fastcall Recorddatawhencontrolprogramstarts1Click( TObject *Sender); void __fastcall PIDSamplefreqEditEnter(TObject *Sender); void __fastcall PIDSamplefreqEditExit(TObject *Sender); void __fastcall TestDACADCCommDataAvailable(TObject *Sender); void __fastcall TestDACADCDelayEditEnter(TObject *Sender); void __fastcall TestDACADCDelayEditExit(TObject *Sender); void __fastcall TestDACADCSamplefreqEditExit(TObject *Sender); void __fastcall TestDACADCSamplefreqEditEnter(TObject *Sender); void __fastcall TestDACADCPWMEditEnter(TObject *Sender); void __fastcall TestDACADCPWMEditExit(TObject *Sender); void __fastcall TestDACADCPortBSelectClick(TObject *Sender); void __fastcall TestDACADCPWMSelectClick(TObject *Sender); void __fastcall TestDACADCAnalogSelectClick(TObject *Sender); void __fastcall TestDACADCFrequencySelectClick(TObject *Sender); void __fastcall PIDPWMEditEnter(TObject *Sender); void __fastcall PIDPWMEditExit(TObject *Sender); void __fastcall PIDPortBSelectClick(TObject *Sender); void __fastcall PIDPWMSelectClick(TObject *Sender); void __fastcall PIDAnalogSelectClick(TObject *Sender); void __fastcall PIDFrequencySelectClick(TObject *Sender); void __fastcall DigitalDownloadButtonClick(TObject *Sender); void __fastcall DigitalMonitorButtonClick(TObject *Sender); void __fastcall DigitalDisconnectButtonClick(TObject *Sender); void __fastcall DigitalRecordButtonClick(TObject *Sender);

Page 290: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

280

void __fastcall DigitalStopButtonClick(TObject *Sender); void __fastcall DigitalPlotButtonClick(TObject *Sender); void __fastcall UsersManual1Click(TObject *Sender); void __fastcall DigitalController1Click(TObject *Sender); void __fastcall DigitalCommDataAvailable(TObject *Sender); void __fastcall DigitalDisplayTimerTimer(TObject *Sender); void __fastcall DigitalPortBSelectClick(TObject *Sender); void __fastcall DigitalPWMSelectClick(TObject *Sender); void __fastcall DigitalAnalogSelectClick(TObject *Sender); void __fastcall DigitalFrequencySelectClick(TObject *Sender); void __fastcall DigitalSetpointEditClick(TObject *Sender); void __fastcall DigitalSetpointEditExit(TObject *Sender); void __fastcall DigitalB0EditClick(TObject *Sender); void __fastcall DigitalB1EditClick(TObject *Sender); void __fastcall DigitalB2EditClick(TObject *Sender); void __fastcall DigitalB3EditClick(TObject *Sender); void __fastcall DigitalB4EditClick(TObject *Sender); void __fastcall DigitalA0EditClick(TObject *Sender); void __fastcall DigitalA1EditClick(TObject *Sender); void __fastcall DigitalA2EditClick(TObject *Sender); void __fastcall DigitalA3EditClick(TObject *Sender); void __fastcall DigitalA4EditClick(TObject *Sender); void __fastcall DigitalSamplefreqEditClick(TObject *Sender); void __fastcall DigitalSamplefreqEditExit(TObject *Sender); void __fastcall DigitalOutputupperlimitEditClick(TObject *Sender); void __fastcall DigitalOutputupperlimitEditExit(TObject *Sender); void __fastcall DigitalOutputlowerlimitEditClick(TObject *Sender); void __fastcall DigitalOutputlowerlimitEditExit(TObject *Sender); void __fastcall DigitalInputupperlimitEditExit(TObject *Sender); void __fastcall DigitalInputupperlimitEditClick(TObject *Sender); void __fastcall DigitalInputlowerlimitEditExit(TObject *Sender); void __fastcall DigitalInputlowerlimitEditClick(TObject *Sender); void __fastcall PIDInputupperlimitEditClick(TObject *Sender); void __fastcall PIDInputupperlimitEditExit(TObject *Sender); void __fastcall PIDInputlowerlimitEditClick(TObject *Sender); void __fastcall PIDInputlowerlimitEditExit(TObject *Sender); void __fastcall PIDOutputupperlimitEditClick(TObject *Sender); void __fastcall PIDOutputupperlimitEditExit(TObject *Sender); void __fastcall PIDOutputlowerlimitEditClick(TObject *Sender); void __fastcall PIDOutputlowerlimitEditExit(TObject *Sender); void __fastcall MultiController1Click( TObject *Sender); void __fastcall MultiMonitorButtonClick(TObject *Sender); void __fastcall MultiDisconnectButtonClick(TObject *Sender); void __fastcall MultiRecordButtonClick(TObject *Sender); void __fastcall MultiStopButtonClick(TObject *Sender); void __fastcall MultiPlotButtonClick(TObject *Sender); void __fastcall MultiDownloadButtonClick(TObject *Sender); void __fastcall MultiCommDataAvailable(TObject *Sender); void __fastcall MultiDisplayTimerTimer(TObject *Sender); void __fastcall PlotLines1Click(TObject *Sender); void __fastcall menutimerTimer(TObject *Sender);

Page 291: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

281

private: // User declarations public: // User declarations __fastcall TMonitorForm(TComponent* Owner); }; //-------------------------------------------------------------------- extern TMonitorForm *MonitorForm; //-------------------------------------------------------------------- #endif

Page 292: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

282

Mainmenu.cpp – Startup menu source code //-------------------------------------------------------------------- #include <vcl\vcl.h> #pragma hdrstop #include "mainmenu.h" #include "main.h" //-------------------------------------------------------------------- #pragma link "explbtn" #pragma resource "*.dfm" TMenuForm *MenuForm; //-------------------------------------------------------------------- __fastcall TMenuForm::TMenuForm(TComponent* Owner) : TForm(Owner) { } //-------------------------------------------------------------------- void __fastcall TMenuForm::OfficeButton3Click(TObject *Sender) { MenuForm->Close(); MonitorForm->Close(); } //-------------------------------------------------------------------- void __fastcall TMenuForm::OfficeButton1Click(TObject *Sender) { //Test I/O Select MonitorForm->Visible=true; MonitorForm->VertScrollBar->Range=392; MonitorForm->Height=438; MonitorForm->Width=596; MonitorForm->Position=poScreenCenter; MonitorForm->TestDACADC1Click(Sender); MenuForm->Close(); } //-------------------------------------------------------------------- void __fastcall TMenuForm::OfficeButton2Click(TObject *Sender) { // SISO Select MonitorForm->Visible=true; MonitorForm->VertScrollBar->Range=480; MonitorForm->Height=526; MonitorForm->Width=596; MonitorForm->Position=poScreenCenter; MonitorForm->DigitalController1Click(Sender); MenuForm->Close(); } //-------------------------------------------------------------------- void __fastcall TMenuForm::OfficeButton4Click(TObject *Sender) { // MIMO Select; MonitorForm->Visible=true;

Page 293: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

283

MonitorForm->VertScrollBar->Range=540; MonitorForm->Height=586; MonitorForm->Width=596; MonitorForm->Position=poScreenCenter; MonitorForm->MultiController1Click(Sender); MenuForm->Close(); } //-------------------------------------------------------------------- void __fastcall TMenuForm::OfficeButton5Click(TObject *Sender) { // PID Select; MonitorForm->Visible=true; MonitorForm->VertScrollBar->Range=432; MonitorForm->Height=478; MonitorForm->Width=596; MonitorForm->Position=poScreenCenter; MonitorForm->PIDController1Click(Sender); MenuForm->Close(); } //-------------------------------------------------------------------- void __fastcall TMenuForm::FormShow(TObject *Sender) { MonitorForm->Visible=false; } //--------------------------------------------------------------------

Page 294: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

284

Mainmenu.h – Startup menu header file //-------------------------------------------------------------------- #ifndef mainmenuH #define mainmenuH //-------------------------------------------------------------------- #include <vcl\Classes.hpp> #include <vcl\Controls.hpp> #include <vcl\StdCtrls.hpp> #include <vcl\Forms.hpp> #include "explbtn.hpp" #include <vcl\ExtCtrls.hpp> //-------------------------------------------------------------------- class TMenuForm : public TForm { __published: // IDE-managed Components TPanel *Panel1; TOfficeButton *OfficeButton1; TOfficeButton *OfficeButton2; TOfficeButton *OfficeButton3; TOfficeButton *OfficeButton4; TOfficeButton *OfficeButton5; void __fastcall OfficeButton3Click(TObject *Sender); void __fastcall OfficeButton1Click(TObject *Sender); void __fastcall OfficeButton2Click(TObject *Sender); void __fastcall OfficeButton4Click(TObject *Sender); void __fastcall OfficeButton5Click(TObject *Sender); void __fastcall FormShow(TObject *Sender); private: // User declarations public: // User declarations __fastcall TMenuForm(TComponent* Owner); }; //-------------------------------------------------------------------- extern TMenuForm *MenuForm; //-------------------------------------------------------------------- #endif

Page 295: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

285

Max250min1.cpp - Error-message form source code //-------------------------------------------------------------------- #include <vcl\vcl.h> #pragma hdrstop #include "Max250min1.h" //-------------------------------------------------------------------- #pragma resource "*.dfm" TMax250min1Form *Max250min1Form; //-------------------------------------------------------------------- __fastcall TMax250min1Form::TMax250min1Form(TComponent* Owner) : TForm(Owner) { } //-------------------------------------------------------------------- void __fastcall TMax250min1Form::Button1Click(TObject *Sender) { Max250min1Form->Close(); } //--------------------------------------------------------------------

Page 296: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

286

Max250min1.h - Error-message form header file //-------------------------------------------------------------------- #ifndef Max250min1H #define Max250min1H //-------------------------------------------------------------------- #include <vcl\Classes.hpp> #include <vcl\Controls.hpp> #include <vcl\StdCtrls.hpp> #include <vcl\Forms.hpp> #include <vcl\ExtCtrls.hpp> //-------------------------------------------------------------------- class TMax250min1Form : public TForm { __published: // IDE-managed Components TImage *Image1; TLabel *Label1; TButton *Button1; void __fastcall Button1Click(TObject *Sender); private: // User declarations public: // User declarations __fastcall TMax250min1Form(TComponent* Owner); }; //-------------------------------------------------------------------- extern TMax250min1Form *Max250min1Form; //-------------------------------------------------------------------- #endif

Page 297: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

287

Max255.cpp - Error-message form source code //-------------------------------------------------------------------- #include <vcl\vcl.h> #pragma hdrstop #include "Max255.h" //-------------------------------------------------------------------- #pragma resource "*.dfm" TMax255Form *Max255Form; //-------------------------------------------------------------------- // This unit will display the Max255Form in which the user will be // prompted that the value in the data entry fields may not exeed // 255 which is the maximum value for an unsigned 8-bit number. //-------------------------------------------------------------------- __fastcall TMax255Form::TMax255Form(TComponent* Owner) : TForm(Owner) { } //-------------------------------------------------------------------- void __fastcall TMax255Form::Button1Click(TObject *Sender) { Max255Form->Close(); } //--------------------------------------------------------------------

Page 298: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

288

Max255.h - Error-message form header file //-------------------------------------------------------------------- #ifndef Max255H #define Max255H //-------------------------------------------------------------------- #include <vcl\Classes.hpp> #include <vcl\Controls.hpp> #include <vcl\StdCtrls.hpp> #include <vcl\Forms.hpp> #include <vcl\ExtCtrls.hpp> //-------------------------------------------------------------------- class TMax255Form : public TForm { __published: // IDE-managed Components TButton *Button1; TLabel *Label1; TImage *Image1; void __fastcall Button1Click(TObject *Sender); private: // User declarations public: // User declarations __fastcall TMax255Form(TComponent* Owner); }; //-------------------------------------------------------------------- extern TMax255Form *Max255Form; //-------------------------------------------------------------------- #endif

Page 299: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

289

Min40.cpp - Error-message form source code //-------------------------------------------------------------------- #include <vcl\vcl.h> #pragma hdrstop #include "Min40.h" #include "main.h" //-------------------------------------------------------------------- #pragma resource "*.dfm" TMin40Form *Min40Form; //-------------------------------------------------------------------- __fastcall TMin40Form::TMin40Form(TComponent* Owner) : TForm(Owner) { } //-------------------------------------------------------------------- void __fastcall TMin40Form::Button1Click(TObject *Sender) { Min40Form->Close(); } //--------------------------------------------------------------------

Page 300: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

290

Min40.h - Error-message form header file //-------------------------------------------------------------------- #ifndef Min40H #define Min40H //-------------------------------------------------------------------- #include <vcl\Classes.hpp> #include <vcl\Controls.hpp> #include <vcl\StdCtrls.hpp> #include <vcl\Forms.hpp> #include <vcl\ExtCtrls.hpp> //-------------------------------------------------------------------- class TMin40Form : public TForm { __published: // IDE-managed Components TLabel *Label1; TImage *Image1; TButton *Button1; void __fastcall Button1Click(TObject *Sender); private: // User declarations public: // User declarations __fastcall TMin40Form(TComponent* Owner); }; //-------------------------------------------------------------------- extern TMin40Form *Min40Form; //-------------------------------------------------------------------- #endif

Page 301: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

291

Plot1.cpp -Plotform1 source code //-------------------------------------------------------------------- #include <vcl\vcl.h> #pragma hdrstop #include "Plot1.h" //-------------------------------------------------------------------- #pragma link "XYPlot" #pragma resource "*.dfm" TPlotForm1 *PlotForm1; extern double Digitalinputrecorded[65536]; extern double Digitaltimerecorded[65536]; extern unsigned short int Digitaltimeindexstop; //-------------------------------------------------------------------- __fastcall TPlotForm1::TPlotForm1(TComponent* Owner) : TForm(Owner) { } //-------------------------------------------------------------------- void __fastcall TPlotForm1::YZoomInButtonClick(TObject *Sender) { double range; double ymax=XYPlot1->YMax; double ymin=XYPlot1->YMin; XYPlot1->YAutoScale=false; range=ymax-ymin; XYPlot1->YMax=ymax-(range/8); XYPlot1->YMin=ymin+(range/8); } //-------------------------------------------------------------------- void __fastcall TPlotForm1::CloseButtonClick(TObject *Sender) { PlotForm1->Close(); } //-------------------------------------------------------------------- void __fastcall TPlotForm1::YZoomOutButtonClick(TObject *Sender) { double range; double ymax=XYPlot1->YMax; double ymin=XYPlot1->YMin; XYPlot1->YAutoScale=false; range=ymax-ymin; XYPlot1->YMax=ymax+(range/8); XYPlot1->YMin=ymin-(range/8); } //-------------------------------------------------------------------- void __fastcall TPlotForm1::XZoomOutButtonClick(TObject *Sender) { double range;

Page 302: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

292

double xmax=XYPlot1->XMax; double xmin=XYPlot1->XMin; XYPlot1->XAutoScale=false; range=xmax-xmin; XYPlot1->XMax=xmax+(range/8); XYPlot1->XMin=xmin-(range/8); } //-------------------------------------------------------------------- void __fastcall TPlotForm1::XZoomInButtonClick(TObject *Sender) { double range; double xmax=XYPlot1->XMax; double xmin=XYPlot1->XMin; XYPlot1->XAutoScale=false; range=xmax-xmin; XYPlot1->XMax=xmax-(range/8); XYPlot1->XMin=xmin+(range/8); } //-------------------------------------------------------------------- void __fastcall TPlotForm1::FormClose(TObject *Sender, TCloseAction &Action) { XYPlot1->RemovePlot(1); } //-------------------------------------------------------------------- void __fastcall TPlotForm1::XYPlot1StartDrag(TObject *Sender, TDragObject *&DragObject) { XYPlot1->Cursor=crDrag; } //-------------------------------------------------------------------- void __fastcall TPlotForm1::XYPlot1EndDrag(TObject *Sender, TObject *Target, int X, int Y) { XYPlot1->Cursor=crCross; } //-------------------------------------------------------------------- void __fastcall TPlotForm1::XYPlot1MouseMove(TObject *Sender, TShiftState Shift, int X, int Y) { char temp[20]; AnsiString ansixmouse = XYPlot1->MouseX; char* pxmouse=ansixmouse.c_str(); float xmouse=atof(pxmouse); sprintf(temp,"%.2f",xmouse); XMouseLabel->Caption=temp; AnsiString ansiymouse = XYPlot1->MouseY; char* pymouse=ansiymouse.c_str(); float ymouse=atof(pymouse); sprintf(temp,"%.0f",ymouse); YMouseLabel->Caption=temp; }

Page 303: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

293

//-------------------------------------------------------------------- void __fastcall TPlotForm1::ScrollRightButtonClick(TObject *Sender) { double range; double xmax=XYPlot1->XMax; double xmin=XYPlot1->XMin; XYPlot1->XAutoScale=false; range=xmax-xmin; XYPlot1->XMax=xmax+(range/16); XYPlot1->XMin=xmin+(range/16); } //-------------------------------------------------------------------- void __fastcall TPlotForm1::ScrollLeftButtonClick(TObject *Sender) { double range; double xmax=XYPlot1->XMax; double xmin=XYPlot1->XMin; XYPlot1->XAutoScale=false; range=xmax-xmin; XYPlot1->XMax=xmax-(range/16); XYPlot1->XMin=xmin-(range/16); } //-------------------------------------------------------------------- void __fastcall TPlotForm1::ScrollUpButtonClick(TObject *Sender) { double range; double ymax=XYPlot1->YMax; double ymin=XYPlot1->YMin; XYPlot1->YAutoScale=false; range=ymax-ymin; XYPlot1->YMax=ymax+(range/16); XYPlot1->YMin=ymin+(range/16); } //-------------------------------------------------------------------- void __fastcall TPlotForm1::ScrollDownButtonClick(TObject *Sender) { double range; double ymax=XYPlot1->YMax; double ymin=XYPlot1->YMin; XYPlot1->YAutoScale=false; range=ymax-ymin; XYPlot1->YMax=ymax-(range/16); XYPlot1->YMin=ymin-(range/16); } //--------------------------------------------------------------------

Page 304: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

294

Plot1.h -Plotform1 header file //-------------------------------------------------------------------- #ifndef Plot1H #define Plot1H //-------------------------------------------------------------------- #include <vcl\Classes.hpp> #include <vcl\Controls.hpp> #include <vcl\StdCtrls.hpp> #include <vcl\Forms.hpp> #include "XYPlot.h" #include <vcl\ExtCtrls.hpp> #include <vcl\Buttons.hpp> //-------------------------------------------------------------------- class TPlotForm1 : public TForm { __published: // IDE-managed Components TXYPlot *XYPlot1; TPanel *Panel1; TPanel *Panel2; TLabel *Label1; TLabel *Label2; TButton *CloseButton; TSpeedButton *YZoomInButton; TSpeedButton *YZoomOutButton; TSpeedButton *XZoomInButton; TSpeedButton *XZoomOutButton; TPanel *Panel3; TPanel *Panel4; TLabel *Label5; TPanel *Panel5; TLabel *XMouseLabel; TPanel *Panel6; TLabel *YMouseLabel; TSpeedButton *ScrollRightButton; TSpeedButton *ScrollLeftButton; TSpeedButton *ScrollDownButton; TSpeedButton *ScrollUpButton; void __fastcall YZoomInButtonClick(TObject *Sender); void __fastcall CloseButtonClick(TObject *Sender); void __fastcall YZoomOutButtonClick(TObject *Sender); void __fastcall XZoomOutButtonClick(TObject *Sender); void __fastcall XZoomInButtonClick(TObject *Sender); void __fastcall FormClose(TObject *Sender, TCloseAction &Action); void __fastcall XYPlot1StartDrag(TObject *Sender, TDragObject *&DragObject); void __fastcall XYPlot1EndDrag(TObject *Sender, TObject *Target, int X, int Y); void __fastcall XYPlot1MouseMove(TObject *Sender, TShiftState Shift, int X, int Y); void __fastcall ScrollRightButtonClick(TObject *Sender);

Page 305: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

295

void __fastcall ScrollLeftButtonClick(TObject *Sender); void __fastcall ScrollUpButtonClick(TObject *Sender); void __fastcall ScrollDownButtonClick(TObject *Sender); private: // User declarations public: // User declarations __fastcall TPlotForm1(TComponent* Owner); }; //-------------------------------------------------------------------- extern TPlotForm1 *PlotForm1; //-------------------------------------------------------------------- #endif

Page 306: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

296

Plot2.cpp –Plotform2 source code //-------------------------------------------------------------------- #include <vcl\vcl.h> #pragma hdrstop #include "Plot2.h" //-------------------------------------------------------------------- #pragma link "XYPlot" #pragma resource "*.dfm" TPlotForm2 *PlotForm2; //-------------------------------------------------------------------- __fastcall TPlotForm2::TPlotForm2(TComponent* Owner) : TForm(Owner) { } //-------------------------------------------------------------------- void __fastcall TPlotForm2::ScrollLeftButtonClick(TObject *Sender) { double range; double xmax=XYPlot1->XMax; double xmin=XYPlot1->XMin; XYPlot1->XAutoScale=false; range=xmax-xmin; XYPlot1->XMax=xmax-(range/16); XYPlot1->XMin=xmin-(range/16); } //-------------------------------------------------------------------- void __fastcall TPlotForm2::SpeedButton3Click(TObject *Sender) { double range; double ymax=XYPlot1->YMax; double ymin=XYPlot1->YMin; XYPlot1->YAutoScale=false; range=ymax-ymin; XYPlot1->YMax=ymax+(range/16); XYPlot1->YMin=ymin+(range/16); } //-------------------------------------------------------------------- void __fastcall TPlotForm2::SpeedButton4Click(TObject *Sender) { double range; double ymax=XYPlot1->YMax; double ymin=XYPlot1->YMin; XYPlot1->YAutoScale=false; range=ymax-ymin; XYPlot1->YMax=ymax-(range/16); XYPlot1->YMin=ymin-(range/16); } //-------------------------------------------------------------------- void __fastcall TPlotForm2::SpeedButton1Click(TObject *Sender) {

Page 307: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

297

double range; double xmax=XYPlot1->XMax; double xmin=XYPlot1->XMin; XYPlot1->XAutoScale=false; range=xmax-xmin; XYPlot1->XMax=xmax+(range/16); XYPlot1->XMin=xmin+(range/16); } //-------------------------------------------------------------------- void __fastcall TPlotForm2::YZoomInButtonClick(TObject *Sender) { double range; double ymax=XYPlot1->YMax; double ymin=XYPlot1->YMin; XYPlot1->YAutoScale=false; range=ymax-ymin; XYPlot1->YMax=ymax-(range/8); XYPlot1->YMin=ymin+(range/8); } //-------------------------------------------------------------------- void __fastcall TPlotForm2::YZoomOutButtonClick(TObject *Sender) { double range; double ymax=XYPlot1->YMax; double ymin=XYPlot1->YMin; XYPlot1->YAutoScale=false; range=ymax-ymin; XYPlot1->YMax=ymax+(range/8); XYPlot1->YMin=ymin-(range/8); } //-------------------------------------------------------------------- void __fastcall TPlotForm2::XZoomInButtonClick(TObject *Sender) { double range; double xmax=XYPlot1->XMax; double xmin=XYPlot1->XMin; XYPlot1->XAutoScale=false; range=xmax-xmin; XYPlot1->XMax=xmax-(range/8); XYPlot1->XMin=xmin+(range/8); } //-------------------------------------------------------------------- void __fastcall TPlotForm2::XZoomOutButtonClick(TObject *Sender) { double range; double xmax=XYPlot1->XMax; double xmin=XYPlot1->XMin; XYPlot1->XAutoScale=false; range=xmax-xmin; XYPlot1->XMax=xmax+(range/8); XYPlot1->XMin=xmin-(range/8); } //-------------------------------------------------------------------- void __fastcall TPlotForm2::XYPlot1MouseMove(TObject *Sender,

Page 308: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

298

TShiftState Shift, int X, int Y) { char temp[20]; AnsiString ansixmouse = XYPlot1->MouseX; char* pxmouse=ansixmouse.c_str(); float xmouse=atof(pxmouse); sprintf(temp,"%.2f",xmouse); XMouseLabel->Caption=temp; AnsiString ansiymouse = XYPlot1->MouseY; char* pymouse=ansiymouse.c_str(); float ymouse=atof(pymouse); sprintf(temp,"%.0f",ymouse); YMouseLabel->Caption=temp; } //-------------------------------------------------------------------- void __fastcall TPlotForm2::CloseButtonClick(TObject *Sender) { PlotForm2->Close(); } //--------------------------------------------------------------------

Page 309: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

299

Plot2.h –Plotform2 header file //-------------------------------------------------------------------- #ifndef Plot2H #define Plot2H //-------------------------------------------------------------------- #include <vcl\Classes.hpp> #include <vcl\Controls.hpp> #include <vcl\StdCtrls.hpp> #include <vcl\Forms.hpp> #include <vcl\ExtCtrls.hpp> #include "XYPlot.h" #include <vcl\Buttons.hpp> //-------------------------------------------------------------------- class TPlotForm2 : public TForm { __published: // IDE-managed Components TPanel *Panel2; TSpeedButton *XZoomInButton; TSpeedButton *XZoomOutButton; TLabel *Label5; TSpeedButton *SpeedButton1; TSpeedButton *ScrollLeftButton; TPanel *Panel5; TLabel *XMouseLabel; TPanel *Panel1; TLabel *Label1; TLabel *Label2; TSpeedButton *YZoomInButton; TSpeedButton *YZoomOutButton; TSpeedButton *SpeedButton3; TSpeedButton *SpeedButton4; TButton *CloseButton; TPanel *Panel6; TLabel *YMouseLabel; TPanel *Panel4; TPanel *Panel3; TXYPlot *XYPlot1; void __fastcall ScrollLeftButtonClick(TObject *Sender); void __fastcall SpeedButton3Click(TObject *Sender); void __fastcall SpeedButton4Click(TObject *Sender); void __fastcall SpeedButton1Click(TObject *Sender); void __fastcall YZoomInButtonClick(TObject *Sender); void __fastcall YZoomOutButtonClick(TObject *Sender); void __fastcall XZoomInButtonClick(TObject *Sender); void __fastcall XZoomOutButtonClick(TObject *Sender); void __fastcall XYPlot1MouseMove(TObject *Sender, TShiftState Shift, int X, int Y); void __fastcall CloseButtonClick(TObject *Sender); private: // User declarations public: // User declarations __fastcall TPlotForm2(TComponent* Owner);

Page 310: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

300

}; //-------------------------------------------------------------------- extern TPlotForm2 *PlotForm2; //-------------------------------------------------------------------- #endif

Page 311: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

301

Plot3.cpp – Plotform3 source code //-------------------------------------------------------------------- #include <vcl\vcl.h> #pragma hdrstop #include "Plot3.h" //-------------------------------------------------------------------- #pragma link "xyplot" #pragma resource "*.dfm" TPlotForm3 *PlotForm3; //-------------------------------------------------------------------- __fastcall TPlotForm3::TPlotForm3(TComponent* Owner) : TForm(Owner) { } //-------------------------------------------------------------------- void __fastcall TPlotForm3::CloseButtonClick(TObject *Sender) { PlotForm3->Close(); } //-------------------------------------------------------------------- void __fastcall TPlotForm3::ScrollUpButtonClick(TObject *Sender) { double range; double ymax=XYPlot1->YMax; double ymin=XYPlot1->YMin; XYPlot1->YAutoScale=false; range=ymax-ymin; XYPlot1->YMax=ymax+(range/16); XYPlot1->YMin=ymin+(range/16); } //-------------------------------------------------------------------- void __fastcall TPlotForm3::YZoomInButtonClick(TObject *Sender) { double range; double ymax=XYPlot1->YMax; double ymin=XYPlot1->YMin; XYPlot1->YAutoScale=false; range=ymax-ymin; XYPlot1->YMax=ymax-(range/8); XYPlot1->YMin=ymin+(range/8); } //-------------------------------------------------------------------- void __fastcall TPlotForm3::YZoomOutButtonClick(TObject *Sender) { double range; double ymax=XYPlot1->YMax; double ymin=XYPlot1->YMin; XYPlot1->YAutoScale=false; range=ymax-ymin; XYPlot1->YMax=ymax+(range/8);

Page 312: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

302

XYPlot1->YMin=ymin-(range/8); } //-------------------------------------------------------------------- void __fastcall TPlotForm3::ScrollDownButtonClick(TObject *Sender) { double range; double ymax=XYPlot1->YMax; double ymin=XYPlot1->YMin; XYPlot1->YAutoScale=false; range=ymax-ymin; XYPlot1->YMax=ymax-(range/16); XYPlot1->YMin=ymin-(range/16); } //-------------------------------------------------------------------- void __fastcall TPlotForm3::ScrollLeftButtonClick(TObject *Sender) { double range; double xmax=XYPlot1->XMax; double xmin=XYPlot1->XMin; XYPlot1->XAutoScale=false; range=xmax-xmin; XYPlot1->XMax=xmax-(range/16); XYPlot1->XMin=xmin-(range/16); } //-------------------------------------------------------------------- void __fastcall TPlotForm3::XZoomInButtonClick(TObject *Sender) { double range; double xmax=XYPlot1->XMax; double xmin=XYPlot1->XMin; XYPlot1->XAutoScale=false; range=xmax-xmin; XYPlot1->XMax=xmax-(range/8); XYPlot1->XMin=xmin+(range/8); } //-------------------------------------------------------------------- void __fastcall TPlotForm3::XZoomOutButtonClick(TObject *Sender) { double range; double xmax=XYPlot1->XMax; double xmin=XYPlot1->XMin; XYPlot1->XAutoScale=false; range=xmax-xmin; XYPlot1->XMax=xmax+(range/8); XYPlot1->XMin=xmin-(range/8); } //-------------------------------------------------------------------- void __fastcall TPlotForm3::ScrollRightButtonClick(TObject *Sender) { double range; double xmax=XYPlot1->XMax; double xmin=XYPlot1->XMin; XYPlot1->XAutoScale=false; range=xmax-xmin;

Page 313: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

303

XYPlot1->XMax=xmax+(range/16); XYPlot1->XMin=xmin+(range/16); } //-------------------------------------------------------------------- void __fastcall TPlotForm3::XYPlot1MouseMove(TObject *Sender, TShiftState Shift, int X, int Y) { char temp[20]; AnsiString ansixmouse = XYPlot1->MouseX; char* pxmouse=ansixmouse.c_str(); float xmouse=atof(pxmouse); sprintf(temp,"%.2f",xmouse); XMouseLabel->Caption=temp; AnsiString ansiymouse = XYPlot1->MouseY; char* pymouse=ansiymouse.c_str(); float ymouse=atof(pymouse); sprintf(temp,"%.0f",ymouse); YMouseLabel->Caption=temp; } //--------------------------------------------------------------------

Page 314: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

304

Plot3.h – Plotform3 header file //-------------------------------------------------------------------- #ifndef Plot3H #define Plot3H //-------------------------------------------------------------------- #include <vcl\Classes.hpp> #include <vcl\Controls.hpp> #include <vcl\StdCtrls.hpp> #include <vcl\Forms.hpp> #include <vcl\ExtCtrls.hpp> #include <vcl\Buttons.hpp> #include "xyplot.h" //-------------------------------------------------------------------- class TPlotForm3 : public TForm { __published: // IDE-managed Components TPanel *Panel2; TSpeedButton *XZoomInButton; TSpeedButton *XZoomOutButton; TLabel *Label5; TSpeedButton *ScrollRightButton; TSpeedButton *ScrollLeftButton; TPanel *Panel5; TLabel *XMouseLabel; TPanel *Panel3; TPanel *Panel4; TPanel *Panel1; TLabel *Label1; TLabel *Label2; TSpeedButton *YZoomInButton; TSpeedButton *YZoomOutButton; TSpeedButton *ScrollDownButton; TSpeedButton *ScrollUpButton; TButton *CloseButton; TPanel *Panel6; TLabel *YMouseLabel; TXYPlot *XYPlot1; void __fastcall CloseButtonClick(TObject *Sender); void __fastcall ScrollUpButtonClick(TObject *Sender); void __fastcall YZoomInButtonClick(TObject *Sender); void __fastcall YZoomOutButtonClick(TObject *Sender); void __fastcall ScrollDownButtonClick(TObject *Sender); void __fastcall ScrollLeftButtonClick(TObject *Sender); void __fastcall XZoomInButtonClick(TObject *Sender); void __fastcall XZoomOutButtonClick(TObject *Sender); void __fastcall ScrollRightButtonClick(TObject *Sender); void __fastcall XYPlot1MouseMove(TObject *Sender, TShiftState Shift, int X, int Y); private: // User declarations public: // User declarations __fastcall TPlotForm3(TComponent* Owner);

Page 315: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

305

}; //-------------------------------------------------------------------- extern TPlotForm3 *PlotForm3; //-------------------------------------------------------------------- #endif

Page 316: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

306

Plot4.cpp – Plotform4 source code //-------------------------------------------------------------------- #include <vcl\vcl.h> #pragma hdrstop #include "Plot4.h" //-------------------------------------------------------------------- #pragma link "xyplot" #pragma resource "*.dfm" TPlotForm4 *PlotForm4; //-------------------------------------------------------------------- __fastcall TPlotForm4::TPlotForm4(TComponent* Owner) : TForm(Owner) { } //-------------------------------------------------------------------- void __fastcall TPlotForm4::CloseButtonClick(TObject *Sender) { PlotForm4->Close(); } //-------------------------------------------------------------------- void __fastcall TPlotForm4::ScrollUpButtonClick(TObject *Sender) { double range; double ymax=XYPlot1->YMax; double ymin=XYPlot1->YMin; XYPlot1->YAutoScale=false; range=ymax-ymin; XYPlot1->YMax=ymax+(range/16); XYPlot1->YMin=ymin+(range/16); } //-------------------------------------------------------------------- void __fastcall TPlotForm4::YZoomInButtonClick(TObject *Sender) { double range; double ymax=XYPlot1->YMax; double ymin=XYPlot1->YMin; XYPlot1->YAutoScale=false; range=ymax-ymin; XYPlot1->YMax=ymax-(range/8); XYPlot1->YMin=ymin+(range/8); } //-------------------------------------------------------------------- void __fastcall TPlotForm4::YZoomOutButtonClick(TObject *Sender) { double range; double ymax=XYPlot1->YMax; double ymin=XYPlot1->YMin; XYPlot1->YAutoScale=false; range=ymax-ymin; XYPlot1->YMax=ymax+(range/8);

Page 317: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

307

XYPlot1->YMin=ymin-(range/8); } //-------------------------------------------------------------------- void __fastcall TPlotForm4::ScrollDownButtonClick(TObject *Sender) { double range; double ymax=XYPlot1->YMax; double ymin=XYPlot1->YMin; XYPlot1->YAutoScale=false; range=ymax-ymin; XYPlot1->YMax=ymax-(range/16); XYPlot1->YMin=ymin-(range/16); } //-------------------------------------------------------------------- void __fastcall TPlotForm4::ScrollLeftButtonClick(TObject *Sender) { double range; double xmax=XYPlot1->XMax; double xmin=XYPlot1->XMin; XYPlot1->XAutoScale=false; range=xmax-xmin; XYPlot1->XMax=xmax-(range/16); XYPlot1->XMin=xmin-(range/16); } //-------------------------------------------------------------------- void __fastcall TPlotForm4::XZoomInButtonClick(TObject *Sender) { double range; double xmax=XYPlot1->XMax; double xmin=XYPlot1->XMin; XYPlot1->XAutoScale=false; range=xmax-xmin; XYPlot1->XMax=xmax-(range/8); XYPlot1->XMin=xmin+(range/8); } //-------------------------------------------------------------------- void __fastcall TPlotForm4::XZoomOutButtonClick(TObject *Sender) { double range; double xmax=XYPlot1->XMax; double xmin=XYPlot1->XMin; XYPlot1->XAutoScale=false; range=xmax-xmin; XYPlot1->XMax=xmax+(range/8); XYPlot1->XMin=xmin-(range/8); } //-------------------------------------------------------------------- void __fastcall TPlotForm4::ScrollRightButtonClick(TObject *Sender) { double range; double xmax=XYPlot1->XMax; double xmin=XYPlot1->XMin; XYPlot1->XAutoScale=false; range=xmax-xmin;

Page 318: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

308

XYPlot1->XMax=xmax+(range/16); XYPlot1->XMin=xmin+(range/16); } //-------------------------------------------------------------------- void __fastcall TPlotForm4::XYPlot1MouseMove(TObject *Sender, TShiftState Shift, int X, int Y) { char temp[20]; AnsiString ansixmouse = XYPlot1->MouseX; char* pxmouse=ansixmouse.c_str(); float xmouse=atof(pxmouse); sprintf(temp,"%.2f",xmouse); XMouseLabel->Caption=temp; AnsiString ansiymouse = XYPlot1->MouseY; char* pymouse=ansiymouse.c_str(); float ymouse=atof(pymouse); sprintf(temp,"%.0f",ymouse); YMouseLabel->Caption=temp; } //--------------------------------------------------------------------

Page 319: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

309

Plot4.h – Plotform4 header file //-------------------------------------------------------------------- #ifndef Plot4H #define Plot4H //-------------------------------------------------------------------- #include <vcl\Classes.hpp> #include <vcl\Controls.hpp> #include <vcl\StdCtrls.hpp> #include <vcl\Forms.hpp> #include <vcl\ExtCtrls.hpp> #include <vcl\Buttons.hpp> #include "xyplot.h" //-------------------------------------------------------------------- class TPlotForm4 : public TForm { __published: // IDE-managed Components TPanel *Panel4; TPanel *Panel1; TLabel *Label1; TLabel *Label2; TSpeedButton *YZoomInButton; TSpeedButton *YZoomOutButton; TSpeedButton *ScrollDownButton; TSpeedButton *ScrollUpButton; TButton *CloseButton; TPanel *Panel6; TLabel *YMouseLabel; TPanel *Panel2; TSpeedButton *XZoomInButton; TSpeedButton *XZoomOutButton; TLabel *Label5; TSpeedButton *ScrollRightButton; TSpeedButton *ScrollLeftButton; TPanel *Panel5; TLabel *XMouseLabel; TPanel *Panel3; TXYPlot *XYPlot1; void __fastcall CloseButtonClick(TObject *Sender); void __fastcall ScrollUpButtonClick(TObject *Sender); void __fastcall YZoomInButtonClick(TObject *Sender); void __fastcall YZoomOutButtonClick(TObject *Sender); void __fastcall ScrollDownButtonClick(TObject *Sender); void __fastcall ScrollLeftButtonClick(TObject *Sender); void __fastcall XZoomInButtonClick(TObject *Sender); void __fastcall XZoomOutButtonClick(TObject *Sender); void __fastcall ScrollRightButtonClick(TObject *Sender); void __fastcall XYPlot1MouseMove(TObject *Sender, TShiftState Shift, int X, int Y); private: // User declarations public: // User declarations __fastcall TPlotForm4(TComponent* Owner);

Page 320: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

310

}; //-------------------------------------------------------------------- extern TPlotForm4 *PlotForm4; //-------------------------------------------------------------------- #endif

Page 321: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

311

Runcontrolprogram.cpp – Runform source code //-------------------------------------------------------------------- #include <vcl\vcl.h> #pragma hdrstop #include "stdlib.h" #include "Runcontrolprogram.h" #include "main.h" #include "Downloadstarterror.h" //-------------------------------------------------------------------- #pragma link "zcomm" #pragma resource "*.dfm" TRunProgramForm *RunProgramForm; void delay_1(int ms); void delay_1(int ms) { DWORD time1 = GetTickCount(); while(GetTickCount()<time1+ms); } //-------------------------------------------------------------------- __fastcall TRunProgramForm::TRunProgramForm(TComponent* Owner) : TForm(Owner) { } //-------------------------------------------------------------------- void __fastcall TRunProgramForm::CommReceiveDataAvailable( TObject *Sender) // This event handler monitors the characters received from the // microcontroller and will start the program on the microcontroller // when the characters which correspond to a reset action is received // from the microcontroller. If any other characters is received // from the microcontroller, the program will call the // ErrorDownloadStartMessage form in which the user will be prompted // that a running program on the microcontroller has to be stopped // before the program on the microcontroller can be started. { unsigned char *buffer,data[10]; buffer=data; // Clear the input buffer by writing zero's to it for (int n=0;n<=10;n++) {data[n]=0;} CommReceive->ReadComm(buffer,4); // The next line can also be: // if (data[0]==13 && data[1]==10 && data[2]==66 && data[3]==85) if (data[0]==13) // if reset is detected { BlinkTimer->Enabled=false;

Page 322: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

312

CommReceive->CloseConnection(); RunProgramForm->Close(); RunComm->OpenConnection(); RunComm->WriteCommByte(13); delay_1(50); char gb600[]="g 2000"; for (int cnt=0;cnt<=5;cnt++) { RunComm->WriteCommByte(gb600[cnt]); delay_1(50); } RunComm->WriteCommByte(13); RunComm->CloseConnection(); // The following four lines will convert the AnsiString type text // into an integer. // If the selected microcontroller program is: // PID -> mcuprogram = 1 // TestADCDAC -> mcuprogram = 2 if (MonitorForm->Recorddatawhencontrolprogramstarts1->Checked) { // if the Digital Control program was selected if (MonitorForm->DigitalController1->Checked) { MonitorForm->DigitalMonitorButtonClick(Sender); MonitorForm->DigitalRecordButtonClick(Sender); } // if the Multi Control program was selected else if (MonitorForm->MultiController1->Checked) { MonitorForm->MultiMonitorButtonClick(Sender); MonitorForm->MultiRecordButtonClick(Sender); } // if the PID program was selected else if (MonitorForm->PIDController1->Checked) { MonitorForm->PIDMonitorButtonClick(Sender); MonitorForm->PIDRecordButtonClick(Sender); } // if the TestDACADC program was selected else if (MonitorForm->TestDACADC1->Checked) { MonitorForm->TestDACADCMonitorButtonClick(Sender); MonitorForm->TestDACADCRecordButtonClick(Sender); } } else { // if the Digital Control program was selected if (MonitorForm->DigitalController1->Checked) { MonitorForm->DigitalMonitorButtonClick(Sender); }

Page 323: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

313

// if the Multi Control program was selected else if (MonitorForm->MultiController1->Checked) { MonitorForm->MultiMonitorButtonClick(Sender); } // if the PID program was selected else if (MonitorForm->PIDController1->Checked) { MonitorForm->PIDMonitorButtonClick(Sender); } // if the TestDACADC program was selected else if (MonitorForm->TestDACADC1->Checked) { MonitorForm->TestDACADCMonitorButtonClick(Sender); } } } // if reset is not detected else { // The next six lines of program code will disable serial // communication between the PC and the microcontroller // and will activate the ErrorDownloadStartMessage form in which // the user will be prompted that a running program on the // microcontroller has to be stopped before the progrma can be // started on the microcontroller. BlinkTimer->Enabled=false; RunComm->CloseConnection(); RunProgramForm->Close(); ErrorDownloadStartMessage->Label3->Caption= "starting the new program."; ErrorDownloadStartMessage->ShowModal(); } } //-------------------------------------------------------------------- void __fastcall TRunProgramForm::BlinkTimerTimer(TObject *Sender) { if (Messagebox->Caption=="") { Messagebox->Caption="Reset The Microcontroller"; } else Messagebox->Caption=""; } //-------------------------------------------------------------------- void __fastcall TRunProgramForm::CancelButtonClick(TObject *Sender) { RunProgramForm->Close(); } //-------------------------------------------------------------------- void __fastcall TRunProgramForm::FormActivate(TObject *Sender)

Page 324: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

314

{ // This event handler enable the serial communication between // the PC and the microcontroller. CommReceive->OpenConnection(); BlinkTimer->Enabled=true; } //-------------------------------------------------------------------- void __fastcall TRunProgramForm::FormClose(TObject *Sender, TCloseAction &Action) // This event handler will check whether serial communication between // the PC and the microcontroller is enabled when RunProgrmaForm // closes and will disconnect the serail port before the form closes. { if (CommReceive->Connected==true) CommReceive->CloseConnection(); } //--------------------------------------------------------------------

Page 325: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

315

Runcontrolprogram.h – Runform header file //-------------------------------------------------------------------- #ifndef RuncontrolprogramH #define RuncontrolprogramH //-------------------------------------------------------------------- #include <vcl\Classes.hpp> #include <vcl\Controls.hpp> #include <vcl\StdCtrls.hpp> #include <vcl\Forms.hpp> #include <vcl\ExtCtrls.hpp> #include "zcomm.h" //-------------------------------------------------------------------- class TRunProgramForm : public TForm { __published: // IDE-managed Components TButton *CancelButton; TLabel *Messagebox; TTimer *BlinkTimer; TZComm *CommReceive; TZComm *RunComm; void __fastcall CommReceiveDataAvailable(TObject *Sender); void __fastcall BlinkTimerTimer(TObject *Sender); void __fastcall CancelButtonClick(TObject *Sender); void __fastcall FormActivate(TObject *Sender); void __fastcall FormClose(TObject *Sender, TCloseAction &Action); private: // User declarations public: // User declarations __fastcall TRunProgramForm(TComponent* Owner); }; //-------------------------------------------------------------------- extern TRunProgramForm *RunProgramForm; //-------------------------------------------------------------------- #endif

Page 326: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

316

Savedata.cpp – Savedata form source code //-------------------------------------------------------------------- #include <vcl\vcl.h> #pragma hdrstop #include "Savedata.h" #include "main.h" //-------------------------------------------------------------------- #pragma resource "*.dfm" TFileOverwriteDialogBox *FileOverwriteDialogBox; //-------------------------------------------------------------------- // This unit is called by the SaveButtonClick event handler in the // "main.cpp" unit. This program section will display the // FileOverwriteDialogBox form which will prompt the user whether // the save procedure may continue or not. //-------------------------------------------------------------------- __fastcall TFileOverwriteDialogBox::TFileOverwriteDialogBox (TComponent* Owner) : TForm(Owner) { } //-------------------------------------------------------------------- void __fastcall TFileOverwriteDialogBox::NoButtonClick( TObject *Sender) // This event handler cancel the save process. { FileOverwriteDialogBox->Close(); } //-------------------------------------------------------------------- void __fastcall TFileOverwriteDialogBox::YesButtonClick( TObject *Sender) { // This event handler will close the FileOverwriteDialogBox form and // call the SaveNowHiddenButtonClick event handler in the "main.cpp" // unit. FileOverwriteDialogBox->Close(); MonitorForm->SaveNowHiddenButtonClick(Sender); } //--------------------------------------------------------------------

Page 327: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

317

Savedata.h – Savedata form header file //-------------------------------------------------------------------- #ifndef SavedataH #define SavedataH //-------------------------------------------------------------------- #include <vcl\Classes.hpp> #include <vcl\Controls.hpp> #include <vcl\StdCtrls.hpp> #include <vcl\Forms.hpp> #include <vcl\ExtCtrls.hpp> //-------------------------------------------------------------------- class TFileOverwriteDialogBox : public TForm { __published: // IDE-managed Components TLabel *Label1; TLabel *Label2; TButton *YesButton; TButton *NoButton; TLabel *Label3; TImage *Image1; void __fastcall NoButtonClick(TObject *Sender); void __fastcall YesButtonClick(TObject *Sender); private: // User declarations public: // User declarations __fastcall TFileOverwriteDialogBox(TComponent* Owner); }; //-------------------------------------------------------------------- extern TFileOverwriteDialogBox *FileOverwriteDialogBox; //-------------------------------------------------------------------- #endif

Page 328: Software Development for Microprocessor Control Systems

Appendix F – The Windows-Based Software Source Code

318

Page 329: Software Development for Microprocessor Control Systems

319

Appendix G The Microcontroller Software Source Code This section contains all the microcontroller software source code. The different modules will be listed as follow: Hc11e9.h Header file for the 68HC11 register definitions Start11.c Default startup code for the 68HC11 Non_bank.sgm HC11 Small and medium memory model Lustart.h Header file which defines the startup description Testio.c Source code for the Test I/O module Testio.prm Linker parameter file for the Test I/O module Digital.c Source code for the SISO Digial Controller Module Digital.prm Linker parameter file for the SISO Digial Controller Module Multi.c Source code for the MIMO Digial Controller Module Multi.prm Linker parameter file for the MIMO Digial Controller Module

Page 330: Software Development for Microprocessor Control Systems

Appendix G – The Microcontroller Software Source Code

320

Hc11e9.h - Header file for the 68HC11 register definitions. #ifndef HC11e9 #define HC11e9 #define Register unsigned char typedef struct { unsigned int bit0 : 1; unsigned int bit1 : 1; unsigned int bit2 : 1; unsigned int bit3 : 1; unsigned int bit4 : 1; unsigned int bit5 : 1; unsigned int bit6 : 1; unsigned int bit7 : 1; } RegisterBits; unsigned int Register_Set=0x1000; #define LCD1 (*(volatile Register*)(0x0000)) #define PORTA (*(volatile Register*)(Register_Set + 0x00)) #define PIOC (*(Register*)(Register_Set + 0x02)) #define PORTC (*(volatile Register*)(Register_Set + 0x03)) #define PORTB (*(volatile Register*)(Register_Set + 0x04)) #define PORTCL (*(volatile Register*)(Register_Set + 0x05)) #define DDRC (*(Register*)(Register_Set + 0x07)) #define PORTD (*(volatile Register*)(Register_Set + 0x08)) #define DDRD (*(Register*)(Register_Set + 0x09)) #define PORTE (*(volatile Register*)(Register_Set + 0x0A)) #define CFORC (*(Register*)(Register_Set + 0x0B)) #define OC1M (*(volatile RegisterBits*)(Register_Set + 0x0C)) #define OC1D (*(volatile RegisterBits*)(Register_Set + 0x0D)) #define TCNT (*(volatile unsigned int *)(Register_Set + 0x0E)) #define TCNTUP (*(volatile unsigned char *)(Register_Set + 0x0E)) #define TIC1 (*(volatile unsigned int *)(Register_Set + 0x10)) #define TIC2 (*(volatile unsigned int *)(Register_Set + 0x12)) #define TIC3 (*(volatile unsigned int *)(Register_Set + 0x14)) #define TIC3UP (*(volatile unsigned char *)(Register_Set + 0x14)) #define TOC1 (*(volatile unsigned int *)(Register_Set + 0x16)) #define TOC1UP (*(volatile unsigned char *)(Register_Set + 0x16)) #define TOC2 (*(volatile unsigned int *)(Register_Set + 0x18)) #define TOC2UP (*(volatile unsigned char *)(Register_Set + 0x18)) #define TOC3 (*(volatile unsigned int *)(Register_Set + 0x1A)) #define TOC3UP (*(volatile unsigned char *)(Register_Set + 0x1A)) #define TOC4 (*(volatile unsigned int *)(Register_Set + 0x1C)) #define TOC4UP (*(volatile unsigned char *)(Register_Set + 0x1C)) #define TOC5 (*(volatile unsigned int *)(Register_Set + 0x1E)) #define TOC5UP (*(volatile unsigned char *)(Register_Set + 0x1E)) #define TCTL1 (*(RegisterBits*)(Register_Set + 0x20)) #define TCTL2 (*(Register*)(Register_Set + 0x21)) #define TMSK1 (*(volatile RegisterBits*)(Register_Set + 0x22))

Page 331: Software Development for Microprocessor Control Systems

Appendix G – The Microcontroller Software Source Code

321

#define TFLG1 (*(volatile RegisterBits*)(Register_Set + 0x23)) #define TFLG1BYTE (*(volatile Register*)(Register_Set + 0x23)) #define TMSK2 (*(volatile RegisterBits*)(Register_Set + 0x24)) #define TFLG2 (*(volatile RegisterBits*)(Register_Set + 0x25)) #define TFLG2BYTE (*(volatile Register*)(Register_Set + 0x25)) #define PACTL (*(RegisterBits*)(Register_Set + 0x26)) #define PACNT (*(volatile Register*)(Register_Set + 0x27)) #define SPCR (*(Register*)(Register_Set + 0x28)) #define SPSR (*(volatile Register*)(Register_Set + 0x29)) #define SPDR (*(volatile Register*)(Register_Set + 0x2A)) #define BAUD (*(Register*)(Register_Set + 0x2B)) #define SCCR1 (*(volatile Register*)(Register_Set + 0x2C)) #define SCCR2 (*(Register*)(Register_Set + 0x2D)) #define SCSR (*(volatile Register*)(Register_Set + 0x2E)) #define SCDR (*(volatile unsigned char*)(Register_Set + 0x2F)) #define ADCTL (*(volatile Register*)(Register_Set + 0x30)) #define ADR1 (*(volatile unsigned char*)(Register_Set + 0x31)) #define ADR2 (*(volatile unsigned char*)(Register_Set + 0x32)) #define ADR3 (*(volatile unsigned char*)(Register_Set + 0x33)) #define ADR4 (*(volatile unsigned char*)(Register_Set + 0x34)) #define BPROT (*(Register*)(Register_Set + 0x35)) #define OPTION (*(Register*)(Register_Set + 0x39)) #define COPRSR (*(Register*)(Register_Set + 0x3A)) #define PPROG (*(Register*)(Register_Set + 0x3B)) #define HPRIO (*(RegisterBits*)(Register_Set + 0x3C)) #define INIT (*(Register*)(Register_Set + 0x3D)) #define TEST1 (*(Register*)(Register_Set + 0x3E)) #define CONFIG (*(Register*)(Register_Set + 0x3F)) /* CFORC bit definitions 0x0B */ #define FOC1 bit7 #define FOC2 bit6 #define FOC3 bit5 #define FOC4 bit4 #define FOC5 bit3 /* OC1M bit definitions 0x0C */ #define OC1M7 bit7 #define OC1M6 bit6 #define OC1M5 bit5 #define OC1M4 bit4 #define OC1M3 bit3 /* OC1D bit definitions 0x0D */ #define OC1D7 bit7 #define OC1D6 bit6 #define OC1D5 bit5 #define OC1D4 bit4 #define OC1D3 bit3 /* TCTL1 bit definition 0x20 */

Page 332: Software Development for Microprocessor Control Systems

Appendix G – The Microcontroller Software Source Code

322

#define OM2 bit7 #define OL2 bit6 #define OM3 bit5 #define OL3 bit4 #define OM4 bit3 #define OL4 bit2 #define OM5 bit1 #define OL5 bit0 /* TCTL2 bit definitions 0x21 */ #define EDG4B bit7 #define EDG4A bit6 #define EDG1B bit5 #define EDG1A bit4 #define EDG2B bit3 #define EDG2A bit2 #define EDG3B bit1 #define EDG3A bit0 /* TMSK1 bit definitions 0x22 */ #define OC1I bit7 #define OC2I bit6 #define OC3I bit5 #define OC4I bit4 #define I4O5I bit3 #define IC1I bit2 #define IC2I bit1 #define IC3I bit0 /* TFLG1 bit definitions 0x23 */ #define OC1F 0x80 #define OC2F 0x40 #define OC3F 0x20 #define OC4F 0x10 #define I4O5F 0x08 #define IC1F 0x04 #define IC2F 0x02 #define IC3F 0x01 /* TMSK2 bit definitions 0x24 */ #define TOI bit7 #define RTII bit6 #define PAOVI bit5 #define PAII bit4 #define PR1 bit1 #define PR0 bit0 /* TFLG2 bit definitions 0x25 */

Page 333: Software Development for Microprocessor Control Systems

Appendix G – The Microcontroller Software Source Code

323

#define TOF 0x80 #define RTIF 0x40 #define PAOVF 0x20 #define PAIF 0x10 /* PACTL bit definitions 0x26 */ #define DDRA7 bit7 #define PAEN bit6 #define PAMOD bit5 #define PEDGE bit4 #define DDRA3 bit3 #define I4O5 bit2 #define RTR1 bit1 #define RTR0 bit0 /* SPCR bit definitions 0x28 */ #define SPIE bit7 #define SPE bit6 #define DWOM bit5 #define MSTR bit4 #define CPOL bit3 #define CPHA bit2 #define SPR1 bit1 #define SPR0 bit0 /* SPSR bit definitions 0x29 */ #define SPIF bit7 #define WCOL bit6 #define MODF bit4 /* BAUD bit definitions 0x2B */ #define TCLR bit7 #define SCP1 bit5 #define SCP0 bit4 #define RCKB bit3 #define SCR2 bit2 #define SCR1 bit1 #define SCR0 bit0 /* SCCR1 bit definition 0x2C */ #define R8 bit7 #define T8 bit6 #define M bit4 #define WAKE bit3 /* SCCR2 bit definitions 0x2D */ #define TIE bit7 #define TCIE bit6

Page 334: Software Development for Microprocessor Control Systems

Appendix G – The Microcontroller Software Source Code

324

#define RIE bit5 #define ILIE bit4 #define TE bit3 #define RE bit2 #define RWU bit1 #define SBK bit0 /* SCSR bit definitions 0x2E */ #define TDRE bit7 #define TC bit6 #define RDRF bit5 #define IDLE bit4 #define OR bit3 #define NF bit2 #define FE bit1 /* SCDR bit definitions 0x2F */ #define R7T7 bit7 #define R6T6 bit6 #define R5T5 bit5 #define R4T4 bit4 #define R3T3 bit3 #define R2T2 bit2 #define R1T1 bit1 #define R0T0 bit0 /* ADCTL bit definitions 0x30 */ #define CCF bit7 #define SCAN bit5 #define MULT bit4 #define CD bit3 #define CC bit2 #define CB bit1 #define CA bit0 /* BPROT bit definitions 0x35 */ #define PTCON bit4 #define BPRT3 bit3 #define BPRT2 bit2 #define BPRT1 bit1 #define BPRT0 bit0 /* OPTION bit definitions 0x39 */ #define ADPU bit7 #define CSEL bit6 #define IRQE bit5 #define DLY bit4 #define CME bit3 #define CR1 bit1

Page 335: Software Development for Microprocessor Control Systems

Appendix G – The Microcontroller Software Source Code

325

#define CR0 bit0 /* PPROG bit definitions 0x3B */ #define ODD bit7 #define EVEN bit6 #define ELAT bit5 #define BYTE bit4 #define ROW bit3 #define ERASE bit2 #define EELAT bit1 #define EEPGM bit0 /* HPRIO bit definitions 0x3C */ #define RBOOT bit7 #define SMOD bit6 #define MDA bit5 #define IRV bit4 #define PSEL3 bit3 #define PSEL2 bit2 #define PSEL1 bit1 #define PSEL0 bit0 /* INIT bit definitions 0x3D */ #define RAM3 bit7 #define RAM2 bit6 #define RAM1 bit5 #define RAM0 bit4 #define REG3 bit3 #define REG2 bit2 #define REG1 bit1 #define REG0 bit0 /* TEST1 bit definitions 0x3E */ #define TILOP bit7 #define OCCR bit5 #define CBYP bit4 #define DISR bit3 #define FCM bit2 #define FCOP bit1 #define TCON bit0 /* CONFIG bit definitions 0x3F */ #define NOSEC bit3 #define NOCOP bit2 #define ROMON bit1 #define EEON bit0 /* PORTA bit definitions 0x00 */

Page 336: Software Development for Microprocessor Control Systems

Appendix G – The Microcontroller Software Source Code

326

#define PA7 bit7 #define PA6 bit6 #define PA5 bit5 #define PA4 bit4 #define PA3 bit3 #define PA2 bit2 #define PA1 bit1 #define PA0 bit0 /* PORTC bit definitions 0x03 */ #define PC7 bit7 #define PC6 bit6 #define PC5 bit5 #define PC4 bit4 #define PC3 bit3 #define PC2 bit2 #define PC1 bit1 #define PC0 bit0 /* PORTB bit definitions 0x04 */ #define PB7 bit7 #define PB6 bit6 #define PB5 bit5 #define PB4 bit4 #define PB3 bit3 #define PB2 bit2 #define PB1 bit1 #define PB0 bit0 /* PORTCL bit definitions 0x05 */ #define PCL7 bit7 #define PCL6 bit6 #define PCL5 bit5 #define PCL4 bit4 #define PCL3 bit3 #define PCL2 bit2 #define PCL1 bit1 #define PCL0 bit0 /* DDRC bit definitions 0x07 */ #define DDC7 bit7 #define DDC6 bit6 #define DDC5 bit5 #define DDC4 bit4 #define DDC3 bit3 #define DDC2 bit2 #define DDC1 bit1 #define DDC0 bit0 /* PORTD bit definitions 0x08 */

Page 337: Software Development for Microprocessor Control Systems

Appendix G – The Microcontroller Software Source Code

327

#define PD5 bit5 #define PD4 bit4 #define PD3 bit3 #define PD2 bit2 #define PD1 bit1 #define PD0 bit0 /* DDRD bit definitions 0x09 */ #define DDD5 bit5 #define DDD4 bit4 #define DDD3 bit3 #define DDD2 bit2 #define DDD1 bit1 #define DDD0 bit0 /* PORTE bit definitions 0x0A */ #define PE7 bit7 #define PE6 bit6 #define PE5 bit5 #define PE4 bit4 #define PE3 bit3 #define PE2 bit2 #define PE1 bit1 #define PE0 bit0 /* Macros and function to permit interrupt service routine programming from C */ #define vector(isr,vector_address) (*(void**)(vector_address)=(isr)) #define cli() _asm("cli\n") #define sei() _asm("sei\n") #define return_int() _asm("rti\n)" #define ldaa50 asm {ldaa #50} #define staa asm {staa 0x0000} #define TRUE 1 #define FALSE 0 #define FOREVER while(TRUE) typedef unsigned int WORD; typedef unsigned char BYTE; #endif

Page 338: Software Development for Microprocessor Control Systems

Appendix G – The Microcontroller Software Source Code

328

Start11.c - Default startup code for the 68HC11. /***************************************************** start11.c - HC11 Small and medium memory model ---------------------------------------------------- Copyright (c) 1995, Archimedes Software, Inc. All rights reserved *****************************************************/ #include "non_bank.sgm" #ifdef __BANKED__ extern void NEAR InitBank (void); #endif #include "lustart.h" /**********************************************************************/ struct _tagStartup _startupData; /* read-only: _startupData is allocated in ROM and initialized by the linker */ #pragma NO_FRAME static void NEAR Init(void) /* purpose: 1) zero out RAM-areas where data is allocated 2) copy initialization data from ROM to RAM parameters: EK page where '_startupData' is allocated called from: _Startup, LibInits */ { asm { ZeroOut: LDX _startupData.pZeroOut ; *pZeroOut LDY _startupData.nofZeroOuts ; nofZeroOuts BEQ CopyDown ; if nothing to zero out NextZeroOut: PSHX ; save *pZeroOut LDD 2,X ; byte count LDX 0,X ; start address NextWord: CLR 0,X ; clear memory byte INX ; inc address ADDD #-1 ; dec byte count

Page 339: Software Development for Microprocessor Control Systems

Appendix G – The Microcontroller Software Source Code

329

BNE NextWord ; PULX ; restore *pZeroOut INX ; advance *pZeroOut INX INX INX DEY ; dec nofZeroOuts BNE NextZeroOut ; CopyDown: LDX _startupData.toCopyDownBeg:2 ; load address of copy down desc. NextBlock: LDD 0,X ; size of init-data -> D BEQ FuncInits ; end of copy down desc. INX INX LDY 0,X ; destination address -> Y INX INX Copy: PSHB LDAB 0,X ; load a word from ROM and STAB 0,Y ; store it in the data area PULB INX ; increment addresses INY ADDD #-1 ; decrement word counter BNE Copy BRA NextBlock FuncInits: } } static long tmp; #pragma NO_FRAME void NEAR _Startup(void) /* purpose: 1) initialize the stack 2) initialize the RAM, copy down init dat etc (Init) 3) call main; parameters: NONE called from: _PRESTART-code generated by the Linker */ { for(;;) { /* forever: initialize the program; call the root-procedure */ asm{ #ifdef __BANKED__ JSR InitBank

Page 340: Software Development for Microprocessor Control Systems

Appendix G – The Microcontroller Software Source Code

330

#endif LDD _startupData.flags ; if flags then BNE Initialize ; init stack pointer LDX _startupData.stackOffset:2 ; stack pointer TXS Initialize: JSR Init ; CallMain: } #ifdef __BANKED__ { tmp = (long)_startupData.main; *(int *)&tmp |= 0x8000; (*(void (*) (void)) tmp) (); } #else (* _startupData.main) (); #endif } /* end loop forever */ }

Page 341: Software Development for Microprocessor Control Systems

Appendix G – The Microcontroller Software Source Code

331

Non_bank.sgm - HC11 Small and medium memory model. #undef FAR #undef NEAR #ifdef __BANKED__ #pragma CODE_SEG NON_BANKED #define FAR -- not allowed -- #define NEAR near #else #define FAR #define NEAR #endif

Page 342: Software Development for Microprocessor Control Systems

Appendix G – The Microcontroller Software Source Code

332

Lustart.h - Header file which defines the startup description. /***************************************************** lustart.h - data structures for startup ---------------------------------------------------- Copyright (c) 1995, Archimedes Software, Inc. All rights reserved Do not modify! *****************************************************/ #ifndef LUSTART_H #define LUSTART_H /*******************************************************************/ /* ABOUT */ /*-----------------------------------------------------------------*/ #if 0 the following datastructures contain the data needed to initialize the processor and memory #endif typedef struct{ unsigned char *beg; int size; /* [beg..beg+size] */ } _Range; typedef void (*_PFunc)(void); extern struct _tagStartup{ unsigned flags; _PFunc main; /* top procedure of user program */ unsigned dataPage; /* page where data allocation begins */ long stackOffset; int nofZeroOuts; _Range *pZeroOut; /* pZeroOut is a vector of ranges with nofZeroOuts elements */ long toCopyDownBeg; /* rom-address where copydown-data begins */ _PFunc *mInits; /* mInits is a vector of function pointers, terminated by 0 */ _PFunc *libInits; /* libInits is a vector of function pointers, terminated by 0 */ } _startupData; extern void _Startup(void); /* execution begins in this procedure */

Page 343: Software Development for Microprocessor Control Systems

Appendix G – The Microcontroller Software Source Code

333

/*--------------------------------------------------------------------*/ #endif

Page 344: Software Development for Microprocessor Control Systems

Appendix G – The Microcontroller Software Source Code

334

Testio.c - Source code for the testio module #include <hc11e9.h> void oc3interrupt(void); void inputcapture(void); void timeroverflow(void); void initpwm(void); void initic3(void); void initsci(void); void inittimerinterrupt(void); void putchar(char new_character); void getparameters(void); void initportb(void); void initadc(void); unsigned char adc(void); /* OC3 interrupt global variables */ volatile unsigned int toc3; volatile unsigned int toc1; volatile unsigned int pwmtimeon; unsigned int pwmperiod; /* Global variables for the inputcapture ISR */ unsigned int tic3upint; unsigned int overflow; unsigned int time1; unsigned char timeroverflows=0; unsigned int period=7813; /* Main Program global variables*/ unsigned char inoutcombination; volatile unsigned char sampletimeroverflows=0; unsigned int realsamplefreq=250; unsigned int realsampletime; volatile unsigned int sampletime; unsigned int reqoverflows; volatile unsigned char samplestarttime; volatile unsigned char sampleendtime; volatile unsigned int count=0; unsigned int maxsamplefreq; volatile unsigned int output=0; unsigned int step; unsigned int input; unsigned int dly; unsigned int outputlowerlimit; unsigned int outputupperlimit; /*Define the memory location for the 8-bit parallel output*/ #define MEMPORTB (*(volatile unsigned char*)(0xA102)) void main(void)

Page 345: Software Development for Microprocessor Control Systems

Appendix G – The Microcontroller Software Source Code

335

{ getparameters(); initsci(); inittimerinterrupt(); switch(inoutcombination) { case 1: initadc(); initportb(); break; case 2: initic3(); initportb(); break; case 3: initic3(); initpwm(); break; case 4: initadc(); initpwm(); break; } output=outputlowerlimit; asm cli; /* Enable the system interrupts */ while(1) { /* Save starttime of routine (the upper 8-bit value of TCNT) */ samplestarttime=TCNTUP; /* Determine the number of TCNTUP counts which correspond to a samplefrequency of maxsamplefreq Hz*/ sampletime=(7813/maxsamplefreq) + samplestarttime; reqoverflows=sampletime/256; sampleendtime=sampletime%256; count++; if ((float) count/realsamplefreq>=0.1*dly) { output=output+step; if (output>outputupperlimit) { output=outputlowerlimit; } count=0; } switch(inoutcombination) { case 2: /* Pulse Width Measurement */ case 3: asm sei; /* disable interrupts */ input=(unsigned int)7813/period;

Page 346: Software Development for Microprocessor Control Systems

Appendix G – The Microcontroller Software Source Code

336

asm cli; /* enable interrupts */ break; case 1: /* Analog input */ case 4: input=adc(); break; } switch(inoutcombination) { case 1: /* 8-Bit PIA Output */ case 2: MEMPORTB=output; break; case 3: /* PWM Output */ case 4: asm sei; pwmtimeon=((float) output/0x100)*pwmperiod; asm cli; break; } if (realsamplefreq>250) { realsamplefreq=250; } if (realsamplefreq<1) { realsamplefreq=1; } if (input>250) { input=250; } if (input<1) { input=1; } if (output>outputupperlimit) { output=outputupperlimit; } if (output<outputlowerlimit) { output=outputlowerlimit; } putchar(251); putchar(realsamplefreq); putchar(252); putchar(input); putchar(253); putchar(output); /*Wait for desired sample delay time to elapse */ while (sampletimeroverflows<reqoverflows); while (TCNTUP<sampleendtime); realsampletime=sampletimeroverflows*256 + TCNTUP - samplestarttime;

Page 347: Software Development for Microprocessor Control Systems

Appendix G – The Microcontroller Software Source Code

337

realsamplefreq=7813/realsampletime; sampletimeroverflows=0; /* Reset sampletimeroverflows */ } } /***************************************************/ /* TCNT counter overflow interrupt service routine */ /***************************************************/ void timeroverflow(void) { timeroverflows++; /* Timeroverflow counter for inputcapture */ sampletimeroverflows++; /*TFLG2.bit7=1; /* Reset timer overflow flag */ /*TFLG2BYTE=0x80;*/ asm { PSHA LDAA #0x80 STAA 0x1025 PULA RTI } } /***************************************************/ /* Frequency Measurement Interrupt Service Routine */ /***************************************************/ void inputcapture(void) { /* Note: It is not neccesary to use the lower 8-bit of the counter function. Because the 68HC11 is an 8-bit microcontroller,processing speed will significantly increase by leaving the lower 8-bits of the counter out of the calculations. The resolution of the upper 8-bits of the TCNT counter is 256*0.5 micro seconds = 0.000128 seconds which is still high enough to provide accurate timing. */ asm /* Reset input flag IC3F by writing 1 to it */ { PSHA LDAA #0x01 STAA 0x1023 PULA } if (TFLG2BYTE>=0x80 && TIC3UP<=0x80) { timeroverflows++; asm { /*Reset TOF Flag*/ PSHA LDAA #0x80

Page 348: Software Development for Microprocessor Control Systems

Appendix G – The Microcontroller Software Source Code

338

STAA 0x1025 PULA } } overflow=(unsigned int) timeroverflows*0x100; /* Copy upper 8-bits of the TIC3 register into tic3upint */ tic3upint=(unsigned int)TIC3UP; /* The overflow variable is the number of the upper 8-bit counts of the TNCT counter that correspond to the amount of TNCT overflows recorded in the timeroverflows variable */ period=(unsigned int) (overflow+tic3upint-time1); /* The period variable is the total number of TCNT upper 8-bit counts between this interrupt service routine and the previous one.*/ time1=(unsigned int)TIC3UP; /* Save the endtime of this ISR */ timeroverflows=0; /* Reset the timeroverflows variable */ asm RTI; } /**************************************/ /* SCI Character transmission routine */ /**************************************/ void putchar(char new_character) { char temp; temp=SCSR; temp=SCDR; while(SCSR==0); SCDR=new_character; } /************************************************/ /* Routine to initialize the microcontroller to */ /* generate a PWM signal on OC3 (PA5) */ /************************************************/ void initpwm(void) { /* Memory locations D9-DB is a 3 byte pseudo interrupt vector for TOC3(PA5) */ (char *) 0x00D9; /* Place jump instruction (op code 7E) in 00D9 */ *(char *) 0x00D9 = 0x7E; (int * ) 0x00DA; /* Place starting address of interrupt routine in DA&DB */ *(int *) 0x00DA = (int)oc3interrupt; OC1M.OC1M5=1; /*couple OC1 to PA7*/ TMSK1.OC3I=1; /*enable the OC3 interrupt*/

Page 349: Software Development for Microprocessor Control Systems

Appendix G – The Microcontroller Software Source Code

339

OC1D.OC1D5=1; /*turn on OC3 when OC1 occurs*/ TCTL1.OL3=1; /*toggle OC3 when OC3 occurs*/ TOC1=TCNT+50000; /* initialize OC1*/ TOC3=TOC1+25000; /* initialize OC3*/ } /*********************************/ /* OC3 Interrupt service routine */ /*********************************/ void oc3interrupt(void) { asm { PSHA LDAA #0x20 STAA 0x1023 PULA } toc1=TOC1+pwmperiod; TOC1=toc1; toc3=toc1+pwmtimeon; TOC3=toc3; asm rti; /*return from interrupt*/ } /************************************************************/ /* Routine to get the downloaded parameters from the PC */ /* The downloaded parameters are stored in 0x0000 - 0x0041 */ /************************************************************/ void getparameters(void) { unsigned char pwmhz; (unsigned char *) 0x0000; (unsigned char *) 0x0001; (unsigned char *) 0x0002; (unsigned char *) 0x0003; (unsigned char *) 0x0004; (unsigned char *) 0x0005; (unsigned char *) 0x0006; step=*(unsigned char *) 0x0000; dly=*(unsigned char *) 0x0001; maxsamplefreq=*(unsigned char *) 0x0002; pwmhz=*(unsigned char *) 0x0003; pwmperiod=2000000/pwmhz; outputlowerlimit=*(unsigned char *) 0x0004; outputupperlimit=*(unsigned char *) 0x0005; inoutcombination=*(unsigned char *) 0x0006; } /************************************************/ /* Routine to initialize the microcontroller to */ /* send and receive serial data */ /************************************************/

Page 350: Software Development for Microprocessor Control Systems

Appendix G – The Microcontroller Software Source Code

340

void initsci(void) { BAUD=0x30; /* Set serial communication to 9600 baud rate */ SCCR2=0xC; /* TE and RE high=Serial Transmit and Receive Enabled*/ } /***************************************************/ /* Routine to initialize the input capture 3 (IC3) */ /* PA0 pin to receive incoming data */ /***************************************************/ void initic3(void) { /* Set input capture in TIC3(PA0) on falling (rising=0x01) edges only */ TCTL2=0x02; TMSK1.bit0=1; /* Enable the interrupt mask for IC3 (PA0) */ asm { PSHA LDAA #0x01 STAA 0x1023 /* Reset flag */ PULA } /* Memory locations E2-E4 is a 3 byte pseudo interrupt vector for IC3(PA0) */ (char *) 0x00E2; /* Place jump instruction (op code 7E) in 00E2 */ *(char *) 0x00E2 = 0x7E; (int * ) 0x00E3; /* Place starting address of interrupt routine in E3&E4 */ *(int *) 0x00E3 = (int)inputcapture; } /*******************************************************/ /* Routine to initialize the timer overflow interrupt */ /*******************************************************/ void inittimerinterrupt(void) { TMSK2.bit7=1; /* Enable the timer overflow interrupt */ asm { /*Reset TOF Flag*/ PSHA LDAA #0x80 STAA 0x1025 PULA } /* Memory locations D0-D2 is a 3 byte pseudo interrupt vector for the timer overflow */ (char *) 0x00D0; /* Place jump instruction (op code 7E) in 00D0 */

Page 351: Software Development for Microprocessor Control Systems

Appendix G – The Microcontroller Software Source Code

341

*(char *) 0x00D0 = 0x7E; (int * ) 0x00D1; /* Place starting address of interrupt routine in D1&D2 */ *(int *) 0x00D1 = (int)timeroverflow; } /***************************************/ /* Function to initialize the */ /* analog-to-digital converter system */ /***************************************/ void initadc(void) { OPTION=0x80;/*Set bit 7 in OPTION high for A/D conversion*/ } /****************************************/ /* Analog to Digital conversion routine */ /****************************************/ unsigned char adc(void) { unsigned char temp; ADCTL=0x5; /* Set analog inputs on PE5 (pin 46) */ while (ADCTL<128); /* Wait for input */ temp=ADR1; return temp; } /******************************************************************/ /* Initialaise Port B on the MC6821 on the Memory extension board */ /* to serve as an 8-bit output port at memory address 0xA102 */ /******************************************************************/ void initportb(void) { (unsigned char *) 0xA102; (unsigned char *) 0xA103; *(unsigned char *) 0xA103=0x00; *(unsigned char *) 0xA102=0xFF; *(unsigned char *) 0xA103=0x04; }

Page 352: Software Development for Microprocessor Control Systems

Appendix G – The Microcontroller Software Source Code

342

Testio.prm Linker parameter file for the testio module. LINK testio.abs NAMES testio.o start11.o ansi.lib END SECTIONS MY_RAM = READ_WRITE 0x4000 TO 0x4FFF; MY_ROM = READ_ONLY 0x2000 TO 0x3FFF; PLACEMENT DEFAULT_ROM INTO MY_ROM; DEFAULT_RAM INTO MY_RAM; END STACKSIZE 0x600

Page 353: Software Development for Microprocessor Control Systems

Appendix G – The Microcontroller Software Source Code

343

Digital.c – Source code for the SISO Digial Controller Module /* SISO Digital Cotroller */ /* Input: Frequency (Hz) on PA0 */ /* Output: PWM on PA3 */ #include <hc11e9.h> /******************************************************************* Description of fuctions oc3interrupt - Interrupt service routine for OC3 inputcapture - Interrupt service routine for frequency sensor (TIC3) timeroverflow - Interrupt service routine for TCNT overflow initpwm - Initialation routine for the PWM output initic3 - Initialation routine for the frequency sensor (TIC3) initsci - Initialation routine for the Serial Communication Interface inittimerinterrupt - Initialation routine for the TCNT timer overflow interrupt putchar - Function to write characters to the serial port getparameters - Function to read the downloaded parameter values delay - Function to enable a short delay before the program starts ********************************************************************/ void oc3interrupt(void); void inputcapture(void); void timeroverflow(void); void initpwm(void); void initic3(void); void initsci(void); void inittimerinterrupt(void); void putchar(char new_character); void getparameters(void); void delay(void); void initportb(void); void initadc(void); unsigned char adc(void); /* OC3 interrupt global variables */ unsigned int toc3; unsigned int toc1; unsigned int pwmtimeon; unsigned int pwmperiod; /* Global variables for the inputcapture ISR */ unsigned int tic3upint; unsigned int overflow; unsigned int time1; unsigned char timeroverflows=0; unsigned int period=7813; /* Main Program control global variables*/ unsigned char inoutcombination;

Page 354: Software Development for Microprocessor Control Systems

Appendix G – The Microcontroller Software Source Code

344

unsigned char feedbackmode; unsigned int setpoint; unsigned int input; unsigned int output; unsigned int outputupperlimit; unsigned int outputlowerlimit; unsigned int inputupperlimit; unsigned int inputlowerlimit; float a0; float a1; float a2; float a3; float a4; float b0; float b1; float b2; float b3; float b4; float u=0; float um1=0; float um2=0; float um3=0; float um4=0; int e=0; int em1=0; int em2=0; int em3=0; int em4=0; /* Main Program loop-control global variables*/ unsigned char sampletimeroverflows=0; unsigned int sampletime; unsigned char samplestarttime; unsigned char sampleendtime; unsigned char realsamplefreq=250; unsigned int realsampletime; unsigned char reqoverflows; unsigned int maxsamplefreq; /*Define the memory location for the 8-bit parallel output*/ #define MEMPORTB (*(volatile unsigned char*)(0xA102)) void main(void) { getparameters(); initsci(); inittimerinterrupt(); delay(); switch(inoutcombination) { case 1: initadc(); initportb(); break;

Page 355: Software Development for Microprocessor Control Systems

Appendix G – The Microcontroller Software Source Code

345

case 2: initic3(); initportb(); break; case 3: initic3(); initpwm(); break; case 4: initadc(); initpwm(); break; } asm cli; /* Enable the system interrupts */ /*************************************************************/ /* This is the starting point of the control algorithm in an */ /* infinite loop */ /*************************************************************/ while(1) { /* Save starttime of routine (the upper 8-bit value of TCNT) */ samplestarttime=TCNTUP; /* Determine the number of TCNTUP counts which correspond to a samplefrequency of maxsamplefreq*/ sampletime=(7813/maxsamplefreq) + samplestarttime; reqoverflows=sampletime/0x100; sampleendtime=sampletime%0x100; /* Start Digital controller calculations */ switch(inoutcombination) { case 2: /* Pulse Width Measurement */ case 3: asm sei; /* disable interrupts */ input=7813/period; asm cli; /* enable interrupts */ break; case 1: /* Analog input */ case 4: input=adc(); break; } /* Set Inputlimits */ if (input<inputlowerlimit) input=inputlowerlimit; if (input>inputupperlimit) input=inputupperlimit; if (feedbackmode==1) { e=setpoint-input; /* negative feedback */ }

Page 356: Software Development for Microprocessor Control Systems

Appendix G – The Microcontroller Software Source Code

346

else { e=setpoint+input; /* positive feedback */ } u=(float) (b0*e + b1*em1 + b2*em2 + b3*em3 + b4*em4 - a1*um1 - a2*um2 - a3*um3 - a4*um4)/a0; if (u<(float)outputlowerlimit) u=(float)outputlowerlimit; if (u>(float)outputupperlimit) u=(float)outputupperlimit; /* Save current values for the next sample period */ um4=um3; um3=um2; um2=um1; um1=u; em4=em3; em3=em2; em2=em1; em1=e; output=u; switch(inoutcombination) { case 1: /* 8-Bit PIA Output */ case 2: MEMPORTB=output; break; case 3: /* PWM Output */ case 4: asm sei; pwmtimeon=((float) output/0x100)*pwmperiod; asm cli; break; } /* Transmit the sample frequecy, input and output values to */ /* the serial port. */ putchar(251); putchar(realsamplefreq); putchar(252); putchar(input); putchar(253); putchar(output); /* Wait for the desired sample period to elapse */ while (sampletimeroverflows<reqoverflows); while (TCNTUP<sampleendtime); /* Calculate the actual time for the sample period. */ /* (This realsampletime will be higher than the desired */ /* sample time entered in the maxsamplefreq variable */ /* if the desired sample period cannot be met due to */

Page 357: Software Development for Microprocessor Control Systems

Appendix G – The Microcontroller Software Source Code

347

/* insufficient processing speed.) */ realsampletime=sampletimeroverflows*256+TCNTUP-samplestarttime; realsamplefreq=7813/realsampletime; /* Restrict the realsamplefreq between 1 and 250 */ if (realsamplefreq>250) realsamplefreq=250; if (realsamplefreq<1) realsamplefreq=1; sampletimeroverflows=0; /* Reset sampletimeroverflows */ } /*end while(1) loop*/ } /************************************************************/ /* Routine to get the downloaded parameters which was */ /* downloaded from the PC. The downloaded parameters are */ /* stored in memory locations 0x0000 - 0x0041 */ /* */ /* The Memory location of the parameters are as follow: */ /* */ /* setpoint 0x0000 (0 decimal) */ /* a0 0x0001-0x0004 (1-4 decmial) */ /* a1 0x0005-0x0008 (5-8 decmial) */ /* a2 0x0009-0x000C (9-12 decmial) */ /* a3 0x000D-0x0010 (13-16 decimal) */ /* a4 0x0011-0x0014 (17-20 decimal) */ /* b0 0x0015-0x0018 (21-24 decimal) */ /* b1 0x0019-0x001C (25-28 decimal) */ /* b2 0x001D-0x0020 (28-32 decimal) */ /* b3 0x0021-0x0024 (33-36 decimal) */ /* b4 0x0025-0x0028 (37-40 decimal) */ /* maxsamplefreq 0x0029 (41 decimal) */ /* pwmhz 0x002A (42 decimal) */ /* feedbackmode 0x002B (43 decimal) */ /* outputupperlimit 0x002C (44 decimal) */ /* outputlowerlimit 0x002D (45 decimal) */ /* inputupperlimit 0x002E (46 decimal) */ /* inputlowerlimit 0x002F (47 decimal) */ /* inoutcombination 0x0030 (48 decimal) */ /************************************************************/ void getparameters(void) { unsigned char pwmhz; (unsigned char *) 0x0000; (float *) 0x0001; (float *) 0x0005; (float *) 0x0009; (float *) 0x000D; (float *) 0x0011; (float *) 0x0015; (float *) 0x0019; (float *) 0x001D; (float *) 0x0021; (float *) 0x0025;

Page 358: Software Development for Microprocessor Control Systems

Appendix G – The Microcontroller Software Source Code

348

(unsigned char *) 0x0029; (unsigned char *) 0x002A; (unsigned char *) 0x002B; (unsigned char *) 0x002C; (unsigned char *) 0x002D; (unsigned char *) 0x002E; (unsigned char *) 0x002F; (unsigned char *) 0x0030; setpoint=*(unsigned char *) 0x0000; a0=*(float *) 0x0001; a1=*(float *) 0x0005; a2=*(float *) 0x0009; a3=*(float *) 0x000D; a4=*(float *) 0x0011; b0=*(float *) 0x0015; b1=*(float *) 0x0019; b2=*(float *) 0x001D; b3=*(float *) 0x0021; b4=*(float *) 0x0025; maxsamplefreq=*(unsigned char *) 0x0029; pwmhz=*(unsigned char *) 0x002A; pwmperiod=2000000/pwmhz; feedbackmode=*(unsigned char *) 0x002B; outputupperlimit=*(unsigned char *) 0x002C; outputlowerlimit=*(unsigned char *) 0x002D; inputupperlimit=*(unsigned char *) 0x002E; inputlowerlimit=*(unsigned char *) 0x002F; inoutcombination=*(unsigned char *) 0x0030; } /***************************************************/ /* TCNT counter overflow interrupt service routine */ /***************************************************/ void timeroverflow(void) { timeroverflows++; /* Timeroverflow counter for inputcapture */ sampletimeroverflows++; asm { PSHA /* Reset timer overflow flag */ LDAA #0x80 STAA 0x1025 PULA RTI /* Return from Interrupt Service Routine */ } } /***************************************************/ /* Frequency Measurement Interrupt Service Routine */ /***************************************************/

Page 359: Software Development for Microprocessor Control Systems

Appendix G – The Microcontroller Software Source Code

349

void inputcapture(void) { /* Note: It is not neccesary to use the lower 8-bit of the counter function. Because the 68HC11 is an 8-bit microcontroller, processing speed will significantly increase by leaving the lower 8-bits of the counter out of the calculations. The 'period' variable, which represents all the TCNT counts, have to be a 32-bit long integer if this program uses all the 16 bits of the TCNT counter. It was found that the compiler used for this program does not compile calculations with 32-bit long integers correctly. The resolution of the upper 8-bits of the TCNT counter is 256*0.5 micro seconds = 0.000128 seconds which is still high enough to provide accurate timing. */ asm /* Reset input flag IC3F by writing 1 to it */ { PSHA LDAA #0x01 STAA 0x1023 PULA } if (TFLG2BYTE>=0x80 && TIC3UP<=0x80) { timeroverflows++; asm { PSHA LDAA #0x80 STAA 0x1025 PULA } } overflow=(unsigned int) timeroverflows*0x100; /* Copy upper 8-bits of the TIC3 register into tic3upint */ tic3upint=(unsigned int)TIC3UP; /* The overflow variable is the number of the upper 8-bit counts of the TNCT counter that correspond to the amount of TNCT overflows recorded in the timeroverflows variable */ period=(unsigned int) (overflow+tic3upint-time1); /* The period variable is the total number of TCNT upper 8-bit counts between this interrupt service routine and the previous one.*/ time1=(unsigned int)TIC3UP; /* Save the endtime of this ISR */ timeroverflows=0; /* Reset the timeroverflows variable */

Page 360: Software Development for Microprocessor Control Systems

Appendix G – The Microcontroller Software Source Code

350

asm RTI; } /**************************************/ /* SCI Character transmission routine */ /**************************************/ void putchar(char new_character) { char temp; temp=SCSR; temp=SCDR; while(SCSR==0); SCDR=new_character; } /************************************************/ /* Routine to initialize the microcontroller to */ /* generate a PWM signal on OC3 (PA5) */ /************************************************/ void initpwm(void) { /* Memory locations D9-DB is a 3 byte pseudo */ /* interrupt vector for TOC3(PA5) */ (char *) 0x00D9; /* Place jump instruction (op code 7E) in 00D9 */ *(char *) 0x00D9 = 0x7E; /* Place starting address of interrupt routine in DA&DB */ (int * ) 0x00DA; *(int *) 0x00DA = (int)oc3interrupt; OC1M.OC1M5=1; /* couple OC1 to OC3 */ TMSK1.OC3I=1; /* enable the OC3 interrupt */ OC1D.OC1D5=1; /* turn on OC3 when OC3 occurs */ TCTL1.OL3=1; /* toggle OC3 when OC3 occurs */ TOC1=TCNT+50000; /* initialize OC1 */ TOC3=TOC1+1; /* initialize OC3 */ } /*********************************/ /* OC3 Interrupt service routine. */ /* This Interrupt Service Routine will generate a PWM signal /* on OC3 (PA5) */ /*********************************/ void oc3interrupt(void) { asm { PSHA LDAA #0x20 STAA 0x1023 PULA }

Page 361: Software Development for Microprocessor Control Systems

Appendix G – The Microcontroller Software Source Code

351

toc1=TOC1+pwmperiod; TOC1=toc1; toc3=toc1+pwmtimeon; TOC3=toc3; asm RTI /* Return from Interrupt Service Routine */ } /************************************************/ /* Routine to initialize the microcontroller to */ /* send and receive serial data */ /************************************************/ void initsci(void) { BAUD=0x30; /* Set serial communication to 9600 baud rate */ SCCR2=0xC; /* TE and RE high=Serial Transmit and Receive Enabled */ } /***************************************************/ /* Routine to initialize the input capture 3 (IC3) */ /* PA0 pin to receive incoming data */ /***************************************************/ void initic3(void) { /* Set input capture in TIC3(PA0) on rising edges only */ /* (For falling edges, TCTL2=0x02) */ TCTL2=0x01; TMSK1.bit0=1; /* Enable the interrupt mask for IC3 (PA0) */ asm /* Reset input flag IC3F by writing 1 to it */ { PSHA LDAA #0x01 STAA 0x1023 PULA } /* Memory locations E2-E4 is a 3 byte */ /* pseudo interrupt vector for IC3(PA0) */ /* Place jump instruction (op code 7E) in 00E2 */ (char *) 0x00E2; *(char *) 0x00E2 = 0x7E; /* Place starting address of interrupt routine in E3&E4 */ (int * ) 0x00E3; *(int *) 0x00E3 = (int)inputcapture; } /*******************************************************/ /* Routine to initialize the timer overflow interrupt */ /*******************************************************/ void inittimerinterrupt(void) {

Page 362: Software Development for Microprocessor Control Systems

Appendix G – The Microcontroller Software Source Code

352

TMSK2.bit7=1; /* Enable the timer overflow interrupt */ asm { /*Reset TOF Flag*/ PSHA LDAA #0x80 STAA 0x1025 PULA } /* Memory locations D0-D2 is a 3 byte pseudo interrupt vector for the timer overflow */ (char *) 0x00D0; /* Place jump instruction (op code 7E) in 00D0 */ *(char *) 0x00D0=0x7E; (int * ) 0x00D1; /* Place starting address of interrupt routine in D1&D2 */ *(int *) 0x00D1 = (int)timeroverflow; } /*****************************************************************/ /* It was found that the first few characters received by the PC */ /* is corrupt.This function will transmit the first few */ /* non-significant characters to the PC before starting the */ /* control algorithm */ /*****************************************************************/ void delay(void) { unsigned int temp; for (temp=0;temp<100;temp++) { putchar(251); putchar(maxsamplefreq); putchar(252); putchar(1); putchar(253); putchar(1); } } /***************************************/ /* Function to initialize the */ /* analog-to-digital converter system */ /***************************************/ void initadc(void) { OPTION=0x80;/*Set bit 7 in OPTION high for A/D conversion*/ } /****************************************/ /* Analog to Digital conversion routine */ /****************************************/

Page 363: Software Development for Microprocessor Control Systems

Appendix G – The Microcontroller Software Source Code

353

unsigned char adc(void) { unsigned char temp; ADCTL=0x5; /* Set analog inputs on PE5 (pin 46) */ while (ADCTL<128); /* Wait for input */ temp=ADR1; return temp; } /******************************************************************/ /* Initialaise Port B on the MC6821 on the Memory extension board */ /* to serve as an 8-bit output port at memory address 0xA102 */ /******************************************************************/ void initportb(void) { (unsigned char *) 0xA102; (unsigned char *) 0xA103; *(unsigned char *) 0xA103=0x00; *(unsigned char *) 0xA102=0xFF; *(unsigned char *) 0xA103=0x04; }

Page 364: Software Development for Microprocessor Control Systems

Appendix G – The Microcontroller Software Source Code

354

Digital.prm - Linker parameter file for the SISO Digial Controller Module

LINK Digital.abs NAMES Digital.o start11.o ansi.lib END SECTIONS MY_RAM = READ_WRITE 0x4000 TO 0x4FFF; MY_ROM = READ_ONLY 0x2000 TO 0x3FFF; PLACEMENT DEFAULT_ROM INTO MY_ROM; DEFAULT_RAM INTO MY_RAM; END STACKSIZE 0x600

Page 365: Software Development for Microprocessor Control Systems

Appendix G – The Microcontroller Software Source Code

355

Multi.c - Source code for the MIMO Digial Controller Module #include <hc11e9.h> /******************************************************************* Description of fuctions oc3interrupt - Interrupt service routine for OC3 inputcapture - Interrupt service routine for frequency sensor (TIC3) timeroverflow - Interrupt service routine for TCNT overflow initpwm - Initialation routine for the PWM output initic3 - Initialation routine for the frequency sensor (TIC3) initsci - Initialation routine for the Serial Communication Interface inittimerinterrupt - Initialation routine for the TCNT timer overflow interrupt putchar - Function to write characters to the serial port getparameters - Function to read the downloaded parameter values delay - Function to enable a short delay before the program starts ********************************************************************/ void inittimerinterrupt(void); void putchar(char new_character); void getparameters(void); void delay(void); void initsci(void); void timeroverflow(void); void oc3interrupt(void); void inputcapture(void); void initpwm(void); void initic3(void); unsigned char adc(void); void initportb(void); void initadc(void); /* OC3 interrupt global variables */ volatile unsigned int toc3; volatile unsigned int toc1; volatile unsigned int pwmtimeon; unsigned int pwmperiod; /* Global variables for the inputcapture ISR */ unsigned int tic3upint; unsigned int overflow; unsigned int time1; unsigned char timeroverflows=0; unsigned int period=7813; /* Main Program control global variables*/ unsigned char analoginputfeedbackmode; unsigned char freqinputfeedbackmode; unsigned int analogsetpoint; unsigned int freqsetpoint;

Page 366: Software Development for Microprocessor Control Systems

Appendix G – The Microcontroller Software Source Code

356

unsigned char input1; unsigned int input2; unsigned int output1; unsigned int output2; unsigned int freqinputupperlimit; unsigned int freqinputlowerlimit; unsigned int analoginputupperlimit; unsigned int analoginputlowerlimit; unsigned int _8bitoutputupperlimit; unsigned int _8bitoutputlowerlimit; unsigned int PWMoutputupperlimit; unsigned int PWMoutputlowerlimit; float p10; float p11; float p12; float p13; float p14; float p20; float p21; float p22; float p23; float p24; float q10; float q11; float q12; float q13; float q14; float q20; float q21; float q22; float q23; float q24; float r10; float r11; float r12; float r13; float r14; float r20; float r21; float r22; float r23; float r24; float u1=0; float u1m1=0; float u1m2=0; float u1m3=0; float u1m4=0; int e1=0; int e1m1=0; int e1m2=0; int e1m3=0; int e1m4=0;

Page 367: Software Development for Microprocessor Control Systems

Appendix G – The Microcontroller Software Source Code

357

float u2=0; float u2m1=0; float u2m2=0; float u2m3=0; float u2m4=0; int e2=0; int e2m1=0; int e2m2=0; int e2m3=0; int e2m4=0; /* Main Program loop-control global variables*/ unsigned char sampletimeroverflows=0; unsigned int sampletime; unsigned char samplestarttime; unsigned char sampleendtime; unsigned char realsamplefreq=250; unsigned int realsampletime; unsigned char reqoverflows; unsigned int maxsamplefreq; /*Define the memory location for the 8-bit parallel output*/ #define MEMPORTB (*(volatile unsigned char*)(0xA102)) void main(void) { getparameters(); initsci(); inittimerinterrupt(); initic3(); delay(); initpwm(); initportb(); initadc(); asm cli; /* Enable the system interrupts */ /*************************************************************/ /* This is the starting point of the control algorithm in an */ /* infinite loop */ /*************************************************************/ while(1) { /* Save starttime of routine (the upper 8-bit value of TCNT) */ samplestarttime=TCNTUP; /* Determine the number of TCNTUP counts which correspond to a samplefrequency of maxsamplefreq*/ sampletime=(7813/maxsamplefreq) + samplestarttime; reqoverflows=sampletime/256; sampleendtime=sampletime%256; /* Start MIMO Controller calculations */

Page 368: Software Development for Microprocessor Control Systems

Appendix G – The Microcontroller Software Source Code

358

input1=adc(); asm SEI; /* disable interrupts */ input2=7813/period; asm CLI; /* enable interrupts */ if (input1<analoginputlowerlimit) input1=analoginputlowerlimit; if (input1>analoginputupperlimit) input1=analoginputupperlimit; if (input2<freqinputlowerlimit) input2=freqinputlowerlimit; if (input2>freqinputupperlimit) input2=freqinputupperlimit; if (analoginputfeedbackmode==1) { e1=analogsetpoint-input1; /* analog negative feedback */ } else { e1=analogsetpoint+input1; /* analog positive feedback */ } if (freqinputfeedbackmode==1) { e2=freqsetpoint-input2; /* frequency negative feedback */ } else { e2=freqsetpoint+input2; /* frequency positive feedback */ } u1=(float) ( q10*e1 + q11*e1m1 + q12*e1m2 + q13*e1m3 + q14*e1m4 + r10*e2 + r11*e2m1 + r12*e2m2 + r13*e2m3 + r14*e2m4 - p11*u1m1 - p12*u1m2 - p13*u1m3 - p14*u1m4); u2=(float) ( q20*e1 + q21*e1m1 + q22*e1m2 + q23*e1m3 + q24*e1m4 + r20*e2 + r21*e2m1 + r22*e2m2 + r23*e2m3 + r24*e2m4 - p21*u2m1 - p22*u2m2 - p23*u2m3 - p24*u2m4); if (u1<(float)_8bitoutputlowerlimit) u1=(float)_8bitoutputlowerlimit; if (u1>(float)_8bitoutputupperlimit) u1=(float)_8bitoutputupperlimit; if (u2<(float)PWMoutputlowerlimit) u2=(float)PWMoutputlowerlimit; if (u2>(float)PWMoutputupperlimit) u2=(float)PWMoutputupperlimit; /* Save current controller input and output values for the next sample period */ u1m4=u1m3; u1m3=u1m2; u1m2=u1m1; u1m1=u1; e1m4=e1m3; e1m3=e1m2; e1m2=e1m1; e1m1=e1;

Page 369: Software Development for Microprocessor Control Systems

Appendix G – The Microcontroller Software Source Code

359

u2m4=u2m3; u2m3=u2m2; u2m2=u2m1; u2m1=u2; e2m4=e2m3; e2m3=e2m2; e2m2=e2m1; e2m1=e2; output1=u1; output2=u2; MEMPORTB=output1; asm SEI; /*disable interrupts*/ pwmtimeon=((float) output2/0x100)*pwmperiod; asm CLI; /*enable interrupts*/ /* Transmit the sample frequecy, input and output values to */ /* the serial port. */ putchar(251); putchar(realsamplefreq); putchar(252); putchar(input1); putchar(253); putchar(input2); putchar(254); putchar(output1); putchar(255); putchar(output2); /* Wait for the desired sample period to elapse */ while (sampletimeroverflows<reqoverflows); while (TCNTUP<sampleendtime); /* Calculate the actual time for the sample period. */ /* (This realsampletime will be higher than the desired */ /* sample time entered in the maxsamplefreq variable */ /* if the desired sample period cannot be met due to */ /* insufficient processing speed.) */ realsampletime=sampletimeroverflows*256+TCNTUP-samplestarttime; realsamplefreq=7813/realsampletime; /* Restrict the realsamplefreq between 1 and 250 */ if (realsamplefreq>250) realsamplefreq=250; if (realsamplefreq<1) realsamplefreq=1; sampletimeroverflows=0; /* Reset sampletimeroverflows */ } /*end while(1) loop*/ }

Page 370: Software Development for Microprocessor Control Systems

Appendix G – The Microcontroller Software Source Code

360

/************************************************************/ /* Routine to get the downloaded parameters which was */ /* downloaded from the PC. The downloaded parameters are */ /* stored in memory locations 0x0100 - 0x01FF */ /* */ /* The Memory location of the parameters are as follow: */ /* */ /* analogsetpoint 0x0100 (0) */ /* freqsetpoint 0x0101 (1) */ /* p10 0x0102-0x0105 (2-5) */ /* p11 0x0106-0x0109 (6-9) */ /* p12 0x010A-0x010D (10-13) */ /* p13 0x010E-0x0111 (14-17) */ /* p14 0x0112-0x0115 (18-21) */ /* p20 0x0116-0x0119 (22-25) */ /* p21 0x011A-0x011D (26-29) */ /* p22 0x011E-0x0121 (30-33) */ /* p23 0x0122-0x0125 (34-37) */ /* p24 0x0126-0x0129 (38-41) */ /* q10 0x012A-0x012D (42-45) */ /* q11 0x012E-0x0131 (46-49) */ /* q12 0x0132-0x0135 (50-53) */ /* q13 0x0136-0x0139 (54-57) */ /* q14 0x013A-0x013D (58-61) */ /* q20 0x013E-0x0141 (62-65) */ /* q21 0x0142-0x0145 (66-69) */ /* q22 0x0146-0x0149 (70-73) */ /* q23 0x014A-0x014D (74-77) */ /* q24 0x014E-0x0151 (78-81) */ /* r10 0x0152-0x0155 (82-85) */ /* r11 0x0156-0x0159 (86-89) */ /* r12 0x015A-0x015D (90-93) */ /* r13 0x015E-0x0161 (94-97) */ /* r14 0x0162-0x0165 (98-101) */ /* r20 0x0166-0x0169 (102-105) */ /* r21 0x016A-0x016D (106-109) */ /* r22 0x016E-0x0171 (110-113) */ /* r23 0x0172-0x0175 (114-117) */ /* r24 0x0176-0x0179 (118-121) */ /* maxsamplefreq 0x017A (122) */ /* pwmhz 0x017B (123) */ /* analoginputfeedbackmode 0x017C (124) */ /* freqinputfeedbackmode 0x017D (125) */ /* analoginputupperlimit 0x017E (126) */ /* analoginputlowerlimit 0x017F (127) */ /* freqinputupperlimit 0x0180 (128) */ /* freqinputlowerlimit 0x0181 (129) */ /* _8bitoutputupperlimit 0x0182 (130) */ /* _8bitoutputlowerlimit 0x0183 (131) */ /* PWMoutputupperlimit 0x0184 (132) */ /* PWMoutputlowerlimit 0x0185 (133) */ /************************************************************/

Page 371: Software Development for Microprocessor Control Systems

Appendix G – The Microcontroller Software Source Code

361

void getparameters(void) { unsigned char pwmhz; (unsigned char *) 0x0100; (unsigned char *) 0x0101; (float *) 0x0102; (float *) 0x0106; (float *) 0x010A; (float *) 0x010E; (float *) 0x0112; (float *) 0x0116; (float *) 0x011A; (float *) 0x011E; (float *) 0x0122; (float *) 0x0126; (float *) 0x012A; (float *) 0x012E; (float *) 0x0132; (float *) 0x0136; (float *) 0x013A; (float *) 0x013E; (float *) 0x0142; (float *) 0x0146; (float *) 0x014A; (float *) 0x014E; (float *) 0x0152; (float *) 0x0156; (float *) 0x015A; (float *) 0x015E; (float *) 0x0162; (float *) 0x0166; (float *) 0x016A; (float *) 0x016E; (float *) 0x0172; (float *) 0x0176; (unsigned char *) 0x017A; (unsigned char *) 0x017B; (unsigned char *) 0x017C; (unsigned char *) 0x017D; (unsigned char *) 0x017E; (unsigned char *) 0x017F; (unsigned char *) 0x0180; (unsigned char *) 0x0181; (unsigned char *) 0x0182; (unsigned char *) 0x0183; (unsigned char *) 0x0184; (unsigned char *) 0x0185; analogsetpoint= *(unsigned char *) 0x0100; freqsetpoint=*(unsigned char *) 0x0101; p10=*(float *) 0x0102; p11=*(float *) 0x0106; p12=*(float *) 0x010A;

Page 372: Software Development for Microprocessor Control Systems

Appendix G – The Microcontroller Software Source Code

362

p13=*(float *) 0x010E; p14=*(float *) 0x0112; p20=*(float *) 0x0116; p21=*(float *) 0x011A; p22=*(float *) 0x011E; p23=*(float *) 0x0122; p24=*(float *) 0x0126; q10=*(float *) 0x012A; q11=*(float *) 0x012E; q12=*(float *) 0x0132; q13=*(float *) 0x0136; q14=*(float *) 0x013A; q20=*(float *) 0x013E; q21=*(float *) 0x0142; q22=*(float *) 0x0146; q23=*(float *) 0x014A; q24=*(float *) 0x014E; r10=*(float *) 0x0152; r11=*(float *) 0x0156; r12=*(float *) 0x015A; r13=*(float *) 0x015E; r14=*(float *) 0x0162; r20=*(float *) 0x0166; r21=*(float *) 0x016A; r22=*(float *) 0x016E; r23=*(float *) 0x0172; r24=*(float *) 0x0176; maxsamplefreq=*(unsigned char *) 0x17A; pwmhz=*(unsigned char *) 0x017B; pwmperiod=2000000/pwmhz; analoginputfeedbackmode=*(unsigned char *) 0x017C; freqinputfeedbackmode=*(unsigned char *) 0x017D; analoginputupperlimit=*(unsigned char *) 0x017E; analoginputlowerlimit=*(unsigned char *) 0x017F; freqinputupperlimit=*(unsigned char *) 0x0180; freqinputlowerlimit=*(unsigned char *) 0x0181; _8bitoutputupperlimit=*(unsigned char *) 0x0182; _8bitoutputlowerlimit=*(unsigned char *) 0x0183; PWMoutputupperlimit=*(unsigned char *) 0x0184; PWMoutputlowerlimit=*(unsigned char *) 0x0185; } /***************************************************/ /* TCNT counter overflow interrupt service routine */ /***************************************************/ void timeroverflow(void) { timeroverflows++; /* Timeroverflow counter for inputcapture */ sampletimeroverflows++; /* Counter for sample period regulation */ asm { PSHA /* Save the contents of accumulator A */ LDAA #0x80 /* Load accumulator A with the mask data */

Page 373: Software Development for Microprocessor Control Systems

Appendix G – The Microcontroller Software Source Code

363

STAA 0x1025 /* Reset the timer overflow flag (TOF) */ PULA /* Retrieve the saved contents of accumulator A */ RTI /* Return from Interrupt Service Routine */ } } /***************************************************/ /* Frequency Measurement Interrupt Service Routine */ /***************************************************/ void inputcapture(void) { /* Note: It is not neccesary to use the lower 8-bit of the counter function. Because the 68HC11 is an 8-bit microcontroller, processing speed will significantly increase by leaving the lower 8-bits of the counter out of the calculations. The 'period' variable, which represents all the TCNT counts, have to be a 32-bit long integer if this program uses all the 16 bits of the TCNT counter. It was found that the compiler used for this program does not compile calculations with 32-bit long integers correctly. The resolution of the upper 8-bits of the TCNT counter is 256*0.5 micro seconds = 0.000128 seconds which is still high enough to provide accurate timing. */ asm /* Reset input flag IC3F by writing 1 to it */ { PSHA /* Save the contents of accumulator A */ LDAA #0x01 /* Load accumulator A with the mask data */ STAA 0x1023 /* Reset TOF flag by writing 1 to it */ PULA /* Retrieve the saved contents of accumulator A */ } if (TFLG2BYTE>=0x80 && TIC3UP<=0x80) { timeroverflows++; asm { PSHA /* Save the contents of accumulator A */ LDAA #0x80 /* Load accumulator A with the mask data */ STAA 0x1025 /* Reset IC3F flag by writing 1 to it */ PULA /* Retrieve the saved contents of accumulator A */ } } overflow=(unsigned int) timeroverflows*0x100; /* Copy upper 8-bits of the TIC3 register into tic3upint */ tic3upint=(unsigned int)TIC3UP; /* The overflow variable is the number of the upper 8-bit counts of the TNCT counter that correspond to the amount of TNCT overflows recorded in the timeroverflows variable */

Page 374: Software Development for Microprocessor Control Systems

Appendix G – The Microcontroller Software Source Code

364

period=(unsigned int) (overflow+tic3upint-time1); /* The period variable is the total number of TCNT upper 8-bit counts between this interrupt service routine and the previous one.*/ time1=(unsigned int)TIC3UP; /* Save the endtime of this ISR */ timeroverflows=0; /* Reset the timeroverflows variable */ asm RTI; /* Return to main program */ } /**************************************/ /* SCI Character transmission routine */ /**************************************/ void putchar(char new_character) { char temp; temp=SCSR; temp=SCDR; while(SCSR==0); SCDR=new_character; } /************************************************/ /* Routine to initialize the microcontroller to */ /* generate a PWM signal on OC3 (PA5) */ /************************************************/ void initpwm(void) { /* Memory locations D9-DB is a 3 byte pseudo */ /* interrupt vector for TOC3(PA5) */ (char *) 0x00D9; /* Place jump instruction (op code 7E) in 00D9 */ *(char *) 0x00D9 = 0x7E; /* Place starting address of interrupt routine in DA&DB */ (int * ) 0x00DA; *(int *) 0x00DA = (int)oc3interrupt; OC1M.OC1M5=1; /* couple OC1 to OC3 */ TMSK1.OC3I=1; /* enable the OC3 interrupt */ OC1D.OC1D5=1; /* turn on OC3 when OC1 occurs */ TCTL1.OL3=1; /* toggle OC3 when OC3 occurs */ TOC1=TCNT+50000; /* initialize OC1 */ TOC3=TOC1+1; /* initialize OC3 */ } /*****************************************************/ /* OC3 Interrupt Service Routine. This routine will */ /* generate a PWM signal on OC3 (PA5) */ /*****************************************************/ void oc3interrupt(void) {

Page 375: Software Development for Microprocessor Control Systems

Appendix G – The Microcontroller Software Source Code

365

asm { PSHA /* Save the contents of accumulator A */ LDAA #0x20 /* Load accumulator A with the mask data */ STAA 0x1023 /* Reset OC3F flag by writing 1 to it */ PULA /* Retrieve the saved contents of accumulator A */ } toc1=TOC1+pwmperiod; TOC1=toc1; toc3=toc1+pwmtimeon; TOC3=toc3; asm RTI /* Return from Interrupt Service Routine */ } /************************************************/ /* Routine to initialize the microcontroller to */ /* send and receive serial data */ /************************************************/ void initsci(void) { BAUD=0x30; /* Set serial communication to 9600 baud rate */ SCCR2=0xC; /* TE and RE high=Serial Transmit and Receive Enabled */ } /***************************************************/ /* Routine to initialize the input capture 3 (IC3) */ /* interrupt service routine. */ /***************************************************/ void initic3(void) { /* Set input capture in TIC3(PA0) on rising edges only */ /* (For falling edges, TCTL2=0x02) */ TCTL2=0x01; TMSK1.bit0=1; /* Enable the interrupt mask for IC3 (PA0) */ asm { PSHA /* Save the contents of accumulator A */ LDAA #0x01 /* Load accumulator A with the mask data */ STAA 0x1023 /* Reset input flag IC3F by writing 1 to it */ PULA /* Retrieve the saved contents of accumulator A */ } /* Memory locations E2-E4 is a 3 byte */ /* pseudo interrupt vector for IC3(PA0) */ /* Place jump instruction (op code 7E) in 00E2 */ (char *) 0x00E2; *(char *) 0x00E2 = 0x7E; /* Place starting address of interrupt routine in E3&E4 */ (int * ) 0x00E3; *(int *) 0x00E3 = (int)inputcapture; }

Page 376: Software Development for Microprocessor Control Systems

Appendix G – The Microcontroller Software Source Code

366

/*******************************************************/ /* Routine to initialize the timer overflow interrupt */ /*******************************************************/ void inittimerinterrupt(void) { TMSK2.bit7=1; /* Enable the timer overflow interrupt */ asm { PSHA /* Save the contents of accumulator A */ LDAA #0x80 /* Load accumulator A with the mask data */ STAA 0x1025 /* Reset TOF Flag by writing 1 to it */ PULA /* Retrieve the saved contents of accumulator A */ } /* Memory locations D0-D2 is a 3 byte pseudo interrupt vector for the timer overflow */ (char *) 0x00D0; /* Place jump instruction (op code 7E) in 00D0 */ *(char *) 0x00D0=0x7E; (int * ) 0x00D1; /* Place starting address of interrupt routine in D1&D2 */ *(int *) 0x00D1 = (int)timeroverflow; } /*****************************************************************/ /* It was found that the first few characters received by the PC */ /* is corrupt.This function will transmit the first few */ /* non-significant characters to the PC before starting the */ /* control algorithm */ /*****************************************************************/ void delay(void) { unsigned int temp; for (temp=0;temp<100;temp++) { putchar(251); putchar(maxsamplefreq); putchar(252); putchar(1); putchar(253); putchar(1); } } /***************************************/ /* Function to initialize the */ /* analog-to-digital converter system */ /***************************************/ void initadc(void) {

Page 377: Software Development for Microprocessor Control Systems

Appendix G – The Microcontroller Software Source Code

367

OPTION=0x80;/*Set bit 7 in OPTION high for A/D conversion*/ } /****************************************/ /* Analog to Digital conversion routine */ /****************************************/ unsigned char adc(void) { unsigned char temp; ADCTL=0x5; /* Set analog inputs on PE5 (pin 46) */ while (ADCTL<128); /* Wait for input */ temp=ADR1; return temp; } /******************************************************************/ /* Initialaise Port B on the MC6821 on the Memory extension board */ /* to serve as an 8-bit output port at memory address 0xA102 */ /******************************************************************/ void initportb(void) { (unsigned char *) 0xA102; (unsigned char *) 0xA103; *(unsigned char *) 0xA103=0x00; *(unsigned char *) 0xA102=0xFF; *(unsigned char *) 0xA103=0x04; }

Page 378: Software Development for Microprocessor Control Systems

Appendix G – The Microcontroller Software Source Code

368

Multi.prm - Linker parameter file for the MIMO Digial Controller Module

LINK Multi.abs NAMES Multi.o start11.o ansi.lib END SECTIONS MY_RAM = READ_WRITE 0x4000 TO 0x4FFF; MY_ROM = READ_ONLY 0x2000 TO 0x3FFF; PLACEMENT DEFAULT_ROM INTO MY_ROM; DEFAULT_RAM INTO MY_RAM; END STACKSIZE 0x9FF