Vous êtes sur la page 1sur 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

Abstract
This thesis concerns the development and application of a user-friendly microprocessor-based digital controller. Microprocessor programming is a specialized, time-consuming and laborintensive 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.

iii

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.

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

vii

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

viii

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

ix

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

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

xi

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

xii

PIA PID PLCC PWM RAD RAM RE RIDE ROM S/N SCI SISO T TC TDRE TE TIC TOC TOF UART VRH VRL

Peripheral Interface Adapter Proportional + Integral + Derivative Plastic Leadless Chip Carrier Pulse Width Modulation Rapid Application Development Random Access Memory Receive Enable Real-time Integrated Development Environment Read Only Memory Signal/Noise Serial Communications Interface Single-Input-Single-Output Sample Period (seconds) Transmit Complete Transmit Data Register Empty Transmit Enable Timer Input Compare Timer Output Compare Timer Overflow Universal Asynchronous Receiver Transmitter Voltage Reference High Voltage Reference Low

xiii

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

Chapter 1 - Introduction

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].

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)

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.

Chapter 1 Introduction

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 systems mathematical model is known, a control system can be designed that will keep the aircraft stable on its proper descent path.

Phased array Radar unit

Controller Computer Lateral position Range Lateral digital compensator Position command Vertical digital compensator Transmitter

Vertical position

Figure 1.2 Basic structure of an Automatic Aircraft Landing System

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 aircrafts position as rapidly and effectively as possible while the systems sensitivity to external disturbances such as wind and radar noise must kept to a minimum.

Chapter 1 - Introduction

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 Instruments TMS320C6201 DSP and is capable of sustained total computational throughput of 6400 MIPS. (Source: Innovative Integration)

Chapter 1 Introduction

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.

Chapter 1 - Introduction

Figure 1.4 The VisSim/DSP Development Environment

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 crosscompiled for use in other environments.

Chapter 1 Introduction

Figure 1.5 The Hypersignal RIDE development environment

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 ECPs 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

Chapter 1 - Introduction

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)

Chapter 1 Introduction

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 laborintensive 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.

Chapter 1 - Introduction

Control Algorithm

Monitor Signals

User Specify Control Parameters

Control Process

Microcontroller

Control Signals

Process

Feedback Signals

Figure 1.7

The microcontroller-based control system

10

Chapter 1 Introduction

1.3 Thesis Overview


This thesis is concerned with the development and application of the microprocessorbased 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 Windowsbased 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 users 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.

11

Chapter 1 - Introduction

12

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 a 0 u( k ) + a1u (k 1) + . . . + a n u (k n ) = b0 e(k ) + b1e(k 1) + . . . + bn e(k n ) (2.1)

where e(k ) and u (k ) are the respective input and output numbers of the computer at time t. The values e(k n ) and u (k n ) are the respective input and output numbers of the computer at time t nT . 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

13

Chapter 2 Digital Controller Fundamentals

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 sample time is kT and the current value of r * (t ) is r (kT ) .

continuous input is r (t ) and the discrete sampler output is r * (t ) . The current

r (t ) time Continuous Signal


Figure 2.1 Representation of the Ideal Sampler with input

r * (t ) Sampler time Discrete Signal r (t ) and output r * (t )

The impulse function, T (t ) is defined as

T (t ) = (t kT )
k =0

(2.2)

The output of the ideal sampler can therefore be expressed as r * (t ) = r( kT ) (t kT ) = r (t ) T (t )


k =0

(2.3)

2.1.2 The z-Transformation


The Laplace transform of the output of the ideal sampler can be written as [r * ( t )] = R * (s ) = r (kT )e kTs
k =0

(2.4)

14

Chapter 2 Digital Controller Fundamentals

Equation 2.4 represents an infinite series that involves factors of e sT and its powers. The transformation between s an z can be defined as z = e Ts Equation 2.5 can also be written in terms of z as s= 1 ln z T (2.6) (2.5)

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

(2.7)

15

Chapter 2 Digital Controller Fundamentals

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 continuoustime RLC filter. L R C

Figure 2.2 The RLC Filter

The differential equation for the second-order RLC filter is d2y dy 2 2 + 2 +0 y = 0 x 2 dt dt where R 2L 1 2 0 = LC (2.8)

(2.9)

16

Chapter 2 Digital Controller Fundamentals

The second-order transfer function of the RLC circuit can be obtained by taking the Laplace transform of Equation 2.8. Y (s ) 02 = 2 2 X (s ) s + 2s + 0

(2.10)

By using the backward difference rule as shown by Bozic (1979), the discrete-time form of Equation 2.10 can be written as y * ( t ) = a0 x * ( t ) + b1 y * ( t T ) + b2 y * ( t 2T ) The solution for the parameter gains using backward difference rule is a0 = 1 b11 = 2e T cos 1T b2 = e
2 T

(2.11)

(2.12)

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.

x(t)

x*(t)

a0

+ + +

y*(t)

b2

b1

y*(t-2T)

z 1

y*(t-T)

z 1

Figure 2.3 Digital filter equivalent for the RLC filter

17

Chapter 2 Digital Controller Fundamentals

2.2.1 Digital Filter Realization


The discrete-time digital transfer function can be defined as

Y (z ) = H (z ) = X (x )

b z
n m=0

n=0 M

(2.13)
m

This digital transfer function is only valid for zero initial conditions, which are satisfied for the cases considered in this text [8]. By taking a 0 = 1 , Equation 2.13 can be expressed as Y ( z ) = bn z n X ( z ) a m z n Y ( z )
n=0 m =1 N M

(2.14)

The equivalent time-domain equation from Equation 2.14 is y * (t ) = bn x * (t nT ) a m y * (t mT )


n =0 m =1 N M

(2.15)

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.

18

Chapter 2 Digital Controller Fundamentals x * (t ) x * (t T ) x * (t 2T ) x * (t nT )

z 1

z 1

z 1

b0 a0 + +

b1 a0 + +

b2 a0 + +

bn a0

+ +

y * (t )

+ + a1 a0 a2 a0

+ + an a0

z 1

y * (t T )

z 1

y * (t 2T )

z 1

y * (t nT )

Figure 2.4 Block diagram for the direct digital filter

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.

19

Chapter 2 Digital Controller Fundamentals b0 + b1 z 1 + b2 z 2 1 + a1 z 1 + a 2 z 2

D( z ) =

(2.16)

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


k =1 p

(2.17)

x * (t )

D1 ( z )

D2 ( z )

D p (z )

y * (t )

Figure 2.5. Block diagram for the cascade digital filter

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 n m . Also, for the difference Equation 2.15 to be physical realizable, a 0 may not be zero.

20

Chapter 2 Digital Controller Fundamentals

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 u( t ) = K P e( t ) + K I e( t )dt + K D where e( t ) = Controller Input / Error signal from plant u( t ) = Controller Output / Control signal to plant K P = Pr oportional Cons tan t K I = Integral Cons tan t K D = Deravitive Cons tan t By taking the Laplace transform, the PID controller can be represented in the s-domain as follow K U ( s ) = K P + I + K D s E( s ) s (2.19) d e( t ) dt (2.18)

Kp

E (s )

KI s

U( s )

KDs
Figure 2.6 The continuous-time PID controller

21

Chapter 2 Digital Controller Fundamentals

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. uD ( t ) = d e( t ) e( t T ) e( t ) dt T

(2.20)

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.

e(t )

Figure 2.7 The right-side rectangular rule


t

u I (t ) = K I e(t )dt
0

(2.21)

Assume that the upper limit of the integral is t = nT . Hence u I ( nT ) = e( t )dt = T e( iT )


0 i =1 nT n

(2.22)

22

Chapter 2 Digital Controller Fundamentals


n +1 i =1

u I (nT + T ) = T e(iT ) = T e(iT ) + Te(nT + T )


i =1

= u I (nT ) + Te(nT + T ) Let n = n 1 , then: u I (nT ) = u I (nT T ) + Te(nT )

(2.23)

(2.24)

The numerical representation of the PID controller can therefore be written as: u( nT ) = K P u P ( nT ) + K I u I ( nT ) + K D u D ( nT ) where: u P ( nT ) = e( nT ) u I ( nT ) = u I ( nT T ) + Te( nT ) u D ( nT ) = e( nT ) e( nT T ) T (2.26) (2.25)

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: Y ( s ) e sT Y ( s ) + y( 0+ ) T

sY ( s )

(2.27)

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

(2.28)

Equation 2.5 defines the mapping function of the standard z-transform as z = e sT (2.29)

23

Chapter 2 Digital Controller Fundamentals

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

s=

(2.30)

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 D( z ) = K P + KIT 2 z + 1 K D z 1 + z 1 T z

(2.31)

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. KP

e*(t)

+
z

+
1

KIT 2

+ +

u*(t)

z 1

KD T +

Figure 2.8 Direct digital implementation of the PID controller

24

Chapter 2 Digital Controller Fundamentals

An alternative method to implement the digital PID controller is to find the secondorder transfer function of Equation 2.31. K P ( z 1)( z ) + K IT (z + 1)( z ) + K D ( z 1)( z 1) 2 T ( z 1)( z )

D( z ) =

KP z 2 z +

K IT 2 K z + z + D z 2 2z + 1 2 T z2 z

)
(2.32)

KT K 2 K T 2K D K z + D K P + I + D z + KP + I 2 2 T T T = 2 z z = b0 + b1 z 1 + b2 z 2 a0 + a1 z 1 + a2 z 2

where KIT KD + 2 T K I T 2K D T 2 (2.33)

b0 = K P +

b1 = K P + b2 = KD T

a0 = 1 a1 = 1 a2 = 0 Consequently, a digital PID controller can be implemented by any second-order direct digital filter structure as discussed in section 2.2.1.

25

Chapter 2 Digital Controller Fundamentals

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.

e1 Multivariable Digital Filter e2

u1 u2

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

The transfer function of the system illustrated in Figure 2.9 can be described as B11 u1 A11 u = B 2 21 A21 B12 A12 e1 B22 e2 A22

(2.34)

The second-order transfer function of each element can be described as B xy Axy b0 xy + b1 xy z 1 + b2 xy z 2 1 + a1 xy z 1 + a 2 xy z 2

(2.35)

26

Chapter 2 Digital Controller Fundamentals

Rewriting Equation 2.34 gives u1 = u2 = B11 B e1 + 12 e2 A11 A12 B21 B e1 + 22 e2 A21 A22

(2.36)

By getting a common denominator, Equation 2.36 can be written as A11 A12 u1 = B11 A12 e1 + A11 B12 e 2 A21 A22u2 = B21 A22 e1 + A21B22e2 Let A11 A12 = P1 = 1 + p1 1 z 1 + p1 2 z 2 + p1 3 z 3 + p1 4 z 4 B11 A12 = Q1 = q1 0 + q1 1 z 1 + q1 2 z 2 + q1 3 z 3 + q1 4 z 4 A11 B12 = R1 = r1 0 + r1 1 z 1 + r1 2 z 2 + r1 3 z 3 + r1 4 z 4 A21 A22 = P2 = 1 + p 2 1 z 1 + p 2 2 z 2 + p 2 3 z 3 + p 2 4 z 4 B21 A22 = Q2 = q 2 0 + q 2 1 z 1 + q 2 2 z 2 + q 2 3 z 3 + q 2 4 z 4 A21 B22 = R 2 = r2 0 + r2 1 z 1 + r2 2 z 2 + r2 3 z 3 + r2 4 z 4 so that Equation 2.37 can be written as P1 0 0 u1 Q1 = P2 u 2 Q 2 R1 e1 R2 e 2 (2.38)

(2.37)

(2.39)

27

Chapter 2 Digital Controller Fundamentals

Expanding Equation 2.39 gives

1 0

p1 1 0

p1 2 0

p1 3 0

p1 4 0

0 1

0 p2 1

0 p2 2

0 p2 3

u1 * (t ) u * (t T ) 1 u1 * (t 2T ) u1 * (t 3T ) 0 u1 * (t 4T ) p2 4 u 2 * (t ) u * (t T ) 2 u 2 * (t 2T ) u * (t 3T ) 2 u 2 * (t 4T ) e1 * (t ) e * (t T ) 1 e1 * (t 2T ) e1 * (t 3T ) r1 4 e1 * (t 4T ) r2 4 e 2 * (t ) e * (t T ) 2 e 2 * (t 2T ) e * (t 3T ) 2 e 2 * (t 4T )

q1 0 = q 2 0

q1 1 q2 1

q1 2 q2 2

q1 3 q2 3

q1 4 q2 4

r1 0 r2 0

r1 1 r2 1

r1 2 r2 2

r1 3 r2 3

(2.40)

28

Chapter 2 Digital Controller Fundamentals

Equation 2.40 can be rearranged as e1 * (t ) e * (t T ) 1 e1 * (t 2T ) e1 * (t 3T ) r1 4 e1 * (t 4T ) r2 4 e 2 * (t ) e * (t T ) 2 e 2 * (t 2T ) e * (t 3T ) 2 ( ) e * t T 4 2

u1 * (t ) q1 0 u * (t ) = q 2 20

q1 1 q2 1

q1 2 q2 2

q1 3 q2 3

q1 4 q2 4

r1 0 r2 0

r1 1 r2 1

r1 2 r2 2

r1 3 r2 3

p1 1 0

p1 2 0

p1 3 0

p1 4 0

0 p2 1

0 p2 2

0 p2 3

u1 * (t T ) u * (t 2T ) 1 u1 * (t 3T ) 0 u1 * (t 4T ) p2 3 u 2 * (t T ) u 2 * (t 2T ) u * (t 3T ) 2 u 2 * (t 4T )

(2.41)

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

29

Chapter 2 Digital Controller Fundamentals

30

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.

31

Chapter 3 Hardware Overview

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.

32

Chapter 3 Hardware Overview

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.

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

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.

33

Chapter 3 Hardware Overview

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)

34

Chapter 3 Hardware Overview

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: Resolution = Analog input range 2n

(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: Resolution = Analog input range 5.12 V = = 20 mV/bit 2n 28

(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.

35

Chapter 3 Hardware Overview

Register name PORTE ADCTL ADR1 ADR2 ADR3 ADR4 OPTION

Memory Address $100A $1030 $1031 $1032 $1033 $1034 $1039

Bit 7 Bit 7 CCF Bit 7 Bit 7 Bit 7 Bit 7 ADPU

Bit 6 Bit 6 Bit 6 Bit 6 Bit 6 Bit 6 CSEL

Bit 5 Bit 5 SCAN Bit 5 Bit 5 Bit 5 Bit 5 IRQE

Bit 4 Bit 4 MULT Bit 4 Bit 4 Bit 4 Bit 4 DLY

Bit 3 Bit 3 CD Bit 3 Bit 3 Bit 3 Bit 3 CME

Bit 2 Bit 2 CC Bit 2 Bit 2 Bit 2 Bit 2 -

Bit 1 Bit 1 CB Bit 1 Bit 1 Bit 1 Bit 1 CR1

Bit 0 Bit 0 CA Bit 0 Bit 0 Bit 0 Bit 0 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.

36

Chapter 3 Hardware Overview

CD 0 0 0 0 0 0 0 0

CC 0 0 0 0 1 1 1 1

CB 0 0 1 1 0 0 1 1

CA 0 1 0 1 0 1 0 1

A/D Channel PE0 PE1 PE2 PE3 PE4 PE5 PE6 PE7

ADRx result for MULT=1 ADR1 ADR2 ADR3 ADR4 ADR1 ADR2 ADR3 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.

37

Chapter 3 Hardware Overview

8-bit Characters to be transmitted

Transmit shift register

Clock Transmit data register


Figure 3.3 Asynchronous serial data transmission on the M68HC11

TxD

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

38

Chapter 3 Hardware Overview

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 BAUD SCCR1 SCCR2 SCSR2 SCDR Memory Address $102B $102C $102D $102E $102F

Bit 7 TCLR R8 TIE TDRE T7/R7

Bit 6 0 T8 TCIE TC T6/R6

Bit 5 SCP1 0 RIE RDRF T5/R5

Bit 4 SCP0 M ILIE IDLE T4/R4

Bit 3 RCKB WAKE TE OR T3/R3

Bit 2

Bit 1

Bit 0 SCR0 0 SBK 0 T0/R0

SCR2 SCR1 0 0 RWU RE NF FE T2/R2 T1/R1

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

39

Chapter 3 Hardware Overview

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 TMSK2 TFLG2 Memory Address $1024 $1025 Bit 7 TOI TOF Bit 6 RTII RTIF Bit 5 PAOVI PAOVF Bit 4 PAII PAIF Bit 3 Bit 2 Bit 1 Bit 0 0 0 0 0 PR1 0 PR0 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 0 0 1 1 EDGxA 0 1 0 1 Configuration Capture disabled Capture rising edges only Capture falling edged only 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

40

Chapter 3 Hardware Overview

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.

41

Chapter 3 Hardware Overview

Pseudo Interrupt Vector Serial communications interface (SCI) Serial peripheral interface (SPI) Pulse accumulator input edge Pulse accumulator overflow Clock counter (TCNT) overflow Timer output compare 5 (TOC5) Timer output compare 4 (TOC4) Timer output compare 3 (TOC3) Timer output compare 2 (TOC2) Timer output compare 1 (TOC1) Timer input capture 3 (TIC3) Timer input capture 2 (TIC2) Timer input capture 1 (TIC1) Real Time Interrupt IRQ XIRQ Software interrupt (SWI) Illegal Op code Computer operating properly Clock monitor

Memory Address Field $00C4-$00C6 $00C7-$00C9 $00CA-$00CC $00CD-$00CF $00D0-$00D2 $00D3-$00D5 $00D6-$00D8 $00D9-$00DB $00DC-$00DE $00DF-$00E1 $00E2-$00E4 $00E5-$00E7 $00E8-$00EA $00EB-$00ED $00EE-$00F0 $00F1-$00F3 $00F4-$00F6 $00F7-$00F9 $00FA-$00FC $00FD-$00FF

Table 3-5 Pseudo vector table for the 68HC11 (Reproduced from Greenfield, 1992)

42

Chapter 3 Hardware Overview

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 Data register A (DRA) Data Direction Register A (DDRA) Control Register A (CRA) Data register B (DRB) Data Direction Register B (DDRB) Control Register B (CRB)
Table 3-6 MC6821 PIA Register addresses

Corresponding Address 0xA100 0xA100 0xA101 0xA102 0xA102 0xA103

43

Chapter 3 Hardware Overview

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*/

44

Chapter 4

The Windows-Based Software

4.1 Introduction
A Windows95 based digital control program was developed, which provides a userfriendly 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

45

Chapter 4 The Windows-Based Software

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 Windowsbased 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-SingleOutput Digital Controller. The three PID controller parameters, K P , K I and K D are converted to the a and b vectors as described in section 2.3.2 before downloading the controller parameters to the microcontroller.

46

Chapter 4 The Windows-Based Software

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.

47

Chapter 4 The Windows-Based Software

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 floatingpoint 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.

48

Chapter 4 The Windows-Based Software

10

11
Convert entered control parameters to hexadecimal format

09

0A

0B

Collate the hexadecimal characters to a single string

090A0B

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

S1060000090A0B

Predefined Control Algorithm

Calculate the checksum and add the checksum byte to the string

S03098B . . . S111B6005 . . . S112B6005 . . . S113B6007 . . .

S1060000090A0BDB

S940000B5 . . .

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

S03098B . . . S1060000090A0BDB S111B6005 . . . S112B6005 . . . S113B6007 . . . S940000B5 . . .


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

49

Chapter 4 The Windows-Based Software

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;

50

Chapter 4 The Windows-Based Software

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.

51

Chapter 4 The Windows-Based Software

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.

52

Chapter 4 The Windows-Based Software


Start the download procedure

Prompt the user to reset the microcontroller

Enable serial communication between the PC and the microcontroller.

Is serial data available in the input buffer?

No

Yes

Was a reset action detected from the microcontroller?

No

Display error message

Yes Initialize the microcontroller to receive program data from the serial communication interface. End the download procedure

Download the control algorithm to the microcontroller in a separate thread.

Is all the data downloaded to the microcontroller?

No

Yes

Was a done message received from the microcontroller?

No

Display error message

Yes Enable the user to start the control algorithm on the microcontroller End the download procedure

End the download procedure

Figure 4.2. Control algorithm download procedure

53

Chapter 4 The Windows-Based Software

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.

54

Chapter 4 The Windows-Based Software

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

55

Chapter 4 The Windows-Based Software

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 doubleinput-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) {

56

Chapter 4 The Windows-Based Software

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++; } }

57

Chapter 4 The Windows-Based Software

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 eventhandler, 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;

58

Chapter 4 The Windows-Based Software

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.

59

Chapter 4 The Windows-Based Software

60

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

61

Chapter 5 The Microcontroller-Based Software

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.

62

Chapter 5 The Microcontroller-Based Software

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 multistep 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 microcontrollers interface to peripheral equipment. Testing a systems response to known input signals Data acquisition. Pulse signal generation

Microcontroller Output

Output Upper Limit

Step size Step delay time Output Lower Limit Time Figure 5.1 Output signal configuration for the Test Input/Output category of programs.

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 microcontrollers interface to peripheral equipment while the complete program source code can be found in Appendix G.

63

Chapter 5 The Microcontroller-Based Software

I/O Combination 1 2 3 4

Associated Input Analog voltage input on pin PE5 Frequency input on pin PA0 Frequency input on pin PA0 Analog voltage input on pin PE5

Associated Output 8-Bit parallel output on pins PB0-PB7 on the MC6821 PIA 8-Bit parallel output on pins PB0-PB7 on the MC6821 PIA PWM output on pin PA5 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.

64

Chapter 5 The Microcontroller-Based Software


Begin

Assign parameter variable names to the downloaded parameter data

Initialize the serial communication interface to transmit serial data.

Initialize the timeroverflow interrupt

Input/Output combination = 1?

Yes

No

Initialize the analog-to-digital converter

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

Input/Output combination = 2?

No

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

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

Input/Output combination = 3?

No

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

1A

1B

1C

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

65

Chapter 5 The Microcontroller-Based Software

1A

1B

1C

Initialize the analog-to-digital converter

Initialize the OC1 and OC3 output to produce a PWM signal

Save sample start-time and calculate the desired sample end-time.

Output = Output Lower Limit

Did the output steptime elapse?

Yes Output = Output + Stepsize

No

Output > Output Upper Limit?

Yes Output = Output Lower Limit No

Input/Output combination = 1 or 4 ?

Yes

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

2C

2A

2B

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

66

Chapter 5 The Microcontroller-Based Software

2C

2A

2B

Read the input on the Analog-to-Digital converter

Input/Output combination = 1 or 2 ?

Yes

No
Send Output the peripheral interface adapter

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

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

Did the desired sample end-time elapse ?

No

Yes

Calculate the real sample period and save this value

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

67

Chapter 5 The Microcontroller-Based Software

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

Microcontroller
Serial Communication Interface

Serial data to PC

Saturation Input

Fourth-Order Digital Filter

Saturation
4

b 0 + b1 z +

+ b2 z

+ b3 z

+ b4 z

Output

a 0 + a1 z 1 + a 2 z 2 + a 3 z 3 + a 4 z 4

Setpoint

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

68

Chapter 5 The Microcontroller-Based Software

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.

Begin

Assign parameter variable names to the downloaded parameter data

Initialize the serial communication interface to transmit serial data.

Initialize the timeroverflow interrupt

Input/Output combination = 1?

Yes

No

Initialize the analog-to-digital converter

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

Input/Output combination = 2?

No

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

1A

1B

1C

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

69

Chapter 5 The Microcontroller-Based Software

1A

1B

1C

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

Input/Output combination = 3?

No

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

Initialize the analog-to-digital converter

Initialize the OC1 and OC3 output to produce a PWM signal

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

Input/Output combination = 1 or 4?

No

Yes

Read the latest frequencyinput 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)

70

Chapter 5 The Microcontroller-Based Software

2A

2B

Read the input on the Analog-to-Digital converter

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

No

Yes

Yes

Input = Input Lower Limit

Input = Input Upper Limit

Feedback mode = Negative Feedback?

No

Yes

Error = Setpoint - Input

Error = Setpoint + Input

Calculate Output by using the digital filter difference equation

3A

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

71

Chapter 5 The Microcontroller-Based Software

3A

Output < Output Lower Limit?

No

Output > Output Upper Limit?

No

Yes Output = Input Lower Limit

Yes Output = Output Upper Limit

Save the current input and output values for the next difference equation calculations

Input/Output combination = 1 or 2?

Yes

No
Calculate the PWM ontime and write this value to memory. Send Output the peripheral interface adapter

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

Did the desired sample end-time elapse ?

No

4 Yes Calculate the real sample period and save this value

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

72

Chapter 5 The Microcontroller-Based Software

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 DoubleInput-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.
Microcontroller
Serial data to PC Serial Communication Interface

Setpoint 1 Saturation Input 1

Multivariable Digital Filter Saturation


b0 11 + b1 11 z + b2 11 z 1 2 1 + a1 11 z + a 2 11 z 1 b0 21 + b1 21 z + b2 21 z 2 1 2 1 + a1 21 z + a 2 21 z
1 2

1 + a1 12 z + a 2 12 z 1 2 b0 xy + b1 xy z + b2 xy z 1 + a1 21 z 1 + a 2 21 z 2 b0 12 + b1 12 z
1

+ b2 12 z

Output 1

Saturation Input 2

Saturation Output 2

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

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.

73

Chapter 5 The Microcontroller-Based Software


Begin

Assign parameter variable names to the downloaded parameter data

Initialize the serial communication interface to transmit serial data.

Initialize the timeroverflow interrupt

Initialize the analog-to-digital converter

Initialize pins PB0-PB7 on the 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 pins PB0-PB7 on the M6821 Peripheral Interface Adapter to serve as an 8-bit output port.

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

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

1A

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

74

Chapter 5 The Microcontroller-Based Software


1A

Read the input on the Analog-to-Digital converter

Frequency Input < Frequency Input Lower Limit?

No

Frequency Input > Frequency Input Upper Limit?

No

Yes

Yes

Frequency Input = Frequency Input Lower Limit

Frequency Input = Frequency Input Upper Limit

Analog Input < Analog Input Lower Limit?

No

Analog Input > Analog Input Upper Limit?

No

Yes Analog Input = Analog Input Lower Limit

Yes Analog Input = Analog Input Upper Limit

Frequency Feedback mode = Negative Feedback?

No

Yes Frequency Error = Frequency Setpoint Frequency Input Frequency Error = Frequency Setpoint + Frequency Input

2A

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

75

Chapter 5 The Microcontroller-Based Software


2A

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 on-time and write this value to memory.

Calculate the PWM output by using a digital filter difference equation.

8-Bit Output < 8-Bit Output Lower Limit?

No

8-Bit Output > 8-Bit Output Upper Limit?

No

Yes

Yes

8-Bit Output = Frequency Output Lower Limit

8-Bit Output = 8-Bit Output Upper Limit

PWM Output < PWM Output Lower Limit?

No

PWM Output > PWM Output Upper Limit?

No

Yes 3A

Yes 3B 3C

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

76

Chapter 5 The Microcontroller-Based Software

3A

3B

3C

PWM Output = PWM Output Lower Limit

PWM Output = PWM Output Upper Limit

Save the current input and output values 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 Sample Frequency values to the Serial Communication Interface (SCI).

Did the desired sample end-time elapse ?

No

4 Yes Calculate the real sample period and save this value

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

77

Chapter 5 The Microcontroller-Based Software

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: Analog input Frequency input Output ports: PWM output 8-Bit Parallel output PA5 PB0-PB7 on MC6821 PIA 40 256 Hz 00000000 11111111 binary PE5 PA0 Associated pins Feasible Range 0 - 5.12 V 0 256 Hz

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

78

Chapter 5 The Microcontroller-Based Software

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

79

Chapter 5 The Microcontroller-Based Software

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.

80

Chapter 5 The Microcontroller-Based Software

Start Interrupt service routine

Reset the IC3F flag by writing 1 to it

Did the timer-overflow (TOF) bit set?

Yes

Did the MSB in the captured TIC3 value set?

No

No

Yes

Increment the timeroverflow variable with 1.

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

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

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

Reset the timeroverflow variable to zero.

Return to the main program

Figure 5.7 Frequency measurement interrupt service routine flow diagram

81

Chapter 5 The Microcontroller-Based Software

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 2560.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 8bits 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; }

*/ */ */ */

82

Chapter 5 The Microcontroller-Based Software

/***************************************************/ /* 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; asm { PSHA LDAA #0x01 STAA 0x1023 PULA } /* Enable the interrupt mask for IC3 (PA0) */

/* Save the contents of accumulator A /* Load accumulator A with the mask data /* Reset input flag IC3F by writing 1 to it

*/ */ */

/* 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 LDAA #0x80 STAA 0x1025 PULA RTI } } /* Save the contents of accumulator A /* Load accumulator A with the mask data */ */

/* Reset the timer overflow flag (TOF) */ /* Retrieve the saved contents of accumulator A */ /* Return from Interrupt Service Routine */

83

Chapter 5 The Microcontroller-Based Software

/***************************************************/ /* Frequency Measurement Interrupt Service Routine */ /***************************************************/ void inputcapture(void) { asm /* Reset input flag IC3F by writing 1 to it */ { PSHA LDAA #0x01 STAA 0x1023 PULA } /* Save the contents of accumulator A /* Load accumulator A with the mask data */ */

/* Reset TOF flag by writing 1 to it */ /* Retrieve the saved contents of accumulator A */

if (TFLG2BYTE>=0x80 && TIC3UP<=0x80) { timeroverflows++; asm { PSHA /* LDAA #0x80 /* STAA 0x1025 /* PULA /* } }

Save the contents of accumulator A Load accumulator A with the mask data Reset IC3F flag by writing 1 to it 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; timeroverflows=0; asm RTI; } /* Save the endtime of this ISR */

/* Reset the timeroverflows variable */ /* Return to main program */

84

Chapter 5 The Microcontroller-Based Software

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

85

Chapter 5 The Microcontroller-Based Software

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; TMSK1.OC3I=1; OC1D.OC1D5=1; TCTL1.OL3=1; TOC1=TCNT+50000; TOC3=TOC1+1; } /* couple OC1 to OC3 */ /* /* /* /* /* enable the OC3 interrupt */ turn on OC3 when OC1 occurs */ toggle OC3 when OC3 occurs */ initialize OC1 */ 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

*/ */ */

86

Chapter 5 The Microcontroller-Based Software

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.

87

Chapter 5 The Microcontroller-Based Software

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 LDAA #0x01 STAA 0x1023 PULA }

/* /* /* /*

Save the contents of accumulator A Load accumulator A with the mask data Reset IC3F by writing 1 to it Retrieve the saved state of accumulator A

*/ */ */ */

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

88

Chapter 5 The Microcontroller-Based Software

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.

89

Chapter 5 The Microcontroller-Based Software

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.

90

Chapter 5 The Microcontroller-Based Software

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

Program.c

Hc11e9.h

Compiler

Compiler

Ansi.lib

Start11.o

Program.prm

Program.o

Linker

Program.abs

Burner

Program.s19

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

91

Chapter 5 The Microcontroller-Based Software

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 Program.c Program.prm Lustart.h Hc11e9.h Non_bank.sgm Ansi.lib Default startup code for the 68HC11. Main control algorithm source code. Linker parameter file. Header file which defines the startup description. Header file for the 68HC11 register definitions. HC11 Small and medium memory model. ANSI C libraries.

92

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 users 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.

93

Chapter 6 Using the Windows-Based Software

Figure 6.1 The startup window of HC11Control.

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.

94

Chapter 6 Using the Windows-Based Software

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 systems response to a known input signal.

Figure 6.2 The Test Input/Output Panel

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.
Microcontroller Output

Output Upper Limit

Step size Step delay time Output Lower Limit

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

95

Chapter 6 Using the Windows-Based Software

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.
Controller
Saturation Input Fourth-Order Digital Filter Saturation
4

b 0 + b1 z +

+ b2 z

+ b3 z

+ b4 z

Output

a 0 + a1 z 1 + a 2 z 2 + a 3 z 3 + a 4 z 4

Setpoint

Figure 6.4 Schematic layout of the SISO digital controller.

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.

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

96

Chapter 6 Using the Windows-Based Software

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.

Controller
Analog Setpoint Saturation

Analog Input

Saturation Multivariable Digital Filter

8-Bit Output

e1 e2
Frequency Input Saturation
b0 11 + b1 11 z 1 + b2 11 z 2 1 2 1 + a1 11 z + a 2 11 z b0 21 + b1 21 z 1 + b2 21 z 2 1 2 1 + a1 21 z + a 2 21 z b0 12 + b1 12 z 1 + b2 12 z 2 1 + a1 12 z 1 + a 2 12 z 2 b0 xy + b1 xy z 1 + b2 xy z 2 1 + a1 21 z 1 + a 2 21 z 2

u1 u2
Saturation PWM Output

Frequency Setpoint

Figure 6.6 Double-Input-Double-Output digital controller

The multivariable digital filter transfer function can be described as follow: B11 u1 A11 u = B 2 21 A21 where B xy Axy b0 xy + b1 xy z 1 + b2 xy z 2 1 + a1 xy z
1

B12 A12 e1 B22 e2 A22

(6.1)

+ a 2 xy z

(6.2)

97

Chapter 6 Using the Windows-Based Software

The six parameter vectors P1 , Q1 , R1 , P2 , Q2 and R2 are defined as P1 = A11 A12 = 1 + p1 1 z 1 + p1 2 z 2 + p1 3 z 3 + p1 4 z 4 Q1 = B11 A12 = q1 0 + q1 1 z 1 + q1 2 z 2 + q1 3 z 3 + q1 4 z 4 R1 = A11 B12 = r1 0 + r1 1 z 1 + r1 2 z 2 + r1 3 z 3 + r1 4 z 4 P2 = A21 A22 = 1 + p 2 1 z 1 + p 2 2 z 2 + p 2 3 z 3 + p 2 4 z 4 Q2 = B21 A22 = q 2 0 + q 2 1 z 1 + q 2 2 z 2 + q 2 3 z 3 + q 2 4 z 4 R2 = A21 B22 = r2 0 + r2 1 z 1 + r2 2 z 2 + r2 3 z 3 + r2 4 z 4 It is the responsibility of the user to calculate the six parameter vectors P1 , Q1 , R1 , P2 , Q2 and R2 from the transfer function shown in Equation 6.1. The vectors P1 , Q1 , R1 , P2 , Q2 and R2 vectors can then be directly implemented on the double-inputdouble-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

98

Chapter 6 Using the Windows-Based Software

6.5 The PID Controller


The structure of the PID controller can be represented as illustrated in Figure 6.8.

PID Controller
Proportional Term

KP

Integral Term Saturation Input

K IT z +1 2 z 1
Derivative Term

+ + +

Saturation Output

Setpoint

K D z 1 T z
Figure 6.8 Schematic layout of the digital PID controller.

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, K P , K I and K D can be any floating-point values, while the sample period, T is determined by the Sample Frequency value.

99

Chapter 6 Using the Windows-Based Software

Figure 6.9 The PID Controller panel.

100

Chapter 6 Using the Windows-Based Software

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.

Start the program on the microcontroller

Disable serial communication Stop recording with the microcontroller

Plot the recorded controller performance data

Download code to the microcontroller

Monitor the controller performance data

Record the controller Save the recorded controller performance performance data data

Figure 6.10 HC11Control toolbar

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.

101

Chapter 6 Using the Windows-Based Software

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 downloading procedure cannot continue due to a running program on the microcontroller

102

Chapter 6 Using the Windows-Based Software

A reset signal is detected from the microcontroller

Download procedure finished

Download error

Download successful

Figure 6.13 The control algorithm download procedure

103

Chapter 6 Using the Windows-Based Software

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.

104

Chapter 6 Using the Windows-Based Software

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: Maximum Recording Time = 65536 Sample Frequency

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.

105

Chapter 6 Using the Windows-Based Software

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.

Figure 6.16 HC11Control plotting windows

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

106

Chapter 6 Using the Windows-Based Software

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.

107

Chapter 6 Using the Windows-Based Software

108

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

109

Chapter 7 Application Example: DC Motor Speed Control

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.
12 V

68 PWM Signal from microcontroller

1k2

2N3904 TIP31

Permanent Magnet DC Motor

Figure 7.1 DC Motor speed control with the PWM Darlington Circuit

110

Chapter 7 Application Example: DC Motor Speed Control

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].

5 V

5 k 6

10 k 1 k 2 Pulse Output Phototransistor

LED

Figure 7.2 The optical interrupt circuit

Aluminum disk

DC Motor LED Phototransistor

Figure 7.3 The optical speed sensor

111

Chapter 7 Application Example: DC Motor Speed Control

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.

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

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

112

Chapter 7 Application Example: DC Motor Speed Control

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.

Motor Speed vs PWM Input


50 45 40 35 30 25 20 15 10 5 0 30 40 50 60 70 80 90 100 110 DC motor PWM input (8-bit unsigned value) 120 130

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 value2.56.

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.)

Motor Speed (Hz)

113

Chapter 7 Application Example: DC Motor Speed Control

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

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


37

32

Motor Speed (Hz)

27

63.2 % Line

22 Time Constant

17

12

7 0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1 1.1 1.2

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

114

Chapter 7 Application Example: DC Motor Speed Control

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 G (s ) = Kb s +b

(7.1)

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 K= Motor Speed 34 6 = = 0.56 PWM Input 90 40

(7.2)

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. b= 1 = 1 =5 0 .2

(7.3)

Quantizer1 Saturation1 + + Saturation2

DC Motor 2.8 s+5 Delay Graph

Step Input

-28 Offset

output.mat To File

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

115

Chapter 7 Application Example: DC Motor Speed Control

The DC motor transfer function can therefore be written as G (s ) = Kb 0.56 5 2 .8 = = s+b s+5 s+5

(7.4)

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.

DC Motor Step Response with 40 to 90 PWM input


40 35

Motor Speed (Hz)

30 25 20 15 10 5 0 0.2 0.4 0.6 0.8 1 1.2

Actual Motor Simulink model

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

116

Chapter 7 Application Example: DC Motor Speed Control

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 K p , K I and K D terms into the a and b vectors of the difference equation as follow. KIT K D + 2 T K T 2K D b1 = K P + I 2 T KD b2 = T a0 = 1 b0 = K P + a1 = 1 a2 = 0 The PID controller can therefore be implemented by specifying the a and b vectors in the Digital Controller section or by specifying the K p , K I and K D 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)

117

Chapter 7 Application Example: DC Motor Speed Control

Step Input Input Graph + 2.16-1.84z-1 1-z-1 Digital Controller -28 Offset Saturation1 Quantizer1 + + Saturation2 2.8 s+5 DC Motor Delay Output Graph

Saturation3

Quantizer2

Zero-Order Hold

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

Figure 7.11

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

118

Chapter 7 Application Example: DC Motor Speed Control

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.

DC Motor speed step response


35 30

Motor Speed (Hz)

25 20 15

Actual Motor Simulink model

10 5 0 0.2 0.4 0.6 0.8 1 1.2 1.4

Time

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

119

Chapter 7 Application Example: DC Motor Speed Control

PID Controller output to the DC motor


90

80

Controller Output

70

60

Actual Controller Output Simulink model

50

40 0 0.2 0.4 0.6 0.8 1 1.2 1.4

Time Figure 7.13 PID Controller output to the DC motor

120

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 filters magnitude response is equal to 3dB [3].

121

Chapter 8 Application Example: Digital Filtering

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
x

Noise

Sensor

mV

Amplifier

Low-pass Filter

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.

122

Chapter 8 Application Example: Digital Filtering

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.

Microcontroller
Serial Communication Interface

Serial data to PC

Saturation Input

Fourth-Order Digital Filter

Saturation
4

b 0 + b1 z +

+ b2 z

+ b3 z

+ b4 z

Output

a 0 + a1 z 1 + a 2 z 2 + a 3 z 3 + a 4 z 4

Setpoint

Figure 8.2

Schematic layout of the microcontroller-based digital filter.

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));

123

Chapter 8 Application Example: Digital Filtering

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. a0 = 1 a1 = 3.2692 a2 = 4.3403 a 3 = 2.7419 a4 = 0.6946 b0 = 0.0011 b1 = 0.0042 b2 = 0.0063 b3 = 0.0042 b4 = 0.0011

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.

Gain dB

-50

-100 0 10

10

10

10

Frequency (rad/sec)

0 -180 -360 -540 10


0

Phase deg

10

10

10

Frequency (rad/sec) Figure 8.3 Frequency response of a fourth-order low-pass Chebyshev type I digital filter

124

Chapter 8 Application Example: Digital Filtering

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.

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

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 noisefiltering abilities of this digital filter.

125

Chapter 8 Application Example: Digital Filtering

130

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

Digital Filter Output (8-bit value)

110

90

70

50 0 1 2 3 4 5 6 7

Frequency (Hz)

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

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


180 160 140

8-Bit value

120 100 80 60 40 20 0 0.25 0.5 0.75 1 1.25 1.5

Filter Input Filter Output

Tim e (seconds )

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

126

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

127

Chapter 9 Application Example: Multivariable Temperature Control

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 systems transient response data can be obtained from step inputs. The systems transient response data is relatively easy to obtain and is sufficient for modeling firstorder 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.

128

Chapter 9 Application Example: Multivariable Temperature Control

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. & Q c

& Q i

& he , m

& hi , m

& = Heat Loss (W ) Q c & = Heat Input (W ) Q i &= Mass Flow Rate (kg s ) m hi = Specific Input Enthalpy ( J kg )

he = Specific Output Enthalpy ( J kg )

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

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 c p 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: Heat Input Rate Heat Output Rate = Heat Accumulation Rate dh &+ m &+m & & [Q h ] [Q h ] = V dt
i i c e e

(9.1)

129

Chapter 9 Application Example: Multivariable Temperature Control

Given that c p is constant for all the temperatures considered, we can write h = c pT where c p = Constant pressure specific heat ( J kg K) T = Temperature (K) The heat loss across the walls occurs by means of conduction and can be defined as & = Te Ti Q c L kA where L = Wall Thickness (m) k = Thermal Conductivity (W/m K) A = Wall Surface Area ( m 2 ) Ti = Inlet air temperature (K ) Te = Outlet air temperature ( K ) Substituting Equations 9.2 and 9.3 into Equation 9.1 gives T T &+m & c T ] [Q L kA
e i p i

(9.2)

(9.3)

dT & c p Te = Vc p e +m dt

(9.4)

Rearranging Equation 9.4 gives the system state-space representation in the form &= Ax + Bu . x kA & cp m dTe T kA L T + 1 &+m & = c p Ti + i e Q i dt Vc p L Vc p

(9.5)

130

Chapter 9 Application Example: Multivariable Temperature Control

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 45C can therefore be measured by the microcontroller. The input resolution can be calculated as follow Resolution = 45C = 0.178C / bit 28
100K

(9.6)

5V 5V 10K

LM35

LM324 +

1K 0-5V

Figure 9.2 The Temperature Measurement Circuit

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.

131

Chapter 9 Application Example: Multivariable Temperature Control

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.
9V 0.1 F

1 1 2 8

16

5k6 10 F
2 15

ICL7660

7 6

+
3 4 14

5k6 DAC0808
13 12 11 10 9

10F

3 4

5V

5k6

5 6 7 8

5k 9V
8

LSB Digital Inputs MSB Analog Output (To Fan)

L272
7

2 1 4

5k

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

132

Chapter 9 Application Example: Multivariable Temperature Control

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.

12 V

68 PWM Signal from microcontroller

1k2

2N3904 TIP31

Heating Coil

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

133

Chapter 9 Application Example: Multivariable Temperature Control

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.

Air Out

Air In Fan

Temperature Sensor

Heating Coil

Figure 9.5 Schematic representation of the temperature system setup

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.

134

Chapter 9 Application Example: Multivariable Temperature Control

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

63.2% Line Time Constant

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

135

Chapter 9 Application Example: Multivariable Temperature Control

The first-order transfer function of the heating process can be written as G (s ) = Kb s +b

(9.7)

where K is the steady-state gain constant and b is the inverse of the process timeconstant. The steady-state gain for the heating process can be calculated as follow: K= = Final Temperature Initial Temperature PWM Step Size 0.178 (159 113) = 0.0546 150

(9.8)

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. 1 1 = = 0.00901 Process Time Constant 111

b=

(9.10)

The heating process transfer function can therefore be expressed as Kb 0.0546 0.00901 0.00049 = = s+b s + 0.00901 s + 0.00901

G (s ) =

(9.11)

20.5 Ambient Temperature Open System Quantizer1 0.00049 Step Input Saturation1 s+0.00901 Delay + + Sum

output.mat To File

Graph

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

136

Chapter 9 Application Example: Multivariable Temperature Control

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


30 29

Temperature (C)

28 27 26 25 24 23 22 21 20 0 50 100 150 200 250 300


Simulink Model Actual System

Time (Seconds)
Figure 9.9 Open loop step response for the heating process

137

Chapter 9 Application Example: Multivariable Temperature Control

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 systems 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 ( K P , K I and K D ) 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. K IT KD 0.08 0.05 + =2+ = 2.002 2 2 T K T 2K D 0.08 0.05 = 2 + = 1.998 b1 21 = K P + I 2 2 T K 0 =0 b2 21 = D = 0.05 T a 0 21 = 1 b0 21 = K P + a1 21 = 1 a 2 21 = 0

(9.12)

138

Chapter 9 Application Example: Multivariable Temperature Control

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. P1 = 1 Q1 = 0 R1 = 0 P2 = 1 z 1 Q2 = 2.002 1.998 z 1 R2 = 0 (9.13)

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

139

Chapter 9 Application Example: Multivariable Temperature Control

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.

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

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.

140

Chapter 9 Application Example: Multivariable Temperature Control

Step Input + Sum1 5.618 Gain Digital Filter -1 2.002-1.998z 1-z-1

Ambient Temperature 19.4

Open System Control Effort Quantizer1 0.00052 Saturation1 s+0.00901 Delay + + Sum

Temperature Out

output.mat Saturation3 Quantizer2 Zero-Order Hold To File

Figure 9.13 Simulink model for PI control of the heating process

Temperature step response for a closed-loop PI control action 28 27 26 Temperature (C) 25 24 23 22 21 20 19 18 0 100 200 300 400 500 Time (Seconds) 600 700 800 Simulink Model Experiment

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

141

Chapter 9 Application Example: Multivariable Temperature Control

Control effort step response for a closed-loop PI control action 200 8-Bit PWM output value

150

100

50

Simulink Model Experiment

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

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

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 systems temperature is higher than the desired system temperature. The PI control parameters for the multivariable control application are as follow: Heating Process: K P = 2 , K I = 0.08 Cooling Process: K P = 2 , K I = 0.08

142

Chapter 9 Application Example: Multivariable Temperature Control

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: K IT KD 0.08 0.05 = 2.002 + =2+ 2 2 T K T 2K D 0.08 0.05 = 2 + = 1.998 b1 21 = K P + I 2 2 T K 0 =0 b2 21 = D = 0.05 T a 0 21 = 1 b0 21 = K P + a1 21 = 1 a 2 21 = 0

(9.14)

The PI control parameters for the cooling process are expressed as follow: KIT KD 0.08 0.05 = 2 = 2.002 2 2 T K T 2K D 0.08 0.05 = 2 = 1.998 b111 = K P I + 2 2 T K 0 =0 b2 11 = D = 0.05 T a 0 11 = 1 b011 = K P a111 = 1 a 2 11 = 0 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.15)

143

Chapter 9 Application Example: Multivariable Temperature Control


1 P 1 = 1 z

Q1 = 2.002 + 1.998z 1 R1 = 0 P2 = 1 z 1 Q2 = 2.002 1.998 z 1 R2 = 0 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.

144

Chapter 9 Application Example: Multivariable Temperature Control

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

145

Chapter 9 Application Example: Multivariable Temperature Control

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.

146

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

147

Chapter 10 Conclusions and Recommendations

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.

148

Chapter 10 Conclusions and Recommendations

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 Motorolas 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 DSPs are rich in math capabilities and most DSPs have a build in multiplieraccumulator (MAC) which is dedicated to multiplying instructions and fast floatingpoint 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].

149

Chapter 10 Conclusions and Recommendations

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.

150

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. Dorf, R.C and Bishop, R.H. (1995) Modern Control Systems. AddisonWesley, New York, pp 240-242. 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. Franklin, G.F.,Powel, J.D. and Workman, M.L. (1990) Digital Control of Dynamic Systems. Addison-Wesley, New York, pp 641-666. Greenfield, J.D. (1992) The 68HC11 Microcontroller. Saunders College Publishing, London, pp 303-306. Bozic, S.M. (1979) Digital and Kalman filtering. Edward Arnorld, London. Kuo, B.C. (1991) Automatic Control Systems 6th edition. Prentice Hall, New Jersey. Lefkon D. and Payne B. (1998) Making embedded systems year 2000 compliant. IEEE Spectrum. 35 , 74-79. Beards, P.H. (1991) Analog and Digital Electronics. Prentice Hall, New York, pp 564-567.

[3]

[4]

[6]

[7]

[8] [9]

[10]

[11]

151

[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. Beckwith, T.G., Marangoni, R.D. and Lienhard, J.H. (1993) Mechanical Measurements Fifth Edition. Addison-Wesley, New York, pp 179-204.

[15]

[16]

The Student Edition of Matlab Users Guide, Prentice Hall, Englewood Cliffs, NJ, pp 273-274. Austin, P.C. (1998) Lecture Handout, 660.704 FC Advanced Control Systems, The University of Auckland.

[17]

[18] [19] [20]

Mills, A. F. (1995) Basic Heat and Mass Transfer. IRWIN, Chicago, pp 4. Motorola M68HC11 Reference Manual, Motorola, Phoenix, AZ, 1990 Gatland, B. (1998) A better tuning method?. Automation & Control. March 98, 30-31.

152

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

153

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

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 twos-complement format.

31

30 - 23

22 - 0

1 bit sign

8-bit exponent + 127 bias

23-bit mantissa with leading one removed

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

63

62 - 52

51 - 0

1 bit sign

11-bit exponent + 1023 bias

52-bit mantissa with leading one removed

Figure A.2 ANSI/IEEE 754 Basic Double-Precision floating-point 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.

154

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

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 1.2 10 1 and not as 12 10 0 . 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. Corresponding Approximate Decimal 10 44.85 10 38.53 10 323.3 10 308.3

Normalized Single Precision Minimum Single Precision Maximum Double Precision Minimum Double Precision Maximum 2 149 (1 2 23 ) 2 126 2 1074 1 2 52 2 1022

Denormalized 2 126
(1 2 23 ) 2 127

2 1022
1 2 52 21023

Table A1 Ranges of the floating-point representation.

155

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

A4. ANSI/IEEE 754 Floating-Point Special Values


Zero Zero can not be represented directly in the in the straight ANSI/IEEE 754 FloatingPoint 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

( 1)s 0.m 2126

, where s is the sign bit and m is the mantissa. Double precision


s

denormalized numbers are represented as ( 1) 0.m 2 1022 . 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.

156

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

A5. ANSI/IEEE 754 Floating-Point Special Operations


All arithmetic operations on special numbers are defined by IEEE as follow: Operation n Infinity Infinity Infinity n0 Infinity + Infinity Infinity Infinity Infinity Infinity Infinity 0 Result 0 Infinity Infinity Infinity Indeterminate Indeterminate Indeterminate

Table A2 Floating-Point Special Operations

157

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

158

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 Srecord 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.

159

Appendix B S-record Information

S-record Field Type Record length Address Code/ Data 2 2

Number of characters

Contents S-record type: S0-S9 Number of character pairs in the character string, excluding type and record length pairs. The 2-4 byte starting address at which the code/data field is to be loaded into memory. The executable program code and data in machine code, which will be loaded into the memory of the microcontroller. 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.

4, 6, or 8 0-n

Checksum

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.

160

Appendix B S-record Information

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 06 The line is a type S0 S-record. This character pair / byte is the record length. Hexadecimal 06 indicates that six character pairs / bytes will follow. The four character address field which is zeros.

00 00 44 48 52 1B

The data field, ASCII H, D and R. The data field can contain any descriptive information regarding the block of S-record data which follows. 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.

161

Appendix B S-record Information

23

Hexadecimal 23 (decimal 35) indicates that 35 character pairs / bytes of data will follow B600 is the 2-byte memory starting-address at which the code/data field will be loaded into.

B6 00

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 Srecord. The last S-record line is a S9 type S-record and can be explained as follow: S9 03 The S9 indicates that the line is an S9 type S-record. Hexadecimal 03 (decimal 3) indicates that 3 character pairs / bytes of data will follow These two character pairs is the 2-byte address of the instruction to which the control is passed. This is the checksum of the S9 record.

B6 00 46

162

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].

163

Appendix C Ziegler-Nichols Tuning of PID Controllers y(t ) K

Figure C1. Typical process response curve

The response of most plants my be approximated by G (s ) = Y (s ) Ke d s = U ( s ) s + 1

(C.1)

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. y(t )
1 0.25

Period t
Figure C2. Quarter decay ratio

164

Appendix C Ziegler-Nichols Tuning of PID Controllers

Type of Controller P

Optimum Gain KP = KP = KP =

K d
0.9 0.27 , KI = 2 K d K d 1.2 0.6 0.6 , KD = , KI = 2 K K d K d

PI

PID

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

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 K u , which is known as the ultimate gain and the period of oscillation Pu , which is known as the ultimate period can be determined as illustrated in Figure C3.

+ -

Ku

Process Pu

Figure C3. Determination of the ultimate gain and ultimate period

The PID controller parameters suggested by Ziegler and Nichols, in terms of K u and Pu , 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.

165

Appendix C Ziegler-Nichols Tuning of PID Controllers

Type of Controller P

Optimum Gain K P = 0 .5 K u K P = 0.45 K u , K I = 0.54 K P = 0.6 K u , K I = 1.2 Ku Pu

PI

PID

Ku , K D = 0.075K u Pu Pu

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

166

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.

167

Appendix D Schematic and PCB Layouts

Figure D1 Schematic layout of the 68HC11 Memory Expansion Board

168

Appendix D Schematic and PCB Layouts

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

169

Appendix D Schematic and PCB Layouts

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

170

Appendix E Application Example Images

This section contains images from the DC motor speed control and multivariable temperature control application examples.

171

Appendix E Application Example Images

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

172

Appendix E Application Example Images

Figure E3.

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

173

Appendix E Application Example Images

174

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 Comsettings.h Download.cpp Download.h Download thread.cpp Download thread.h Downloadstarterror.cpp Downloadstarterror.h InsufficientDataFormFile.cpp InsufficientDataFormFile.h Communication settings form sourcce code Communication settings form header file Download form source code Download form header file Download thread source code Download thread header file Downloadstarterror form source code Downloadstarterror form header file InsufficientDataForm source code InsufficientDataForm header file

175

Appendix F The Windows-Based Software Source Code

Main.cpp Main.h Mainmenu.cpp Mainmenu.h Max250min1.cpp Max250min1.h Max255.cpp Max255.h Min40.cpp Min40.h Plot1.cpp Plot1.h Plot2.cpp Plot2.h Plot3.cpp Plot3.h Plot4.cpp Plot4.h Runcontrolprogram.cpp Runcontrolprogram.h Savedata.cpp Savedata.h

Main form source code Main form header file Startup menu source code Startup menu header file Error-message form source code Error-message form header file Error-message form source code Error-message form header file Error-message form source code Error-message form header file Plotform1 source code Plotform1 header file Plotform2 source code Plotform2 header file Plotform3 source code Plotform3 header file Plotform4 source code Plotform4 header file Runform source code Runform header file Savedata form source code Savedata form header file

176

Appendix F The Windows-Based Software Source Code

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";

177

Appendix F The Windows-Based Software Source Code

} //-------------------------------------------------------------------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"; } //--------------------------------------------------------------------

178

Appendix F The Windows-Based Software Source Code

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

179

Appendix F The Windows-Based Software Source Code

Download.cpp - Download Form source code


// File: download.cpp //------------------------------------------------------------------#include <vcl\vcl.h> #pragma hdrstop #include #include #include #include "download.h" "Download thread.h" "main.h" "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

180

Appendix F The Windows-Based Software Source Code

// // // // // //

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

181

Appendix F The Windows-Based Software Source Code

// 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;

182

Appendix F The Windows-Based Software Source Code

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

183

Appendix F The Windows-Based Software Source Code

// 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(); }

184

Appendix F The Windows-Based Software Source Code

//------------------------------------------------------------------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=""; } //-------------------------------------------------------------------

185

Appendix F The Windows-Based Software Source Code

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

186

Appendix F The Windows-Based Software Source Code

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++)

187

Appendix F The Windows-Based Software Source Code

{ 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()

188

Appendix F The Windows-Based Software Source Code

// 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() // // // // { Download1->ErrorTimer->Enabled=true; // Enable the ErrorTimer. Download1->Messagebox->Left=192; Download1->Messagebox->Caption="Done"; } //-----------------------------------------------------------------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.

189

Appendix F The Windows-Based Software Source Code

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

190

Appendix F The Windows-Based Software Source Code

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(); } //--------------------------------------------------------------------

191

Appendix F The Windows-Based Software Source Code

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

192

Appendix F The Windows-Based Software Source Code

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(); } //--------------------------------------------------------------------

193

Appendix F The Windows-Based Software Source Code

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

194

Appendix F The Windows-Based Software Source Code

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;

195

Appendix F The Windows-Based Software Source Code

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;

196

Appendix F The Windows-Based Software Source Code

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;

197

Appendix F The Windows-Based Software Source Code

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;

198

Appendix F The Windows-Based Software Source Code

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)

199

Appendix F The Windows-Based Software Source Code

{ // // // // // 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],

200

Appendix F The Windows-Based Software Source Code

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. //--------------------------------------------------------------------

201

Appendix F The Windows-Based Software Source Code

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 break; case 2: strcpy((char *)PIDdata4,(char break; case 3: strcpy((char *)PIDdata3,(char break; case 4: strcpy((char *)PIDdata2,(char break; case 5: strcpy((char *)PIDdata1,(char break; case 6: strcat((char *)PIDdata5,(char strcat((char *)PIDdata5,(char strcat((char *)PIDdata5,(char strcat((char *)PIDdata5,(char strcat((char *)PIDdata5,(char

*)data);

*)data);

*)data);

*)data);

*)data);

*)PIDdata4); *)PIDdata3); *)PIDdata2); *)PIDdata1); *)data);

int len=strlen((char *)PIDdata5);

202

Appendix F The Windows-Based Software Source Code

// // // // // // // // // //

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++; } }

203

Appendix F The Windows-Based Software Source Code

}// 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]; } }

204

Appendix F The Windows-Based Software Source Code

//-------------------------------------------------------------------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); }

205

Appendix F The Windows-Based Software Source Code

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

206

Appendix F The Windows-Based Software Source Code

// // // //

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==" " ||

207

Appendix F The Windows-Based Software Source Code

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;

208

Appendix F The Windows-Based Software Source Code

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);

209

Appendix F The Windows-Based Software Source Code

(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;

210

Appendix F The Windows-Based Software Source Code

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);

211

Appendix F The Windows-Based Software Source Code

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;

212

Appendix F The Windows-Based Software Source Code

ppwmhz=PIDPWMEdit->Text.c_str(); pwmhz=atoi(ppwmhz); vars[42]=(unsigned char)pwmhz; // // // // if 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. (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

213

Appendix F The Windows-Based Software Source Code

// 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. // Start download procedure

Download1->ShowModal(); } }

//-------------------------------------------------------------------// 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)

214

Appendix F The Windows-Based Software Source Code

{ 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)

215

Appendix F The Windows-Based Software Source Code

// // // // // // // //

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();

216

Appendix F The Windows-Based Software Source Code

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 // Start download procedure

Download1->ShowModal(); }

} //-------------------------------------------------------------------void __fastcall TMonitorForm::TestDACADCMonitorButtonClick( TObject *Sender) // This event handler will enable serial communication between the

217

Appendix F The Windows-Based Software Source Code

// // // // // //

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)

218

Appendix F The Windows-Based Software Source Code

{ 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.

219

Appendix F The Windows-Based Software Source Code

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

220

Appendix F The Windows-Based Software Source Code

{ 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 break; case 2: strcpy((char *)TestDACADCdata4,(char break; case 3: strcpy((char *)TestDACADCdata3,(char break; case 4: strcpy((char *)TestDACADCdata2,(char break; case 5: strcpy((char *)TestDACADCdata1,(char break; case 6: strcat((char *)TestDACADCdata5,(char strcat((char *)TestDACADCdata5,(char strcat((char *)TestDACADCdata5,(char strcat((char *)TestDACADCdata5,(char strcat((char *)TestDACADCdata5,(char

*)data);

*)data);

*)data);

*)data);

*)data);

*)TestDACADCdata4); *)TestDACADCdata3); *)TestDACADCdata2); *)TestDACADCdata1); *)data);

int len=strlen((char *)TestDACADCdata5);

221

Appendix F The Windows-Based Software Source Code

// // // // // // // // // //

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];

222

Appendix F The Windows-Based Software Source Code

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; }

223

Appendix F The Windows-Based Software Source Code

//-------------------------------------------------------------------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;

224

Appendix F The Windows-Based Software Source Code

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";

225

Appendix F The Windows-Based Software Source Code

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 // PIDCode2 : Input=Frequency // PIDCode3 : Input=Frequency // PIDCode4 : Input=Analog on { PIDPWMLabel->Enabled=false; PIDPWMEdit->Enabled=false; PIDRunButton->Enabled=false; PE5, Output=8-bit (PB0-PB7) on IC3, Output=8-bit (PB0-PB7) on IC3, Output=PWM on OC3 (PA5) PE5, Output=PWM on OC3 (PA5)

PIDOutputLabel->Caption="8-bit parallel output"; //AnsiString s19filename; if (PIDFrequencySelect->Checked) { pidinoutcombination=2; //s19filename="digital2.s19"; } else { pidinoutcombination=1; //s19filename="digital1.s19"; }

226

Appendix F The Windows-Based Software Source Code

//MonitorForm->DigitalCode->Lines->LoadFromFile(s19filename); } //-------------------------------------------------------------------void __fastcall TMonitorForm::PIDPWMSelectClick(TObject *Sender) // PIDCode1 : Input=Analog on // PIDCode2 : Input=Frequency // PIDCode3 : Input=Frequency // PIDCode4 : Input=Analog on { PIDPWMLabel->Enabled=true; PIDPWMEdit->Enabled=true; PIDRunButton->Enabled=false; PE5, Output=8-bit (PB0-PB7) on IC3, Output=8-bit (PB0-PB7) on IC3, Output=PWM on OC3 (PA5) PE5, Output=PWM on OC3 (PA5)

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)

227

Appendix F The Windows-Based Software Source Code

// 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

228

Appendix F The Windows-Based Software Source Code

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;

229

Appendix F The Windows-Based Software Source Code

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;

230

Appendix F The Windows-Based Software Source Code

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;

231

Appendix F The Windows-Based Software Source Code

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;

232

Appendix F The Windows-Based Software Source Code

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);

233

Appendix F The Windows-Based Software Source Code

vars[42]=(unsigned char)pwmhz; // // // // if 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. (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

234

Appendix F The Windows-Based Software Source Code

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. // Start download procedure

Download1->ShowModal(); }

} //-------------------------------------------------------------------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(

235

Appendix F The Windows-Based Software Source Code

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];

236

Appendix F The Windows-Based Software Source Code

} } //-------------------------------------------------------------------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

237

Appendix F The Windows-Based Software Source Code

// 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 break; case 2: strcpy((char *)Digitaldata4,(char break; case 3: strcpy((char *)Digitaldata3,(char break; case 4: strcpy((char *)Digitaldata2,(char break; case 5: strcpy((char *)Digitaldata1,(char break; case 6: strcat((char *)Digitaldata5,(char strcat((char *)Digitaldata5,(char strcat((char *)Digitaldata5,(char

*)data);

*)data);

*)data);

*)data);

*)data);

*)Digitaldata4); *)Digitaldata3); *)Digitaldata2);

238

Appendix F The Windows-Based Software Source Code

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)

239

Appendix F The Windows-Based Software Source Code

{ 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;

240

Appendix F The Windows-Based Software Source Code

} 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)

241

Appendix F The Windows-Based Software Source Code

// 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; } //--------------------------------------------------------------------

242

Appendix F The Windows-Based Software Source Code

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; }

243

Appendix F The Windows-Based Software Source Code

//-------------------------------------------------------------------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)

244

Appendix F The Windows-Based Software Source Code

{ 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(); } }

245

Appendix F The Windows-Based Software Source Code

//-------------------------------------------------------------------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;

246

Appendix F The Windows-Based Software Source Code

// 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.

247

Appendix F The Windows-Based Software Source Code

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); }

248

Appendix F The Windows-Based Software Source Code

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)

249

Appendix F The Windows-Based Software Source Code

{ 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();

250

Appendix F The Windows-Based Software Source Code

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;

251

Appendix F The Windows-Based Software Source Code

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;

252

Appendix F The Windows-Based Software Source Code

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;

253

Appendix F The Windows-Based Software Source Code

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;

254

Appendix F The Windows-Based Software Source Code

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;

255

Appendix F The Windows-Based Software Source Code

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;

256

Appendix F The Windows-Based Software Source Code

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();

257

Appendix F The Windows-Based Software Source Code

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;

258

Appendix F The Windows-Based Software Source Code

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;

259

Appendix F The Windows-Based Software Source Code

(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);

260

Appendix F The Windows-Based Software Source Code

(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;

261

Appendix F The Windows-Based Software Source Code

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);

262

Appendix F The Windows-Based Software Source Code

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;

263

Appendix F The Windows-Based Software Source Code

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;

264

Appendix F The Windows-Based Software Source Code

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; // // // // if 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. (MultiAnalogNegFeedbackSelect->Checked) { vars[124]=1; //Negative feedback } else { vars[124]=2; //Positive feedback } if (MultiFreqNegFeedbackSelect->Checked)

265

Appendix F The Windows-Based Software Source Code

{ vars[125]=1; } else { vars[125]=2; }

//Negative feedback

//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;

266

Appendix F The Windows-Based Software Source Code

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);

267

Appendix F The Windows-Based Software Source Code

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. // Start download procedure

Download1->ShowModal(); }

} //-------------------------------------------------------------------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 break; case 2: strcpy((char *)Multidata8,(char break; case 3: strcpy((char *)Multidata7,(char break; case 4: strcpy((char *)Multidata6,(char break; case 5: strcpy((char *)Multidata5,(char break; case 6: strcpy((char *)Multidata4,(char break; case 7: strcpy((char *)Multidata3,(char break; case 8: strcpy((char *)Multidata2,(char

*)data);

*)data);

*)data);

*)data);

*)data);

*)data);

*)data);

*)data);

268

Appendix F The Windows-Based Software Source Code

break; case 9: strcpy((char break; case 10: strcat((char strcat((char strcat((char strcat((char strcat((char strcat((char strcat((char strcat((char strcat((char

*)Multidata1,(char *)data);

*)Multidata9,(char *)Multidata9,(char *)Multidata9,(char *)Multidata9,(char *)Multidata9,(char *)Multidata9,(char *)Multidata9,(char *)Multidata9,(char *)Multidata9,(char

*)Multidata8); *)Multidata7); *)Multidata6); *)Multidata5); *)Multidata4); *)Multidata3); *)Multidata2); *)Multidata1); *)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) {

269

Appendix F The Windows-Based Software Source Code

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;

270

Appendix F The Windows-Based Software Source Code

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(); } //------------------------------------------------------------------

271

Appendix F The Windows-Based Software Source Code

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;

272

Appendix F The Windows-Based Software Source Code

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;

273

Appendix F The Windows-Based Software Source Code

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;

274

Appendix F The Windows-Based Software Source Code

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;

275

Appendix F The Windows-Based Software Source Code

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;

276

Appendix F The Windows-Based Software Source Code

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;

277

Appendix F The Windows-Based Software Source Code

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);

278

Appendix F The Windows-Based Software Source Code

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);

279

Appendix F The Windows-Based Software Source Code

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);

280

Appendix F The Windows-Based Software Source Code

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

281

Appendix F The Windows-Based Software Source Code

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;

282

Appendix F The Windows-Based Software Source Code

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; } //--------------------------------------------------------------------

283

Appendix F The Windows-Based Software Source Code

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

284

Appendix F The Windows-Based Software Source Code

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(); } //--------------------------------------------------------------------

285

Appendix F The Windows-Based Software Source Code

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

286

Appendix F The Windows-Based Software Source Code

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(); } //--------------------------------------------------------------------

287

Appendix F The Windows-Based Software Source Code

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

288

Appendix F The Windows-Based Software Source Code

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(); } //--------------------------------------------------------------------

289

Appendix F The Windows-Based Software Source Code

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

290

Appendix F The Windows-Based Software Source Code

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;

291

Appendix F The Windows-Based Software Source Code

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; }

292

Appendix F The Windows-Based Software Source Code

//-------------------------------------------------------------------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); } //--------------------------------------------------------------------

293

Appendix F The Windows-Based Software Source Code

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);

294

Appendix F The Windows-Based Software Source Code

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

295

Appendix F The Windows-Based Software Source Code

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) {

296

Appendix F The Windows-Based Software Source Code

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,

297

Appendix F The Windows-Based Software Source Code

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(); } //--------------------------------------------------------------------

298

Appendix F The Windows-Based Software Source Code

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);

299

Appendix F The Windows-Based Software Source Code

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

300

Appendix F The Windows-Based Software Source Code

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);

301

Appendix F The Windows-Based Software Source Code

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;

302

Appendix F The Windows-Based Software Source Code

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; } //--------------------------------------------------------------------

303

Appendix F The Windows-Based Software Source Code

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);

304

Appendix F The Windows-Based Software Source Code

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

305

Appendix F The Windows-Based Software Source Code

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);

306

Appendix F The Windows-Based Software Source Code

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;

307

Appendix F The Windows-Based Software Source Code

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; } //--------------------------------------------------------------------

308

Appendix F The Windows-Based Software Source Code

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);

309

Appendix F The Windows-Based Software Source Code

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

310

Appendix F The Windows-Based Software Source Code

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;

311

Appendix F The Windows-Based Software Source Code

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); }

312

Appendix F The Windows-Based Software Source Code

// 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)

313

Appendix F The Windows-Based Software Source Code

{ // 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(); } //--------------------------------------------------------------------

314

Appendix F The Windows-Based Software Source Code

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

315

Appendix F The Windows-Based Software Source Code

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); } //--------------------------------------------------------------------

316

Appendix F The Windows-Based Software Source Code

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

317

Appendix F The Windows-Based Software Source Code

318

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 Start11.c Non_bank.sgm Lustart.h Testio.c Testio.prm Digital.c Digital.prm Multi.c Multi.prm Header file for the 68HC11 register definitions Default startup code for the 68HC11 HC11 Small and medium memory model Header file which defines the startup description Source code for the Test I/O module Linker parameter file for the Test I/O module Source code for the SISO Digial Controller Module Linker parameter file for the SISO Digial Controller Module Source code for the MIMO Digial Controller Module Linker parameter file for the MIMO Digial Controller Module

319

Appendix G The Microcontroller Software Source Code

Hc11e9.h - Header file for the 68HC11 register definitions.


#ifndef HC11e9 #define HC11e9 #define Register typedef struct { unsigned int unsigned int unsigned int unsigned int unsigned int unsigned int unsigned int unsigned int } RegisterBits; unsigned char

bit0 bit1 bit2 bit3 bit4 bit5 bit6 bit7

: : : : : : : :

1; 1; 1; 1; 1; 1; 1; 1;

unsigned int Register_Set=0x1000; #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define LCD1 PORTA PIOC PORTC PORTB PORTCL DDRC PORTD DDRD PORTE CFORC OC1M OC1D TCNT TCNTUP TIC1 TIC2 TIC3 TIC3UP TOC1 TOC1UP TOC2 TOC2UP TOC3 TOC3UP TOC4 TOC4UP TOC5 TOC5UP TCTL1 TCTL2 TMSK1 (*(volatile Register*)(0x0000)) (*(volatile Register*)(Register_Set + 0x00)) (*(Register*)(Register_Set + 0x02)) (*(volatile Register*)(Register_Set + 0x03)) (*(volatile Register*)(Register_Set + 0x04)) (*(volatile Register*)(Register_Set + 0x05)) (*(Register*)(Register_Set + 0x07)) (*(volatile Register*)(Register_Set + 0x08)) (*(Register*)(Register_Set + 0x09)) (*(volatile Register*)(Register_Set + 0x0A)) (*(Register*)(Register_Set + 0x0B)) (*(volatile RegisterBits*)(Register_Set + 0x0C)) (*(volatile RegisterBits*)(Register_Set + 0x0D)) (*(volatile unsigned int *)(Register_Set + 0x0E)) (*(volatile unsigned char *)(Register_Set + 0x0E)) (*(volatile unsigned int *)(Register_Set + 0x10)) (*(volatile unsigned int *)(Register_Set + 0x12)) (*(volatile unsigned int *)(Register_Set + 0x14)) (*(volatile unsigned char *)(Register_Set + 0x14)) (*(volatile unsigned int *)(Register_Set + 0x16)) (*(volatile unsigned char *)(Register_Set + 0x16)) (*(volatile unsigned int *)(Register_Set + 0x18)) (*(volatile unsigned char *)(Register_Set + 0x18)) (*(volatile unsigned int *)(Register_Set + 0x1A)) (*(volatile unsigned char *)(Register_Set + 0x1A)) (*(volatile unsigned int *)(Register_Set + 0x1C)) (*(volatile unsigned char *)(Register_Set + 0x1C)) (*(volatile unsigned int *)(Register_Set + 0x1E)) (*(volatile unsigned char *)(Register_Set + 0x1E)) (*(RegisterBits*)(Register_Set + 0x20)) (*(Register*)(Register_Set + 0x21)) (*(volatile RegisterBits*)(Register_Set + 0x22))

320

Appendix G The Microcontroller Software Source Code

#define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define

TFLG1 (*(volatile RegisterBits*)(Register_Set + 0x23)) TFLG1BYTE (*(volatile Register*)(Register_Set + 0x23)) TMSK2 (*(volatile RegisterBits*)(Register_Set + 0x24)) TFLG2 (*(volatile RegisterBits*)(Register_Set + 0x25)) TFLG2BYTE (*(volatile Register*)(Register_Set + 0x25)) PACTL (*(RegisterBits*)(Register_Set + 0x26)) PACNT (*(volatile Register*)(Register_Set + 0x27)) SPCR (*(Register*)(Register_Set + 0x28)) SPSR (*(volatile Register*)(Register_Set + 0x29)) SPDR (*(volatile Register*)(Register_Set + 0x2A)) BAUD (*(Register*)(Register_Set + 0x2B)) SCCR1 (*(volatile Register*)(Register_Set + 0x2C)) SCCR2 (*(Register*)(Register_Set + 0x2D)) SCSR (*(volatile Register*)(Register_Set + 0x2E)) SCDR (*(volatile unsigned char*)(Register_Set + 0x2F)) ADCTL (*(volatile Register*)(Register_Set + 0x30)) ADR1 (*(volatile unsigned char*)(Register_Set + 0x31)) ADR2 (*(volatile unsigned char*)(Register_Set + 0x32)) ADR3 (*(volatile unsigned char*)(Register_Set + 0x33)) ADR4 (*(volatile unsigned char*)(Register_Set + 0x34)) BPROT (*(Register*)(Register_Set + 0x35)) OPTION (*(Register*)(Register_Set + 0x39)) COPRSR (*(Register*)(Register_Set + 0x3A)) PPROG (*(Register*)(Register_Set + 0x3B)) HPRIO (*(RegisterBits*)(Register_Set + 0x3C)) INIT (*(Register*)(Register_Set + 0x3D)) TEST1 (*(Register*)(Register_Set + 0x3E)) CONFIG (*(Register*)(Register_Set + 0x3F))

/* CFORC bit definitions 0x0B */ #define #define #define #define #define FOC1 FOC2 FOC3 FOC4 FOC5 bit7 bit6 bit5 bit4 bit3

/* OC1M bit definitions 0x0C */ #define #define #define #define #define OC1M7 OC1M6 OC1M5 OC1M4 OC1M3 bit7 bit6 bit5 bit4 bit3

/* OC1D bit definitions 0x0D */ #define #define #define #define #define OC1D7 OC1D6 OC1D5 OC1D4 OC1D3 bit7 bit6 bit5 bit4 bit3

/* TCTL1 bit definition 0x20 */

321

Appendix G The Microcontroller Software Source Code

#define #define #define #define #define #define #define #define

OM2 OL2 OM3 OL3 OM4 OL4 OM5 OL5

bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0

/* TCTL2 bit definitions 0x21 */ #define #define #define #define #define #define #define #define EDG4B EDG4A EDG1B EDG1A EDG2B EDG2A EDG3B EDG3A bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0

/* TMSK1 bit definitions 0x22 */ #define #define #define #define #define #define #define #define OC1I OC2I OC3I OC4I I4O5I IC1I IC2I IC3I bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0

/* TFLG1 bit definitions 0x23 */ #define #define #define #define #define #define #define #define OC1F OC2F OC3F OC4F I4O5F IC1F IC2F IC3F 0x80 0x40 0x20 0x10 0x08 0x04 0x02 0x01

/* TMSK2 bit definitions 0x24 */ #define #define #define #define #define #define TOI RTII PAOVI PAII PR1 PR0 bit7 bit6 bit5 bit4 bit1 bit0

/* TFLG2 bit definitions 0x25 */

322

Appendix G The Microcontroller Software Source Code

#define #define #define #define

TOF RTIF PAOVF PAIF

0x80 0x40 0x20 0x10

/* PACTL bit definitions 0x26 */ #define #define #define #define #define #define #define #define DDRA7 PAEN PAMOD PEDGE DDRA3 I4O5 RTR1 RTR0 bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0

/* SPCR bit definitions 0x28 */ #define #define #define #define #define #define #define #define SPIE SPE DWOM MSTR CPOL CPHA SPR1 SPR0 bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0

/* SPSR bit definitions 0x29 */ #define SPIF #define WCOL #define MODF bit7 bit6 bit4

/* BAUD bit definitions 0x2B */ #define #define #define #define #define #define #define TCLR SCP1 SCP0 RCKB SCR2 SCR1 SCR0 bit7 bit5 bit4 bit3 bit2 bit1 bit0

/* SCCR1 bit definition 0x2C */ #define #define #define #define R8 T8 M WAKE bit7 bit6 bit4 bit3

/* SCCR2 bit definitions 0x2D */ #define TIE #define TCIE bit7 bit6

323

Appendix G The Microcontroller Software Source Code

#define #define #define #define #define #define /* SCSR #define #define #define #define #define #define #define

RIE ILIE TE RE RWU SBK

bit5 bit4 bit3 bit2 bit1 bit0

bit definitions 0x2E */ TDRE TC RDRF IDLE OR NF FE bit7 bit6 bit5 bit4 bit3 bit2 bit1

/* SCDR bit definitions 0x2F */ #define #define #define #define #define #define #define #define R7T7 R6T6 R5T5 R4T4 R3T3 R2T2 R1T1 R0T0 bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0

/* ADCTL bit definitions 0x30 */ #define #define #define #define #define #define #define CCF SCAN MULT CD CC CB CA bit7 bit5 bit4 bit3 bit2 bit1 bit0

/* BPROT bit definitions 0x35 */ #define #define #define #define #define PTCON BPRT3 BPRT2 BPRT1 BPRT0 bit4 bit3 bit2 bit1 bit0

/* OPTION bit definitions 0x39 */ #define #define #define #define #define #define ADPU CSEL IRQE DLY CME CR1 bit7 bit6 bit5 bit4 bit3 bit1

324

Appendix G The Microcontroller Software Source Code

#define CR0

bit0

/* PPROG bit definitions 0x3B */ #define #define #define #define #define #define #define #define ODD EVEN ELAT BYTE ROW ERASE EELAT EEPGM bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0

/* HPRIO bit definitions 0x3C */ #define #define #define #define #define #define #define #define /* INIT #define #define #define #define #define #define #define #define RBOOT SMOD MDA IRV PSEL3 PSEL2 PSEL1 PSEL0 bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0

bit definitions 0x3D */ RAM3 RAM2 RAM1 RAM0 REG3 REG2 REG1 REG0 bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0

/* TEST1 bit definitions 0x3E */ #define #define #define #define #define #define #define TILOP OCCR CBYP DISR FCM FCOP TCON bit7 bit5 bit4 bit3 bit2 bit1 bit0

/* CONFIG bit definitions 0x3F */ #define #define #define #define NOSEC NOCOP ROMON EEON bit3 bit2 bit1 bit0

/* PORTA bit definitions 0x00 */

325

Appendix G The Microcontroller Software Source Code

#define #define #define #define #define #define #define #define

PA7 PA6 PA5 PA4 PA3 PA2 PA1 PA0

bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0

/* PORTC bit definitions 0x03 */ #define #define #define #define #define #define #define #define PC7 PC6 PC5 PC4 PC3 PC2 PC1 PC0 bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0

/* PORTB bit definitions 0x04 */ #define #define #define #define #define #define #define #define PB7 PB6 PB5 PB4 PB3 PB2 PB1 PB0 bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0

/* PORTCL bit definitions 0x05 */ #define #define #define #define #define #define #define #define PCL7 PCL6 PCL5 PCL4 PCL3 PCL2 PCL1 PCL0 bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0

/* DDRC bit definitions 0x07 */ #define #define #define #define #define #define #define #define DDC7 DDC6 DDC5 DDC4 DDC3 DDC2 DDC1 DDC0 bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0

/* PORTD bit definitions 0x08 */

326

Appendix G The Microcontroller Software Source Code

#define #define #define #define #define #define

PD5 PD4 PD3 PD2 PD1 PD0

bit5 bit4 bit3 bit2 bit1 bit0

/* DDRD bit definitions 0x09 */ #define #define #define #define #define #define DDD5 DDD4 DDD3 DDD2 DDD1 DDD0 bit5 bit4 bit3 bit2 bit1 bit0

/* PORTE bit definitions 0x0A */ #define #define #define #define #define #define #define #define PE7 PE6 PE5 PE4 PE3 PE2 PE1 PE0 bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0 to permit interrupt service routine

/* Macros and function programming from C */ #define #define #define #define #define #define #define #define #define typedef typedef #endif

vector(isr,vector_address) (*(void**)(vector_address)=(isr)) cli() _asm("cli\n") sei() _asm("sei\n") return_int() _asm("rti\n)" ldaa50 asm {ldaa #50} staa asm {staa 0x0000} TRUE 1 FALSE 0 FOREVER while(TRUE) unsigned int WORD; unsigned char BYTE;

327

Appendix G The Microcontroller Software Source Code

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; and initialized by the linker */ /* read-only: _startupData is allocated in ROM

#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 LDY BEQ NextZeroOut: PSHX LDD LDX NextWord: CLR INX ADDD _startupData.pZeroOut ; *pZeroOut _startupData.nofZeroOuts ; nofZeroOuts CopyDown ; if nothing to zero out ; save *pZeroOut 2,X ; byte count 0,X ; start address 0,X ; clear memory byte ; inc address #-1 ; dec byte count

328

Appendix G The Microcontroller Software Source Code

BNE PULX INX INX INX INX DEY BNE CopyDown: LDX copy down desc. NextBlock: LDD BEQ INX INX LDY Y INX INX Copy: PSHB LDAB and STAB area PULB INX INY ADDD BNE BRA FuncInits: } } static long tmp; #pragma NO_FRAME

NextWord

; ; restore *pZeroOut ; advance *pZeroOut

NextZeroOut

; dec nofZeroOuts ;

_startupData.toCopyDownBeg:2 ; load address of 0,X FuncInits ; size of init-data -> D ; end of copy down desc.

0,X

; destination address ->

0,X 0,Y

; load a word from ROM ; store it in the data

; increment addresses #-1 Copy NextBlock ; decrement word counter

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: procedure */ asm{ #ifdef __BANKED__ JSR InitBank initialize the program; call the root-

329

Appendix G The Microcontroller Software Source Code

#endif LDD BNE LDX TXS Initialize: JSR _startupData.flags Initialize _startupData.stackOffset:2 ; if flags then ; init stack pointer ; stack pointer

Init

CallMain: } #ifdef __BANKED__ { tmp = (long)_startupData.main; *(int *)&tmp |= 0x8000; (*(void (*) (void)) tmp) (); } #else (* _startupData.main) (); #endif } /* end loop forever */ }

330

Appendix G The Microcontroller Software Source Code

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

331

Appendix G The Microcontroller Software Source Code

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 } _Range;

*beg; int size;

/* [beg..beg+size] */

typedef void (*_PFunc)(void);

extern struct _tagStartup{ unsigned flags; _PFunc main; unsigned dataPage; */ long stackOffset; int nofZeroOuts; _Range *pZeroOut; with nofZeroOuts elements */ long toCopyDownBeg; begins */ _PFunc *mInits; pointers, terminated by 0 */ _PFunc *libInits; pointers, terminated by 0 */ } _startupData; extern void _Startup(void); */

/* top procedure of user program */ /* page where data allocation begins

/* pZeroOut is a vector of ranges /* rom-address where copydown-data /* mInits is a vector of function /* libInits is a vector of function

/* execution begins in this procedure

332

Appendix G The Microcontroller Software Source Code

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

333

Appendix G The Microcontroller Software Source Code

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)

334

Appendix G The Microcontroller Software Source Code

{ 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;

335

Appendix G The Microcontroller Software Source Code

asm cli; break; case 1: case 4: input=adc(); break; }

/* enable interrupts */ /* Analog input */

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;

336

Appendix G The Microcontroller Software Source Code

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 { PSHA LDAA #0x01 STAA 0x1023 PULA } /* Reset input flag IC3F by writing 1 to it */

if (TFLG2BYTE>=0x80 && TIC3UP<=0x80) { timeroverflows++; asm { /*Reset TOF Flag*/ PSHA LDAA #0x80

337

Appendix G The Microcontroller Software Source Code

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; TMSK1.OC3I=1; /*couple OC1 to PA7*/ /*enable the OC3 interrupt*/

338

Appendix G The Microcontroller Software Source Code

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 *) pwmhz=*(unsigned char *) 0x0003; pwmperiod=2000000/pwmhz; outputlowerlimit=*(unsigned char outputupperlimit=*(unsigned char inoutcombination=*(unsigned char }

0x0002;

*) 0x0004; *) 0x0005; *) 0x0006;

/************************************************/ /* Routine to initialize the microcontroller to */ /* send and receive serial data */ /************************************************/

339

Appendix G The Microcontroller Software Source Code

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 { PSHA LDAA #0x80 STAA 0x1025 PULA }

/*Reset TOF Flag*/

/* 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 */

340

Appendix G The Microcontroller Software Source Code

*(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; }

341

Appendix G The Microcontroller Software Source Code

Testio.prm
LINK testio.abs NAMES END

Linker parameter file for the testio module.

testio.o start11.o ansi.lib

SECTIONS MY_RAM = READ_WRITE 0x4000 TO 0x4FFF; MY_ROM = READ_ONLY 0x2000 TO 0x3FFF; PLACEMENT DEFAULT_ROM DEFAULT_RAM END STACKSIZE 0x600

INTO INTO

MY_ROM; MY_RAM;

342

Appendix G The Microcontroller Software Source Code

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;

343

Appendix G The Microcontroller Software Source Code

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;

344

Appendix G The Microcontroller Software Source Code

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 */

345

Appendix G The Microcontroller Software Source Code

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 */ */ */ */ */ */

346

Appendix G The Microcontroller Software Source Code

/* 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; } /*end while(1) loop*/ } /* Reset sampletimeroverflows */

/************************************************************/ /* 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;

347

Appendix G The Microcontroller Software Source Code

(unsigned (unsigned (unsigned (unsigned (unsigned (unsigned (unsigned (unsigned

char char char char char char char char

*) *) *) *) *) *) *) *)

0x0029; 0x002A; 0x002B; 0x002C; 0x002D; 0x002E; 0x002F; 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 */ /***************************************************/

348

Appendix G The Microcontroller Software Source Code

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 { PSHA LDAA #0x01 STAA 0x1023 PULA } /* Reset input flag IC3F by writing 1 to it */

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 */

349

Appendix G The Microcontroller Software Source Code

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; TMSK1.OC3I=1; OC1D.OC1D5=1; TCTL1.OL3=1; TOC1=TCNT+50000; TOC3=TOC1+1; } /* /* /* /* /* /* couple OC1 to OC3 */ enable the OC3 interrupt */ turn on OC3 when OC3 occurs */ toggle OC3 when OC3 occurs */ initialize OC1 */ 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 }

350

Appendix G The Microcontroller Software Source Code

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 { PSHA LDAA #0x01 STAA 0x1023 PULA } /* Reset input flag IC3F by writing 1 to it */

/* 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) {

351

Appendix G The Microcontroller Software Source Code

TMSK2.bit7=1; asm { PSHA LDAA #0x80 STAA 0x1025 PULA }

/* Enable the timer overflow interrupt */

/*Reset TOF Flag*/

/* 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 */ /****************************************/

352

Appendix G The Microcontroller Software Source Code

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; }

353

Appendix G The Microcontroller Software Source Code

Digital.prm - Linker parameter file for the SISO Digial Controller Module
LINK Digital.abs NAMES END Digital.o start11.o ansi.lib

SECTIONS MY_RAM = READ_WRITE 0x4000 TO 0x4FFF; MY_ROM = READ_ONLY 0x2000 TO 0x3FFF; PLACEMENT DEFAULT_ROM DEFAULT_RAM END STACKSIZE 0x600

INTO INTO

MY_ROM; MY_RAM;

354

Appendix G The Microcontroller Software Source Code

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;

355

Appendix G The Microcontroller Software Source Code

unsigned unsigned unsigned unsigned unsigned unsigned unsigned unsigned unsigned unsigned unsigned unsigned float float float float float float float float float float float float float float float float float float float float float float float float float float float float float float

char input1; int input2; int output1; int output2; int freqinputupperlimit; int freqinputlowerlimit; int analoginputupperlimit; int analoginputlowerlimit; int _8bitoutputupperlimit; int _8bitoutputlowerlimit; int PWMoutputupperlimit; int PWMoutputlowerlimit;

p10; p11; p12; p13; p14; p20; p21; p22; p23; p24; q10; q11; q12; q13; q14; q20; q21; q22; q23; q24; r10; r11; r12; r13; r14; r20; r21; r22; r23; 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;

356

Appendix G The Microcontroller Software Source Code

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 */

357

Appendix G The Microcontroller Software Source Code

input1=adc(); asm SEI; /* disable interrupts */ input2=7813/period; asm CLI; /* enable interrupts */ if if if if (input1<analoginputlowerlimit) input1=analoginputlowerlimit; (input1>analoginputupperlimit) input1=analoginputupperlimit; (input2<freqinputlowerlimit) input2=freqinputlowerlimit; (input2>freqinputupperlimit) input2=freqinputupperlimit;

if (analoginputfeedbackmode==1) { e1=analogsetpoint-input1; } else { e1=analogsetpoint+input1; } if (freqinputfeedbackmode==1) { e2=freqsetpoint-input2; } else { e2=freqsetpoint+input2; }

/* analog negative feedback */

/* analog positive feedback */

/* frequency negative feedback */

/* 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;

358

Appendix G The Microcontroller Software Source Code

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; } /*end while(1) loop*/ } /* Reset sampletimeroverflows */

359

Appendix G The Microcontroller Software Source Code

/************************************************************/ /* 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) */ /************************************************************/

360

Appendix G The Microcontroller Software Source Code

void getparameters(void) { unsigned char pwmhz; (unsigned (unsigned (float *) (float *) (float *) (float *) (float *) (float *) (float *) (float *) (float *) (float *) (float *) (float *) (float *) (float *) (float *) (float *) (float *) (float *) (float *) (float *) (float *) (float *) (float *) (float *) (float *) (float *) (float *) (float *) (float *) (float *) (unsigned (unsigned (unsigned (unsigned (unsigned (unsigned (unsigned (unsigned (unsigned (unsigned (unsigned (unsigned char *) char *) 0x0102; 0x0106; 0x010A; 0x010E; 0x0112; 0x0116; 0x011A; 0x011E; 0x0122; 0x0126; 0x012A; 0x012E; 0x0132; 0x0136; 0x013A; 0x013E; 0x0142; 0x0146; 0x014A; 0x014E; 0x0152; 0x0156; 0x015A; 0x015E; 0x0162; 0x0166; 0x016A; 0x016E; 0x0172; 0x0176; char *) char *) char *) char *) char *) char *) char *) char *) char *) char *) char *) char *) 0x0100; 0x0101;

0x017A; 0x017B; 0x017C; 0x017D; 0x017E; 0x017F; 0x0180; 0x0181; 0x0182; 0x0183; 0x0184; 0x0185;

analogsetpoint= *(unsigned char *) 0x0100; freqsetpoint=*(unsigned char *) 0x0101; p10=*(float *) 0x0102; p11=*(float *) 0x0106; p12=*(float *) 0x010A;

361

Appendix G The Microcontroller Software Source Code

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

*/ */

*/ */

362

Appendix G The Microcontroller Software Source Code

STAA 0x1025 PULA RTI } }

/* Reset the timer overflow flag (TOF) */ /* Retrieve the saved contents of accumulator A */ /* 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 { PSHA LDAA #0x01 STAA 0x1023 PULA } /* Reset input flag IC3F by writing 1 to it */ /* /* /* /* Save the contents of accumulator A Load accumulator A with the mask data Reset TOF flag by writing 1 to it Retrieve the saved contents of accumulator A */ */ */ */

if (TFLG2BYTE>=0x80 { timeroverflows++; asm { PSHA /* LDAA #0x80 /* STAA 0x1025 /* PULA /* } }

&& TIC3UP<=0x80)

Save the contents of accumulator A Load accumulator A with the mask data Reset IC3F flag by writing 1 to it 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 */

363

Appendix G The Microcontroller Software Source Code

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; TMSK1.OC3I=1; OC1D.OC1D5=1; TCTL1.OL3=1; TOC1=TCNT+50000; TOC3=TOC1+1; } /* /* /* /* /* /* couple OC1 to OC3 */ enable the OC3 interrupt */ turn on OC3 when OC1 occurs */ toggle OC3 when OC3 occurs */ initialize OC1 */ initialize OC3 */

/*****************************************************/ /* OC3 Interrupt Service Routine. This routine will */ /* generate a PWM signal on OC3 (PA5) */ /*****************************************************/ void oc3interrupt(void) {

364

Appendix G The Microcontroller Software Source Code

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 LDAA #0x01 STAA 0x1023 PULA }

/* /* /* /*

Save the contents of accumulator A Load accumulator A with the mask data Reset input flag IC3F by writing 1 to it 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; }

365

Appendix G The Microcontroller Software Source Code

/*******************************************************/ /* Routine to initialize the timer overflow interrupt */ /*******************************************************/ void inittimerinterrupt(void) { TMSK2.bit7=1; /* Enable the timer overflow interrupt */ asm { PSHA LDAA #0x80 STAA 0x1025 PULA }

/* /* /* /*

Save the contents of accumulator A Load accumulator A with the mask data Reset TOF Flag by writing 1 to it 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) {

366

Appendix G The Microcontroller Software Source Code

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; }

367

Appendix G The Microcontroller Software Source Code

Multi.prm - Linker parameter file for the MIMO Digial Controller Module
LINK Multi.abs NAMES END Multi.o start11.o ansi.lib

SECTIONS MY_RAM = READ_WRITE 0x4000 TO 0x4FFF; MY_ROM = READ_ONLY 0x2000 TO 0x3FFF; PLACEMENT DEFAULT_ROM DEFAULT_RAM END STACKSIZE 0x9FF

INTO INTO

MY_ROM; MY_RAM;

368

Vous aimerez peut-être aussi