You are on page 1of 470

Programming

MicrocontrollersinC
Second Edition
Ted Van Sickle
A Volume in the EMBEDDED TECHNOLOGY
TM
Series
Eagle Rock, Virginia
www.LLH-Publishing.com
Programming Microcontrollers in C 2001 by LLH Technology Publishing.
All rights reserved. No part of this book may be reproduced, in any form or means
whatsoever, without written permission from the publisher. While every precaution has
been taken in the preparation of this book, the publisher and author assume no
responsibility for errors or omissions. Neither is any liability assumed for damages
resulting from the use of the information contained herein.
ISBN:1-878707-57-4
LibraryofCongressControlNumber:00-134094
Printed in the United States of America
10 9 8 7 6 5 4 3 2 1
Project management and developmental editing:
Carol S. Lewis, LLH Technology Publishing
Interior design and production services:
Kelly Johnson, El Cajon, California
Cover design: Brian McMurdo, Valley Center, California
Visit us on the web: www.LLH-Publishing.com
1 Introduction to C ............................................................... 1
Some Simple Programs ...................................................................... 1
Names................................................................................................. 8
Types and Type Declarations ............................................................. 9
Storage Classes, Linkage, and Scope ................................................ 12
Character Constants ........................................................................... 15
Arrays.................................................................................................. 18
Other types.......................................................................................... 20
Operators and Expressions................................................................. 24
Increment and Decrement Operators.................................................. 30
Precedence and Associativity ............................................................. 34
Program Flow and Control .................................................................. 36
Functions............................................................................................. 51
Recursion ............................................................................................ 61
Summary............................................................................................. 63
2 Advanced C Topics ........................................................... 65
Pointers............................................................................................... 65
Multidimensional Arrays ...................................................................... 80
Structures ............................................................................................ 87
More Structures................................................................................... 107
Input and Output ................................................................................. 110
Memory Management ......................................................................... 114
Miscellaneous Functions ..................................................................... 116
Summary............................................................................................. 121
3 What Are Microcontrollers? ............................................. 123
Microcontroller Memory....................................................................... 127
Input/ Output ....................................................................................... 129
Programming Microcontrollers ............................................................ 134
Coding Tips for Microcontrollers ......................................................... 137
4 Small 8- Bit Systems......................................................... 149
Microcontroller Memory....................................................................... 153
Timers ................................................................................................. 166
Analog- to- Digital Converter Operation .............................................. 195
Pulse Width Modulator System........................................................... 201
Other Program Items........................................................................... 207
Summary............................................................................................. 209
5 Programming Large 8- Bit Systems ................................ 211
Header File.......................................................................................... 211
Sorting Programs ................................................................................ 230
Data Compression .............................................................................. 237
Timer Operations ................................................................................ 245
Summary............................................................................................. 285
6 Large Microcontrollers ..................................................... 287
The MC68HC16 .................................................................................. 288
System Integration Module ( SIM) ....................................................... 296
A Pulse Width Modulation Program .................................................... 299
Cosmic MC68HC16 Compiler ............................................................. 305
Table Look- Up.................................................................................... 319
Digital Signal Processor Operations ................................................... 326
Other MC68HC16 Considerations ...................................................... 345
7 Advanced Topics in Programming Embedded
Systems ( M68HC12) ............................................................ 347
Numeric Encoding............................................................................... 352
Numeric Decoding............................................................................... 354
Coding the alpha data ......................................................................... 356
The Monitor Program .......................................................................... 370
The SAVEIT() Routine ........................................................................ 376
The printout() and the printafter() Functions ....................................... 378
Reset ................................................................................................... 381
Input/ Output Functions....................................................................... 382
Putting It All Together.......................................................................... 386
Summary............................................................................................. 391
8 MCORE, a RISC Machine .................................................. 393
Delay Routine...................................................................................... 395
Delays Revisited ................................................................................. 401
Serial Input/ Output ............................................................................. 404
Handling Interrupts .............................................................................. 413
A Clock Program................................................................................. 419
Keyboard............................................................................................. 432
Integrating Keyboard and Clock.......................................................... 440
Adding a Display ................................................................................. 442
Summary............................................................................................. 446
Index ...................................................................................... 447
IntroductiontoSecondEdition
Today, even more than when the first edition of this book was written,
the use of microcontrollers has expanded to an almost unbelievable level.
A typical car has 15 microcontrollers. A modern home can have more than
50 microcontrollers controlling everything from the thermostat, to the
furnace, to the microwave. Microcontrollers are everywhere! In the mean-
time, many new chips have been placed on the market as well.
Also, there have been significant modifications to our programming
languages. The standard C language is now called C99 rather than C89.
There have been several changes in the language, but most of these
changes will not be available to us for some time. Many of the modifica-
tions to the language will be of little use to programs for embedded
systems. For example, complex arithmetic has been added to the lan-
guage. It is rare that we use even floating-point arithmetic, and I have
never seen an application for an embedded system where complex arith-
metic was needed. However, other additions allow improved optimization
processes, such as the restrict keyword and the static keyword used to
modify the index of an array. Other changes have less impact on the
generation of code, such as the // opening to a single line comment. Also,
today you will have no implicit int return from a function. All in all,
expect the new versions of C compilers to be significant improvements
over the older versions. Also, expect that the new compilers will not break
older code. The features of the new standard should begin showing up in
any new version of the compilers that you use.
The C++ standard committee has completed its work on the first
language standard for C++. There is much clamor about the use of C++ for
embedded systems. C++ as it stands is an excellent language, but it is
aimed primarily at large system programs, not the small programs that we
will be developing into the future. C still remains the grand champion at
giving us embedded programmers the detailed control over the computer
that we need and that other computer languages seem to overlook.
The first six chapters of the book have been revised and any errors that
were found were corrected. Every chapter has been altered, but not so
much that you would not recognize it. Chapter 7 has been added. In that
chapter, a relatively complex program is developed to run on the
M68HC912B32. The development system was based on this chip and it
had no significant RAM to hold the code during development. Therefore,
all of the code was completely designed, coded, and tested on a DOS-
vii
viii Introduction to Second Edition
based system. Extensive tests were completed to make certain that there
were no hidden bugs. The modules were small and easy to test. Each
module was tested with a program written to exercise all parts of the
module. When the several modules were integrated into a single program,
the program worked in the DOS-based system. All changes needed to
convert this program were implemented under the control of conditional
compiler commands. When the program was converted to the M68HC12
version and compiled, it loaded correctly and ran.
Chapter 8 introduces a new chip for Motorola, the MMC2001. This
chip is a RISC chip. Many of the good things to be said of RISC
configurations are absolutely true. This chip is very fast. Each of its
instructions requires only one word, 32 bits, of memory. Almost all
instructions execute in a single clock cycle. The chip that I used here ran at
32 mHz, and you could not feel any temperature rise on the chip. It is from
a great family of chips that should become a future standard.
The first edition of this book had several appendices. These were
needed to show general background material that the reader should not be
expected to know. Also, quite a few specialized header files used to
interconnect the program to the peripheral components on the
microcontroller were included. Also, with the first edition, there was a
card with which the reader could order two diskettes that contained all of
the source code in the book, demonstration compilers that would compile
the source code, and other useful information. All of these things have
been included on the CD-ROM that comes with this edition. Additionally,
you will find PDF versions of all appropriate Motorola data manuals and
reference manuals for all of the chips discussed in the book. Also included
are copies of all header files used with the programs, and some more that
will probably be useful to you.
IntroductiontoFirstEdition
Early detractors of the C language often said that C was little more
than an over-grown assembler. Those early disparaging remarks were to
some extent true and also prophetic. C is indeed a high level language and
retains much of the contact with the underlying computer hardware that is
usually lost with a high level language. It is this computer relevance that
makes people say that C is a transform of an assembler, but this computer
relevance also makes C the ideal high level language vehicle to deal with
microcontrollers. With C we have all of the advantages of an easily
understood language, a widely standardized language, a language where
programmers are readily available, a language where any trained program-
mer can understand the work of another, and a language that is very
productive.
The main purpose of this book is to explore the use of C as a
programming tool for microcontrollers. We assume that you are familiar
with the basic concepts of programming. A background in C is not
necessary, but some experience with a programming language is required.
I have been teaching C programming for microcontrollers for several
years, and have found that my students are usually excellent programmers
with many years of experience programming microcontrollers in assembly
language. Most have little need or interest in learning a new language. I
have never had a class yet where I was able to jump into programming
microcontrollers without providing substantial background in the C lan-
guage. In many instances, students believe that a high-level language like
C and microcontrollers are incompatible. This forces me, unfortunately, to
turn part of my class into a sales presentation to convince some students
that microcontrollers and C have a future together. I am usually able to
show that the benefits gained from using C far outweigh the costs attrib-
uted to its use. The first two chapters are included for those who are
unfamiliar with C. If you are already familiar with C, feel free to skip
ahead to Chapter 3.
C is a very powerful high level language that allows the programmer
access to the inner workings of the computer. Access to computer details,
memory maps, register bits, and so forth, are not usually available with
high level languages. These features are hidden deliberately from the
programmer to make the languages universal and portable between ma-
chines. The authors of C decided that it is desirable to have access to the
heart of the machine because it was intended to use C to write operating
systems. An operating system must be master of all aspects of the machine
ix
x Introduction to First Edition
it is controlling. Therefore, no aspect of the machine could be hidden from
the programmer. Features like bit manipulation, bit field manipulation,
direct memory addressing, and the ability to manipulate function ad-
dresses as pointers have been included in C. All of these features are used
in programming microcontrollers. In fact, C is probably the only popular
high level language that can be conveniently used for a microcontroller.
Every effort has been made to present the C aspects of programming
these machines clearly. Example programs and listings along with their
compiled results are presented whenever needed. If there are problems
hidden in the C code, these problems are explored and alternate methods
of writing the code are shown. General rules that will result in more
compact code or quicker execution of the code are developed. Example
programs that demonstrate the basis for these rules will be shown.
C is a rich and powerful language. Beyond the normal high level
language capability, C makes extensive use of pointers and address indi-
rection that is usually available only with assembly language. C also
provides you with a complete set of bit operations, including bit manipula-
tions and bit fields in addition to logical bit operations. In C, the program-
mer knows much about the memory map which is often under program-
mer control. A C programmer can readily write a byte to a control register
of a peripheral component to the computer. These assembly language-like
features of the C language serve to make C the high level language of
choice for the microcontroller programmer.
As a language, C has suffered many well-intended upgrades and
changes. It was written early in the 1970s by Dennis Ritchie of Bell
Laboratories. As originally written, C was a free wheeling language
with few constraints on the programmer. It was assumed that any pro-
grammer using the language would be competent, so there was little need
for the controls and hand-holding done by popular compilers of the day.
Therefore, C was a typed language but it was not strongly typed. All
function returns were assumed to be integer unless otherwise specified.
Function arguments were typed, but these types were never checked for
validity when the functions were called. The programmer could specify an
integer argument and then pass a floating point number as the argument.
These kinds of errors are made easily by the best programmer, and they
are usually very difficult to find when debugging the program.
Another set of problems with the language was the library functions
that always accompanied a compiler. No standard library was specified. C
does not have built-in input/output capability. Therefore, the basic C
standard contained the specifications for a set of functions needed to
provide sensible input/output to the language. A few other features such as
a math library, a string handling library, and so forth started out with the
xi Introduction to First Edition
language. But these and other features were included along with other
enhancements in a helter-skelter manner in different compilers as new
compiler versions were created.
In 1983, an ANSI Committee (The X3J11 ANSI C Standards Com-
mittee) was convened to standardize the C language. The key results of the
work of this committee has been to create a strongly typed language with a
clear standard library. One of the constraints that the ANSI committee
placed upon itself was that the existing base of C code must compile error
free with an ANSI C compiler. Therefore, all of the ANSI dictated typing
requirements are optional under an ANSI C compiler. In this text, it is
always assumed that an ANSI compliant compiler will be used, and the
ANSI C form will be used throughout.
C compilers for microcontrollersespecially the small devices
must compromise some of the features of a compiler for a large computer.
The small machines have limited resources that are required to implement
some of the code generated by a compiler for a large computer. When the
computer is large, the compiler writer need not worry about such problems
as limited stack space or a small register set. But when the computer is
small, these limitations will often force the compiler writer to take extraor-
dinary steps just to be able to have a compiler. In this book, we will
discuss the C programming language, not an abbreviated version that you
might expect to use with some of the smaller microcontrollers. In the
range of all microcontrollers, you will find components with limited
register sets, memory, and other computer necessary peripherals. You will
also find computers with many megabytes of memory space, and all of the
other important computer features usually found only on a large computer.
Therefore, we will discuss the language C for the large computer, and
when language features must be abbreviated because of computer limita-
tions, these points will be brought out.
All of the programs found in this book have been compiled and tested.
Usually source code that has been compiled has been copied directly from
computer disks into the text so that there should be few errors caused by
hand copying of the programs into the text. The compilers used to test
these programs are available from Byte Craft Ltd. of Hamilton, Ontario,
Canada (for the MC68HC05) and Intermetrics of Cambridge, Massachu-
setts (for the MC68HC11 and MC68HC16). If you wish to develop
serious programs for any of these microcontrollers, you should purchase
the appropriate compiler from the supplier.
How does one partition a book on C programming for microcontrollers?
First, the text must contain a good background on the C language. Second,
it is necessary to include a rather extensive background on some
microcontrollers. Finally, C must be used to demonstrate the creation of
code for the specified microcontrollers. This approach is used here. The C
xii Introduction to First Edition
background is complete. The background on the chosen microcontrollers
is presented briefly, as this book is not intended to be a text on
microcontrollers. Therefore, the chapters that cover specific microcontrollers
are to the point. The references found in each chapter contain texts and
data books that will cover the various microcontrollers discussed. This
book grew out of my teaching activities, so chapters include several
exercises suitable for classroom as well as individual use. The only way to
learn programming is to program, and the exercises are designed to let you
put the material in each chapter to use in typical microcontroller program-
ming situations.
Chapters 1 and 2 contain a background on ANSI C. Data in these
chapters is basic to all C programs. There is no specific coverage for
microcontroller programming. Chapter 3 contains a brief background on
microcontrollers, and it also contains general programming guidelines that
should be used when writing code for microcontrollers.
Chapter 4 is devoted to writing programs for the MC68HC05 family.
In this chapter, the use of microcontroller specific header files is intro-
duced. These header files are written for a specific part, and must be
included in any program for the part.
In Chapter 5 you will find techniques for programming the MC68HC11
family of parts. Several of the peripherals on these parts are examined, and
code to access these peripherals is written.
More complex microcontrollers are found in the MC68HC16 and the
MC68300 families. Programming the MC68HC16 is discussed in Chapter
6. This part contains an internal bus with several peripherals placed on this
bus. Access to these peripherals is through memory mapped registers and
how these peripherals are accessed will be found in Chapter 6.
There are several appendices. Appendix A contains several header
files that are useful in programming MC68HC05 programs. Appendix B
contains some code that demonstrates the power of the types defined by
structures, and how these types can be made into very convenient new
types by the typedef keyword.
One of the advantages of a high level language is that it isolates the
programmer from the details of the computer being programmed. There
are both plusses and minuses to this idea. First, as a programmer, you do
not need to know details of the register map and the programmers model
of the computer being programmed because the language takes care of
these details for you. On the other hand, microcontrollers all have periph-
erals and other components that must be accessed by the program. The
programmer must be able to write C code that will set and reset bits and
flags in control registers for these parts. It would be desirable to write this
book with no detailed discussion of the insides of the microcontrollers you
Introduction to First Edition xiii
will be programming; however, I could not do it. I needed a careful
discussion of the ways peripheral components are used. Appendix C and
Appendix E contain detailed descriptions of the MC68HC11 and the
MC68HC16 family parts respectively. I am particularly indebted to
Motorola Semiconductor Products, Inc. for the contents of Appendix E.
This Appendix is a very slightly modified version of the Appendix D
found in the MC68HC16Z1 users manual.
Appendix C contains a header file for the MC68HC11Ex series, and
Appendix F contains several header files needed to program the MC68HC16
components.
This book has taken entirely too much time to write. As the author, it
is my fault, and I have been a burden to those around me while I have
labored on this task. The basis for the text comes from about three years of
teaching classes on programming microcontrollers in C. This class has
been taught as a three or four day course, mainly to Motorola customers. I
am amazed that it is possible to learn from every class that I teach. During
the time I have been writing, I have learned object oriented programming
and the C++ language, and I have also taught classes on this subject. It is
difficult to move from one language to another, especially languages with
similar roots like C and C++, and not get them mixed up. I am comfort-
able that this book is on C without C++ spilling into the material.
I have received much help in writing this book. My dear wife, who
understands nothing about computers, has read most of the book and made
comments about the contents. If this text is more readable than usual, it is
her contribution. Any problems that you find are my responsibility entirely.
Motorola has provided me much time and support that I appreciate.
Most of the photographs found in the book are from Motorola files. My
manager, Neil Krohn, has encouraged me at every phase in the preparation
of this manuscript. Neil and Motorola deserve my heartfelt thanks.
[This is a blank page.]
WhatsontheCD-ROM?
Programs
The programs on this CD-ROM will help you learn how to program
small embedded control systems. The directory named Programs contains
all of the programs from the book. Programs from each chapter are
grouped together in directories named Chapter1, Chapter2, etc., where the
number corresponds to the book chapter in which the code is found. The
subdirectory Header~1, or Header Files, contains a series of directories
that contain the specific header files needed to connect your compiled
code to the peripherals found on the indicated chips. These header files
have been used extensively, but you will probably still find an occasional
bug in them. If you do find a bug, please notify me at the email address
below.
There are demonstration compilers for the M6805, the M68HC11, and
the M68HC16 families of chips. The Byte Craft Limited compiler is
placed in directory C6805. Instructions for use of this compiler can be
obtained by merely typing \c6805\c6805 with no arguments and the
instruction sheet will appear.
The two Intermetrics demonstration compilers are placed in
HC11DEMO and HC16DEMO respectively. When using one of these
compilers, the directory name should be placed in the system path. Only
one of the demo directories should be in the path at a time because the two
compilers both use the same function names. Confusion will reign if both
directories are in the path at the same time. In the Software directory, you
will find files named HC16BOOK.TXT and HC11BOOK.TXT. These
files are transcriptions of the books normally shipped with the Demo Kit
packages from Intermetrics. There is no convenient means to copy the
several figures found in these books into these ASCII files. Therefore, the
files are complete with the exception of the figures. The text describes the
contents of the figures. I am sorry for any inconvenience caused by these
necessary omissions. Also, the contents of these books contain discus-
sions of how you should install the various programs contained in the
Demo Kits. These compilers are already installed on the CD-ROM, but
the basic programs from which they are installed are found in the directo-
ries HC16 and HC11. You can reinstall these demonstration compilers
from the programs in these directories if you wish.
xv
xvi What's on the CD-ROM?
Intermetrics no longer supports the compilers found on the CD-ROM.
If you wish continued support with these compilers, you should contact
COSMIC Software at
Cosmic Software
400 W. Cummings Park STE6000
Woburn, MA 01801-6512
781 932 2556 x 15
MotorolaReferenceManualsandDataManuals
The CD-ROM contains full copies of several Motorola M68HC11
reference manuals and data manuals, along with similar information for
the M68HC05, M68HC08, M68HC12, M68HC16, and M683XX family
of chips, and the MCORE family. These reference materials have been
provided with the permission of Motorola and are there for your use.
eBook
Also included on the CD-ROM is a full, searchable eBook version of
the text in Adobe pdf format. In addition, there are sample chapters of
other electronics engineering references available in both eBook and
print versions from LLH Technology Publishing.
Good luck on your venture into C.
Ted Van Sickle
e-mail: tvansickle@a-sync.com
http://www.a-sync.com/
Chapter 1
IntroductiontoC
Programmingisacontactsport.Programmingtheoryisinterest-
ing, but you must sit at a keyboard and write code to become a
programmer.The aim of this introductory section is to give you a
briefglimpseofCsothatyoucanquicklywritesimpleprograms.
Later sections will revisit many of the concepts outlined here and
provideamorein-depthlookatwhatyouaredoing.Fornow,lets
startwritingcode.
SomeSimplePrograms
Cisafunctionbasedlanguage.YouwillseethatCusesfarmore
functionsthanotherprocedurallanguages.Infact,anyCprogramit-
self is merely a function.This function has a name declared by the
language.InC,parametersarepassedtofunctionsasarguments.A
functionconsistsofanamefollowedbyparenthesesenclosingargu-
ments,orperhapsanemptypairofparenthesesifthefunctionrequires
noarguments.Ifthereareseveralargumentstobepassed,theargu-
mentsareseparatedbycommas.
ThemandatoryprogramfunctionnameinCismain.EveryCpro-
grammusthaveafunctionnamedmain,andthisfunctionistheone
executedwhentheprogramisrun.Examinethefollowingprogram:
#include<stdio.h>
intmain(void)
{
printf(Microcontrollersruntheworld!\n);
return0;
}
1
2 Chapter 1 Introduction to C
ThisprogramcontainsalloftheelementsofaCprogram.Note
firstthatCisafreeformlanguage.Spaces,carriagereturns,tabs,
andsofortharefortheprogrammersconvenienceandareignored
bythecompiler.Thefirstlineoftheprogram
#include<stdio.h>
iscalledapreprocessor command.Preprocessorcommandsareiden-
tifiedbythe#atthebeginningoftheline.Inthiscase,#include
tellsthepreprocessortoopenthefilestdio.handreaditintothe
programtobecompiledwiththeremainderoftheprogram.Thefile
nameissurroundedbyanglebrackets<>.Thesedelimiterstellthe
compilertosearchforthefileinaregiondesignatedbytheoperating
system as SET INCLUDE. Had the file name been delimited by
doublequotes,,theoperatingsystemwouldhavesearchedonly
thedefaultdirectoryforthefile.Thedefaultdirectoryis,ofcourse,
thedirectoryfromwhichyouareoperating.
Thenextlineoftheprogramisadefinitionforafunctionnamed
main.InANSIC,asopposedtoclassicC,eachfunctiondefinition
mustinformthecompilerofthereturntypefromthefunction,and
thetypeofthefunctionsarguments.Inthiscase,thefunctionmain
hastoreturnanintegeranditexpectsnoarguments.Thetypeint
precedingthefunctionnameindicatesthatitreturnsanintegerand
thatnoargumentstothefunctionareexpected.
The line following the function definition contains an opening
brace {.This brace designates the beginning of a block or a com-
poundstatement.Thenextlineoftheprogramcontainsafunction
calltothefunctionprintf().Thisfunctionismadeavailableto
theprogrambytheinclusionoftheheaderfilestdio.h,anditisa
functionthatwritesamessagetothecomputerterminalscreen.In
thiscase,themessagetobesenttothescreenis
Microcontrollersruntheworld!
Theescape character \nattheendofthemessageinformsthe
program to insert a new line at that point. The complete message
includingthenewlineescapecharacterisenclosedindoublequotes.
Thesedoublequotesidentifyastring,andthestringistheargument
tothefunctionprintf().Notethatthestatementbeginningwith
printfisclosedwithasemicolon.InC,everystatementistermi-
natedwithasemicolon.
3 Some Simple Programs
Afterthemessageissenttothescreen,thereisnothingmorefor
the program to do, so the program is terminated by executing the
statementreturn0;.Thisstatementreturnsthevalue0backto
thecallingprogram,whichistheoperatingsystem.Also,execution
ofthereturnstatementwillcauseallopenfilestobeclosed.Ifthere
werenoreturnstatementattheendoftheprogram,thenormalpro-
cessingattheendoftheprogramwouldcloseopenfiles,butthere
wouldbenovaluereturnedtothecallingprogram.
Thisisanareawherethereismuchdiscussionandmanydissent-
ingviewpoints.EarlyCdidnotrequirethatmainreturnavalueto
thecallingprogram.WhentheC89standardwaswritten,itrequired
thatmainreturnanint.Unfortunately,manypeople,setintheir
ways, have refused to adhere to the standard nomenclature in this
caseandtheyoftenusevoidmain(void)insteadoftheform
above. Most compilers will ignore this form and allow the void
main(void)functioncall.Forsomereason,thisformangersmany
codereviewers,soyoushouldusethecorrectformshownabove.
Theprogramisclosedbytheinclusionofaclosingbrace,},at
theend.Therecouldbemanystatementswithintheblockfollowing
main()creatingaprogramofanycomplexity.Theclosingbraceis
theterminatorofacompoundstatement.Thecompoundstatementis
theonlycaseinCwhereacompletestatementclosuredoesnotre-
quireasemicolon.
Anotherprogramexampleisasfollows:
#include<stdio.h>
intmain(void)
{
inta,b,c,d;
a=10;
b=5;
c=2;
d=a*b*c;
printf(a*b*c=%d\n,d);
4 Chapter 1 Introduction to C
d=a*b+c;
printf(a*b+c=%d\n,d);
d=a+b*c;
printf(a+b*c=%d\n,d);
return0;
}
Beforediscussingthisbitofcode,weneedtotalkaboutthenum-
bersusedinit.Likemosthigh-levellanguages,Cprovidesfordifferent
classesofnumbers.Theseclassescaneachbevariabletypes.One
classistheintegertypeandasecondisthefloating pointtype.We
willexaminethesenumberclassesinmoredetaillater,butfornow
letusconcentrateontheintegertypes.Integernumbersusuallyhave
anumericrangeofabout2
(n-1)
,wherenisthenumberofbitsthat
containstheintegertype.Integersarealsocalledintegraltypes.Inte-
graltypesdonotunderstandorpermitfractions.Anyfractionthat
resultsfromadivisionoperationwillbetruncatedanddisappearfrom
the calculation.All variables must be declared or defined to be a
specifictypepriortotheiruseinaprogram.
Thefirstlineofcodeinmain
inta,b,c,d;
declaresthevariablesa,b,c,anddtobeintegertypes.Thispar-
ticularstatementisbothadeclarationandadefinitionstatement.A
definition statement causes memory to be allocated for each vari-
able,andalabelnametobeassignedeachlocation.Adeclaration
statement does not cause memory allocation, but rather it merely
providesinformationastothenatureofthevariabletothecompiler.
Wewillseemoreofdefinitionanddeclarationstatementslater.
Thethreeassignmentstatements
a=10;
b=5;
c=2;
assign initial values to the variables a,b, and c.The equal sign
signifiesassignment.Thevalue10isplacedinthememorylocation
designatedasa,etc.Thenextstatement
d=a*b*c;
5 Some Simple Programs
notifiesthecompilertogeneratecodethatwillcausetheintegerstored
inlocationatobemultipliedbytheintegerinb andtheresultofthat
producttobemultipliedbytheintegerfoundinc.Usually,thename
a,b,orcisusedtodesignatethecontentofthememorylocation
assignedtothelabelname.Thisintegerresultwillbestoredinthe
locationidentifiedbyd.
Theprintstatement
printf(a*b*c=%d\n,d);
is similar to the same statement in the first example. In this case,
however,thedatastring
a*b*c=%d\n
containsaprintercommandcharacter%d.Thischaracternotifiesthe
printffunctionthatitistotakethefirstargumentfollowingthe
datastring,convertittoadecimalvalue,andprintitouttothescreen.
Theresultofthislineofcodewillbe
a*b*c=100
printedonthescreen.
Thelineofcode
d=a*b+c;
demonstratesanothercharacteristicofthelanguage.Eachoperator
isassignedaprecedencethatdeterminestheorderinwhichanex-
pression is evaluated.The parenthesis operators are of the highest
precedence.Theprecedenceofthe*operatorishigherthanthatof
the+operator,sothisexpressionwillbeevaluatedas
d=(a*b)+c;
Inotherwords,theproductindicatedby*willbeexecutedprior
totheadditionindicatedbythe+.Theexpressionthatfollowslater
inthecode
d=a+b*c;
willbeevaluatedas
d=a+(b*c);
causingtheresultofthethirdcalculationtodifferfromthatofthe
second.
6 Chapter 1 Introduction to C
Theresultobtainedwhenrunningthisprogramisasfollows.
a*b*c=100
a*b+c=52
a+b*c=20
Hereisanotherexamplethatdemonstratesaprimitivelooping
construct:
#include<stdio.h>
intmain(void)
{
inti;
i=1;
printf(\ti\ti\ti\n);
printf(\t\tSquaredCubed\n\n);
while(i<11)
{
printf(\t%d\t%d\t%d\n,i,i*i,i*i*i);
i=i+1;
}
return0;
}
Thisexamplewasdesignedtoproduceasimpletableoftheval-
uesofthefirsttenintegers,thesevaluessquared,andthesevalues
cubed.Thelines
printf(\ti\ti\ti\n);
printf(\t\tSquaredCubed\n\n);
combinetoproduceaheaderthatidentifiesthecontentsofthethree
columnsgeneratedbytheprogram.Theescapecharacter\tisatab
characterthatcausesthescreencursortoskiptothenexttabposi-
tion.ThedefaulttabvalueinCiseightspaces.
Thecommand
while(i<11)
.....
causestheargumentofthewhiletobeevaluatedimmediately,and
iftheargumentisTRUE,thestatementfollowingthewhilewillbe
7 Some Simple Programs
executed.Theargumentshouldbereadiislessthan11.Theini-
tially assigned value for i was 1, so the argument is TRUE. The
compoundstatement
{
printf(\t%d\t%d\t%d\n,i,i*i,i*i*i);
i=i+1;
}
willstartexecutionwiththevalueofibeingequalto1.Oncethis
statementisevaluated,controlispassedbacktothewhileandits
argumentisevaluated.IftheargumentisTRUE,thestatementfol-
lowingwillbeevaluatedagain.Thissequencewillrepeatuntilthe
argumentevaluatesasFALSE.
Inthisexpression,thestringargumentoftheprintffunction
containsthree%dcommands.Each%dcommandcausesthecorre-
spondingargumentfollowingthestringtobeprintedtothescreen.
Therearetabcharacters,\t,toseparatethevariousprintedvalues
onthescreen.Thefirst%dwillcausethevalueofitobeprinted
onthescreen.Thesecond%dwillcausethevaluei*i, or i
2
, to
beprintedtothescreen.Thethird%dwillprintthevalueofi*i*i,
or i
3
tobeprinted.WhenCexecutesthefunctioncall,thevalues
oftheargumentsarecalculatedpriortothecall,soargumentslike
i*iareevaluatedbythecallingprogramandpassedbyvalueto
thefunction.
Thestatement
i=i+1;
isanexampleoftheuseofbothprecedence and associationthe
directioninwhichexpressionsareevaluatedinC.Theequalsign
hereisanoperatorjustlikethe+symbol.The+operatorisevaluated
fromlefttoright,andthe=operatorisevaluatedfromrighttoleft.
Also,the+operatorhashigherprecedencethanthe=operator.There-
fore,theabovestatementwilladdonetothevaluestorediniand
thenassignthisnewvaluetothevariablei.Thisexpressionsimply
incrementsthevariablei.
The above statement is the terminating statement of the com-
poundstatementfollowingthewhile.Sinceihadaninitialvalue
of1,controlwillbereturnedtothewhilewithavalueof2fori. 2,
8 Chapter 1 Introduction to C
ofcourse,islessthan11,sothestatementfollowingthewhilewill
beexecutedagainandnewvalueswillbeprintedtothescreen.This
sequencewillberepeateduntiltheincrementedvalueforiequals
11, at which time i<11 will be FALSE.At that point in the pro-
gram,thestatementfollowingthewhilewillbeskipped,andthe
programwillhavereacheditsend.Theresultofexecutingtheabove
programisshowninthefollowingtable:
i i i
squared cubed
1 1 1
2 4 8
3 9 27
4 16 64
5 25 125
6 36 216
7 49 343
8 64 512
9 81 729
10 100 1000
EXERCISES
1.Write,compile,andexecuteeachoftheexampleprogramsshown
inthissection.
2.WriteaprogramtocalculatetheFahrenheittemperaturefortheCel-
siusvaluesbetween0degreesand100instepsof10each.The
conversionformulaisF=9*C/5+32.Useintegervariables,andex-
aminetheresultwhenyouuseF=C*(9/5)+32.Whatwentwrong?
Names
Variables,constantsandfunctionsinCarenamed,andthepro-
gram controls operations on these named variables and constants.
Variablesandconstantsarecalledoperands.Namescanbeasmany
as31characterslong.Thecharactersthatmakeupthenamecanbe
theupperandthelowercaseletters,thedigits0through9,andthe
underscorecharacter_.Thereareseveraldefinedconstantsand
functions that are used by the compiler.All of these names begin
9 Names
with an underscore. Because of this convention, you should avoid
theuseofanunderscoreasthefirstcharacterforeitherfunctionor
variablenamesinyourcode.Thisapproachwillcompletelyavoid
name conflict with these hidden or unexpected names. Compilers
usuallyallowthenamestobeuniqueinthefirst31characters.Un-
fortunately,somelinkersusedtolinkvariousprogrammodulesrequire
thatthenamesbeuniqueinthefirstsixoreightcharacters,depend-
ingonthelinker.
Chasacollectionofkeywordsthatcannotbeusedfornames.
Thesekeywordsarelistedbelow:
KEYWORDS
auto double int struct
break else long switch
case enum register typedef
char extern return union
const float short unsigned
continue for signed void
default goto sizeof volatile
do if static while
TypesandTypeDeclarations
Chasonlyafewbuilt-intypes.Heretheyare:
charisusuallyeightbits.Thecharacteristhesmalleststor-
ageunit.
intanintegerisusuallythesizeofthebasicunitofstorage
forthemachine.Anintmustbeatleast16bitswide.
floatasingleprecisionfloating-pointnumber.
doubleadoubleprecisionfloating-pointnumber.
Additionalqualifiersareusedtomodifythebasictypes.These
qualifiersinclude:
shortmodifiesanint,andisavariablewhosewidthisno
greaterthanthatoftheint.Forexample,withacompilerwitha32
bit int a shortint could be 16 bits.You will find examples
whereshortandintarethesamesize.
10 Chapter 1 Introduction to C
longmodifiesanint,andisavariablesizewhosewidthis
nolessthanthatofanint.Forexample,ona16-bitmachine,an
intmightbe16bits,andalongintcouldbe32bits.longcan
alsomodifyadoubletospecifyanextendedprecisionfloating-point
number.Youwillfindexampleswherealongandanintarethe
samesize.
signedmodifiesallintegralnumbersandproducesarange
ofnumbersthatcontainsbothpositiveandnegativenumbers.For
example,ifthetypecharis8bits,asignedcharcancontainthe
range of numbers 128 to +127. Default for char and int is
signedwhentheyaredeclared.
unsignedmodifiesallintegralnumbersandproducesarange
ofnumbersthatarepositiveonly.Forexample,ifthetypecharis8
bits,anunsignedcharcancontaintherangeofnumbers0to
+255.Itisnotnecessarytoincludethetypeintwiththequalifiers
shortorlong.Thus,thefollowingstatementsarethesame:
longinta,c;
shortintd;
and
longa,c;
shortd;
Whenavariableisdefined,spaceisallocatedinmemoryforits
storage.The basic variable size is implementation dependent, and
especiallyformicrocontrollers,youwillfindthatthisvariabilitywill
showupwhenyouchangefromonemicrocomputertoanother.
Each variable must be defined prior to being used.A variable
maybedefinedatthebeginningofanycodeblock,andthevariables
scopeistheblockinwhichitisdefined.Whentheblockinwhichthe
variableisdefinedisexited,thevariablegoesoutofexistence.There
isnoproblemwithdefiningvariableswiththesamenameindiffer-
entblocks.Thecompilerwillmakecertainthatthesevariablesdo
notgetmixedupintheexecutionofthecode.
Anadditionalqualifierisconst.Whenconstisusedasaquali-
fieronthedeclarationofanyvariable,aninitializationvaluemustbe
declared.Thisvaluecannotbechangedbytheprogram.Therefore
thedeclaration
Types and Type Declarations 11
constdoublePI=3.14159265;
willcreatethevalueforthemathematicalconstantpiandstoreitin
thelocationprovidedforPI.AnyattempttochangethevalueofPI
bytheprogramwillcausecompilererror.
Conventionsforwritingconstantsarestraightforward.Asimple
numberwithnodecimalpointisanint.Tomakeanumberlong,
youmustsuffixitwithanl oranL.Forexample,6047 isanintand
6047Lisalong.TheuorUsuffixonanumberwillcausecreation
ofaproperunsignednumber.
Afloating-pointnumbermustcontainadecimalpointoranex-
ponent or both. The numbers 1.114 and 17.3e-5 are examples of
floating point numbers.All floating point numbers are of the type
double unless a suffix is appended to the number.Any number
suffixedwithanforanFisasingleprecisionfloating-pointnum-
ber,andasuffixoflorLonafloating-pointnumberwillgeneratea
type long double. Octal (base 8) and hexadecimal (base 16)
numbers can be created.Any number that is prefixed with a 0a
leadingzeroistakentobeanoctalnumber.Hexadecimalnumbers
are prefixed with a 0x or a 0X.The rules above for L and U also
applytooctalandhexadecimalnumbers.
Thefinaltypequalifierisvolatile.Thequalifiervolatile
instructsthecompilertoNOToptimizeanycodeinvolvingthevari-
able.Inexecutionofanexpression,asideeffectreferstothefactthat
theexpressionalterssomething.Thesideeffectofthefollowingstate-
ment
a=b+c;
isthatthestoredvalueofaischanged.Asequencepointisapointin
thecodewhereallsideeffectsofpreviousevaluationsarecompleted
andnosideeffectsfromsubsequentevaluationswillhavetakenplace.
Animportantconsiderationoftheoptimizationisthatifanexpression
hasnosideeffects,itcanbeeliminatedbythecompiler.Therefore,if
astatementinvolvesnosequencepoint,oraltersnomemory,itissub-
jecttobeingdiscardedbythecompiler.Thisoperationisnotparticularly
badwhenwritingnormalcode,butwhenworkingwithmicrocontrollers
where events can occur as a result of hardware operations, not the
program,thisoptimizationcanutterlydestroyaprogram.Forexample,
wheneverthehardwarecanalterastoredvalue,thecompilershould
12 Chapter 1 Introduction to C
beabletodiscardaccessestothatvaluebecausetheprogramnever
altersthevalue.Insuchacircumstance,ifyouhadananalog-to-digital
converterperipheralinyoursystem,theprogramwouldneverbere-
quiredtoreaditsreturnvaluemorethanonce.Theprogramdidnot
change the value stored in the input location subsequent to the first
read,thereforeitsvaluehasnotchangedanditisnotnecessarytoread
thelocationagain. Thiswillalwaysproducewrongresults.Thekey
wordvolatileindicatestotheprogramthatavariablemustnotbe
optimized.Therefore,iftheinputlocationisidentifiedasa vola-
tilevariable,itwillnotbeoptimizedandtheproblemwillgoaway.
Asapointofinterest,accessingavolatileobject,modifyingan
object,modifyingafile,orcallingafunctionthatdoesanyofthose
operationsarealldefinedassideeffectsbythestandard.
StorageClasses,Linkage,andScope
Additional modifiers are called storage classes and designate
whereavariableistobestoredandhowitisinitialized.Thesestor-
age classes are auto (for automatic), static, and malloced.
Thefirsttwostorageclassesaredescribedinthefollowingsections.
Thestorageclassmallocprovidesdynamicmemoryallocationand
isdiscussedindetailinChapter2.
Automaticvariables
Forlocalvariablesdefinedwithinafunction,thedefaultstorage
classisauto.Anautomaticvariablehasthescopeoftheblockin
whichitisdefined,anditisuninitializedwhenitiscreated.Auto-
maticvariablesareusuallystoredontheprogramstack,sospacefor
thevariableiscreatedwhenthefunctionisentered.Whenthestack
iscleaneduppriortothereturnattheendofthefunction,allvari-
ablesstoredonthestackaredeleted.
Aswesawinourfirstprogramexample,variablescanbeinitial-
izedatthetimeofdeclarationbyassigningthevariableaninitialvalue:
intrupt=17;
Anautomaticvariablewillbeassigneditsinitialvalueeachtime
the block in which it is declared is entered. If the variable is not
initializedatdeclaration,itwillcontainthecontentsofuninitialized
memory,whichcanbeanyvalue.
Storage Classes, Linkage, and Scope 13
Anotherclassofvariableisregister.Aregisterclassvariable
isautomatic,i.e.,itcomesintobeingatthebeginningoftheblockin
whichitisdefinedanditgoesoutofscopeattheendoftheblock.If
a register is available in the computer, a register variable
willbestoredinaregister.Todefinearegistervariable,youshould
usetheform
registerintroger=10;
Thesevariablescanbelong,short,int,orchar.
When a register is not available, a register variable will be
stored just like any other automatic variable.A programmer might
considertheuseofregistervariablesincodethatcontainstight
loopstosavethetimeofmemoryaccesseswhileexecutingtheloop.
Abitofadvice.Compilershaveimprovedcontinuouslyoverthepast
years.Withtodayscompilers,theoptimizersaresoefficientthatthe
compilercanprobablydoabetterjobofassigningregistervari-
ablesthantheprogrammer.Therefore,itmakeslittlesensetospecifya
lotofregistervariablesjusttoimprovetheefficiencyofyourcode.
Staticvariables
Sometimesyoumightwanttoassignavaluetoavariableand
haveitretainthatvalueforlaterfunctioncalls.Suchavariablecan
becreatedbycallingitstaticatitsdefinition.Therearetwogroups
ofstaticvariables:Localstaticvariableswhichhaveascope
of the function in which they are defined, and global or external
staticclassvariables.Unlessotherwisedeclared,allstaticclass
variablesareinitializedto0whentheyarecreated.
Therearetwogroupsofexternalstaticvariables.Anyexter-
nalvariableisastaticclassvariable.Itisautomaticallyinitialized
tothevalue0whentheprogramisloadedunlessthevalueisother-
wisedeclaredinthedefinitionstatement.Anexternalvariablethatis
declaredasstaticinitsdefinitionstatementlike
staticintredoubt;
will have file scope. Remember normal external variables can be
accessedfromanymoduleintheentireprogram.Astaticexter-
nalvariablecanbeaccessedonlyfromwithinthefileinwhichitis
defined.Notethatstaticvariablesarenotstoredonthestack,but
ratherstoredinastaticdatamemoryarea.
14 Chapter 1 Introduction to C
Insideofafunction,thefollowingdeclarationismade:
staticintkeep=1;
Whentheprogramisloadedandexecuted,thevalue1isassigned
tokeep.Thereafter,eachtimethefunctionisentered,keepwill
notbeinitializedbutwillretainthevalueassignedtoitthelasttime
thefunctionwasexecuted.
Globalvariablescanbedesignatedasstatic.Aglobalvari-
ablethatisstaticissimilartoaconventionalglobalvariablewith
theexceptionthatitcanbeaccessedonlyfromthefileinwhichitis
declared.
Ifthereisanexternalvariablethatisdeclaredinonefilethatisto
beaccessedbyafunctiondefinedinanotherfile,thefunctionmust
notifythecompilerthatthevariableisexternalwiththeuseofthe
keywordextern.Thefollowingisanexampleofsuchanaccess.
Infile1:
intable;
intmain(void)
{
longquickstart(void);
longr;
.
.
.
able=17;
l=quickstart();
.
.
}
Infile2:
longquickstart(void)
{
externintable;
.
/*dosomethingwithable*/
.
Character Constants 15
returnresult;
}
When the file 1 is compiled, the variable able is marked as
external,andmemoryisallocatedforitsstorage.Whenthefile2is
compiled,thevariableableisrecognizedtobeexternalbecauseof
theexternkeyword,andnomemoryisallocatedforthevariable.
When the link phase of the compilation is completed, all address
referencestoableinfile2willbeassignedtheaddressofablethat
wasdefinedinfile1.Theexampleaboveinwhichthedeclaration
externintable;
allowedaccesstoablefromthefile2willnotworkifablehad
beendeclaredasfollowsinfile1:
staticintable;
Character Constants
Characterconstantsorescapesequencesaredatathatcanbestored
in memory locations designated as char.A character constant is
identifiedbyabackslashprecedingthecharacter.Wehaveseenthe
useofthecharacterconstants\nand\tinpreviousexamples.
Severaloftheseescapesequencesshowninthefollowingtablehave
predefinedmeanings.
Escape Meaning
Sequence
\a bellcharacter
\b backspace
\f formfeed
\n newline
\r carriagereturn
\v verticaltab
\t horizontaltab
\? questionmark
\\ backslash
\ singlequote
\ doublequote
\ooo octalnumber
\xxx hexadecimalnumber
16 Chapter 1 Introduction to C
Iftheseconstantsareusedwithinaprogram,theymustbeidentified
byquotes.Intheearlierexample,thenewlinecharacterwasapartof
astring.Therefore,iteffectivelywascontainedinquotes.Ifasingle
characterconstantistobegenerated,theconstantmustbeincludedin
singlequotes.Forexample,atestmightincludeastatementlike
if(c!=\t)
....
Thisstatementcausesthevariablectobecomparedwiththeconstant
\t,andthestatementfollowingtheifwillbeexecutediftheyare
notthesame.Anotherpreprocessorcommandis#define.Withthe
#definecommand,youcandefineacharactersequencethatwillbe
placedinyourcodesequencewheneveritisencountered.Ifyouhave
characterconstantsthatyouwishtouseinyourcode,theseconstants
canbeidentifiedas
#defineCR\x0d
#defineLF\x0a
#defineBELL\x07
#defineNULL\x00
andsoforth.
Welldiscussthe#definepreprocessorcommandfurtherlater.
Thefollowingprogramshowsuseofanescapecharacter.
/*Countlinesoftextinaninput*/
#include<stdio.h>
intmain(void)
{
intc,nl=0;/*thenumberoflinesisinnl*/
while((c=getchar())!=EOF)
if(c==\n)
nl++;
printf(Thenumberoflinesis%d\n,nl);
return0;
}
Character Constants 17
Oftenyouwillwanttoleavecluesastowhattheprogramor
lineofcodeissupposedtodo.Commentswithinthecodeprovide
thisdocumentation.ACcommentisdelimitedby
/*.......*/
andthecommentcancontainanythingexceptanothercomment.In
otherwords,commentsmayNOTbenested.Thefirstlineofcode
intheaboveprogramisacomment,andthesixthlinecontainsboth
codeandacomment.Thecompilerignoresallinformationinside
thecommentdelimiters.
Thisprogramusestwointegervariablescandnl.Thevariable
cisthetemporarystoragelocationinwhichinputdataarestored,
andnliswherethenumberofinputlinesarecounted.
Thewhilestatementcontainsarathercomplicatedargument.
At any point in a C program when a value is calculated, it can be
storedinaspecifiedlocation.Forexample,inthewhileexpression
while((c=getchar())!=EOF)
theinnerexpression
c=getchar()
causes the function getchar() to be executed. The return from
getchar()isacharacterfromtheinputstream.Thischaracteris
assignedtothevariablec.Afterthisoperationiscompleted,there-
sultreturnedfromgetchar()iscomparedwiththeconstantEOF.
EOFmeansend-of-file,anditisthevaluereturnedbygetchar()
whenaprogramtriestoreadbeyondtheendofthedatastream.Itis
definedinthefilestdio.h.Thesymbol!=isread isnotequal
to. Therefore,theargumentofthewhilewillbeTRUEsolongas
getchar() does not return an EOF and the statement following
thewhilewillbecontinuallyexecuteduntilanEOFisreturned.
Operatorsinanexpressionthathavethehigherprecedencewillbe
executedbeforethelowerprecedenceoperators.Intheexpression
c=getchar()!=EOF
theoperator!=hasahigherprecedencethanthatofthe=operator.
Therefore,whenthisexpressionisevaluated,thelogicalportionof
the expression will be evaluated first, and the result of the logical
18 Chapter 1 Introduction to C
evaluationeitherTRUEorFALSEwillbeassignedtothevari-
ablec.Thisresultisofcourseincorrect.Toavoidthisproblem,use
(c=getchar())!=EOF
as the while argument. In this case, the parentheses group the
c=getchar()expressionanditwillbecompletedpriortoexecu-
tionofthecomparison.Thevariablecwillhavethecorrectvalueas
returnedfromtheinputstream.Iftheaboveexpressionislogically
true,thenthevaluethatwasreturnedfromtheinputstreamistested
todetermineifitisanewlinecharacter.Ifanewlinecharacteris
found,thecounternlisincremented.Otherwise,thenextcharacter
isreadinandthesequencerepeateduntilanEOFisreturnedfrom
the getchar().Whenever an assignment is executed inside of
anotherexpression,alwaysenclosethecompleteassignmentexpres-
sioninparentheses.
Thefinalstatementintheprogram
printf(Thenumberoflinesis%d\n,nl);
printsoutthenumberofnewlinecharactersdetectedinreadingthe
inputfile.
Arrays
Anarrayisacollectionofliketypesofdatathatarestoredin
consecutivememorylocations.Anarrayisdesignatedatdeclaration
timebyappendingapairofsquarebracketstothearrayname.Ifthe
size of the array is to be determined at the declaration, the square
bracketscancontainthenumberofelementsinthearray.Following
areproperarraydeclarations.
externinta[];
longrd[100];
floattemperatures[1000];
charst[]={Makeacharacterarray};
floatpressure[]={1.1,2.3,3.9,3.7,2.5,1.5,
0.4};
As you can see, the size of an array must be designated in some
mannerbeforeyoucanuseemptysquarebracketsinthedesignation.
Inthefirstcaseabove,thearraya[]isdefinedinglobalmemory,so
allthatisnecessaryforthecompilertoknowisthata[]isanarray.
Arrays 19
Theargumentofanarrayissometimescalleditsindex.Itisanum-
berthatselectsaspecificentryintoanarray.Arrayargumentsstart
withzeroalways.Therefore,whenanarrayof100elementsiscre-
ated, these elements are accessed by using the arguments 0 to 99.
The standard requires that the first element beyond the end of the
array be accessible as an array entry.Attempts to access elements
beyondthatwillgiveundefinedresults.
Arrayscanbeinitializedatdeclaration.Theinitializationvalues
mustbeenclosedinbraces,andifthereareseveralindividualnu-
merical values, these values must be separated by commas. In the
caseofastringinitialization,itisnecessarytoincludethestringin
quotes and also enclose the string along with its quotation marks
within the braces. In both of these cases, the size of the array is
calculatedatcompiletime,anditisunnecessaryfortheprogrammer
tofigurethesizeofthearray.
Astringisaspecialcaseofanarray.Wheneverastringisgener-
atedinC,anarrayofcharactersiscreated.Thelengthofthearrayis
onegreaterthanthelengthofthestring.Theindividualcharacters
from the string are placed in the array entries. To be a proper C
string,thearrayslastcharactermustbeazerooranull.Allstrings
inCarenullterminated.Ifyouasaprogrammercreateastringin
yourprogram,youmustappendanullontheendofthecharacter
arraytobeguaranteedthatCwilltreatthearrayasastring.
Iftheprogrammershouldspecifyanarraysizeandtheninitial-
izeaportionofthearraylike
inttime[6]={1,5,3,4};
thecompilerwillinitializethefirstfourmembersofthearraywith
the specified values and initialize the remainder of the array with
zerovalues.Thisapproachallowsyoutoinitializeanyarraywithall
zerovaluesby
longziggy[100]={0};
whichwillfillalloftheelementsofthearrayziggy[]withzeros.
C provides you with no array boundary checking. It is the
programmers responsibility to guarantee that array arguments do
notviolatetheboundariesofthearray.
20 Chapter 1 Introduction to C
Othertypes
There are mechanisms for creating other types in C. The three
othertypesareenum,union,andstruct.Itisoftenquiteconve-
nienttomakeuseofthedatatypestoaccomplishthingsthataredifficult
withthenormaltypesavailable.Wewillseehowtousethesetypesin
thissection.
Theenum
ThenameenumisusedinCinamannersimilartothe#de-
finepreprocessorcommand.Theenumstatement
enumstate{OUT,IN};
producesthesameresultas
#defineOUT0
#defineIN1
Here,thenamestateiscalledthetagname.InthiscaseOUTwillbe
givenavalueof0andINavalue1.Inthe enum{}form,unless
specificallyassigned,thememberswillbegivensuccessivelyincreas-
ingvaluesandthefirstwillbegivenavalue0.Valuescanbeassigned
byanenum{};
enummonths{Jan=1,Feb,Mar,April,May,June,
July,Aug,Sept,Oct,Nov,Dec};
willcauseJantobe1,Feb2,andsoforthuptoDecwhichwillbe12.
Each member can be assigned a different value, but whenever the
programmerassignmentsstop,thevaluesassignedtothevariables
following will be successively increased.These values are, by de-
fault,oftheinttype.Thenamemonthsintheaboveexpressionis
calledatagname.Anenumcreatesanewtypeandyoumighthave
several enums in your code that you would wish to create as in-
stances.Thekeywordenum withitstag nameidentifiesthespecific
enumwhenitisusedasatypeidentifierinadefinitionstatement.
Anotherexample
enum(FALSE,TRUE,Sun=1,Mon,
Tues,Wed,Thur,Fri,Sat);
Other Types 21
willresultinFALSEbeing0,TRUE1,Sun1,Mon2,andso
forthtoSat7.Notethatitisnotnecessarytoassignatagnameto
anenum.
Anenumistypedatdeclarationtime.Therefore,thevaluescre-
atedbyanenumareindeednumericalvalues.Thisdiffersfromthe
#definebecausethestatement
#defineFALSE0
willcausethecharacter0tobeinsertedintothesourcecodewhen-
everthelabelFALSEisencountered.Assuch,the#defineconstruct
isacharactersubstitution techniqueoramacroexpansion.There-
sultofanenumisanumericalsubstitution.The#defineconstruct,
beingasimplecharactersubstitution,hasnotypingattachedtoits
arguments.Constantscreatedbyanenumaretyped,andtherefore,
will avoid many of the potential hazards of dealing with untyped
variables.
Letusexaminehowonemightuseatypecreatedwithanenum
construct.Thefollowingenumdefinestwoconstants
enumdirection{LEFT,RIGHT};
Inaprogram,adefinitionstatement
enumdirectiond;
willcauseavariabledtobecreated.Theacceptablevaluesfordare
thenamesLEFTandRIGHT.Weknow,ofcourse,thatthenumerical
valueforLEFTis0andthevalueforRIGHT.Withinyourprogram,
youcanassignandtestthevalueofd.Forexample,
if(d==LEFT)
dosomething
or
if(d==RIGHT)
dosomethingelse
or
d=RIGHT;
Asstatedearlier,theacceptablevaluesfordareLEFTandRIGHT.
Thereisnocheckingwithintheprogramtoseeiftheprogrammer
22 Chapter 1 Introduction to C
hasindeedkeptthetrust.Therefore,itispossibletoassignanyinte-
gervaluetod,andtheprogramwillcompile.Itprobablywillnot
workcorrectly,however.
TheUnion
Theunionwasinventedwhenmemorywasverydear.Themain
purposeoftheunionwastoallowthestoringofseveralvariablesat
asinglememorylocation.Aunionhasatagnamemuchthesame
astheenumabove.
unionseveral
{
longbiggie;
intmiddle_size;
charlittle,another_char;
shortlittle_bigger;
};
Theunionseveralcontainsseveralmembers.Thesemembers
are not necessarily of the same type and there can be multiple in-
stancesofthesametype.Tocreateaninstanceofsuchaunion,you
needadefinitionstatement.Thisstatementcanbeexternalorimme-
diatelyfollowingtheopeningofacodeblock,andhencelocal.Such
astatementmightbe
unionseveralthese;
Thisdefinitioncausesaunionseveralnamedthesetobecre-
atedwithmemoryallocated.Toaccessthemembersoftheunion,
youcanusethedotoperatoras
these.biggie=something;
or
another=these.another_char;
Aninterestingfeatureofaunion.Ifyoushouldcheckthesize
of aunion,you would find that it is the size of the largest of its
members.Wheneveryouaccess,eitherreadorwrite,aunion,the
propersizedataiswrittenorread,anditoverwritesanyotherdata
thatmightbefoundinthememorylocation.Therefore,youcanuse
aunion forstorageofonlyoneofitsmembersatatimeandwriting
Other Types 23
anything to the union destroys any data previously stored to the
union.
Thestruct
Yetanothertypeisthestruct.Thestructisacollectionof
thingsmuchlikethearray.Inthecaseofthestruct,therearetwo
majordifferences.Astruct can contain different types, and the
structitselfisafirstclasstype.Anarraymustbeacollectionof
liketypes,andanarrayisNOTatype,sothetype-likethingsyou
candowithastructarenotavailableforanarray.
Youcreateastructinmuchthesameformaswasseenwitha
union.Youmayuseatagname.
structable
{
chara,b;
intc,d;
};
Thisstructismadeupoftwocharactersandtwointegers.Ifyou
wishtodefineaninstanceofthestruct,youshoulduse
structablehere:
Accessthemembersofthestructwiththedotoperatorlike
here.a=a;
here.b=16;
here.c=32000;
here.d=-16500;
WewillseemoreofstructinChapter2whereyouwilllearn
howtomakeuseofthenewtypescreatedbystruct.
EXERCISES
1.Writeaprogramthatreadsallofthecharactersfromaninputfile
andprintsthecharactersonthescreen.Usethegetchar() func-
tionusedearliertoreadtheinputsandtheputchar(c)toprint
theresultstothescreen.
2.Modifytheaboveprogramtocountthenumberofcharactersinan
inputstream.
24 Chapter 1 Introduction to C
3.Writeaprogramthatreadsthecharactersfromaninputfileand
countsinanarraytheoccurrencesofeachletter.Makethepro-
gramcaseinsensitivebytreatingalluppercaselettersaslower
case.
Operators and Expressions
Thevariablesandconstantsdiscussedintheprevioussectionare
classed as operands. They are values or objects that are operated
uponbyaprogram.Theoperationsthattakeplacearespecifiedby
operators.This section contains a discussion of the several opera-
tors.
OperatorsaboundinC.Allofthesymbolsinvolvedinthelan-
guageareoperators.Eachhasaprecedenceandanassociativity.This
section is concerned with how operators and operands are put to-
gethertointeractinamannerdesiredbytheprogrammer.
ArithmeticOperators
The arithmetic operators are those used to perform arithmetic
operations.Theseoperatorsare:
+
-
*
/
%
These operators are called binary operators because they are al-
waysusedwithtwooperands.Theseoperandsareplacedoneither
sideoftheoperator.Thesymbol+designatesarithmeticaddition,
and the symbol designates subtraction. The symbols * and /
designate multiplication and division, respectively. These opera-
torsareclearlydifferentfordifferentvariabletypes.Thecompiler
understands these differences and creates correct code for the
operand types involved. The modulus operator % returns the re-
mainderafteranintegerdivision.Themodulusoperatorworksonly
onintegertypes-int,char,andlong.Itcannotbeappliedto
typesfloat,doubleorlongdouble.
Operators and Expressions 25
Twounaryoperatorsare+and.Theseoperatorsareofhigher
precedence than the normal arithmetic operators. They operate on
onlytheoperandwrittentotherightoftheoperatorandaretherefore
calledunary.Theunaryminussigncausesthenegativevalueofthe
operandtobecalculated,andtheunarypositivesigncausesnocal-
culationtotakeplace.
Among the binary operators, *,/, and % have equal prece-
dence,whichishigherthatof+and.Theunaryoperators+and
haveahigherprecedencethan*,/,or%.Thearithmeticoperators
willworkwithanyofthearithmetictypes.Becausetheoperations
neededforanintegeroperationdifferfromthoseneededforthecor-
responding double operation, the compiler will place the proper
arithmeticroutinesinthecodetoperformthespecifiedoperation.
Theconceptofafractionisalmostunknowntoanintegertype.
Ifadivisionoftwointegersisexecuted,theresultisroundedtoward
zero.Therefore,theresultof1/2is0asis9999/10000.Thischarac-
teristicisoftenusedinprogramming.
Theonlywaythatyoucanhandlefractionswithintegeropera-
tionsistomakeuseofthemodulusoperation.Theresultofa %bis
theremainderthatisleftoverafteraisdividedbyb.Themodulus
operationcanprovideinsightintothefractionalvalueofwhatisleft
overafteranintegerdivide.
EXERCISES
1.Writeaprogramthatevaluates
f(x)=X
2
3X+2
forvaluesofXin0X3instepsof0.1.
2.Therootsofaquadraticequationcanbeevaluatedbytheequation
x=(b+sqrt(b
2
4ac))/2a
and
x=(bsqrt(b
2
4ac))/2a
wherethequadraticequationisax
2
+ bx + c = 0.Writeapro-
gramthatwillevaluatetherootsofsuchanequation.Notethatthe
termsqrt(b
2
- 4ac)iscalledthediscriminant.Ifitsargument
26 Chapter 1 Introduction to C
isnotpositive,thesquarerootofanegativenumberisimaginary
andtheequationhascomplexroots.Handlebothrealandcomplex
rootsinyourprogram.
RelationalorLogicalOperators
Therelationaloperatorsareallbinaryoperators.Whencontained
inanexpression,theprogramwillevaluatetheleftoperandandthen
therightoperand.Theseoperandswillbecompared,andifthecom-
parisonshowsthatthemeaningoftheoperatoriscorrect,theprogram
willreturn1.Otherwise,theprogramwillreturna0.Inthevocabu-
laryofC,FALSEisalwayszero.Ifcalculatedbyalogicalexpression,
TRUEwillalwaysbeone.However,iftheargumentofaconditional
expressionisanythingbutzero,itwillrespondasiftheargumentis
TRUE.Inotherwords,FALSEisalwayszeroandTRUEisanything
else.Therelationaloperatorsare:
< (lessthan)
<= (lessthanorequalto)
> (greaterthan)
>= (greaterthanorequalto)
Theseoperatorsallhavethesameprecedence,whichisslightlyhigher
thanthefollowingequalityoperators:
== (isequalto)
!= (isnotequalto)
Thelogicaloperatorsare&&and||.Thefirstoperatorindicatesa
logicalANDandthesecondalogicalOR.AlogicalANDwillreturn
TRUEifbothofitsoperandsareTRUE,andalogicalORwillreturn
TRUE if either of its operands is TRUE.The logicalOR has lower
precedencethanthelogicalAND.TheprecedenceofthelogicalAND
islowerthantheprecedenceoftherelationaloperatorsandtheequal-
ityoperators.
Intheevaluationoflonglogicalexpressions,theprogramstarts
ontheleftsideoftheexpressionandevaluatestheexpressionuntilit
knowswhetherthewholeexpressionistrueorfalse,anditthenexits
theevaluationandreturnsapropervalue.Forexample,supposethere
Operators and Expressions 27
isacharacterc,anditisnecessarytodetermineifthischaracterisa
letter.Insuchacase,thefollowinglogicalexpressionmightbeused:
if(c>=A&&c<=Z||c>=a&&c<=z)
Thelogicalandoperator&&haslowerprecedencethananyofthe
relationaloperators,sotherelationalexpressionswilleachbeevalu-
atedpriortothe&&operations.Ifuponenteringthisexpression,cis
equaltothecharacter5,whichisarithmeticallysmallerthanany
oftheletters,thefirsttermc>= A willbeFALSE.Therefore,the
result of the first logical and expression is known to be FALSE
without evaluating the term c <=Z. The evaluation will then
skiptothethirdtermc>= a,andthetermc<=Zwillnotbe
evaluated. In this case, the character 5 will be smaller than the
characterasothatthesecondandexpressionwillalsobeFALSE.
Therefore,thelogicalvaluewillbeknownafterevaluationofonly
twoofthelogicaltermsoftheargumentratherthanhavingtoevalu-
ateallfouroftheterms.
EXERCISES
1.Writeafunctionthatconvertsacharacterthatisalettertolower
case.
2.Leapyearsoccureveryfouryearsunlesstheyearhappenstobe
divisibleby100.Anyyeardivisibleby400isaleapyear,however.
WritealogicalexpressionthatwillreturnTRUEifthegivenyear
isaleapyearandFALSEifitisnot.
TypeConversionsWithinExpressions
Impliedinourearlierdiscussionsonvariabletypes,differentdata
typesnotonlyoccupydifferentwidthinmemory,somemaybecom-
pletelyincompatiblewhenattemptingtoexecuteoperationsinvolving
mixeddatatypes.Inearlierlanguages,itwasuptotheprogrammer
toguaranteethatthedatatypesinvolvedwithanoperationwerethe
same.Cresolvesthisproblem,andthecompilerwillselecttheproper
datatypetocompleteoperationsonmixeddatatypes.
Eachdatatypehasanimpliedwidth.Whenanoperationistobe
executedonmixeddatatypes,thewidthsofthetwotypesareevalu-
ated, and the lesser width operand is promoted to the type of the
28 Chapter 1 Introduction to C
greaterwidthoperandpriortoexecutionoftheoperation.Thus,if
theprogramcalledford=a*b,wheredisoftypelong,ais
typeint,andbistypelong,awillbeconvertedtothetypelong
priortothemultiplication.
Thislogiccarriesovertomixingoffloatanddoubletypes
aswell.Ifforexampleaprogramcalledforthedivisiona/bwhere
a isofthetypeint andb isofthetypedouble,theprogramwould
convertatothetypedoublebeforeexecutionofthedivide.
Theremightbetimeswhentheprogrammerwillwanttochange
thetypeofavariable.Cprovidesacastoperatorwhichforcesthe
program to convert the type of a variable to a different type.This
unaryoperatorhastheform.
(typename)expression
where the results of the evaluation of the expression will be con-
vertedtothenamedtypecontainedwithintheparenthesespreceding
theexpression.
BitwiseOperators
Operatorsthatworkontheindividualbitswithinavariableare
calledbitwiseoperators.Followingisatableofalloftheseopera-
tors:
& bitwiseAND >> rightshift
| bitwiseInclusiveOR << leftshift
^ bitwiseExclusiveOR ~ onescomplement
Thefirstthreebitwiseoperatorsaretraditionalbinaryoperators.
Thesebinaryoperatorsoperateinintegertype(char,int,long,
etc.)operands,andthetwooperandsmustbeofthesametype.
IfabitwiseANDisexecuted,thoselocationsintheresultwhere
bothoperandshavebitvaluesof1willhaveavalueof1.Allother
locationswillbe0.ForabitwiseinclusiveOR,eachbitinthe
resultwillbe1wheneitherorbothoperandbitsare1.Alllocations
where both operand bits are 0 will be 0. The exclusiveOR is
similartoanadditionwithnocarry.Wheneverthebitsintheoper-
andsaredifferent,theresultbitwillbe1.Ifbothoperandbitsarethe
same,eitherbothbits1orbothbits0,theresultwillbe0.
Operators and Expressions 29
Therightshiftoperatorandtheleftshiftoperatorarealsobi-
naryoperators.Herethetypesoftheoperandsneednotbethesame.
Theexpression
x>>3
causesthevariablextobeshiftedtotherightbythreebitspriortoits
use.Likewise,
y<<5
willcauseytobeshiftedtotheleftbyfivebits.Inallnumbersys-
tems,aleftshiftbyonedigitcorrespondstoamultiplicationbythe
number base. Similarly, a shift to the right by one digit causes a
divisionbythenumberbase.Weareusingthebinarysysteminthis
case,soashiftleftbyonebitcausesthenumbertobemultipliedby
two. Unlike most number systems, the binary system (or twos
complementsystem)allowsthesignofthenumbertobecontained
in the binary representation of the number itself. These consider-
ations lead to two different types of shifts for a system of binary
numbers.Ashiftinwhichbitsvacatedbytheshiftarereplacedby
zerosiscalledalogical shift.Allleftshiftsarelogicalshifts.Asthe
shift progresses toward the left, bits that fill the number from the
rightwillallbezero.Bitsthatshiftoutofthenumberontheleftside
arelost.Arightshiftcanbeeitheralogicaloranarithmetic shift.If
thetypebeingshiftedissigned,thesignbitwhichistheleftmost
bitwillpropagate,retaininganumberofthesamesign.Thisisan
arithmetic sign. If the number being shifted is unsigned, zeros are
filledintothenumberfromtheleftastheshiftproceeds.Inallcases,
bits shifted out of a number by a shift operation will be lost. The
onescomplementoperator~isaunaryoperatorthatcausesthebits
inavariabletobereversed.Every1isreplacedbya0,andevery0is
replacedbya1.ThebitwiseAND andORoperationsareusedtoturn
bitsonandoff.Supposethatwehaveacharactervariabler,andwe
wishtoturntheleastsignificantthreebitsoff.Try
r=r&~7;
Inthiscase,thenumber7haseachoftheleastsignificantbitsturned
onor1.Therefore,theterm~7hasallofthebitsinthenumberbut
theleastsignificantturnedonandthesethreebitsareturnedoffor0.
30 Chapter 1 Introduction to C
When this mask isANDed with r, all of the bits of r, with the
exceptionoftheleastsignificantthreebits,willbeANDedwitha1,
and these bit values will remain unchanged. The least significant
threebitswillbeANDedwith0andtheresultinthesethreebitswill
be0.ThebitwiseORwillturnbitson.Supposeyouwantedtoturn
bits2and3ofraboveon.Hereyouwoulduse
r=r|0x0c;
The hexadecimal number 0x0c is a number that has bits 2 and 3
turnedonandallotherbitsturnedoff.ThisORoperationwillleave
bits2and3onandallotherbitswillremainunchanged.Suppose
thatyouwanttocomplementabitinavariable.Forexample,bit0of
the memory location PORTA must be toggled each time a certain
routineisentered.Theexpression
PORTA=PORTA^1;
willperformthisoperation.Allofthebitsexceptforbit1ofPORTA
willremainunchangedbecausetheexclusiveORofanybitwitha0
willnotchangethebitvalue.However,ifbit1is1inPORTA the
exclusiveORwillforcethisbitto0.Ifthisbitis0,theexclusiveOR
willforcethisbittoa1.Therefore,theaboveexpressionwillcomple-
mentbit0ofPORTAeachtimeitisexecuted.
Thebitwiseoperators&,|,and ^areoflowerprecedence
thantheequalityoperators,andhigherprecedencethanthelogical
ANDoperator.Thebitshiftoperatorsareofthesameprecedence,of
lowerprecedencethanthearithmeticoperators+and-,andofhigher
precedencethantherelationaloperators.
Increment and Decrement Operators
WhentheClanguagewaswritten,everyeffortwasmadetowrite
alanguagethatisconciseandyetunambiguous.Severalpowerful
short-handoperatorswereincludedinthelanguagethatwillshorten
theprogram.Theincrementanddecrementoperatorsareexamples
ofsuchshort-handoperators.Intheexamplesearliertherewerein-
stancesofexpressionssuchas
i=i+1;
Increment and Decrement Operators 31
Heretheivaluestoredinmemoryisreplacedbyonemorethanthe
value found there at the beginning of execution of the expression.
TheCexpression
++i;
willdoexactlythesamething.Theincrementoperator++causes1
tobeaddedtothevalueinthememorylocationi.Thedecrement
operator--causes1tobesubtractedfromthevalueinthememory
location.Theincrementanddecrementoperatorscanbeeitherpre-
fixorpostfixoperators.If,likeabove,the++operatorprecedesthe
variable, it is called a prefix operator. If the variable is used in an
expression,itwillbeincrementedpriortoitsuse.Forexample,sup-
posei=5.Thentheexpression
j=2*++i;
willleavea12forthevaluejand6fori.Ontheotherhand,ifi
againis5,theexpression
j=2*i--;
willleaveavalueof10forjand4forI.
Aneasywaytoseehowthepreincrementandthepostincrement
worksisasfollows:Supposethatyouhaveapairofstatements
j=j+1;
<statementwithj>
Thesestatementscanbereplacedwith
<statementwith++j>
Thepreincrementmeansthatyoushouldreplacejwithj+1before
youevaluatetheexpression.Likewisethestatements
<statementwithj>
j=j+1;
canbereplacedwith
<statementwithj++>
withthepostincrement,youshouldevaluatetheexpressionandthen
replacejwithj+1.
32 Chapter 1 Introduction to C
Oftensomebodywillwonderwhatwillhappenifyouhavemul-
tiple increments, either pre or post, of a variable within a single
expression.Thereisaneasyanswerforthatquestion.Donotdoit.
Thestandardprovidesthatbetweensequencepoints,anobjectshall
haveitsvaluemodifiedatmostonceandthepriorvalueoftheobject
shallbeaccessedonlytodetermineitsvalue.Interpretationsofthe
aboverequirementsdisallowstatementssuchas
j=j++;
or
a[j]=j++;
or
m=j+++++j;
AssignmentOperators
AnothershorthandthatwasincludedinCiscalledtheassign-
ment operator. When you are programming, you will find that
expressionssuchas
i=i+2;
or
x=x<<1;
areusedoften.Almostanybinaryoperatorcanbefoundontheright
sideoftheexpression.AspecialsetofoperatorswascreatedinCto
simplifytheseexpressions.Thefirstexpressioncanbewritten
i+=2;
andthesecond
x<<=1;
These expressions use what is defined as an assignment operator.
Theoperatorsthatcanbeusedinassignmentoperatorsare
+ >>
- <<
* &
Increment and Decrement Operators 33
/ ^
% |
Ifyouhavetwoexpressionse1ande2,andlettheoperand$repre-
sentanybinaryCoperator,then
e1$=e2;
isequivalentto
e1=(e1)$(e2);
Theprecedenceofalloftheoperatorassignmentsarethesameand
lessthantheprecedenceoftheconditionaloperatordiscussedinthe
next section. These operators assignments and the = operator are
associatedfromrighttoleft.
TheConditionalExpression
Anothercodesequencefoundfrequentlyis
if(exp1)
exp2;
else
exp3;
Thelogicalexpressionexp1isevaluated.IfthatexpressionisTRUE,
exp2isexecuted.Otherwise,exp3isexecuted.Inthecompactno-
tationofC,theabovecodesequencecanbewritten
exp1?exp2:exp3;
Thisexpressionisreadifexp1isTRUE,executeexp2.Otherwise,
executeexp3.Anotherwayofstatingthisisthatifexp1isTRUE,
thevalueoftheexpressionisexp2;otherwisethevalueoftheex-
pressionisexp3.
Theconditionalexpressionisfoundofteninmacrodefinitions,
whichwelldiscusslater.
EXERCISES
1.Writeaprogramtodetermineifanumberisevenorodd.
2.Writeafunctionthatdeterminesthenumberofbitsinaninteger
onyourmachine.
34 Chapter 1 Introduction to C
3.Writeaprogramthatwillrotatethebitsinthenumber0x5aa5to
the left by n bits.A rotate differs from a shift in that the most
significantbitwillbeshiftedintotheleastsignificantbitduring
therotation.Ashiftmerelyshiftszerosintotheleastsignificant
bit.
4.Anarithmeticrightshiftpropagatesthemostsignificantbittothe
rightwhenthenumberisshiftedright.Ifzerosareshiftedintothe
mostsignificantbit,theshiftiscalledalogicalrightshift.Writea
programthatdetermineswhetheryourcompilerimplementsalogi-
calorarithmeticrightshiftwiththeoperator>>withbothsigned
andunsignedarithmetic.
5.Writeafunctionupper(c)thatreturnstheuppercaseletterifthe
charactercisalowercaseletter.Otherwiseitshallreturnthechar-
acterc.
6.Ifyouusedtheif()elseconstructinproblem4,rewritethefunc-
tiontousetheconditionalexpression.
Precedence and Associativity
Hereisasummaryoftherulesofbothprecedenceandassocia-
tionofallCoperators.Thehigheranoperatorfallsinthetable,the
higheritsprecedence.Operatorsthatfallonthesamelineareallof
the same precedence.All symbols used in C are operators.There-
fore,theoperator()referstotheparenthesesenclosingthearguments
toafunctioncall.Theoperator[]referstothebracketsenclosingthe
argumentofanarray.Theperiodoperator.andthecommaoperator,
will both be discussed when introduced. Likewise, the -> and the
sizeofoperatorswillbeintroducedlater.
Operator Associativity
()[]->. lefttoright
!~+++-*&(type)sizeof righttoleft
*/% lefttoright
+ - lefttoright
<<>> lefttoright
Precedence and Associativity 35
<<=>=> lefttoright
==!= lefttoright
& lefttoright
^ lefttoright
| lefttoright
&& lefttoright
|| lefttoright
?: righttoleft
=+=-=*=/=%=&=^=|=<<=>>=righttoleft
, lefttoright
Notetheveryhighprecedenceoftheparenthesesandthesquare
brackets.Itisthehighprecedenceoftheseoperatorsthatallowsthe
programmertoforceoperationsthatarenotinlinewiththenormal
precedence of the language.The second highest precedence is the
listofunaryoperators.Theseoperatorsareallassociatedfromright
toleft.
EXERCISES
1.WhichofthefollowingwordsarevalidnamesforuseinaCpro-
gram?
able toots
What_day_is_it WindowBar
_calloc 8arnold
Hurting? value
constant Constant
sizeof continue
2.Writeaprogramtoevaluatetheconstant
(1.0377x107+3.1822x103)/(7.221x104+22.1x106)
Theanswerwillbe0.468162.
3.Writeafunctionthatraisestheintegerxtothepowern.Namethe
function x_to_the_n, and write a program that evaluates
x_to_the_nforseveraldifferentvaluesofbothxandn.
36 Chapter 1 Introduction to C
4.Writeaprogramthatwillexamineaspecifiedyearanddetermine
ifitisaleapyear.
5.Writeaprogramthatwillcountthenumberofdigitsinaninput
file.Recordandprintoutthenumberofoccurrencesofeachdigit.
6.InCthetermwhitespacereferstotheoccurrenceofaspace,a
tabcharacter,oranewlinecharacter.Writeaprogramthatwill
evaluatethenumberofwhitespacecharactersinaninputfile.
ProgramFlowandControl
Program flow and control comprise several different means to
controltheexecutionofaprogram.Loopingconstructs,forexample,
controltherepeatedexecutionofaprogramsegmentwhileadjusting
parametersusedintheexecutionateitherthebeginningortheendof
the loop.Two way branches are created by if/else statements,
andthechoiceofoneofmanyoperationscanbeaccomplishedwith
theelseiforswitch/casestatements.Thefollowingpara-
graphswillprovideaquicklookateachoftheseprogramflowand
controlmethods.
TheWhileStatement
TherearethreeloopingconstructsavailabletotheCprogrammer:
the while() statement, the for(;;) statement and the do/
while()statement.Thefollowingprogramdemonstratestheuseof
thewhileloopingconstructalongwithsomeotherconcepts.Wehave
seenthewhilestatementearlier,butthefollowingprogramwillpro-
videanewlookatitsuse.
#include<stdio.h>
intmain(void)
{
intguess,i;
i=1;
guess=5;
while(guess!=i)
{
Program Flow and Control 37
i=guess;
guess=(i+(10000/i))/2;
}
printf(Thesquarerootof10000is
%d\n,guess);
return0;
}
Asinthefirstexample,the#includestatementisusedtobring
standard input/output features into the program, and the program
startswiththefunctiondefinitionmain().Insideofthemainpro-
gram,thefirststatementis
intguess,i;
Thisstatementdefinesthevariablesguessandiasintegers.No
valueisassignedtoiatthistime,butaspaceinmemoryisallocated
toguessandiandthespaceissufficienttostoreaninteger.The
firstexecutablestatementintheprogramis
i=1;
Thisstatementiscalledanassignmentstatement.Theequalsignhere
is a misnomer. The statement is read replace the contents of the
memorylocationassignedtoiwitha1.Thenextstatement
guess=5;
assignsavalue5tothevariableguess.Thestatement
while(guess!=i)
invokesaloopingoperation.Thewhileoperationwillcausethe
statementfollowingtoexecuterepeatedly.Atthebeginningofeach
loopexecution,thewhileargumentguess!=iischecked.This
argumentisreadguessisnotequaltoi.Solongasthisargumentis
TRUE,thestatementfollowingthewhilewillbeexecuted.When
guess becomesequaltoi,thestatementfollowingthewhile will
beskipped.
Thewhileisfollowedbyacompoundstatementthatcontains
twostatements:
{
i=guess;
38 Chapter 1 Introduction to C
guess=(i+(10000/i))/2;
}
ThiscalculationisknownasaNewtonloop.Itstatesthatifiisa
guessatthesquarerootof10000,then(i+(10000/i))/2isa
better guess.The loop will continue to execute until i is exactly
equaltoguess.Atthistimethecompoundstatementwillbeskipped.
Whenthestatementfollowingthewhileisskipped,program
controlispassedtothestatement
printf(Thesquarerootof10000is%d\n,guess);
Thisstatementprintsoutthevalueofthelastguess,whichwillbe
thesquarerootof10000.
TheForLoop
Manytimes,asequenceofcodelike
statement1;
while(statement2)
{
.
.
.
statement3;
}
willbefound.Thisexactsequencewasseenintheaboveexample.
Thereisashorthandversionofthissequencethatcanbeused.Itisas
follows:
for(statement1;statement2;statement3)
Theforconstructtakesthreearguments,eachseparatedbysemi-
colons.Inoperation,theforconstructiscompiledexactlythesame
astheabovesequence.Inotherwords,statement1isexecuted
followedbyastandardwhilewithstatement2asitsargument.
Thecompoundstatementthatfollowswillhavestatement3placed
atitsend,sothatstatement3isexecutedjustpriortocompletion
ofthestatementfollowingthewhileconstruct.Theforconstruct
canbeusedtowritetheaboveprograminthefollowingmanner:
#include<stdio.h>
Program Flow and Control 39
intmain(void)
{
intguess,i;
for(i=1,guess=5;i!=guess;)
{
i=guess;
guess=(i+(10000/i))/2;
}
printf(Thesquarerootof10000=
%d\n,guess);
return0;
}
Recallthattheforallowsthreearguments.Notallarguments
arenecessaryforproperexecutionofthefor.Inthiscase,onlytwo
argumentsareincluded.Thefirstargumentisreallytwoinitializa-
tion arguments separated by a comma operator.When the comma
operatorisused,thestatementsseparatedbycommasareeachevalu-
ateduntilthesemicolonisfound.Atthistime,theinitializationis
terminated.Bytheway,thecommaoperatorcanbeusedinnormal
code sequences so that you can string several statements in a row
withoutseparatingthemwithsemicolons.Thesecondargumentof
theforconstructisi!=guess.Theforloopwillexecuteso
longasthisexpressionisTRUE.Notethatthereisnothirdstatement
intheforinvocation.
Thisargumentiswhereyouwouldnormallyplacethechangein
ithatistotakeplaceattheendofeachloop.Inthiscase,theopera-
tion on i is i=guess. If this expression were used for the third
argument,attheendofthefirstloop,thesecondargumentwouldbe
FALSE,andexecutionofthecalculationwouldbeprematurelyter-
minated.
TheDo/WhileConstruct
Anotherloopingstructureisthedo/whileloop.Recallthatthe
argumentofawhilestatementistestedpriortoexecutingthestate-
ment following. If the argument of the while is FALSE to begin
with,thestatementfollowingwillneverbeexecuted.Sometimes,itis
40 Chapter 1 Introduction to C
desiredtoexecutethestatementatleastoncewhethertheargumentis
TRUEornot.Insuchacase,theargumentshouldbetestedattheend
oftheloopratherthanatthebeginningaswiththewhile.Thedo/
whileconstructaccomplishesthisoperation.Theconstructionofa
do-whileloopisasfollows
.
.
do
{
.
.
.
}while(expression);
.
Theprogramwillenterthedoconstructandexecutethecodethat
follows up to the while statement.At that time, the expression is
evaluated.IfitisTRUE,programcontrolisreturnedtothestatement
followingthedo.Otherwise,iftheexpressionevaluatestoFALSE,
controlwillpasstothestatementfollowingthewhile.Noticethat
thereisasemicolonfollowingthewhile(expression).Thissemi-
colonisnecessaryforcorrectoperationofthedo-whileloop.
The following function converts the integer number n into the
correspondingASCII string. The function has two parts: the first
partconvertsthenumberintoanASCIIstring,buttheresultisback-
wardinthearray;thesecondpartreversesthedatainthearrayso
thattheresultiscorrect.
/*convertapositiveintegertoanASCIIstring;
validforpositivenumbersonly*/
voiditoa(unsignedintn,chars[])
{
inti=0,j=0,temp;
/*convertthenumbertoASCII*/
do
{
Program Flow and Control 41
s[i++]=0+n%10;
n/=10;
}while(n!=0);
s[i]=0;/*makethearrayastring*/
/*butitisbackwardsinthearrayreverse
t*/
i;/*dontswaptheNULL*/
while(i>j)
{
temp=s[j];
s[j++]=s[i];
s[i--]=temp;
}
}
Thefunctionusesthreeintegervariables.Thevariablesiandj
arebothinitializedtozero,andthevariabletempdoesnotneedto
beinitialized.Thefirstportionoftheprogramcontainsado-while
loop.Within this loop, the number is converted into a string. The
statement
s[i++]=0+n%10;
firstcalculatesthevalueoftheintegermodulo10.Thisvalueisthe
numberof1sinthenumber.Addingthatvaluetothecharacter0
willcreatethecharacterthatcorrespondstothenumberof1s.This
value is stored in the location s[i] with i=0 and then i is
incremented.
Thesecondstatementintheloopreplacesnwithndividedby
10.This code removes any 1s that were in the number originally,
andnowtheoriginal10sareinthe1sposition.Sincethisdivisionis
anintegerdivision,iftheresultisbetween0and1itwillberounded
to0.Therefore,thetestinthewhileargumentallowstheabovetwo
statementstorepeatuntiltheoriginalnumbernisexhaustedbyre-
peateddivisionsby10.
Whenthedo-whileloopiscompleted,s[i]willbethecharac-
terimmediatelyfollowingthestringofcharacters.Astringiscreated
byplacinga0oranullinthislocationofthearray.
42 Chapter 1 Introduction to C
Toreversethedata,theprogramstartsbydecrementingisothat
s[i],thelastentryinthearray,isthemostsignificantcharacterin
thenumber,anditmustbeplacedinthefirstarraylocations[0]:.
Likewise,thecharacterins[0]mustbeplacedins[i]:andso
forth.Thewhileloopthatfollowsaccomplishesthisrequirement.
EXERCISES
1.Writeaprogramatoi(s[])thatstartswithacharacterstring
andconvertsthisstringtoanint.Assumethatthestringcontains
nosign.
2.Writeaprogramthatreadsatextfileonecharacteratatimeand
countsthenumberofwordsinthefile.
TheIf/ElseStatement
Theif/elsestatementhasthegeneralform
if(expression)
statement1;
else
statement2;
Ifthelogicalevaluationoftheexpressionthatistheargumentofthe
ifisTRUE,statement1willbeexecuted.Afterstatement1
is executed, program control will pass to the statement following
statement2,andstatement2willnotbeexecuted.Iftheevalu-
ationofstatementisFALSE,statement2willbeexecuted,and
statement1willbeskipped.Theelsestatementisnotneces-
sary.Ifthereisnoelsestatement,theexpressionisevaluated.Ifit
isTRUE,statement1willbeexecuted.Otherwise,statement1
willbeskipped.Thefollowingprogramdemonstratestheuseofthe
if/elseflowcontrolmethod.
/*countnumberofdigitsandothercharactersin
input*/
#include<stdio.h>
intmain(void)
Program Flow and Control 43
{
intc,nn,no;
no=0;
nn=0;
while((c=getchar())!=EOF)
if(c>=0'&&c<=9')
nn++;
else
no++;
printf(Digits=%d and other characters=%d\n,nn,no);
return0;
}
Thestatement
intc,nn,no;
declaresthethreevariablesc,nn, andnotobeintegers.Youmay
declareasmanyvariablesasyouwishwithasingledeclarationstate-
ment.Thenextstatements
no=0;
nn=0;
initializethevaluesofnoandnnto0.Variablesdeclaredwiththe
abovesequenceofinstructionsareautomaticvariables.Thesevari-
ablesarenotinitializedbythecompiler,andtheprogrammermust
initializethemtoarequiredvalue.Otherwisethevariableswillcon-
taingarbage.
Thecodesequence
while((c=getchar())!=EOF)
if(c>=0'&&c<=9')
nn++;
else
no++;
comprisethewhileanditsfollowingstatement.Theifportionof
the statement tests the value ofc and determines if it is a digit.A
characterconstantisidentifiedasaspecificvaluebyplacingthechar-
acter value in single quotes. Therefore, the expression c>=0'
determinesifthecharacterinthelocationcisgreaterthanorequal
44 Chapter 1 Introduction to C
tothecharacter0.Ifitis,theresultofthisexpressionisTRUE.Oth-
erwise,theresultisFALSE.Theexpressionc<=9'determinesif
theinputcharacterislessthanorequaltothecharacter9.Ifbothof
theselogicalexpressionsareTRUE,thentheANDofthetwowillbe
TRUE,andthestatementnn++willbeexecutedtocountthenum-
bersfoundintheinputstream.Programcontrolwillthenskiptothe
endoftheifstatementandcontinuetoexecutethewhileloop.If,
on the other hand, either of these expressions is FALSE, then the
ANDofthetworesultswillbeFALSEandthestatementno++will
beexecuted.Thisstatementkeepscountofthenumberofcharacters
thatarenotdigitsfoundintheinputstream.
Attheconclusionoftheprogram,thegetchar()willreturn
anEOF characterandtheprogramwillfalloutofthewhile loop.It
willthenexecutethefollowingstatement:
printf(Digits=%dandothercharacters=%d\n,nn,no);
Thestringcontainedwithinthedoublequotesinthisargumentcauses
acombinationoftextpluscalculatedvaluesofvariablestobeprinted
out.Supposethattheprogramfound51numbersand488otherchar-
acters.Theprintoutfromtheprogramwouldthenbe:
Digits=51andothercharacters=488
Each%disassociatedwithitscorrespondingargumentandconverted
toanumericalvaluebeforeitissenttothescreen.
TheIf-ElseIfStatement
Sometimesitisnecessarytoselectamongseveralalternatives.
One of the methods that C offers is the if-elseif sequence.
Examine the following program that counts the number of occur-
rencesofeachvowelinaninput.Theprogramalsocountsallother
charactersfoundintheinput.
/*Countthenumberofoccurrencesofeachvowel
foundinaninputandalsocountallothercharac-
ters.*/
#include<stdio.h>
intmain(void)
Program Flow and Control 45
{
intna=0,ne=0,ni=0,no=0,nu=0;
intnother=0,c;
while((c=getchar())!=EOF)
if(c==A||c==a)
na=na+1;
elseif(c==E||c==e)
ne=ne+1;
elseif(c==I||c==i)
ni=ni+1;
elseif(c==O||c==o)
no=no+1;
elseif(c==U||c==u)
nu=nu+1;
else
nother=nother+1;
printf(As=%d,Es=%d,Is=%d,Os=%d,Us=%dand
Others=%d\n,na,ne,ni,no,nu,nother);
return0;
}
ThisprogramshowsseveralnewfeaturesofC.Thefirstisfoundin
theprogramlines
intna=0,ne=0,ni=0,no=0,nu=0;
intnother=0,c;
Whenthevariablesnaandsofortharedefined,theyareassigned
initial values of 0. Such an initialization is always possible when
variablesaredefined.Thenextstatementoftheprogramis
while((c=getchar())!=EOF)
if(c==A||c==a)
na=na+1;
elseif(c==E||c==e)
ne=ne+1;
elseif(c==I||c==i)
ni=ni+1;
elseif(c==O||c==o)
no=no+1;
elseif(c==U||c==u)
46 Chapter 1 Introduction to C
nu=nu+1;
else
nother=nother+1;
Thissinglestatementhasquiteafewlinesofcodeassociatedwithit,
andtherearesomenewconceptshere.First,theargumentsoftheifs
arecombinationsoftwologicalexpressions.Theexpression
c==A||c==a
saysthatifc isequaltouppercaseaORifcisequaltolowercase
atheargumentisTRUE.Theverticalbars||arethelogicalopera-
torOR.
Thefirstifstatementisevaluated.IfitsargumentisTRUE,the
statementfollowingtheifisexecutedandprogramcontrolmoves
totheendoftheifstatements.Otherwise,thefirstelseifstate-
mentargumentisevaluated.IfthisargumentisTRUE,thefollowing
statementisexecutedandprogramcontrolmovestotheendofthe
ifstatements.Thisprocessisrepeateduntiloneoftheargumentsis
foundtobeTRUE,oralloftheelseifstatementsareevaluated.
Atthattime,thefinalstatementfollowingtheelseentryisevalu-
ated.Thefinalelseisnotrequired.
In the above statement, please note that the while statement
itselfandallthatfollowsitformasinglestatementtothecompiler.
Likewise, the combination of all of the if-ifelse constructs
also form a single statement. Furthermore, each of the statements
followingeitheraniforanifelseformsinglestatements.The
formattingofthisstatementhelpsyouunderstandwhatisgoingon,
butremember,theformatofsuchastatementiscompletelyuptothe
programmer.Thelanguageiscompletelyfreeformat.Thewhile
statementaboveanditsstatementfollowingisindeedconfusingto
observe,andprobablytheonethingthattheprogrammercandoto
reducetheconfusionistoblockthestatementsfollowingboththe
while and the if and else key words. In this case the while
statementwouldlooklike
while((c=getchar())!=EOF)
{
if(c==A||c==a*
{
Program Flow and Control 47
na=na+1;
}
elseif(c==E||c==e)
{
ne=ne+1;
}
elseif(c==I||c==i)
{
ni=ni+1;
}
elseif(c==O||c==o)
{
no=no+1;
}
elseif(c==U||c==u)
{
nu=nu+1;
}
else
{
nother=nother+1;
}
}
Thisblockofsourcecodeislongerthantheoriginalform,butit
isexactlythesametothecompiler.Thiscodeisindeedlongerthan
theoriginalform,butitisalsomuchlessopentomisinterpretation
andmisunderstanding.Writingcodethatcannotbemisinterpretedis
asmuchtheresponsibilityoftheprogrammeraswritingcodethat
works.Therefore, when writing production code, you should seri-
ouslyaimtogeneratecodethatisnotopentoanymisinterpretation,
eventhoughitwillmakeyoursourcecodesomewhatlonger.Usu-
allywhenyouwritecodethatiseasytomaintain,itwillnotaffect
thesizeofyourobjectcode.
Theprintffunctioncall
printf(As=%d,Es=%d,Is=%d,Os=%d,Us=%dand
Others=%d\n,na,ne,ni,no,nu,nother);
48 Chapter 1 Introduction to C
hasthenormalprintfarguments.Notehoweverthatthestringis
notconfinedtooneline.Ccompilerswillnotallowastringtobe
splitamongseverallinesinaprogram.However,anANSICcompli-
antcompilerwillcausetwoadjacentstringstobeconcatenatedinto
asinglestring,sotheabovecodewillcompilewithouterror.
Break,continue,andgoto
These commands will cause a C program to alter its program
flow.Ifabreakstatementisencountered,theprogramwillexitthe
loopinwhichitisexecuting.Breakcanbeusedtoexitfor,while,
do-while,andswitchstatements.Anexampleoftheuseofthe
breakstatementisshowninthenextsection.
The continue statement causes the next iteration of a for,
while, or a dowhile loop to be started. In the case of the for
statement,thelastargumentisexecuted,andcontrolispassedtothe
beginningoftheforloop.Forboththewhileandthedo-while,
theargumentofthewhilestatementistestedimmediately,andthe
programproceedsaccordingtotheresultofthetest.
The break statement is seen frequently, and the continue
statementisrarelyused.Anotherstatementthatisevenmorerarely
used is the goto. In C, the programmer can create a label at any
locationbytypingthelabelnamefollowedbyacolon.Ifitisneces-
sary, the goto<label> can be used to transfer control of the
programfromonelocationtoanother.Ingeneral,Cprovidesenough
structuredlanguageformsthattheuseofthegoto<label>se-
quence will rarely be needed. One place where the goto can be
usedeffectivelyiswhentheprogramisnesteddeeplyandanerroris
detected.Insuchacase,thegotostatementisaneffectivemeansof
unwindingtheprogramfromadeeplooptoanouterlooptoprocess
theerror.Ingeneral,youshouldavoidgotostatementswhenever
possible.
Thatsaid,thereisanexcellentalternativetoagoto.Thereach
ofagotoislimitedtothefunctioninwhichitisdefined.Infact,the
reach should probably be confined to the block in which it is de-
fined. Since new variables can be defined at the beginning of any
block,undefinedbehaviorcanbeintroducedwhenagotobranches
intoablockwherenewvariableshavebeendefined.Also,youcan
introduceundefinedbehaviorwhenyoubranchoutofablockwhere
Program Flow and Control 49
variableshavebeendefined.Inbothcases,thebranchisaroundop-
erationsofdefiningordeletinglocalvariables.Thealternativeisto
makeuseofthesetjmp()andlongjmp()functions.
These handy library functions are declared in the setjmp.h
headerfile.Alsodeclaredinthisheaderisatypecalledenv.Inyour
program,youmustdefineanexternalinstanceofenv.Thisparam-
eter is used as an argument to setjmp(). setjmp() saves the
statusofthecomputerintheinstanceofenvwhenitiscalled.When
calledoriginallysetjmp()returnsazerooraFALSE.Thefunc-
tionlongjmp()takestwoarguments.Thefirstistheenvvariable
correspondingtothereturnlocationintheprogram.Thesecondis
anintegerthatisreturned.Executationofthelongjmp()returns
controltowithinthesetjmp()function.Whencontrolisreturned
to the function that called the setjmp() the parameter that was
passedfromthelongjmp()isreturned.Therefore,whencontrol
returnsfromsetjmp()asimpletestdetermineswhetherthefunc-
tionsetjmp()orlongjmp()wascalled.
Thesefunctionsrestorethestatusofthecomputertothatwhich
existedwhenthesetjmp()wascalled.Thisrestorationautomati-
cally unrolls all function calls between the execution of the
setjmp()andthelongjmp().Also,therearenoblockorfunc-
tionlimitsontheuseofthesefunctions.Aslongasenv isaglobally
accessiblevariable,longjmp()canpasscontrolfromanylocation
inaprogramtoanyother.
TheSwitchStatement
Asecondapproachtoselectionbetweenseveralalternatesisthe
switchstatement.Thisapproachissometimescalledtheswitch/case
statement.Followingisaprogramthataccomplishesexactlythesame
astheaboveprogram.Inthiscase,theswitchstatementisused.
/*Countthenumberofoccurrencesofeachvowel
foundinaninputandalsocountallothercharac-
ters.*/
#include<stdio.h>
intmain(void)
{
50 Chapter 1 Introduction to C
intna=0,ne=0,ni=0,no=0,nu=0;
intnother=0,c;
while((c=getchar())!=EOF)
switch(c)
{
caseA:
casea:na=na+1;
break;
caseE:
casee:ne=ne+1;
break;
caseI:
casei:ni=ni+1;
break;
caseO:
caseo:no=no+1;
break;
caseU:
caseu:nu=nu+1;
break;
default:
nother=nother+1;
}
printf(As=%d,Es=%d,Is=%d,Os=%d,Us=%dand
Others=%d\n,na,ne,ni,no,nu,nother);
return0;
}
Thisprogramperformsexactlythesamefunctionastheearlierone.
Thedataarereadinacharacteratatimeasbefore.Here,however,
theswitchstatementisused.Thestatementswitch(c)causesthe
argumentoftheswitchtobecomparedwiththeconstantsfollow-
ingeachofthecasestatementsthatfollows.Whenamatchoccurs,
thenextsetofstatementstofollowacolonwillbeexecuted.Once
theprogramstartstoexecutestatements,allofthefollowingstate-
ments will be executed unless the programmer does something to
causetheprogramtoberedirected.Thebreakinstructiondoesex-
Functions 51
actlythisoperationforus.WhenaCprogramencountersabreak,
it jumps to the end of the current block. Therefore, the breaks
followingtheexecutablestatementsabovewillcausetheprogramto
jumpoutoftheexecutingsequenceandreturntogetthenextcharac-
terfromtheinputstream.
Whenalloptionshavebeenexhaustedwithoutamatch,thestate-
mentsfollowingthedefaultlinewillbeexecuted.Itisnotnecessary
tohaveadefaultline.
EXERCISES
1.Writeaprogramthatcountsthenumberoflines,words,andchar-
actersinaninputstream.
2.Extendtheprogramfromtheexerciseabovetocalculatetheper-
centageusageofeachcharacterinthealphabet.
3.Aprimenumberisanumberthatcannotbeevenlydividedbyany
number.Forexample,thenumbers1,2,and3areallprimenum-
bers.Writeaprogramthatwillcalculateandprintoutthefirst200
primenumbers.
Writethisprogramwithouttheuseofeitheramodulooradivide
operation.
Functions
ThefunctionistheheartofaCprogram.Infact,anyCprogram
ismerelyafunctionnamedmain.Thepurposeofafunctionisto
provideamechanismtoallowasingleentryofacodesequencethat
istoberepeatedmanytimes.Afunctionisthemostreusableelement
intheClanguage.Properlywrittenanddebuggedfunctionscanbe
collectedintoaprogramwhenneeded.Therefore,theuseoffunc-
tionswillallowtheprogrammertowritesmallerprogramsanditis
notnecessarytorewritecommonfunctionsthatareusedoften.
Afunctioncanhavemanyargumentsornonewhatsoever.Func-
tionargumentsarecontainedinparenthesesfollowingthefunction
name. The values of the arguments are the parameters needed to
executethefunction.Afunctioncanreturnavalue,orperhapsitwill
nothaveareturnvalue.Anexampleofafunctionthatreturnsavalue
isgetchar()whichreturnsacharacterfromtheinputstream.
52 Chapter 1 Introduction to C
Afunctionmaynotbenestedinsideanotherfunction.Therefore,
anyfunctionmustbecreatedoutsideoftheboundariesofanyother
functionorprogramstructure.Functionshaveonlyoneentrypoint,
andtheyreturnonlyonereturnitem.Thereturncanbeofanytype
that C supports. Functions can have several arguments. The argu-
mentscanbeofanyvalidCtype.
InANSIC,theuseofafunctionrequirestheuseofafunction
prototype.Afunction prototypeisastatementofthefollowingform:
typefunction_name(type,type,type,...);
The first type preceding the function name is the type to be re-
turnedfromthefunction.Itisalsocalledthetypeofthefunction.
Theseveraltypesfoundintheargumentarethetypesofthecorre-
sponding arguments that are sent to the function.Variable names
mayormaynotbeusedfortheargumentsofafunctionprototype.
Thetypelististheimportantitem.Thetypesintheargumentlistare
separatedbycommas.
Thusfar,itmightseemthatwehavebeenblindlyusingfunctions
likeprintf(),getchar(),andputchar()withouttheben-
efitoffunctionprototypes.Notso!Theheaderfilestdio.hcontains
thefunctionprototypesofallinput/outputrelatedfunctions,soitis
notnecessaryforyoutoputafunctionprototypeinyourcodefor
thesefunctions.Otherlibraryfunctionshavetheirprototypesintheir
ownheaderfiles.
Compilerswilldiffer.Ifaprogrammerattemptstosendthewrong
typeofdatatoafunctionthroughitsargument,thecompilermight
consideritanerrororitmightwellconverttheargumenttothecor-
rect type prior to calling the function. In either case, the compiler
willnotletaprogramusethewrongtypeofdataasanargumenttoa
function.Thestandardallowsthattheparametertypebecorrectedto
the correct type and proceed. Some embedded systems compilers
will require that the type of each parameter be correct before the
programcancompile.
Oneitemthatisimportant.Copiesofparametersarepassedto
anyfunction.Copiesareplacedonthesystemstackorinregistersor
bothbeforethefunctioncallisexecuted.Therefore,theprogramcan
use these parameters in any way without altering the calling pro-
gram.Infact,afteryouhavedonewhatisneededwithaparameter,
youmayusetheparameterasastoragelocationforyourfunction.
Functions 53
Data returned from a function will always be converted to the
correcttypebeforeitispassedbacktotheprogram.Ifyouwishto
haveadifferenttypereturned,thecastoperatorcanbeusedtochange
thereturndatatypetoanytypedesired.
ANSICdefinedthetypevoid.Thistypeisusedinseveraldif-
ferentways.Ifthereisnofunctionreturn,theprototypemustidentify
thefunctionastypevoid.Alsowhentherearenofunction argu-
ments,theargumentlistmustcontainthetypevoid.Thisuseofthe
keywordvoidwillpreventproblemsinfunctioncalls.
Notethatthefunctionprototypeaboveisterminatedwithasemi-
colon.Thesemicolonisneededinthefunctionprototype,butitis
nottobeusedafterthenameofthefunctioninthecodewherethe
function is defined. The function prototype is a declaration state-
ment that merely provides information to the compiler while the
functionprologue,thefirstlineofthefunction,isafunctiondefini-
tionwhichopensthecodeforthefunction.
ThephilosophyinCistousefunctionswithlittleprovocation.
Usingmanyfunctionsproducescodethatiseasytoreadandfollow.
Oftenitiseasiertodebugmanysmallfunctionsratherthanalarger
program.Onemusttempertheseideassomewhatwhenwritingcode
for small microcontrollers. Calling a function requires some over-
headthatisrepeatedeachtimethefunctionisaccessed.Ifthetotal
overheadismorethanthelengthofthefunction,itisbettertouse
in-linecode.In-linecodeimpliesthatthefunctioncodeisrepeated
in-line every time that it is needed. If the function code is much
greater than the calling overhead, the function should be used. In
betweentheselimits,itisdifficulttodetermineahard-and-fastrule.
In microcontroller applications, it is probably best to use function
calls to a single function if there is a net savings of memory as a
result.Thissavingsiscalculatedbyfirstdeterminingthecodeneeded
priortocallingthefunction,thecodeneededtocleanuptheprocess
afterthefunctioncall,thenumberoftimesthefunctioniscalled,and
thelengthofthefunction.Thein-linecodewillbesmallerthanthe
correspondingfunctioncode.Therefore,ifthetotalcodeforthenum-
beroffunctioncallslistedfirstexceedsthetotalin-linecoderequired
toaccomplishthesameoperations,thenusethein-linecode.Other-
wise,usefunctioncalls.
54 Chapter 1 Introduction to C
Theaboveargumentisvalidformicrocontrollerapplicationscode.
Itdoesnotnecessarilyfollowforcodewrittenforlargecomputers.
Whenwritingforalargecomputer,thereareusuallyfewmemory
constraints.Inthosecases,itisprobablybesttousemorefunction
callsandnotbeworriedaboutthememoryspacetakenupbyfunc-
tioncallsunlessthereisaseriousspeedconstraint.Whenspeedisa
problem,theprogrammermustgothroughananalysissimilartothat
abovewiththedependentparameterbeingtimeratherthanmemory
space.Insmallcomputerswhereseveralregisterscanbesavedand
restored when a function is entered and exited, single instructions
canrequiremanyclockcycles.Whendecidingwhethertouseafunc-
tionorin-linecode,theprogrammermustassessthetotaltimelostto
enteringandexitingafunctioneachtimeitisentered,andweight
thattimelostasafractionofthetotaltimetheprogramresidesinthe
function. If this time is large, and the program requires too much
executiontime,considertheuseofin-linefunctions.
Itisalwaysgoodtowritesmallfunctionsandcreatesimplecall-
ing programs to exercise the small functions. These programs are
usedtodebugthefunctions,andtheyarediscardedafterthefunc-
tionsaredebugged.Iflater,theprogramconstraintsdictatethatin-line
codeshouldbeused,theessentialcodeofthefunctioncanbewritten
intotheprogramwhereveritisneeded.Anotherapproachthatwill
bediscussedinthenextchapteristouseamacrodefinitiontospecify
asmallfunction.Withamacrodefinition,thefunctioncodeiswrit-
tenin-linetotheprogramwheneverthefunctionisinvoked.
Letusrevisitanexampleusedearlier.Writeaprogramtocalcu-
lateanddisplaythesquarerootofeachintegerlessthan11:
/*Calculateanddisplaythesquarerootsof
numbers
1<=x<=10*/
#include<stdio.h>
#defineabs(t)(((t)>=0)?(t):-(t))
#definesquare(t)(t)*(t)
doublesqr(double);
intmain(void)
Functions 55
{
inti;
doublec;
for(i=1;i<11;i++)
{
c=sqr(i);
printf(\t%d\t%f\t%f\n,i,c,square(c));
}
return0;
}
/*thesquarerootfunction*/
doublesqr(doublex)
{
doublex1=1,x2=1,c;
do
{
x1=x2;
x2=(x1+x/x1)/2;
c=x1-x2;
}
while(abs(c)>=.00000001);
returnx2;
}
Theresultofthiscalculationisshownbelow:
1 1.000000 1.000000
2 1.414214 2.000000
3 1.732051 3.000000
4 2.000000 4.000000
5 2.236068 5.000000
6 2.449490 6.000000
7 2.645751 7.000000
8 2.828427 8.000000
9 3.000000 9.000000
10 3.162278 10.000000
56 Chapter 1 Introduction to C
Thesecondlineofcode
#defineabs(t)(((t)>=0)?(t):-(t))
iscalledamacrodefinition.Inthiscase,themacrodefinitionhasthe
appearanceofasimplefunction.Thisfunctionwillcalculatetheab-
solutevalueoftheargumentt.Theabsolutevalueoftheargumentis
apositivevalue.Iftheargumentispositive,itisreturnedunchanged.
Ifitisnegative,itismultipliedby1beforeitisreturned.Amacro
definitionisatypeofcharacterexpansion.Wheneverthefunction
abs(x)isfoundinthecode,thecharacterstring(((x)>=0)?
(x):-(x))isputinitsplace.Theargumentxcanbeanyvalid
C expression.This function returns the absolute value of its argu-
ment.Themacrodefinition
#definesquare(t)(t)*(t)
returns the square of t. Since these arguments can be any valid C
expression,itisnecessarytobecautiouswhenwritingthemacrodefi-
nitions. Suppose that the parentheses were left out of the above
expression,andthemacrowerewritten
#definesquare(t)t*t
Alsosupposethatthecodeusingthisfunctionwereasfollows:
x=square(y+3);
Thecharacterexpansionofthisexpressionwouldbe
x=y+3*y+3;
Theresultofthiscalculationis4*y+3andnot(y+3)*(y+3)as
expected.Whenwritingmacrodefinitions,surroundallarguments
andfunctionscreatedbythemacrowithparenthesessothatallargu-
mentsareevaluatedpriortouseinthemacrodefinitionfunction.
Anotherproblemcansneakintoyourcodethroughimproperly
writtenmacros.Supposethatyouwantamacrothatdoublesthevalue
ofitsargument.Suchamacrocouldbewritten
#definetimes_two(x) (x)+(x)
Thismacrowhenexpandedinthefollowingexpression
x=7*times_two(y);
Functions 57
willyield
x=7*(y)+(y);
whichisthewronganswer.Theproblemcanbeeasilycorrectedby
wrappingparenthesesaroundthewholemacroas
#definetimes_two(x)((x)+(x))
Remember,alwaysplaceanyargumentofamacrowithinparenthe-
sesandalwaysplacetheentiremacrodefinitioninparentheses.
Notethatthereisnosemicolonattheendofthemacrodefini-
tion.Thereshouldnotbe.Ifasemicolonwereplacedattheendofa
macro definition, extra semicolons would be entered into expres-
sionscontainingmacroswithunpredictableresults.
Thefunctionprototype
doublesqr(double);
notifiesthecompilerthatthefunctionreturnsadoubleandtakesa
doubleargument.
Insideofthemainfunction,theforloop
for(i=1;i<11;i++)
{
c=sqr(i);
printf(\t%d\t%f\t%f\n,i,c,square(c));
}
isusedtocalculatetheseveralresults.Thevariablecisofthetype
double,andiisan int.Theexpressionc=sqr(i)willbeac-
ceptedbythecompiler.Thisfunctionreturnsadoublewhichcanbe
stored in c.The argument is an int, but the compiler recognizes
that sqr requires a double argument and converts i to a double
beforeitissenttothefunctionsqr().
Thecodeinthefunctionsqr()isarestatementofasquareroot
operation that we saw earlier. In this case, the function processes
floating-point numbers rather than the integers used before.Three
doublevariablesareneeded.Thevariablesx1 andx2 arethecurrent
andlastvaluesfoundintheNewtoniteration.Astheresultconverges
tothecorrectvalueforthesquareroot,severalthingshappen.Vari-
ablesx1andx2becomeequal.Thesquareofx2,orx1forthat
matter,becomesequaltox.Theproductofx1andx2becomes
58 Chapter 1 Introduction to C
equaltox.Anyofthesetestscanbeusedtodetermineiftheesti-
matehasbeenthroughenoughiterationstobeaccurate.
Themacrodefinitionabs(x)isusedtotestfortheendofthe
loop.Youwillnotethattheargumentisevaluatedthreetimesforthe
expansionofthemacro.Ifweplacealotofcalculationwithinthe
argument of a macro definition, the expansion of the macro may
causethecodetocalculatetheargumenttoberepeatedseveraltimes.
Forthisreason,theexpression
c=x1-x2;
isplacedinsideofthewhileloop,andthetesttodetermineloop
terminationusesabs(c).
Attheendofafunction,areturnstatementwillcausethevalue
oftheexpressionfollowingthewordreturntobeevaluatedand
returnedtothecallingfunction.Ifthisexpressionisnotofthetype
specifiedbythefunctionprototype,itwillbeconvertedtothecor-
recttypepriortobeingreturnedtothecallingfunction.Theexpression
followingthereturnstatementcanbeenclosedinparenthesesornot.
Anotherexamplewillshowtheuseofstaticexternalvariables.
/*Readinastringfromthekeyboardandprintit
outinreverseorder.*/
#include<stdio.h>
#definenull0
/*somefunctionprototypes*/
voidpush(int);
intpull(void);
intmain(void)
{
intc;
push(null);
while((c=getchar())!=\n)
push(c);
printf(\n);
while((c=pull())!=null)
Functions 59
putchar(c);
printf(\n);
return0;
}
Thefollowingcodeistobecompiledinaseparatefilefromthecode
above:
/*thestackfunction*/
#defineMAX100
staticintbuffer[MAX];
staticintsp;
voidpush(intx)
{
if(sp<MAX)
buffer[sp++]=x;
else
{
printf(stackoverflow\n);
exit(1);
}
}
/*theunstackingfunction*/
intpull(void)
{
if(sp>0)
returnbuffer[sp];
else
{
printf(stackunderflow\n);
exit(1);
}
}
Astackisalastin,firstout(LIFO)structure.Therefore,astack
canbeusedtoreversetheorderofdatasenttoit.Theaboveprogram
usesastackoperation.Thefunctionspushandpullidentifiedinthe
60 Chapter 1 Introduction to C
function prototypes perform the stacking operations for the main
program.Inthemainprogram,anullispushedontothestackto
identifytheendofthedataasitispulledoffofthestackacharacter
atatime.Dataarereadinacharacteratatime,andaseachcharacter
is read in, it is pushed onto a stack.When a new line character is
detected,theinputphaseisstopped,andthedatawrittentothestack
ispulledoffandprinted.Whenthenullisdetected,thedatahave
allbeenpulledoffthestack,andtheprogramisended.
Inthefunctionabove,thefunctionexit()isused.Thisfunc-
tion is similar to the return operation. Whenever a call to the
functionexitisexecuted,theargumentisevaluated,anyfilesopen
forwriteareflushedandclosed,andthecontrolofthecomputeris
returnedtotheoperatingsystem.Theevaluationoftheargumentis
returnedtotheoperatingsystem.Wheneverareturnisencoun-
tered, the expression following the return call is evaluated and
returnedtothecallingfunction.Ifcontrolisinmain()whenthe
returnisencountered,theevaluationoftheexpressionisreturned
totheoperatingsystem.Also,frommain()allfilesopenforwrite
are flushed and closed.The function exit() and return work
thesameinmain(),butexit()exitsaprogramandreturnscon-
troltotheoperatingsystemfromanywhereintheprogram.
Inaseparatecompilation,thestackfunctionsarecompiled.In
that function, the macro definition MAX is defined as 100. Macro
definitionscanbeusedtodefineanycharacterstringthatisneeded
inaprogram.Theyarenotlimitedtodefiningpseudofunctions.Two
externalvariablesaredefinedinthisfile:anarrayofMAXintegers
namedbufferandanintcalledsp.Thesevariablesaredeclared
tobestatic.Assuch,thesevariablescanbeaccessedbyanyfunction
inthefile,buttheyarenotavailabletoanyfunctionoutsideofthe
file.Thevariablespisusedasanindexintothearraybuffer.When
apushisexecuted,atesttodetermineifspislessthanMAXiscom-
pleted.IfspislessthanMAX,thedataarestoredatthesplocation
inbufferandspisthenincremented.Otherwise,anerrormessage
indicatesthatastackoverflowhasoccurredandtheprogramisex-
ited.
Thepull()functionisthereverseofthepush()operation.
Firstacheckismadetoseeiftherearesomedataonthestacktobe
pulledoff.Iftherearedata,thestackpointerisdecremented,andthe
Recursion 61
contentofthebufferatthatlocationisreturnedtothecallingpro-
gram.Intheeventthatspis0whenthepulloperationisexecuted,a
stack underflow message is sent to the screen prior to exiting the
program.
Theadvantagetoourmakingthebufferandthestackpointerin
thestackfunctionsstaticcanbeeasilyseen.Supposethatthesevari-
ablescouldbeaccessedfromanywhereintheprogram.Inthatcase,
itwouldnotbenecessaryfortheprogrammertocallthefunctions
pushorpulltostackandunstackdata.Ifseveraldifferentpro-
grammerswereusingthesamestackfordifferenttasksinonelarge
program,itwouldbepossiblefordifferentprogrammerstoaccess
thestackasexpected,orfromtheirowntasks.Supposeaprogram-
mer made the mistake of pre-decrementing the stack pointer on
stackingandpost-incrementingthestackpointeronunstacking.The
wholeprogramwouldsuddenlybeinchaos.Therefore,maskingthese
variablesfromtherestoftheprogramcanreduceseriouspotential
debuggingproblems.
Recursion
A recursive routine is one that calls itself. The C language is
supposedtoproducerecursivecode.Compilersforlargemachines
usuallysupportrecursion,butrecursionisoftenoneofthefirstcasu-
altiesonsmallmicrocontrollers.Automaticvariablesarecreatedwhen
a function is entered, and they are stored on the stack. Therefore,
each time a function is called, a new stack frame is created, and
variablesinplacefromanearlierexecutionofthefunctionareunal-
tered.Suchafunctioniscalledre-entrant,andre-entrantfunctions
arealsorecursive.Anexampleofasimplerecursivefunctionisthe
factorial:
n!=n*(n-1)*(n-2)*....*2*1
Aninterestingobservationthatcanbemadeoffactorialisthat
n!=n*(n-1)!
ornfactorialequalsntimesn-1factorial.Also,thefactorialof0is
definedas1.Withthesedefinitions,itispossibletowritethefollow-
ingrecursivefunctiontocalculatethefactorialofanumber:
longfactorial(intn)
62 Chapter 1 Introduction to C
{
if(n==0)
return1;
else
returnn*factorial(n-1);
}
Thissurprisinglysimplefunctioncalculatesthefactorial.When-
ever you write a recursive routine, it is important to have means of
gettingoutoftheroutine.Intheabovecase,whentheargumentreaches
zero,thefunctionreturnsaresultratherthancallingitselfagain.At
that time the routine will work itself back a level at a time until it
reachestheinitialfactorialcall,andthecalculationwillbedone.
Recursioncancreatesomeelegantcodeinthatthecodeisvery
simpleoftentoosimple.Thereisacostintheuseofrecursivecode,
andthatisstackspace.Eachtimeafunctioncallismade,theargu-
mentisplacedonthestackandasubroutinecallisexecuted.Asa
minimum,thereturnaddressistwobytes,andthevalueoftheargu-
mentisalsotwobytes.Thus,atleastfourbytesofstackspaceare
neededforeachfunctioncall.Thatisnoproblemwhenthefactorial
ofasmallnumberiscalculated.(Thefactorialof13islargerthan
canbeheldinalong,soonlysmallnumberscanbeconsideredfor
afactorial.)However,ifarecursivefunctioniswrittenthatcallsit-
selfmanytimes,itispossibletogetintostackoverflowproblems.
Anotherinterestingrecursiveroutineisthefunctiontocalculate
aFibonaccinumber.AFibonaccinumbersequenceisdescribedby
thefollowingfunction:
longfib(intn)
{
if(n==1)
return1;
elseif(n==0)
return1;
else
returnfib(n-1)+fib(n-2);
}
Thissneakyfunctioncallsitselftwice.Someinterestingcharacteris-
ticsofthisfunctionarelefttotheexercisesthatfollow.
Summary 63
EXERCISES
1.WriteafunctiontocalculatetheFibonaccinumberfor10,20,30,
and40.
2.Deviseameansfordeterminingthenumberoftimesthefibfunc-
tion is called in the above program. What is this number for
fib(20)?
3.Aseparateproblemfromthenumberoftimesthefunctioniscalled
isthenumberoftimesthefunctioniscalledwithoutexitingthrough
the bottom of the function. This term is called the depth of the
function.Determinethemaximumdepthofthefib()function
incalculatingfib(20).
4.Repeatproblem1,butrewritetheFibonaccinumberfunctionso
thatitdoesnotemployrecursion.Howdoesthetimetoexecute
thisversionofthefib(30)comparedtothatabove?
Summary
ThebasicsofwritingprogramsinChavebeendiscussedinthis
chapter.Severalimportantconceptshavebeenskippedoverinthis
presentationandwillbecoveredinChapter2.
Ifyouhavenotdoneso,itisrecommendedthatyouenterand
compileeachexampleshown.Theseprogramswillallcompileand
runundertheMIXPowerCCompiler,theCosmiccompilerforthe
M68HC11, the M68HC16, and the M68300 series of chips. They
alsocompileontheDIABMCOREcompiler.Withtheexceptionof
theMIXPowerCcompiler,allofthecompilerslistedarecrosscom-
pilers that run on a PC platform, but compile code for another
computer.
TheANSIversionofthelanguageisthecurrentstandard,and
noneoftheclassicalCconstructshavebeenintroducedinthistext.It
isnottotheprogrammersadvantagetousetheclassicalversionof
thelanguage,eventhoughprogramsthatconformtoclassicalCwill
compileonanANSIcompliantcompiler.AnyversionofaC++com-
pilerstructuredtocompileCcodewillalsocompileANSICcode.
TheDIABcompilerlistedaboveisaC/C++compiler.
[This is a blank page.]
Chapter 2
AdvancedCTopics
Pointers
The use of pointers sets the C language apart from most other
high-levellanguages.Pointers,underthenameofindirect addressing,
arecommonlyusedinassemblylanguage.Mosthigh-levellanguages
completelyignorethispowerfulprogrammingtechnique.InC,point-
ersaresimplyvariablesthataretheaddressesofothervariables.These
variablescanbeassigned,beusedasoperands,andtreatedmuchthe
same as regular variables. Their use, however, can simplify greatly
manyofthetrulydifficultproblemsthatariseinday-to-dayprogram-
ming.Letsdiscusspointerswiththeviewthattheyofferusapowerful
newtooltomakeourprogrammingjobseasier.
HowToUsePointers
Apointertoavariableistheaddressofavariable.Thusfarinour
discussion of variables, the standard variable types were found to
occupy 8-, 16-, or 32 bits depending on the type. Pointers are not
typesinthesenseofvariables.Pointersmightoccupysomenumber
ofbits,andtheirsizeisimplementationdependent.Infact,thereare
casesofpointerstoliketypeshavingdifferentsizesinthesamepro-
gramdependingoncontext.
Ifthevariablepx isapointertothetypeint andx isanint,px
canbeassignedtheaddressofxby
px=&x;
Theampersand(&)notifiesthecompilertousetheaddressofx
ratherthanthevalueofxintheaboveassignment.Thereverseop-
erationtothataboveis
65
66 Chapter 2 Advanced C Topics
x=*px;
Heretheasterisk(*) isaunaryoperatorthatappliestoapointer
anddirectsthecompilertousetheintegerpointedtobythepointer
pxintheassignment.Theunary*isreferredtoasthedereference
operator.Withthesetwooperators,itispossibletomovefromvari-
abletopointerandbackagainwithease.
A pointer is identified as a pointer to a specific type by state-
mentslike
int*px,*pa;
long*pz;
float*pm;
Intheabovedeclarations,eachofthevariablesprecededbythe
unaryasteriskidentifiesapointertothedeclaredtype.Thepointers
px andpaaretheaddressesofintegers.pz istheaddressofalong,
andpmistheaddressofafloatingpointnumber.Alwaysremember:
if pk is a pointer to an integer, *pk is an integer. Therefore, the
declarationsintheaboveexamplesarecorrectanddodefineints,
longsandfloats.However,whenthecompilerencountersthe
statement
int*pi;
itprovidesmemoryspaceforapointertothetypeint,butitdoes
notprovideanymemoryfortheintitself.Supposethataprogram
hasthefollowingdeclaration:
intm,n;
int*pm;
Thestatement
m=10;
pm=&m;
willassignthevalue10tomandputitsaddressintothepointerpm.
Ifwethenmaketheassignment
n=*pm;
thevariablenwillhaveavalue10.
Anotherinterestingfactaboutpointersisshowninthefollowing
example:
Pointers 67
intable[10];
int*p;
Afterithasbeenproperlydeclared,whenthenameableisinvoked
withoutthesquarebrackets,thenameisapointertothefirstlocationin
thearray.Sothefollowingtwostatementsareequivalent:
p=&able[0];
and
p=able;
Ofcourse,thenthelementofthearraymaybeaddressedby
p=&able[n];
Theunarypointeroperatorshavehigherprecedencethanthearith-
meticoperators.Therefore,
*pi=*pi+10;
y=*pi+1;
*pi+=1;
allresultintheintegersbeingalteredratherthanthepointers.Inthe
firstcase,theintegerpointedtobypiwillbeincreasedby10.Inthe
secondcase,ywillbereplacedbyonemorethantheintegerpointed
tobypi.Finally,theintegerpointedtobypiwillbeincreasedby
1.Thestatement
++*pi;
causestheintegerpointedtobypitobeincreasedby1.Both++
andtheunary*associatefromrighttoleft,sointhefollowingcase
*pi++;
thepointerpiisincrementedafterthedereferenceoperatorisapplied.
Therefore,thepointerisincrementedinthiscase,andtheinteger*pi
remainsunaltered.Ifyouwishtopost-incrementtheinteger*pi,use
(*pi)++;
Attimes,itisnecessarytopre-incrementthepointerbeforethe
dereference.Inthesecases,use
*++pi;
68 Chapter 2 Advanced C Topics
Pointersworkwitharrays.Supposethatyouhave
int*pa;
inta[20];
Aswehavealreadyseen,
pa=a;
assignstheaddressofthefirstentryinthearraytothepointerpa
muchthesameas
pa=&a[0];
does.Toincrementthepointertothenextlocationinthearray,you
mayuse
pa++;
or
pa=pa+1;
Inanycase,thepointerthatis1largerthanpapointstothenext
elementinthearray.Thisoperationistrueregardlessofthetypethat
pa points to. If pa points at an integer, pa++ points to the next
integer.Ifpapointsatalong,pa++pointstothenextlong.If
papointstoalongdouble,pa++pointstothenextlongdouble.In
fact,ifpapointstoanarrayofarrays,pa++pointstothenextarray
in the array of arrays. C automatically takes care of knowing the
numberthatmustbeaddedtoapointertopointtothenextelement
inanarray.
In the above case, since a is an array of 20 integers, and pa
pointstothefirstentryinthearray,itfollowsthatpa+1pointsto
thesecondelementinthearray,and pa+2pointstothethirdele-
ment. Similarly, *(pa+1) is the second element in the array and
*(pa+2)isthethirdelement.
Thereisasetofarithmeticthatcanbeappliedtopointers.This
arithmeticisdifferentfromthenormalarithmeticthatcanbeapplied
to numbers. In all cases, the arithmetic applies to pointers of like
typespointingtowithinthesamearrayonly.Whentheseconditions
aremet,thefollowingarithmeticoperationscanbecompleted:
Pointers can be compared. Twopointerstoliketypesinthesame
arraycanbecomparedinaClogicalexpression.
Pointers 69
Pointers can be subtracted.Twopointerstoliketypesinthesame
arraycanbesubtractedwithaCarithmeticexpression.Theresult
ofthesubtractionwillbethenumberofelementsbetweenthetwo
pointers,notthedifferenceinthevaluesofthepointers.
Pointers can be incremented and decremented.Apointerintoan
arraycanbeeitherincrementedordecremented.Theresultwillbe
apointerthatpointstoanadjacentelementinthearray.
Pointers can be assigned. A pointer can be assigned to another
pointerofthesametype.
Pointerscannotbeadded,multiplied,divided,masked,shifted,
or assigned a pointer value of an unlike type. Pointers can be as-
signedtoanotherpointerofthetypevoid*.
Thenameofanarrayisapointertothefirstelementinthisarray.
ThistypeofvariableoccupiesaspecialplaceinC.Thenamecan
alwaysbeusedasapointer,andassignedtoanotherpointer,butit
cannotbeassignedto.Anyattempttoassignanewvaluetothearray
namewouldupsetthebeginningofthearraytotheprogram.
Therefore,anarraynameasapointercanbeusedasavalueon
therightsideofanassignmentequalsign,butitcannotbeusedon
theleftsideoftheequalsign.Cvariablesarebrokenintothetypes
rvalue and lvalue.All C variables, with the exception of the
namesoffunctionsandarrays,arebothrvaluesandlvalues.
Theycanbeusedoneithersideofanequalsigninanassignment
statement.Functionnamesandarraynamesarervaluesandcan
be used only on the right side of the equal sign in an assignment
statement.Variablesdeclaredasconstantsandconstantscreatedby
the#definestatementarealsorvalues.
Thetypevoid*hasaspecialmeaningwhenappliedtopointers.
Avoidpointer(sometimesreferredtoasagenericpointer)isapointer
that does not point at any specific type. Some functions will return
voidpointers,andtousethesepointers,theymustbecastontothe
typethattheyrepresent.Therefore,apointerofthetypevoid*can
beassignedthevalueofatypedpointer.However,unlessthevoid*
pointeriscastontothespecifiedtype,theincrement,decrement,
subtraction,andsoforthwillnotwork.A voidpointercanbe
usedinexpressions,butitisimpossibletoalteritsvalue.
70 Chapter 2 Advanced C Topics
PointersandFunctionArguments
Values passed to functions as arguments are copies of the real
values.Thedatatobepassedtoafunctionarepushedonthestackor
savedinregisterspriortothefunctioncall.Therefore,ifthefunction
should modify any of the arguments, this modification would not
propagatetothecallingfunction.Therefore,afunctionlike
voidswap(intx,inty)
{
inttemp;
temp=x;
x=y;
y=temp;
}
doesnothingbutswaptwopassedvalues,andthosevaluesarenever
returnedtothecallingprogram.Thisperformanceisgoodaswellas
bad. The bad situation is shown above when the function simply
does not work as expected.The good side is that it is not easy to
inadvertentlychangevariablevaluesinthecallingprogram.Theuse
ofpointerspermitsthisproblemtobeavoided.Thetechniqueiscalled
passingparametersbyreference.Considerthefollowingfunction:
voidswap(int*px,int*py)
{
inttemp;
temp=*px;
*px=*py;
*py=temp;
}
Heretheintegerspointedtobypxandpyareswapped.These
integersarethevaluesinthecallingprogram.Thepointervaluesin
thecallingprogramareunaltered.
Cmakesextensiveuseofpassingparametersbyreference.Re-
callthefirstprograminChapter1.Thatprogramhastheline
printf(Microcontrollersruntheworld!\n);
Pointers 71
WenowknowthatthestringMicrocontrollersrunthe
world!\nisnothingmorethanacharacterarrayterminatedbya
zero.Thecompilercreatesthatarrayinthememoryoftheprogram.
Thatarrayisnotpassedtoprintf.Apointertothatarrayispassed
toprintf.Thenprintfprintsthecharacterstothestandardout-
putandincrementsthroughthearrayuntilitfindsthe0terminator.
Thenitquits.Inotherinstances,argumentslikes[]wereused.In
thesecases,Cautomaticallyknowstopassapointertothearray.Itis
interesting.Ifyouhaveanarrayints[nn]andpassthatarraytoa
functionass,youcanuseanargumentint*pinthefunctionand
theninthefunctionbodydealwiththearrayp[].TheClanguage
isextremelyflexibleintheuseofpointers.Anexampleofthistype
ofoperationisasfollows:
/*Countthecharactersinastring*/
#include<stdio.h>
intstrlen(char*);
intmain(void)
{
intn,s[80];
fgets(s,80,stdin);
n=strlen(s);
printf(Thestringlength=%d\n,n);
return0;
}
intstrlen(char*p)
{
inti=0;
while(p[i]!=0)
i++;
returni;
}
72 Chapter 2 Advanced C Topics
Theaboveversionofstrlen()willreturnthenumberofchar-
acters in the string not including the terminating 0. The function
gets()isastandardfunctionthatretrievesacharacterstringfrom
thekeyboard.Theprototypeforthisfunctioniscontainedinstdio.h.
Itisinterestingtonotethatthefunctionstrlen()canbealteredin
severalwaystomakethefunctionsimpler.Theindexi inthefunction
canbepost-incrementedintheargumentsothatitisnotnecessaryto
havethestatementfollowingthewhile().Thisfunctionwillbe
intstrlen(char*p)
{
inti=0;
while(p[i++]!=0);
returni;
}
Becausethewhile()argumentisevaluatedasalogicalstate-
ment,anyvalueotherthan0willbeconsideredTRUE.Therefore,
intstrlen(char*p)
{
inti=0;
while(p[i++]);
returni;
}
providesexactlythesameperformance.Yetanotherviewpointisfound
by
intstrlen(char*p)
{
inti;
for(i=0;*p++;i++);
returni;
}
Eachoftheabovefunctionsusingstrlen()showadifferent
operationinvolvingpassingargumentsbyreference.
Let us examine another use of passing arguments by pointers.
Pointers 73
Thefollowingfunctioncomparestwostrings.Itreturnsanegative
numberifthestringpislessthanthestringq,0ifthetwostrings
areequal,andapositivenumberifthestringpisgreaterthanthe
stringq.
intstrcomp(char*p,char*q)
{
while(*p++==*q++)
if(*(p-1)==\0)/*Thestringsareequal*/
return0;/*zero*/
return*(p-1)-*(q-1);/*Thestringsare
unequal, return the correctvalue*/
}
Herethewhile()statementwillexamineeachcharacterinthe
stringuntiltheargumentisnotequal.Note,thatthepointerspandq
are incremented after they are used. The test for equality will not
occuruntilafterthepointersareincremented,soitisnecessaryto
decrementthepointerptodetermineifthelastequalvalueinthe
two strings is a zero character. If the last value is a zero, the two
stringsareequal,anda0isreturned.Ifthelasttestedcharacterisnot
azero,thetwostringsarenotequalandthedifferencebetweenthe
lastcharacterinpandthelastcharacterinqisreturned.Thischoice
willgivethecorrectsignneededtomeetthefunctionspecification.
Anotherapproachcanbeusedthateliminatestheincrementsand
decrementswithintheprogramandconfinesthemtotheargument
ofaforconstruct.Consider
intstrcomp(char*p,char*q)
{
for(;*p==*q;p++,q++)
if(*p==\0)
return0;
return*p-*q;
}
Thepointerspandqarebothincrementedafterthetestinthe
if statement.Therefore, the pointer values are correct for the if
statement as well as for calculation of the return value when the
stringsarenotequal.
74 Chapter 2 Advanced C Topics
Ciscompletelyunforgivingifyouexceedtheboundariesofthe
arrayinyourcalculations.Cdoesnothaveintrinsicboundarychecks,
anditispossibletoincrementpointersrightofftheendofanarray.
For that matter, the array index can be decremented to addresses
below the beginning of the array. When a program makes such a
mistake,itwilldestroyotherdata,perhapsdestroytheprogrambe-
ingexecuted,orintheworsecase,theprogramcancrashthesystem.
The simple single-tasking computers that run MS-DOS or similar
operatingsystemshavenomemoryprotectionfeaturethatprotects
onetaskfromanother.Insuchcases,aprogramthatrunswildand
overwritesmemorynotassignedtoitcandestroyothertasksthatare
loadedinmemorywhethertheyarerunningornot.
EXERCISES
1.Write several versions of a function that copies one string into
another.
2.Writeafunctionthatconcatenatestwostrings.Concatenationof
twostringsmeansthatonestringwillbewrittenattheendofthe
other. Write this function with and without the use of pointers.
Whatistheadvantageofthepointerversionofthefunction?
Letusconsideraproblemthatwillbeanalyzedinmoredetail
later.Supposethatafunctionisneededthatwillsortthecontentsof
anarrayintoascending(ordescending)order.Thereareseveralsort
functions,andeachhasitsownsetofadvantagesanddisadvantages.
Thesimplestandprobablymostintuitiveiscalledthebubblesort.In
a bubble sort, a swap flag is reset. The first entry in the array is
comparedwiththesecond,andiftheyareinthewrongorder,they
areswapped.Thenthesecondentryiscomparedwiththethird,and
theyareswappedornot.Ifaswapeveroccurs,theswapflagisset.
Theelementsofthearrayaresuccessivelycomparedandswapped
untilalloftheelementsinthearrayhavebeencompared.Ifaswap
hasoccurredduringthescanofthearray,theswapflagisreset,and
thewholeprocessisrepeated.Thisprocessrepeatsuntilthescanof
thearraycausesnoswapstooccur.Atthattime,thearrayisinorder.
If the array contains n elements, this approach requires on the
orderofnsquaredcomparesandswaps.Forlargearrays,thetimeto
sortanarraywithabubblesortisinordinate.Anotherapproachwas
Pointers 75
discovered by D. L. Shell. The Shell sort allows the array to be
sorted with n times the logarithm base two of n. This difference
can be substantial. For example, if the array contains 1000 ele-
ments, the bubble sort will require on the order of 1,000,000
compares and swaps while the Shell sort will need only 10,000.
Therefore,thebubblesortshouldnotbeusedtosortlargearrays.
AnothersorttechniquethatisusedwasdiscoveredbyC.A.R.
Hoare.Thistechniqueiscalledthequicksort.Itusesarecursive
approachtoaccomplishthesort,anditalsorequiresnlogbase2of
n compares and swaps. The shell sort and the quick sort usually
requireaboutthesametimetoaccomplishthesort.Wewilldem-
onstrateashellsortnow.
The code for a shell sort follows. Note that extensive use of
pointersisusedinthisversionoftheshellsort.
/*shell_sort():sortthecontentsofthearray*v
intoascendingorder*/
voidshell_sort(int*v,intn)
{
intgap,i,j,temp;
for(gap=n/2;gap>0;gap/=2)
for(i=gap;i<n;i++)
for(j=i-gap;j>=0&&*(v+j)>*(v+j+gap);
j-=gap)
{
temp=*(v+j);
*(v+j)=*(v+j+gap);
*(v+j+gap)=*(v+j);
}
}
Theshellsortreceivesasargumentsapointertoanarrayofinte-
gersandanintegernwhichisthelengthofthearray.
Thissortworksbysuccessivelydividingthearrayintosubarrays.
Thefirstoperationdividesthewholearrayintotwoparts;thesecond
divideseachofthetwosubarraysintotwonewsubarrays,foratotal
offourarrays;andsoforth.
76 Chapter 2 Advanced C Topics
Thecorrespondingelementsineachsubarrayarecompared,and
iftheyareoutoforder,theyareswapped.Atthecloseofthisopera-
tion,anewsetofsubarraysarecreated,andtheprocessisrepeated
over these subarrays. Eventually, the gap between elements in the
subarrayswillbereducedtoone,andthearraycontentswillbesorted.
Theouterforloopabovecontrolsthesplittingofthearraysinto
thesubarrays.Thesecondloopstepsalongthearraypairs.Thein-
nermostloopsuccessivelycomparestheelementsthatareseparated
bygapsinthesubarrays.Ifelementsarefoundthatareoutoforder,
theyarereversedorswappedinthearray.
EXERCISES
1.Restatetheshellsortabovetousearraysratherthanpointersto
arrays.
2.Writeaprogramthatreadsincharactersfromtheinputstreamand
recordthenumberofoccurrencesofeachcharacter.Calculatethe
percentageoccurrenceofeachcharacter,andprintouttheresultin
ascendingorderofpercentageofoccurrence.
Functionscanreturnpointers.Forexample,prototypetoafunc-
tionthatreturnsapointeris:
int*able(char*);
Hereablereturnsapointertoaninteger.
InC,aNULLpointerisneverused.ANULLpointerimpliesthat
somethingistobestoredattheaddresszero.Thisaddressisneveravail-
ablefordatastorage,sonofunctioncanreturnavalidNULLpointer.
TheNULLpointercanbeusedasaflagoranerrorreturn.Thepro-
grammershouldneverallowaNULLpointertobedereferenced,which
impliesthatdataarereadorstoredat0.
IfCwillsupportapointertoavariable,itrequiresbutlittleimagi-
nationtoreasonthatCwillsupportpointerstopointers.Infact,there
is no practical limit in the language to the depth of dereference C
will support. C will also allow arrays of pointers, and pointers to
functions.(Wediscussedpointerstoarraysintheprecedingsection.)
Anarrayofpointerscanbeveryusefulwhenneeded.Amostobvi-
oususeforanarrayofpointersistoreadthecontentsofacommand
linetoaprogram.Sofarinourdiscussionofprograms,therehave
beennoprovisionsforreadingthecontentofacommandlinethatis
Pointers 77
writtentothescreenwhentheprogramisexecuted.Acommandline
canbereadbytheprogram.Thedefinitionoftheprogramnamemain
whenextendedtoreadinacommandlineisasfollows
voidmain(intargc,char*argv[])
Theintegervariableargcisthenumberofentriesonthecommandline.
The array of pointers to the type charargv[] contains pointers to
strings.Whenenteringargumentsontothecommandline,theymustbe
separatedbyspaces.Thefirststringpointedtobyargv[0] isthename
of the program from the command line.The successive pointer values
pointtoadditionalcharacterstrings.Thesestringsareeach0terminated,
andtheypointtothesuccessiveentriesonthecommandline.Thevalueof
argcisthetotalnumberofcommandlineentriesincludingtheprogram
name.Itmustberememberedthateachentryinargv[]isapointertoa
string.Therefore,ifanumberisenteredonthecommandline,itmustbe
convertedfromastringtoaninteger,orfloatingpointnumber,priortoits
useintheprogram.Letusseehowthisconceptcanbeused.Earlier,we
wroteafunctiontocalculateaFibonaccinumber.Letsusethisfunctionin
aprograminwhichtheargumentfortheFibonaccicalculationisreadin
fromthecommandline:
#include<stdio.h>
#include<stdlib.h>
longfib(int);/*Fibonaccinumberfunction
prototype*/
intmain(intargc,char*argv[])
{
inti;
i=atoi(argv[1]);
printf(TheFibonaccinumberof%d =%ld\n,i,
fib(i));
return0;
}
We will not repeat the code for fib(i).A new header file,
stdlib.h,isincludedwiththisprogram.Thefunctionprototype
foratoi()iscontainedwithinthisheaderfile.Thestandardcom-
mandlineargumentsareusedinthecalltomain().Theline
78 Chapter 2 Advanced C Topics
i=atoi(argv[1]);
causesthefunctionatoiASCIItointegerconversiontobeex-
ecutedwithapointerasanargument.Thispointerpointstothefirst
argumentfollowingtheprogramnameonthecommandline.Inthis
case,itwillbepointingtoanASCIIstringthatcontainsthenumber
tobeusedasanargumentforthefib()call.Thisstringmustbe
converted to an integer before fib() can operate on it, which is
exactlywhattheatoi()functionaccomplishes.Thefinallinein
thisprogramprintsouttheresultofthecalculation.
Anotherexampleofuseofthecommandlineargumentsistoprint
outthecommandline.Thefollowingprogramwillaccomplishthistask.
#include<stdio.h>
intmain(intargc,char*argv[])
{
inti;
for(i=0;argc--;i++)
printf(%s,argv[i]);
printf(\n);
return0;
}
Theargumentstomain()arethesameasbefore.Thisprogram
entersafor loopthatinitializesi tozero.Itdecrementsargc each
timeittestsitsvalue,andexecutesuntiltheloopinwhichargcis
decrementedto0.Theprintfcall
printf(%s,argv[i]);
printsoutthestringtowhichargv[i]points.Noticethespaceinthe
string%s.Thisspacewillforceaspacebetweeneachargumentas
itisprinted.Theprogramiswrittensothattherearenonewlinecharac-
tersprinted.Argumentswillallbeononeline,andtheywilleachbe
separatedbyaspace.Theprintf()statementafterexecutionofthe
for()loopwillprintoutasinglenewlinesothatthecursorwillreturn
tothenextlineaftertheprogramisexecuted.
Command line entry is but a simple example of use of arrays of
pointers.Anotherareainwhicharraystopointersareneededisinorder-
ingstringsofdata.Forexample,itispossibletocollectalargenumber
ofwordsinmemory,sayfromaninputstream.Supposethatitisneeded
toalphabetizethesewords.Wesawearlier,thattheshellsortwillorder
Pointers 79
thecontentsofanarray,soitmightbepossibletosimplymodifythe
shellsorttodothisjob.
First,acomparisonisneededthatwilldetermineifthelexicalvalue
ofaonewordissmaller,equal,orlargerthanthatofanotherword.Such
acompareroutinewasoutlinedabove.Second,aswaproutinethatwill
swapthewordsthatareinthewrongorder.Hereisacasewhereanarray
ofpointerscanbequiteuseful.Assumethattheprogramthatreadsinthe
datawillputeachwordintoaseparatememorylocationandkeepan
arrayofpointerstothebeginningofeachwordratherthanjustthearray
ofthewordsthemselves.Thenintheshellsort,whenaswapisrequired,
ratherthanswappingthewords,swapthepointersinthearray.Swap
routinesthatswappointersinthearrayareveryeasytoimplement.On
theotherhand,swaproutinestoswaptwostringsinmemoryarediffi-
cultandslow.Therefore,wecancreateasortroutinethatismuchmore
efficientifweuseanarrayofpointersratherthananarrayofstrings.
/*shell_sort():sortthecontentsofthearray
char*v[]intoascendingorder*/
#include<string.h>
voidshell_sort(char*v[],intn)
{
intgap,i,j;
char*temp;
for(gap=n/2;gap>0;gap/=2)
for(i=gap;i<n;i++)
for(j=i-gap;j>=0&&
strcmp(v[j],v[j+gap]);j-=gap)
{
temp=v[j];
v[j]=v[j+gap];
v[j+gap]=v[j];
}
}
Here the strcmp() routine is used to determine if a swap is
needed.strcmp()isidentifiedintheheaderfilestring.h.When
needed,thecontentsofthearrayofpointerstothebeginningofthe
wordsisswappedratherthanswappingthewordsthemselves.
80 Chapter 2 Advanced C Topics
Animportantpointofstyle:Recallthatafewpagesbackafunc-
tionstrcomp()waswrittenasanexample.Itdidtheexactsame
operationsasstrcmp()above.Whyshouldwechooseoneover
theother?Well,libraryfunctionshavebeenwritten,rewritten,de-
bugged, and worked over for years. They work correctly, and you
can count on their robust construction.As a general rule, use a li-
braryfunctionifyoucanfindonetodothejobthatyouareattempting.
Mostofthetime,programmerswhowriteduplicatesoflibraryfunc-
tionsdoittosatisfytheirownegos.Therewardispoorwhenabugis
discovered, especially in production code, that could have been
avoidedbyusingastandardlibraryfunction.
Multidimensional Arrays
Csupportsmultidimensionalarrays.Programmersoftenfindthat
muchoftheneedformultidimensionalarrayswillgoawaywiththe
availabilityofpointers.MultidimensionalarraysinCarethoughtof
asarraysofarrays.Thisideacanbeextendedtomorethantwodi-
mensions.Atwo-dimensionalarrayisidentifiedas
array[x][y];/*[row][column]*/
Thefirstargumenttotherightcanbethoughtofastherowdimen-
sion,andthesecondthecolumndimension.Elementsspecifiedby
therightmostargumentarestoredinadjacentmemorylocations.
Anarraycanbeinitializedatdeclarationtime.Forexample:
intarray[3][4]={{10,11,12,13},
{14,15,16,17},
{18,19,20,21}};
Itisequallyvalidtoinitializethearrayasfollows:
intarray[3][4]={10,11,12,13,14,15,16,17,18,19,20,21};
Either form of initialization will place the proper numbers in the
proper location in memory, and the two-dimensional indices will
workproperlyineithercase.
Frequently,itisneededtoknowthesizeofavariableinC.This
variablecanbeabasictype,anarray,amultipledimensionalarray,or
evenastructurethatwillbeintroducedlater.Cprovidesanoperator
Multidimensional Arrays 81
thathasmuchtheappearanceofafunctioncalledsizeof.Todeter-
minethesizeofanyvariable,usethesizeofoperatorasfollows:
a=sizeofarray;
whichwillreturnthenumberofbytescontainedinarray[][]above.
There are several important different ways that you can use the
sizeof operator. First, the value of the return from sizeof is in
characters.Thetypeofthereturniscalledatypesize_t.Thisspecial
typeisusuallythelargestunsignedtypethatthecompilersupports.
FortheMIXcompiler,itisanunsignedlong.Ifyoushouldwant
thesizeofatypeinyourprogram,youshouldenclosetheparameterin
parentheses.Ifyouwantthesizeofanyotheritem,donotusetheparen-
theses. One other item. If the sizeof operator is used in a module
whereanarrayisdefined,itwillgiveyouthesizeofthearrayasabove.
Ifyoushouldpassanarraytoafunction,thearraynamedegeneratesto
a pointer to the array, and in that case, the return from the sizeof
operatorwouldgiveyouthesizeofapointertothearray.
Acommonexampleprogramusingtwo-dimensionalarraysisto
determinetheJuliandate.TheJuliandateissimplythedayofthe
year.Thefollowingfunctionisonethatallowscountingthenumber
ofdaysthathavepassedinayear.
intmonth_days[2][13]={
{0,31,28,31,30,31,30,31,31,30,31,30,31},
{0,31,29,31,30,31,30,31,31,30,31,30,31}};
intJulian_data(intmonth,intdate,intyear)
{
inti,leap;
leap=year%4==0&&year%100!=0||year%400==0;
for(i=1;i<month;i++)
day+=month_days[leap][i];
returnday;
}
Thedeclaration
intmonth_days[2][13]={
{0,31,28,31,30,31,30,31,31,30,31,30,31},
{0,31,29,31,30,31,30,31,31,30,31,30,31}};
82 Chapter 2 Advanced C Topics
types month_days as an array of 26 integers. This array is a
two-dimensionalarrayoftworowsof13columnseach.Thevalues
assignedareshown.Theextra0entryatthebeginningofeacharray
istoallowtheconventionalmonthdesignations1through12tobe
usedasindicesandnothavetoworryaboutthefactthatarraysinC
startwitha0index.
Theintroductionoftheprogramisnormal.Thefunctionreturns
an int and expects to receive three int arguments; one for the
month,oneforthedayofthemonth,andonefortheyear.Notethat
theyearmustbethefullyear,like2013,ratherthanmerely13.The
firstexecutablestatementisthelogicstatement:
leap=year%4==0&&year%100!=0||year%400==0;
Leapyearsareusuallyeveryfouryears.However,asmalldiscrepancy
stillexistsinthelengthoftheyearwiththe onceeachfouryears
correction.Tofurthercorrecttheerror,thecalendarmakershavede-
cidedthatyearsdivisibleby100willnotbealeapyearunlesstheyear
is divisible by 400.The above statement is a logical statement that
determinesfirstiftheyearisdivisibleby4.Ifitisdivisibleby4,itis
thencheckedtodetermineifitisdivisibleby100.Theresultofthis
muchoftheanalysiswillbeTRUEforanyyeardivisibleby4,andnot
divisibleby100.IfthisportionofthecalculationisTRUE,leapwill
beassignedavalueTRUE,or1,andtheevaluationwillterminate.If
theresultofthefirstportionofthecalculationisFALSE,itwillbe
necessarytoevaluatethelasttermtodetermineifthewholestatement
isTRUEorFALSE.Thevariableleapwillbeassignedtheresultof
year%400==0
inthiscase.
leapisassignedavalueof1or0accordingtotheresultofthe
logicevaluation.Thisvaluecanbeusedasanindexintothetwodi-
mensionalarraytodetermineifthenumberofmonthdaysinaleap
yearoranonleapyearwillbeusedinthecalculationoftheJuliandate.
PointersandMultidimensionalArrays
Perhapsoneofthemostwidelymisunderstoodandthereforemys-
terious aspects of pointers and C has to do with multidimensional
arrays.Theseproblemsarereallynotdifficult.Amultidimensional
Multidimensional Arrays 83
arraymustalwaysbeunderstoodasbeingarraysofarraysofarrays
andsoforth.Forexample,thedeclaration
intar[3][5];
definesthreearraysoffiveelementseach.Wehavealreadyseenthat
datastoredinthisarrayiscolumnmajor.Thesecondargumentpoints
to a column in the two-dimensional array, and ar[n][0] and
ar[n][1]arestoredinadjacentmemorylocations.Followingthe
logicofarraynamesandpointers,thearraynamearisapointerto
thefirstelementinthearray.Thevalueobtainedwhenusingaras
anrvalueis&ar[0][0].Theorderofevaluationofthesquare
brackets is from left to right so that *(ar+1) is a pointer to the
elementar[1][0]inthearray.Thinkofthetwo-dimensionalar-
rayasbeing*(ar+n)[i]wherenhasarangefrom0to2andi
hasarangefrom0to4.Anincrementinnherewillincrementthe
absolutevalueofthepointerby5*sizeof(int).
Theseideascanbecarriedtothenextlevel.Theelement*(ar+n)
isapointertothefirstelementofafive-elementarray.Therefore,the
evaluation of *(*(ar+n)+i) is the value found in the location
ar[n][i].Theimportantitemisthattheright-mostargumentin
multipledimensionalarrayspointtoadjacentmemorylocations,and
theincrementsoftheleftargumentsstepthecorrespondingpointer
valuefromarraytoarraytoarray.
Theseideascanbeextendedtoarraysofmorethantwodimen-
sions.Hadthearraybeen
doublebr[3][4][5];
then*(*(*(br+1)+2)+3)wouldbetheelementbr[1][2][3]
fromtheabovearray,and *(*(br+1)+2)+3isapointertothis
element.
EXERCISES
1.WriteafunctionthatwillreceivetheyearandtheJuliandateof
thatyear,andcalculatethemonthanddate.
2.Writeafunctionthatwillcalculatetheproductofa4by4matrix
and a scalar. The scalar product requires multiplication of each
elementinthematrixbythescalarvalue.
84 Chapter 2 Advanced C Topics
3.Writeafunctionthatwillcalculatethevectorproductoftwo1by
4 matrices. The vector product of two arrays is the sum of the
productsofthecorrespondingelementsofthetwoarrays.
4.Writeafunctionthatwillcalculatethematrixproductoftwo4by
4matrices.Thematrixproductisamatrixwhosei,jelementis
the vector product of the ith row of the first matrix and the jth
columnofthesecondmatrix.Assuch,theproductoftwo4by4
matricesisa4by4matrix.
Chaspointerstofunctions.Acommonuseforpointersforfunc-
tions is in creating vector tables for microcontrollers. Most
microcontrollerapplicationsinvolvetheuseofinterrupts.Whenan
interruptoccurs,themachinestatusissaved,andprogramcontrolis
transferredtoaninterruptserviceroutine.Atthecloseoftheinter-
rupt service routine, the machine status is returned to the earlier
condition, and control is returned to the interrupted program.An
addresstableinmemorycalledthevectortablecontainstheaddresses
ofeachinterruptserviceroutine.Itistheprogrammersresponsibil-
itytofillthevectortablewiththeproperaddressesforthevarious
interruptserviceroutines.Pointerstofunctionsallowtheprogram-
meraccesstotheaddressesoftheinterruptserviceroutines.Wewill
seeseveraldifferentmethodstocreatethevectortablesinthechap-
tersontheindividualmicrocontrollersthatfollow.
Apointertoafunctionisidentifiedby
int(*function_ptr)();
Theabovedeclarationsaysthatfunction_ptr isapointertoa
functionthatreturnsatypeint.Theargumentsarenotdeclaredhere.
Theparenthesessurrounding*function_ptrarerequired.Ifthey
werenotincluded,thedeclarationwoulddeclarefunction_ptras
afunctionthatreturnsapointertothetypeint.Iffunction_ptr
isavalidpointertoafunction,thefunctioncanbeaccessedby
(*function_ptr)(args);
The above declaration form can be used for arrays as well as
functions.Thedeclaration
char(*array_ptr)[];
Multidimensional Arrays 85
statesthatarray_ptrisapointertoanarrayofchar.Thedeclaration
char*array[];
statesthatarrayisanarrayofpointerstothetypechar.Although
youwillrarelyfinditused,thesedeclarationscanbecombinedto
createverycomplicateddeclarations.
Oneconstructfromthegeneralareaofcomplicateddeclarationsis
soimportanttomicrocontrollercodethatitmustbecovered.Csup-
portsvariabletypescalledlvalues.Asmentionedearlier,anlvalue
isatypeofvariablethatcanbethedestinationforanassignment.Most
variablesinCarelvalues.Notableexceptionsarefunctionnames
andarraynames.Ifaprogramdealswithanumberthatcanbeamemory
address,itcanbemadeaccessibletothelanguagebycastingthead-
dresstoanappropriatetype.Forexample,supposethataspecialtable
islocatedattheaddress0x1000inmemory.Further,supposethatthe
typetobestoredatthataddressisaninteger.Here,thecodesequence
(int*)0x1000
forcesthenumber0x1000tobeapointertoatypeint.Oftenthis
ideamustbecarriedfurther,andtheprogrammerwantstoputavalue
intoaspecificaddress.Theaboverepresentationisapointertothe
typeint.Therefore,avaluecanbeassignedtothatintby
*(int*)0x1000=integer_value;
whichwillplaceinteger_valueintothelocation0x1000inthe
computermemory.
Frequently,controlregisters,dataregisters,andinput/outputport
registersareplacedatspecificlocationsinmemory.Theseregister
locationscanbeconvertedtotractableCnamesbyuseofthe#de-
finemacrocapabilityofC.SupposethatanI/Oportislocatedat
theaddress.
#definePORTA(*(char*)0x1000)
allowstheuseofthenamePORTAinthecomputerprogram.Idefine
PORTAasapseudo-variable.Itiscreatedbyamacroexpansionand
such things are usually constants or function-like expansions.The
aboveisneither.PORTAcanbeassignedto,oritsvalueread.You
canevendooperationslike
86 Chapter 2 Advanced C Topics
PORTA|=0X80;
if(PORTA&0x6==0)
dosomething;
YoucanperformanyoperationswithPORTAthatyouwouldwant
withanynormalvariableinthelanguage.WhilePORTAhasbeen
generated by a macro expansion it also can be used as a variable.
Thus, the title pseudo-variable. Unless there is a specific reason,
though,Iwillcallthesemacrosvariables.
Theabovepseudo-variableisofthetypechar,anditsaddressis
0x1000.Thiscapabilityisveryusefulinprogrammingmicrocontrollers.
Whenprogrammingmicrocontrollers,therearetworeasonswhy
itisnecessarytobeabletomanipulatedirectaddressesinmemory.
Mosthigh-levellanguageswillnotallowtheprogrammerdirectac-
cesstospecificmemorylocations.Asseenabove,Cdoesallowthe
programmertobendtheserulesenoughtobeabletostoredatainto
aspecificmemoryaddress.Anotherfeaturethatishighlydesirable
istobeabletoplacetheaddressofafunctionataspecificaddress.
Thiscapabilityisnecessarywhenimplementinganinterruptservice
routine.Whenaninterruptoccurs,thecomputerwillstopitscurrent
operation,saveatleastthevaluescontainedinthestatusregisterand
theprogramcounter,andbeginexecutionatanaddresscontainedin
avectorlocation.Eachinterruptwillhaveavectoraddress,andeach
interruptwillrequireitsowninterruptserviceroutine.Programini-
tializationwheninterruptsareinvolvedwillrequirethattheprogram
placetheaddressesofanyinterruptserviceroutinesintothespecific
vectoraddressesforeachinterrupt.
Acontinuationoftheaboveapproachcanbeusedinthiscase.There
is a direct address in memory that is to receive the interrupt service
routineaddress.Letsthinkforamomentaboutwhatthisaddressis.The
addressisgoingtocontaintheaddressofafunction.Theaddressitselfis
apointertoamemorylocation.Thecontentsofthislocationareapointer
thatpointstoafunctionthatistheinterruptserviceroutine.Allinterrupt
serviceroutinesareofthetypevoid.Therefore,thevectoraddressisa
pointertoapointertoatypevoid.Tobeabletoplacethevalueofthe
pointertoatypevoidintothislocation,wemustassertoneadditional
levelofindirectiontoaccessthecontentofthespecificmemoryloca-
tion.Therefore,thefollowinglineofcode
Structures 87
*(void**)0xfffc=isr;
placesthebeginningaddressofthefunctionisrintothememory
location0xfffc.
Aconvenientmethodofexecutingthisoperationistocreatea
macro.Thefollowingmacrodefinitionworks:
#define vector(isr,address)(*(void **)(address)=(isr))
Nowthefunctioncall
vector(timer,0xffd0);
willplacetheaddressofthefunctionnamedtimerintotheloca-
tion 0xffd0 in the computer memory map. It is important that
timerbedefinedasafunctionthatreturnsatypevoid.
Structures
AnotherfeatureofCnotfoundinmanyhigh-levellanguagesis
thestructure.Astructureissimilartoanarray,butfarmoregeneral.
Astructureisacollectionofoneormorevariablesidentifiedbya
singlename.Thevariablescanbeofdifferenttypes.Structuresare
typesinthesensethatanintisatype.Therefore,ifyouhaveprop-
erlydeclaredastructure,youmaydeclareanotherstructureofthe
sametype.Examinethefollowingstructure:
structperson
{
char*name;
char*address;
char*city;
char*state;
char*zip
intheight;
intweight;
floatsalary;
};
Thisstructurecontainssomeofthefeaturesthatdescribeaper-
son.Thepersonsnameandaddressaregivenaspointerstocharacter
strings.Thepersonsheightandweightareintegers,andthesalaryis
88 Chapter 2 Advanced C Topics
afloating-pointnumber.Thestructuredeclarationmustbefollowed
byasemicolon.Thiscombinationofvariablesiscreatedeverytime
astructureofthetypepersonisdeclared.Thenamepersonfollow-
ingthestructdeclarationiscalledthestructuretagormerelythe
tag.Tagsareoptional.Ifatagisused,itmaybeusedtodeclareother
structuresofthesametypeby
structpersonap,bp,cp;
Hereap,bp,andcparestructuresofthetypeperson.Asingle
instanceofastructurecanbedeclaredby
struct{....}a;
Inthiscaseaisastructurewiththeelementsdefinedbetweenthe
braces.The elements that make up a structure are called its mem-
bers.Membersofastructurecanbeaccessedbyappendingaperiod
followedbythemembernametothestructurename.Forexample,
thenameofthepersonrepresentedbyapisaccessedby
ap.name
andthatpersonssalaryis
ap.salary
Apointertoastructurecanbeused.Thepointerppersoniscreatedby
structperson*pperson;
Ifapointertoastructureisused,membersofthestructurecanbe
accessedbytheuseofaspecialoperator->.Thisoperatoriscreated
by use of the minus sign (-) followed by the right angle bracket
character (>). The height of a person identified by the pointer
ppersonisaccessedby
pperson->height
Arraysofstructuresareused,andwhendealingwithpointerstoar-
raysofstructures,toincrementthepointerwillmovethepointerto
thenextstructure.Ifaprogramhas
structpersonpeople[20],*pp;
andppismadetopointatpeople[0]by
pp=people
Structures 89
then
people[1].name
isthesameas
++pp->name
Astructurecanhaveanotherstructureasamemberelement.Consider
structpoint
{
intx;
inty;
};
wherepointcontainstwointegerelements,xandy.Acirclecan
nowbedefinedby
structcircle
{
structpointcenter;
intradius;
};
Inthiscaseaccesstothemembersofcenterisby
circle.center.x
or
circle.center.y
Ofcoursetheradiusisaccessedby
circle.radius
Functionscantakestructuresasargumentsandtheycanreturn
structures.Forexample,thefunctionmake_point()thatfollows
returnsastructure.
structpointmake_point(intx,inty)
{
structpointhold;
hold.x=x;
90 Chapter 2 Advanced C Topics
hold.y=y;
returnhold;
}
Observethatthestructpointistreatedasatypewithnodiffi-
cultyinthisfunction.Thereturntypeisstructpoint,andwithin
thebodyofthefunctionholdisalsoatypestructpoint.Thex
argumentpassedtothefunctionisplacedinthexmemberofhold as
istheyargumentplacedintheymember.Thenthestruct hold is
returnedtothecallingfunction.Alloftheseoperationsarelegal.
Sincestructurescreatetypes,structurescanhavemembersthat
arestructures.Forexample,supposethatthestruct rectfora
rectangleisdefinedas
structrect
{
structpointp1;
structpointp2;
};
Letsoutlineaprogramthatwillinscribeacirclewithinarect-
angle.Thecircleistangenttothesidesthatmakeupthenarrowest
dimensionoftherectangle.
/*Inscribeacircleinarectangle*/
/*firstdeclaresomeusefulstructures*/
structpoint
{
intx;
inty;
};
structcircle
{
structpointcenter;
intradius;
};
structrect
{
Structures 91
structpointp1;
structpointp2;
};
/*hereisafunctiontomakeacircle*/
structcirclemake_circle(structpointct,int
rad)
{
structcircletemp;
temp.center=ct;
temp.radius=rad;
returntemp;
}
/*someusefulfunctionlikemacros*/
#definemin(a,b)(((a)<(b))?(a):(b))
#defineabs(a)((a)<0?-(a):(a))
/*functionprototypes*/
voiddraw_rectangle(structrect);
voiddraw_circle(structcircle);
intmain(void)
{
structcirclecir;
structpointcenter;
structrectwindow={{80,80},{600,400}};
intradius,xc,yc;
center.x=(window.p1.x+window.p2.x)/2;
center.y=(window.p1.y+window.p2.y)/2;
xc=abs(window.p1.x-window.p2.x)/2;
yc=abs(window.p1.y-window.p2.y)/2;
radius=min(xc,yc);
cir=make_circle(center,radius);
92 Chapter 2 Advanced C Topics
draw_rectangle(window);
draw_circle(cir);
return0;
}
Atthebeginningoftheprogram,severalimportantstructtypes
aredefined.Theseincludeapoint,arectangle,acircle,andafunc-
tion to make circle given its center and its radius. Two macro
definitionsareneeded.Thefirstisthecalculationfortheminimum
value of a and b and the second returns the absolute value of the
argument. Two function prototypes are included. These functions
willdrawarectangleandacircletothescreen,respectively.
Inside the main program cir is declared to be of the type
struct circle,centerisstruct point,andwindowis
ofthetypestruct rect.Whenwindowisdefined,itisinitial-
izedtothevaluesshown.Thistypeofinitializationisacceptableto
structuresaswellasarrays.Therectangleisdefinedbytwopoints.
Thepoint{80,80}isthelowerlefthandcorneroftherectangle,and
the point {600,400} is the upper right corner. These locations are
implementation dependent, and in some cases might represent the
upperleftcorner{80,80}andthelowerrightcorner{600,400}.
Thecenterofthewindowiscalculatedbydeterminingtheaver-
age value of the x members of each point along with the average
value of the y members. These values are the exact center of the
rectangle.Thecenteroftheinscribedcirclewilllieatthispoint.The
radiusoftheinscribedcirclewillbeone-halfthelengthoftheshort-
estdimensionoftherectangle.Thetwopotentialvaluearecalculated
asxcandyc.Heretheabsolutevalueisused,becauseingeneral,it
isimpossibletoknowthattherectanglewillbespecifiedbythelower
lefthandcornerinp1andtheupperrighthandcornerinp2.Ifthese
pointswereinterchanged,negativevalueswouldbecalculated.The
selectionofthepositiveresultthroughtheabs()macroavoids
this problem.The final choice for radius is the minimum value of
xcoryc.
Theabovecalculationsprovideenoughinformationtospecifythe
circle,sociriscalculatedasthereturnvaluefrommake_circle().
Finally,twocompilerspecificfunctions,draw_rectangle()and
draw_circle(),areusedtodrawthecalculatedfigurestothescreen.
Structures 93
Whileitwouldnotbedifficulttoexecutethesecalculationswithout
theuseofstructures,itisobviousthatthestructureformulationofthe
programmakesamuchsimplerandeasiertofollowprogram.Thevari-
ablesandprogramelementsareobjectshereratherthanmerenumbers.
Chasacommandcalledtypedef.Thiscommandcanrename
aspecifiedtypefortheconvenienceoftheprogrammer.Itdoesnot
createanewtype,itmerelyrenamesanexistingtype.Forexample,
typedefintMiles;
typedefcharByte;
typedefintWord;
typedeflongDword;
are all valid typedef statements.After the above invocations, a
declaration
Milesm;
Bytea[20];
Wordword;
Dwordbig;
wouldmakemanint,aanarrayof20characters,wordthetype
int,andbigalong.Allthathashappenedisthatthesetypesare
aredefinitionoftheexistingtypes.Newtypesdefinedbytypedefs
areusuallywrittenwithanuppercasefirstletter.Thisisatradition,
notarequirementoftheClanguage.
Structuresusedearliercouldbemodifiedbyuseofthetypedef.
Consider
typedefstruct
{
intx;
inty;
}Point;
This typedef redefines the earlier struct point as Point. The
judicioususeoftypedefscanmakeaprogrameveneasiertoread
thanthesimpleuseofstructs.Theprogramthatfollowsisthe
sameasthatabovewhereallofthestructuresaretypedefnewnames.
/*Inscribeacircleinarectangle*/
94 Chapter 2 Advanced C Topics
typedefstruct
{
intx;
inty;
}Point;
typedefstruct
{
Pointcenter;
intradius;
}Circle;
typedefstruct
{
Pointp1;
Pointp2;
}Rect;
Circlemake_circle(Pointct,intrad)
{
Circletemp;
temp.center=ct;
temp.radius=rad;
returntemp;
}
/*someusefulmacros*/
#definemin(a,b)(((a)<(b))?(a):(b))
#defineabs(a)((a)<0?-(a):(a))
/*functionprototypes*/
voiddraw_rectangle(Rect);
voiddraw_circle(Circle);
intmain(void)
{
Circlecir;
Pointcenter;
Rectwindow={{80,80},{600,400}};
Structures 95
intradius,xc,yc;
center.x=(window.p1.x+window.p2.x)/2;
center.y=(window.p1.y+window.p2.y)/2;
xc=abs(window.p1.x-window.p2.x)/2;
yc=abs(window.p1.y-window.p2.y)/2;
radius=min(xc,yc);
cir=make_circle(center,radius);
draw_rectangle(window);
draw_circle(cir);
return0;
}
Thefunctionmake_circle()returnsatypeCircleandre-
quiresargumentsPointandint.Circleisusedtodeclarethe
variable temp in make_circle().Within the main program
Circle,Point,andRectareusedastypesinthedefinitionof
the several structure type variables used in the program. With the
typedefdeclarations,thereisnobasicchangetotheprogram,but
itiseasiertoreadandfollow.
Thetwofunctionsdraw_rectangle()anddraw_circle()
arenotstandardCfunctions.Thesefunctionsareprogrammedand
thelistingofthefinalprogramisshowninAppendixB.
SelfReferentialStructures
Astructurecannotcontainitselfasamember.Structuredefini-
tionsarenotrecursive.However,astructurecancontainapointerto
astructureofthesametype.Thiscapabilityhasprovenquiteuseful
indealingwithcomplicatedsortorlistingproblems.Onesortprob-
lemthatcanbeeasilytreatedisthebinary treesort.Atreesortreceives
data,suchasaword.Withinthetreethereisaroot nodethatcontains
aword.Thenodealsocontainsacountofthenumberoftimesthe
wordhasbeenseenandtwopointerstoadditionalnodes.Thesenodes
arecalledchildordescendentnodes.Traditionally,thenodetothe
leftcontainsawordthatislessthantherootword,andthenodeto
therightcontainsawordthatisgreaterthantherootnode.Asdata
arereadintothetree,thenewwordiscomparedwiththerootword.
Ifitisequaltotherootword,thecountinthenodeisincremented,
96 Chapter 2 Advanced C Topics
andanewwordisreceived.Ifthewordisnotthesameandisless
thantherootword,thenodetotheleftisaccessedandthecompari-
sonisrepeated.Thisprocessisrepeateduntilamatchisfoundora
nodewithnodescendantsisfound.Ifamatchisfound,thecountof
thatnodeisincremented.Ifnomatchisfoundanewnodeiscreated
andplacedatthebottomlocation,andthewordisinsertedintothe
newnode.Thisprocessisrepeatedwiththesmallerwordsalways
goingtotheleftandthelargerwordsalwaysgoingtotheright.
Eventuallyatreethatcontainsallofthedifferentwordsenteredinto
the program will have been created. The tree has several properties.
Sinceeachnodehastwochildnodes,thetreebuildsinabinarymanner.
Therootlevelhasexactlyoneentry,thesecondlevelhastwoentries,the
thirdlevelhasfourentries,andsoforth.Ifthetreeisbalanced,eachlevel
willhaveapoweroftwoentries.However,ifworddataaretakenin
randomly,itispossiblethatsometreebrancheswillterminateearlyand
otherswillextendtoadepthorlevelthatexceedssome.
Oncethedataareplacedintothetree,itispossibletosortitorto
arrangethewordsinalphabeticalorder.Ifwetraversethetreefrom
therootnodetotheextremeleft,wewillfindthewordthatissmall-
est.Immediatelyabovethatwordwillbethenextlargerword.Tothe
rightofthesecondwordwillbewordslargerthanitselfbutsmaller
thanthewordinthenextnodeabove.Therefore,therightpathmust
be traversed to the left to find the next larger words.All of this
rightandleft,largerandsmallersoundscomplicated.Itisnot.
Hereisacasewherealittlethoughtandrecursivecodewillhelp
thingsalongeasily.Thecodethatfollowsisacompletefunctionto
alphabetizeandcountthenumberoftimesthateachwordisusedin
adocument.Severalnewconceptswillbeshowninthisprogram,so
itwillbebrokenintoshortblocksanddescribedinthesesmallpieces
ofcoderatherthantryingtobiteintothewholeprogramatonetime.
Thestructuretnodeislistedbelow.
typedefstructtnode
{/*thetreenode*/
char*word;/*pointstotext*/
intcount;/*occurrences*/
structtnode*left;/*pointertoleftchild*/
structtnode*right;/*pointertorightchild*/
}Tnode;
Structures 97
Thefirsttwoelementstothisstructureareapointertotheword
contained in the node, and the number of times that the word has
been seen. The last two elements are pointers to structures of the
typestruct tnode.Notethatinthetypedefofthestruct
tnode,thestructuretagwasused.Itisnecessarytousethetagin
thiscasebecausetheself-referentialpointersinsideofthestructure
needsthetagtofindthecorrecttype.Fortheremainderofthepro-
gram,thetypedefTnodeisused.
Somenewfilesareincludedintheincludefiles.Thesefileswill
bediscussedinafollowingsection.Thefirstisctype.h.Thispro-
gram uses several character tests that are identified in ctype.h.
Therearestringoperationsfoundinstring.h ,andtherearestan-
dardfunctionsdefinedinstdlib.h.
#include<stdio.h>
#include<ctype.h>
#include<string.h>
#include<stdlib.h>
Thelistoffunctionprototypesforthefunctionswritteninthis
programfollow:
Tnode*addtree(TNODE*,char*);
Tnode*talloc(void);
voidtreeprint(TNODE*);
intgetword(char*,int);
char*strsave(char*);
Thefirstfunctionisthefunctionthatisusedtoaddatreetothe
program. *talloc() is a function that allocates memory for a
Tnode. The function treeprint() prints out the tree, and
getword()readsinawordfromtheinputstream.Therearetwo
functionprototypesdefinedwithintheprogramgetword().These
functionsareusedbygetword()only.Thefinalfunctionabove
savesthestringpointedtobytheargumentinasafeplaceandre-
turnsapointertothewordlocationinmemory.
Themainprogramisrelativelysimple.TheconstantMAXWORD
isthemaximumnumberofcharactersthatcanbeallowedinaword.
Withinmain()apointertoastructureTnodenamedrootisde-
claredalongwithacharacterarraynamedwordandanintegeri.
98 Chapter 2 Advanced C Topics
/*wordfrequencycount*/
#defineMAXWORD100
intmain(void)
{
Tnode*root;
charword[MAXWORD];
inti;
root=NULL;
while(getword(word,MAXWORD)!=EOF)
if(isalpha(word[0]))
root=addtree(root,word);
treeprint(root);
return0;
}
ANULLvalueisassignedtoroot,andtheprogramentersaloopthat
readswordsfromtheinputstream.Itisassumedthatifthefirstcharacter
of the word is a letter, that a word has been read in. The function
isaplha()returnsaTRUEifitsargumentisaletter,andaFALSEif
itisnot.Iftheinputisaletter,theroutineaddtreeisexecutedwiththe
argumentsrootandword.Thefirsttimethatthisfunctionisexecuted,
rootisaNULL.Thisloopisrepeatedlyexecuteduntilgetword()
receivesanEOFcharacterfromtheinputstream.Atthattimetheinput
loopterminates,andthefunctiontreeprint()isexecuted.When
treeprint()iscompleted,main()returnsa0tothecallingpro-
gram or the operating system. This signal can be used to notify the
operatingsystemthattheprogramhasexecutedcorrectly.
HereisagoodpointtointroducetheconceptofaNULLpointer.
OftenpeopleusethetermNULL tomeanzerooracharactercontain-
ingazero.Thisideaisincorrect.Inthistext,thewordNULLmeans
aNULLpointertoatypevoid.Suchapointercanbedefinedina
headerfileandthedefinitionwilllooklike
#defineNULL((*void)0)
AnyplaceyouseethenameNULLinthistext,ithastheabovemeaning.
The function addtree() is the most complicated function in
Structures 99
thisprogram.ThisfunctionreceivesapointertoaTnodeandapointer
toacharacterstringasarguments.ItreturnsapointertoaTnode.If
theTnodepointerargumentisaNULLonentrytothefunction,the
firstifloopisexecuted.Withinthatloop,talloc()returnsapointer
toanewTnode.Thefunctionstrsave()copiesthestringintoa
safeplaceandreturnsapointertothislocation.Thispointerisputinto
thewordpointerlocationinthenewTnode.Avalueof1isputinto
thecountlocation,andthepointerstotheleftandrightchildTnodes
aresettoNULL.Atthistime,thewordhasbeenputintotheTnode,
andthepointertothisTnodeisreturnedtothecallingprogram.
/*addtree:addanodewithw,atorbelowp*/
Tnode*addtree(Tnode*p,char*w)
{
intcond;
if(p==NULL)/*newwordhasarrived*/
{
p=talloc();/*makeanewnode*/
p->word=strsave(w);
p->count=1;
p->left=p->right=NULL;
}
elseif((cond=strcmp(w,p->word))==0)
p->count++;/*repeatedword*/
elseif(cond<0)/*lessthanintoleftsubtree*/
p->left=addtree(p->left,w);
else/*greaterthanintorightsubtree*/
p->right=addtree(p->right,w);
returnp;
}
Supposenowthatatalatertimeaddtree()iscalledandthis
timepisnolongeraNULL.Inthiscase,astringcomparetestwillbe
executedtodetermineifthewordthathasbeenpassedisequaltothat
intheTnodepointedtobyp.Ifitisequal,itisarepeatedwordfor
thatnode,sothewordcountisincrementedandcontrolisreturnedto
thecallingprogram.Ifitisnotequal(say,itislexicallylessthanthe
100 Chapter 2 Advanced C Topics
wordofthenode),itisnecessarytoeithertraversetothenodeonthe
leftoraddanewnodeontheleftifthereisnonethere.Thecode
p->left=addtree(p->left,w);
does exactly what is needed in this case. This recursive call to
addtree()willdescendtotheleftTnodeifoneexists.Ifonedoes
notexist,thepointertotheleftTnode willbeNULL,soaddtree()
willcreateanewnodeforthislocation.addtree()returnsapointer
tothenewnode,soitwillbeplacedintheleftpointerofthisnode.
Hadthelexicalvalueofthewordbeengreaterthanthatofthe
wordstoredinthenode,theaddtree()callwouldworkonthe
pointertotherightchildnode.Therefore,thefunctionaddtree()
willstartattherootnodeandtraversedownthetreetotherightor
left child nodes depending on the size of the word relative to the
sizes of the words in the tree. If the word is found in the tree, its
countisincremented.Ifcontrolproceedsdownthetree,andtheword
isnotfound,eventually,aTnodewithaNULLpointertothedirec-
tionthatthepathmustmove.AthattimeanewTnodeiscreated
andthewordisassignedtothatTnode.
Whenallofthedatatobeinputintothetreearereadin,control
is passed to the function treeprint(). The argument of
treeprint()isapointertotherootnodeandtreeprint()
returnsnothingtothecallingprogram.Efficientprintingoutofthe
datarequiresanotherrecursiveroutine.Thefunctiontreeprint()
shownbelowshowsthisroutine.treeprint()iscalledwiththe
rootpointerasanargument.TherootpointerwillnotbeaNULL,so
thecodefollowingtheifstatementwillbeexecuted.Thefirst
/*treeprint:in-orderprintoftreep*/
voidtreeprint(TNODE*p)
{
if(p!=NULL)
{
treeprint(p->left);
printf(%4d%15s\n,p->count,p->word);
treeprint(p->right);
}
}
Structures 101
statementofthiscodeisarecursivecalltotreeprint()withthe
pointertotheleftchildpointerasanargument.Thisrecursivecallwill
causecontroltopropagatetothelowestandleftmostlevelofthetree.At
thistimetreeprint()willreturnnormally,andthewordpointedto
intheTnodewillbeprintedoutbytheprintf()call.Theprogram
will then start a recursive treeprint() to the right of this node.
Controlwillimmediatelygototheleftsideoftherightbranchandwill
descendthelowestlevelandprintoutthewordfound.Thisroutine
willrepeatupanddownuntilthewholetreecontenthasbeenprinted.
The function strsave() copies the word passed to it as an
argumentintoasaveplaceandreturnsapointertothismemoryloca-
tion to the calling program. C provides for dynamic allocation of
memory.
char*strsave(char*s)/*makeaduplicateofs*/
{
char*p;
p=(char*)malloc(strlen(s)+1);
if(p!=NULL)
strcpy(p,s);
returnp;
}
Up to this point, all memory access was to memory allocated by
declaration statements.With dynamic allocation, the program can
go to the operating system and request memory at any time. This
memoryisfromamemoryareacalledtheprogramheap.Thefirst
calltoallocatememoryismalloc()shownabove.Thefunction
prototypeforthisfunctionisfoundinstdlib.h ,andthefunc-
tion requires an argument that is the length of the memory space
needed.Theprogramreturnsapointertothebasetypeofthesystem,
chars, to the required block of memory. If there is not enough
memoryavailable,thefunctionreturnsaNULLpointer.Cwillnever
returnavalidNULLpointer.Therefore,ifyouhaveaCprogramcall
thatreturnsapointer,theprogramcanalwaystestforaNULL pointer
todetermineifthecallsucceeded.Intheabovecode,itisassumed
thatthecallingprogramwillcheckfortheNULLpointeranddeter-
minewhattodo.
102 Chapter 2 Advanced C Topics
Thefunctionprototypeofthefunctionmalloc()iscontained
instdlib.h.Thisfunctionreturnsapointertoatypevoid.If
youwillrecalltherulesofarithmeticforpointers,apointertoatype
voidcanbeassignedtoanyotherpointertype,andviceversa.There-
fore,itisnotnecessarytocastthereturnfromthemalloccallto
thetypechar*aswasdoneabove.Infact,therearepeoplethatsay
thatyoushouldnotperformthiscast.Ifyoumakeamistakeand
donotincludetheheaderstdlib.h,thenthecompilerwouldas-
sumethatthereturnfromthemallocfunctioncallisanint.The
castoperationwouldintroduceabugintoyourcodeiftheheader
were not included. The error of the missing header file would be
identifiedbythecompilerifthereisnocastbecausetheprogram
wouldbeloathetoassignanintegertoapointer.Therefore,thecode
withoutthecastismorerobust.
Ipersonallyobjecttothislogic.Thecurrenttrendistoinsistthat
alloperandsinexpressionsthatarenotofthecorrecttypebecast
to the correct type prior to execution of any operators. This trend
largelyignorestheautomatictypepromotionthattakesplacewhen
therearemixedtypeswithinasingleexpression.Infact,manypro-
grammingstandardsinsistthatallmixedtypesbecastexplicitly.In
suchanenvironment,itseemsrathersillythatonecasebesingled
outanddonedifferently.
The function talloc() also makes use of the malloc()
function. In this case, the argument of the malloc() call is the
sizeofoperator.sizeofisaCoperatorthatreturnsthesizeof
theargument.sizeofisanoperatorinCandrequiresnoprototype.
/*talloc:makeatnode*/
TNODE*talloc(void)
{
return(TNODE*)malloc(sizeof(TNODE));
}
Thememoryallocationfunctionmalloc()returnsapointerto
thebasicmemorysizeofthesystem.Itisalwaysnecessarytocast
thereturnfrommalloc()ontothetypeofvariablethatthereturn
mustpointto.Inthiscase,thecast istothetypepointertoTNODE.
Instrsave(),thecastwastothetypepointertochar.There-
fore,thestatement
Structures 103
return(TNODE*)malloc(sizeof(TNODE);
willreturntothecallingfunctionapointerofthetypeTNODEtoa
freememoryspacethesizeofaTNODE.Thisfunctioniscalledby
the function addtree().You will note that addtree() does
nottestthereturnfromtalloc()todetermineifthereturnisa
NULL pointer. Good programming practice would dictate that the
return from talloc() should be tested to make certain that
malloc()didnotreturnaNULLpointer.
Thenextfunctionthatmustbeincorporatedintotheprogramis
getword().getword()returnsthefirstcharacteroftheword
oranEOFinthecasethatanEOFisdetected.Itrequirestwoargu-
ments.Thefirstisapointertoacharacterarrayintowhichtheinput
dataaretobestored.Thesecondargumentisthelengthofthearray
andhencethemaximumlengthofanywordthatcanbereadintothe
program by getword().Two functions are accessed by
getword().Thefirstisgetch()whichreturnsacharacterfrom
theinputstream.Thesecondisungetch()whichrestoresachar-
acterbackontotheinputstream.Wewillseelaterthatforgetword()
toworkcorrectly,itmustpullonemorecharacterthanthelengthof
thewordinsomecases.Whenthathappens,theextracharactermust
beputbackontotheinputstreamsothatitwillbeavailableforthe
nextgetch()call.
/*getword:getnextwordorcharacterfrominput*/
intc,getch(void);
voidungetch(int);
intgetword(char*word,intlim)
{
char*w=word;
while(isspace(c=tolower(getch())));
if(c!=EOF)
*w++=c;
if(!isalpha(c))
{
*w=\0;
returnc;
}
for(;lim>0;w++)
104 Chapter 2 Advanced C Topics
if(!isalnum(*w=tolower(getch())))
{
ungetch(*w);
break;
}
*w=\0;
returnword[0];
}
Thefirstexecutablestatement
while(isspace(c=tolower(getch())));
includestwostandardCfunctions.Thefunctionisspace()has
its prototype in the header file ctype.h. This function returns a
TRUEifitsargumentisaspaceandFALSEotherwise.Thesecond
function,tolower(),isalsoprototypedinctype.h.Ittests
theargumentandreturnsalowercaseletteriftheargumentisupper
case.Therefore,thisoperationwillloopuntilitreceivesanonspace
input,andthelowercaseversionoftheletterinputwillbestoredinc.
Ifc isnotanEOF,itisputintothenextopenlocationoftheword
arrayandthepointerintothisarrayisincremented.Ifthereturnisan
EOF,thesecondifstatementwillexecute.Theifstatement
if(!isalpha(c))
{
*w=\0;
returnc;
}
teststodetermineifthecharacterfromtheinputstreamisaletter.
isalpha()returnsaTRUEifitsargumentisaletterandaFALSE
otherwise.Ifthecharactertakenfromtheinputstreamisan EOF,
isalpha()willreturnaFALSEandthestatementfollowingthe
ifwillbeexecuted.Inthiscase,azerocharacteriswrittentothe
word,andtheEOFisreturnedtothecallingfunction.
Ifthereturnisaletter,thefollowingsequencewillbeexecuted:
for(;lim>0;w++)
if(!isalnum(*w=tolower(getch())))
{
ungetch(*w);
Structures 105
break;
}
Thecentralloophereistheifstatement.Itsargumentexecutes
getch()toreadincharactersfromtheinputstream.Theseinputs
areconvertedtolowercaseandstoredintothearraylocationpointed
tobyw.Theresultisthencheckedtodetermineifitisaletterora
number.Ifitisnot,itisputbackontotheinputstreamandtheloop
is exited by the break instruction. If it is a letter or a number, the
pointertotheoutputarraywisincrementedandthemaximumlength
ofthearrayisdecremented.Ifthislastresultisgreaterthanzero,the
nextcharacterisreadin.Otherwise,theifstatementisskipped.
Thelasttwostatementsinthefunctionare
*w=\0;
returnword[0];
Thelastentryofthecharacterarrayismadea\0 tosatisfythe
C requirement that a string must terminate with a 0, and the first
characterofthewordisreturnedtothecallingprogram.Thisvalue
isreturnedjusttoguaranteethatanEOFisnotreturned.
Therearetwofinalfunctionsrequiredforthisprogram.Thesefunc-
tionsworktogethertoformthegetch()/ungetch()pair.Aglobal
buffer with an argument BUFSIZE is created, and a global integer
bufpisdeclared.bufpisinitializedto0.Sincethesevariablesare
global,theyareinitializedatthebeginningoftheprogram,andthey
willnotbechangedwhencontrolisreturnedtoacallingfunction.
Ingetch(),thevalueofbufpistested.Ifitisgreaterthan0,
the character returned is taken from the buffer and the bufp is
decremented.Otherwise,anewcharacterisreadfromtheinputstream
bygetchar().
#defineBUFSIZE100
charbuf[BUFSIZE];/*bufferforungetch*/
intbufp=0;/*nextfreepositioninbuffer*/
intgetch(void)/*getthenextcharacterfromthe
buffer*/
106 Chapter 2 Advanced C Topics
{
return(bufp>0)?buf[bufp]:getchar();
}
voidungetch(intc)/*putcharacterbackonto
input*/
{
if(bufp>=BUFSIZE)
printf(ungetch:toomanycharacters\n);
else
buf[bufp++]=c;
}
Whenungetch()isexecuted,atestismadetodetermineif
this store would exceed the buffer length. If bufp will be greater
thatBUFSIZE after it is incremented, an error return is executed.
Otherwise,thereturncharacterisputinthebufferanditisthereto
bereadthenexttimegetch()isexecuted.
ThisprogramhasintroducedseveralCfunctions.Infact,Chasa
ungetchar()thatdoesthesamefunctionasungetch()above.It
hasgivenexamplesofstructurescontainingpointerstolikestructures,
recursivefunctionstoprocessdata,anddynamicmemorymanagement.
EXERCISES
1.Withaneditor,enterthetreeprogramandcompileit.Torunthis
program,useaninputredirectionsuchasc:>tree<(filename)
2.Modifytheaboveprogramtodeterminethenumberoflevels,and
recordthelevelnumberwitheachword.Printoutthelevelswhen
the output is printed. Hint: the levels can be determined in the
addtree()function,andtheprintoutofthelevelsrequireamodi-
ficationoftreeprint().
3.Addahistogramtotheaboveprogramthatshowsthenumberof
entriesineachlevel.Countthetotalnumberofdifferentwordsin
thedocumenttested.
More Structures 107
More Structures
Therearetwomoreimportantconsiderationsthatshouldbeplaced
understructures.Thefirstoftheseistheunion,andthesecondisbit
manipulationsandbit fields.
Unions
Aunionisdefinedmuchthesameasastruct.Thereisasignifi-
cantdifference,though.Aunioncanhaveseveraldifferentarguments,
eachofwhichisadifferenttype.Thecompiler,whenitseesaunion
declared,providesenoughmemorytoholdthelargestargumentof
theunion.Whendifferentargumentsareused,thedifferenttypes
occupythesamememorylocation.Considerthefollowingsequence:
structbothints
{
inthi,lo;
};
unionboth
{
longl;
structbothintsb;
}compound;
Thissequencewillcausethecompilertogenerateastructurethat
containstwoints.Theunionbothwillprovidespaceforwhich-
everislarger,along orastructbothints.Ofcourse,along
is the size of struct bothints , so enough memory will be
providedtostorealong.Inuse,asequencelike
compound.b.hi=a;
compound.b.lo=b;
willplacetheintaintotheupperlocationofcompound,andb
will go into the lower location of compound.After these opera-
tions,compound.lwillcontainainitsupperword,andbinits
lowerword.Ifcompound.lwereusedasavariable,itwouldbe
thiscombination.
Unionsaremostoftenthoughtofasamethodofsavingmemory.
Ifseveralvariablesarecompletelyindependentandneverusedatthe
108 Chapter 2 Advanced C Topics
sametime,aunionthatcontainstheseseveralvariableswillallow
theprogrammertostoreeachinthesamememorylocation.
Bitfields
Theconceptsofbit fieldsfalllooselyunderstructures.Thefirst
built-in operations that allow bit manipulations from C involve an
enum.Considerthefollowingenum:
enum{PB1=1,PB2=2,OUT1=4,OUT2=8};
intPORTA;
Noticethatthedifferentelementsoftheenumareeachpowersof2.
Wecanthenuseanexpressionlike
PORTA|=PB1|PB2;
toturnonbitscorrespondingtoPB1andPB2intheintegerPORTA.
Or,thesecorrespondingbitsmightbeturnedoffinPORTAby
PORTA&=~(PB1|PB2);
Testscanbeexecutedlike
if(PORTA&(PB1|PB2)==0)
HeretheargumentoftheifcallwillbeTRUEifbothbitscorre-
spondingtoPB1andPB2areturnedoffinPORTA.
Thesemanipulationsarenotreallyspecialbitmanipulations.What
isseenhereismerelycreationofbit-likeoperationsusingnormalC.
C does support bit fields. Bit fields are created in the form of a
struct.Thefollowingstructdefinesseveralbitfields:
struct
{
unsignedintPB1:1;
unsignedintPB2:1;
unsignedintOUT1:1;
unsignedintOUT2:1;
unsignedintALL:4;
}FLAGS;
Thisstructconsistsofseveralbitfields.Thecolonthatfol-
lowsthefieldnamedesignatesthebitfieldwhosesizeisthenumber
More Structures 109
followingthecolon.Thefirstfourfieldsareeach1bitwide,andthe
finalfieldALLis4-bitswide.Thesebitscanbeturnedonby:
FLAGS.OUT1=FLAGS.OUT2=1;
oroff
FLAGS.OUT1=FLAGS.0UT2=0;
andtheycanbetested
if(FLAGS.PB1==0&&FLAGS.PB2==1)
...
Some of the compilers have special bit constructs. These con-
structsareusuallystructsthathaveeither8-or16-bitswithinthe
field.ThesestructsareusefulasBooleanvariables.
Whensettingupamicrocontrollerprogram,theprogrammerwill
frequently want to have bit fields at specific locations in memory.
ThesebitfieldscanbeusedasI/Oports,controlregistersandeven
arraysofbitstobeusedinternallyasflags.Anapproachtothisprob-
lemisfoundinthebitarray.
typedefstruct
{
bit_0:1;
bit_1:1;
bit_2:1;
bit_3:1;
bit_4:1;
bit_5:1;
bit_6:1;
bit_7:1;
}BITS:
Amacrodefinitionisusedtocreateavariable:
#definePORTA(*(BITS*)0x1000)
Withthesedefinitions,instructionstatementslike
PORTA.bit_7=0;
if(PORTA.bit_3==1&&PORTA.bit_2==0)
etc.canbeusedindealingwiththebitswithinthismemorylocation.
110 Chapter 2 Advanced C Topics
InputandOutput
Chasnoprovisionforeitherinputoroutputwithinthelanguage.
Anysuchoperationsmustbeprogrammedasfunctionsthatarecalled
fromtheprograms.ThereareseveralstandardI/Ofunctionsthatare
alwaysincludedwithacompleteCcompiler.However,inmanyin-
stances,compilersforverysmallmicrocontrollerswillhavenobuilt-in
input/outputcapability.
Fileaccessesarethroughasetoffunctionsandaspecialstruc-
ture.Thestruct FILEisastructurethatcontainsallparameters
neededtoaccessafile.Thefilepointerisgivenavalueby
FILE*fp;
FILE*fopen(char*name,char*mode);
Herenameisapointertoacharacterarraythatcontainsthename
ofthefile.Thisnamecanbesimplythefilenameifthefileresidesin
thedefaultdirectory,oritcanbethecompletepathname-filename
combinationforfileselsewhereinthefilesystem.Thestringpointed
tobymodeisaoneortwocharacterstring.Thevariousmodesare
rreadonly
wwriteonly
aappend
andsometimes
bbinary
rwread/write
Toopenafile,theprogrammustcontainastatement
fp=fopen(name,mode);
wherefpisdeclaredasapointertothetypeFILE.Oncethefileis
opened,allfileaccesseswillusefpasanargumentinsomeway.
Therearetwosinglecharacterfileaccessfunctions:
intgetc(FILE*fp);
intputc(intc,FILE*fp);
Thefirstfunctionreturnsacharacterfromanopenfilefpandthe
secondputsacharactercontoanopenfilefp.Therearethreespecial
filepointerscreatedbytheoperatingsystemwhenaprogramisloaded.
Thesethreefilepointersarestdin,stdout,andstderr.stdin
Input and Output 111
is the standard input, and defaults to the keyboard. stdout in the
standardoutputanddefaultstotheterminalscreen,andstderris
thestandarderroroutputwhichdefaultstotheterminalscreen.These
defaultscanberedirectedbytheoperatingsystemthroughtheuseof
redirectionoperatorsandpipeoperatorswhentheprogramisexecuted.
Thefunctionsgetchar()andputchar()aremacrodefini-
tions:
#definegetchar()getc(stdin)
#defineputchar(c)putc(c,stdout)
Therefore,getchar()willreadasinglecharacterfromthekey-
board,andputchar()willputasinglecharactertotheterminalscreen.
TherearestringI/Owiththefilefunctions.Astringcanbeputto
afileby
intfputs(char*string,FILE*fp);
This function returns an EOF if an error occurs. Otherwise, it
returnsazerowhenthereisnoerror.
Astringcanbereadfromafileby
intfgets(char*string,intmaxline,FILE*fp);
fgetsreturnsthenextinputlinefromthefilefp.Thesedataare
writtenintostring,andcancontainatmostmaxline-1charac-
ters.Thestringis0terminated.fgetswillreturnazerowhenan
erroroccurs.Ifthereisnoerror,fgetsreturnsthepointerstring.
Anotherimportantfileaccessfunctionis
intfclose(FILE*fp);
Thisfunctionreleasesthefilepointerfpanditcausesanydata
writtentothefile,butnotwrittentothefinaldestination,tobewritten.
Forexample,mostdiskfilesystemsuseabuffertostoreupasignifi-
cantamountofdatabeforeitiswrittentothedisk.Ifdataarebuffered
whenthefclose()routineisexecuted,anybuffereddataiswritten
tothediskandtheprogramconnectiontothefilesystemisdissolved.
Different compilers have several file handling routines.To ob-
tainthemaximumadvantageoftheseroutines,youshouldconsult
themanualthatcomeswithyourspecificcompiler.
We have seen several instances of input/output functions. The
mostcommonistheprintf()function.Thisfunctionisbutone
112 Chapter 2 Advanced C Topics
ofseveralfunctionsthatcanbegroupedtogetherunderthecategory
offormattedinput/output.Theformattedoutputfunctionsinclude
intprintf(char*format,arg1,arg2,...);
intsprintf(char*string,char*format,
arg1,arg2,...);
intfprintf(FILE*fp,char*format,arg1,
arg2,...);
Thefunctionprintf()hasbeenusedthroughoutthetextsofar,
andthereshouldbelittlequestionastoitsuse.Thisfunctionprintsdata
totheterminalscreen.Thepointerformatpointstoacharacterstring
thatcontainstheinformationtoprintout.Withintheformat,therecan
be conversion commands identified by a percent sign %.These com-
mandswillbediscussedindetaillater.Thenumberorarguments,arg1,
arg2,etc.dependonthenumberofcommandswithintheformatstring.
Thesecondfunctionabove,sprintf(),performsexactlythe
sameconversionasprintf().Ratherthanprintingtheresultto
the screen, it is written into the character array string in memory
designatedbychar*string.
Datacanbeprintedtoafilewiththethirdfunctionfprintf().
Herefpisthefilepointerofanopenfile,andtheremainderofthe
argumentsareexactlythesameaswiththeprintf()function.
Thefollowingisalistofalltheconversioncommandsandtheir
meanings.Ifthecharacterfollowingthe%inaformatstringisnot
foundinthetable,functionbehaviorswillbeundefined.
Character Printed as
d,i int:decimalnumber
o int:unsignedoctalnumber
x,X int:unsignedhexadecimalnumber
u int:unsigneddecimalnumber
c int:singlecharacter
s char*: print characters from string until \0 is
detected.
f double:floatingpoint[-]m.ddddwherethenum-
berofdsisgivenbyprecision.Defaultprecisionis6.
e,E double:floatingpoint[-]m.ddddExxwherethenum-
berofdsisgivenbytheprecision,andthepowerof10
exponentcanbeplusorminus.Defaultprecisionis6.
Input and Output 113
g,G Useseorfformat,whicheverrequiresleastspace.
% Noargumentisconverted.Printasa%
Additional formatting capability exists. The complete form of
the%commandisasfollows:
%[flags][width][.precision][modifier]type
wherethevariousoptionalfieldshavethefollowingmeanings.
flags
- Left-justifythevalueifthereisawidthfieldspeci-
fied.
+ Printleading+characterforpositiveoutputs
width
Width Precision
Minimumwidthof
printzone.Padthe
fieldwith0ifthe
leadingwidth
specifieris0.
Thenumberofdigits
totherightofthe
decimalpoint.For
strings,themaximum
numberofcharacters.
Modifier
Modifier Meaning
h Usedwithanyintegraltype,datatypeisshort.
l Usedwithanyintegraltype,datatypeislong.
L Usedwithanyfloatingpointtype,thedatatypeis
longdouble.
Thisformattingapproachworkswithstringsaswellasnu-
mericaloutputs.Ifastringoutputcontainsafieldwidthoraprecision,
it works much the same as a numerical output. If the field width
specifiedisnotlongenoughtoholdtheoutputstring,thespecified
field width is ignored. The complete string is printed out. With a
string, precision specifies the number of output characters. If the
precisionissmallerthanthefieldwidth,thewidthoftheoutputfield
willbetheprecisionspecification.Aminussignappliedtofieldwidth
114 Chapter 2 Advanced C Topics
willcausethedatatobeprintedtotheleftedgeofthefield.Other-
wise,thedatawillprinttotheextremerightedgeofthefield.
FormattedinputisalsoprovidedinC.Thethreeformatted
inputfunctionsare
intscanf(char*format,arg1,arg2,...);
intsscanf(char*string,char*
format,arg1,arg2,...);
intfscanf(FILE*fp,char*format,arg1,arg2,...);
Thefirstofthesefunctionsreadsformatteddatafromthestandard
input,thesecondreadsformatteddatafromastringinmemory,and
thethirdreadsformatteddatafromanopenfilefp.Thereisasig-
nificantdifferencebetweentheformattedinputsandoutputs.Recall
thattheargumentsintheformattedoutputsaredatavalues.Inthe
formatted inputs, all arguments must be pointers to locations in
memorythatcanholdthedatatypesspecifiedinthedatastring.If
theprogramshouldcontain
inti;
.
.
.
scanf(%d,i);/*BAD*/
theprogramwillprobablycompile,thecompilerswillnotnotean
error,andtheprogramwillcrashbecausethescanf()argumentis
notapointer.Itisgenerallyrecommendedthatyouavoiduseofthe
scanf()function.
Memory Management
TherearetwofunctionsinCthatallowdynamicmemoryman-
agement.Thefunction
void*malloc(size_tn);
returns a pointer to a block of memory that is n bytes long. This
memoryisuninitialized.malloc()(andcalloc()below)re-
turnsapointertoablockofmemoryofthetypevoid.Therefore,
beforeitcanbeused,thereturnpointermustbecastontothedata
type that the program requires. In this case, an assignment of the
returnvaluetoapointerofthecorrecttypewillwork.Ifthisstepis
Memory Management 115
not taken, none of the usual pointer arithmetic will work. If the
memoryisnotavailabletobeallocated,theallocationprogramwill
returnaNULL.
Aseconddynamicmemoryallocationfunctionis
void*calloc(intnumber,size_tn);
Thisfunctionreturnsapointertoatypevoid.Ittakestwoarguments.
Thefirstargumentisthenumberofitemsandthesecondargumentis
thesizeofthespecificitem.Therefore,ifyouwishedtoallocatespace
fortenTNODEsfromtheaboveproblem,youshoulduse
(TNODE*)calloc(10,sizeof(TNODE));
calloc()differsfrommalloc()inthatitreturnsapointerto
initialized space. The calloc() function initializes all memory
assignedbythefunctiontozero.Whenmemoryisallocatedbyei-
thermalloc()orcalloc(),thismemorymustbereturnedto
thesystem.Ifallocatedmemoryisnotreturnedtothesystem,even-
tuallyalloftheavailablememorywillbeallocated.Furtherattempts
toallocatememorywillfail.Ifthereturnpointerfromtheallocation
functionisnottestedandproperlyhandledwhenaNULLisreturned,
the program will exhibit undefined behavior.This problem can be
avoidedbydeallocatingmemorywhenitisnolongerneededbythe
program.Thefunction
voidfree(void*);
willreleaseallocatedmemory.Theargumentinthiscasemustbea
pointerthatwasreturnedfromanallocatefunction,eithermalloc()
orcalloc().
Anadditionalmemoryallocationfunctionis
void*realloc(void*,size_t);
Thefirstparameterhereisapointertoapreviouslyallocatedmemory
block,andthesecondisthenewsizethatyouwantfortheallocated
memory.Thisfunctionwillchangethesizeoftheallocatedmemory
block.Ifyouarereducingthesizeoftheblock,thepointerreturned
will probably be the same as that passed to realloc. If you are
increasingthesizeoftheblock,andthereisnotenoughcontiguous
memoryavailable,thefunctionwillsearchforapropersizedblock.
116 Chapter 2 Advanced C Topics
Ifoneisfound,thedatastoredintheoriginalblockarecopiedtothe
newblockandtheproperspaceisallocated.Thepointerreturnedin
thiscasewillnotbethesameasthatpassed.
Miscellaneous Functions
Cprovidesseveralsetsofmiscellaneousfunctionsthatarevery
useful. As mentioned earlier, the input/output functions that are
prototypedin stdio.harenotpartsofthelanguage,butinstead
areseparatefunctions.Themiscellaneousfunctionsareprototyped
isseveraldifferentheaderfiles.Manyofthesefunctionsaremacros,
andiftheyare,themacrodefinitionsarecontainedintheheaderfile.
FollowingisalistofseveralheaderfilesspecifiedbytheANSI
Standard.Witheachheaderfileisalistoffunctionsorfunctionpro-
totypes contained within these files. You should look to the
documentationforyourcompilertogetthedetaileddescriptionsof
eachofthesefiles.
Asmentionedearlier,thesefilesarethere,tested,workandare
probablyasrobustandreliableasanycodewritten.Theydowhat
theyaresupposedto,andtheyarefree.Itmakeslittlesensetore-
write these programs just to satisfy an ego trip. I have seen shop
codingstandardsthatdidnotallowtheuseofstandardlibraryfiles
becausetheprogrammerscouldnotexaminethesourcecode.Sucha
standardisabsolutelysilly.Ifyoudonottrustthecompilertopro-
videsafe,satisfactorylibrarycode,youshouldnottrustthecompiler
togenerateanycode.Therefore,youareusingthewrongcompiler.
Getacompilerthatmeetsyourstandard.
Mostembeddedprogramsthatemploymicrocontrollersdonot
havestandardconnectionstoinput/outputdevices.Forexample,there
israrelyaterminalorakeyboardattachedtoanembeddedsystem.
Morelikelyyouwouldexpecttofindanumeric,orspecial,keypad
andanLCDspecialpurposeoutputdisplay.Noneofthestandardi/o
programs can connect with such devices. In such cases, it will be
yourresponsibilityastheprogrammertowritedriverstointerface
withthesedevices.Also,youwillrarelyseediskfilesinyourem-
beddedproduct.Therefore,youwillrarelyneedtoincludetheheader
filestdio.hinamicrocontrollerprogram.
Miscellaneous Functions 117
STRINGOPERATIONSDefinedinstring.h
strcat(s,t) concatenatettos
strncat(s,t,n)concatenatencharactersofttos
strcmp(s,t) returnnegative,0,orpositive
fors<t,s==t,ors>trespectively
strncmp(s,t,n)comparencharactersoftands
strcpy(s,t) copyttos
strncpy(s,t,n)copyncharactersofttos
strchr(s,c) pointtothefirstcinsor\0
strrchr(s,c) pointtolastcinsor\0
CHARACTERTESTSinctype.h
isalpha(c) non-zeroifcisalphabetic,0ifnot
isupper(c) non-zeroifcisuppercase,0ifnot
islower(c) non-zeroifcislowercase,0ifnot
isdigit(c) non-zeroifcisadigit,0ifnot
isxdigit(c) non-zeroifcisahexadecimaldigit,0ifnot
isalnum(c) non-zeroifc isadigitoralphabetic,zeroifnot
isspace(c) non-zeroifcisablank,tab,newline,
return,formfeed,verticaltab,0ifnot
ispunct(c) non-zeroifcisaprintingcharacterexcept
space,letter,ordigit
iscntrl(c) non-zeroifcisacontrolcharacter,0ifnot
isgraph(c) non-zeroifprintingcharacterexceptspace
isprint(c) non-zeroifprintingcharacterincludingspace
toupper(c) returncconvertedtouppercase
tolower(c) returncconvertedtolowercase
MATHFUNCTIONSinmath.h
sin(x) sineofx,xinradians
cos(x) cosineofx,xinradians
tan(x) tangentofx,xinradians
asin(x) arcsineofx,-1<=x<=1
acos(x) arccosineofx,-1<=x<=1
atan2(x,y) fourquadrantarctanofy/x,inradians
atan(x) twoquadrantarctanofx,inradians
sinh(x) hyperbolicsineofx
118 Chapter 2 Advanced C Topics
cosh(x) hyperboliccosineofx
tanh(x) hyperbolictangentofx
exp(x) exponentialfunctionofx
log(x) logarithmbaseeofx
log10(x) commonlogarithmofx
pow(x,y) raisextotheypower
sqrt(x) squarerootofx
fabs(x) absolutevalueofx
ceil(x) smallestintegernotlessthanx
floor(x) largestintegernotgreaterthanx
ldexp(x,n) x*2^n
frexp(x,int*exp) splitdoubleintomantissaandexponent
modf(x,double*ip)Splits x into integral and fractional
parts.Putsintegralinipandreturns
fractionalpart.
fmod(x,y) floating-pointremainderofx/y
Thesefunctionsallrequiredoubleargumentsandreturndoublevalues.
Utilityfunctionsinstdlib.h
doubleatof(constchar*s);
integeratoi(constchar*s);
longatol(constchar*s);
doublestrtod(char*str,char**scanstop);
longstrtol(char*str,char**scanstop,intbase);
unsignedlongstrtoul(char*str,char**scanstop,intbase);
ldiv_tldiv(longnumer,longdenom);
div_tdiv(intnumer,intdenom);
longlabs(longn);
intabs(intn);
void*bsearch(void*key,void*base,size_tnumber,size_tsize,
int(*compare)(void*,void*));
voidqsort(void*base,size_tnumber,size_tsize,
int(*compare)(void*,void*));
intrand(void);
intsrand(unsignedintseed);
void*calloc(size_tnobj,size_tsize);
void*malloc(size_tsize);
void*realloc(void*p,size_tsize);
Miscellaneous Functions 119
voidfree(void*p);
voidabort(void);
intatexit(void(*fcn)(void));
voidexit(intstatus);
intsystem(constchar*name);
Non-localJumpsinsetjmp.h
intsetjmp(env);
intlongjmp(env,int);
Diagnosticsinassert.h
Themacroassert()isdefinedinassert.h
Signalsinsignal.h
void(*signal(intsig,void(*sighandler)(int)))(int);
intraise(intsig);
DateandTimeFunctionsintime.h
char*asctime(structtm*timeptr);
clock_tclock(void);
char*ctime(time_t*timer);
doubledifftime(time_ttime2,time_ttime1);
structtm*gmtime(time_t*timer);
structtm*localtime(time_t*timer);
time_tmktime(structtm*timeptr);
size_tstrftime(char*buffer,size_tbufsize,char*format,
structtm*timeptr);
time_ttime(time_t*timer);
Standardinputandoutputinstdio.h
void clearerr(FILE*fp);
int fclose(FILE*fp);
int feof(FILE *fp);
int ferror(FILE *fp);
int fflush(FILE*fp);
int fgetc(FILE*fp);
int fgetpos(FILE*fp,fpos_t*pos);
char *fgets(char*buffer,intn,FILE*fp);
FILE *fopen(char*filename,char*access);
120 Chapter 2 Advanced C Topics
int fprintf(FILE*fp,char*format,...);
int fputc(intc,FILE*fp);
int fputs(char*string,FILE*fp);
size_t fread(void*buffer,size_tsize,size_tnumber,FILE
*fp);
FILE *freopen(char*filename,char*mode,FILE*fp);
int fscanf(FILE*fp,char*fs,...);
int fseek(FILE*fp,longoffset,intorigin);
int fsetpos(FILE*fp,fpos_t*pos);
long ftell(FILE*fp);
size_t fwrite(void*buffer,size_tsize,size_tnumber,FILE
*fp);
int getc(FILE*fp);
char *gets(char*buffer);
void perror(char*string);
int printf(char*format,...);
int putc(intc,FILE*fp);
int puts(char*string);
int remove(char*filename);
int rename(char*oldname,char*newname);
void rewind(FILE*fp);
int scanf(char*format,...);
void setbuf(FILE*fp,char*bufptr);
int setvbuf(FILE*fp,char*bufptr,intbuftype,size_t
bufsize);
int sprintf(char*s,char*format,...);
int sscanf(char*s,char*format,...);
FILE *tmpfile(void);
char *tmpnam(char*buffer);
int ungetc(intc,FILE*fp);
int vfprintf(FILE*fp,char*format,va_listarglist);
int vprintf(char*format,va_listarglist);
int vsprintf(char*s,char*format,va_listarglist);
Asyouscanthroughtheabovelistings,youwillseemanytypes
thatarenotfromtheusuallistofavailabletypes.Wheneveryoufind
suchatype,thetypewillbeeitheratypedefofastructureora
typedefofastandardtype.Thesetypedefs willbefoundinthe
headerfilewheretheyareused.
Summary 121
Summary
Inthischapter,youhaveseenhowpointersareusedinC,learned
aboutstructures,andviewedasummaryofthecontentsofthestan-
dardClibrary.Youhavealsobeenshowntheessentialsofcreating
headerfilesthatcanattachperipheraldevicestoyourprograms.These
areaswillbeexploredindetailinlaterchapters.
[This is a blank page.]
Chapter 3
WhatAreMicrocontrollers?
Amicrocontrollerdiffersfromamicroprocessorinseveralim-
portant ways. The early name for a microcontroller was
microcomputer.Thebigdifferencebetweenamicroprocessoranda
microcomputer/microcontrolleristhecompletenessofthemachine
eachrepresents.Amicroprocessorwassimplytheheartofacom-
puter.Toputamicroprocessorintouse,thedesignerrequiredmemory,
peripheralchips,andserialandparallelportstomakeacompletely
functionalcomputer.Bycontrast,themicrocomputerwasdesigned
tobeacompletecomputeronasinglechip.Necessarymemoryand
peripheralcomponentswereintegratedontothechipsothatacom-
plete computer-based system could be built with a minimum of
externalcomponents.Abasicmicrocontrollerisshowninblockdia-
gramforminFigure3-1.
Arithmetic
LogicUnit
Input/Output
Program
Memory
DataMemory
Figure3-1:ATypicalMicrocontrollerBlockDiagram
123
124 Chapter 3 What Are Microcontrollers?
Thecentralcontrolunitofthemicrocontrolleristhearithmetic
logic unit (ALU). Figure 3-1 shows that theALU is connected to
threedifferentblocks.Thefirstistheinput/outputblock(I/O),the
second is the program memory, and the third is the data memory.
MostMotorolamicrocontrollerscombinethelastthreeblocksinto
oneblock.ThearchitectureshowninthefigureisknownasaHarvard
architecture, as opposed to the more common Von Neumann
architecture.TheHarvardarchitectureisacomputerconfiguration
inwhichthememoryareathatcontainstheprograminstructionsfor
thecomputerisseparatedfromthememoryareainwhichdataare
stored. By contrast, the Von Neumann architecture has just one
memoryspacewherebothprogramanddataarestored.
The main functional difference between Harvard and Von
Neumann architectures is in their ultimate operating speeds. Both
architectures require that the ALU access memory once each
instructiontogetthenextinstructiontoexecute.Oftentheinstruction
beingexecutedwillalsorequireanaccesstomemory.Readingdata
into a register, storing data in a memory address, and accessing a
locationinmemorythatisinfactaninput/outputregisterareexamples
ofoperationsthatrequirememoryaccessesinadditiontothenormal
memoryfetches.AsseeninFigure3-1,theHarvardarchitecturehas
twoormoreinternaldatabussesoverwhichthesedifferentaccesses
cantakeplace.Thereareusuallytwosuchinternalbusses:onefor
instructionaccess,andoneforotherdataaccess.Theprocessorcan
easilytellwhichdatabustouse.Iftheaccessistofetchaninstruction,
itisrelativetotheprogramcounter.Theseaccesseswillgotothe
programmemoryarea.Allothermemoryaccesseswillgotothedata
memory area. It is entirely possible to have two or more memory
accessessimultaneouslywithaHarvardarchitecture.
TheVon Neumann architecture is somewhat simpler than the
Harvardarchitecture.AVonNeumannprocessorhasonlyonememory
bus.All memory accesses must go through this single path on the
system. With such a system, the processor can never process more
thanonememoryaccessatatimeandallmemoryaccessesinstruction,
data,orinput/outputmustpassthroughasingledatabus.Thisisthe
originofthetermVonNeumannbottleneck.Themultipleaccesses
tomemoryforeachinstructionultimatelylimitthemaximumspeedof
aVonNeumannarchitectureprocessor.However,thespeedofsuch
processorscanbemanymillionsofinstructionspersecond,sothere
What are Microcontrollers? 125
arenumerousexcellent,fastmicrocontrollersconstructedwiththeVon
Neumannarchitecture.TheVonNeumannarchitecturehasbeenthe
mainstay of microcontrollers and will be the only microcontroller
configurationavailablefortheforeseeablefuture.
Amicrocontrollerhasitsprogramstoredinternally,andtheALU
readsaninstructionfrommemory.Thisinstructionisdecodedbythe
ALU and executed. At the completion of the execution of the
instruction, the next instruction is fetched from memory and it is
executed.Thisprocedureisrepeateduntiltheendoftheprogramis
found,ortheprogramgetsintoaloopwhereitisinstructedtobranch
backtoabeginningpoint.Inthiscase,themachinewillstayinthe
loop forever or until something happens to release it from the
never-endingloop.
Therearethreewaysforamachinelockedinalooptoberemoved
from the loop so it can execute code outside of the loop. These
operationsarecalledexceptions.Thefirstistoresetthepartwitha
resetsignal.Aresetsignalusuallyrequiresconnectingtheresetpin
oftheparttoalogiclowsignal.Alogiclowisusuallyground.When
this condition is detected, several internal registers are set to
predeterminedvalues,andthemicrocontrollerfetchestheaddressof
the reset routine from a specific memory location.This address is
placed in the program counter, and the program starts to execute.
There is a table in memory that contains the addresses of several
routinesaccessedwhenexceptionsoccur.Thesearetheaddressesof
theinterruptserviceroutines,resetroutines,etc.Thistableiscalled
thevectortable,andtheaddressesarecalledvectors.
Asecondmeansofforcingthepartoutoftheloopisforthepart
todetectanexternalinterrupt.Anexternalinterruptoccurswhenthe
interruptrequest(IRQ)pinonthepartissetlow.Thispinistestedat
thebeginningoftheexecutionofeachinstruction.Therefore,ifan
instructionisbeingexecutedwhenanIRQisasserted,theinstruction
willcompletebeforetheIRQsignalisprocessed.Processingforthe
IRQconsistsoffirstdeterminingifIRQsareenabled.Iftheyare,the
statusofthemachineissaved.Allinterruptsaredisabledbysetting
the interrupt mask bit in the status register of the microcontroller.
ThentheaddressstoredintheIRQvectorlocationisfetched.This
address,theaddressoftheinterruptserviceroutine(ISR),isplaced
intheprogramcounter.TheISRthenexecutes.
126 Chapter 3 What Are Microcontrollers?
The process of saving the status of the machine is to push the
contentsofallmachineregistersontothemachinestack.Therefore,
theISRcansafelyuseanyofthecentralmachineresourceswithout
disrupting the operation of the main line of code when control is
returned. When exiting an ISR, it is necessary to use a special
instructioncalledareturnfrominterruptorareturnfromexception.
Thisinstructionrestoresthestatusofthemachinefromthestackand
picksupexecutionofthecodefromtheinstructionfollowingtheone
wheretheinterruptoccurred.
Thethirdmeansforexitingthemainloopoftheprogramisfrom
internalinterrupts.Themicrocontrollerperipheralscanoftencause
interrupts to occur.An internal interrupt causes exactly the same
sequence of operations to occur as an external interrupt. Different
interruptvectorsareusedforeachoftheseveralinternalperipheral
partssothecauseoftheinterruptisgenerallyknownandcontrolis
directedtothespecificISRforeachoftheseveralpossibleinternal
interrupts.
Dataaretransferred,informationispassed,oreventsarehandled
eithersynchronouslyorasynchronously.Thedifferencebetweenthese
twomethodsofdatatransferhasmainlytodowithhowtheclocking
ofthedataishandled.Themostcommonformofsynchronousdata
transferiswithathree-wireseriallink.Oneofthewiresisaclock,
andtheothertwoareinputdataandoutputdata,respectively.Fora
synchronoustransfer,thevalueoftheinputisusuallysampledatone
edgeoftheclocksignal(suchasthefalloftheclock)andthevalue
ofthebittobesentoutisguaranteedtobecorrectatthefallofthe
clocksignal.Anysynchronoussystemmustsetitsoutputatsucha
timethatitwillbestablewhiletheclockishigh,andholditinthat
conditionuntiltheclocksignalfalls.Toreceiveabit,thecondition
oftheinputlinemustbelatchedintothesystemastheclocksignal
fallsfromhightolow.
Withinthecomputer,thereisanotherdistinctionforsynchronous.
Oftenaninputisallowedtosetabitwhenitoccurs.Ifthishappens,
theprogramwillnotexpeditiouslyobservethefactthatthebitisset.
In fact, the program will test the state of the bit according to the
programtimingrequirements.Thistypeofoperationisalsocalled
synchronousbecausethetestissynchronizedwiththeprogram.
Asynchronousoperation,ontheotherhand,usuallydependsona
prearranged series of events to cause the data transfer. Serial data
Microcontroller Memory 127
communicationsisacommonexampleofasynchronousdatatransfer.
Here, an input line can have two states: mark and space.A line is
heldatthemarkstatewhenevernodataarebeingtransferred.When
dataaretobetransferred,thedatalineistransitionedtothespace
state and held there for a specified time.This period is called the
startbit.Fromthattimeonward,thedatabitsareplacedontheline
a bit at a time so that at the specified time intervals the receiving
devicecanexaminethedatalineanddeterminethebitsequence.
Asynchronousoperationmeansthatthereisnocomputerclock-
related specification as to the time that events will occur.Another
example of asynchronous transfer occurs within the computer.
Generally, events and data transfers that are initiated by interrupts
areconsideredtobeasynchronous.Mostoftheperipheraldevices
that are found on Motorola microcontrollers will allow either
synchronous or asynchronous notification of the program that the
peripheralbusinessiscompleted.
Thefollowingsectionscontainbriefdiscussionsofmicrocontroller
memoryandseveralofthestandardperipheralsfoundonthesedevices.
Thesediscussionsareintendedtobequalitativeandprovideabroad
overviewofthesepartsofthemicrocontroller.Detaileddescriptions
of how to access and use these several peripherals will be found in
laterchapters.
Microcontroller Memory
Inamicrocontroller,theprograminstructionsareusuallystored
inamemorytypecalledread-onlymemory(ROM).ROMisusually
programmed by a special mask during the manufacture of the
microcontrollerandiscalledmaskedROM.ROMistheleastexpensive
meansofstoringaprograminamicrocontroller,especiallyforhigh-
volumemanufacturing.
Thereareatleasttwomeansfortheenduserofthemicrocontroller
toplacetheprogrammemoryintothechip.Thefirstiscallederasable
programmableread-onlymemory(EPROM).EPROMisamemory
technologythatcanbeerasedbyexposingittohigh-energyultraviolet
light.TheEPROMrequirestheapplicationofahighvoltagetobe
programmed. The memory can be programmed with either a
development system or a special programming board designed
specificallytoprogramthemicrocontroller.
128 Chapter 3 What Are Microcontrollers?
Packages that contain EPROM have a quartz glass window
throughwhichtheultravioletlightcanpasswithminimumattenuation.
Thesepackagesarequiteexpensive,andtherefore,microcontrollers
withEPROMareusuallytooexpensivetouse.EPROMwasusedfor
developmentpurposesinthepast,butitisjusttooexpensiveinlight
ofmorerecentdevelopmentstobeusedforthatpurposetoday.
Forlimitedproductionpurposes,alessexpensiveversionofthe
EPROMchipisavailable.Thisistheonetimeprogrammable(OTP)
chip. An OTP chip has the exact same silicon component as an
EPROM,butitispackagedinastandardplasticpackage.Thispackage
is much less expensive than the windowed package discussed
previously. However, once the chip has been programmed, the
programcontentscannotbechanged.
There is yet another means of storing programs or, in some
instances, data in a microcontroller. This technique is called
electricallyerasableprogrammableread-onlymemory(EEPROM).
EEPROM is programmable from instructions within the
microcontroller.EEPROMalsorequiresahighprogrammingvoltage.
IftherearelargeblocksofEEPROMonthechip,theprogramming
voltageisusuallyappliedduringtheprogrammingcyclethrougha
pinconnectedtoanexternalvoltagesource.Incaseswheretheamount
ofEEPROMtobeprogrammedisrelativelysmall,achargepumpon
themicrocontrollerchipwillallowtheEEPROMtobeprogrammed
with no externally applied voltage. The amount of EEPROM that
can be programmed with an on-board charge pump is usually so
smallthatitisnotusefulforstoringprograminstructions.Buton-
boardEEPROMcanbequiteusefulinthestorageofdatagenerated
by the program that must be saved through a power-down cycle.
Sometimesintheexecutionoftheprogram,somedataaregenerated
thatmustbesavedforlateruse.Thesedataarecalledvolatiledataor
variables,andareusuallystoredinrandomaccessmemory(RAM).
Carefuldesignofaprogramwillusuallyresultintheneedformuch
lessRAMthanROM.Inmostmicrocontrollers,theamountofRAM
isusually60toatmostafewhundredbytes.TheamountofROM,
EPROM or EEPROM usually runs from 1000 bytes upwards to a
fewtensofthousandsofbytes.
EEPROMisquiteexpensive,andhasbeenreplacedbyanewer
technologycalledFLASHmemory.FLASHprogramsinamanner
Input/Output 129
similar to EEPROM and it is inexpensive enough to allow rather
largeamountsofprogrammablememoryonamicrocontrollerchip.
Youwillfindchipswith30,000bytesandmoreofFLASHandthe
intent is to use these chips for production runs. The FLASH is
programmedaspartoftheproductioncycle.Wewillseemanydetails
onprogrammingFLASHmemoryinlaterchapters.
The architecture of Motorola microcontrollers is strictly Von
Neumann.Thatis,withinthemicrocontrollerchip,thereisonlyone
databusoverwhichallprogram,data,andinput/outputmustpass.In
aHarvardarchitecturesystem,eachofthesedifferentdatatypeswill
haveadedicatedbusoverwhichtheinformationwillpass.Therefore,
theHarvardarchitecturemicrocontrollerisabletoaccessdata,program,
andI/Osimultaneously.Thesimultaneousavailabilityofthesedifferent
datapathscanresultinasignificantincreaseinoverallprocessorspeed.
Italsoincreasestheareaofthemicrocontrollerdieand,hence,thecost
ofthemicrocontroller.Ingeneral,mostoftheapplicationstowhich
themicrocontrollersaredirecteddonotrequireextremespeed.Thus,
theVonNeumannarchitectureiscompletelysatisfactory.
Input/Output
TheMotorolamicrocontrollersuseanarchitecturecalledmemory-
mapped I/O. Each I/O device input and output registers, its control
registers,andstatusregistersaremappedintomemorylocations.I/O
transactions require no special computer instructions. It is merely
necessarytoknowthememorylocationsofthepertinentregistersand
theusesoftheregisterbitstobeabletohandleanyI/Ofunction.Listed
belowarebriefdescriptionsofseveralmicrocontrollerI/Operipherals
foundonMotorolamicrocontrollers.Notalloftheseperipheralsystems
arefoundoneachmicrocontroller.Itispossibletopickandchoose
between needs for the several peripheral systems and select a
microcontrollerthathasexactlythoseperipheralsrequired.
TimerSubsystems
Therearefourpopulartimersystemsthatyouwillfindondifferent
microcontrollers.Thefirstisageneral-purposetimer.Motorolarefers
to the general-purpose timers as either 8- or 15-bit timers. These
timersaredifferent.The8-bitsystemcontainsaprescalerthatcounts
downfromsystemclock.Theoutputfromtheprescalerisfedintoa
130 Chapter 3 What Are Microcontrollers?
counter that counts down from it the value stored in it.When the
counterunderflows,aflagisset,andaninterruptcanbeexecuted.
The 15-bit timer is a strictly Motorola name, and it is even
simpler than the 8-bit timer. This timer has a 15-bit minimally
programmable prescaler. An interrupt can be taken from two
locationsinthisripplecounter.
A second class of timer is the 16-bit timer.This timer is often
calledageneralpurposetimer.Thesetimerscontaina16-bitcounter
that is clocked by the system clock. There are two associated
subsystems:thefirstiscalledaninputcapturesystem,andthesecond
istheoutputcompare.
Theinputcapturesystemsimplycapturesthevalueofthesystem
timercounterwhenaninputoccurs.Theseinputscansetaflagor
requestaninterruptsotheinputcanbeprocessedeithersynchronously
orasynchronously.Theimportantfactisthattheexacttimeofthe
input relative to the 16-bit clock is saved when the input occurs.
Applications for input capture systems are interpulse period
measurementsorfrequencymeasurements.
Theoutputcomparesystemallowstheprogrammertospecifya
timerelativetothe16-bitcounterwhenanoutputistooccur.This
timeiscalculatedbyaddingthetimeoffsetvaluetothecurrentvalue
of the 16-bit counter. This result is stored in the output compare
register.Whenthe16-bitcountercountstothevalueintheoutput
compareregister,theoutputoccurs,abitisset,andaninterruptcan
beprocessedifdesired.
Inputcaptureandoutputcomparefunctionsaresometimescalled
high-speed inputs and outputs. The number of input captures and
outputcomparesystemsvaryfromasfewasoneeachtoasmanyas
16programmabletimers,eachofwhichcanbeeitherinputcapture
oroutputcompare.
Thereisanotherstyleoftimersubsystemthatisusedonhigh-end
microcontrollers.Thissystemiscalledthetimerprocessorunit(TPU).
Inmostconventionalcomputers,thecontentsofamemorylocation
arecalledanoperand,andtheprocessorhasbuilt-inoperatorsthat
operateontheoperands.ATPUisalsoacomputer,butratherthan
usingmemorylocationcontentsasoperands,timeisthemainoperand
used by the TPU. Most TPUs contain many complex systems to
implementtheiroperation.TheTPUoftheM68300familyandthe
M68HC16familycontainssixteenregisters,eachofwhichcanbe
Input/Output 131
operatedaseitheraninputcaptureoranoutputcompare.Eachoutput
compare can have its events coupled to other registers to control
intricatetimingeventswithfinetimeresolution.Wewillnotseethe
directprogrammingofaTPUinthistext,butwewillseesomeofthe
typesofeventsthatarecontrolledbytheTPUprogrammedwiththe
usual16-bittimer.
On the newer computers, such as the MCORE architecture, a
time-of-day(TOD)clockhasbeenintroduced.Thisclockisbasedon
a32768-Hzwatchcrystal.Thesecrystalsarereadilyavailable,small,
veryaccurate,andquiteinexpensive.Theironlyproblemisthatthey
areslow,andarenotverygoodforfinetimemeasurementsunless
thecrystalisusedasatimebasetoafrequencysynthesizer.
Another timer function found on most microcontrollers is the
computer operating properly (COP) or watchdog timer. Most
microcontrollers are placed in embedded controls. That is, the
microcontrollerisapartofalargersystem,andusuallyanoperator
neverdealsdirectlywiththemicrocontroller.Eventhoughgreatcare
hasbeentakeninthedesignofthemicrocontroller,itispossibleto
cause these devices to get lost from the program that they are
executing.Thepowermightdip,oralargetransientmagneticfield
mightcausetheparttogointoabnormaloperation.Insuchacase,
theeasiestwaytorestorenormaloperationistosendthepartthrough
aresetsequence.Suchasequencewillrestorealloftheinitialinternal
statusofthemicrocontroller,executetheinitializationcodeprocedure
oftheprogram,andrestarttheexecutionoftheapplicationloop.A
COPtimerprovidesjustthisfunction.ACOPtimerisatimerwitha
relativelylongperiod.OncetheCOPtimerisstarted,itisnecessary
for the main program to reset the COP periodically prior to the
expiration of the COP period. The COP timer is never allowed to
timeout.Ifthecomputergetslost,theprogramnolongerresetsthe
COP,sothetimerwilleventuallyoverflow,andthisoperationcauses
themicrocontrollertoreset.Therefore,ifthepartevergetslostfrom
itsnormalprogramsequence,theCOPwillforcearesetandrestore
thenormaloperationofthesystem.
DigitalInput/Output
MostmicrocontrollershaveseveraldigitalI/Oports.Usuallyaport
consistsofeightorfewerbits,andthebitsintheseportscanbeoutputs,
inputs,oroftenbitprogrammableaseitherinputoroutputbits.Ifa
132 Chapter 3 What Are Microcontrollers?
port has programmable I/O, it will have an associated data direction
registerDDRA,DDRB,andsoforth.TheportsareusuallynamedPORTA,
PORTB,andsoforth.DDRAisassociatedwithPORTA.EachbitinDDRA
hasacorrespondingbitinPORTA.IfabitinDDRAisset,thecorresponding
bitinPORTAisanoutput.ThesameistrueforPORTB,PORTC,PORTD,
PORTE,andsoforthiftheseportsexistonthepart.
Aportpincanbemadeintoanoutput.Whenthisoccurs,thispin
becomes a latched output. In other words, when this bit is set it will
remainsetuntilitisresetbytheprogram,andviceversa.Justbecausea
portpinisdesignatedtobeanoutputdoesnotmeanthatitsstatecannot
bereadbythecomputer.Whenaportisreadin,thestateofallofthe
outputsaswellasthestateoftheinputswillbeshownintheresult.
SomeI/Opinsaremultiplexedandservemultiplefunctions.For
example, microcontrollers with analog-to-digital converters,ADC,
usuallyallowtheADCpinstoserveasdigitalinputpinsaswell.In
thatcaseyouneedmerelyreadtheinputport,andthosepinsthatare
abovethehighthresholdwillindicateone,andthosebelowthelow
threshold will indicate zero. Reading the port does not affect the
ADCoperationatall.
Analog-to-DigitalConverters
TheADCsubsystemonmostmicrocontrollersconsistsofasingle
successiveapproximationanalog-to-digitalconverterprecededbyan
analogmultiplexerthatcanswitchtheconvertertoanyofseveralinput
pins. The program controls this switching. The electromagnetic
environmentofthesurfaceofamicrocontrollerdieisaboutasbadas
can be found anywhere. Therefore, attempts to do fine resolution
measurementsofanalogvoltagesinthesepartsisfraughtwithproblems.
MostADCsusearesistiveladdertoactasadigital-to-analogconverter.
Theinputstothisladderaresequencedinaprescribedmannertobuild
avoltagethatmatchesthevoltagebeingmeasured.TheinputtotheD-
to-Aisthenthedigitalequivalenttothevoltagebeingmeasured.
Precisionresistorsareverydifficulttomanufactureonsilicon,
andevenprecisionmatchingbetweenresistorsisextremelydifficult.
Whilemakingprecisioncapacitorsisverydifficultonasilicondie,
itispossibletomakeseveralcapacitorswithhighlyaccurateratios
betweenthecapacitorvalues.Therefore,theapproachistouseaset
ofmatchedcapacitorsandachargebalancetechniquetoaccomplish
Input/Output 133
the successive approximation of the analog voltage. This method
works well, and 8- and 10-bit systems are available on
microcontrollerswithplusorminusone-halfbitaccuracy.
SerialInput/Output
Wherewouldthecomputerbewithoutserialinput/output?The
serialsystemwasprobablythefirstdirecthumaninterfacewithany
computersystem.Ithasexpanded,andtoday,relativelylow-speed
asynchronousserialinterfacesareusedforterminalandmodemand
networkinterfaces.High-speedsynchronousseriallinksareusedfor
alloftheaboveplusinter-computerconnections,hardwareperipheral
communications,andothertypesofdeviceswherehigh-speed,secure
communicationisrequired.
Manymicrocontrollershavebothasynchronousandsynchronous
communications peripherals built in. Usually, an asynchronous
interfaceiscalledaserialcommunicationsinterface(SCI)whilethe
synchronousinterfaceiscalledaserialperipheralinterface(SPI).
TypicallySCIsystemscancommunicateatanyofthepopular
asynchronousserialbitrates.Thesesystemshavebuilt-inbaudrate
generators,doublebufferedinputandoutputregisters,andallofthe
errordetectionfoundonauniversalasynchronousreceiver-transmitter
(UART) chip. These I/O devices can be either polled or interrupt-
drivenbythecomputerportionofthemicrocontroller.
TheSPIisdesignedtocommunicateathighspeedswithother
microcontrollersorperhapswithhardwaredeviceswithasynchronous
serialinterface.Thesedevicestypicallyrunatmegabitpersecond
rates. Since synchronous systems require a system clock, each
microcontrollerSPIcanactaseitheramasteroraslave.Themain
differencebetweenthemasterandtheslaveiswhichchipgenerates
the system clock. The master generates the system clock, and the
data are clocked into and out of the slave by the system clock.
CommunicationswiththemicrocontrollerandtheSPI canbeeither
polled(synchronous)orviainterruptcontroller(asynchronous).
DifferentControllers
Not all of these peripheral systems are found on each
microcontroller.Itispossibletopickandchoosebetweenneedsfor
theseveralperipheralsystemsandselectamicrocontrollerthathas
134 Chapter 3 What Are Microcontrollers?
exactlythoseperipheralsrequired.Thesmallestmicrocontrollerhas
only a 15-bit timer, and the most complete MC68HC05 part has
everythingbutaSPIsystem.Allvarietiesinbetweentheseextremes
exist. In the larger chips, some of the basic requirements for the
microcontrollerchange.Wewillseetheselargerchipsinlaterchapters.
Programming Microcontrollers
Theprecedingbriefdescriptionofwhatmicrocontrollersaregives
aratherbleakpictureofapotentialprogrammingenvironmentfrom
a computer standpoint. Most programmers are used to having an
operatingsystemthathandlessuchmundanethingsasI/O,memory
management,timemanagement,programloading,errorprocessing,
interdeviceorintertaskcommunications,andsoforth.Beprepared
for a giant step backwards when you address the microcontroller.
Thereisusuallynooperatingsystem,nolibrariesofusefulfunctions,
noI/Ohandling,nothingbutabare-bonescomputerwithabunchof
hard-to-tameperipheralcomponentsonboardthesingle-chipdevice.
C compilers for the microcontrollers have been available long
enoughthattheyarethoroughlytestedanddoagoodjobofcreating
proper code. Anyone who has programmed a microcontroller in
assemblylanguageknowsthattheprogramsmustbeverydirectand
havenofancyoverhead.Memoryisstrictlylimited,andthecompiler
mustgenerateassemblycodethatisasresourcefulascanbecreated
byanythoroughlyqualifiedassemblylanguageprogrammerforthe
machine.
Thedevelopmentenvironment,whilequitesophisticatedinterms
of how it works, does little for the programmer in terms of direct
help in debugging a program. There are two different types of
developmentsystemsthatareincommonuse.Bothofthesesystems
require a host computer to run the device. The simplest of these
systemsgoesbynameslikeevaluationmodule,evaluationsystem,
orevaluationboard.Thesedevicesareusuallyboard-levelproducts
thatrequireapowersupplyinadditiontoahostcomputer.
The software to run the development boards is merely a good
terminalemulator.Assemblersandlinkersforthedifferentchipsare
providedaspartofthedevelopmentboard.Theprogrammerwrites
thecodeforthepartinthehostcomputer.Thiscodeisassembled,
compiled, and linked in the host computer. The code is then
Programming Microcontrollers 135
down-loadedtothedevelopmentboardthrougheitheraserialora
parallellinkdependingupontheindividualsystem.
The development board has the microcontroller that is to be
emulated on board. This microcontroller sometimes operates in a
nonusermodethatallowsinternalbusaccess.Asecondcomputeron
thedevelopmentboardcontrolstheoperationofthemicrocontroller.
Code delivered from the host is put into memory accessed by the
microcontroller, and the microcontroller can operate as if the code
werecontainedwithinitsinternalmemory.AlloftheI/Olinesassociated
withthemicrocontrollerarebroughttoaheaderonthedevelopment
board,andacablecanbeattachedtothisheadertoaplug-indevice
thatplugsintoatargetboard.Thistargetsystemthenoperatesasifit
hadaprogrammedmicrocontrollerpluggedintoitssocket.
The microcomputer on the development board has a complete
monitor system in its firmware. This monitor provides
communications with the host, down-loading and up-loading
capability and, most important, complete debugging firmware for
themicrocontroller.
Thereisasinglelineassembleranddisassemblerinthefirmware.
Thispackageallowstheprogrammertoexamineandchangememory
inassemblymnemonics.Themicrocontrollerprogramcanbesingle
stepped,run,addressbreakpointed,andthememorycanbedisplayed
innormalhexadecimalformat.Themicrocontrollerrunsatfullspeed
whenemulatingoperationinatargetboard.
An experienced programmer will be able to debug code in a
microcontrollerwiththehelpofsuchadevelopmentboard.Thereis
additional software available that provides a nice display of all
pertinentinformationinasinglescreenonthehostcomputer.Inthis
area, you will also find that the microcontroller can be controlled
fromadisplayofCsourcecodeonthehostcomputer.Thistechnique
iscalledsourceleveldebugging.
On later chips, another feature is incorporated to help the
developmentenvironment.ThisfeatureiscalledBackgroundDebug
Mode, or ONCE. Both of these similar operations allow debug to
take place in an external computer without any access to the
microcontrollerresourcessuchasinterruptsormemory.Whenachip
isputintoBDM,certainpinsbecomeaspecialserialinput/output
port.Thereareseveralcommandsthatcanbedeliveredtothisport
fromanexternalcomputer.Thesecommandsallowthecomputerto
136 Chapter 3 What Are Microcontrollers?
set memory, examine memory, examine registers, set and clear
registers,executecode,setandclearbreakpoints,andsoforth.All
oftheoperationsnormallyneededtodebugaprogramcanbeexecuted
through this special serial port. There is no need for an on-board
monitoronthemicrocontroller,anditisnotnecessarytomakeuse
ofthechipinterruptsbythedebuggerduringthedebugoperation.
Alloftheprogrammingneededforthedebuggercanresideinahost
computer. Most modern chips have this type of interface, which
greatlysimplifiesdebuggingofmicrocontrollers.
Alloftheabovecapabilitiesareavailablewiththedevelopment
boards.Anotherlevelofcapabilityisavailable.Thesedevicesarebox
level, and usually have a built-in power supply. Most development
systemsrequireahostcomputer,andusuallytheycomewithspecial
softwaretointerfacewiththehostcomputer.Thesesystemshaveallof
thecapabilitiesoutlinedaboveplussomesignificantimprovements.
Thebreakpointcapabilityofthesesystemsismuchimprovedoverthe
simpleaddressbreakpointabove.Hereacomplicatedbreakpointcan
beemployedthatwillbreaktheprogramoperationonreadorwrite,at
anydataoraddresslocation,onaccessofdataorprogram,oraccessof
arangeofdataoraddresslocations.Also,thebreakpointcanoccur
afteraspecifiednumberofoccurrencesofthebreakpointconditions.
Anothermajordifferenceinthedevelopmentsystemsisthetrace
buffer.Atracebufferisamemorythatisasmanyas48or64bitswide.
Eachclockcycleofthemicrocontroller,theconditionofalladdress
bits,thedatabus,theinternalmicrocontrollercontrolbus,andasmany
as16externaltestpointlinesarecapturedinthetracebuffer.
Usually,thetracebufferis4to16kilowordsdeep,soitcanhold
a significant number of microcontroller clock cycles. Even if the
microcontrollerisrunningslowly,onemillionclockcyclespersecond,
suchatracebufferrepresentsaninsignificantexecutiontime.Tohelp
makethedatacontainedinthetracebuffer,tracebuffercapturecan
becontrolledbyasystemthatisthesameasthebreakpointoperation.
Therefore, the portion of the program that is traced is under the
detailedcontroloftheprogrammer.
Thedatainthetracebuffercanbedisplayedinseveraldifferent
manners.Thesimplest,ofcourse,istoprinttothecomputerscreen
the I/O pattern of all the lines captured. This type of display is
extremelydifficulttointerpret,butitisusefulinsomecases.Tohelp
theprogrammerdeterminewherethemicrocontrollerisoperating,it
Coding Tips for Microcontrollers 137
ispossibletoreadthedatabitsanddisplayadisassembledversionof
the code being read into the microcontroller. This display is also
quiteusefulindebuggingthecode.
Yetanotherdisplayiscalledalogicanalyzer.Alogicanalyzeris
anoscilloscopedisplaythatshowsthelogicalstatusofthevarious
linescapturedinthetracebuffer.Alogicanalyzerisaseparatedevice,
butitcanhaveabuilt-indisassemblerthatdisplaysthedisassembled
codealongwiththeconditionofthedesignatedlines.
Thedeviceswithlogicanalyzersandtracebuffersarequiteabit
moreexpensivethanthedevelopmentboardsdiscussedearlier.Some
ofthedevelopmentsystemsprovidesourceleveldebuggingcapability
forhigh-levellanguageslikeC.
Another approach to development systems has been made
availableinsomeofthenewermicrocontrollers.Themicrocontrollers
fromtheMC68HC16familyandthosefromtheMC68300familyall
have a background mode of operation. When operating in the
backgroundmode,thesechipsstoptheirnormalcomputingandstart
serialcommunicationswithanexternalcomputer.Thebackground
mode can be entered as the result of an internal command or an
external signal. There are enough debug commands that can be
communicatedoverthisporttoallowcompletedebugofanyprogram
thatthemicrocontrollermightberunning.Minimumexternalcircuitry
isneededtosupportthedebugmode,sothesehigh-poweredchips
can operate as their own development environment. Here, the
development support is mostly software contained within the host
computer,andthedeliverablesystemcancontainalloftheessential
componentsofadevelopmentsystem.
CodingTipsforMicrocontrollers
Oneofthemajortasksfacingaprogrammerwhenwritingcodein
ahigh-levellanguageforanymicrocontrolleristomaketheresulting
programasreadableaspossible.Otherpeoplewhomightlaterneedto
readormodifyyourcodemustbeabletounderstandwhatisgoingon
inyourprogram.Itisextremelyimportantthatmnemonicsbeusedas
muchaspossiblewhendealingwithvariousregisters,theirbitcontents,
andspecialmemoryaddressesthroughoutyourprograms;otherwise,
theresultingcodewillbeaquasi-Cprogramfilledwithmanynumbers
andfunny-lookingcastoperationsthatwillbelargelyincomprehensible
tootherstryingtomaintainyourprogram.
138 Chapter 3 What Are Microcontrollers?
Modern large 8-bit systems are very nearly as complete as
yesterdaysmini-computers.Programsformicrocontrollersarealso
gettinglarge,andtheyareincreasinglybeingwrittenbyateamof
programmersinsteadofasingleprogrammer.Themanagementof
theprogrammingtaskismuchmoreimportantwhenateamisinvolved
becausetheperson-to-personinterfaceisthemostdangerousinall
programming. It is easy for people to make mistakes; misspelled
words, interchanged order of parameters in a function argument,
passingincorrectdatatoafunction,etc.,areallproblemsthatcan
(and often will) arise when several people try to write a single
program.Eachpersonontheteamcanprobablykeepamaximumof
sixorsevenfunctioninterfacesinmind,andeventhenmistakeswill
bemade.Whentheprogramisreallylarge,therewillbedozensof
function interfaces and sources of possible error will abound. For
example, most of the time programmers will try to use what is in
mindratherthanlookupaquestionablefunctioncall.
How can these problems be minimized? Fortunately, there are
severalstepsyoucantaketokeeperrorsdowntoamanageablylow
level.AbigoneistomakecertainthatanANSI-certifiedcompilercan
beusedforanyprogramandthatthecomputerwillenforcestricttype
checking in the program. This will cause most of the errors due to
carelessnessorsimpleaccidentstobecaughtatcompiletimeandnot
during the debugging phase. If such errors are not caught by the
compiler,theyareamongthemostdifficulttofindwhentheyshowup
atruntime.Programscanbeimprovedbyfollowingtheseconventions:
1. Useaconsistentconstantdefinitionnamingconvention.Useallcapital
lettersforthenamesofconstantsdefinedin#definestatements.
2. Makeallfunctionnamesthoroughlydescriptive.Useseveralwords
foreachnameifpossible,andcapitalizethefirstletterofeach
wordsothatthewordscanbedistinguishedeasily.Forexample,
a function that returns the time should have a name like
TimeOfDay() or Time_Of_Day().The important thing is
thatthenamedescribethefunctioninsomedetail.Beconsistent
withnamingconventions.Ifyoustartwithnameshavingnoun-
derscores,keepthisconventionthroughouttheentireprogram.
3. Makeuseoftypedefandthefactthatstructurescreatenewtypes.
Wherepossible,createatypethatisdescriptivetoyourprogram.
Forexample,intheClanguagetheinterfacetoallinput/outputand
Coding Tips for Microcontrollers 139
filesisthroughthetypeFILE.FILEinthiscaseissimplyatype
thathasbeenmadeavailabletotheprogramthroughatypedef
statementofastructurethatcontainsalloftheessentialelements
neededforfileinput/output.Itisrecommendedthattypescreated
bytypedefstatementsinvolvingastructureshouldhavenames
withthefirstlettercapitalized.Thenamesofthesetypesshouldbe
briefandshouldbeonewordonly.
4. TheCmacrogivesustheabilitytocreatefunctionsthatwillbe
compiledin-line.Thisisveryuseful,butrememberthereisno
typecheckingformacrodefinedfunctionsandyoudonotknow
whatwillbereturnedfromamacrofunction.Thisdoesnotmean
toavoidmacrofunctions,butitdoesmeanthatwithnotypecheck-
ingwehaveapartoftheprogramthatdoesnotgetthenormal
scrutinyweexpectwithmostfunctioncalls.Becarefulwhenus-
ing macrosyou, not the compiler, must make certain that the
argumenttypesandthereturntypeareallcorrect.
5. Useasfewglobalvariablesaspossible.Globalvariablesseemto
beaneasywaytoavoidusingfunctionarguments,buttheyalso
can make debugging extremely difficult. Parameters should be
passed to functions as arguments. This approach will give the
programmersomeassurancethatcompiletimecheckingwillcatch
any typing errors, and will eliminate the problems of side ef-
fectsfoundwithglobalvariables.
6. Beconsistent.Whendesigningfunctioncalls,maketheorderof
the parameters in the argument list logical and be consistent
throughoutthewholeprogram.
7. Avoidcomplicatedargumentlists.Ifitbecomesnecessarytosend
manyvariablestoafunction,createastructurethatcontainsallofthe
argumentsandsendapointertotheargumentstructureasaparam-
eterratherthantheargumentsthemselves.Sincethemembersofthe
structureareallmnemonicswithhopefully!meaningfulnames,
thefillingofthestructureshouldresultinamoreaccuratecreationof
theparameterlistthanwouldbefoundiftheparametersarealllisted
inthefunctionargument.
8. Becourteousdocumentyourcode.Thereisnoneedforacom-
mentforeverylineofcode,butitisunconscionablethataprogram
should go page after page with no comments. Every function
140 Chapter 3 What Are Microcontrollers?
should have a comment header that explains what the function
doesintheprogram.Theheadershouldcontainalistofthefunc-
tionargumentsandarecordofmodificationstothefunction.If
thereissomenonobviouscodeintheprogram,thiscodeshould
bedocumentedtoexplainwhatishappening.
9. KernighanandRitchie,thedevelopersofC,gaveusalanguage
thatisrichwithshorthandnotation.Whileoftenuseful,thisisa
toolthatcanbebadlymisused.Dontwritecodeinaconvoluted
mannerusingtrickyshorthandnotationssothatnobodycanun-
derstandwhatyouretryingtodo.Youmightbetheonewhohas
tomaintaintheresultingcodeadecadelater!
10.Alwayscreatemnemonicsforaddressesandbitvariablesusedin
theprogram.
11.UseassemblylanguageonlywhenCcannotaccomplishneces-
saryoperations.
12.Microcontrollers usually work with unsigned variables. Often the
microcontrollercancreatemoreefficientcodewhendoingcompares
with unsigned variables.Therefore, use unsigned variables every-
whereunlessitisnecessarytousesignedvariables.Afewtypedef
operationswillhelpkeeptheuseofunsignedvariablesinmind:
typedefWORDunsignedint;
typedefBYTEunsignedchar;
Inwritingcodeforamicrocontroller,youmustbeabletodeal
with ports at some specific address location, the bits within these
ports, control registers, certain data registers, and other important
controlfunctions.Theprogramcanbeeasilywrittenifthenamesof
allregisters,ports,bits,andsofortharetakenfromthecomponent
specificationandnotmadesubjecttothewhimoftheprogrammer.
Therefore, if all of the ports and bits have the name given in the
microcontroller reference manual, then any variable used will be
definedinoneplaceandtheprogrammerneedonlyfindtheappro-
priate register along with the definition of its bits in the reference
manualtounderstandwhatisbeingdoneintheprogram.Therefer-
encemanualbecomespartofyourdocumentation.
WesawbackinChapter2howtocreatemnemonicsforaddress
locations.Itisnecessaryforprogrammerstowriteaseriesofdefine
Coding Tips for Microcontrollers 141
statementswhichidentifyalloftheregisterlocations,portaddresses,
andbitnamesforthemicrocontroller.Itisbestifallofthesepre-
liminarydataareplacedinaheaderfilespecifictoadeviceandthen
itcanbeincludedatthebeginningofprogramsforthedevice.This
approachisconvenientbecauseitgivestheprogrammertheability
to use mnemonics throughout the program. It also provides some
limitedportability.Ifaseconddeviceinthesamefamilyhassome-
whatdifferentregisterandportlocations,itispossibletowriteanew
headerfileforthisseconddeviceandcodewrittenfortheoriginal
devicewillprobablyworkwiththeseconddevicewhentheproper
header file is included.We will discuss header files further as we
examinetheprogrammingofspecificmicrocontrollers.
Inthisbook,youwillseetheCprogramminglanguageusedto
develop code for embedded systems products. C is a powerful
languagethatcanbeabusedandisoftenthesubjectofsuchabuse.
Dont abuse this fine language. It is your responsibility as a
programmertowritecodethatiseasytoread,easytounderstand,
easytodebug,easytomaintain,andeasytouse.Anyfancyanticsin
coding are uncalled for and not needed.Any group that is writing
projectcodeshouldimplementashopcodingstandardthatwilldirect
the way code is written. There are several organizations that have
preparedsuchstandards.Icannotagreewithalloftheelementsof
thesecodingstandardsthatIhaveseen,butanycodingstandardis
betterthannone.Researchthematterandfindacodingstandardthat
comesclosetosuitingyourneedsandthenmodifyittomeetyour
needsexactly.Andthenuseit.
Ipreviouslymentionedgroupdevelopment.Ihaveseenmany
smallprojectsinwhichthesoftwaredevelopmentwasanafterthought.
Therearestillmanyprojectsthatcanfitintoafewhundredbytesor
evenafewthousandbytes.Suchprojectsmightnotseemtorequire
thecarefuloversightimpliedbyashopstandard.Buttheydo!Inthe
development of software, you will find that the initial cost of the
softwareisdwarfedbythecostofmaintenance.Therefore,anyeffort
putforthtohelpthemaintenanceofthesoftwareintothefutureis
effortwellspentregardlessofthesizeoftheproject.Youwilloften
findthatnewerchipshavemassivememoryspacesandwiththese
memory spaces available, the code will expand to fill them. This
expansion of the code is not necessarily bad if the expansion
accompanies improved operation and features. However, one
142 Chapter 3 What Are Microcontrollers?
implicationisthattheonehardwareengineerinthelabcannolonger
beexpectedtodevelopthecodeforsuchprojects.Moreandmore
teamsarecomingtogethertodevelopembeddedsystemssoftware
today.Suchteamsalmostdemandthatacodingstandardbeinplace
ifthecodethusgeneratedistoeverbeuseful.
Testing
Infuturechapterswewillseemanyprogrammingexamplesde-
veloped.Thecodeinsuchexampleshasbeentestedandrunsonthe
microcontrolleritwasdesignedfor.Thehardwareinterfaceusedto
testtheseprogramshasbeenaseriesofevaluationboardsbuiltby
Motorola.Theseveraldifferentboardsusedeachrepresentadiffer-
ent approach to an inexpensive development environment. For the
MC68HC05 family, I used the MC68HC05EVM and
MC68HC05EVSseries.TheEVMisanevaluationmoduleformany
oftheolderMC68HC05familyofmicrocontrollers.Thisfamilygrew
solargeandsomanydifferentdeviceswereintroducedintotheprod-
uct line that it was impossible for a single board to provide the
developmentservicesneededforthewholefamily.Anewseriesdes-
ignatedastheEVSfamilywasdevelopedtomeettheseexpanding
needs.TheEVSiscomprisedofabaseboardwithmanyoftheneeded
interfacecomponents.Adaughterboardcontainingallofthecom-
ponentuniquecapabilityofthesystemispluggedintothebaseboard.
Thesesystemsprovideexcellentdevelopmentenvironments.Each
systemcontainsamicrocontrollerofthetypebeingdeveloped.Inthe
caseoftheMC68HC05family,theon-boardcomponentsareoperat-
inginaspecialmodecalledthenon-usermode.Inthenon-usermode,
thedevicereorganizesitspinstoprovideanexpandedbusoperationso
that memory and external control can be used on what is usually a
single-chipmicrocontroller.Fortheseparts,aspecialchipisusedcalled
aportreplacementunit,orPRU,whichisputontotheexpandedbus,
anditsoutputsareexactlythesameaswhatwouldbeseenontheports
ifthechipwereoperatinginthenormalmode.Withthiscapability,
RAMcanbesubstitutedforinternalROMonthemicrocontrollerand
thesoftwareimplicationsofthischangeareunlimited.Forexample,
programs can be loaded into the memory at will, memory access
breakpoint can be implemented, the program can be started at any
point,thecontentsofthememorycanbechanged,andsoforth.
Coding Tips for Microcontrollers 143
Afirmwaremonitorisplacedontheevaluationboard.Aserial
port is added, and the board, under the control of the monitor,
communicates with a host computer.As a matter of fact, the host
needonlybeaterminalinthemostbasiccase.Themonitorprovides
several important debug and development functions. Code can be
downloadedfromthehostcomputerintothememoryoftheevaluation
board. The monitor contains a single line assembler/disassembler
module.Withthissoftwareavailable,theusercanexaminethecode
inthemicrocontrollermemoryineitherhexadecimalormnemonic
form.Also,memorycontentscanbechangedineitherhexadecimal
ormnemonicform.Breakpointscanbeinsertedintothecode,and
theoperationoftheprogramcanbeobservedfromtheterminalof
thehostcomputer.
Inadditiontotheevaluationcapabilityoftheseboards,theyalso
eachhaveextensionheadersthatallowtheboardtobepluggedinto
a target system. When operated in this manner, the target system
operatesasifithasaprogrammedmicrocontrollerinitssocket.Of
course,thecodeinthemicrocontrolleristhatinthememoryonthe
evaluationmodule.Theemulationofthemicrocontrollerinthiscase
isexcellent.Themicrocontrolleronboardtheevaluationmoduleis
executing the code for the target system. The microcontroller re-
sources used in the target system are those found on board the
microcontroller in the evaluation module. In most cases, the lines
connected to the target system are connected directly to either the
evaluationmodulemicrocontrollerorPRU.ThePRUisdesignedto
emulatethepinoperationofthemicrocontrolleraswellaspossible.
Therefore,theloadspresentedtothetargetsystembytheemulator
andthesignalresponsesofthesepinsverynearlyduplicatethoseof
themicroprocessorbeingemulated.
Figures 3-2 and 3-3 are photographs of the MC68HC05EVM
andtheMC68HC05EVS,respectively.NotethatFigure3-2showsa
single-boardsystemwhileFigure3-3showsatwo-boarddevice.All
ofthedevelopmentdevicesdiscussedhererequireanexternalpower
supply.AnydevicesuffixedEVMneedsa+5voltsupplyaswell
as+12and-12voltsources.Thehighervoltagesuppliesareneeded
onlytodrivetheRS232communicationssignalsnecessarytocom-
municate with the host computer. On the EVS and the
MC68HC16EVBboards,onlya+5voltsupplyisneeded.Mostof
thecomponentsbeingemulatedbytheseboardscanhavesomeon-
144 Chapter 3 What Are Microcontrollers?
boardnonvolatilememory,suchasEEPROMorEPROM.Theevalu-
ationboardseachprovideameansofprogrammingthesememories.
Usually, a high voltage is needed. This voltage will vary from
part-to-partanditmustbeappliedasaseparatevoltageontheboard.
Figure3-2:MC68HC05EVMSingleBoardDevelopmentSystem.
Figure3-3:MC68HC05EVSTwo-BoardDevelopmentSystem.
Coding Tips for Microcontrollers 145
The previous discussion is aimed at the MC68HC05 development
boards.TheMC68HC11alsohasanEVM.ThisEVMoperatesex-
actlythesameasthatdiscussedabove.ThereareseveralEVMsfor
the different parts in the MC68HC11 family. Figure 3-4 shows a
photographoftheMC68HC11EVM.
Figure3-4:
MC68HC11EVMDevelopmentSystem.
In all of the devices weve discussed, communication with the
hostcomputeristhroughanRS232seriallinkfromtheboard.The
developmentworkcanbedonewithaterminalemulatoronthehost
computer.Suchaterminalemulatormightbefoundinthesoftware
programsPROCOMMorKERMIT.Certainly,anyterminalemulator
candothejob,andthosementionedherearejusttwoofmany.
Developmentthroughasimpleterminalemulatorisusuallynot
theeasiestapproach.Motorolashipsasoftwarepackagewitheach
evaluationdevice.ThissoftwarepackageiswrittenbyP&EMicro-
computerSystems,Inc.Itprovidesawindowedenvironmentthat
showstheconditionsofmanyinternalfeaturesofthedevicebeing
evaluated.Alloftheinternalmicrocontrollerregistersaredisplayed,
alistingofthebreakpointsthathavebeensetareshown,ablockof
thecodebeingdebuggedisdisplayed,andacontrolscreenisalso
available.Thedisplaywilldifferwithvariousdevices,butingeneral
thescreeninterfaceiseasytouseandunderstand.
146 Chapter 3 What Are Microcontrollers?
Insomecases,acompletesymbolicdebugenvironmentcanbees-
tablished.P&EMicrocomputerSystems,Inc.,hasafilesystemthat
allowstransferofsourcecodetotheprogram.Thissourcecodeis
displayedinthecodewindow.Ithelpsduringthedebugprocedureto
seethesourcecodewhilesteppingthroughit.Thiscapabilityisavail-
able with the compiler used for the MC68HC05, but not for the
MC68HC11andMC68HC16families.
AllofthesoftwarewrittenbyP&ErunsundertheDOSoperating
system.Today,therearefewercomputersthatrununderDOSthan
inthepast,soyoumightwanttofindalaterdevelopmentsystemthat
runsunderamoremodernoperatingsystem.IhavealwaysusedDOS
by itself or running under either Windows 3.1 or one of the later
Windowsoperatingsystems.DuringtheavailabilityofOS/2,itwas
an ideal operating system to develop microcontrollers under these
DOS-based development systems. More recent systems require
Windows95orlater.
Developmentisenhancedifthehostcomputerhasmultitasking
capability.Thiscapabilitycancomefromanyofthepopularoperat-
ingsystems,suchasMicrosoftWindowsorXWindows.Insucha
case,itispossibletokeepaneditorwiththelistingfileofthepro-
grambeingdebuggedinawindowalongwiththeP&Edisplayin
anotherwindow.Thisapproachprovidesbothinsightintothecode
beingdevelopedalongwiththeconditionofthehardwareastheex-
ecutionofthecodeproceeds.Itisrecommendedthatthisapproach
beusedwhendebuggingprogramsonevaluationboards.
Unfortunately,noneoftheseevaluationboardsallowsaccessto
theoperationofthecomponentbeingdebuggedwhenthedeviceis
executingthetestcode.Toachievethislevelofoperationwouldin-
creasethecomplexityofthedevelopmentboardsignificantly.Also
note there is no provision for a trace buffer on these boards. The
newerboards,EVSandMC68HC16EVB,provideheadersthatcan
be connected to a logic analyzer that can act as a trace buffer and
provide many of the functions usually found in the more compre-
hensivedevelopmentdevices.
OnelastdevelopmentdeviceusedistheMC68HC16EVB,shown
inFigure3-5.Thisboarddiffersfromtheothersinonesignificant
way.TheMC68HC16familyofdevices(aswellasthosefoundin
theMC68300family)provideacapabilitynotusuallyfoundinmost
Coding Tips for Microcontrollers 147
microcontrollers. These devices can be placed into a background
debug mode that facilitates development of the code. In all of the
above development boards, the monitor software must execute on
themicrocontrollerbeingdeveloped.Thisoperationmeanstheremust
beeithermemorybankswitchingorthemonitormustoccupysome
ofthenormalmemoryspaceofthemicrocontroller.Ineithercase,
thepresenceofthemonitorsoftwarecanbeseenintheoperationof
themicrocontroller.Also,developmentwiththeabovesystemswill
requirethatotherresourcesbeusedforthedevelopmentoperation.
Forexample,ifcontrolofthedevelopmentisthroughaserialportto
aterminal,theSPIofthemicrocontrollerwillprobablybeused.In
thebackgrounddebugmode(BDM)ofthelargerdevices,thismemory
and resource sharing between the monitor and the code being de-
buggedisunnecessary.WhenadeviceisplacedintoBDM,itsnormal
operation ceases and all communications with the device occurs
throughaspecialserialport.Throughthisserialport,thecondition
ofthedevicecanbeexamined,memorycanbeaccessedandchanged,
breakpointscanbeestablished,etc.,justliketheinvasivetechnique.
However,whenthedeviceisreturnedtooperation,thereisnoway
thepresenceofthemonitorcanbeseenbytherunningprogram.
Figure3-5:MC68HC16EVBDevelopmentSystem.
148 Chapter 3 What Are Microcontrollers?
With BDM, all debug software can be placed on a host computer.
Therefore,itispossibletowritemuchbetterdebuggingsystemsthat
connectthroughtheBDMsystem.Mostrecentmicrocontrollerchips
employ some type of background debug mode operation. It is not
always called BDM. It might be called ONCE or JTAG, but these
operationsarebasicallysimilarandallowbackgrounddebuggingof
themicrocontrollerandahosttocontainallofthenecessarydebug
software.
AnotheradvantagetousingtheBDMisthatallcommunication
betweenthehostandthedeviceisthroughan8-wirebus.Thisbus
canbeaccessedinanydevice,sothesedevicesbecometheirown
developmentsystemsandnodevelopmentsystemisreallyneededto
workonthefinaltargetsystem.
TheMC68HC16EVBusestheBDMoperation.Communications
withthehostcomputerarethroughtheparallel,orprinter,portonthe
computer.P&EhaswrittenaninterfaceforPCclonecomputersthat
uses the parallel port. Its operation is essentially as for the
MC68HC05EVMandMC68HC11EVMdevices.P&Ehasalsomade
an additional device which can connect to the 8-wire BDM bus and
connectdirectlytothehostcomputerparallelport.Itrequiresa+5volt
powersourceandtakesitsvoltagethroughthelinestothetargetsystem.
Threeotherchipswillbeexaminedinthefollowingchapters.The
M68HC08 family and the M68HC12 family are extensions of the
M68HC05andtheM68HC11families,respectively.Yetanotherrecent
chipfamilyistheMCORE.TheseRISCchipsareveryfastandrunat
extremelylowpower.TheMMC2001chipfromthisfamilywillbe
examined.ThedevelopmentsystemfortheMCOREchipsiscalledan
EBDIExtended Background Debug Interface. This package is
interfacedtoanevaluationboardthroughan8-wireserialport.
Alloftheprogramsinthechaptersthatfollowweretestedonthe
appropriatedevelopmentboards.Theseprogramsarerelativelysmall
because each is designed to show some feature of either the
microcontrollerorthelanguageasappliedtothemicrocontroller;larger
programswerenotappropriatetothetutorialaimsofthisbook.With
judicioususeoftheboardsalongwiththedevelopmentenvironment
onthehostcomputer,theseprogramswereeasytodevelopanddebug.
Chapter 4
Small8-BitSystems
Notsurprisingly,writingcodeforanymicrocontrollerwhether
in assembly language or a high-level language like Crequires a
detailedknowledgeofthemicrocontrollerbeingprogrammed.Usu-
ally, a high-level programming language requires little knowledge
oftheunderlyingcomputeronthepartoftheprogrammer.Thisap-
proach allows the programmer to concentrate on the nature of the
problembeingsolvedratherthanhowtosqueezetheproblemintoa
specificcomputer.ACabstractcomputerhasbeendesignedandyou
writecodeforthiscomputerwhenyouwriteCcode.Theabstract
computerhasnoregisters,controlregisters,indexoraddressregis-
ters,oranyotherofthenormalresourcesfoundonatypicalcomputer.
Thelanguageissufficienttoallowpropercreationofcodeneededto
runthecorecomputer.However,theessenceofanymicrocontroller
isthespecialon-boardperipheralsthatitprovides.Theseperipherals
arenotdirectlyavailablefromtheClanguageeither.
Programmingtechniquesmustallowuseoftheseperipheralsor
the high-level language is valueless. Three distinct levels of
microcontrollerswillbecoveredindifferentsectionsofthistext.The
simplestmicrocontrollerisembodiedintheM68HC05family.These
8-bitdevicesareusuallycompletelyself-containedanddonotsupport
anexpandedbus.AnotherlevelofcomplexityisfoundintheM68HC08,
theM68HC11andtheM68HC12families.Thesecomputersarealso
8-bitmachines,buttheyhavemoreregistersthantheM68HC05fam-
ily and support an expanded data bus.With the expanded data bus,
thesefamiliescanhaveexternalmemoryandperipheralsinadditionto
those within the chip itself. (The peripherals on these chips are not
very different from those found on the M68HC05.) The step up in
computerpoweristheM68HC16microcomputer.Thiscomputerisa
149
150 Chapter 4 Small 8-Bit Systems
16-bitmachineanditsperipheralcomponentsarenearlyalldifferent
fromthosefoundonthe8-bitmachines.TheM68HC16isasuperset
oftheM68HC11;itwillexecuteM68HC11code,butthehardware
computerextensionsandnewperipheralcomponentsaresignificant.
Tosuccessfullyprogramamicrocontrollerusingahigh-levellan-
guage,theprogrammermustbeabletoaccessvariouscontrolandstatus
registersinthecomputer.Theprogrammustforcethelanguagetoplace
bothprogramanddatamemoryaddressesintheproperlocationsinthe
memorymap.Vectorsassociatedwithinterruptserviceroutines,andthe
serviceroutinesthemselves,mustbehandleddirectlybytheprogram.
Thesetasksaredifficulttoaccomplishwithmosthigh-levellanguages,
butCallowsaccesstothesethingswithoutextensions.However,mostC
compilersformicrocomputershaveextensionsthatallowsuchspecial
featurestobeeasilytreated.
ThecompilerusedinthischapteriscalledC6805
1
.Itwaswrittento
supporttheM68HC05familyofdevices.Beforewarned:someM68HC05
microcontrollerinstructionshavenocounterpartinthestandardClan-
guage.Specialdirectivesidentifyuniquemicrocontrollercharacteristics
tothecompiler.ListedinTable4-1belowarenineassemblyinstructions
availabletothe68HC05.TheseinstructionshavenoequivalentCcall.
Theycanbeaccessedaseitherasingleinstruction(alluppercase)oras
a function call as shown. The function call requires a pair of closed
parenthesestofollowthenameoftheinstruction.
Function Operation
CLCorCLC() clearcarrybit
SECorSEC() setcarrybit
CLIorCLI() clearinterruptflag(interruptson)
SEIorSEI() setinterruptflag(interruptsoff)
NOPorNOP() nooperation
RSPorRSP() resetstackpointer
STOPorSTOP() STOPinstruction
SWIorSWI() softwareinterrupt
WAITorWAIT() WAITinstruction
Table4-1:AssemblyCodesDirectlyCallableByC6805
1
ByteCraftLimited,421KingStreetNorth,Waterloo,Ontario,CanadaN2J4E4
Small 8-Bit Systems 151
ApragmaisaCpreprocessorcommandnotdefinedbythelan-
guage.Assuch,thecompilerwritercanusethe#pragma command
tosatisfyaneednotspecificallyidentifiedbythelanguage.C6805
uses pragmas to identify microcontroller-specific characteristics.
Table4-2containsalistofpragmasusedbyC6805.Theformatofa
pragmadirectivehereis
#pragmaportxxportname@address
whereportxxcanbeportr,portw,orportrwwhichshows
whethertheportisread,write,orboth.portname isthenameused
intheprogramfortheport.Theatsymbol(@)identifiesamemory
address.#pragma moridentifiesthecontentsofthemaskedoption
registerusedonfieldprogrammablechips.Therearesomeinstruc-
tions that are not found across the whole M68HC05 family. In
particular,somedevicesmaynothavetheMUL,theDIV,theSTOP,
and the WAIT instruction. The #pragma has a preprocessor call
that identifies the instructions from this set in the particular
microcontroller.
pragma Function
#pragmaportxy
#pragmamemory
#pragmamor
#pragmahas
#pragmaoptions
#pragmavector
I/Oportdefinition
RAM/ROMdefinition
maskoptionregister
instructionsetoptions
compilerdirectives
interruptvectordefinitions
Table4-2:C6805pragmaDirectives
This compiler has certain options that can be inserted from the
commandlineor,ifneededbytheprogrammer,the#pragmaop-
tions preprocessorcommandcanalsobeusedtosettheappropriate
compileroptions.Finally,the#pragma vectoridentifiesagiven
functionnameasaninterruptserviceroutine.Whenthecompilercom-
pilesthenamespecified,itwillplacetheaddressofthefunctioninto
thedefinedvectorlocation.Anothermodificationinthecompiledcode
willtakeplacewhen#pragmavectorisused.Allreturnsfroma
functionidentifiedbyavectorpragmawillusethereturnfromin-
terruptinstructionratherthantheusualreturnfromsubroutine.
152 Chapter 4 Small 8-Bit Systems
Another useful directive pair is the #asm and the #endasm.
Thecodeenclosedinablockthatstartswith#asmandendswith
#endasmmustbeinstandardassemblylanguage.Variablesdefined
intheCprogramcanbeusedsafely.
C can accomplish almost everything that the assembly lan-
guageprogramcan.YouwillfindthattheC6805compilerwillcreate
tight, efficient code that is probably as good as can be written by a
competentassemblyprogrammer.Thereare,however,someitemsthat
areabsolutelyforeignandinaccessibletoacompiler.Acompilercre-
atescodeforanabstractmachinethatdoesnotexistinreality.The
usualregistersfoundintherealmachinearenonexistentintheabstract
machine.Forexample,itisnotpossibletoaccessthestatusregisterof
themicrocontrollerwithcompiledcode.Usually,statusregistercon-
tents are not directly important to the conduct of the program. But
laterwellseeanexamplewheretheabilitytomanipulatethecarrybit
of the status register can save many bytes of code. Therefore, it is
importanttobeabletousesomeassemblycodeaswellasC.
This chapter will concentrate on small 8-bit microcontrollers.
Subsystems such as timers, analog-to-digital converters, computer
operating properly (COP) timers, etc., found on the 8-bit systems
willbeoutlinedandtheirprogrammingdiscussed.Whilethemain
detailsofthecentralprocessorinthemicrocontrollerareimportant
totheassemblylanguageprogrammer,theyareoflittleinterestto
theCprogrammer.ThisobservationistrueatleastattheClevel.Ifit
becomesnecessarytoenteranassemblylanguageprogramforopti-
mizationofcodesizeorotherconsiderations,thentheprogrammer
isrequiredtohavedetailedknowledgeoftheprogrammingmodel
andtheinternalarchitectureofthecomputer.
Lets start by discussing important microcontroller peripheral
components that you can expect to find.Well begin with what is
probablythemostimportantsingleconsiderationintheselectionof
amicrocontrollertodoajobthedevicememory.Thisdiscussion
willbefollowedbysectionsonotherimportantperipheralssuchas
timers,analog-to-digitalanddigital-to-analogconverters,serialcom-
munications devices, and simple digital input/output lines.
Microcontroller Memory 153
Microcontroller Memory
Mostmicrocontrollershavememoryon-board.Thememoryis
in the form of random access memory (RAM), read-only memory
(ROM),erasableprogrammableread-onlymemory(EPROM),elec-
tricallyerasableread-onlymemory(EEPROM),andanewertypeof
EEPROMmemorycalledFLASH.Thesememorytypesarediscussed
inthefollowingparagraphs.ThediscussionofFLASHmemorywill
bedeferreduntilthechapterontheM68HC08family.
RandomAccessMemory(RAM)
In a microcontroller, onboard RAM is static random access
memory.Itisalwaysvolatilewhenthepowertothemicrocontroller
isremoved,thecontentsofthismemorydisappear.Sometimes,spe-
cialprovisionsaremadetodeliverpowertoRAMwhentheprocessor
isintheoffstate.Thisprovisioniscalledbatterybacked-upRAM,
anditisoneofthealternativewaysthatasmallamountofimportant
datacanbesavedwhenpowerisremovedfromthemainsystem.
The requirement for RAM in typical microcontroller applica-
tionsismodesttosmall.AvailableRAMisusuallylimitedtoafew
hundredbytes,andoftentherewillbeaslittleasafewtensofbytes
ofRAM.Inthedesignofthemicrocontroller,priceisamajorcon-
sideration.Thetotalsiliconareaofthecomputerdieoftendrivesthe
finalpriceofthecomponent.Inmostcomputers,abasepageisthe
first256bytesofmemory.Thispageisuniquebecauseitrequires
only8-bitsofaddresstoreachanylocation.Siliconareaneededto
constructtheaddressdecodingfortheupperaddressbitsisnotre-
quired to address base page memory. Therefore, onboard RAM is
usually located in the computer base page. There are some other
functionsthatareusuallyassignedtothebasepage.Generally,you
willfindthattheamountofRAMislimitedtolessthan256bytes.
Read-OnlyMemory(ROM)
Programsandotherdatathatcanneverbechangedarestoredin
ROM.ROMisprogrammedduringthemanufactureofthechip,and
itscontentscannotbechangedoncethemicrocontrollerisdelivered
tothecustomer.TheROMprogramisinstalledasamasklayerand
iscalledmaskedROM.
154 Chapter 4 Small 8-Bit Systems
Mostmicrocontrollerapplicationsrequiremoreprogrammemory
spacethanRAMspace.Thesmallestmicrocontrollerusuallyhasabout
512bytesofROM,whilethelargestcancontainasmuchas32,000
bytes (32 kilobytes, or 32k) or more. Sometimes, the programmer
will find it desirable to have a small amount of ROM that can be
accessedfromthecomputerbasepage.Tomeettheserequirements,
themicrocontrollerdesignerswillplaceafewbytesofROMinthe
basepagememorymap.
ErasableProgrammableRead-OnlyMemory(EPROM)
EPROM is a form of programmable memory that permits the
programmer to change the program contents and, if necessary, re-
turnandchangeitlateraftertesting.Asthenameimplies,itispossible
toreprogramEPROM.First,thismemorymustbeerased.Theeras-
ing procedure involves allowing ultraviolet light to fall upon the
memoryareaofthedie.Thishigh-energylightremovesstoredcharge
thatisplacedoneachmemorygateduringprogramming.
EPROMprogrammingrequiresthatahigherthannormalvolt-
agebeappliedtothechip,andthecodebesystematicallyplacedin
eachmemorylocation.Theprocedureisslowbecausethecodemust
beleftinplaceforseveralmillisecondsforeachmemorylocation
stored.Often,aseparateprogrammerboardisusedtotransfercode
from an EPROM to the microcomputer EPROM. These program-
mingboardscanprogramasmanyasonetoeightpartsatatime.
EPROMrequiresalargersilicondieareathanthecorresponding
amountofROM.Therefore,itissomewhatmoreexpensive.Also,
thewindowpackagethatallowstheEPROMtobeerasedisexpen-
sive. This additional expense makes it impractical to use normal
EPROMforproductionvolumes.ThewindowpackageEPROMde-
vicesareexcellentfordevelopmentpurposes,though.Themodestly
highercostofthesedevicesisnotaseriousimpedimenttotheiruse
indevelopmentprograms.
Theeconomicsofproductionsetsthesmallestproductionvol-
umeforamaskedROMmicrocontrollerataboutonetofivethousand
units.AnalternativetotheuseofmaskedROMatsmallerlevelsof
productioniscalledtheone-timeprogrammable(OTP)chip.These
devicesusethestandardEPROMtechnologyfortheirprogrammemo-
ries.They are programmed in the same manner as EPROM chips.
Microcontroller Memory 155
Theirpackages,however,havenowindowstoallowerasureofthe
programonceitisputinplace.Thesedevicescostsomewhatmore
thanmaskedROM,buttheyaresufficientlylessexpensivethanthe
EPROMpartstoalloweconomicproductionofrathersmallquanti-
ties.Theydohavethedisadvantagethat,onceprogrammed,theycan
neverbeusedforadifferentprogram.
ElectricallyErasableProgrammableRead-OnlyMemory(EEPROM)
EEPROMisatechnologythatusesamemorycellsimilartothe
standardEPROMcell.Thesecellsaresomewhatlargerthanthestan-
dard EPROM, and are therefore more expensive. It is possible to
erase an EEPROM electrically without the high-energy ultraviolet
light.EEPROMrequiresahighvoltageinprogramminganderasing
thememory.SomemicrocontrollershaveEEPROMthatcanbepro-
grammed without an externally applied high voltage. This
programmingisaccomplishedbytheuseofanonboardchargepump
to generate the programming voltage. Such charge pumps are not
capableofdeliveringmuchcurrent,sotheamountofEEPROMthat
canbeprogrammedfromanonboardsystemisusuallylimitedtoa
maximum of 512 bytes. This EEPROM is used for the storage of
informationgatheredafterthemicrocontrollerhasbeenplacedinto
asystem.Thismemoryisnotoftenusedforthestorageofprogram.
ThesmallerblockofEEPROMcanbeprogrammedwiththeuse
oftheonboardchargepump,andcanbeprogrammedonthefly
duringthenormalexecutionofprogram.DeviceswithEEPROMare
moderatelyexpensivebecauseEEPROMrequiresthelargestsilicon
areaofanymemorytechnology.
OtherMemoryConsiderations
Not all microcontrollers have enough onboard memory to suf-
ficeinsomejobs.Inthesecases,anexpandedbuspartcanbeused.
Expandedbuspartsallowtheprogrammertoaccessmemorythatis
externaltothemicrocontroller.Noneofthesmallmicrocontrollers
currently provide for expanded bus operation. The larger
microcontrollerslarge8-bit,16-bit,or32-bitprovideexpanded
bus.Insomeinstances,theyprovidenoonboardmemoryatall.As
we will see later, pins on a microcontroller are at a premium.An
expandedbusoperationmeansthatsomeofthecomponentpinsmust
156 Chapter 4 Small 8-Bit Systems
be used to access memory and will not be available for other
microcontrollerfeatures.(Pinusage,busexpansion,andpinmulti-
plexing will be discussed in later sections.) The important
considerationatthispointisthatthelimitedprogrammemoryarea
usuallyassociatedwithamicrocontrollershouldnotcauseserious
concern.Iftheprogramgrowstoexceedtheavailablesizeofonboard
memoryforamicrocontrollerfamily,itisalwayspossibletogeta
larger microcontroller that can handle any additional memory re-
quirements.Theprogramminggoal,though,isusuallytoconfinethe
programinthesmallestpossibleprogrammemoryspacesothatthe
leastexpensivemicrocontrollerwilldothejob.
UsingMicrocontrollerMemory
InourdiscussiononvariablesinChapter1,itwasshownthatC
treatsallautomaticvariablesaslocaltotheblockinwhichtheyare
declared.Thescopeofthesevariablesistheblockwheretheyare
declared.Sincethesevariablesexistonlyintheblockwheretheyare
declared,thememorylocationsdedicatedtothestorageofthesevari-
ablescanbefreedwhenthevariablesgooutofscope.Theserules
createanidealsituationforstorageontheprogramstack.Memory
spaceiseasilycreatedonthestackatthebeginningofablock,andit
isequallyeasilydestroyedatthecloseoftheblock.Thisoperationis
exactly what is needed, but it cannot be used in a typical small
microcontroller.MostmicrocontrollershaveverylimitedRAM,and
thestackarrangementinthemiscompletelydifferentfromthatyou
willfindonalargecomputer.OntheM68HC05familyofparts,for
example, the chip has a hardware stack and no stack pointer into
memorythatthecompilerwritercanaccess.Therefore,itisimprac-
ticaltoevenattempttousethesystemstacktostorelocalvariables.
The hardware stack on these chips is used only for storage of the
processorstatuswhenaninterruptoccursortostorethereturnad-
dress from a jump to a subroutine. The stack pointer is set to its
initialvalueonmicrocontrollerreset,andtheoccurrenceofaninter-
ruptorajumptosubroutineinstructionaretheonlywaysthatthe
stackpointercanbechanged.
In the larger machines, the stack pointer is set to a value that
points to a memory location. This pointer will be automatically
incrementedanddecrementedbytheequivalentofstackpushorpull
Microcontroller Memory 157
operations.Theprogramcanarbitrarilychangethestackpointervalue
sothatroomforautomaticvariablescanbeeasilyprovidedorelimi-
nated.Inthesmallmicrocontrollers,automaticvariablesarestored
inRAMandtheirscopeisnotlimitedtotheblockinwhichtheyare
defined.Theiraccessislimitedtotheirblock,however.Considerthe
followingcodesegment:
main()
{
inti;
.
.
.
}
voidable(void)
{
inti;
.
.
.
}
Thetwooccurrencesofthevariableiinthiscasewillcauseno
troublebecauseeachiwillbegivenauniquelocationinRAMand
thescopingarrangementwillinsurethatanyreferencetoiinmain()
willnotbeconfusedwiththeiinable()andviceversa.
Animportantimplicationofthischangeinstorage:recursionis
nolongeravailable!Onlyonememorylocationisavailableforeach
variable in the program. When a stack is used to store automatic
variables,afunctioncancallitselfandanewblockiscreatedeach
timethefunctionisentered.Thus,eachtimeafunctioncallsitself,a
newstackframethatcontainsspaceforallautomaticstorageinthe
functioniscreated.Thefunctioncancallitselfrepeatedlyaslongas
thereisspaceonthestacktocreatenewstackframesforthesucces-
sive calls. Without stack space for variable storage, recursion is
impossible.
Asecondlimitationthatoccursisintheavailableargumentsfor
function calls. The compiler C6805 for the M68HC05 family de-
fines an int as an 8-bit number and a long as a 16-bit number.
158 Chapter 4 Small 8-Bit Systems
ThisdefinitionisnotcompliantwiththeANSIStandard,whichre-
quiresthatanintbeatleast16bitswideandalongbeatleast32
bits. Sincethestackcannotbeusedtopassarguments,theymustbe
passedineitherregistersorasglobalvariables.Iftheyarepassedin
registers,onlytwobytescanbepassed.Theargumentscanbeeither
twointsoronelong.Functionreturnvalueshavethesamelimi-
tations. Of course, the program can use global variables to pass
informationtoorfromafunction.Aglobalvariabledefinedexternal
toanyfunctioncanbeaccessedbyanyfunctionintheprogram.
MostCcompilersfortheM68HC05familyprovideautomatic
placement of variables in the available RAM of the part. Specific
memoryaddressesareidentifiedtothecompilerbythe#pragma
memorydirectives.Thefollowingcodesegmentshowsanexample
ofhowthememoryisdefinedwithinanM68HC05program:
#pragmamemoryROMPAGE0[48]@32;
#pragmamemoryROMPROG[5888]@2048;
#pragmamemoryRAMPAGE0[176]@80;
#pragmamemoryRAMPROG[256]@256;
Thissequenceofcodewillbeusedtoidentifythememorymapof
theM68HC05B6.Thisparthas48bytesofROMinpagezerostart-
ingataddress32.Thereare5888bytesofprogramROMstartingat
address2048.The176bytesofpagezeroRAMstartsataddress80.
Thereare256bytesofEEPROMinthispartthatbeginattheaddress
256.HerewetreatEEPROMasprogramRAMbecauseitispro-
grammableandisoutsideofthebasepage.
Inclusion of the above code lines will identify the necessary
memory locations for the compiler, and further concerns about
memory locations should be unnecessary.The compiler will auto-
matically place the code in the ROMPROG area and the RAM
requirementswillfallatthestartingaddressidentifiedbyRAMPAGE0.
ProgrammerswhowishtomakeuseoftheROMPAGE0memorycan
dosobyacommandlike
constinttable[]={,,,...,}@32;
ThisinstructionwillplacethespecifiedarrayofdataintheROMPROG0
areaandwillstartitattheaddress32.
Microcontroller Memory 159
ProgrammingEEPROM
EEPROMisreadlikeanyothermemoryinthemicrocontroller.
TwodifferenttypesofEEPROMcanbefoundonamicrocontroller:
programmemoryanddatastoragememory.Programmemoryusu-
allycannotbeprogrammedwithouttheaidofanexternallyapplied
programmingvoltage.Datastoragememorycanbeprogrammedfrom
withintheprogramandrequiresnoexternallyappliedprogramming
voltage. In the case of the M68HC805B6, there are 5888 bytes of
programEEPROMand255bytesofdatastorageEEPROM.Other
thanthereducedsizeofthedatastoragememory,thismemoryisno
differentfromtheprogrammemory.Itispossibletowritecodeto
thedatastorageEEPROMandexecutethiscode.
OneadditionalbyteofdatastorageEEPROMexistsandiscalled
theOPTIONregister.ThisregistercontentissavedinEEPROMwhich
is read into a latched register during the initialization of the
microcontroller.Theaddressofthisregisteris0x100.Thebitsinthis
register control the security option of the part and control a block
protectregioninthedatastorageEEPROMthatwillpreventacci-
dentalwritingofdataintotheprotectedmemoryarea.Adescription
ofthesebitsfollows:
OptionsReg
0x0100
Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0
EE1P SEC
SEC Bit0 SecurityBit.WhentheSECbitisprogrammedto
zero,thecontentsoftheEPROMaresecuredby
preventingaccesstothetestmode.Theonlyway
toerasetheSECbittoaonestateistoenterthe
self-check mode. In this event, the data on
EEPROMwillallbeerased.WhentheSECbitis
changed, its new value will have no effect until
afterthenextchipreset.
EE1P Bit1 EEPROMBlockProtectBit.TheEEPROMisin
twoparts:0x101to0x11fispart1and0x120to
0x1ffispart2.TheEE1Pbitallowspart2tobe
protected.Ifthisbitisintheerasedstate,(1),part
2oftheEEPROMwillbeprotected.Thismemory
areacanbereadasusual,butanyattempttowrite
to this area will fail. The protection remains in
160 Chapter 4 Small 8-Bit Systems
effect after this bit is erased until after the next
chipreset.
ControloftheEEPROMprogrammingisthroughtheEEPROMCTL
registerfoundataddress0x07.Thebitsinthisregisterareasfollows:
EEPCTL/CLK
0x07
Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0
ECLK E1ERA 0 0 0 0 E1LAT E1PGM
E1PGM Bit0 EEPROMProgramBit.Thisbitturnstheinternal
Vppchargepumponandoff.Whenthisbitis0,
thechargepumpisturnedoff,andwhenitisat1,
the charge pump is turned on.The charge pump
voltagecanbemeasuredonthepinVpp1.Thisbit
cannotbesetuntilaftertheprogramdataarelatched
inplacebyassertingtheE1LATbit.Resettingthe
E1LATbitwillalsoresettheE1PGMbit.
E1LAT Bit1 EEPROMData/AddressLatch.Whenthisbitisre-
settozero,boththeE1PGMbitandtheE1ERAbit
areresettozero.WhentheE1LATbitisreset,data
canbereadfromtheEEPROM.Thefirstdatawrite
totheEEPROMarrayafterthisbitissetislatched
until the E1LAT bit is reset. Data can be latched
onlywhentheE1PGMbitisresettozero.Thisop-
eration allows programming of the EEPROM.
E1LAT isautomaticallyresetwhenthechipisreset
orwhentheSTOPinstructionisexecuted.
E1ERA Bit2 EEPROMEraseBit.IfthebitE1ERAisresetto
zerowhenE1LAT andE1PGMaresettoone,data
are programmed into the EEPROM. Otherwise,
if E1ERA is set to one and E1LAT and E1PGM
are set to one, the specified address in the
EEPROM will be erased. E1ERA cannot be set
beforeE1LAT,andresettingE1LATtozerowill
causeE1ERAtobereset.
Letusnowexamineapossiblesequenceofcodethatcanbeused
to program and erase locations in EEPROM. First, several macro
definitionsshouldbeusedtodefinethevariousparametersused.
Microcontroller Memory 161
/*pragmastoidentifyEEPROMcontrolregisters*/
#pragmaportrwEEPROM_CTL@0x07;
#pragmaportrwOPTIONS@0x100;
.
.
.
/*EEPROMprogrammingspecificdefines*/
#defineE1PGM0
#defineE1LAT1
#defineE1ERA2
#definePROG_TIME10
.
.
/*somefunctionprototypes*/
voiddelay(unsignedlong);
voidprogram(int,int);
voiderase(int);
.
.
.
intEEPROM[0xff]@0x101;/*IdentifytheEEPROM*/
voidprogram(intaddress,intvalue)
{
EEPROM_CTL.E1LAT=1;/*settheE1LATbit*/
EEPROM[address]=value;/*putthedataandaddress
inplace*/
EEPROM_CTL.E1PGM=1;/*turnonthechargepump*/
delay(PROG_TIME);/*delayprogrammingtime*/
EEPROM_CTL.E1LAT=0;/*resettheE1LATalso
resetstheE1PGMbit*/
} /*returnwhendone*/
voiderase(intx)
{
162 Chapter 4 Small 8-Bit Systems
EEPROM_CTL.E1LAT=1;/*settheE1LATbit*/
EEPROM_CTL.E1ERA=1;/*settheE1ERAerasebit*/
EEPROM[x]=0;/*selecttheaddress*/
EEPROM_CTL.E1PGM=1;/*turnonthechargepump*/
delay(PROG_TIME);/*waittheappropriatetime*/
EEPROM_CTL.E1LAT=0;/*resettheE1LATbitturns
offbothE1PGMandE1ERA
bits*/
} /*returnwhendone*/
Theaboveprogramsequencesarecompiledandlistedbelow.
Thefunctiondelayisnotincludedorlinkedintothisprogram.
Tohandlethistypeofproblem,theregistersaresetupforthefunc-
tioncall,andtheinstructionJSR$****isexecuted.Alaterlinking
willreplacetheunknownfunctionaddresswiththecorrectvalue.An
appropriatedelay()functionwillbewritteninthetimersection.
Theinstructionsforthisfunctioncallarefoundataddresses0x80c
to0x80finthefollowinglisting.
00200030#pragmamemoryROMPAGE0[48]@32;
08001700#pragmamemoryROMPROG[5888]@2048;
005000B0#pragmamemoryRAMPAGE0[176]@80;
01000100#pragmamemoryRAMPROG[256]@256;
/*pragmastoidentifyEEPROMcontrolregisters*/
0007#pragmaportrwEEPROM_CTL@0x07;
0100#pragmaportrwOPTIONS@0x100;
/*EEPROMprogrammingspecificdefines*/
0000#defineE1PGM0
0001#defineE1LAT1
0002#defineE1ERA2
000A#definePROG_TIME10
/*somefunctionprototypes*/
voiddelay(long);
Microcontroller Memory 163
voidprogram(int,int);
voiderase(int);
0101010100FFintEEPROM[0xff]@0x101;
voidprogram(intaddress,intvalue)
00500051{
0801BF50STX$50
0803B751STA$51
08051207BSET1,$07EEPROM_CTL.E1LAT=1;
0807D70101STA$0101,XEEPROM[address]=value;
080A1007BSET0,$07EEPROM_CTL.E1PGM=1;
080C5FCLRXdelay(PROG_TIME);
080DA60ALDA#$0A
080FCD0000JSR$****
08121307BCLR1,$07EEPROM_CTL.E1LAT=0;
081481RTS}
voiderase(intx)
0052{
0815B752STA$52
08171207BSET1,$07EEPROM_CTL.E1LAT=1;
08191407BSET2,$07EEPROM_CTL.E1ERA=1;
081B97TAXEEPROM[x]=0;
081C4FCLRA
081DD70101STA$0101,X
08201007BSET0,$07EEPROM_CTL.E1PGM=1;
08225FCLRXdelay(PROG_TIME);
0823A60ALDA#$0A
0825CD0000JSR$****
08281307BCLR1,$07EEPROM_CTL.E1LAT=0;
082A81RTS}
The function program() requires 20 bytes and the function
eraserequires22.ThisisagoodpointtoexploresomeoftheC
programmingpracticesthatcanleadtopoorM68HC05familycom-
164 Chapter 4 Small 8-Bit Systems
piledcode.TheM68HC05familyisafamilyof8-bitmachines.There
hasbeennodiscussionoftheprogrammersregistermodelofthese
devices.Programmermodelsofthelargermicrocontrollerswillbe
discussedbecauseknowledgeoftheprogrammersmodelmighthelp
incraftinggoodCcode.Forthesesmallmachines,thewatchwordis
8-bit.Theinternalstructureofthesystemisall8-bit.Thewidthof
thesingleindexregisteris8bits,andthewidthoftheaccumulatoris
also8bits.Theprogramcounterismorethan8bitsinmostcases,
butitiswideenoughtoaddressonlytherangeoftheinternalcom-
puter memory. In fact, the width of the stack pointer in the
M68HC05Bxfamilyisonly6bits.Thereisnoluxuryofsparebitsin
anyregister.
Therefore,whenwritingcodefortheM68HC05family,keepfore-
mostinyourmindthatyouaredealingwithan8-bitdevice.Ifatall
possible,avoid16-bitoperationsbecausetheywillalwaysresultinlarger
memory and/or code usage.The following code demonstrates an ex-
ampleofthecarelessuseof16-bitimpliedcodeinan8-bitmachine.
Considertheerase()routinefromabove.Thisfunctioncould
havebeenwrittenasfollows:
voiderase(int*x)
{
EEPROM_CTL.E1LAT=1;/*settheE1LATbit*/
EEPROM_CTL.E1ERA=1;/*settheE1ERAerasebit*/
*x=0;/*selecttheaddress*/
EEPROM_CTL.E1PGM=1;/*turnonthechargepump*/
delay(PROG_TIME);/*waittheappropriatetime*/
EEPROM_CTL.E1LAT=0;/*resettheE1LATbitturns
offbothE1PGMandE1ERA
bits*/
} /*returnwhendone*/
The only change in this version is to pass the integer *x to the
functionbyreference.Remember,sincealladdressesintheM68HC05
familyofpartsaregreaterthan8bits,thecompilermusthandlethe
transfer of the pointerx as a 16-bit number.The statement*x=0;
compilesintoaninlinefunctionattheaddressrange0x81dto0x82cin
thecompiledversionofthecodeshownbelow.Thisfunctioncreatesa
subroutinethatdoesanindexedstorewitha16-bitoffset.First,the
value to be programmed is placed in the accumulator. Then the op
Microcontroller Memory 165
code,0xd7,todoastoretheaccumulatorindexedwitha16-bitoffset
is created at the location 0x56 in memory. The 16-bit offset is the
addresspassedtothefunctioninthecombinationofthexregisterand
theaccumulator.Thisaddressisplacedinthememorylocations0x58
and0x57,completingthestoreinstruction.Attheaddress0x59,are-
turn from subroutine instruction, 0x81, is placed to complete the
function.Theindexregisteriscleared,andthistwo-instructionsub-
routineisexecutedtostoretheappropriatedatapriortotheprogram
settingthelatchbit.
voiderase(int*x)
0052{
0815BF52STX$52
0817B753STA$53
08191207BSET1,$07EEPROM_CTL.E1LAT=1;
081B1407BSET2,$07EEPROM_CTL.E1ERA=1;
081DB758STA$58*x=0;
081F9F TXA
0820B757STA$57
08224F CLRA
0823AED7LDX#$D7
0825BF56STX$56
0827AE81LDX#$81
0829BF59STX$59
082B5F CLRX
082CBD56JSR$56
082E1007BSET0,$07EEPROM_CTL.E1PGM=1;
08305F CLRXdelay(PROG_TIME);
0831A60ALDA#$0A
0833CD0000JSR$****
08361307BCLR1,$07EEPROM_CTL.E1LAT=0;
083881 RTS}
Thiscodesequencerequires36bytes,plus4bytesofuncommit-
tedRAMspace,toaccomplishwhatrequired22bytesintheearlier
exampleofthesameoperation.
Youmustnotavoidtheuseofpointersbecauseofthisoneex-
ample.Therearecaseswhenproperpointerusagewillprovidethe
best code that you can generate. When writing code for
microcontrollers,usemanyrelativelysmallfunctionsthatyoucan
166 Chapter 4 Small 8-Bit Systems
compileindividuallyandexamineiftheycreateoutlandishcode.Once
thesesmallfunctionsarealldebugged,youcanintegratetheminto
yourprogramaseitherinlinecodeorasfunctioncalls.Hence,the
fundamental rule of writing good high-level code for a
microcontroller:theproductionofgoodCcodeforamicrocontroller
isajointeffortbetweentheprogrammerandthecompilerwriter.
ErasureofEEPROMcausescomponentwear,andmostEEPROMs
willwearoutafteralargenumberoferasures.Thenatureofthedeg-
radationisthatthecomponentrefusestoeraseaftermanyerasures.
Therehasbeennoevidencethatdataretentionisaffectedbyrepeated
erasures.Thenumberoferasuresthatcancauseproblemsistempera-
turesensitive.Mostofthesedevicesareratedfor10,000write/erase
cyclesatthemaximumratedtemperatureforthepart.Atroomtem-
perature,thenumberofwrite/erasecycleswithoutdamagecangrow
toseveralhundredthousand.Inlightofthesefacts,itisimportantthat
programsusecareinrewritingthecontentsofEEPROM.
EXERCISES
1.The EEPROM in microcontrollers erase to the 1 state. Write a
function that checks to determine if an erasure cycle erases the
contentsofagivenlocationinmemory.
2.Write a function that compares data to be programmed into
EEPROManddetermineifitisnecessarytoeraseabytecontain-
ingdatabeforeitisreprogrammed.Thisapproachwillextendthe
lifeoftheEEPROM.
Timers
Thesystemsoftimersplacedonmicrocontrollersareamongthe
mostcreativeengineeringeffortsmostpeoplewilleversee.Thefunc-
tionsofthesetimerscoverliterallydozensofdifferentoperations.
This set of peripheral components mainly relieve the computer of
muchworkassociatedwithexecutionoftheperipheralfunction.We
willstartwiththesimplesttimerandoutlinedifferenttimercapabili-
tiesinincreasingcomplexity.ThemostbasictimerintheM68HC05
family is called the 15-bit timer, and probably the most advanced
timersystemisthe16-bittimer.Thesedifferenttimersystemsare
literally unrelated in the features they offer.Another timer feature
Timers 167
offeredinsomemicrocontrollersisthe computeroperatingprop-
erly (COP) timer. Each of the systems will be examined in some
detailinthefollowingparagraphs.
MultifunctionTimer15-BitTimer
A timer of this nature can be found on the smallest of the
M68HC05components,suchastheM68HC05J1ortheM68HC05P8,
anditisnotfoundontheM68HC05Bxdevicesdiscussedpreviously.
Thistimerconsistsofan8-bitripplecounterfollowedbyanaddi-
tional7-bitcounter.Thiscounterchainisdrivenbyasignalthatisat
one-fourththeinternalclockfrequencyofthemicrocontroller.The
internal clock frequency in turn is half the crystal frequency.This
portionofthecounteriscompletelyuncontrolled.Theprogramcan,
however,readthevalueofthiscounteratanytime.Ablockdiagram
ofthistypeoftimerisshowninFigure4-1.
Internal
Processor
Clock
(XTAL 2)
2 2 2 2 2 2 2 2
2 2 2 2 2 2 2
2 2 2
Least Significant Eight Bits of 15 Stage Ripple Counter
MSB
Timer Count Register
Fixed
Divide By
4
TOF RTIF TOFE RTIE 0 0 RT1 RT0
RTI Rate Select
$0008
TCSR
$0009
TCR
Most Significant Seven Bits of 15 Stage Ripple Counter
LSB
COP Timeout-Generate
Internal MCU Reset
Q
S
R
Service (Clear)
COP Watchdog
Figure4-115-bitTimerBlockDiagram
168 Chapter 4 Small 8-Bit Systems
0x08
Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0
0 0
STATUSREG
RT1 RT0 TOFE RTIE TOF RTIF
RT0 Bit0 RealTimeInterruptSelectRates.Thesebitscon-
troltherateatwhichthereal-timeinterruptand
theCOP resettimewilloccur.Notethatthesetwo
RT1 Bit1 bitsaredeliveredtotheRTIRateSelectregisterin
thediagram.Table4-3showsthevariousRTIand
COPratesthatcanbeobtainedfordifferentvalues
ofRTIandRT0.Resetsetsbothbitssothatthe
periodic rates will be the slowest possible when
thepartcomesoutofreset.Itisexpectedthatthese
bits will not be changed If these bits are altered,
thefirstcyclefollowingthechangewillbewrong.
RTIE Bit4 RealTimeInterruptEnable.Whenthisbitisset,a
CPUinterruptrequestisgeneratedwheneverthe
RTIFisset.
TOFE Bit5 Timer Overflow Enable. When this bit is set, a
CPUinterruptrequestisgeneratedwheneverthe
TOFisset.
RTIF Bit6 RealTimeInterruptFlag.Thisbitissetwheneverthe
outputfromtheselecteddividerstagesisset.Ifthe
RTIEisalsoset,settingofthisbitwillrequestaCPU
interrupt.Thisbitisclearedbyresetorbywritinga
zerotoit.Itisnotpossibletowritea1tothisbit.
TOF Bit7 TimerOverflowFlag.Thisbitissetwheneverthe
8-bitripplecounteroverflowsfroma0xfftoa0x00.
Thisbitisclearedbyresetorbywritingazeroto
it. It is not possible to write a 1 to this bit. The
timingthatresultsfromselectionofvaluesforRT1
andRT0 are shown inTable 4-1.This table also
showstherealtimeinterruptratefordifferentval-
uesoftherealtimeinterruptselectratebits.
The timer counter register at address 0x09 contains the value
foundinthe8-bitripplecounter.Thecontentsofthiscountercanbe
readatanytime,butitcannotbewrittento.Whenthepartcomesout
ofreset,thetimercounterregistercontainsazero.4096clockcycles
willfollow,duringwhichtheTCRwillcountattheminimumrate.
Timers 169
Atthecloseofthisperiod,theinitializationofthepartiscomplete,
and the TCR is again reset to zero prior to execution of the code
identifiedbytheresetvector.WhenevertheRESETlineisasserted,
theTOFwillbeloadedwithzeros.
AnyprogramcanreadtheTCR,soitispossibletogenerateasyn-
chronoustimeeventsfasterthantheTOF ortheRTIFwouldindicate.
When the processor enters theWAIT mode after execution of a
WAITinstruction,theCPUclockhalts,butthetimerclockcontinues
toexecute.Iftheinterruptsarenotmasked,atimerinterrupt,anexter-
nalinterruptoraresetwillcausethedevicetoexittheWAITmode.
Table4-3:RTIAndCOPRatesforF =4.0MHz
xtal
RT1 RT0 RTIRate Minimum
COPReset
0 0 8.2ms 57.3ms
0 1 16.4ms 114.7ms
1 0 32.8ms 229.4ms
1 1 65.5ms 458.8ms
IfaSTOPinstructionisexecuted,thetimerclockishaltedalong
with the CPU clock. The STOP mode is exited when an external
interruptoccursortheRESETlineisasserted.Inthiscase,thepart
performsasdescribedabove.
Mostmicrocontrollersareplacedinoperationwithnooperatorto
intervene in the event of a problem.A COP timer will provide one
meansofrecoveringiftheoperationofthemicrocontrollergetslost.
Getslost?Thesituationthatcancauseamicrocontrollertogetlost
is usually some type of voltage spike or glitch in the power supply
operation.Theprogramcounterusuallyendsupwithavalueoutside
oftheprogram,andnooneknowswhatwillhappen.TheCOPissim-
plyatimerthatcountsforaspecifiedamountoftime.IftheCOP timer
has not been reset before the specified time elapse, the COP timer
overflowcausesaninternalresetofthemicrocontroller.Ifthecauseof
theproblemisadropinpowerorothererror,inmostinstancesforcing
aresetwillbringthemicrocontrollerbackintonormaloperation.
The COP control register is located at address 0x7f0 in the
M68HC05J1. To service the COP from the program, the program
must merely write a zero to bit 0 of this address to reset the COP
portionofthetimersystem.
170 Chapter 4 Small 8-Bit Systems
Goodprogrammingpracticedictatesthatmicrocontroller-specific
informationbeplacedinaheaderfilelikethatshownhere:
#pragmaportrwPORTA@0x00;
#pragmaportrwPORTB@0x01;
#pragmaportrwDDRA@0x04;
#pragmaportrwDDRB@0x05;
#pragmaportrwTCST@0x08;
#pragmaportrwTCR@0x09;
#pragmaportrw__COPSVS@0x7f0;
#pragmavector__TIMER@0x07f8;
#pragmavector__IRQ@0x07fa;
#pragmavector__SWI@0x07fc;
#pragmavector__RESET@0x07fe;
#pragmahasSTOP;
#pragmahasWAIT;
#pragmahasMUL;
#pragmamemoryRAMPAGE0[64]@0xc0;
#pragmamemoryROMPROG[1024]@0x300;
#defineRT00/*TSCRBits*/
#defineRT11
#defineRTIE4
#defineTOFE5
#defineRTIF6
#defineTOF7
Listing4-3:HeaderFileForTheM68HC05J1
The#pragmaandseveralimportant#definecommandsare
microcontrollerspecific.Therefore,tochangetheprogramfromone
microcontroller to another, the programmer need only change the
microcontroller header file. Listing 4-3 is a header file for the
M68HC05JJ1controller.Thefirstsixentriesidentifythelocations
oftheI/Oports,thedatadirectionregisters,timerstatus/controlreg-
ister,andthetimercounterRegister.Thenextfiveentriesspecifythe
COPserviceaddressandthevectorlocationsforthispart.Notethat
thenamesassociatedwiththevectorlocationsallstartwithadouble
Timers 171
underscore.Thesenamesarealsolistedinallupper-caseletters.These
entriesarethenamesofthevariousinterruptserviceroutines.Since
Ciscasesensitive,thenamesofthefunctionstobeusedasinterrupt
serviceroutinesmusthavethesameform.
Thethree#pragmaentriesidentifiedashasnotifiesthecom-
piler that the microcontroller has the STOP, WAIT, and MUL
instructions.The next pair of entries defines the memory map for
thismicrocontroller.Finally,thenextsixentriesare#definesthat
identifythebitsintheTCSR.Therefore,mnemonicrepresentations
ofallregistersandbitscanbeusedintheCprogram.
Several header files for the M68HC05 family are found on the
CD-ROM. The conventions in these files are to use bit names and
register names that are identical to those used in the technical data
booksthatdescribethedevices.Therefore,theprogrammercansafely
useregisternamesandbitnamesfoundinthebookswithouthavingto
lookupthevaluesintheheaderfiles.Thesefilesincludecommandsto
preventlistingofthesefilesinthecompilerlistingoutputfiles.
Listedbelowisasimpleprogramthatshowstheuseofthe15-bit
timerintheM68HC05J1.Thisprogramisnotaimedatdoingmore
thanshowingtheuseofthetimeroperation.Thesystemwillcreate
aninaccurateclockinwhichthetimeinhours,minutes,andseconds
willberecordedinmemory,butnoprovisiontodisplaythesevalues
orevensetthevalueswillbeconsideredatthistime.
Mostclockingoperationsshouldbeinterruptdriven.Ifaperiodic
interruptcanbegenerated,theoperationoftheclockwillbetranspar-
enttoanyotheroperationsbeingconductedinthemicrocontroller.
#includehc05j1.h
enum{FALSE,TRUE);
enum{OFF,ON};
#defineFOREVERwhile(TRUE)
#defineMAX_SECONDS59
#defineMAX_MINUTESMAX_SECONDS
#defineMAX_HOURS12
#defineMAX_COUNT121
/*definetheglobalvariables*/
inthrs,mts,sec;
172 Chapter 4 Small 8-Bit Systems
intcount;
main(void)
{
count=0;/*startcountatzero*/
TCST.RT0=OFF;/*57.3mscoptimer*/
TCST.RT1=OFF;/*8.192msRTI*/
TCST.RTIE=ON;/*TurnontheRTI*/
TCST.RTIF=OFF;/*Resetinterrupt*/
TCST.TOF=ON;/*flags*/
CLI();/*turnoninterrupt*/
FOREVER
{
if(sec>MAX_SECONDS)/*doclockthings*/
{
sec=0;
if(++mts>MAX_MINUTES)
{
mts=0;
if(++hrs>MAX_HOURS)
hrs=1;
}
}
/*hereiswhereanyapplicationsprogramshould
beplaced.*/
}
}
void__TIMER(void) /*routineexecutedevery
RTI(8.192ms)*/
{
TCST.RTIF=OFF;/*resetinterruptflag*/
if(++count>MAX_COUNT)
{
sec++;/*incrementseconds*/
count=0;/*resetthecounteachsecond*/
}
}
Listing4-4:ATime-of-DayProgramBasedOnThe15-bitTimer.
Timers 173
Afewwordsaboutagoodprogrammingpractice:numbersina
programwithnodefinedmeaningarecalledmagicnumbers. You
should avoid magic numbers, because a number with no meaning
makeslifedifficultfortheprogrammaintenancepeople.Inthepro-
gramabove,severalnumbersareneeded.Thesenumbersaregivena
namebyeitherenumstatementsor#definestatements.Then,in
the program, you can see every instance of the use of the number
doeshaveameaningrelativetotheprogram.Anotheradvantageto
avoidingmagicnumbersisnottooevidentintheaboveprogram,but
itistrulyanimportantadvantage.Iftheprogramislongandcom-
plicated, these numbers might be used many times. Then if a
maintenancesituationrequiresthechangeofthevalueofanumber
intheprogram,itcanbechangedinoneplaceandarecompilation
willcorrecteveryinstanceofthenumberintheprogram.
Several global variables are used in this program: hrs, mts,
sec,andcount.Thesevariablesareallchangedinthemainpro-
gram,buttheyareavailableinanyotherpartoftheprogramifneeded.
Forexample,thecountvariableisinitializedtozerointhemain
programandincrementedandresetintheinterruptserviceroutine.
Onepointshouldbenotedinthisprogram:themainprogramhasall
ofthetimecalculationsbasedonthecurrentcontentsofsec.The
variablesecisincrementedeachsecondintheinterruptservicerou-
tine.Someprogrammerswouldputthecompletetimeservicewithin
theinterruptserviceroutine.Thatis,theywouldresetsecwhenit
reaches60,incrementmts,andsoforthwithintheinterruptservice
routine.Eitherapproachwillprovidethesameresult,andeachtakes
thesametotalcomputertime.Itis,however,bettertokeepthetime
that the program is controlled by the interrupt service routine at a
minimum.Interruptsaredisabledwhenaprogramisinaninterrupt
serviceroutine.Ifthereareseveralcompetinginterrupts,execution
ofaninterruptserviceroutinepreventsotherinterruptsfrombeing
processed.Quickestresponsetoallinterruptswillbeobtainedifall
oftheinterruptserviceroutinesareasshortaspossible.
ProgramOrganization
Acompiledversionofthisprogramislistedbelow.Notethatthe
compiler listing routine prints out the contents of the include file.
Thememorymap#pragmasputstheRAMinpage0beginningat
174 Chapter 4 Small 8-Bit Systems
0xc0andtheprogrammemorystartsat0x300.Notethatthecom-
piler places the global variables in 0xc0 through 0xc3, and the
executableprogrambeginsat0x300asonewouldexpect.
Thefirstseveralinstructionsclearthecountlocationandsetor
resetproperbitsintheTSCR.TheinstructionCLIclearstheinter-
ruptbitinthestatusregisterofthemicrocontroller.Whenthisbitis
cleared,interruptswilldetectedandprocessed.
ThebeginningoftheloopdefinedbythemacrocommandFOR-
EVERisataddress0x30d.Thismacrocausesnocodeatthebeginning
oftheloop.Attheendoftheloop,address0x32b,thereisaninstruc-
tionBRA0x30dthatcausescontroloftheprogramtostartatthe
beginning of the loop.That is the total code created by the macro
FOREVER. Within this loop, the code created by the compiler is
straightforwardandnotverydifferentfromcodethatwouldbecre-
atedbyacompetentassemblylanguageprogrammer.
#includehc05j1.h
0000#pragmaportrwPORTA@0x00;
0001#pragmaportrwPORTB@0x01;
0003#pragmaportrPORTD@0x03;
0004#pragmaportrwDDRA@0x04;
0005#pragmaportrwDDRB@0x05;
0008#pragmaportrwTCST@0x08;
0009#pragmaportrwTCNT@0x09;
07F0#pragmaportrw__COPSVS@0x7f0;
07F8#pragmavector__TIMER@0x07f8;
07FA#pragmavector__IRQ@0x07fa;
07FC#pragmavector__SWI@0x07fc;
07FE#pragmavector__RESET@0x07fe;
#pragmahasSTOP;
#pragmahasWAIT;
#pragmahasMUL;
00C00040#pragmamemoryRAMPAGE0[64]@0xc0;
03000400#pragmamemoryROMPROG[1024]@0x300;
Timers 175
0000#defineRT00
0001#defineRT11
0004#defineRTIE4
0005#defineTOFE5
0006#defineRTIF6
0007#defineTOF7
0001#defineTRUE1
0000#defineFALSE0
0001#defineFOREVERwhile(TRUE)
00C000C100C2inthrs,mts,sec;
00C3intcount;
main(void)
{
03003FC3CLR$C3count=0;
03021108BCLR0,$08TCST.RT0=0;
03041308BCLR1,$08TCST.RT1=0;
03061808BSET4,$08TCST.RTIE=1;
03081D08BCLR6,$08TCST.RTIF=0;
030A1F08BCLR7,$08TCST.TOF=0;
030C9A CLICLI();
FOREVER
{
030DB6C2LDA$C2if(sec==60)
030FA13CCMP#$3C
03112518BCS$032B
{
03133FC2CLR$C2sec=0;
03153CC1INC$C1if(++mts==60)
0317B6C1LDA$C1
0319A13CCMP#$3C
031B260EBNE$032B
{
031D3FC1CLR$C1mts=0;
031F3CC0INC$C0if(++hrs==13)
0321B6C0LDA$C0
0323A10DCMP#$0D
176 Chapter 4 Small 8-Bit Systems
03252604BNE$032B
0327A601LDA#$01hrs=1;
0329B7C0STA$C0}
}
032B20E0BRA$030D}
032D81RTS}
void__TIMER(void)
07F8032E{
032E1D08BCLR6,$08TCST.RTIF=0;
03303CC3INC$C3if(++count==122)
0332B6C3LDA$C3
0334A17ACMP#$7A
03362604BNE$033C
{
Timers
03383CC2INC$C2sec++;
033A3FC3CLR$C3count=0;
}
033C80RTI}
07FE0300
Atthebeginningoftheinterruptserviceroutinethereisanentry
07f8,whichhasavalueof032e,intheaddresscolumn.Thisentry
places the address of the timer interrupt service routine 0x032e
intothetimervector0x07f8.Thecodegeneratedintheinterrupt
serviceroutineisstraightforwardandlittledifferentfromwhatone
wouldexpectanassemblylanguageprogrammertodo.Note,how-
ever,thatthereturnattheendoftheinterruptserviceroutineisan
RTIinstruction.Thisistheinstructionthatcausesthemicrocontroller
torestoretheprocessorstatustothestatethatexistedwhentheinter-
ruptoccurred.ThenormalreturnfromsubroutineRTSdoesnotrestore
the processor state.AnRTI must be used to return from interrupt
serviceroutines,andanyfunctionidentifiedwithavectorpragma
willbeassumedtobeaninterruptserviceroutinebythecompiler.
Itwasnotedearlierthatthistimerroutineisinaccurate.Itisinac-
curate only because 122 periods of 8.192 milliseconds each total
0.999424seconds.Thisseeminglysmallerrorwillcausebigproblems
Timers 177
ifonewantsarealclockbecausetheerroramountsto2.1secondsper
hour. One way this error could be corrected is to adjust the crystal
frequencyofthemicrocontroller.Supposewewoulduseafrequency
of3.996354MHzinsteadof4.0MHz.Thisnumberisderivedby
122*2^15/f=1
whichyieldstheabovevalueforf.The122periodsof8.196721milli-
seconds,whichisthereal-timeinterrupttimeforthisfrequency,isexactly
1second.Anotherapproachinvolvesmakingsmallcorrectionstothe
timeperiodicallysothatontheaveragethetimeiscorrect.Anexample
ofaninterruptserviceroutinethatmakesthesecorrectionsisasfollows:
void__TIMER(void)/*routineexecutedeveryRTI
(8.192ms)*/
{
staticintcorr1,corr2,corr3;
TCST.RTIF=0; /*flags*/
if(++count==122) /*incrementseconds*/
{ /*Tocorrectfor8.192*/
sec++; /*mspertick.Run122*/
if(++corr1==14)/*tickspersecondfor*/
{ /*13seconds,and123*/
corr1=0; /*forthe14thsecond*/
if(++corr2==80)/*Withthisalgorithm*/
{ /*thereare14.000128*/
corr2=0; /*actualsecondsper*/
if(++corr3==4) /*14indicated.Then*/
{/*run79ofthese*/
count=1; /*cyclesfollowedby*/
corr3==0; /*onecycleof14*/
} /*secondswith122ticks*/
else /*persecond.The*/
count=0; /*elapsedtimeforthis*/
} /*cycleis1120.002048*/
else /*secondsforand*/
count=(-1); /*thecountis1120*/
}/*seconds.Repeatthis*/
else /*cycle4timesandon*/
178 Chapter 4 Small 8-Bit Systems
count=0;/*thelastcycledrop*/
} /*onetickmakesthe*/
} /*indicateandelapsed*/
/*timeexactly4480sec.*/
The three static variables corr1, corr2, and corr3 are used to
keep track of the number of times the several different loops in the
algorithmareexecuted.Cwillalwaysinitializethesevariablestozero
andthentheirvaluewillberetainedfromcalltocallofthefunction.
16-bitTimers
The multifunction timer discussed in the previous section pro-
videsforimplementationofrelativelysimpletimingfunctions.Lets
assume that the microcontroller clock frequency is 4.0 MHz. The
fastestinterrupttimewiththissystemis0.512milliseconds,andthe
granularityoftheinterrupttimesisinlarge,power-of-twoblocksfor
theRTIsystem.Also,therelationoftheinterrupttimestounityis
not clean; complicated algorithms or special frequency crystals
areneededtogetthedevicetorespondaccuratelyinseconds.
Oftenmicrocontrollerapplicationsmustprovidemorethanone
time function.The 15-bit timer is set up to provide only one time
base.Ofcourse,aprogrammercanprogramthetimertocontrolmany
different functions and at many different times. The limits on the
functionsandtimesaredifficulttodetermine.Itisclearthatthefast-
estpracticaltimebaseinthe15-bittimeris0.512milliseconds.To
obtainanyfinertimeresolution,theprogrammerwouldhavetocom-
paretheTCRbitstoaspecifiedvalueonacycle-by-cyclebasis.This
typeofprogramcompletelyconsumesthemicrocontrollerandleaves
noprocessingtimeforotherfunctionsduringtheexecutionofthe
timingprogram.Ifthetimebasemustbeotherthansomemultipleof
0.512millisecondsandnotoneofthestandardRTItimes,thepro-
cessorcanprobablyserviceonlyonetimefunction.Iftherequired
timescanfallontheabovevalues,theprocessorcanexecuteseveral
time-basedfunctionslimitedbythetotaltimerequiredtoexecutethe
functionsandthemicrocomputerinterruptlatencytime.
The16-bittimeraddressestheseproblems.Ablockdiagramofthis
type of timer is shown in Figure 4-2.This style of timer contains an
internal 16-bit counter that is clocked at some fraction of the
Timers 179
MC68HC05B6InternalBus
ICF1 TDF OCF1 ICF2 OCF2
Internal
Processor
Clock
8-bit
Buffer
4
Counter
Alternate
Register
Output
Compare
Register1
Output
Compare
Register2
Input
Capture
Register1
Input
Capture
Register2
Output
Compare
Circuit1
Output
Compare
Circuit2
Edge
Detect
Circuit1
Edge
Detect
Circuit2
TCAP2
Pin
TCAP1
Pin
TCMP2
Pin
TCMP1
Pin
D
Q
C
Latch
Latch
D
C
Q
Timer
Control
Register
$12
Timer
Status
Register
$13
7
6
5
4
3
ToPLM
InternalTimerBus
High
Byte
Low
Byte
High
Byte
Low
Byte
High
Byte
Low
Byte
High
Byte
Low
Byte
High
Byte
Low
Byte
$18
$19
$16
$17
$1E
$1F
$14
$15
$1C
$1D
$1A
$1B
Overflow
Detect
Circuit
16-bit
FreeRunning
Counter
OLVL1 IEDG1 OLVL2 FOLV1 FOLV2 TOIE OCIE ICIE
Input Output Overflow
Capture Compare Interrupt
Figure4-2:
Interrupt Interrupt $1FF4.5
$1FF8.9 $1FF6.7 16-BitTimerForTheM68HC05B6
180 Chapter4 Small 8-Bit Systems
microcontroller crystal frequency.An input capture operation de-
tects the occurrence of an input and transfers the contents of the
16-bitcounterintotheinputcaptureregister.Thistransferwillal-
wayssetaflag,anditcancauseaCPUinterruptifdesired.Withan
inputcapturesystem,precisemeasurementoftimeintervalispos-
sible.Detailssuchasphasebetweentwowaveformscanbedetermined
orslightdifferencesinfrequenciesbetweenseveralsignalscanbe
detected. The input capture provides far more accurate time mea-
surement than can be obtained with either synchronous polling or
asynchronousinterrupttimemeasurements.Thereisatinyinherent
delaybetweentheoccurrenceoftheinputandthesettingoftheinput
captureregister.Suchameasurementmadebypollinganinputwould
require that the computer have a free running counter available to
interrogate when the input is detected. Then, the computer would
havetobeassignedtotallytothejobofwatchingtheinputforthe
impendingtransition.Whenthetransitionisdetected,thevalueof
thecounterwouldhavetobereadtodeterminethetimeofthetran-
sition.Ofcourse,thissequenceofoperationswouldrequireseveral
computerclockcyclespertest,andalsoseveralcycleswouldbere-
quired to read the counter. Therefore, the accuracy of the time
measurementwouldbecompromisedbythesenecessarytimedelays.
Anasynchronousinterruptmethodtodeterminethetimeinter-
valisbetterthanapolledmethod,buteventhismethodhasbuilt-in
errorsthatmakeitanimpracticalmeanstomeasuretimeintervals
accurately.Theinputcaptureregisterinputsystemresolvesmostof
the problems associated with accurate measurement of time inter-
valswithamicrocomputer.
Another type of timing problem exists. Suppose that the time
thataneventistooccurhasbeencalculated.Ifthetimeofoccur-
renceistobeaccurate,wehaveasituationlikethatdiscussedabove.
Theprocessorwillhavetospendallofitstimewatchingtheclockto
determinewhenthecorrecttimehasarrived.Anytimespentonother
tasksduringthismeasurementintervalwillbealatencyduringwhich
theprocessorcannotdetermineifthespecifiedtimehasarrived.In
thiscase,theaccuracyoftheeventtimewillbedegradedbythetime
spentonothertasks.
The16-bittimeravoidsthistypeofproblemnicely.Anoutput
comparesystemisused.Thetimeofoccurrenceiscalculatedrela-
Timers 181
tivetotheinternal16-bitcounter.Thisvalueisplacedintoanoutput
compareregister.Thecontentofthecounteriscomparedautomati-
callybythemicrocontrollertothevalueintheoutputcompareregister
ateachcountofthecounter.Whenthetwovaluesareequal,aflagis
set, an output occurs, and if desired, the CPU is interrupted. The
outputcomparesystemcanbeusedtogeneratewaveforms,tocon-
trolphasesbetweendifferentwaveforms,tocontroleventsbasedon
calculatedtimes.
Differentmicrocontrollerswillhavedifferingnumbersofinput
captureandoutputcompareregisters.Inthediscussionsthatfollow,
detailsofasingleinputcaptureandoutputcompareregisterwillbe
discussed. It is assumed that these registers are part of an
M68HC05B6,sotherearetwoinputcapturesandtwooutputcom-
pares onthe microcontroller. For details on access to the second
registerset,refertotheappropriatedatamanual.Laterwewillsee
microcontrollersthathavemanymoreinputcaptureandoutputcom-
paresystems(upto16ononemicrocontroller).
TimerControlRegister
Thetimercontrolregister(TCR)islocatedattheaddress0x12.
This read/write register controls the operation of the 16-bit timer
system.Shownbelowisadiagramofthisregister,andalistingofthe
functionsofthevariousregisterbits.
TCR
0x12
Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0
IEDG1 ICIE OCIE OLVI1 TOIE FOLV1 FOLV2 CLVL2
OLVL1 Bit0 Output Level 1.The contents of this bit will be
copiedtotheoutputlevellatchthenexttimean
outputcompareoccurs.Thisresultwillappearat
TCMP1. This bit and the output level latch are
clearedwhenthepartisreset.
IEDG1 Bit1 Input Edge 1.This bit determines the transition
directionthatwillcauseaninputtooccuronIn-
putCapture1:
IEDG1=0FallingEdge
IEDG1=1RisingEdge
Thecontentsofthisbitareundeterminedandun-
affectedatreset.
182 Chapter4 Small 8-Bit Systems
OLVL2 Bit2 Output Level 2.The contents of this bit will be
copiedtotheoutputlevellatchthenexttimean
outputcompareoccurs.Thisresultwillappearat
TCMP2. This bit and the output level latch are
clearedwhenthepartisreset.
FOLV1 Bit3 ForcedOutputCompare1.Thisbitalwaysreads
zero.Aonewrittentothispositionwillforcethe
OLVL1bittobecopiedtotheoutputlevellatch.
ThisresultwillappearatTCMP1.Aforcedout-
putcomparedoesnotaffecttheOCF1bitinthe
timerstatusregister.Thisbitisclearedatreset.
FOLV2 Bit4 ForcedOutputCompare2.Thisbitalwaysreads
zero.Aonewrittentothispositionwillforcethe
OLVL2bittobecopiedtotheoutputlevellatch.
ThisresultwillappearatTCMP2.Aforcedout-
putcomparedoesnotaffecttheOCF2bitinthe
timerstatusregister.Thisbitisclearedatreset.
TOIE Bit5 TimerOverflowInterruptEnable.IftheTOIEisset,
thetimeroverflowinterruptisenabledandaninter-
ruptwilloccurwhentheTOFflagissetinthetimer
statusregister.Thisbitisclearedatresetandthein-
terruptisinhibited.
OCIE Bit6 OutputCompareInterruptEnable.IftheOCIEbit
isset,theoutputcompareinterruptisenabled,and
aninterruptwilloccurwhenevereithertheOCF1
ortheOCF2issetinthetimerstatusregister.This
bitisclearedatresetandtheresetisinhibited.
ICIE Bit7 InputCaptureInterruptEnable.IftheICIEbitis
set,theinputcompareinterruptisenabledandan
interruptwilloccurwhenevereithertheICF1or
theICF2issetinthetimerstatusregister.This
bitisclearedatresetandtheresetisinhibited.
TimerStatusRegister
ThisregisterTSRisan8-bitregister.Themostsignificant5
bitsofthisregistercontainreadonlystatusinformation.Thesebits
describetheconditionofthe16-bittimersystem.Theirfunctionsare
outlinedbelow:
Timers 183
TSR
0x13
Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0
ICF2 OCF2 ICF1 OCF1 TOV
OCF2 Bit3 OutputCompareFlag2.Thisbitissetwhenthe
content of the free-running counter matches the
contents of output compare register 2. OCF2 is
cleared by accessing the TSR (specifically the
OCF2)followedbyanaccesstothelowbyteof
the output compare register 2, 0x1f.The output
compareflag2isundeterminedatpoweronand
isunaffectedbyreset.
ICF2 Bit4 InputCaptureFlag.Thisbitissetwhenanega-
tiveedgeissensedatTCAP2.Itisclearedbyan
accessofthetimerstatusregisterfollowedbyan
accessofthelowbyteoftheinputcaptureregis-
ter,0x1d.Theinputcapture2flagisundetermined
atpoweronandisunaffectedbyreset.
TOF Bit5 TimerOverflowBit.Thisbitissetbyatransition
of the free-running counter from a 0xffff to a
0x0000.ItisclearedbyaccessingtheTSRwiththe
TOFsetfollowedbyanaccessofthefree-running
counter low byte, 0x19. The TOF bit is undeter-
minedatpoweronandisunaffectedbyreset.
OCF1 Bit6 OutputCompareFlag1.Thisbitissetwhenthe
content of the free-running counter matches the
contents of output compare register 1. OCF2 is
cleared by accessing the TSR (specifically the
OCF1)followedbyanaccesstothelowbyteofthe
outputcompareregister1,0x17.Theoutputcom-
pare flag 1 is undetermined at power on and is
unaffectedbyreset.
ICF1 Bit7 Input Capture Flag 1. This bit is set when the
properedgeissensedatTCAP1.Theedgeisse-
lectedbytheIEDG1bitintheTCR.Itiscleared
byanaccessofthetimerstatusregisterfollowed
byanaccessofthelowbyteoftheinputcapture
register,0x15.Theinputcapture1flagisunde-
terminedatpoweronandisunaffectedbyreset.
184 Chapter4 Small 8-Bit Systems
ToclearbitsintheTSR,theprogrammustfirstaccesstheTSR
followedbyanaccessoftheLSBoftheregisterassociatedwiththebit
thatmustberesetintheTSR.Thissequencecanleadtoproblemsin
dealingwiththecounterregister.Supposeyouareattemptingtomea-
sureanelapsedtimeandarereadingthecounterregisteratrandom
timesandyoualsowillreadtheTSRtoservicetimerrequirements.It
is possible in these circumstances to accidentally reset the TOF bit
whenitisundesired.Toavoidthisproblem,analternatecounterregis-
terhasbeendesignedintotheM68HC05devices.Thealternateregister
alwayscontainsthesamevaluesastheprimeregister,buttheTOFbit
intheTSRisnotresetwhenthealternateregisterisread.
CounterRegister
Thecounterregisterisfoundinthememorylocations0x18and
0x19.Theleastsignificantbyteofthecounterisin0x19.Analter-
natecounterregisterisfoundinaddresses0x1aand0x1bwith0x1b
being the least significant byte of this register.These registers are
clocked at the same time and are incremented from low values to
highervalues.Thecountersareclockedatone-fourthoftheinternal
processorclock,whichinturnisone-halftheoscillatorfrequency.
Theclockingfrequencyisone-eighththecrystalfrequency,andthe
clockingperiodis2microsecondswhenthecrystalfrequencyis4
MHz.TheseratiosarenotadjustableintheM68HC05B6.
Thefree-runningcountervaluescanbereadatanytime.Aread
sequence that reads only the least significant byte will receive the
count value at the time of the read. If the most significant byte of
eithercounterisread,thecountvaluewillbereceivedandthecon-
tentsoftheleastsignificantbytewillbetransferredtoabuffer.This
valuewillremaininthebufferuntiltheprogramreadsthecontents
oftheleastsignificantbyteoftheregister.Thevaluereceivedforthis
readisthebufferedvaluesavedwhenthemostsignificantbytewas
read.Themostsignificantbyte,MSB,canbereadseveraltimesprior
to reading the least significant byte, LSB, and the contents of the
bufferwillremainunchanged.AftertheMSBhasbeenreadandthe
LSB has been buffered, the free-running counter continues to be
incremented at its normal rate. If the MSB/LSB read sequence is
started,itisnecessarytoreadtheLSBtocompletethesequence.
The counter is 16 bits, and when the register overflows from
Timers 185
0xffffto0x0000,thetimeroverflow(TOF)bitisset.Thiseventcan
causeaninterruptiftheTOIEbitisset.Sincetheregisterisclocked
at2microseconds,theintervalbetweenTOFis0.131072seconds.
InputCaptureRegisters
There are two input capture registers called ICR1 and ICR2.
ICR1isfoundataddresses0x14and0x15,andICR2islocatedat
addresses0x1cand0x1d.TheloweraddressalwayscontainstheMSB
ofa16-bitnumber.Withtheexceptionoftheedgedetectionsystem
discussedintheTCRsection,thesetworegistersoperatethesame.
ICR1canbesettorespondtoeitherarisingedgeorafallingedge
on the timer compare input pin TCAP1. If IEDG1 is 0, ICR1 re-
spondstoafallingedgeonTCAP1.Otherwise,ifIEDG1 is1,ICR1
respondstoarisingedgeonTCAP1.ICR2respondsonlytoafall-
ingedgeonTCAP2.Aninterruptwillalsoaccompanyaninputcapture
ifthecorrespondingICIEbitissetintheTCR.
The contents of the free-running counter are transferred to the
inputcaptureregisterseachclockcycle.Therefore,theregisterscon-
tainavaluethatcorrespondstothemostrecentinputcapture.Aftera
read of the most significant byte of the input capture register, the
transferofnewdatatotheleastsignificantbyteoftheinputcapture
register is inhibited until this byte is read.At no time during this
sequenceisthecounterregisterinhibited.
OutputCompareRegisters
There are two output compare registers. OCR1 is found at ad-
dress locations 0x16 and 0x17 while OCR2 is located at 0x1e and
0x1f.Again the lower addresses contain the MSB of these 16-bit
numbers.Theseregistersmaybereadorwrittenatanytimeregard-
lessofthetimerhardware.Iftheoutputcomparefunctionsarenot
utilized,thesefourbytescanbeusedfordatastorage.Theircontents
arenotalteredatreset.Thereisonlyoneoutputcompareinterrupt
bitthatisusedforbothoutputcomparesinthesystem.
Thecontentsoftheoutputcompareregistersarecomparedwith
thecontentsofthecounterregistereachcycleofthecounterregister.
Ifamatchisfoundwitheitheroutputcompareregister,thecorre-
sponding output compare flagOCF1 or OCF2 bit is set.Also,
thevalueofproperoutputlevelbitOLVL1orOLVL2istrans-
186 Chapter4 Small 8-Bit Systems
ferredtotheproperoutputpin,TCMP1orTCMP2.IftheOCIEbitis
setinthetimercontrolregister,aninterruptwillaccompanytheout-
putcompare.
Therearetimeswhenitisdesirabletoforceanoutputcompare
from a program. The FOLV1 and FOLV2 bits can be used for this
purpose.Thesebitswillalwaysread0,butwritinga1tothesebitsin
theTCRwillcausetransferofthecorrespondingOLVL1orOLVL2bit
to the specified output compare bit, either TCMP1 or TCMP2. This
outputdoesnotaffectthecompareflags,sonointerruptisgenerated.
Programmingthe16-bitTimer
Wewillexamineseveraldifferentusesofthe16-bittimersystem
inthissection.Thefirstismerelyarepeatofthesimpletimerpro-
grammedinthesectiononthe15-bitsystem.Herewemerelywant
tokeeptrackoftime,hours,minutes,andsecondsinmemory.No
provisionsaremadeyetforreadingthetimevaluesortochangethe
values;theseproblemswillbediscussedlater.
Alistingofthisprogramisshownbelow.Inthiscase,theheader
filefortheM68HC05B6isused.Alistingofthisfileisfoundonthe
CD-ROM.Thisprogramwillmakeuseofanoutputcomparetogen-
erateperiodicinterruptstothemicrocontroller.Wewilluseoutput
compare register 1. It will be set up so that when the first output
compareinterruptoccurs,thecontentsoftheoutputcompareregis-
terwillbeincrementedby500.Sincetheclockingtimeofthecounter
registeris2microseconds,5002-microsecondperiodswillallowan
outputcompareevery1millisecond.Thisoccurrencewillbetreated
intheinterruptserviceroutine.
#includehc05b6.h
inthrs,mts,sec;/*globalvariables*/
longcount=1000;
structbothbytes/*16bitintstructure*/
{
inthi;
intlo;
};
Timers 187
unionboth/*andunion*/
{
longl;
structbothbytesb;
};
unionbothtime_count;
registeraac;
main()
{
TCR.OCIE=1;/*enableoutputcompareinterrupt*/
CLI();/*enableallinterrupts*/
FOREVER
{
if(sec>59)/*doclockthingseachminute*/
{
sec=0;
if(++mts>59)
{
mts=0;
if(++hrs>12)
hrs=1;
}
}
WAIT();
}
}
void__TIMER_OC(void)/*timeinterruptservice
routine*/
{
if(TSR.OCF2==1)/*isthisinterruptduetoOC2?*/
{
ac=OCLO2; /*Yes.readOCLO2todisable*/
return; /*theinterruptandexit*/
} /*theroutine*/
188 Chapter4 Small 8-Bit Systems
/*theprogramgetshereeverymillisecond*/
time_count.b.hi=OCHI1;
ac=TSR;/*ArmOCF1bitclear*/
time_count.b.lo=OCLO1;/*ClearOCF1bit*/
time_count.l+=500;/*500countsperms*/
OCHI1=time_count.b.hi;
OCLO1=time_count.b.lo;
if(--count==0)
return;
else
{
sec++;/*hereeverysecond*/
count=1000;/*resetcountto1second*/
}
}
Listing4-4:TimerUsingOutputCompares
The listing shows that microcontroller executing programs are
brokenintothreedistinctsections.Thefirstsectionisreferredtoas
theinitializationsection.Inthiscase,theinitializationsectionisthe
firsttwolinesfollowingthemain()invocation.Intheinitialization
section,thecodeexecutedsetsuptheoperationofthemicrocontroller.
Generally,thiscodeisexecutedonlyonce.Therefore,initialization
ofvolatilememoryvalues,settingupofinterrupts,establishmentof
I/Oportsanddatadirectionregistersareallcompletedintheinitial-
izationoftheprogram.Unlessthereisapressingreason,themain
systeminterruptsshouldnotbeenabledduringinitialization.
Thesecondsectionistheapplicationssection.Theapplications
sectionisusuallyaloopthatcontainsallofthecodetobehandled
routinelybythemicrocontroller.Allinputoroutputoperationsshould
takeplacewithintheapplicationssection.
Thethirdsectionoftheprogramisthecollectionofinterruptservice
routines(asynchronousservicesection).Theseroutinesarecalledwhen
appropriateinterruptsaregenerated.Ingeneral,interruptservicerou-
tinesshouldbeshortanddoaslittleaspossibletoservicethespecified
interrupt. When an interrupt is serviced, the status register of the
microcontrollerissavedandthesysteminterruptisdisabled.Therefore,
unlesstheprogrammertakesspecialcaretore-enabletheinterrupts,no
Timers 189
otherinterruptcanbeservicedwhilethemicrocontrollerisexecutingan
interruptserviceroutine.Thisoperationdoesnotleadtomissedinter-
rupts,butitcancauseaninordinatedelayinserviceofaninterrupt.
Insomecases,itispossiblethatdatamightbelostifaninterrupt
isnothandledexpeditiously.Forexample,ahigh-speedserialport
mightnotifythemicrocontrollerthatitsreceivingdatabufferisfull
byaninterruptwhentheinterruptisdisabled.Insuchacase,ifthe
interruptserviceroutinebeingexecutedisnotcompletedbeforethe
nextserialdataarereceived,thedatainthebufferwillbelost.
Sometimesitisnecessarytopassdatabetweentheapplications
portionoftheprogramandtheinterruptserviceroutine.Thesedata
canbestoredinglobalmemory,andbothroutinescanaccessthem.
Hereisacasewhereyoumustexaminetheassemblycodegenerated
bythecompilertomakecertainthatnoproblemswillbegenerated
inpassingofdatabetweentheseroutines.Problemscanbecreated
bypassinginformationthisway,buttheycanbeavoidedifthepro-
gramrigorouslyavoidsloadingdatathatischangedinaninterrupt
serviceroutineintoaregisterintheapplicationsectionofthepro-
gram.Wewillseeinstancesofthisproblemlater.
IfyougobacktoListing4-4,youllseethattheprogramorgani-
zationdiscussedaboveisalsoused.Thisorganizationwillbefound
foreveryprograminthisbook.Wewillrefertotheinitialization,the
applications,andtheasynchronousservicesectionsoftheprogram.
Thisarrangementworksquitewell,andisreliable.Thereshouldbe
astrongjustificationifalternateprogramformsaretobeused.
Whenprogrammingthe15-bittimer,wefoundthataskingacom-
piler designed specifically for an 8-bit machine to work in 16-bit
quantitiesoftencreatedunwieldycode.Aprogrammer,however,does
notalwayshavethefreedomtoworkwith8-bitquantitiesonly.Allof
thetimeregistersinthissystemare16bitswide,andthetimevalues
containedintheseregistersmustbeprocessed.Theseregistersareal-
wayslocatedintwoadjacent8-bitmemorylocations.Onemethodfor
handlingthe8/16-bitdichotomyistouseaunion.Thecodesequence
structbothbytes
{
inthi;
intlo;
};
190 Chapter4 Small 8-Bit Systems
creates a structure that contains two bytes. This structure is com-
binedwithatypelongintheunionbelow.Rememberthataunion
providesspacetoholditslargestmemberandthedifferentmembers
oftheunionwilloccupythesamememoryspace.Therefore,the
memory space to store the longl is the exact same memory to
storethestructureb.b.hiwilloccupythemostsignificantbyteof
l,andb.lowilloccupytheleastsignificantbyteofl.Itisnoweasy
todealwiththebytesofthe16-bitquantitywhenmovingthedata
around,andequallyeasytoinvoke16-bitarithmeticoperationson
thelongcombinationofthetwobytes.
unionboth
{
longl;
structbothbytesb;
};
Thestatement
unionbothtime_count;
declaresthattime_countisaunionofthetypeboth.Inthein-
terruptserviceroutine,themembersoftime_countarehandled
withlittledifficulty,asshownbelow.
The type registera defined as ac above is unique to the
M68HC05compiler.Thistypespecifiesthatthevariableacwillbe
storedintheaccumulator.Thereisalsoaregisterxtypeforthe
indexregister.
In the main program, the output compare interrupt is enabled
and the system interrupt is enabled with theCLI() instruction in
theinitializationsection.Theprogramthenentersanendlessloopin
whichtheclockisservicedeverytimesecbecomes60.Theparam-
etersecwillbechangedbytheinterruptserviceroutineeverysecond
so that the system should be a satisfactory clock. This loop is the
initializationsection.
ThelastinstructionintheFOREVERloopisaWAIT()instruc-
tion.Thisinstructionplacestheprocessorintothewaitmode.Inthis
mode, processor operations are halted and the microcontroller op-
erationisconfiguredtoreduceenergyconsumption.Theoperation
oftheinternaltimersproceedasusual.Thepartisremovedfromthe
wait mode by either a reset or the occurrence of an interrupt.The
Timers 191
interruptcanbeeitheraninternaloranexternalinterrupt.Sincethe
outputcomparetimerissetupanditsinterruptisenabled,whenthe
internalcountermatchesthecontentsoftheoutputcompareregister,
aninterruptwilloccurandremovetheprocessorfromthewaitmode.
Sometimes,itisdesirabletogetameasureofthefractionofthe
timethatthemicrocontrollerisusedtoexecuteitsprogram.Theuse
ofthewaitmodeprovidesanexcellentmechanismformeasurement
ofthisusage.Ifthereisanextraoutputportpinavailable,thispin
canbesetjustpriortoenteringthewaitmode.Thepincanthenbe
resetasthefirstinstructionintheinterruptserviceroutine.Tomake
thismeasurementmoreaccurate,youcansetanotheroutputpinto
theonconditionallofthetime.Measurethesetwooutputswithan
averagingDCvoltmeter.Onehundredtimestheratioofthecycling
output to the fixed output is the percentage of time that the
microcontrollerisavailabletoexecuteothercode.
Examinethefollowingcodesequence:
time_count.b.hi=OCHI1;
ac=TSR;/*ArmOCF1bitclear*/
time_count.b.lo=OCLO1;/*ClearOCF1bit*/
time_count.l+=500;/*500countspermillisecond*/
OCHI1=time_count.b.hi;
OCLO1=time_count.b.lo;
Thefirstinstructioncopiesthehighbyteoftheoutputcompare
registerintothehighbyteofthestructurebintheuniontime_count.
WhentheTSRiscopiedintothearegister,thesystemissetuptoclear
the OCF1 bit. Then, the low byte of the output compare register is
movedintothelowbyteofthestructureb.Theseoperationsleavethe
16-bit contents of the output compare register in the union
time_count.l.NotethatthehighbyteismovedfromOCHI1,the
TSRisaccessed,andthenthelowbyteismovedfromOCLO1.This
sequence,accessingOCLO1aftertheTSRhasbeenaccessedwillclear
the output compare flag 1, OCF1, and remove the interrupt source.
500isaddedtothis16-bitnumber,andtheresultiscopiedbackinto
theoutputcompareregister1abyteatatime.
Whileitisusuallybesttokeeptheinterruptserviceroutinesshort,
sometimesotheroperationscanbecompletedwithintheseroutines
thatcanbeuseful.RecallthatintheEEPROMprogrammingroutine
192 Chapter4 Small 8-Bit Systems
therewasafunctioncalleddelay.Adelayfunctioncanbeintegrated
intoatimeinterruptserviceroutineeasily.Theinterruptservicerou-
tineaboveisenteredeverymillisecond.Wespecifiedafunctiondelay
thathadanunsignedlongargumentthatcorrespondstotherequired
delayinmilliseconds.Suchafunctioncouldbeimplementedas:
voiddelay(unsignedlong);
unsignedlongtime=0;
voiddelay(unsignedlongdel)
{
time=del;/*placethedelaytimeintheglobal
memory*/
while(time>0);
}
Nowwemustaddonecodesequencetotheinterruptserviceroutine
above:
if(--count==0)
{
if(time>0)
--time;
return;
}
Thefunctiondelay()placesthevalueoftherequireddelayin
theunsignedlonglocationtime.Theprogramthenhangsonthe
whilestatementsolongastimeisgreaterthan0.Everytimethe
ISRisenteredwhichiseverymillisecondthelongunsigned
valuetimewillbedecremented.Whenthepropertimehaspassed,
thedelay()functionwillreturntothecallingprogram.
Thefunctiondelay()doessomethingthatmanyprogrammers
donotlike:theprogramhangsinaloopuntilaspecifiedtimehas
passed. This operation may seem to waste the microcontroller re-
source. Note, however, that the program does not spend all of the
timeintheloop;interruptsarebeingservicedduringthistime.We
willseethatthetimerinterruptisonlyoneofmanypotentialinter-
ruptsthatwillbeworkingonthepartatalltimes.Placingthedevice
intoawaitloopforafewmillisecondsmaystopthemainprogramin
Timers 193
itstracks,butthebackgroundoperationsbeingservicedbytheinter-
ruptswillcontinuetobeprocessedunhindered.Inthiscase,aglobal
variablehasbeenusedtotransferdatabetweenaninterruptservice
routine and the applications portion of the program. The variable
time is set in the applications program, and the completion of the
timedelayisevaluatedintheapplicationsportionoftheprogram,
andtimeitselfisdecrementedintheinterruptserviceroutine.
Itispossibletocreateerrorsinoperationwiththistypeofproce-
dure.Oneplacewhereanastybugcancreepintoyourcodeiswhen
youaredealingwithbitmanipulationsinboththeapplicationpor-
tionoftheprogramandtheinterruptserviceroutine.Supposethat
youwanttotoggleabitwhenaneventwasdetectedintheapplica-
tion, and simultaneously you need a periodic bit toggle that is
controlledbycodeintheinterruptserviceroutine.Thecodesequence
mightappearasfollows:
.
.
PORTA.BITAPP=!PORTA.BITAPP;
.
.
Intheinterruptserviceroutine,thecodecouldbe
.
.
PORTA.BITINT=!PORTA.BITINT;
Ineachcase,thiscodewillcompileinto
ldaPORTA
eor2^BITNUMBER
staPORTA
Thesamecodesequencewillappearinboththeapplicationand
theinterruptserviceroutinewiththeBITNUMBERappropriatelycho-
sen.Supposethatweareintheapplication,andhavejustexecuted
theldaPORTAinstructionwhentheinterruptoccurs.Intheinter-
ruptserviceroutine,theabovecodewillbeexecutedproperly,and
whencontrolisreturnedtotheprogrammainline,itwillcontinue
withtheeorinstruction.However,thecontentsofPORTAwillhave
194 Chapter4 Small 8-Bit Systems
beenchangedbytheinterruptserviceroutine,sothevaluethatwas
loadedbytheldainstructionpriortotheinterruptisnolongervalid.
The earlier loaded value of PORTA will be restored by the above
sequenceintheapplicationcode,andthechangemadeintheinter-
ruptserviceroutinewillbeundone.
Thisbitofinterplaybetweentheapplicationsprogramandthe
interruptserviceroutineisatypeofsoftwarerace.Itcanbeeasily
avoided. Whenever a variable is changed in both the applications
code and in an ISR, the erroneous set/reset can be avoided if the
program disables all interrupts before the offending instruction in
theapplicationscode.Theinterruptsmustthenbere-enabledafter
thecodeexecution.Inthiscase,thecodewillbe


SEI();
PORTA.BITABB=!PORTA.BITAPP;
CLI();


in the applications code. In this case, there can be no interrupt to
interferewiththeproperhandlingofPORTAintheapplication.
Inthetimerroutineabove,thereiswhatsomemightcallaglaring
oversight.Thetimerwasnotinitializedintheinitializingroutineof
theprogram.Thefirstlinesofcodemerelyenabledthetimerinterrupt
andthenproceededintotheFOREVERloop,whichistheapplications
portionoftheprogram.TheinitialstateoftheTCRandtheOCRregis-
tersisnotestablishedatreset.Thereisnowayofknowingwhenthe
first output compare will take place. If the initial value of the OCR
happenstobeonelessthanthatoftheTCR,therewillbeanoutput
compareabout0.13secondsaftertheinterruptsareenabled,andfrom
thenontheinterruptperiodwillbeaccurate.Ifitisimperativethatthe
firstoutputcompareoccuratexactlythespecifiedtime,thenthecode
forinitializationoftheoutputcompareregistersmustbeincludedin
theinitializationroutine.Otherwise,ifthiserrorintheinitialtiming
canbetolerated,itwillsavebytesofcodespacethatmightbedesper-
atelyneededforanotherportionoftheprogram.
Analog-to-Digital Converter Operation 195
EXERCISES
1.Writeaprogramthatusesanoutputcomparesystemtogenerate
anaccuratewaveformwitha1000.0secondperiod.
2.Devise a convenient method to test the performance of the pro-
graminExercise1above.
3.Writeaprogramtogeneratetwowaveforms.Oneoutputistobeat
twicethefrequencyoftheother.Thedutyfactorsofthetwosig-
nalsaretobeequalto50%.Thefrequencyoftheslowestwaveis
tobe1000Hz.Thephaseofthehigherfrequencysignalistobe
suchthatitsrisingedgeistooccur260microsecondsfollowing
therisingedgeofthefirstsignal.
4.TwoDCmotorsarerunning.Eachmotorhasanopticalinterrupter
onitsshaftwith15interruptsperrevolutionoftheshaft.Allbutone
oftheinterruptsoccupyone-sixteenthofthecircumferenceofthe
rotation.Thefifteenthinterruptoccupiesone-eighthofthecircum-
ference.Usinginputcaptureregisters,measurethespeedofthetwo
motors,andprovideaslowdownorspeedupsignalthatcanbeused
oneithermotortosynchronizetherotationofthetwomotorswith
thewideinterrupterpositionsontheshaftsbeinginlock-step.
5.Whatmicrocontrollercharacteristicswillcontrolthemaximumspeed
atwhichthemotorsinExercise4canrun?Theminimumspeed?
Analog-to-Digital Converter Operation
Theanalog-to-digitalconverter(ADC)foundontheM68HC05
familyismoderatelysimpleinitsoperation.Thereareafewimpor-
tant items that must be remembered when dealing with the ADC.
MostimportantisthattheADCmustbeturnedonforatleast100
microsecondspriortoreadingavalue.If100microsecondshasnot
elapsed,itisguaranteedthatthevaluereadwillbeinerror.TheADC
isturnedonbysettingtheADONbitintheADCcontrol/statusregis-
ter. This register is referred to as AD_CTST. The following code
sequencewillturntheADCon:
AD_CTST=0;
AD_CTST.ADON=1;
196 Chapter4 Small 8-Bit Systems
Thefollowingfunctionwillprovideareadingofasinglechannelof
theADCinput:
unsignedintread_adc(intk)
{
AD_CTST&=~0X7;
AD_CTST|=k;
while(AD_CTST.COCO==0)
;/*waitheretilCOCOisset*/
returnAD_DATA;
}
Theargumentkisthechannelthatistoberead,andkcanhave
avalueof0to7toreadtheexternalchannels.
Thefirsttwolinesofcodeintheabovefunctionwillplacethe
channelnumbertobereadinthechannelbitsofAD_CTST.These
bitsmustbeclearedbyaninstructionsequencethatwillnotalterthe
upperbitsofAD_CTSTbecausetheADONbitisintheupperportion
of AD_CTST.This bit cannot be reset while the ADC operation is
continuing. The first line of code clears the least significant three
bits,andthesecondlineplacesthechannelnumberinthesebits.
WritingtoAD_CTSTwillcausetheADCconversiontostart.There-
fore,allthatmustbedoneistowaituntiltheconversioniscompleted
toreadthedataintotheprogram.Thecode
while(AD_CTST.COCO==0)
;/*waitheretilCOCOisset*/
willkeepcontrolofthemicrocontrollerinthatinstructionsequence
untiltheCOCObit,whichistheconversioncompletionbit,isset.At
thattimethevaluefoundinAD_DATAwillbetheresultofthelatest
conversion.
Often,theADCresultsmustbesubjectedtosomeprocessingto
removeunwantedcharacteristicsofthesignalbeingmeasured.Here
is a case where careful use of assembly language procedures can
makeabigdifferenceintheexecutionspeedaswellastheamountof
code needed.An example that is often used is to average the past
valuesofthedata.Areasonablysimpleapproachistoallowthelat-
estADCreadingtohavea50%weightandallofthepastreadingsto
have a 50% weight. The following example code will accomplish
thistaskinthreedifferentways:
Analog-to-Digital Converter Operation 197
#includehc05b6.h
unsignedadc_data[8];
unsignedread_adc(int);
main()
{
unsignedintj;
AD_CTST=0;
AD_CTST.ADON=1;
for(j=0;j<8;j++)
{
adc_data[j]=(read_adc(j)+adc_data[j])/2;
adc_data[j]>>=1;
adc_data[j]+=read_adc(j)>>1;
#asm
ldxj
ldaj
jsrread_adc
addadc_data,x
rora
staadc_data,x
#endasm
}
}
Listing4-5:ThreeDifferentADCAveragingRoutines
The first attempt to read and average the data approaches the
problemassimpleaspractical.ThedataarereadinfromtheADC,
addedtothecorrespondingstoreddatainthearrayadc_data,the
resultisdividedbytwo,andthefinalaverageisputbackintothe
properlocationinthearray.Thefollowinglineofcodeisallthatis
necessarytoaccomplishthistask:
198 Chapter4 Small 8-Bit Systems
adc_data[j]=(read_adc(j)+adc_data[j])/2;
Hidden in this code is the fact that both read_adc and
adc_dataareunsignedresults.Whentwounsignednumbersare
addedtogether,themostsignificantbitofeachcanbe1sotherecan
beacarryoroverflowwhentheadditiontakesplace.Problemsfrom
this carry can be avoided in this case by merely using a long or
double precision add routine in adding the two numbers. Then,
whentheresultisdividedby2,ifabitiscarriedintotheupperbyte
oftheresultitwillbeshiftedbackintothelowerbyte.Theresultof
thisoperationiscorrectandwillfitintoasingleunsignedint.
Thecompiledversionoftheaboveprogramwithread_adc()
mergedintoitfollows:
#includehc05b6.h
00500008 unsignedadc_data[8];
unsignedread_adc(int);
voidmain(void)
{
0058 unsignedintj;
01003F09CLR$09 AD_CTST=0;
01021A09BSET5,$09 AD_CTST.ADON=1;
01043F58CLR$58 for(j=0;j<8;j++)
0106B658LDA$58
0108A108CMP#$08
010A2436BCC$0142
{
010CCD0143JSR$0143 adc_data[j]=(read_adc(j)+
adc_data[j])/2;
010FBE58LDX$58
0111EB50ADD$50,X
0113AE02LDX#$02
0115CD0157JSR$0157
01189F TXA
0119BE58LDX$58
011BE750STA$50,X
153
Analog-to-Digital Converter Operation 199
011DBE58LDX$58adc_data[j]>>=1;
011FE650LDA$50,X
012144 LSRA
0122BE58LDX$58
0124E750STA$50,X
0126B658LDA$58adc_data[j]+=
read_adc(j)>>1;
0128CD0143JSR$0143
012B44 LSRA
012CBE58LDX$58
012EEB50ADD$50,X
0130E750STA$50,X
#asm
0132BE58ldxj
0134B658ldaj
0136CD0143jsrread_adc
0139EB50addadc_data,x
013B46 rora
013CE750staadc_data,x
#endasm
}
013E3C58INC$58
014020C4BRA$0106
014281 RTS }
unsignedintread_adc(intk)
0059 {
0143B759STA$59
0145B609LDA$09 AD_CTST&=~0X7;
0147A4F8AND#$F8
0149B709STA$09
014BB609LDA$09 AD_CTST|=k;
014DBA59ORA$59
014FB709STA$09
200 Chapter4 Small 8-Bit Systems
01510F09FDBRCLR7,$09,$0151
while(AD_CTST.COCO==0);
0154B608LDA$08 returnAD_DATA;
015681 RTS
}
0157BF5ASTX$5A
0159B75BSTA$5B
015B4F CLRA
015C5F CLRX
015D5C INCX
015E385BLSL$5B
016049 ROLA
0161B05ASUB$5A
01632403BCC$0168
0165BB5AADD$5A
016799 SEC
016859 ROLX
016924F3BCC$015E
016B53 COMX
016C81 RTS
1FFE0100
TheassemblycodetoexecutethissinglelineofCcodeisfoundin
the address range $10c to $11b, or 17 bytes of code. However,
thereisacalltothedoubleprecisionaddroutineataddress$115.
Thisroutineoccupiestheaddressrange$157to$16c,or22addi-
tional bytes of code hidden from the main routine.Therefore, this
requires37bytesofcodeforitsexecution.
Thenextapproachistoavoidtheoverflowproblembydividing
by2eachofthetermstobeaddedpriortotheaddition.Divisionby
2isaccomplishedbyshiftingeachofthetermstotherightbyone
bit.Thisapproachguaranteesthattherewillbenooverflowintothe
higherbytebecausethemostsignificantbitofeachnumberwillbe0
aftertheshift,andnobinaryadditioncancausemorethana1-bit
overflow.Therefore,thesumwillatmosthaveitsmostsignificant
bit turned on. This number is then stored in the location
adc_data[j].
PulseWidthModulatorSystem 201
Theassemblycodecreatedbythecompilerforthisapproachis
in the address range $11d to $130. This code uses 21 bytes of
memory.Carefulexaminationofthiscodewillshowthattheinstruc-
tionat$122isunneeded,sothecodecouldhavebeencompletedin
17bytes.
Theassemblyversionofthesameroutinemerelyaddsthetwo
unsignednumbers,andthenrotatestheresultright1bittoaccom-
plishthedivideby2.The1-bitrotateaccomplishesthesamethingas
arightshiftby1bitwiththeexceptionthatthecarrybitisshifted
intothemostsignificantbitoftheresult.Theonlywaythecarrybit
couldbesetisbythemostsignificantbitsofbothaddendsbeing1.
Theassemblyversionofthecoderesidesin$132to$13candre-
quires12bytesofcode.
Hereisacasewherejudiciouschoiceofassemblycodewill
provideasignificantimprovementintheamountofcodeneededto
executeaspecificprogram.Themainreasonthattheassemblyver-
sionisshorteristhatthecarrybitintheconditioncoderegisteris
availabletotheprogrammerfromassembly.Thisbitiscompletely
hiddenfromtheprogrammerinanyhigh-levellanguage.Therefore,
trickslikerotatingabitfromthecarryintoaregisterarenotavail-
ableinthehigh-levellanguage.
EXERCISE
1.Write a routine to average readings from the ADC on a
microcontroller,butweightthecurrentreadingthreetimesthatof
thepastaverage.
PulseWidthModulatorSystem
Inthissectiononprogrammingofthetimers,twoapproachesto
the generation of a pulse width modulation (PWM) signal will be
discussed.Theseapproachesbothusetheoutputcomparesystemof
the16-bittimer.
WhatisaPWMsystem?APWMsignalisaperiodicsignalwhere
thesignalissethighforacalculateddutyfactor,andthentheoutput
goes low for the remainder of the period. If you measure a PWM
signalwithanaveragingvoltmeteritwillhaveavalueequaltothe
peakvoltagetimesthedutyfactorofthePWM.Herethedutyfactor
isdefinedastheratiooftheontimetorepetitionperiodofthesignal.
202 Chapter4 Small 8-Bit Systems
Thus, we have created a simple digital-to-analog converter. Many
controlapplicationsneedanalogcontrolsignalsforpartsofthesys-
tem.PWMsystemsonmicrocontrollersprovideanexcellentmeans
for providing these analog voltages, so long as the limitations we
willdiscussbelowareacceptabletothetotalsystemdesign.
Thebuilt-inPWMsintheM68HC05Bxfamilyofdevicespro-
vide you with one of two pulse periods: the programmable timer
clockfrequencydividedby256or4096.Thesefrequenciesarefixed,
andtheintervalisdividedinto256parts.Therefore,theanalogfre-
quency rangesand the accuracy of the analog reproductionis
limitedtoonepartin256overtherangeoftheoutput.
WhenusingtheoutputcomparesystemtocreateaPWM,itis
possibletoachieveafineranalogresolutionatslowerfrequencies,
orperhapsafastersignalwithpooreraccuracy.APWMcreatedfrom
anoutputcomparesystemissomewhatmoreflexiblethantheusual
built-inPWM.WiththePWMsystemsbuiltaroundtheoutputcom-
paresystem,thecomputerisrespondingtofrequentinterrupts.When
aninterruptoccurs,thesystemstatusispushedontothestackandthe
address of the interrupt service routine is placed into the program
counter.Ittakesapproximately10clockcyclestorespondtoanin-
terruptafterthecompletionoftheexecutinginstruction.Returnfrom
aninterruptrequires9clockcycles.Therefore,itisnotpossibleto
accomplishthefullgoalofaPWMwithanoutputcomparesystem.
Thegoalinthiscaseistoachievefullonattheoneextremeinput
levelandfulloffattheother.Thetimesrequiredtoprocessaninter-
ruptwilllimittheperformanceatoneextreme,theotherorperhaps
bothwhenaPWMisimplementedwithanoutputcomparesystem.
A first example is shown in the following listing.This example
showstheinterruptserviceroutinealongwiththenecessarydefines
only.Itisassumedthattheoutputcompareinterruptbitalongwiththe
interruptbitareproperlysettoallowtheoutputcompare2tointerrupt
theprocessor.Alsoshowninthisexampleiscodetocontrolasecond
outputcompare1toprovidethesystemwithafixedtimebase.
Inoperation,theapplicationsportionoftheprogrammustplace
apairofcomplementarynumbers,pwm_number andoff_count,
inplace.Thesumofthesetwonumbersmustequalaconstantthat
establishestheperiodforthePWMsignal.FortheM68HC05B4,the
PulseWidthModulatorSystem 203
periodwillbe2microsecondstimesthetotalcountvalue.Priorto
startinguseofthePWM,thebitflag.ONshouldberesetandthe
valueforcount,whichisthemaintimebaseperiodcount,should
beset.
/*bitsinflag*/
#defineON0
unionbothtime_cnt;
unsignedlongoff_count,pwm_number,count;
bitsflag;
void__TIMER_OC(void)
{
if(TSR.OCF2==1)/*accessestheTSR*/
{
if(flag.ON==0)
{
flag.ON=1;
TCR.OLVL2=0;/*TimerCompare2off*/
time_cnt.b.hi=OCHI2;/*getstarttime*/
time_cnt.b.lo=OCLO2;/*resettheOCF*/
time_cnt.l+=pwm_number;
OCHI2=time_cnt.b.hi;
OCLO2=time_cnt.b.lo;
return;
}
else
{
flag.ON=0;
TCR.OLVL2=1;/*TimerCompare2toon*/
time_cnt.b.hi=OCHI2;/*getstarttime*/
time_cnt.b.lo=OCLO2;/*resettheOCF*/
time_cnt.l+=off_count;
OCHI2=time_cnt.b.hi;
OCLO2=time_cnt.b.lo;
return;
204 Chapter4 Small 8-Bit Systems
}
}
else/*mustbethatOCF1==1ratherthanOCF2
*/
{
time_cnt.b.hi=OCHI1;/*outputcompare*/
time_cnt.b.lo=OCLO1;/*getlobyte*/
time_cnt.l+=count;/*timeforinterrupt*/
OCHI1=time_cnt.b.hi;
OCLO1=time_cnt.b.lo;/*resettheOCF*/
ms_10++;
return;
}
}
Listing4-6:ISRForPWMSystem
Sincetheinterruptbitsaresettoallowoutputcompareinterrupts,
aninterruptwilloccur.Theinterruptserviceroutinewillbeentered,
andtheinstructionsequence
if(TSR.OCF2==1)/*accessestheTSR*/
{
.
.
.
accomplishestwothings.First,itdeterminesiftheoutputcompare2
causedtheinterrupt,and,secondly,itaccessestheTSRandarmsthe
resetoftheOCFXwhentheproperlowerbyteoftheoutputcompare
registerisreadlater.
Forthemoment,assumethatOCF2bitisset:theinterruptwas
causedbyacompareinoutputcompareregister2.Inthiscaseatest
ismadetodetermineifflag.ONisreset.Sincetheinitializationrou-
tineresetthisbit,itwillbe0.Therefore,thecodesequence
flag.ON=1;
TCR.OLVL2=0;/*TimerCompare2toturnoff*/
time_cnt.b.hi=OCHI2;/*getthestarttime*/
time_cnt.b.lo=OCLO2;/*resettheOCF*/
time_cnt.l+=pwm_number;
PulseWidthModulatorSystem 205
OCHI2=time_cnt.b.hi;
OCLO2=time_cnt.b.lo;
return;
willbeexecuted.ThiscodeistheoncodeforthePWMsystem.
Thefirstinstructioninthissequencewillsetthebitflag.ON,so
thatthiscodewillnotbeexecutedinthenextexecutionoftheinter-
rupt service routine. The bit TCR.OLVL2 is the state that will be
transferred to TCMP2 pin when an output compare occurs.
TCR.OLVL2isthensetto0sothatTCMP2willbesetlowwhenthe
nextoutputcompareoccurs.Thecodesequencethatfollowsgetsthe
contentsoftheoutputcompareregister2,incrementsthisvalueby
pwm_number,andplacesthisnewvaluebackintooutputcompare
register2.Thus,thetimeoftheoutputcompareisestablishedand
theinterruptserviceroutineisexited.
Eventually,thenextoutputcompare2interruptwilloccur.Since
thebitflag.ONhasbeenset,thefollowingcodewillbeexecuted.
ThiscodeistheoffcodeforthePWMsystem.Thefirstbusiness
totakecareofistoresetthebitflag.ONsothattheonportionof
PWMcodewillbeexecutedthenexttimeintotheISR.TCR.OLVO2
issetsothatTCMP2willgoonwhenthenextoutputcompareoccurs.
flag.ON=0;
TCR.OLVL2=1;/*TimerCompare2toturnon*/
time_cnt.b.hi=OCHI2;/*getthestarttime*/
time_cnt.b.lo=OCLO2;/*resettheOCF*/
time_cnt.l+=off_count;/*completethecycle*/
OCHI2=time_cnt.b.hi;
OCLO2=time_cnt.b.lo;
return;
ThecontentsofOCR2arehandledasabove,butthistimetheirvalue
isincrementedbythecontentsofoff_count.Themainlinecode
isthenre-enteredbytheuseofthereturninstruction.
ThereisanotherapproachtogenerationofPWM signalswithout-
putcomparesystemsthatwillmateriallyaidthisproblem.However,
thisapproachrequirestwooutputcomparesystems.Oneoutputcom-
paresystemisusedtocreatethetimebaseandtheotherisusedto
generate the on or off time. Lets examine the following interrupt
serviceroutine.Outputcompare1isusedheretogeneratethePWM
206 Chapter4 Small 8-Bit Systems
period.Thewaythatthisroutineworks,itispossibleforaninterrupt
tooccurasaresultofacompareonoutputcompare2.Thisinterrupt
istobeignored,andthefirstfivelinesofthecodebelowtestsforthis
conditionandclearsinterruptwhenitoccurs.Thisinterruptoccurs
attheendoftheontime.Controloftheprogrammustbeoutofthis
portionoftheISRandinthemainlinecodebeforethenextinterrupt
causedbyOCF1occurs.Thetimerequiredforthefirstfivelinesof
codehereisabout18microseconds,whichistheminimumontime.
void__TIMER_OC(void)
{
if(TSR.OCF2==1)
{
ac=OCLO2;/*ifinterruptiscausedbyout-
put*/
return;/*compare2resetitandreturn*/
}
time_cnt.b.hi=TCHI;/*getintheTCR*/
time_cnt.b.lo=TCLO;/*getlobyte*/
time_cnt.l+=count;/*bumpthetimecounter
fornext*/
OCHI1=time_cnt.b.hi;/*interrupt*/
OCLO1=time_cnt.b.lo;/*resettheOCF*/
if(flag.PWM==1)
{
TCR.OLVL2=1;/*TimerCompare2tosetoutput*/
TCR.FOLV2=1;/*turnonTimercompare2output*/
TCR.OLVL2=0;/*TimerCompare2toresetoutput*/
time_cnt.b.hi=TCHI;/*getthestarttime*/
time_cnt.b.lo=TCLO;
time_cnt.l+=pwm_number;
OCHI2=time_cnt.b.hi;
OCLO2=time_cnt.b.lo;
}
}
Listing4-7:AlternatePWMISR
Thenextsequenceisthecoderequiredtoestablishthetimebase.
Thistimebaseoperatesonoutputcompare1.Thisroutineissimilar
tothosediscussedabove.Abitinthebitfieldflagistestedtodeter-
OtherProgramItems 207
mineifthePWMsignalistobeturnedon.Ifflag.PWMisset,the
PWMcodewillbeexecuted.Whenthisroutineisentered,TCMP2
willberesettozero.ThefirstinstructionsetsTCR.OLVL2sothat
TCMP2willbeonatthenextoutputcompare.Thenextinstruction,
TCR.FOVL2=1,setstheforceoverflowbitforTCMP2whichwill
causethisbittobeturnedonsinceTCR.OLVL2isset.Thistimeis
thebeginningoftheonperiodofthePWMsignal.
Thenextinstruction
TCR.OLVO2=0;
issothatTCMP2willgoofforberesetatthenextoutputcompare2.
Controlisthenpassedtothemainlineofcode.WhenTCMP2oc-
curs, the output will return to 0 and an interrupt will occur. This
interruptisdetectedbythefirstlinesoftheinterruptserviceroutine.
Onecouldwriteacodesequencethatwouldgeneratethemirror
imagesignaltothatabove.Thatis,theofftimewouldbecontrolled
byTCMP2andtheontimewouldbethedifferencebetweenthetime
ofTCMP2andthemaintimebase.
OtherProgramItems
Severalothersmallprogramscometomindthatareveryuseful
inprogrammingmicrocontrollers.Withthesesmallparts,itisusu-
allydesirabletoavoidlibraryfunctionsand,ifpossible,useabagof
trickstoarriveatthedesiredresults.Forexample,dealingwithnum-
bersforeitherinputoroutputoffersagoodplacetoexercisesome
experienceoverexpedience.Onecasewhereitisoftenimportantto
minimizecodespaceisingeneratingbinarycodeddecimal(BCD)
numbersfromintegernumberstooutputfromacomputer.Perhaps
themostdirectapproachtoaccomplishthisconversionisasfollows:
/*convertabinarynumberlessthan100toBCD*/
unsignedcharconvert_bcd(unsignedcharn)
{
unsignedintresult;
if(n>99)return0xff;
result=n/10<<4;
result+=n%10;
208 Chapter4 Small 8-Bit Systems
returnresult;
}
Listing4-8:FirstBCDConversion
Thissmallfunctiontakesan8-bitcharacternthatislessthan99
andconvertsthenumberintoone8-bitresult.Theuppernibbleisthe
numberoftensinthenumberandthelowernibbleisthenumberof
units.Ahexadecimalnumber0xffisreturnedifthenumberisgreater
than99.Notethatthecalculationrequiresanintegerdivideopera-
tionandamodulusoperationwhichisequivalenttoadivideoperation.
Thecodetoexecutethedivideandmodulusoperationsmustbeasso-
ciatedwiththisfunctiontocompleteitstask.
Anotherapproachisshownbelow.Thisapproachavoidsanyexter-
nalfunctioncallsandactuallyrequireslesstotalcodethantheversionin
Listing4-8,eventhoughtheCcodeissomewhatlonger.Inthiscase,the
whileloopessentiallydividestheinputnumberby10andplacesthe
resultinthemostsignificantnibbleoftheresult.Afterthetenshavebeen
removedfromthenumber,allthatisleftistheunits.Thisvaluethe
numberofunitsisORedontheresultbeforeitisreturned.
/*convertabinarynumberlessthan100toBCD*/
unsignedcharconvert_bcd(unsignedcharn)
{
unsignedintresult;
if(n>99)return0xff;
result=0;
while((n-10)>=0)
result+=0x10;
n+=10;
result+=n;
returnresult;
}
Listing4-9:SecondBCDConversion
The function shown below was originally written for use on a
M68HC05,butwaslaterusedonaM68HC11aswell.Atwo-digit
numbermustbesenttoaseven-segmentLEDdisplay.Thenumber
tobeshowniscontainedinthememorylocationsfortensandunits.
Summary 209
ThenumericdisplaytakesfourinputsthataremerelytheBCDvalue
ofthenumbertobeshown.Withthisparticulardisplay,a4-bitnum-
berbetweenthevaluesof0and9willbedisplayed.Ifeachofthe
fourinputlinestothedisplayisturnedon,thedisplaywillbeturned
off. The parameters passed to the functionhigh and loware
flagstoindicatewhetherthecorrespondingoutputistobeturnedon.
voiddisplay(inthigh,intlow)
/*Displaythecontentsofunitsandtensonthe
appropriateLEDdisplays.Highcorrespondsto
tens,andlowcorrespondstounits.Iftheproper
argumentisTRUE,thecorrespondingLEDwillbe
turnedon.IftheargumentisFALSE,theLEDwill
beturnedoff.*/
{
unsignedintsave;
save=tens<<4;
save|=units70x0f;
PORTA=save;
if(!high)
PORTA|=0xf0;
if(!low)
PORTA|=0xf;
}
Summary
Inthischapter,wehavediscussedprogrammingtechniquesfora
few of the more important peripheral components found on
microcontrollers.TimersandADCapplicationswillbereconsidered
inlaterchapters.Inlaterchapters,serialcommunications,attendant
programmingoflook-uptables,interpolationbetweendatapointsin
look-uptables,andsynchronouscommunicationsfromstandarddigi-
tal I/O pins rather than an SPI will be covered. Some small 8-bit
microcontrollershavepulsewidthmodulation(PWM)outputsthat
canbeusedasadigital-to-analogconverter(DAC).Oftentheranges
availablefromthesefixedPWMsystemsarenotsatisfactoryforthe
required application. Other methods of accomplishing the PWM
operationwillbediscussedinlaterchapters.
210 Chapter4 Small 8-Bit Systems
Manyoftheperipheralcomponentsfoundonthesmall8-bitde-
vicesarefoundonlargermicrocontrollers.Thenextchapterintroduces
agroupoflargermicrocontrollers,theM68HC11family.Thecom-
pilerusedforthedevelopmentoftheM68HC05codedoesnotextend
totheM68HC11family.Therefore,thesourcecodewilllookalittle
differentinthefollowingchapters,butitwillstillbeallC.Togener-
ate code for the M68HC05, the compiler has had to bend the
conceptsofANSICtocreatecodethatwouldworkwiththatfamily.
Largermicrocontrollersaccommodatemoreofthelargecomputer
featuressouseofANSICispossible.
Chapter 5
ProgrammingLarge8-BitSystems
Thischapterontheprogrammingoflarge8-bitsystemswillmake
use of the MC68HC11 microcontroller. It is absolutely necessary
thatanyprogrammerunderstandthedevicewhenwritingcodefora
microcontroller application. If you are not familiar with the
MC68HC11family,thenreadtheM68HC11ReferenceManualand
theM68HC11ESeriesTechnicalDataManualontheaccompanying
CD-ROMtogettheneededbackgroundtobeabletocontinuethe
workinthischapter.
Header File
TheCD-ROMcontainstheCheaderfileHC11E9.H.Thisfileshould
be included with any program that is going to be used on the
MC68HC11E9 or the MC68HC711E9.An abbreviated version of
thisheaderfileislistedbelow. Theheaderfilehasabout400linesof
sourcecode,andmostofthatcodeisrepeatsoftheportionsofcode
showninthefollowinglisting.
#ifndefHC11e9
#defineHC11e9
unsignedintRegister_Set=0x1000;
typedefstruct{
unsigned charbit0:1;
unsigned charbit1:1;
unsigned charbit2:1;
unsigned charbit3:1;
211
212 Chapter5 Programming Large 8-Bit Systems
unsigned charbit4:1;
unsigned charbit5:1;
unsigned charbit6:1;
unsigned charbit7:1;
}Register;
#definePORTA(*(volatileRegister*)(Register_Set+0))
typedefstruct{
unsignedcharSTAF:1;
unsignedcharSTAI:1;
unsignedcharCWOM:1;
unsignedcharHNDS:1;
unsignedcharOIN :1;
unsignedcharPLS :1;
unsignedcharEGA :1;
unsignedcharINVB:1;
}Pioc;
#definePIOC (*(volatilePioc*)(Register_Set+2))
#definePORTC(*(volatileRegister*)(Register_Set+3))
#definePORTB(*(volatileRegister*)(Register_Set+4))
.
.
.
#defineTCNT (*(unsignedint*)(Register_Set+0xE))
#defineTIC1 (*(unsignedint*)(Register_Set+0x10))
.
.
.
/*Toclearbitsintheflagregistersusetheform
TFLG1=OC1
toclearOC1FinTFLG1. Usethisformonlyinthe
twoflagregistersTFLG1andTFLG2below.
*/
HeaderFile 213
#defineOC1F0x80
#defineOC2F0x40
#defineOC3F0x20
#defineOC4F0x10
#defineI4O5F0x08
#defineIC1F0x04
#defineIC2F0x02
#defineIC3F0x01
#defineTFLG1(*(unsignedchar*)(Register_Set+0x23))
.
.
.
typedefstruct{
unsignedcharTCLR:1;
unsignedcharSCP :2;
unsignedcharRCKB:1;
unsignedcharSCR :3;
}Baud;
#defineBAUD (*(volatile
Baud*)(Register_Set+0x2B))
.
.
.
/* Macrosandfunctiontopermitinterruptservice
routineprogrammingfromC.
Tousethevectorcall,dovector(isr,
vector_address)whereisrisapointertothe
interruptserviceroutine,andvector_address
isthevectoraddresswheretheisrpointer
mustbestored. */
#define vector(isr,vector_address)(*(void**)(vector_address)=(isr))
#definecli()_asm(cli\n)
#definesei()_asm(sei\n)
214 Chapter5 Programming Large 8-Bit Systems
#ifndefNULL
#defineNULL(void*)0
enum{FALSE,TRUE};
enum{STOP,START};
enum{OFF,ON};
#defineFOREVERwhile(TRUE)
typedefunsignedintWORD;
typedefunsignedcharBYTE;
#endif
#endif
Thefirstinstructioninthefileis
#ifndefHC11E9
#defineHC11E9
andthelastentryinthefileis
#endif
Theselinesofcodeareusefultopreventmultipledefinitionsofthe
itemsdefinedwithinthefile.Iftheheaderfilehasnotbeenpreviously
compiledasapartoftheprogramwhentheabovestatementisseen,
HC11E9willnotbedefined.ThefirstinstructiondeterminesifHC11E9
isnotdefined,andifitisnot,thesecondlinedefinesit.Thenallofthe
codeuntilthematching#endifwillbecompiled.IfHC11E9isalready
defined,thenthecompilerwillskipthecodelinesuntilthematching
#endifisfound.Therefore,theprogrammercanputan
#include<hc11E9.h>
atthebeginningofeachprogrammodule,anditwillbeusedinthe
programonlyonceevenifseveralmodulesarecombinedintoone
and the above statement is included several times in a single file.
This approach is convenient because it allows each module to be
compiledandtestedandthentheseveralmodulescanbemergedand
compiledasaunitwithoutworryaboutmultiplydefinedvariables
andvaluesfoundinheaderfile.
The file next entry is a simple typedef and declaration of a
structurecalledRegister.Thisstructurecontainseight1-bitentries.
Eachofthesebitscorrespondstoaspecificbitinaregisterfield,and
HeaderFile 215
thebitsaregiventhenamesbit0,bit1,...bit7.Therefore,
when dealing with specific bits within a type Register, the
programmershouldusebitx,wherexisthenumberofthebitbeing
referenced.
In the second portion of the file that follows, all of the I/O
registersaredeclared.
TheexternalvariableRegister_Setisgivenavalue0x1000.
ThisvalueistheinitiallocationoftheI/Oregistermapinthesystem.
IntheMC68HC11,bitmanipulationassemblyinstructionshaveaone-
byte address that can be an offset from an index register. With the
indexedversionoftheinstruction,anysinglebyteorbitintheentire
memory map can be accessed or tested with a single instruction.
However,theaddressoperationmustbeindexed.Ifyouuseasingle
addresswithoffsetstoeachoftheregistersasisdoneintheheader
file,thecompilerwillautomaticallyplacethevalueofRegister_Set
intoanindexregisterandusetheoffsetsspecifiedtoallowindexed
accesstothedataintheregistersfromanywhereintheprogram.
ThevalueofRegister_Setisnotfixedbythemicrocontroller.
Itcanbechangedwithinthefirst64clockcyclesfollowingreset.To
makethischange,theprogrammermustassignthecorrectvalueto
the INIT register in the I/O memory space. This value should be
changedintheinitializationroutinefortheprogram,whichisusually
writteninassemblylanguage.AftertheINITregisterischanged,a
newpropervalueassignedtoRegister_Setwillallowthedesired
accesstoallregistersandbitsintheI/Omemorymap.
The definition of Register shows that any instance of this
variabletypeisacollectionofeightbits.Anylocationthatisdefined
asatypeRegister istrulyacollectionofbitsandeachbitmustbe
processedindividually.Forexample,PORTAisdeclaredtobeofthe
typeRegister. Therefore,anexpressionlike
PORTA=0x3f;
will result in an illegal assignment error because PORTA is of the
typeRegister,notchar.
Itispossibletomakeassignmentstoportsdefinedintheabove
manneraseitherabyte-widefieldorasbitfields.Returntotheinitial
declarationofaregisterintheheaderfile:
typedefstruct
216 Chapter5 Programming Large 8-Bit Systems
{
signedcharbit0:1;
...
unsignedcharbit7:1;
}Register;
Wecannowdeclare:
typedefunion
{
charbyte;
Registerbits;
}Mix_Register;
andthus
#definePORTA(*volatile
Mix_Register*)(Register_Set+0)
willallowtheprogrammertouse
PORTA.byte=0x2E
tosetthevalueofallbitsintheportwithoneinstructionandinthe
sameprogramtouse
PORTA.bits.bit3=1;
toset,reset,ortesttheindividualbitsinsideoftheport.Inthisbook,
wewillusethebitfieldsonlyasshowninheaderfile.
Since PORTA is of the type Register, it is possible to deal
withtheindividualbitswithinthislocationbynormalCconstructs
suchas
PORTA.bit3=1;
if(PORTA.bit6==0)
...
Ofcourse,itismuchbettertodefinepracticalnamestothevarious
bitswithintheporttoachieveevenclearercode:
#defineONTRUE
#defineMOTORbit3
#definePUSH_BUTTONbit6
.
HeaderFile 217
.
.
PORTA.MOTOR=ON;/*turnthemotoron*/
.
.
.
if(PORTA.PUSH_BUTTON==ON)
{
dopushbuttonthings
}
With this compiler, an int is a 16-bit value. Therefore, the
registersthataretwobytesarecastontothetypeint.Usuallythese
registersareaccessedasintsonlyandthereisnoneedtohavethe
individual bit access afforded by the use of the Register type.
Thetimercounterregister(TCNT)isonesuchregisterthatisaccessed
asanintonly.Therearealsoafewonebyte,or8-bit,registersthat
areaccessedasbytesonly.Nobitaccesseswithintheseregistersare
needed.Inthesecases,theregisteriscastontothetypechar.The
severalADRxregistersareexamplesofthistype.TheADRxregisters
containtheresultofananalog-to-digitalconversionthatisusually
handledasan8-bitunitonly.
Inmostinstances,registerlocationsshouldbeunsigned.TheADRx
registerseachcontaintheresultofanalog-to-digitalconversions.These
results are all unsigned. Therefore, these registers should be cast as
unsignedchar.Alsonotethatallofthetimercountandinputcapture
oroutputcompareregistersarealsodeclaredasunsigned.
Inthelistingabove,youwillnotethattherearetwopartstothe
declaration of each register.The first identifies all of the bits in the
registerthroughastructuretypedef.Thenamacrodefinitionofthe
portnamecauseseachinstanceoftheportnameintheprogramtobe
replacedbythedereferencedvalueoftheregisteraddresscastontoa
pointer of the correct type. The port name is the name of the port
foundinthedatamanual,andthebitnamesgiventhebitsinthestructure
arethenamesfoundinthedatamanual.Therefore,ifyouwishtoset
thebitnamedHNDSfoundintheregisterPIOC,youneedtouse
PIOC.HDNS=ON;
Therearetworegisterlocationsthatworkdifferentlyfromthe
rest. These are the two flag registers whose bits are set by the
218 Chapter5 Programming Large 8-Bit Systems
occurrenceofaninterrupt.Thebitsintheseregistersareturnedoff
whenthecodeinstructsthebittobeset.Sincethesetworegistersare
sodifferentfromtheremainderoftheregistersinthesystem,Ihandle
themdifferently.Ratherthandeclareastructurefortheseregisters,
theindividualbitsare#definedaspower-of-twovalues.Therefore,
the bit OC2F is defined as 0x40 and the bit IC2F is #defined as
0x02. The flag1 register TFLG1 is forced to the address
Register_Set+0x23.NowtoclearthebitOC2F,youneedtoset
TFLG1=OC2F;
Thefinalsectionofthefilecontainsseveralmacrosthatarehelpful
inhandlinginterruptserviceroutines.Thefirstmacrois
#definevector(a,b)((*(void**)b)=(a))
This macro is used to place the address of an interrupt service
routineintoavectoraddress.Theargumentaisapointertotheinterrupt
serviceroutine,andbisthevectoraddress.Ifoneaskswhatbis,you
mustsaythatbisapointertoalocationthatcontainstheaddressofthe
interruptserviceroutine.Theinterruptserviceroutineaddressisalsoa
pointertofunctionthathasno(void)return.Therefore,thevector
addressisapointertoapointertothetypevoidandmustbecastas
suchbeforeitcanbeused.Thisvaluemustbedereferencedtobeable
toplacetheaddressoftheinterruptserviceroutineintoit.Youcanuse
themacrovector(a,b)toplacetheaddressofeachinterruptservice
routineusedintothepropervectorlocation.
Thismacrowillcreatecodethatcopiestheaddressofaninterrupt
service routine to the specified memory location. This operation is
neededwheneverthevectortableisstoredinRAM,sothatthevector
table must be rebuilt each time the microcontroller is powered up.
Another approach must be used to place interrupt service routine
addressesinthevectortablewhenthistableiscontainedinROM.This
lattercaseisprobablymorecommonthantheformer.Inthiscase,we
aretryingtofillamemoryarraywiththevaluesoftheaddressesofthe
severalinterruptserviceroutinesthattheprogrammightuse.Oneway
todothisoperationistobuildanarraythatcontainstheseaddresses,
compilethisarray,andthenatlinktimeforcethearraytobelinkedto
thememorylocationcorrespondingtothebeginningofthevectortable.
Considerthefollowingcodesequence.
HeaderFile 219
externvoidIC1_Isr(),OC3_Isr(),_stext();
void(*constvector[])()={0,0,0,0,0,0,0,OC3_Isr,0,
0,0,0,IC1_Isr,0,0,0,0,0,0,0,_stext};
Thistwo-linesequenceidentifiesthreefunctions,eachofwhich
returnsnothing.Thefirsttwoareinterruptserviceroutinesthatwill
process interrupts from input capture 1 and output compare 3,
respectively. The third entry is the name of the entry point in the
start-uproutinethatislinkedtotheCprogram.Thesecondlineof
codeindicatesthatvectorisanarrayofconstpointerstofunctions
ofthetypevoid.Thereisoneentryinthisarrayforeachinterrupt
vector and the reset vector for the micro-controller. This array is
initializedwitheitherzerosortheaddressesoftheinterruptservice
routinesintheproperlocations.Theaddressofthestart-uproutineis
placed in the last location in the array.This little program will be
compiledandlinkedtothefinalprogram.Thenameofthefilethat
containsthisfileisinterrup.c,anditmustbemodifiedforeach
programinwhichitisused.Atlinktime,theaddressofvector[]
willbeforcedto0xffd6whichisthebeginningofthevectortable
intheMC68HC11family.
Some programmers will initialize the vector table with a known
addressratherthan0.Intheeventthataspuriousinterruptoccursand
takestheprocessortoanunusedvectorlocation,theprocessorwould
certainly get lost if the vector table were filled with zeros. Placing a
knownprogramintoallunusedvectorlocationswillpreventthisproblem.
Another problem can occur in the operation of unattended
microcontrollers. It is possible that control of the microcontroller
couldbedivertedtounusedROMlocationsbyseriousnoisespikes.
Such a loss of control will not be devastating if the system uses a
computeroperatingproperly(COP)system.However,anothersafety
back-upthattheprogrammercanincorporateintotheprogramisto
fillallunusedmemorywiththeone-byteinstructionswi(software
interrupt).Thisinstructioncausestheprogramtosavethemachine
statusandpasscontroltothefunctionaddressedintheSWIvector
location.Ifthisvaluecontainstheaddressofthestart-upprogram,
the system will be restarted immediately if control is accidentally
movedtounusedROM.
220 Chapter5 Programming Large 8-Bit Systems
Thereareseveralsmallroutinesassociatedwiththeprocessing
ofinterruptsthatarenotintheClibrary.Theseroutinesarewritten
asfunctionstomakeiteasiertoaccesstheseimportantoperations.
Thecli()andsei()functionsallowtheprogramtoclearorset
theinterruptbitintheconditioncoderegister(CCR).Theprogrammer
can with these two functions and the interrupt masks in the I/O
memorymapcontrolallinterruptoperationsofthepart.
Thecompilermustbenotifiedthatafunctionistobeaninterrupt
serviceroutine.Aninterruptserviceroutinecanhavenoarguments,
anditmustreturnnothing.Therefore,thefunctionprototypeofan
interruptserviceroutinemightlooklike
voidisr_clock(void);
However,thecompilerwouldstillhavenowayofknowingthatthis
functionisaninterruptserviceroutine.Thereasonthatthecompiler
mustknowanisristhattheMC68HC11familystacksthecomplete
machine status when an interrupt is accepted by the device. This
statusmustberestoredwhentheprogramcontrolisreturnedtothe
interrupted program.The machine status is restored when an rti
instructionisexecuted.Therefore,anyreturnfromaninterruptmust
be the assembly instruction rti rather than the instruction rts
usuallyusedtoreturnfromafunction.Aninterruptserviceroutineis
identified to the compiler by the sequence @port ahead of the
definition of the function in the function prototype. The function
prototypeofaninterruptserviceroutineshouldbe
@portvoidisr_clock(void);
Thisflagwillcauseallreturnsfromthefunctiontobertiinstructions.
There is no guarantee that there will be macro definitions for
usefulnumbersandfunctions.Aseriesofenumerationsthatdefine
TRUE,FALSE,ON,OFF,START,STOP,etc.,areincludedtopro-
vide mnemonics for these often-used values.The pointer constant
NULL is also defined by a macro here. These constants are often
definedinotherheaderfiles,sotheprotectionagainstincludingthese
constants more than one time is also included.Also useful is the
macroFOREVERwhichisincluded.
HeaderFile 221
EXERCISES
1.Writeaheaderfilethatcontainsdefinitionsofallvectorsshownon
page 3 of the HC11 E Series Programming Reference Guide,
M68HC11ERG/ADfoundontheCD-ROM.Thisfileshouldbein-
cludedwithanyprogramthatisintendedtomakeuseofinterrupts.
2.Create a small program that uses the function vector(a,b).
Compilethefunctionandobservetheassemblylanguagecodegen-
eratedtoaccomplishthisoperation.
TheCosmicCompiler
TheCosmiccompilerwasoriginallyknownastheWhitesmiths
compiler. Cosmic retained the maintenance contract on this com-
pilerthroughacoupleofcorporateowners,andnowhastherightsto
thecompiler.ThiscompilerusedfortheMC68HC11familyissome-
whatmorecomplicatedtousethantheByteCraftcompilerusedwith
theC68HC05.Thecompilershouldbeinstalledusingtheinstallpro-
gramthatcomeswithit.Youshouldallowthecompilertomodify
yourautoexec.batandconfig.sysfilesunlessyouplantodoityour-
self.Thesystempathshouldcontainthepathtothebindirectoryin
thedirectorythatcontainsthecompiler.Therearealsotwosetcom-
mands that should be inserted into the autoexec.bat file. These
changes,oncecompleted,willmakecompilationofprogramsrather
easy.Thiscompilercreatesanintermediateassemblylanguagepro-
gram that must be assembled. The result of the assembly is a
relocatableobjectmodule.Thismodulemustbelinkedwithother
modulesoftheprogramandbasiclibrarymodulestocomprisethe
finalprogram.Thelinkingphaseofthecompilationplacesallofthe
partsoftheprogramintheirpropermemorylocation.
Fortunately, the compiler can make use of command files to
controlthecompilationsequence.Thesefilesrelievetheprogrammer
oftheneedtorememberthedozensoflittledetailsthatmustgointo
eachcompilation.Wewillstartwiththehighestlevelofthecommand
filesandworkdownintothelowerlevels.Thebasiccommandfileto
compileaprogramandcreateanSRecordversionoftheprogram
isasfollows:
222 Chapter5 Programming Large 8-Bit Systems
c-dlistcs+o%1.c
lnkh11<%1.lnk
hexh11-s-o%1.hex%1.h11
Thisfileiscalledcomp.batanditisinvokedby
comp<filename>
The%1inthecommandfilewillbereplacedby<filename>when
thecommandfileisrun.Thefirstlineofthecommandfiletellsthe
compiler,namedc,toexecutewiththeoptions-dlistcsand+o.
Thenameofthefilewillbethefilenameenteredonthecommand
linewitha.cextension.The-dlistcsoptioncausesalistingfile
tobegeneratedandsavedinafileofthesamenamefilenamebut
withanextension.ls.The+ooptioninformsthecompilertocreate
arelocatableobjectmoduleoftheprogram.
Thebasicinvocationsyntaxofthecompileris
c [options]file.[c| s | o ][filen.[ c | s | o ]]
Any portion of the command line in the above sequence that is
enclosedinsquarebrackets[]isoptional.Therefore,theonlyrequired
commandlineentryfollowingtheccallisthefilename.(Referto
thecompilermanualforthevarietyofoptionsthatcanbeusedon
thiscommandline.)
Severalfilescanbeincludedonthecommandline.Eachofthese
filescanhaveoneofthreeextensions,c,s,oro.Iftheextension
is.c,thecompilerexpectsaCprogram.Ifitis.s,thecompiler
willprocessanassemblylanguageprogram.Whentheextensionis
.o,thecompilerinvokesthelinker.
Thecompilercreatesarelocatableobjectmodulethatislinked
bythenextlineinthecommandfile.
lnkh11<%1.lnk
Thedirectcalltothelinkerlnkh11ishandedacommandfileto
controlthelinking.Eachprogrammusthaveitsownlinkcommand
file, and the extension of this file is .lnk. An example linker
commandfileisshownbelow.Thiscommandfileisforaprogram
developedlaterinthischapter.
HeaderFile 223
#
#linkcommandfileformotorfrprogram
#
+h#multi-segmentoutput
-omotorfr.h11#outputfilename
+text-b0xd000#programstartaddress
+data-b0x0000#datastartaddress
crtsmot.o#start-uproutine
motorfr.o#applicationprogram
libi.h11#integerlibrary
libm.h11#machinelibrary
+text-b0xffd6#vectorsstartaddress
interrup.o#interruptvectors
+def__memory=__bss__#symbolusedbylibrary
Commentlinesareprecededwitha#inthiscommandfile.The
firstexecutablelineofcodeinthefilecontainsacommand+h which
notifies the linker that the program will be in multiple memory
segmentsratherthaninasingleblockinmemory.Thesecondline
-omotorfr.h11
tells the linker to write the output file to motorfr.h11. This
particularlinkerfileisforaprogramnamedmotorfr.The+text
optionplacesthebeginningofthecodeportionofthenextmoduleto
belinkedattheoffset0xd000.The+dataoptionplacesthedata
memoryforthenextmoduleattheoffset0x0000.Finally,thenames
ofthemodulestobelinkedarenext.Themodulecrtsmot.oisa
relocatableobjectmoduleversionofastart-upprogram.Thisroutine
willbediscussedbelow.Thenextmoduletobelinkedismotorfr.o
which is the output of the compiler. This line is followed by the
invocationoftwolibrarycalls.Thefirstistotheintegerlibrary,and
the second is to the machine library. These libraries will provide
necessarycodeforfunctioncallsthatarenotcontaineddirectlyin
the program.Another library named libf.h11 contains floating
pointoperationsthatmightbeneededinyourprogram.
Another+textoptionwillforcethebeginningofthecodelinked
next to the address 0xffd6. This address is the beginning of the
MC68HC11vectortable,andthecodelinkedatthispointisthevector
functiondiscussedearlier.Thisentrywillcreatethevectortableat
224 Chapter5 Programming Large 8-Bit Systems
thecorrectlocationinmemory,anditwillalsoplacetheaddressesof
thedesignatedvectorsintheproperlocationsinthetable.
The start-up routine mentioned earlier is shown below. This
routine is patterned after one provided with the compiler. This
assembly language program contains all of the code necessary to
begintheoperationoftheCprogramtowhichitislinked.Butnote
this point on syntax: within C, all function and memory names
generatedbythecodearemodifiedbytheadditionofanunderscore
_atthebeginningofthename.Therefore,ifthefunctionmain() in
theCprogramweretobereferredtobyanassemblyprogram,the
assemblyprogramwouldberequiredtouse_main.Youwillnotice
that there are many names beginning with both single and double
underscores. For example _main has a single underscore, and
__memoryhasadoubleunderscoreintheexternalstatementthat
follows.Wheneveranassemblylanguagememorylocationorfunction
namehasunderscoresprecedingthename,oneoftheunderscores
mustbediscardedwhenthissamememoryorfunctionnameisused
inaCprogramtobelinkedtothemodule.
Hereyouseeanexampleofwhytheprogrammershouldnotuse
anunderscoreforthefirstcharacterofaname.Thecompilerwriter
assumescompletefreedomtousethesingleunderscoretobeginany
nameneededbytheoperationofthecompiler,andtheprogrammer
shouldconcedethisfreedomtothecompilerwriterbyavoidingthe
useoftheunderscoreforthefirstcharacterofanameanywherein
hisprogram.
Anexampleofthislinkagehasalreadybeenseen.Inaprevious
sectionwherethevectortablewasprogrammed,theentrypointinto
theprogramwasthefunction_stext().Noteinthecodethatfollows
thatthefunctionnameintheassemblylanguagepartoftheprogramis
__stextwithadoubleunderscore.Thisstart-uproutinehasbeen
modifiedforusewithaprogramthatwewilluselaterinthetext.The
mostsignificantmodificationisthefirsttwoexecutableinstructions
whichsettheyregistertothebeginningoftheI/Oregistermemory
areaandthensetsbits0and1ofthelocationoffset36(0x24)fromthe
y register content. These instructions set the prescaler of the timer
counterto4sothatthetimerwillincrementattheslowestpossible
rate.ThesetwoinstructionsmodifythecontentsofTFLG2andthey
mustbechangedwithin64buscyclesafterthemicrocontrollerexits
reset. These changes and others needed in the INIT register, the
HeaderFile 225
OPTION register, and the CONFIG register must be placed in this
location in the program.These registers become read only memory
locationsafterthefirst64buscyclesfollowingreset.
The value __memory is calculated in the command file
motorfr.lnk and it is the number of bytes of memory that the
program uses for volatile memory. The start of the base memory
section is _sbss and it is zero for this program. The instruction
sequencestartingwithldx#__sbss andendingwithbnezbcl
willclearallofthevolatilememoryusedbytheprogram.Finallythe
stackpointerissettoavalueof0xffandtheCprogramisexecuted
bythejsr_maincall.
.processorm68hc11
;
;CSTART-UPFORMC68HC11
;
.external_main,__memory
.public_exit,__stext,__return
;
.psect_bss
__sbss:
.psect_text
__stext:
ldy#4096
bset1,36,y;settheprescalerto/4
clra;resetthebss
ldx#__sbss;startofbss
braloop;startloop
zbcl:
staa0,x;clearbyte
inx;nextbyte
loop:
cpx#__memory;uptotheend
bnezbcl;andloop
prog:
sts__sdata;savespformonitorreturn
xgdx;initializestackpointer
ldd#00ffH;putstackpointeratffforHC11E9
xgdx
226 Chapter5 Programming Large 8-Bit Systems
txs
jsr_main;executemain
_exit:
lds__sdata;restorestackpointer
rts;andreturntocallingprogram
__return:
rti;usedbydefaultinterruptvector
;
.psect_data
__sdata:
.word0;avoidanypointertonull
.end
Thestart-upprogrammustbewrittentoaccountforanyspecial
problems that might be needed for your program. Through this
routine, memory can be initialized with data stored in ROM, the
specialregistersthatmustbeprocessedwithinthefirst64buscycles
canbeset,thestackcanbeplacedwheretheprogrammerdesires,
and so forth.The code at the end of the routine restores the stack
pointertothevalueitcontainedwhenthestart-uproutinewasentered
andexecutesanrts,returntosubroutine,toreturncontrolofthe
processortoamonitorthatstartedtheprogramifoneexists.
The location __sdata is the first byte following the volatile
memoryusedbytheprogram.Thisvaluewillbeusedbythememory
allocationfunctionstoprovidememoryonthesystemheap.
Finally,thelastlineofthecompilercommandfile
hexh11-s-o%1.hex%1.h11
causesexecutionoftheprogramhexh11,whichconvertstheobject
modulefrommachinecodetoanSrecordformatthatcanbewritten
intoanevaluationmoduleorusedtoburnanEPROMversionofthe
microcontroller.ThisSrecordfilecanalsobedeliveredtothefactory
and used to define a mask for a mask ROM version of the
microcontroller. The file created by this line of code will have an
extension.hex.
EXERCISES
1.Writeandcompileasmallprogramthatwillshowsomebitmanipu-
lationsinPORTA.Maketheprogramtest,set,andclearbitsinthis
HeaderFile 227
port.Doestheassemblylanguagegeneratedbythecompilerappear
tobeefficient?Ifnot,whatcanbedonetoimprovethecode?
2.WriteandcompileaprogramthatusesOutputCompare3togener-
ateaperiodicinterrupt.Thisinterruptshouldoccureachmillisecond.
3.WiththetimetickgeneratedbytheresultsofExample2above,
createaclockthatwillkeeptrackofthetimeofdayaccuratetothe
nearestone-hundredthofasecond.
TheCompilerOptimizerandVolatile
ThecompileroptimizerthatisapartoftheCosmicCcompilerdoes
anexcellentjobofreducingcodesize.Oneofthestepsinvolvedisto
removecoderequiredtochangevaluesthatarenotchangedbythepro-
gram.Recallthatthevolatilequalifieridentifiesvariblesthatshouldnot
beoptimized.Thefollowingcodesequencewillshowthisproblem:
volatilecharable;
charbaker
test(void)
{
chardog;
dog=able;
dog=able;
able=0;
able=0;
dog=baker;
dog=baker;
baker=0;
baker=0;
}
Notethatthisfunctionmakesmultipleassignmentsofdog,able,
andbaker.Theassignmentsinvolvingableshowhowthecompiler
respondstoavolatilevariable,andbakertoanonvolatilevariable.
Thefollowinglistingisthecompilationoftheaboveprogram:
1;CompilateurCpourMC68HC11(COSMIC-France)
32.includemacro.h11"
228 Chapter5 Programming Large 8-Bit Systems
3.list+
4.psect_text
5 ;1volatilecharable;
6 ;2charbaker;
7 ;3
8 ;4test(void)
9 ;5{
10_test:
1100003Cpshx
12000134des
13000230tsx
14.setOFST=1
15;6chardog;
16;7
17;8dog=able;
180003F60000ldab_able
19LL4:
200006E700stabOFST-1,x
21;9dog=able;
220008F60000ldab_able
23LL6:
24000BE700stabOFST-1,x
25;10able=0;
26000D7F0000clr_able
27LL01:
28;11able=0;
2900107F0000clr_able
30LL21:
31;12dog=baker;
320013F60001ldab_baker
33;13dog=baker;
340016E700stabOFST-1,x
35;14baker=0;
36;15baker=0;
3700187F0001clr_baker
38;16}
39001B31ins
40001C38pulx
41001D39rts
HeaderFile 229
42;17
43.public_test
44.psect_bss
45_baker:
460000.byte[1]
47.public_baker
48.psect_data
49_able:
50.byte[1]
51.public_able
52.end
Lines17through24correspondtothetwolines
dog=able;
dog=able;
The memory location of able in the program is _able, and the
memorylocationfordogisatOFST-1,x.Notethatthevaluein
_ableisreadandplacedintodogtwiceastheprogramstated.
Also,theinstructionclr_ableisexecutedtwicetoaccountfor
thetwolines
able=0;
able=0;
Thiscodeiswhatyoushouldexpectwhenthevolatilekeywordis
usedwhenableisdeclared.Ontheotherhand,lines31through34
showthecompilationofthetwoClines
dog=baker;
dog=baker;
Inthiscase,youwillnotethatthevalueforbaker,storedat_baker,
isplacedintotheaddressofdogonlyonceeventhoughthecodeline
isrepeated.Similarly,thetwolines
baker=0;
baker=0;
resultinassemblycodethatclearsthelocation_bakeronlyonce.
Thistypeofoptimizationwillsaveyoumuchcodespace.Itiscertainly
aproblemwheneverthereisamemorylocationthatcanbechanged
fromoutsidetheprogram.Thevolatilekeywordwillcausethe
230 Chapter5 Programming Large 8-Bit Systems
optimizationoperationtoskipoverallvariablesthatcanbechanged
by the hardware portion of the system without knowledge of the
program.
Sorting Programs
Youmightnotexpectthatsortingroutineswouldbeimportantwhen
programmingmicrocontrollers,buttherehavebeenseveralinstancesin
my experience where sorting of a list of data was needed in a
microcontroller application. Therefore, lets examine some sorting
routinesthatcanbeusedwithamicrocontrolleranddeterminewhichof
severalpopularapproachesisbestforuseinamicrocontrollerprogram.
Thereareseveralsortingroutinesthatarepopularwithprogram-
mers. The three most-used routines are named the entry sort, the
Shellsort,andthequicksort.Theentrysortisaroutinethatisthor-
oughlydiscreditedbecauseitisextremelyslowwhencomparedwith
theotherroutines.Anentrysortordersthecontentsofanarrayin
place.The first entry in the array is compared with the remaining
entriesand,ifanyarrayentryissmallerthanthefirst,thesevalues
areswapped.Thisoperationisthenrepeatedforthesecondentryin
thearrayfollowedbythethirdentryinthearrayuntilallentriesin
thearrayarecomparedwithallothers.Whenthissequenceiscom-
pleted,thearrayissorted.Iftherearenentriesinthearray,thefirst
scan involves n compares, the second involves n-1 compares, the
thirdn-2andsoforth.Therefore,thetotalnumberofcomparesis
n+(n-1)+(n-2)+...1
Thevalueofthissumisn*(n-1)/2.Inotherwords,theentrysort
2
requiresontheorderofn compares.
TheShellsortwasdiscoveredin1959byD.L.Shell.Likethe
entrysort,theShellsortordersthecontentsofanarrayinplace.The
Shellsortsplitsthen-elementarrayintotwohalves.Thecontentsof
thesetwohalvesarecomparedentry-by-entryand,ifthevalueinthe
onehalfislargerthanthatintheother,theentriesareswapped.These
arrays are then split again, and the contents of the four arrays are
scannedandorderedtwoatatimeasabove.Thenthefourarraysare
splitintoeightarraysandthescanandorderingoperationisrepeated
again.Thisoperationofsplittingthearraysandorderingthecontents
isrepeateduntiltherearen/2arraysof2elementseach.Afterthis
lastscanandsortoperation,thearrayisordered.
SortingPrograms 231
There are n/2 compares completed each scan of the array.
However,thesortwillbecompletedafterthelogarithmbased-2ofn
timesthroughthearray,becauselog
2
nisthenumberoftimesthatan
arraythatcontainsnentriescanbecutinhalf.Therefore,thetimeto
executeaShellsortofanarrayofnitemswillbenearlyproportional
to n*log(n). For even medium-sized arrays, this time is
2
significantlyshorterthanfortheentrysort.Forexample,anarrayof
1000 entries requires time on the order of 1000000 to execute an
entrysortand10000toexecuteaShellsort.
Another sort is the quick sort developed by C.A. R. Hoare in
1962.Thissortisarecursiveroutine.Itsortsanarrayinplace.Assume
thatthearrayrunsfromlefttorightandwewanttosortthearrayin
ascendingvaluesfromlefttoright.Anarrayscanwillplaceatleast
oneofthearrayvaluesintheproperfinalarraylocation.Thisentry
iscalledthepivotentry.Asthescaniscompleted,allentrieslarger
than the pivot value are swapped to the right end of the array and
smaller values are placed in the left end of the array. When this
operationiscompleted,thetwoportionsofthearrayexcludingthe
pivotentryareagainquicksortedandtheresultofthisrecursive
operationisthatthefinalresultissorted.Thissortingoperationalso
requirestimeproportionalton*ln(n)/2.
ThequestionnowariseswhetherweshoulduseaShellsortora
quicksortwhenwritingcodeforamicrocontroller.Letsexamine
thesefunctions.ThecodeforaShellsortisasfollows:
/*shell_sort(intv[],inti):sortthearrayv
ofithingsintoascendingorder*/
voidswap(int*,int*);
voidshell_sort(intv[],inti)
{
intsplit,m,n;
for(split=i/2;split>0;split/=2)
for(m=split;m<i;m++)
for(n=m-split;n>=0&&
v[n]>v[n+split];n-=split)
swap(v+n,v+n+split);
}
232 Chapter5 Programming Large 8-Bit Systems
Theouterloopintheprecedingroutinecontrolsthewaythatthe
arrayissplit.Itfirstsplitsthearrayinhalfandthenshrinksthearrays
byhalvesuntilthesubarraysbecomezeroinwidth.Thesecondloop
stepsalongtheelementsofthearrays,andthethirdloopcomparesthe
elementsthatareseparatedbysplitandswapsthemwhennecessary.
Thequicksortis:
/*quick_sort(intv[],intleft,intright):
sortthearrayvintoascendingorder*/
voidquick_sort(intv[],intleft,intright)
{
inti,pivot;
if(right>left)
{
swap(v+left,v+(right+left)/2);/*chosethe
valueatcentertopivoton*/
pivot=left;
for(i=left+1;i<=right;i++)
if(v[i]<v[left])
swap(v+(++pivot),v+i);
swap(v+left,v+pivot);/*putthepartition
elementinplace*/
quick_sort(v,left,pivot-1);
quick_sort(v,pivot+1,right);
}
}
Theswaproutineforbothofthesesortsisthesame:
/*swap(int*,int*):swaptwointegersinan
array*/
voidswap(int*i,int*j)
{
inttemp;
temp=*i;
*i=*j;
*j=temp;
}
Oneofthenicethingsaboutbothoftheseprogramsisthattheswap
operationisnotbuiltintotheprogram.Therefore,youcanswapvalues
SortingPrograms 233
aswasdoneabove,butalso,youcanswappointersfromanarrayof
pointers to order a set of data that would be difficult to swap. For
example,ifyouhadacollectionofwords,youcoulduseasrtcmp()
routinetodeterminewhetheronewordwaslexicallylargerthanthe
otherandthenwriteaswaproutinethatmerelyswappedthepointers
to these words rather than swapping the words themselves. This
approachtosortingalistofwordsisrelativelysimple.Ontheother
hand,itwouldbeextremelydifficultnearlyimpossible,infact
tosortalistofwordsthatarepackedintomemory.
The following program is used to test the performance of the
abovesortroutines.Theprogramsimplymakesanarrayof11entries
and sorts the array by both the Shell sort and the quick sort. The
resultofthisprogramisprintedoutbelow.
#include<stdio.h>
main()
{
intv[]={81,99,23,808,3,77,18,27,128,360,550};
inti,k[11];
for(i=0;i<11;i++)
k[i]=v[i];
shell_sort(k,11);
for(i=0;i<11;i++)
printf(%d,k[i]);
printf(\n);
quick_sort(v,0,11-1);
for(i=0;i<11;i++)
printf(%d,v[i]);
printf(\n);
}
Theoriginalarrayisnotprintedoutbytheprogram,buttheorderof
thearrayisseenintheabovelisting.Thetwosortprogramssortthe
valuescorrectly.
3182327778199128360505808
3182327778199128360505808
The quick sort routine is not the best example of recursive
programming.Usually,theuseofrecursionresultsinaprogramthat
is significantly shorter than would be expected with conventional
234 Chapter5 Programming Large 8-Bit Systems
linearprogramming.Here,theShellsortrequiresfewerlinesofC
codeand,aswewillsee,theShellsorthasasmallerassemblylanguage
program.Youwouldnotexpectthelinearprogramtobeshorterin
eitherCorassemblylanguage.Thesetwoprogramswerecompiled
andtheresultsanalyzed.
TheShellsortrequires0x78(120)bytesofcodewhilethequick
sortneeds0xaa(170)bytesofcode.Thisamountofextracodewould
notbeaseriouscostifthatweretheendofthecosts.However,each
timearecursiveroutinecallsitselfitmustestablishanargumentset
thatcontainsallofthevariablestobepassedtothefunction.When
thequick_sortroutinecallsitself,itmustpassthreeparameters.
Theseparametersareusuallypassedineitherthestackorincomputer
registers.Whenquick_sortreturnscontroltothecallingprogram,
the stack pointer must be corrected. quick_sort will continue
callingitselfrepeatedlywhilethevalueoftheparameterrightis
greaterthanthevalueoftheparameterleftwhenthefunctionis
entered.Eachtimethefunctioniscalled,theprogramwillcreatea
new stack frame which must be made available from RAM.
Unfortunately,RAMisusuallyamorepreciouscommoditythanROM
toamicrocontroller.
ItispossibletogetanideaabouthowmuchRAMisneededtodo
aquicksort.Thestackframeconsistingofsixbytesfourbytesfor
parametersplustwobytesforthereturnaddressmustbecreated
eachtimequicksortisentered.Youcancountthemaximumnumber
of times recursive routine calls itself. The maximum depth is the
numberoftimesthefunctioniscalledbeforeanormalreturntothe
callingfunctionisexecuted.Thedepthisfoundbyincrementinga
counteachtimethefunctionisentered.Whenevercontrolispassed
backtothecallingfunctionthroughthenormalreturnsequenceat
theendofthefunction,thedepthwillbeevaluatedtodetermineifit
isthelargestvalueseensofar,andthenthedepthwillbereturnedto
zero.Thetwolistingsbelowincorporatethesemodifications.
/*quick_sort(intv[],intleft,intright):
sort thearrayvintoascendingorder*/
voidquick_sort(intv[],intleft,intright)
{
inti,value;
externintcalls,depth,max_depth;
SortingPrograms 235
calls++;/*countthenumberoftimescalled*/
depth++;
if(right>left)
{
swap(v+left,v+(right+left)/2);/*chosethe
valueatcentertopartitionon*/
value=left;
for(i=left+1;i<=right;i++)
if(v[i]<v[left])
swap(v+(++value),v+i);
swap(v+left,v+value);/*putthepartition
elementinplace*/
quick_sort(v,left,value-1);
quick_sort(v,value+1,right);
}
if(depth>max_depth)
max_depth=depth;
depth=0;
}
voidswap(int*,int*);
voidquick_sort(intv[],intleft,intright);
#include<stdio.h>
intcalls,depth,max_depth;
main()
{
intv[11]={81,99,23,808,3,77,18,27,128,360,550};
inti;
quick_sort(v,0,11-1);
for(i=0;i<11;i++)
printf(%d,v[i]);
printf(\n);
printf(calls=%d\nmax_depth=%d\n,calls,max_depth);
}
Notethattheglobalvariablescallsanddepthareincremented
eachtimequick_sort()isentered.Whenquick_sort()is
exitedthroughitsnormalreturnprocedureattheendoftheroutine,
depthisexaminedtodetermineifitisgreaterthanmax_depth.
236 Chapter5 Programming Large 8-Bit Systems
Ifitis,max_depthisreplacedbydepth.depthisresettozero
priortoreturningthroughtheendofthequick_sort()routine.
Theresultofthisprogramisasfollows:
3182327778199128360550808
calls=15
max_depth=4
To sort the above 11 element array, the program called
quick_sort()15timesandthemaximumnumberofstackframes
thatwerecreatedatonetimewasfour.Eachstackframeconsistsof
fourbytesfordataandtwobytesforthereturnaddress.Therefore,at
onetimeintheexecutionofthisprogram,thesortroutinerequired
24bytesofstackspaceinadditiontothememoryarearequiredto
holdthearraybeingsorted.Thisisdistressingwhenyouremember
thatthearrayis22byteslong!
Careful analysis of the program will show that the expected
maximumnumberofstackframesforthequicksortisproportionalto
ln
2
n.Therefore,thestackframeperformancewillgetbetterwhenthe
sizeofthearrayislarger.Themainproblemwiththeuseofanyrecursive
routineisthatyoudonotknowexactlythenumberofstackframes
needed and therefore you must always analyze the maximum stack
framedepthandallowthatamountofstackforexecutionofthefunction.
The quick sort is faster than the Shell sort under mostbutnot
allcircumstances.Letstaketheexampleofhavingaquicksortand
aShellsortcompiledtorununderthesamehostcomputer.Iflarger
arraysareusedtodothemeasurementandrandomarraysareused,we
willfindthatthesorttimeforbothquicksortandShellsortdepends
on the array. The reason for this difference is the number of swap
routinesthatmustbeexecutedduringthesortoperation.Therefore,
therewillbesomearraysthattheShellsortwillsortquickerthatthe
quicksort.However,thequicksortisusuallyfasterthantheShellsort.
TheShellsortiseverybitasflexibleasthequicksortandcanbe
usedtosortdifferenttypes,characterstrings,andswappointersrather
thanswaptheobjectsbeingsorted.Therefore,inamicrocontroller
applicationwherememoryisalwayslimited,youshoulduseaShell
sort rather than a quick sort because the Shell sort has no funny
memoryrequirementsthatwillalwaysoccurwitharecursiveroutine
likethequicksort.
DataCompression 237
The purpose of the above discussion is to demonstrate that the
programmermustexercisemuchmorecareinthedetailsofprogram
designforamicrocontrollerthanisnecessaryforalargermachine.The
above sorting routine would be of no concern for a typical desktop
machinebecauseRAMisusuallyofnoconsiderationwithsuchmachines.
Itmightnotbeaproblemforsomemicrocontrollerapplications,butin
acasewhereRAMislimitedandneeded,itmightmakethedifference
betweenbeingabletogettheprogramtorunornot.
Inmostinstances,theeleganceofrecursivecodehasacostof
RAM.Usuallyarecursiveprogramwillbeslowerthantheequivalent
linearprogram.Themicrocontrollerprogrammermustexamineeach
instanceofcodetodetermineiftheelegantrecursiveprogramhas
hiddensideeffectsthatendupcostingmoreincomputerresources
thanisgainedinsmallcodesize.
EXERCISES
1.Writeaprogramtorunonahostcomputerthatwilltestthetime
requiredtoexecutebothaquicksortandaShellsortonrandom
largearrays.Makethearraysizesselectablefromthekeyboard.
2.TestboththequicksortandShellsortforvariousarraysizes.Ex-
amine the time required to execute the sorts for several random
arrays.Explainwhatishappeningwhenarraysof4090,4095,and
4096entriesaresorted.
Data Compression
Another program problem that can arise with microcontroller
applications is handling displays in which there are many phrases
andnameseachconsistingofseveralletters.Thequestionthatmust
beconsideredisthemostefficientmethodofstoringthesephrases
andnames,inmemorysothattheycanberecalledfordisplay.The
oldest, and yet very effective, method of compressing the data for
storageistouseaHuffmancode.Thiscodeisdevelopedbasedon
thestatisticaloccurrenceofeachletterinthealphabet.Aletterthat
occursfrequentlywillbegivenashortcodesequence.Aletterthatis
seen infrequently can be assigned a long code, which will not
appreciablyaffectthenumberofbitsperletterinthemessage.
238 Chapter5 Programming Large 8-Bit Systems
Huffmancodesareself-synchronizing.Alongstringofcharacters
canberepresentedasaseriesofbits,andthedecodingprogramcan
findeachcharacterinthesequencewithoutanyspecialflagstodesignate
theendofeachcharacter.MessagesstoredasASCIIcharactersrequire
atleast7bitspercharacter,andbecauseofthenatureofstorageina
computer,8bitsareusuallyassignedtoeachcharacter.WithaHuffman
code,itispossibletoreducetheaveragenumberofbitspercharacter
for the whole English language to about 4.5 bits per character.
Sometimesevenfewerbitsareneededwithlimitedmessages.
TheprogrammerdoesalloftheHuffmanencodingandthecomputer
mustdecodethemessagesfordisplay.Huffmandecodingrequiresextensive
bitmanipulation,soCisanideallanguagetodecodethemessages.
AHuffmandecodingschemecanberepresentedbyastrictlybinary
tree.Abinarytreeiscomprisedofacollectionofnodes.Eachnodehas
twodescendents,oftencalledtherightandleftdescendents(thusthe
termbinarytree).Theterminatingnodeinatreeiscalledaleaf.Ina
strictlybinarytree,everynonleafnodehasbotharightandleftdescendent.
Ifastrictlybinarytreehasnleafs,ithasatotalof2n 1nodes.
TheHuffmancodeisdecodedinthismanner.Thesequencealways
startsattherootnode.Thecodesequencetobedecodedisexamineda
bitatatime.Ifthebitisa0,movetotheleftnode.Ifthebitisa1,
movetotherightnode.Thetreeistraverseduntilaleafisfoundwhich
contains the desired character.The sequence is then restarted at the
rootnode.Ifthetreeisnotknown,thesequenceofbitsisbewildering.
Usuallyitisfoundthattheoccurrenceofonesandzerosisaboutequally
likely,sonostatisticalanalysiscanbeappliedtodecodethesequence
easily.Adisadvantageisthatifasinglebitinthesequenceislost,the
remainder of the code stream is undecipherable. Of course, the
advantage to the Huffman code is that it takes somewhere between
one-quarterandone-halfthenumberofbitstorepresentamessageas
isrequiredbytheASCIIcode.AHuffmanCodetreeisshowninFigure
5-1. The bit sequence 111111100101111010100000 as decoded by
thistreeisseentospellthewordcommittee.Thissequencerequires
23bits,andtheASCIIcodeneededtorepresentcommitteeis72bits
long. Of course, this tree was designed specifically for the word
committee,buttrytoencodeotherwordsthatcanbemadeofthese
sameletterssuchastic, me, come, tom, mite,etc.,andyou
willfindthateverywordthatcanbederivedfromthistreerequires
fewerbitsthanthecorrespondingASCIIsequencewouldneed.
DataCompression 239
IfyoulookatFigure5-1,youwillnotethattheletterse,m,and
trequireonly2bitseachtodeterminethevalue.Theseletterswere
selectedtoberepresentedby2-bitvaluesbecausetheyarethemost
frequently occurring letters in the message. The remainder of the
lettersrequiremorebitsbuttheydonotoccursoofteninthemessage.
e
l
o
m t
c
Figure5-1:HuffmanCodeTree
Thecodemustbedesignedspecificallyforthemessagestobe
represented. First, all of the characters in all of the messages are
collected into a histogram of the occurrence of each character.
Remember to include spaces and other such characters in the list.
Onceyouhavedeterminedthenumberofdifferentcharactersinthe
list, you can design a tree that will compress the code. If the list
containsndifferentcharacters,therewillbe2n 1nodesinthetree.
Eachlevelinthetree,startingfromtherootnodeatthezerothlevel,
can contain 2
k
nodes or leafs. This tree cannot be balanced like a
binarysorttreebecausewewantsomeoftheleafstobedetermined
by as few as 2 bits, and we do not care about the number of bits
neededtodetermineacharacterthatoccursinfrequently.InFigure
5-1,levels0and1containonlynodeswithnoleaves.Level0contains
threeleavesandonenode.Itisthroughthissinglenodethatallofthe
remainderofthecharactersmustbefound.
Aseriesofavionics-relateditemswereputtogetherandananalysis
of the frequency of characters in these messages was completed.A
Huffmancodethatwillencodethesedataeffectivelywascreated.This
240 Chapter5 Programming Large 8-Bit Systems
codeisshowninTable5-1.Frequentlyoccurringletterslikee,i,ora
areencodedwithonlytwoorthreebits.Ontheotherhand,lettersthat
occurveryinfrequentlylikecorvrequire9bitstoencode.Even
though some letters require more than 8 bits to encode, the average
numberofbitspercharacterforthisparticularmessagesetisonly4.032.
DecodingaHuffmancodewithaprogramisrelativelyeasy.The
programmustcontaintheHuffmantreewithallofitsnodesandleaves.
Ifwewanttheentirealphabetandaspace,aperiod,acommaandan
endofmessage,therewillbe59entriesinthetree.Thisoranequivalent
treeisanoverheadthatmustbecarriedforeveryHuffmanprogram.
Assume that the statistical analysis of the messages along with the
constructionoftheHuffmantreeiscomplete.Theapproachtakento
buildthistreeinmemoryistoallowonebyteforeachnode.Thetree
issearchedfromtherootnode,whichisthelowestaddress.Themessage
tobedecodedisexamined.Ifthebitinthemessageisazero,thenode
pointerisincrementedbyoneandthenextbitisexamined.Ifthebitin
themessageisaone,thenodepointerisincrementedbythecontentof
thenode.Allprintablecharactersareenteredintothetreeasnegative
numbers.Thecontentsofthenodeareexamined.Ifthecontentofthe
node is positive, the next bit from the message is examined and so
forth.Wheneverthecontentofanodeisnegative,itsmostsignificant
bitisremoved,andthecharacterissenttotheoutput.Atthattime,the
nodepointerisreturnedtotherootnode,andthesequenceisrepeated
untilanendofmessageisfound.
Character Code Character Code
E 00 D 110000
I 01 110001
A 100 G 111100
\n 101 U 111101
N 11001 L 1111100
R 11010 O 1111101
T 11011 F 11111100
M 11100 H 11111101
S 11101 P 11111110
C 111111110
V 111111111
Table5-1:HuffmanCode
DataCompression 241
ThelistingshownbelowisasimpleHuffman-encodedroutineto
printouttothescreenseveralaircraft-orientedtermsthatmightbe
usedinanon-boardavionicssystem.Thefirstpartofthefunctionis
alistoftheseveralwordsorphrases.
#include<stdio.h>
/*Themessagestosendout*/
staticunsignedcharM1[]={0x9f,0x36,0xef,0xdc,0x0a};
staticunsignedcharM2[]={0xfd,0x26,0x0e,0x7c,0xa0};
staticunsignedcharM3[]={0xc1,0xee,0xe6,0x7f,0xc6,
0x3a,0x39,0x1c,0xb9,0xf2,0x80};
staticunsignedcharM4[]={0xfc,0xf4,0xf9,0x8e,0x8e,
0x47,0x2e,0x7c,0xa0};
staticunsignedcharM5[]={0x8e,0xb1,0xef,0xf0,0x61,
0x40};
staticunsignedcharM6[]={0x73,0x8f,0xef,0xdf,0x75,
0xda};
staticunsignedcharM7[]={0xdb,0xc2,0x80};
staticunsignedcharM8[]={0x3b,0xb7,0x93,0x66,0x18,
0xed,0xe1,0x8f,0xdf,0xcc,0x66,
0xb4,0xff,0xe7,0xca};
staticunsignedcharM9[]={0xf3,0x5f,0x7d,0xce,0x18,
0xf7,0xf8,0x30,0xa0};
/*TheHuffmantree*/
conststaticchar
Node[]={4,2,E|0X80,I|0X80,4,2,A|0X80,
\n|0X80,10,6,4,2,D|0X80,|0X80,
N|0X80,2,R|0X80,T|0X80,4,2,M|0X80,
S|0X80,4,2,G|0X80,U|0X80,4,2,
L|0X80,O|0X80,4,2,F|0X80,H|0X80,2,
P|0X80,2,C|0X80,V|0X80};
voiddecode(unsignedchar*M)
{
unsignedcharmask=0x80;
chari=0,j=0,k=0,l=0;/*jisthenodepointer,
iisthebytepointer,M
isthemessagepointer*/
while(k!=\n)
242 Chapter5 Programming Large 8-Bit Systems
{
if((mask&M[i])==0)
j++;/*usenextnodeentryifbitiszero*/
else
j+=Node[j];/*jumptodesignatednodewhen
one*/
if(Node[j]<0)
{/*ifaprintable,senditout*/
putchar(k=Node[l]&0x7f);
j=0;/*alsogototherootnode*/
}
if((mask>>=1)==0)/*ifthemaskiszero,turn
onMSB*/
{
mask=0x80;
i++;/*andgetthenextbytefrommessage*/
}
}
}
Listing5-1:HuffmanDecodeFunction
ThenextpartoftheprogramistheHuffmantreeneededtodecode
thedata.Thistreewasconstructedtodecodedataspecificallyforthe
ninemessagesofthisproblem.Youwillnotethateachbyteinthe
tableisanode.Intermixedinthetablearenumbersthatdictatejumps
tothenextnodedependingonwhethertheincomingbitisazeroor
aone.Theleaveseachcontainanegativenumberthatisgenerated
bytheinclusiveORofthecharactertobeprintedandthenumber
0x80.
Themessagesaresenttothefunctiondecodeasapointertoabit
array.Thedatamustbeexaminedonebitatatimetoimplementthe
decoding.ThebitselectionisaccomplishedbyANDingthedatain
theincomingmessagewiththecontentsofthevariablemask.Mask
isinitiallysetto0x80,sothemostsignificantbitofthefirstbyteof
theincomingdataisselected.Laterintheroutine,thevalueofmask
will be shifted right to select other bits in the incoming sequence.
Thevariablekisloadedwiththecharactertobeoutputduringthe
program.Thelinefeedcharacter\nwasusedtodeterminetheend
of message, so the decoding sequence will be executed until the
DataCompression 243
characterthatwasoutputfromtheprogramisa\n.Recalltheway
thatthetreewasbuilt.Ifanincomingbitis0,thenextnodeinthe
treewillbetaken.Iftheincomingbitis1,thecontentofthecurrent
nodewillbeaddedtothenodepointertodeterminethenextnodein
thetree.Ifatanytimeanegativenumberisfoundinthetree,aleaf
hasbeenfound.Thedataportionofthisbyte,bits0through6,will
besentouttothescreen.
Aftereachbitisprocessed,thenextbitinthesequencemustbe
processed.Thenextbitisselectedbyshiftingthemaskbytetothe
right one bit. If the result of this shift creates a zero mask, a new
mask with a value of 0x80 is created and the next byte from the
incomingmessagecodeisselectedwheniisincremented.
Thesimpleprogrambelowcausestheninemessagestobeprinted
onthescreen:
main()
{
decode(M1);
decode(M2);
decode(M3);
decode(M4);
decode(M5);
decode(M6);
decode(M7);
decode(M8);
decode(M9);
}
Listing5-2:MessagePrintingProgram
Theresultofexecutionofthisprogramisshownbelow.Thenine
messages contain 124 characters that would require 992 bits of
memorytostorethemessagesinstandardASCIIformat.Theencoded
sequencerequires500bitsor63bytesofstorage.
ALTITUDE
HEADING
DISTANCEREMAINING
FUELREMAINING
AIRSPEED
244 Chapter5 Programming Large 8-Bit Systems
INHOURS
TIME
ESTIMATEDTIMEOFARRIVAL
GROUNDSPEED
Thefunctionbelowwaswrittentoshowthedifferenceinmemory
required for the Huffman code and conventionalASCII coding.This
programwascompiledasafunctiontoberunontheMC68HC11.The
functiondecodegiveninListing5-1wascompiledtoMC68HC11code.
TheresultofthesetwocompilationsshowedthatListing5-1createdan
objectmodulethatwas255byteslong,andListing5-2createdanobject
modulethatwas277byteslong.TheHuffmancodeforeventhesmall
messagelistinthiscaseprovidednearly10%reductionincodesize.A
larger message list would provide an even greater memory savings
becausethecoderequiredtodecodethemessageswouldbeallocated
overmoremessagecharacterstobesentout.
#include<stdio.h>
charM1[]=ALTITUDE;
charM2[]=HEADING;
charM3[]=DISTANCEREMAINING;
charM4[]=FUELREMAINING;
charM5[]=AIRSPEED;
charM6[]=INHOURS;
charM7[]=TIME;
charM8[]=ESTIMATEDTIMEOFARRIVAL;
charM9[]=GROUNDSPEED;
voiddecode(char*M)
{
while(*M!=0)
putchar(*M++);
putchar(\n);
}
Listing5-3:NonencodedOutputFunction
EXERCISES
1.HowcouldthetreeinListing5-1bealteredtoreduceitssizeby8
bytes?Whateffectwouldthischangehaveontheroutinedecode?
Wouldtherebeanetsavingsinoverallcode?
TimerOperations 245
2.DoananalysisofasubstantialpieceofwritingandcreateaHuffman
codethatwillencodethedataefficiently.Itisrecommendedthat
thefirstthreepagesofanovelbeusedforthisanalysis.Compute
theaveragenumberofbitspercharacterthatthiscodegenerates.
Hint:youmightwanttowriteaprograminCforthehostcom-
putertocalculatethehistogramandhelpcreatetheHuffmancodes.
3.Write a program that will implement the above code so that an
operatorcantypethedataintoacomputerandtheHuffmancode
sequences will be generated.You should break the message se-
quencesintomoderatesizebitstrings,500to1000bits,andrestart.
4.CreateaHuffmantreetableaswasusedinListing5-1todecode
theHuffmancodedevelopedinExercise2.
5.HowcanyoudoublethenumberofentriesinaHuffmantreeby
addingonlyonebittothecodestrings?
Timer Operations
Theprogramswrittenintheearliersectionsonsortinganddata
compression were more computer programs than microcontroller
programs. The code written would work on a desktop system or a
mainframe computer if needed. In this section, we graduate to true
microcontrollerprogramming.ThesetupoftheMC68HC11family
requiresthattheprogrammerhaveadetailedknowledgeoftheoperation
of the device. Even though the program is written in a high-level
language,itistheresponsibilityoftheprogrammertoproperlysetall
of the necessary control bits to make the device work as desired.
Unfortunately,therearefewhelpfultoolsthatcanguideyouthrough
thisportionoftheprogram.Youmustfirstunderstandwhatyouwant
the device to do and then dig through its specifications to find the
necessary bits to be set to make it perform as desired. It is highly
recommendedthatpriortoanattemptatprogrammingthisdevicethat
youfamiliarizeyourselfwiththetechnicaldatamanualforitaswell
asthereferencemanualforthefamilythatisfoundontheCD-ROM.
The timer subsystem in the MC68HC11 family contains both
inputcaptureoperationsandoutputcomparefunctions.Inthissection,
wewillexplorethesesubsystemsassociatedwiththeMC68HC11Ex
series.ThemaindifferencebetweentheExseriesandtheotherdevices
liesinthenumberofoutputcompareandinputcapturesystemson
246 Chapter5 Programming Large 8-Bit Systems
each device. The Ex series has four output compares, three input
captures, and one timer that can be programmed as either output
compareorinputcapture.Theotherdeviceshavethreeinputcaptures
andfiveoutputcompares.
OutputCompareSubsystems
Whatdoesanoutputcomparedo?Theexplanationofthetimer
subsystemmustalwaysbeginwiththe16-bittimercountercalledTCNT
thatisalwayscountingatsomefractionofthesystembusfrequency.
Thebusfrequencyisalwaysone-fourthofthesystemcrystalfrequency.
Theprescalerfrequencyissettothebusfrequencydividedbyeither1,
4,8,or16dependingonthebitsPR1andPR0intheregisterTMSK2.
The timer counter register can be read at any time but it cannot be
writtento.TheOutputCompare1isspecial.Allofthediscussionthat
followsisvalidforalloutputcompares,butaswillbeshownlater
OutputCompare1hascapabilitybeyondtheothers.
Associated with each output compare system there is a single
16-bitoutputcompareregistercontainingthetimethattheprogram
needsaneventtooccur.WhenTCNTcontentsmatchesthatofOCx,
an OCx event occurs. Note that I say an event, not output. What
happenswhenthecontentsoftheTCNTmatchesthecontentsofOCx
isuptotheprogram.Associatedwitheachoutputcompareisapin
that can be set, reset, or toggled when an output compare occurs.
Whenanoutputcompareoccurs,thecorrespondingOCxFflagbitis
setintheTFLG1register.Thisbitcanbeexaminedasynchronously
bytheprogramtodeterminewhetheranoutputcomparehasoccurred.
IfthecorrespondingbitintheTMSK1registerissetwhentheOCxF
flagbitisset,aninterruptwillberequestedbythepartandtheevent
will be processed asynchronously. These are the operations of all
outputcomparesubsystemsinthepart.
There are three input captures, four output compares, and one
timerthatcanbeprogrammedaseitheranoutputoraninput.This
timeriscontrolledbytheI4O5bitinthePACTLregister.Whenthis
bitisazero,theprogrammabletimerisanoutputcompare.Otherwise
whenthebitisset,theprogrammabletimerisaninputcapture.Often
itisdesirabletohaveanoutputcompareoperationbeinitiatedbythe
completionofanotheroutputcompare.OutputCompare1issetup
in just this manner. The bits in the OC1M and the OC1D registers
controlthecouplingbetweentheOutputCompare1andtheother
TimerOperations 247
outputcomparesubsystems.Whenoneofthemaskbits,sayOC1M5,
issetintheOC1MandacompareoccursonOC1,inadditiontothe
normaloperationthatusuallyoccurswhenOC1happens,thecontents
ofthecorrespondingbit,OC1D5,intheOC1Dregisterissenttothe
output compare pin, which in this case is OC3. Completely
independentoftheoperationofOC1,OC3couldbesettotoggleat
some time. Output Compare 3 could be programmed to be a PWM
outputwhereOutputCompare1establishestheperiodoftheoutput,
andOutputCompare3establishestheontime.
The applications for use of the coupled output compares are
unlimited.An accurate PWM is but one of several.These outputs
could be set up to establish an output sequence to drive a stepper
motor. The control of acceleration or deceleration of the motor is
easilycontrolledbymerelyselectingthebasetimeusedwithOC1.
Ifyourecall,theoutputcompare-basedPWMsystemdiscussed
fortheMC68HC05hadseverallimitations.Forexample,thatsystem
requiredthatthesystemoperatefrominterruptserviceroutines.The
latencytimeofinterruptservicewassolongthattheminimumpulse
width was considerably longer than one would expect.Also, the
interruptservicetimingdictatedthemaximumontimeforthepulse,
whichagainwasnotnearly100%.Letuslookathowwewoulddoa
PWMsystemwiththecoupledoutputcomparesystems.
#includehc11e9.h
/*ThisprogramwillprovideaPWMoutputtoOC3,or
PA5.Theperiodwillbetheintegervalue
foundinperiod,andtheontimewillbethe
integervaluefoundintime_on.Keeptime_on
lessthanperiod.*/
#definePERIOD0X1000
#defineTIME_ON0x0800
WORDperiod=PERIOD,time_on=TIME_ON;
main()
{
OC1M.OC1M7=ON;/*sentOC1outtoPA7*/
248 Chapter5 Programming Large 8-Bit Systems
OC1M.OC1M5=ON;/*coupleOC1toOC3*/
OC1D.OC1D5=ON;/*turnonOC3whenOC1occurs*/
TCTL1.OL3=ON;/*toggleOC3whenOC3occurs*/
PACTL.DDRA7=ON;/*makeOC1anoutputtoPA7*/
TOC1=TCNT+period;/*setOC1totheperiod*/
TOC3=TOC1+time_on;/*setOC3tothetimeon*/
FOREVER
{
if(TFLG1&OC1F)
{
TFLG1=OC1F;/*resetOC1interruptflag*/
TOC1+=period;
OC1D.OC1D7^=ON;/*toggletheoutput
Compare1bit*/
}
if(TFLG1&OC3F)
{
TFLG1=OC3F;/*resetOC3interruptflag*/
TOC3=TOC1+time_on;
}
}
}
Listing5-4:PulseWidthModulationRoutinePWM.C
Thisroutinestartswiththeinclusionoftheheaderfilehc11e9.h.
Itiscreatedasamainprogramtodemonstratehowitwillwork,but
shouldbechangedtoasubroutinelater.Theperiod andtime_on
intervalaredeclaredasglobalvariables.Theyaredeclaredtobethe
type WORD. WORD is a typedef synonym for the type unsigned
int.Themainprogrambeginswithaseriesoffiveinitialization
instructions.Thefirsttwoinstructions
OC1M.OC1M7=ON;
OC1M.OC1M5=ON;
declarethattheoutputofOC1shouldbesenttotheoutside,which
willbetopinPA7,andthatwheneverOC1occurs,OC3throughpin
PA5shouldbeactivated.
TimerOperations 249
Theinstruction
OC1D.OC1D5=ON;
indicatesthatwhenOC1occurs,OC3shouldbeturnedon.Thenext
instruction
TCTL1.OL3=ON;
causesOC3totogglewhenitstimeexpires,andtheinstruction
PSCTL1.DDRA7=ON;
setstheDDRA7 bitsothatsignalsfromOC1 willbesenttotheoutput
pinPA7.TOC1 andTOC3areinitializedbythenexttwoinstructions.
TOC1 is given a value of the contents of period greater than the
contentsofthetimercounterregisterTCNT.TOC3issetequaltothe
contentsofTOC1plusthetime_on.
The routine then enters an endless loop.Within this loop, two
flagsareexaminedandiftheyareset,theyarereset.Also,newtimes
arecalculatedforwhenthenextoutputcomparesshouldoccur.The
OC1FflaginTFLG1issetwheneveranOutputCompare1occurs.
Thisflagmustthenbereset.Theinstructionsequence
if(TFLG1&OC1F)
{
TFLG1=OC1F;
.
.
willaccomplishtherequiredassemblyinstructionstotestthebitand
resetitifthebitisturnedon.
The time of the next OC1 is calculated as TOC1+period. In
thisparticularinstance,thebitOC1D.OC1D7iscomplementedso
thattheoutputobservedonPA7willtogglewiththeoccurrenceof
eachOC1.TFLG1.OC3FistestedtodetermineifanOutputCompare
3hashappened.Ifithas,thisbitisreset,andTOC3issettoanew
valueofTOC1+time_on.Withthissetup, OC3PA5willgoon
wheneachOC1occurs,andwillberesetanamountcorresponding
totime_onafteritgoeson.Therefore,theperiodofthissystem
canbesetandtheontimecanbeanyvaluelessthantheperiod.
Normally,theoperationofaPWMistogenerateananalogsignal
thatispresentcontinuously.Theaboveprogramdoesperformthis
250 Chapter5 Programming Large 8-Bit Systems
task,butitalsoassumesthatthecomputerdoesnothavemuchelseto
do.Othertaskscouldbebuiltintotheaboveprogram,butitisabsolutely
necessarythattheprogramhaveacycletimethatisshorterthanthe
periodofthePWMsignal.IfthelooptimeoftheFOREVERloopisless
thanthePWMperiod,thenyoucanusetheabovesynchronousapproach.
Itmakesnodifferencewheninthecyclethatthetwoifstatementsin
theFOREVERloopareexecuted.Itisnecessarythattheybeexecuted
priortotheoccurrenceoftheOC1 thatdesignatestheendoftheperiod.
IfitbecomesnecessarytoincludesomuchcodeintheFOREVER loop
thatitisimpossibletoguaranteethatthelooptimewillalwaysbeless
thantheperiod,thenanasynchronousapproachshouldbeused.This
program was compiled and executed on an evaluation module. The
valueoftime_onwasadjustedtodeterminetherangeofoutputsthat
could be created with this program.The minimum time on must be
greaterthanthetimerequiredtoexecutethecode
if(TFLG1&OC3F)
{
TFLG1=OC3F;/*resetOC3interruptflag*/
TOC3=TOC1+time_on;
}
when OC3F is found on. The reason for this timing is that TOC3
must be updated after TOC1 is given a new value and the update
mustbecompletepriortothepassingoftime_on.Otherwise,the
periodofTOC1willpassbeforetheOC3willoccur.Thistimewas
measured,anditwasfoundtobe6clockcycles.Therefore,reliable
performanceisobtainedwithaminimumtimeonof6clockcycles.
Themaximumtimeonwasfoundtobe0xffewiththeabove
code. The output signal at 0xfff was on all of the time with no
singlecycleoffperiodastheprogramwouldindicate.
Aninterruptcanberequestedwheneveranoutputcompareoccurs.
We are servicing two output compares in this case. Ones initial
thoughtmightbetohavetwointerrupts,inthiscaseoneforOC1 and
one for OC3. Is this approach really necessary? If it is guaranteed
that the time_on parameter is always less than period, then an
approachthatcanbeusedistodelaytheresetoftheOC1flaguntil
theOC3hasoccurred.OC3willalwayshappenafterOC1.Theproblem
withthisapproachisthatOC3occursveryneartheendoftheperiod,
andtheremightnotbeenoughtimetoresettheOC1interruptflag
TimerOperations 251
priortotheexpirationoftheperiod.Thefollowingprogramcanbe
usedtodemonstratethisapproach:
#includehc11e9.h
/*ThisprogramwillprovideaPWMoutputtoOC3,or
PA5. Theperiodwillbetheintegervalue
foundinperiod,andtheontimewillbethe
integervaluefoundintime_on.Keeptime_on
lessthanperiod.Thisprogramusesasynchro-
nousserviceofoutputcompareoccurrences.*/
WORDperiod=0x1000,time_on=0x0800;
@portvoidOC3_Isr(void);/*needaprototypeforthe
ISR*/
main()
{
OC1M.OC1M7=ON;/*sentOC1touttoPA7*/
OC1M.OC1M5=ON;/*coupleOC1toOC3*/
TMSK1.OC3I=ON;/*enabletheOC3interrupt*/
OC1D.OC1D5=ON;/*turnonOC3whenOC1occurs*/
TCTL1.OL3=ON;/*toggleOC3whenOC3occurs*/
PACTL.DDRA7=ON;/*makeOC1anoutputtoPA7*/
TOC1=TCNT+period;/*setOC1totheperiod*/
TOC3=TOC1+time_on;/*setOC3tothetimeon*/
cli();/*enablethesysteminterrupts*/
FOREVER
{ /*waithereforever*/
}
}
@portvoidOC3_Isr(void)
{
TFLG1=OC1F;/*resetOC1interruptflag*/
TOC1+=period;
OC1D.OC1D7^=ON;/*toggletheoutput*/
TFLG1=OC3F;/*resetOC3interruptflag*/
TOC3=TOC1+time_on;
}
Listing5-5:SystemUsingAsynchronousTimeServicePWM1.C
252 Chapter5 Programming Large 8-Bit Systems
Noticethatthiscodeisverysimilartotheearlierprogramshown
inListing5-4.Theinterruptservicehandlingissetupbyuseofthe
@portconstructandthetwoaddedinstructionswhichfirstenable
theOC3interruptandthenenablethesysteminterrupts.Thecode
thatwascontainedwithintheFOREVER loopinListing5-4hasbeen
movedintotheinterruptserviceroutineinthisprogram.
Thisprogramwasrun,anditwasexperimentallydeterminedthat
the maximum value that can be allowed for time_on is 0xff0
whenperiodis0x1000.Thismaximumvalueindicatesthat16clock
cyclesor8microsecondsatan8-MHzcrystalisneededtoservice
the interrupt prior to the occurrence of an OC1.The minimum on
timefoundhereisslightlybetterthanfoundwiththecodeinListing
5-4.Inthiscase,theminimumontimeis1clockcycle,whichisthe
expectedminimumvalue.
Wehavealreadyseenthatasignificanttimeisrequiredtoprocess
aninterrupt,anditisusuallyimpossibletohaveanoutputeventoccur
duringtheinterruptserviceroutine.Withtheabovecodeitiseasyto
have a minimum on time of one clock cycle. This small time is
accomplishedbyhavingthesettingoftheoutputsignalnotbeattended
by an interrupt. The interrupt will occur when the output signal is
reset.Therefore,whenthecoupledoutputsignalwithOC1goeshigh,
theoutputcompareonthecoupledchannelwillhaveitseventevenif
thetimeisasshortasoneclockcyclebeyondtheoccurrenceofOC1.
AssumethatthecoupledchannelisOC3.Whentheeventoccurson
OC3, an interrupt will occur. In this interrupt service routine, both
OC1andOC3willhavetobesetuptooperateinthecorrectmanner.
Thisoperationhasaproblemwithlongontimes.Iftheeventassociated
withOC3occursafewclockcyclespriortotheoccurrenceoftheOC1
event,andtheinterruptiscausedbyOC3,thentheOC1set-upmight
not be completed when the next OC1 time arrives. In this case, the
wholebaseperiodwouldgooutofkilter,andtherewouldbeatleast
one cycle of the output that would be based on the timer overflow
cycleratherthanthedesiredtimebase.
Asisoftenfoundinengineeringoperations,thereisachoicethat
canbemade.IftheinterruptisbasedontheresettimeofthePWM
cycle,thenaminimumonperiodofonecyclecanbeachieved.With
thischoiceofoperation,themaximumontimewillbeseveralclock
cyclesperhaps20to30shortof100%on.Ontheotherhand,if
theinterruptisbasedonthesettimeofthePWMcycle,theminimum
TimerOperations 253
ontimeispoorandthemaximumontimecanbeuptooneclock
cycleshyofthebaseperiod.Ifyouwishtohavegoodperformance
at both ends, minimum on time at the same time as maximum on
time,youcanexaminetheontimeinyourprogramandifitisless
than50%ofthebasetimeperiod,controlthePWMbyaninterrupt
on reset. Otherwise, control the PWM by an interrupt on set.
Implementationofthecodeforthisapproachislefttotheexercises.
Output compare operations OC2 through OC4 and the
programmabletimersubsystemI4O5areallidentical.Theseversatile
timerscanbeusedtogeneratecomplextimingwaveformsthatare
usefulinkeepingtime,runningsteppermotors,etc.Theexamples
shownabovedemonstratehowtheseoutputscanbeconvertedintoa
PWM digital to analog output. The coupling between OC1 and the
other outputs provides an excellent mechanism for synchronizing
twotimeeventsfortheoutsidecircuitry.Ofcourse,thesesubsystems
cancreateeventsintime,buttheyarecompletelyunabletomeasure
time.Wewilllaterexaminetheanalysisoftimedeventsthatcanbe
measuredwiththehelpoftheinputcapturesubsystems.
EXERCISES
1.WritethecodethatwilldeterminefromtheontimeforthePWM
theinterruptoperationthatwillallowtheminimumoffandmaxi-
mumontimesimultaneously.
2.ModifythecodeinListing5.4toeliminatetheneedforacondi-
tionaltestif(OC1D.OC1D7==1).
InputCaptureSubsystems
OntheMC68HC11EXfamily,therearethreeinputcapturetimers
andonetimerthatcanbeprogrammedaseitheraninputcaptureor
an output compare. These sub-systems are used to measure time
interval.Thesame16-bittimerusedintheoutputcomparesystems
isusedtosupporttheinputcaptures.Whenaninputoccursononeof
theinputcapturepins,thevaluecontainedinthe16-bittimerissaved
inaregisterdesignatedforthatpin,aflagisset,andtheprocessor
canrequestaninterrupt.Withinputcaptures,wecanmeasureperiod
andhencefrequency(orspeed).Oneoftheleadingapplicationswhere
theinputcaptureisusedisinautomaticbrakingsystems.Weshall
254 Chapter5 Programming Large 8-Bit Systems
chooseasomewhatsimplersystemforanexample,butthegeneral
approachusedhereismuchthesameaswouldbeusedinthedesign
ofanautomaticbrakingsystem.
SupposethatwehaveaDCmotorthatisbeingcontrolledbyan
MC68HC11E9andwishtobeabletosetthespeedofthemotor.The
motor has a magnetic sensor whose output will cycle once each
rotationofthemotor.Todeterminethespeedofthemotor,wemust
measurethecycletimeoftheoutputfromthesensor.Letusexamine
theminimumspeedofthemotor.TheTCNTregisterisbeingclocked
atafrequencythatiseitherone-fourthofthecrystalfrequencyofthe
systemoritcanbealteredbyaprescalervalueofeither4,8,or16.
The 16-bit TCNT register will overflow every 65,536 clocks at its
input.Therefore,ifweusean8-MHzclock,thetimeroverflowperiod
will be 32.768 ms with no prescaler, 131.072 ms with a prescaler
valueof4,262.144mswithaprescalervalueof8,or524.288ms
withaprescalervalueof16.Theminimumspeedatwhichthemotor
canmoveandstillbedetectedunambiguouslymustbegreaterthan
onerevolutioninthetimeroverflowtime.Ifthemotorrotatesany
slowerthanthisvalue,thedifferencesintimesbetweentwoinputs
willbesuchthattheprogramcannottelliftheperiodislongerthan
oneTCNToverflowtimeoraveryshorttime.Itispossibletoextend
theminimumunambiguoustimethatcanbemeasuredbythesystem
throughtheuseofatimeroverflowinterrupt,butletsexaminean
approach without these steps and then look at the time extended
approachlater.
Themaximumpracticaltimetobemeasuredwiththedivide-by-16
prescaler is 500 milliseconds. The minimum rotation speed must be
greaterthan1revolutionper500millisecondsor120revolutionsper
minute. The motor that we will use in this example has a minimum
speedof1000rpm,sothattheprescalerneednotbeasgreatas16.We
willuseaprescalervalueoffour,whichwillprovideaboutaminimum
speedof500rpmsothatthereisasafetyfactorinourmeasurement.
Withthedivide-by-fourprescaler,theminimumtimethatcanbe
measuredis(4[crystaltobusfrequencydivision]*4[prescalerdivide
ratio]/8MHz[clockfrequency]),whichis2microseconds.Atthis
time interval, the maximum speed of the motor shaft that can be
measured is one revolution in 2 microseconds, or 500000 * 60
revolutionsperminute.Itisquiteclearthatsuchasystemisbetter
suitedtohandlehigh-speedoperationsthanlowspeed.Ifthereisno
TimerOperations 255
clearreasonotherwise,itisusuallybesttooperateacontrolsystem
atthemaximumpossiblespeed.Onereasonthatisimportantisthe
operationofthePWMDACthataccompaniestheoperationofthe
controlsystem.ItisusuallybesttohaveaPWMrunatthehighest
practical speed. If the PWM is slow, then conversion of the pulse
output from the system to a DC voltage is difficult and not very
accurateonaninstantaneousbasis.
Thefollowingcodesegmentmightbeusedasaninterruptservice
routinetohandletheinputcaptureoperation.
@portvoidIC1_Isr(void)
{
TFLG1=IC1F;/*resetIC1interruptflag*/
measured_period=TIC1-time1;
time1=TIC1;
}
Hereitisassumedthatthemaximumtimebetweeninputcapturesis
lessthanthetimeofatimeroverflow.Inthiscase,thetimeismerely
the difference between the current value and the preceding value
whichisstoredintime1.
Thisapproachhasonlyonemajorproblem.Mostinputssuchas
willbeobtainedfromreedswitches,pushbuttons,andevenoptical
interrupttypedeviceswillbenoisywhenthecontactisclosed.This
noiseiscalledswitchbounce,anditwillalwaysbepresentwitha
contactclosure.Therefore,theswitchmustbedebouncedinsome
mannerbeforeitsdataarereliable.
The most common way of debouncing a contact closure is to
observetheclosure,andthenwaitatimeandobserveifthecontactis
stillclosed.Ifclosed,itisassumedthatthecontactisgood;otherwise,
anotherwaitperiodinallowedtoelapseandthecontactisobserved
again.Thisprocedureisrepeateduntilthecontactisclosedonapair
ofsuccessiveobservations.Onlythenisitassumedthatthecontactis
closed. The time between observations is the subject of much
engineeringdebate.Oftenthedesignercanplaceanoscilloscopeon
the contact and repeatedly close and open it. With proper
synchronizationoftheinstrument,itispossibletoseethesignalcaused
bythebouncingcontacts.Ifthistimecanbemeasured,thenhaving
adebouncetimeofperhapstwicethebouncetimewillprobablygive
asafetimeforthedebounce.However,youshouldnotassumethat
256 Chapter5 Programming Large 8-Bit Systems
this value will be correct over the lifetime of the contact. As the
mechanismages,itispossiblethatthebouncetimewillchange,and
itwillalwayschangeintheworstpossibleway.Therefore,besafe,
andkeepthedebouncetimeatleasttwicethebouncetime,andperhaps
longerforthesakeofsafety.Therangeofvaluesusedfordebounce
timesrangesfrom2to30milliseconds.
Thissystemismeasuringthetimeofaninput.Howcanwestick
anarbitrarytimefordebounceintoourmeasurementequationandbe
reliable?Itispossibletodothedebounceandnothavethetimeaspart
ofthemeasuredinterval.Thecontactclosurewillcauseanobservable
input.Ourrealconcernwithdebounceistoguaranteethatnoadditional
inputsoccuraftertheinitialinputhasbeenprocessed.Therefore,we
canimplementadebouncebymerelynotre-enablingtheinputcapture
interruptuntilthedebouncetimehaspassed.Thisway,thetimeofthe
firstedgeseenintheinputsequenceisprocessed,andallotherinputs
caused by bounce will not be processed because the input capture
interruptisdisabled.Thetimethattheinterruptisdisabledcanalsobe
adjustedtomeettheparticularneedsoftheprogram.Forexample,in
thesystemwewillconstructbelow,thespeedismeasuredwithareed
switchandamagnetonthemotorshaft.Thecircuitwillbebuiltsuch
thattheclosingoftheswitchwillcauseavoltagetofallfrom+12volts
to0volts.Thereisaresistorbetweenthe12-voltsupplyandtheswitch.
Thebottomsideoftheswitchisgrounded,andastheswitchisclosed
andopened,thevoltagemeasuredatthetopoftheswitchwillchange
from12voltstoground.Whentheswitchcloses,itisexpectedthatit
will bounce and the voltage will chatter between 0 and 12 volts.
Surprisingly,theopeningoftheswitch,whileitwillexhibitlessbounce,
willalsogeneratetheseunwantedsignals.Ifwewanttoblockoutall
oftheerrorsignalsthatcanbeintroducedbythebounce,itisnecessary
thatthetimefollowingtheinitialsignaldropbeprotected,aswellasa
timearoundthesignalrisethatoccursmidwayduringtheshaftrotation.
Inthefirstexample,wewillprovideafixedtimeforthedebounce.
Laterwhentheprogramismeasuringthespeedofthemotor,wewill
provide a debounce time that is somewhat longer than one half the
measuredperiodtoblockoutallbouncesignalsthatoccuronboththe
risingandfallingedgeoftheinputsignal.
Theinputcapturesubsystemwillcaptureanyspecifiedinputwhen
enabled.Theseinputsarecapturedwhethertheinterruptsareenabled
ornot.Inotherwords,ifaninputoccursaftertheonethatwascaptured,
TimerOperations 257
itwillbecapturedandtheoriginalsavedvaluewillbelost.Therefore,
the very first operation in the interrupt service routine for an input
capture should be to save the contents of the input capture register.
Then subsequent inputs from bounces will not affect the measured
time.Anotherproblemcanoccur,however.Wheneveraninputoccurs
onaninputcaptureline,notonlyarethetimedatacaptured,butalso,
theappropriateinputcaptureinterruptflagisset.Ifthisflagisset,an
interrupt will be requested whenever the input capture interrupt is
enabled.Therefore,inthedebounceinterruptroutine,theinputcapture
interruptflagforthechannelbeingusedshouldalsobereset.
Westillmustcontrolthetimethattheinputcaptureisdisabled.How
thiscontrolisimplementeddependsonthesystem.Ifthesystemisnot
busy,onemightcalculateavaluethatequalsthecontentsoftheTCR
plusthenumberoftimercounterticksinthedebouncetime.Thisvalue
could then be compared with the contents of the TCR, and when the
TCRequalsthecalculatedvalue,theinputcaptureinterruptwouldbe
reenabled,andcontrolreturnedtotheinterruptedprogram.Thisapproach
providesanaccuratedebouncetime,buttheprocessorisdevotedentirely
tothemeasurementofthistimeduringthedebouncetime.Itisnotwise
totieupamicrocontrollerformillisecondsatatimeandlockoutother
importantactionsthatmighttakeplaceduringthattime.
Ifallothereventsthatareoccurringwithinthemicrocontroller
are interrupt driven, the programmer could re-enable the system
interruptspriortoenteringthedelaytime.Thisapproachwouldat
leastkeeptheprocessoravailableforotherasynchronouseventsthat
mightoccurduringthedebounceperiod.Yetanotherapproachwould
betodisabletheinputcaptureinterruptandwithintheapplications
program,provideatimemeasurementthatwouldhavetoexpirebefore
theinputcaptureinterruptisreenabled.Bothofthesemethodscan
beimplementedwithouttheuseofanoutputcompare.Ifanoutput
compareisavailable,itcouldbeusedtoexecutethedebouncetimeout.
Thisoutputcomparewouldbesetupintheinputcaptureinterrupt
serviceroutine.Alsowithintheinputcaptureinterruptserviceroutine,
theinputcaptureinterruptwouldbedisabled.Theoutputcompare
interruptserviceroutinewoulddisabletheoutputcompareoperation
andreenabletheinputcapture.Thisapproachisbyfarthebest,and
willbeusedhere.Thecodeforthismethodofdebounceisincluded
in the listing shown in Listing 5-6. In this case, a fixed debounce
timeisused.Wewillseethevariabledebouncetimeinalaterprogram.
258 Chapter5 Programming Large 8-Bit Systems
A beginning program or framework from which to build this
applicationisshowninListing5-6.Allthisprogramcontainsisthe
setupoftheinterruptsandtheinterruptserviceroutines.Inputcapture
1willserveasinputfromthemotorshaftencoder.Themotorwillbe
controlledbyaPWMsignal.Thissignalwillbefilteredtoprovidea
DCsignalthatcandrivethemotor.AswiththeMC68HC05programs,
thiscodeisbrokenintothreebasicparts:1)theinitializationsection,
2)theapplicationssection,and3)theasynchronousservicesection.
Inthiscase,thereisnoapplicationssection,soitisdesignatedbya
FOREVERcommandfollowedbyanemptyblock.
TheprogrambeginswiththeinclusionoftheHC11E9.H header
file.Immediatelyfollowingthisentryaretheprototypeentriesfor
alloftheinterruptserviceroutines.Thedeclarationsoftheglobal
variablesfollows.Thefirstsetofvariablesareallassociatedwiththe
input capture, and the second line of variables controls the output
compareportionoftheprogram.
Noticethatthebitset-upinstructionsareallgroupedsothatthe
bitsfromeachregisteraresetinthesamelocation.Itisnotnecessary
togrouptheseinstructions;however,iftheyaregroupedbyregister
as is done here, the compiler will use a single bit manipulation
instruction to set all of the bits in each register. The first 8-bit
manipulationinstructionsinthefollowingcodewillrequireonlysix
assemblyinstructionsastheyaregrouped.
#includehc11e9.h
#defineMS3_DEBOUNCE1500
#definePERIOD0X1000
#defineTIME_ON0x0800
@portvoidIC1_Isr(void);
@portvoidOC2_Isr(void);
@portvoidOC3_Isr(void);
WORDmeasured_period,time1,delpc;
WORDPWM_period=PERIOD,time_on=TIME_ON;
main()
{
TCTL2.EDG1B=ON;/*capturefallingedgeonly*/
TimerOperations 259
OC1M.OC1M7=ON;/*sentOC1touttoPA7*/
OC1M.OC1M5=ON;/*coupleOC1toOC3*/
TMSK1.OC3I=ON;/*enabletheOC3interrupt*/
TMSK1.IC1I=ON;/*enabletheIC1interrupt*/
OC1D.OC1D5=ON;/*turnonOC3whenOC1occurs*/
TCTL1.OL3=ON; /*toggleOC3whenOC3occurs*/
PACTL.DDRA7=ON;/*makeOC1anoutputtoPA7*/
TOC1=TCNT+PWM_period;/*setOC1totheperiod*/
TOC3=TOC1+time_on;/*setOC3timeon*/
cli(); /*enablethesysteminterrupts*/
FOREVER
{
/*putapplicationcodehere*/
}
}
@portvoidIC1_Isr(void)
{
time1=TIC1;
TFLG1=IC1F;/*resetIC1interruptflag*/
measured_period=TIC1-time1;
TOC2=TCNT+MS3_DEBOUNCE;/*3msdebouncetime*/
TMSK1.IC1I=OFF;/*disableIC1interrupt*/
TMSK1.OC2I=ON;/*enableOC2interrupt*/
}
@portvoidOC2_Isr(void)
{
TFLG1=IC1F|OC2F;/*resetIC1&OC2interruptflag*/
TMSK1.OC2I=OFF;/*disableOC2interrupt*/
TMSK1.IC1I=ON;/*enableIC1interrupt*/
}
@portvoidOC3_Isr(void)
{
TFLG1=OC1F;/*resetOC1interruptflag*/
TOC1+=PWM_period;
OC1D.OC1D7^=ON;
260 Chapter5 Programming Large 8-Bit Systems
TFLG1=OC3F;/*resetOC3interruptflag*/
TOC3=TOC1+time_on;
}
Listing5-6:MotorControlProgramFramework
The interrupt service routine for IC1 resets the IC1F bit in the
TFLG1register.Thentheelapsedtimefromthelastinputcapturetime
iscalculated.Theresultofthiscalculationissavedinperiod1which
isthecurrentelapsedtimerequiredforthemotortorotateonerevolution.
Attheendofthiscalculation,thecontentsoftheinputcaptureregisteris
savedintime1tobeusedastheoldtimeinthenextcalculation.
ThePWMoutputfromOC3willbeusedtodrivemotor1whose
shaft sensor is fed into IC1.The value in speed will be the desired
speedofthemotorinrevolutionsperminute.Therangeofthisnumber
willbe1000<=RPM<=10000,anditwillhavetobeputinplacethrough
adebuggerforthistest.Thisrangeofmotorspeedwaschosentosat-
isfythespeedofasmallDCmotorusedinthefinalsystem.Letusplan
aservotypeoperationwherethemotorisdrivenbyafeedbackloop
thatiscontrolledbythespeederror.Therefore,withintheapplications
loop,theremustbecodetocheckandcontrolthePWMsignaltoforce
thespeed1parametertomatchtheinputspeedparameter.
TheinputspeedismeasuredinRPM,andthevaluesmeasuredby
themicrocontrollerarealltimes.Aquestionthatshouldbeconsideredis
whetherthenumberplacedinspeed1 willactuallybetimesorshould
thisnumberbeRPM.Tocalculatethetime,notethatthereisoneinterrupt
perrevolutionoftheshaftandoneminuteis60seconds,soRPM/60will
berevolutionspersecond.Whatweneedisthenumberofbuscyclesin
thetimecorrespondingtothisperiod.Withaprescalercountoffour,the
clockingspeedoftheTCNTregisterisonecounteverytwomicroseconds,
or500,000countspersecond.Therefore,theconversionfromRPMto
timeforarevolutionoftheshaftinbuscyclecountsis
500000*60 30000000
Counts= =
RPM RPM
At 3000 RPM, the count value will be 10000 while at 16000
RPM the count value will be 1875. These numeric values can be
handledbythetimersystemintheMC68HC11.
The above expression can be used to calculate RPM from the
countvalueas
TimerOperations 261
30000000
RPM=
Counts
Neithercalculationisconvenientinamicrocontroller.Thenumerator
islargerthananintbutsmallerthanalong.BothCountsand
RPMhavearangethatcanbecontainedinanint.Onewouldexpect
thattheconversiontotimeshouldbedoneontheinputspeed.That
way,thedivisionwouldbedoneonlyonceforeachspeedsetting.If
themeasuredtimeswereconvertedtoRPMeachtimeatimewere
measured,thecomputerprogramwouldbeloadedwithcomplicated
divisionsinitsrealtimeapplicationportion.Butletsexaminethe
natureoftheerrorwiththedifferenttypesofmeasures.Supposethe
inputRPMwereconvertedtotimeandthemeasurementswerebased
ontime.Thentheerrorsignal,whichisthedifferencebetweenthe
measured value and the desired value, would have a wrong sense.
Thatisifthemotorismovingtooslowly,thentheerrorsignalwould
benegative,whichwouldcausethemotortogoevenslower.Ifthe
calculationweredonebasedonRPMandthemotorweregoingtoo
slow,theerrorsignalwouldbepositive.Inthiscase,thecontrolwould
drivethemotorfasterwhichistheneededcorrection.
The difficulty with the time-based system could be solved by
usingthenegativevalueoftheerrorsignalforthefeedbackcontrol.
Asimpleanalysiswillshowthepotentialproblemwiththisapproach.
Supposethatweworkwithtwocounts,C
d
andC .Letususethe
m
valueKfortheconstantintheaboveequation.Therefore,
j 1 1 \
e = C
d
C = K
,

( m
RPM
d (
RPM
m ,
Theerrorsignalisseentobe
j RPM RPM
d
\
m
e =K
, (
RPM
d
*RPM
( m ,
Whenthetwospeedsarenearlythesame,thisexpressionisvery
nearlyproporstionaltothedifferencebetweenthetwospeeds.However,
whenoneofthespeedsdeviatessignificantlyfromtheother,itwill
causetheresultanterrorsignaltobelesssensitivetodifferencethan
wouldbeexpected.Also,thereistheproblemthatoccursifthemotor
isstoppedandtheerrorsignalinthatcaseisundefined.
262 Chapter5 Programming Large 8-Bit Systems
IfthecountsareconvertedtoRPMpriortocalculationoftheerror
signal, the reduction of sensitivity for large errors would not be a
problem.Theproblemthatoccurswhenthemotorisstoppedstillexists.
Inthiscase,noinputcapturewouldoccurwhenthemotorisnotrotating,
andthecountvaluewouldbeundefined.Thereseemstobenoclear-cut
reason to choose the time or the velocity measurement. Each has
advantagesandeachhasdrawbacks.Thedrawbacksareaboutthesame
for each, so we will choose the case that has the simplest program.
Therefore,thetime-basedorcount-basedsystemwillbeused.
Nowcomestheinterestingproblemofthecalculationof3000000/
RPM.Eachtimethedesiredspeedofthemotorisinputtothesystem,
thiscalculationmustbecompleted.Thestraightforwardcalculation
ofthisvaluewillyieldcodeasfollows:
#includehc11e9.h
WORDcount(WORDRPM)
{
unsignedlongnum=30000000;
returnnum/RPM;
}
Thelistingfileofthecompiledversionofthisfunctionis
1;CompilateurCpourMC68HC11(COSMIC-France)
2 .includemacro.h11"
3 .list+
4 .psect_text
5;1#includehc11e9.h
6 .psect_data
7_Register_Set:
800001000 .word4096
9 ; 2
10; 3WORDcount(WORDRPM)
11; 4{
12 .psect_text
13 _count:
140000BD0000 jsr c_kents
TimerOperations 263
1500030C.byte12
16.set OFST=12
17; 5unsignedlongnum=120000000;
180004CC0E00ldd#3584
190007ED0AstdOFST-2,x
200009CC0727ldd#1831
21000CED08stdOFST-4,x
22;6
23;7returnnum/RPM;
24000EEC0ClddOFST+0,x
2500106F02clr2,x
2600126F03clr3,x
270014ED06stdOFST-6,x
280016EC02 ldd2,x
290018ED04 stdOFST-8,x
30001AEC08 lddOFST-4,x
31001CED02 std2,x
32001EEC00 ldd0,x
330020C3FFF7 addd#-9
340023188F xgdy
350025EC0A lddOFST-2,x
360027BD0000 jsrc_ludv
37002AAE00 lds0,x
38002C38 pulx
39002D39 rts
40;8}
41;9
42.public_count
43.public_Register_Set
44.external c_kents
45.external c_ludv
46.end
This function requires 0x2d bytes (45 bytes) of code and that
doesnotcountthefunctionsc_ludvandc_kentsthatmustbe
linkedtothisfunction.Ourinnocuouslittleone-linepieceofcode
createsaratherformidablepieceofassemblycode.Ifatallpossible,
itwouldbedesirabletoshortenthisfunction.Aslightmodification
oftheabovefunctioncodeis
264 Chapter5 Programming Large 8-Bit Systems
#includehc11e9.h
WORDcount(WORDRPM)
{
return30000000lu/RPM;
}
Thecompiledversionofthisprogramis
1;CompilateurCpourMC68HC11(COSMIC-France)
2 .includemacro.h11"
3 .list+
4 .psect_text
5;1#includehc11e9.h
6 .psect _data
7_Register_Set:
800001000 .word4096
9 ; 2
10;3WORDcount(WORDRPM)
11;4{
12 .psect _text
13 _count:
140000BD0000 jsr c_kents
15000308 .byte8
16 .setOFST=8
17;5 return 120000000lu/RPM;
180004EC08 lddOFST+0,x
1900066F02 clr2,x
2000086F03 clr3,x
21000AED06 stdOFST-2,x
22000CEC02 ldd2,x
23000EED04 stdOFST-4,x
240010CC0727 ldd #1831
250013ED02 std2,x
260015EC00 ldd0,x
270017C3FFFB addd#-5
28001A188F xgdy
29001CCC0E00 ldd #3584
30001FBD0000 jsr c_ludv
TimerOperations 265
310022AE00 lds0,x
32002438 pulx
33002539 rts
34;6}
35;7
36.public_count
37.public_Register_Set
38.external c_kents
39.external c_ludv
40.end
Notethatthisversiondiffersfromthefirstonlyinthatthenumber
30000000isnotcreatedinadeclaration,butratheriscreatedinline
whenitisneeded.Thisversionrequires37bytesofcode.
Thepurposeofthisexerciseistodemonstratethatthereareusually
manydifferentwaysthatanypartofaprogramcanbeapproached.
Iftheprogrammergrabsthefirstideaandplodsthroughwithoutany
carefulexaminationofthecodebeinggeneratedbythecompiler,the
programwillalmostalwayssuffer.Theassemblylistingsofprograms
shouldbeexamined,andwhereitseemsasifthecompileriscreating
clumsycode,anewapproachshouldbeconsidered.WritingCcode
foramicrocontrollerisajointexercisebytheprogrammerandthe
compilertocreatethemostefficientoverallprogram.
Letsreturntotheproblem:wewishtosetthespeedofamotorand
themeasurablecontrolsignalisthetimeofarevolution.Mostservotype
devicesworktopositionanoutput.Oursmustsetaspeedwhichisa
differentproblemfrommost.TheinputwillbeanRPMwhichwillbe
convertedtoatime.Oursystemmustcomparethedesiredtimewiththe
measuredtimeandcorrectthespeedtomakethetwotimesmatch.A
signaltodrivethemotorwillbegeneratedbasedonthedesiredtime,
and this signal will be adjusted by the error signal calculated as the
differencebetweenthemeasuredtimeandthedesiredtime.Thefollowing
pseudocodesequencewillaccomplishthedesiredoperation.
FOREVER
{
do
converttotime;
calculatetherequiredPWMoutputcount;
applycalculatedtimeerrortoPWMcount;
266 Chapter5 Programming Large 8-Bit Systems
readinthemotorspeed;
while(motorspeeddoesnotchange);
}
Forthemoment,letusdefertheproblemofgettingthedesiredmotor
speed.Thisvaluewillbeconvertedtotimebyuseofthecount()
routine and will be saved in motor_period. Next, we need to
calculatetherequiredmotorvoltage.Forthiscalculation,letusrevert
toanexperimentaltechniquethatcanbeusedusefully.Anopenloop
systemwassetuptotesttheoperationofthemotorsystem.Several
input values were entered, and the performance of the motor was
recorded.Table5-2showstheresultofthesemeasurements.
PWM_Count PWM_Count icapperiod periodms voltage RPM
Hex decimal counts
0x700 1792 15812 31.62 2.186 1897
0x780 1920 11405 22.81 2.341 2630
0x800 2048 8581 17.17 2.498 3494
0880 2176 6841 13.68 2.653 4385
0x900 2304 5616 11.23 2.809 5342
0x980 2432 4759 9.52 2.964 6304
0xa00 2560 4059 8.12 3.118 7391
0xa80 2688 3530 7.06 3.273 8499
0xb00 2816 3085 6.17 3.424 9724
0xb80 2944 2736 5.47 3.578 10965
Table5-2:MotorPerformanceMeasurements
The data for this table were gathered by the use of an
M68HC11EVM and a simple motor driver. This driver is a
demonstrationboardprovidedbyMotorolatoshowtheuseofthe
MC33033pulsewidthmotordriverandtheMPM3002FETmotor
driverHbridge.AsmallDCmotorwithaspeedrangeof1000to
11000rpmwasmountedontheboard,andtheappropriatecircuitry
was added to interface the board to the computer. This interface
consistedofasimpleRCintegratortoreceivethePWMsignalfrom
thecomputerboardandacircuittomeasuretherotationofthemotor.
This latter circuit was quite crude. A magnetic reed switch was
mountednearthemotorshaftandamagnetcementedtotheshaft.
Foreachrotationoftheshaft,thereedswitchwouldcloseandopen
onetime.Aresistorwasconnectedbetweenthe12voltsofthemotor
driverandonesideoftheswitch;theothersideoftheswitchwas
TimerOperations 267
grounded.Therefore,duringeachrotationthetopsideoftheswitch
wouldjumpfrom12voltsto0voltsandback.Thisvoltageislarger
thanthemaximuminputforthemicrocontroller,sothe12voltsquare
wavewasclampedtoamaximumhighvaluewitharesistoranda
diodeconnectedtothe+5voltpowersupplyoftheEVM11board.
TheschematicdiagramforthistestsetupisshowninFigure5-2and
aphotographofthecompletesystemisshowninFigure5-3.
M6811C11EVM
OC1
OC3
IC1
PWMOutput
Time-Input
33k
1
Ping
33033
+5V
33k
8.2k
.01
12V
Magnet
Switch
MC33033-MPM3002MotorDrive
Figure5-2:SchematicDiagramofMotorDriverTestCircuit
Figure5-3:PhotographOf
AssembledMotorDriverTestCircuit.
268 Chapter5 Programming Large 8-Bit Systems
The program used to obtain the data in the above table was a
slight modification of the motor control program listing given in
Listing5-6.Theonlychangeinthisprogramwasthatthefunction
@portvoidIC1_Isr(void)fromListing5-7wasused.This
routinestoresinthelocationmeasured_periodavalueequalto
theaverageofthelasteightmeasuredperiods.
Forseveralreasons,areedswitchisprobablytheworstexample
ofaninputsensorthatyoucanfindforamicrocontroller.Ichosethis
inputbecauseitisthepoorest,andtheresulthasbeensatisfactory.
Withreedswitches,thereareseriousbounceproblemsonboththe
risingandfallingedgesofthesignals.Thelifeexpectancyforareed
switchisrelativelysmall,abouttenmillionclosures.Duringthecourse
ofpreparingthistext,Ibrokeonereedswitchandhadprobablya
total of several hours of service out of the two used for these
experiments. In practice, it is recommended that rotational
measurementsbemadewithopticalinterrupters.Donot,however,
think that an optical interrupter is free from bounce problems.An
opticalinterrupterwillexhibitbothbounceandalsoarelativelyslow
risetime.Insuchacase,itisnecessarytouseasoftwaredebounce
technique and also an external Schmidt trigger circuit to create a
quickandstablerisetimethatcanbecapturedbythemicrocontroller.
Thedatafortheabovetableweremeasuredonthecircuitshownin
Figure5-2.ItwasfoundthatthePWMtovoltageconversionwasvery
accurateandrepeatablewithmanychangesinthesystem.Forexample,
theprescalervaluewaschangedfromthevalueof4discussedabove
to2andupto16.NodifferencecouldbenotedinthePWMtovoltage
conversionoverthisrange.Also,theinputcapturevalueswerequite
stable.TheprograminListing5-6wascompiledandusedtocomplete
themeasurements.ThePWM_countvaluewaschangedmanuallyover
therangeofvaluesshownabove.Thevalueforicapperiodisthevalue
foundinmeasured_periodintheprogram.Thevoltagemeasured
wastheintegratedvaluethatwassentintotheinputoftheMC33033
motordriver.TheRPMwascalculatedas
60000
RPM=
measured_period
DatafromthistableareusedtocreateanequationthatrelatesRPM
to the PWM_count.This equation will be used in the program to
TimerOperations 269
closetheloopandregulatethemotorspeed.Therelationthatcanbe
derivedfromtheabovedatais
RPM+12528
PWM_count=
7.875
This expression is accurate to about 1% across the range of
interest.Themeasureddataistheinputcapturecount,whichwewill
call p. What we must do is to calculate a new value for the
PWM_countfromameasuredp.Anerrorinpiscalledpandthis
expressionmeansachangeinp.ThePWM_countwillbedesignated
aspcandalsomeansachangeinpc.Weshallnowattempttoarrive
atanequationthatexpressesthenecessarychangeinpctocorrect
foranerrorinp.Theerrorinpisthedifferencebetweenthedesired
cycletimeandthemeasuredcycletime.RPMintheaboveexpression
isconvertedtocycletimepbynotingthattheRPMis60000/shaft
cycletimeinmilliseconds,andthattheclockisticking500timesper
millisecond.Therefore,wehave
1 j 12528+60000*500\
p =
c , (
7.875
(
p
,
Ifthereisaerrorinthecycletimesay,p,thenthechangein
pc,pc,isseentobe
3809500
p +p =1591+
c c
p+p
This expression, after some simplification and approximation
reducesto
p = 3809500+
p
c
2
(5-1)
p
Thisvaluecalculatedbytheaboveexpressionwillbeusedtochange
the PWM_count that drives the motor. The data contained in
measured_periodareplacedtherebytheinputcaptureinterrupt
serviceroutine.Itisassumedthatthedatatherearealwayscurrent.
The calculation to determine the PWM_count correction is
substantial. We shall use this approach here to determine the
correction,butrecognizethatthereisanotherapproachthatprobably
requireslesstotalcalculation.Thisapproachistousealookuptable.
270 Chapter5 Programming Large 8-Bit Systems
Wewillseethelook-uptableinsomedetailinChapter6.
Wewillprobablyrunintooverflowproblemsifcareisnotexercised
inthecalculationofthecorrectionp
c
.InEquation5-1above,pisthe
timeofashaftrotationinmilliseconds.Thisnumbercanvaryfrom1000
to20000dependingonthemotorspeed.Thebestapproachwecould
useistodividetheconstant-3809500bythevalueofp.Thenmultiply
theresultbypandfinallydividetheresultbypasecondtime.This
approachwillminimizetheoverflowproblems.Intheexpressionbe-
low,pisthemeasured_period,pcisthePWM_count,andp is
thecalculateddifferencemotor_period-measured_period.
FOREVER
{
if(old_motor_speed!=motor_speed)
{
motor_period=30000000lu/motor_speed;
old_motor_speed=motor_speed;
PWM_count=((motor_speed+12528)/63)*8;
PWM_count=limit(PWM_count);
delpc=(3809500/motor_period);
delpc=delpc*(motor_period-measured_period)/p;
PWM_count-=delpc;
/*readinthemotorspeed;*/
}
}
Recall that division by 7.875 is needed in the calculation of
PWM_Count.Thisfloating-pointoperationisavoidedbydividing
theexpressionby63/8.Mostoften,floatingpointoperationscanbe
approximatedbyintegeroperationswithsufficientaccuracy.
Itwasmentionedearlierthatitispossibletoextendthemaximum
measurabletimetosomethinggreaterthanthetimerequiredtoclock
thetimercounterregister65535times.Ifthelongesttimeexceeds
thisvalue,thetimeroverflowinterruptcanbeusedtoanadvantage.
Supposethatyouwanttomeasurealongtimewithinputcapture1.
When this measurement is started, the value in the TCNT will be
saved,andthetimeroverflowinterruptwillbeenabled.Alsoacounter
willberesettozero.Inthetimeroverflowinterruptserviceroutine,
the counter will be incremented. Eventually, an input capture will
occur,andthetimebetweeninputsiscalculatedasthetimeremaining
TimerOperations 271
prior to the first TOI, plus 65535 times the number of TOIs that
haveoccurred,plusthetimeindicatedintheinputcaptureregister.
Withaschemeofthisnature,thereisessentiallynolimittothelength
of time that can be measured accurately. The resolution of this
measurementisthetimeincrementoftheprescaleroutput.
A velocity servo is a particularly difficult application. Remember
thatvelocityormotorspeedisthederivativeofposition.Anyderivative
operationispronetonoise,andthesuccessfulservomustbecarefully
puttogether.Forexample,theequationcalculatedabovetodetermine
thefeedbacktermisessentialtotheproperoperationofthesystem.An
interestingchallengeistotrytoduplicatetheoperationofthesystem
describedherewithanormalgaintypefeedback.Eventhoughtheprogram
seemstobemessy,thisapproachwillwork,andmostotherapproaches
giveyouawildlyhuntingoroscillatingsystem.Thecalculationofthe
properfeedbackvaluewillavoidmanyoftheseproblems.
Anotherproblemareawillbefound.IftheaboveFOREVERloopis
allowedtorunwithoutanytimecontrol,thecomputerwillbecalculating
a new feedback value many times before the effect of an earlier
calculationwillbeseeninthesystemperformance.Thisoperationagain
causesthesystemtobecomeunstable,andusuallythesystemnever
findsthefinalvaluebuthuntsoversomewiderangearoundit.This
operation can be corrected by slowing the rate at which feedback
correctionsarecalculated.Inparticular,severalrateshavebeentested,
anditwasfoundthatastable,accuratesystemwouldbeobtainedwith
anewfeedbackvaluecalculatedeachquarterofasecond.Thistime
controlisshowninthelistingbelow.Themainapplicationprogramis
brokenintotwoparts:thefirstpartisthecodethatwillbeexecuted
wheneverthemotorspeedischangedandthesecondpartisthecode
thatwillalterthePWM_countwhichisthefeedbackportionofthe
program.Thefirstportionisexecutedunderthecontrolofanifstatement
if(old_motor_speed!=motor_speed)
Thereisnomeanstochangethemotorspeedinthisprogram,and
this change will be introduced in the next section. Therefore, it is
expectedthattheportionofthecodecontrolledbythisifstatement
willexecutethefirsttimetheprogramisexecuted,anditshouldnever
beexecutedagainuntilthesystemisreset.Thesecondifstatement
if(tick)
272 Chapter5 Programming Large 8-Bit Systems
willexecuteitscontrolcodeeachtimetickisTRUE.tickisini-
tializedtoTRUEwhenitiscreated,anditissettoFALSEeachtime
the if (tick) routine is entered in the application program. If
yougototheendofListing5-7,youwillfindthattickisresetto
TRUE about each quarter of a second in the PWM timer routine.
This sequence will cause the feedback calculation to be executed
abouteachquarterofasecond.
TheinitializationportionoftheprogramshowninListing5-7is
littlechangedfromthatoftheoneshowninListing5-6.Asmentioned
above, we have added an application section that contains the
calculations to control the motor speed.Also, there is one simple
functionthatisusedbytheapplicationsection.
#includehc11e9.h
#defineDIVIDE_8_SHIFT 3
#defineCOUNT_8 8
#defineCOUNT_MAX 3300
#defineCOUNT_MIN 1600
#defineCOUNT_ONE_QUARTER 32
#definePERIOD 0X1000
#defineTIME_ON 0x0800
#defineIMPOSSIBLE 3500
#defineTOO_LOW 100
@portvoidIC1_Isr(void);
@portvoidOC2_Isr(void);
@portvoidOC3_Isr(void);
longlimit(long);
longmeasured_period,delpc;
WORDtime1,time2,motor_period,
motor_speed=IMPOSSIBLE;
WORDold_motor_speed=TOO_LOW,rpm,mparray[COUNT_8];
longPWM_period=PERIOD,PWM_count=TIME_ON;
inttick=TRUE,count=0;
main()
{
TimerOperations 273
/*Theinitializationportionoftheprogram*/
TCTL2.EDG1B=ON;/*capturefallingedgeonly*/
OC1M.OC1M7=ON;/*sentOC1outtoPA7*/
OC1M.OC1M5=ON;/*coupleOC1toOC3*/
TMSK1.OC3I=ON;/*enabletheOC3interrupt*/
TMSK1.IC1I=ON;/*enabletheIC1interrupt*/
OC1D.OC1D5=ON;/*turnonOC3withOC1*/
TCTL1.OL3=ON;/*toggleOC3whenOC3occurs*/
PACTL.DDRA7=ON;/*makeOC1anoutputtoPA7*/
TOC1=TCNT+PWM_period;/*setOC1*/
TOC3=TOC1+PWM_count;/*setOC3timeon*/
cli();/*enablethesysteminterrupts*/
/*theapplicationsportionoftheprogram*/
FOREVER
{ /*Allofthenumbersusedbelowarederived
inthetext*/
if(old_motor_speed!=motor_speed)
{
motor_period=30000000Lu/motor_speed;
old_motor_speed=motor_speed;
PWM_count=((motor_speed+12528)/63)*8;
PWM_count=limit(PWM_count);
}
if(tick)
{
tick=FALSE;
delpc=(3809500Lu/motor_period);
delpc=delpc*
(motor_period-measured_period)/
motor_period;
PWM_count-=delpc;
PWM_count=limit(PWM_count);
rpm=30000000L/measured_period;
}
/*inputthenewmotorspeed*/
}
}
/*functionsofthemainprogram*/
274 Chapter5 Programming Large 8-Bit Systems
/*rangeofacceptablePWM_countis1600 to 3300*/
longlimit(longx)
{
if(x<COUNT_MIN)
returnCOUNT_MIN;
elseif(x>COUNT_MAX)
returnCOUNT_MAX;
else
returnx;
}
/*Theasynchronousserviceportionoftheprogram*/
@portvoidIC1_Isr(void)/*themotorspeed
measurement*/
{
staticinti;
intj;
time2=TIC1;
TFLG1=IC1F;/*resetIC1interruptflag*/
mparray[i]=time2-time1;
if(++i==COUNT_8)
{
i=0;
measured_period=0;
for(j=0;j<COUNT_8;j++)
measured_period+=mparray[j];
measured_period>>=DIVIDE_8_SHIFT;
}
time1=time2;
TOC2=time2+5*measured_period/8;/*debouncetime
5/8revolution*/
TMSK1.IC1I=OFF;/*disableIC1interrupt*/
TMSK1.OC2I=ON;/*enableOC2interrupt*/
}
@portvoidOC2_Isr(void)/*thedebounceisr*/
{
TFLG1=IC1F|OC2F;/*resetinterruptflags*/
TimerOperations 275
TMSK1.OC2I=OFF;/*disableOC2interrupt*/
TMSK1.IC1I=ON;/*enableIC1interrupt*/
}
@portvoidOC3_Isr(void)/*thePWMisr*/
{
TFLG1=OC1F;/*resetOC1interruptflag*/
TOC1+=PWM_period;
OC1D.OC1D7^=ON;
TFLG1=OC3F;/*resetOC3interruptflag*/
TOC3=TOC1+PWM_count;
if(++count==COUNT_ONE_QUARTER)
{
count=0;/*enterthespeedcontrol*/
tick=TRUE;/*abouteachquarterof
ofasecond*/
}
}
Listing5-7:MotorControlProgram
In this program, dynamic debounce is used. In the function
IC1_Isr()thedebouncetimeisacalculatedvalueratherthana
mere3msaswasdoneinListing5-6.Herethedebouncelock-out
timeisfive-eighthsofthecurrentmeasuredperiod.Thisvaluegoes
beyond the half-way point in the input waveform enough to avoid
anybouncethatwilloccurduringtherisetimeoftheinputsignal.
TheremainderofthisprogramisquitesimilartothatinListing5-6.
Wehavecompletedmostoftheapplication.Theremainingparts
oftheprogramaretofindameanstoreadintothemicrocontroller
thespeedthatisdesiredforthemotor,andtointegrateanddebugthe
wholeprogram.Usually,thespeedisestablishedbysomemeasure-
ment being done with the microcontroller. Let us approach the
problemalittledifferently.Insteadofmakingthespeedaresultofa
measurement, lets enter the speed into the part through the asyn-
chronousserialport.
SerialCommunicationsInterface(SCI)
TheSCIisanotheroftheveryusefulperipheralfunctionsfound
ontheMC68HC11familyofmicrocontrollers.Infact,the SCIis
276 Chapter5 Programming Large 8-Bit Systems
foundonpartsfromallfamiliesofMotorolamicrocontrollers.The
SCIperformstheoperationofafullfunctionuniversalasynchronous
receivertransmitter(UART).Itcanoperatewithmoststandardbaud
rates, and several nonstandard rates. Control of this peripheral is
throughtheBAUDregister,theSCSR(serialcommunicationsstatus
register),andbothSCCR1andSCCR2(serialcommunicationscontrol
registers1and2).Thereisoneadditionalregistercalledtheserial
communications data register. This register when written to is the
transmitdataregister,andwhenreadthereceiverdataregister.Both
thetransmitandreceivedataregistersaredoublebuffered.
2
The BAUD register contains two test bits and two divide control
registersthatsetthebaudratefortheSCIsystem.ThebitsSCP control
thebaudrateprescaler.Thisprescalerhastheunlikelyprescalevalueof
divide-by-13whenbothbitsareset.Thisvaluesetsthemaximumbaud
rateto9600whenthesystemisdrivenbyan8MHzclock.Withthis
prescalervalue,allofthestandardbaudratesfrom9600downto150are
availabletotheSCI.TheseconddivideriscomprisedofSCR.Thebit
patternsinthesebitswillselectanypoweroftwodivisorsbetween1
0
and1282
7
.Foroursystem,wewillchoose9600baud,whichis
sufficientlyslowthatthereshouldbefewcommunicationsproblems.
Thecodetosetupthisbaudrateisasfollows:
BAUD.SCP=3;
BAUD.SCR=0;
Theselinesofcodemustbeaddedtotheinitializationportionofthe
programtosetupthebaudrateto9600baudfortheSCIsystem.
WewillusetheSCIsystemtoreadintherequiredmotorspeed
fortheprogramstartedintheprecedingsection.Suchasystemmust
be able to read in data through the SCI,but it must also echo the
same data back to the originating source to provide full duplex
operation. Therefore, both serial transmit and receive must be
implemented. With the above system, there is no serious need to
implementaninterruptdrivensystem.Thecomputerisclearlynot
beingusedtoitscapacity,sowewilladdtheSCIinputandoutput
sequencetotheapplicationsportionofthecodeandfeelsafethatno
inputdatawilleverbelostbecauseofanoverrunerror.(Anoverrun
erroroccurswhenanewinputoverwritesanoldinputbeforetheold
inputisprocessed.)Therefore,noneofthebitsin SCCR1needbe
changedfromtheirresetvalue.IntheSCCR2register,therearetwo
TimerOperations 277
bits,transmitenableandreceiveenable,thatmustbesettoenable
theSCI.Thefollowingtwolinesofcodewillenablethesebits.
SCCR2.TE=1;
SCCR2.RE=1;
Thesetwolinesofcodemustalsobeaddedtotheinitializationportion
oftheprogram.
Thecodetoreadthedatainisasfollows:
if(SCCR.RDRF==1)/*readindataifitisthere*/
{
new_character=SCDR;/*getnewbyteandresetRDRF*/
while(SCCR.TDRE==0);/*waituntiltransmit
bufferempty*/
SCDR=new_character; /*sendoutbyteandreset
TDRE*/
}
Thissequenceofcodedoesquiteabitmorethanyoumightexpect.
Beforethiscodesequencecanbeexecuted,boththeRDRF andTDRE
flagsmustbesetandreset.TheRDRFissetwhenacharacterhas
beenreceivedbytheSCI,andthe TDREissetwhentheSCDRis
emptyandcanreceiveacharactertosend.Bothofthesebitsarereset
bythesequentialreadofSCSRwiththebitsetfollowedbyareadfor
theRDRForawritefortheTDREtotheSCDRregister.Theabove
sequenceaccomplishesalloftheproperbitresets,transmitsthenewly
receivedcharacterbacktothesender,andleavesthenewcharacter
in the location new_character .After receiving the data, the
followingsequenceconvertsitintoabinarynumbertobeprocessed
bytheremainderoftheprogram.
if(SCSR.RDRF==1)/*readindataifthere*/
{
new_character=SCDR;/*getnewbyteandresetRDRF*/
while(SCSR.TDRE==0);/*waituntiltransmit
bufferempty*/
SCDR=new_character; /*sendoutbyteandreset
TDRE*/
/*ifanumber,processit*/
if(new_character>=0'&&new_character<=9')
278 Chapter5 Programming Large 8-Bit Systems
new_speed=10*new_speed+new_character-0';
elseif(new_character==\r)
{
/*rejectanynumberoutofrange*/
/*andstartoveragain*/
if(new_speed>=1000&&new_speed<=10000)
motor_speed=new_speed;
new_speed=0;
}
else
new_speed=0;/*rejecteverythingelse*/
}
Thevariablenew_speedisinitializedto0outsideofthisportion
oftheprogram.Iftheinputcharacterisanumber(anumberisany
characterthatliesbetween0and9),itisconvertedfromacharacter
toanumberwhenthecharacter0issubtractedfromit.Thisvalue
isaddedtotentimesthevaluestoredinnew_speed ,andtheresult
issavedinnew_speed.Repeatedexecutionsofthiscodesequence
willconvertaseriesofASCIIcharacternumberstoanappropriate
unsigned integer value. The entry sequence is terminated when a
nonnumbercharacterisreceived.Ifthischaracterisalineterminator
(acarriagereturnescapecharacterinthiscase),thenewspeedvalue
isputintomotor_speedtocausethemotortochangetothenew
value,andnew_speedisresettozerotoawaitforthenextinput.
Ifanyothercharacterisreceived,thedatasavedinnew_speedis
lost, and the whole entry of a new speed into the system must be
repeatedfromthebeginning.
InListing5-7therewasalonelylineofcode
/*inputthenewmotorspeed*/
That line has been replaced by the above and entered into Listing
5-8.The new motor speed input is placed in the main loop of the
applicationsprogram,soatestismadeeachtimethroughtheloopto
determineifthereisanewinputfromtheserialport.Thisroutine
alsosendsoutthecurrentspeedofthemotoronceeachhalfsecond.
Thisoutputiscontrolledbytheparameterstick1andin_process.
tick1 is set to TRUE each half second, and if in_process is
FALSEthemotorspeediscalculatedandsenttotheserialportoutput.
TimerOperations 279
Thissequencerepeatseachhalfseconduntilin_process issetto
TRUE. Whenever a character is read in through the serial port,
in_processissettoTRUEtodisablethecontinualoutputfrom
thesystemwhileanewinputspeedvalueisbeingentered.Ifthereis
anewcharacterintheinputbuffer,thischaracterisreadinandthe
RDRFflagisreset.Thenewcharacterisimmediatelyechoedbackto
thesendingdeviceaspartoffullduplexoperation.Ifthenewcharacter
isadigititisprocessed,ifitisalinefeeditisalsoprocessed,andany
numberstringisconvertedtoanintegersothatitcanbeusedbythe
computer. The size of the number is tested to be certain that it is
withintheacceptablespeedlimitsforthemotor,andifitpassesall
ofthetests,itisplacedinthevariablelocationmotor_speedto
indicatethatanewmotorspeedishereandshouldbeprocessed.
#includehc11e9.h
#defineDIVIDE_8_SHIFT 3
#defineCOUNT_8 8
#defineCOUNT_MAX 3300
#defineCOUNT_MIN 1600
#defineCOUNT_ONE_QUARTER 32
#defineCOUNT_ONE_SECOND 128
#definePERIOD 0X1000
#defineTIME_ON 0x0800
#defineIMPOSSIBLE 3500
#defineTOO_LOW 100
#defineRPM_MIN 1000
#defineRPM_MAX 11000
#defineCR 0x0d
#defineLF 0x0a
/*functionprototypes*/
@portvoidIC1_Isr(void);
@portvoidOC2_Isr(void);
@portvoidOC3_Isr(void);
intputchar(charnew_character);
voiddprint(unsignedintc);
voiddo_crlf(void);
longlimit(long);
280 Chapter5 Programming Large 8-Bit Systems
/*externalvariabledefinitions*/
longmeasured_period,delpc;
WORDtime1,time2,
motor_period,motor_speed=IMPOSSIBLE;
WORDnew_speed;
WORDold_motor_speed=TOO_LOW,rpm,mparray[COUNT_8];
longPWM_period=PERIOD,PWM_count=TIME_ON;
intnew_character,tick=TRUE,count=0,in_process;
inttick1=TRUE,count1=0;
WORDgot_new=TRUE;
main()
{
/*Theinitializationportionoftheprogram*/
TCTL2.EDG1B=ON;/*capturefallingedgeonly*/
OC1M.OC1M7=ON;/*sentOC1outtoPA7*/
OC1M.OC1M5=ON;/*coupleOC1toOC3*/
TMSK1.OC3I=ON;/*enabletheOC3interrupt*/
TMSK1.IC1I=ON;/*enabletheIC1interrupt*/
OC1D.OC1D5=ON;/*turnonOC3whenOC1occurs*/
TCTL1.OL3=ON; /*toggleOC3whenOC3occurs*/
PACTL.DDRA7=ON;/*makeOC1anoutputtoPA7*/
TOC1=TCNT+PWM_period;/*setOC1totheperiod*/
TOC3=TOC1+PWM_count;/*setOC3timeon*/
BAUD.SCP=3; /*setuptheSCI*/
BAUD.SCR=0; /*9600baud*/
SCCR2.TE=ON;
SCCR2.RE=ON;
cli(); /*enablethesysteminterrupts*/
/*theapplicationsportionoftheprogram*/
FOREVER
{
if(old_motor_speed!=motor_speed)
{ /*Allofthenumbersusedbeloware
derivedinthetext*/
motor_period=30000000lu/motor_speed;
old_motor_speed=motor_speed;
TimerOperations 281
PWM_count=((motor_speed+12528)/63)*8;
PWM_count=limit(PWM_count);
}
if(tick)
{
tick=FALSE;
delpc=(3809500lu/motor_period);
delpc=delpc*(motor_period-
measured_period)/motor_period;
PWM_count-=delpc;
PWM_count=limit(PWM_count);
rpm=30000000L/measured_period;
}
/*inputthenewmotorspeed*/
/*SendoutthemeasuredRPMtotheterminal
periodically*/
if(tick1&&!in_process)
{
tick1=FALSE;
rpm=30000000L/measured_period;
dprint(rpm);
do_crlf();
}
if(SCSR.RDRF==ON)/*readindataifitis
there*/
{
in_process=TRUE;
new_character=SCDR;/*getnewbyteand
saveit*/
while(SCSR.TDRE==OFF);/*waituntiltransmit
bufferisempty*/
SCDR=new_character;/*sendoutbyteand
resetTDRE*/
/*gotanumber,processit*/
if(new_character>=0'&&new_character<=9')
new_speed = 10*new_speed+new_character-0;
elseif(new_character==\r)
282 Chapter5 Programming Large 8-Bit Systems
{
do_crlf();
/*rejectanynumberoutofrange*/
/*andstartoveragain*/
if(new_speed>=RPM_MIN&&new_speed<=RPM_MAX)
{
got_new=TRUE;
in_process=FALSE;
motor_speed=new_speed;
new_speed=0;
}
}
else
new_speed=0;/*rejecteverythingelse*/
}
}
}
/*functionsofthemainprogram*/
/*therangeofacceptablePWM_countis1600to
3300*/
longlimit(longx)
{
if(x<COUNT_MIN)
returnCOUNT_MIN;
elseif(x>COUNT_MAX)
returnCOUNT_MAX;
else
returnx;
}
/*sendoutasinglecarriagereturn-linefeed
sequence*/
voiddo_crlf(void)
{
TimerOperations 283
while(SCSR.TDRE==OFF);
SCDR=CR;
while(SCSR.TDRE==OFF);
SCDR=LF;
}
/*sendasinglecharactertotheserialport*/
intputchar(charnew_character)
{
while(SCSR.TDRE==OFF);
/*waituntiltransmitbufferempty*/
SCDR=new_character;
/*sendoutbyteandresetTDRE*/
}
/*convertanintegerandsendittotheserial
portasastring*/
voiddprint(unsignedintc)
{
if(c/10)/*recursivelydeterminesif*/
dprint(c/10);/*azerohasbeenreachedandthen*/
putchar(c%10+0');/*sendsoutthecharacters*/
}
/*Theasynchronousserviceportionoftheprogram*/
@portvoidIC1_Isr(void)/*themotorspeed
measurement*/
{
staticinti;
intj;
time2=TIC1;
TFLG1=IC1F;/*resetIC1interruptflag*/
mparray[i]=time2-time1;
if(++i==COUNT_8)
{
i=0;
284 Chapter5 Programming Large 8-Bit Systems
measured_period=0;
for(j=0;j<COUNT_8;j++)
measured_period+=mparray[j];
measured_period>>=DIVIDE_8_SHIFT;
}
time1=time2;
TOC2=time2+5*measured_period/8;/*debouncetime
Is5/8revolution*/
TMSK1.IC1I=OFF;/*disableIC1interrupt*/
TMSK1.OC2I=ON;/*enableOC2interrupt*/
}
@portvoidOC2_Isr(void)/*thedebounceisr*/
{
TFLG1=IC1F|OC2F;/*resetinterruptflags*/
TMSK1.OC2I=OFF; /*disableOC2interrupt*/
TMSK1.IC1I=ON; /*enableIC1interrupt*/
}
@portvoidOC3_Isr(void)/*thePWMisr*/
{
TFLG1=OC1F; /*resetOC1interruptflag*/
TOC1+=PWM_period;
OC1D.OC1D7^=ON;
TFLG1=OC3F; /*resetOC3interruptflag*/
TOC3=TOC1+PWM_count;
if(++count>=COUNT_ONE_QUARTER)
{
count=0; /*enterspeedcontrolabout*/
tick=TRUE; /*eachquarterofasecond*/
}
if(++count1==COUNT_ONE_SECOND)
{
count1=0;
tick1=TRUE;
}
}
Listing5-8:TheCompletedApplication
Summary 285
Therearethreeinput/outputroutinesthathavebeenwrittenfor
this program. These routines, putchar(), dprint(), and
do_crlf(), can be used with other systems with a serial input/
output system. The Cosmic compiler does provide the usual I/O
routineslikeprintf(),gets(),puts(),etc.Itdoesnotprovide
abasicputchar()andgetchar()whichisusedbyallofthese
libraryroutines.Thereasonthattheseroutinesarenotprovidedby
thecompileristhewidevarietyofwhattheprogrammerwillwantto
implement with the built-in SCI ports on the MC68HC11 family.
The putchar() shown above will work in most instances. The
dprint() routine is a recursive routine that converts an integer
intoanASCIIstringandsendsittotheSCIport.
Thereisonefinalmodificationtotheprogram.Inthelastlinesof
the PWM timer routine, count1 and tick1 are processed to set
tick1 tobeTRUEeachsecond.Thisflagisthenusedtocontrolthe
writingofthemotorspeedstotheterminalscreen.
Summary
Therehasbeennoattempttoworkalloftheperipheralsonthe
MC68HC11.Thevariousperipheralsaresimilartothoseontheother
partsthatwehavediscussedinotherchaptersorwilldiscusslater.
WehaveseenseveraltimerapplicationsbothintheMC68HC11and
in the MC68HC05. We will see other timer applications in the
followingchapters.
Wehaveseendetaileduseoftheoutputcomparetimersubsystem
tomakeapulsewidthmodulationdigital-to-analogconvertersystem.
Dependingontheprogram,thesystemallowedexcellentperformance
ineithershortontimesormaximumontimes,butnotbothwithoutthe
additionofasignificantamountofcode.Wewillseeasysteminthe
nextchapterthatprovidesexcellentperformanceforbothminimum
andmaximumontimes.Thisperformanceisnotalimitationofthe
MC68HC11,merelyalimitationoftheprogramspresentedsofar.
The input capture subsystem has been used to measure motor
speedinasimpleDCmotorcontroller.Thissystemusedaprimitive
reed switch to measure the rotation of the motor shaft, and the
performance of the switch was poor. A debouncing system was
developedthatpreventedinputcapturestooccurforaspecifiedtime
after the first input was detected. This approach uses an output
286 Chapter5 Programming Large 8-Bit Systems
comparechannel,butitdoesnottieupthemicrocontrollertowait
outanydelaytimesduringthedebounceperiod.Thisprogramisnot
tooremovedfrommanyofthoseencounteredintherealworld.
The organization of the program is similar to how most
applicationscanbeprogrammed,andthewayinwhichtheprogram
wasdevelopedshowedhowmostproblemsshouldbeapproached.
The problem was broken down into a set of small operations that
couldeachbehandledeasily.Thesedifferentpartsoftheprogram
weredeveloped,tested,anddebuggedseparately.Thisapproachkeeps
thedevelopmentoftheindividualpartsoftheprogrammanageable,
anddebuggingisnottoodifficult.Ifthewholeprogramwerewritten
andthendebuggingstarted,itwouldhavebeennearlyimpossibleto
separateouttheeffectsofonepartoftheprogramontheothers.The
maininterruptserviceroutineswerewrittenfirstandtestedaswell
aspossiblebythemselves.Withtheseimportantfunctionsbehindus,
itwaseasytoattacktheapplicationsportionoftheprograminwhich
theclosedloopsystemwasimplementedalongwiththemanagement
oftheinput/outputthroughtheserialportofthedevice.
TheMC68HC11isapowerfulenoughcomputerthatitispossible
tomakeanANSIcompliantcompiler.Parameterscanbepassedto
functionsonthestack,andre-entrantorrecursivefunctionscanbe
written for this part as was demonstrated with the dprint()
function.Remember,itisthemicrocontrollerthatlimitedtheANSI
compliancewiththeMC68HC05notthecompiler.
Chapter 6
LargeMicrocontrollers
Inthischapterwellexaminetheprogrammingofsystemsem-
ployinglargemicrocontrollers.Therealmofthelarge-microcontroller
system is not all that different from the 8-bit systems. One of the
mainadvantagesoftheuseofahigh-levellanguageisthatitkeeps
the nasty details of the underlying computer hidden from the pro-
grammer. Usually, the programmer will not see much difference
betweenthecodefordifferenttypesofcomputers.Thefallacytothis
idea is that when programming any microcontroller, the program-
mermustknowaboutandusealloftheon-boardperipheralsfound
onthemicrocontroller.Theseperipheralswillvaryfrommachineto
machine,andhowtheyareaccessedwilldifferfromdevicetode-
vice. In this chapter, however, we are going to see an application
whereasubstantialamountofassemblylanguageisrequired.The
chip that we are going to use here has a Digital Signal Processor
section.Thisprocessorisaccessedthroughspecialcorechipregis-
tersandthecoreconditioncoderegister.Theabstractmachinethat
the compiler creates code for contains no registers.Therefore, the
onlyaccesstothesefeaturesisthroughassemblylanguage.Wewill
showhowtocreateassemblylanguagefunctionsthatcanbeaccessed
fromyourCprogram.
Thepartthatwewilluseforthe16-bitdiscussionsistheMotorola
MC68HC16familyofcomponents.ThesearesimilartotheMC68HC11
inmanyways,butthereareimportantdifferences.First,therearesome
new registers that must be programmed directly to make the
MC68HC16 work as desired. (The only register in the MC68HC11
thatmustreceivespecialassemblyinstructionsistheconditioncode
register.)Also,theMC68HC16doesnothaveautomaticstackingofits
registers when an exception occurs, unlike the MC68HC11. There-
fore,allinterruptserviceroutinesmustbeginwithcodethatsavesthe
287
288 Chapter6 Large Microcontrollers
statusofthemachinebeforethenormalinterruptoperationscanpro-
ceed.Wewillseeafewotherdifferencesbetweenthesedevices,but
themaindifferenceisinthewayperipheralsarehandled.
OntheMC68HC16,thecoreprocessoriscalledtheCPU16.This
central computer is interfaced to an internal bus called the
inter-modualbus(IMB).TheIMBisverymuchlikethebusahard-
waredesignerwouldputontoanexternalcircuitboard.Ithasaddress
anddatabussesandallofthenecessarycontrolsignalstocontrolany
peripheralthatthemicrocontrollermighthaveapplied.Inthestan-
darddevice,theMC68HC16Z1,therearefivebuilt-inperipherals:
thesystemintegrationmodule(SIM),theanalog-to-digitalconverter
(ADC), the queued serial peripheral interface module (QSPI), the
general-purposetimermodule(GPT),andthestaticrandomaccess
memorymodule(SRAM).Thesemodulesandotherscanbeaddedor
deletedinfuturecomponentsasthecustomerneedsdictate.
Theseveralinternalperipheralmodulesareeachinterfacedtothe
IMB.Eachmodulehasaspecificsetofregistersthatarelocatedatan
address relative to the base address of the module. These base ad-
dresses are set at design time. This is interesting because the same
modulesareusedontheMC68300seriesofmicrocontrollers,which
are32-bitmicrocontrollers.Therefore,thematerialpresentedinthis
chapterisdirectlyapplicabletotheMC68300seriesofmicrocontrollers.
The only difference that the programmer will see is that the base
memorylocationsofthevariousperipheralmodulesaredifferent,but
eventhesedifferencesdisappearbecauseofthecarefuldesignofthe
microcontrollers.Wethereforecanconsiderthischaptertobeonlarge
microcontrollersratherthanonthe16-bitsystemsalone.
The MC68HC16
TheMC68HC16isatrulycomplicateddevice.However,forour
purposes, it can be divided into its several components, and each
componentissomewhatasonewouldexpectfromaprogramming
standpoint.Therefore,wewillexaminethisfamilyofpartsasacol-
lectionofmodules.Eachmoduleisratherstraightforward.Thecore
processor,whichisknownastheCPU16,isindeedacompleteand
competentmicrocomputer.Thebulkofitscomplexityishiddenby
thefactthattheprogramiswritteninC.Thissectioncontainsabrief
descriptionoftheMC68HC16Z1microcontrollerthatcanbeusedto
TheMC68HC16 289
aidinwritingprogramsforthecomponentinC.Thereareseveral
Motorolamanualsthatareusefuladjunctstothischapter.
123456
CopiesofthesemanualsarealltobefoundontheattachedCD-
ROM. It is recommended that these manuals be reviewed prior to
anyattempttowritecodeforthisfamily.
CPU16CoreProcessor
The CPU16 represents an attempt to bridge the difference be-
tweenthelarge8-bitmicrocontrollersandthehigh-endcomponents
embodiedintheMC68300family.Thisprocessorisa16-bitproces-
sor.Assuch,itsinstructionsareeach16bitswide,instructionsare
readfrommemory16bitsattime,andtheinstructionsareprocessed
16bitsatatime.Onthisparticularpart,a20-bitaddressbuswith
additionalcontrolallowstheprogramtoaccesstwoindividualone-
megabyteaddressmaps.Thecontrolsavailabledistinguishbetween
programmemoryanddatamemory.
Ithasbeenstatedseveraltimesthattheprogrammersmodelfor
amicrocontrollerisnottooimportantwhenwritingcodeinC.Tobe
abletoaccessallofthefeaturesofaCPU16,youwillhavetouse
assemblylanguage-basedfunctions.Therearecertainfeaturesthat
are simply outside the concept of a high-level language. In these
cases, it is recommended that functions which access and control
thesefeaturesbewrittenandthenyoucancallthesefunctionsfrom
theCprogram.ThemainpropertiesoftheCPU16thatarenotavail-
able to the C programmer are the DSP type registers found in the
part.Programmingoftheseregistersisthesubjectofalatersection
ofthischapter.
The20-bitaddressspaceoftheCPU16isasignificantdeviation
fromthenormal16-bitaddressspaceoftheMC68HC11.Thischange
hasbeenhandledbytheadditionofseveral4-bitextensionregisters
forthoseregistersthatdealspecificallywithaddresses.Theseregis-
tersaretheprogramcounter(PC),thestackpointer(SP),thethree
1
M68HC16 Family MC68HC16Z1 Users Manual MC68HC16Z1UM/AD
2
M68HC16 Family CPU16 Central Processor Unit Reference Manual CPU16RM/AD
3
Modular Microcontroller Family GPT General Purpose Timer Reference Manual GPTRM/AD
4
Modular Microcontroller FamilyADCAnalog-to-Digital Converter Reference ManualADCRM/AD
5
Modular Microcontroller Family QSM Queued Serial Module Reference Manual QSMRM/AD
6
Modular Microcontroller Family SIM System Integration Module Reference Manual SIMRM/AD
290 Chapter6 Large Microcontrollers
indexregisters(IX,IY,andIZ),andtheEKregister.Alltheseregis-
tersexceptfortheEKare16bitswide.TheEKregisterisanextension
register that is used with the extended addressing mode.Any ex-
tendedaddresscalculationwillresultina16-bitnumber.Theresult
willbeconcatenatedwiththeEKregistertocreatea20-bitaddress.
(TheEKregisterhasnothingtodowiththeEaccumulatorfoundin
thedevice.)TheextensionregistersarenamedPK,SK,XK,etc.The
extensionregistersareusuallysetduringinitializationofthedevice,
andthereisnoneedtochangethemduringprogramoperation.The
contentofanextensionregisterisapagepointer.Thepagesinthis
caseareeach65536byteslong.Transitionfromonepagetoanother
isautomatic.Forexample,ifanaddressiscalculatedforajmpwhich
will pass program control to code in another page, the proper ad-
dress will be calculated for both base and extension register
automatically.Thecalculationwillalterthecontentsofboththebase
andtheextensionregisterwithoutprogrammerconcern.
TheMC68HC16familycurrentlyhastheseveralinternalmodules
mentionedabove,anditisplannedthatfutureversionsofthepartwill
havemoremodules.Thiscomplexityhassuggestedthatthearrange-
ment of the header file for the part be broken into several different
files:Onefileforthemainprocessor,andseveraldifferentheaderfiles,
one for each of the peripheral modules in the individual part. This
approach is shown in the HEADER/HC16HEADERS directory on
theCD-ROM.Thereyouwillfindaheaderfilenamedhc16.h along
withfilesnamedadc.h,gpt.h,sim.h,sram.h,andqsm.h.
Whenwritingcodeforanyspecificmodule,youshouldincludethe
hc16.h file along with the proper files for the peripheral portions
needed. The hc16.h file must be included first because there are
itemsdefinedinthisfileneededbytheotherheaders.
Onemajordifferencebetweenthelargeandsmalldevicesisthe
waytheexceptionvectortableishandled.Recallthat,intheMC68HC11
family,allinterruptvectorsareplacedatthetopofmemory.Withthe
MC68HC16family,thevectortableiscontainedwithinthefirst512
bytesofmemory.Uponreset,theCPU16coreprocessorreadsthefirst
fourwordsofmemorywhereitmustfindcertaindatafortheopera-
tionoftheprogram.Theaddress0mustcontainawordwhoseleast
significant12bitsarethecontentsoftheZK,theSKandthePKreg-
isters when the part comes out of reset. The address 2 contains the
initialprogramcounter,andtheaddress4mustcontaintheinitialstack
TheMC68HC16 291
pointer.Finallytheaddress6mustcontaintheinitialvalueoftheIZ
register.NotethatthewordaddressesintheMC68HC16arealways
even.Inthismachineyouwillfindwordsonevenboundaries,bytes
anywhere,andlongwordsonevenboundaries.Thesedataareloaded
intothismemoryareabytheuseofavectorroutinesimilartothatseen
inChapter5fortheMC68HC11.Withthisapproach,alloftheregis-
tersneededtobeginoperationofthebasiccomputerareloadedfrom
memoryatresettime.Ofcourse,thisoperationdoesnoteliminatethe
need for program initialization; it merely provides a mechanism by
which the processor will start accessing memory at the correct ad-
dresseswhenthedevicecomesoutofreset.
Table 6-1 contains a listing of the uses of each entry in the
vectortable.Notethatvectors0x0through0x37haveassigned
functions.Thevectors0x38through0xffareavailableforuser-
definedoperations.Notetherelationshipbetweenthevectornumber
andthevectoraddress.Thevectoraddressisalwaystwicethevec-
Table6-1:ExceptionVectorTable
Number
0 0x0000 ResetInitialZK,SK,PK
1 ResetInitialPC 0x0002
2
3
4
0X000C
0X000E
0X0010
0X0012-0X001C
0X0070-0X01FE
0X0032-0X006E
ResetInitialSP 0X0004
ResetInitialIZ 0X0006
0X0008
BusError 0X000A 5
6
7
8
9-E
F 0X001E
10
11
12
13
14
15
16
17
18
19-37
38-FF
0X0020
0X0022
0X0024
0X0026
0X0028
0X0030
0X002A
0X002C
0X002E
Breakpoint
Vector
VectorAddress TypeofException
SoftwareInterrupt
DivisionbyZero
Unassigned,Reserved
UninitializedInterrupt
Level0Autovector
IllegalInstruction
Level1Autovector
Level2Autovector
Level3Autovector
Level4Autovector
Level5Autovector
Level6Autovector
Level7Autovector
User-definedInterrupts
Unassigned,Reserved
SpuriousInterrupt
292 Chapter6 Large Microcontrollers
tornumber.Whenprogrammingtheinterruptvectorsintheseveral
peripheralmodulesoftheMC68HC16,theprogrammerwillselect
theinterruptvector.Whenitcomestimetoplacetheinterruptser-
vice routine address in the proper memory location, it is to the
vectoraddressNOTthevectornumberthatthisvaluemustbe
assigned.
Whensettingupthevectortable,awiseprogrammerwillfillall
ofthepossibleunusedvectoraddresseswiththeaddressofadummy
functionthatprovidesanorderlyreturntotheprogramintheevent
ofanunexpectedinterrupt.Usuallythefirst0x18or24vectorsshould
befilledwiththisaddress.Anexamplefunctionthatcanbeusedfor
thistypeofoperationis
static@portvoid_init_vector(void)
{}
ThisprogramwillcompiletoasingleRTI(returnfrominterrupt)
thatwillreturntheprogramcontroltothelocationwhentheinterrupt
occurred.Astaticfunctionisnotusedoften.Whenafunctionis
declaredstatic,itcanbeseenonlyinthefileinwhichitisdefined.
Followingisalistingoftheroutinevector.c.Thisprogram
ismodeledcloselyafterthatprovidedwiththeCosmicMC68HC16
Ccompiler.
extern@far@portvoid_stext(void);/*startuproutine*/
extern@portvoidOC3_Isr(void);/*ISRaddress*/
static@portvoid_init_vector(void);
staticconststructreset{
@far@portvoid(*rst)(void);/*reset+code
extension*/
unsignedshortisp;/*initialstackpointer*/
unsignedshortdpp;/*directpagepointer*/
@portvoid(*vector[252])(void);/*interruptvectors*/
}_reset={
_stext, /*1-startaddress*/
0x03fe, /*2-stackpointer*/
0x0000, /*3-pagepointer*/
_init_vector,/*4-Breakpoint*/
_init_vector,/*5-BusError*/
TheMC68HC16 293
_init_vector,*6-SoftwareInterrupt*/
_init_vector,/*7-IllegalInstruction*/
_init_vector,/*8-DividebyZero*/
_init_vector,/*9-Reserved*/
_init_vector,/*a-Reserved*/
_init_vector,/*b-Reserved*/
_init_vector,/*c-Reserved*/
_init_vector,/*d-Reserved*/
_init_vector,/*e-Reserved*/
_init_vector,/*f-UninitializedInterrupt*/
_init_vector,/*10-Reserved*/
_init_vector, /*11-Level1InterruptAutovector*/
_init_vector, /*12-Level2InterruptAutovector*/
_init_vector, /*13-Level3InterruptAutovector*/
_init_vector, /*14-Level4InterruptAutovector*/
_init_vector, /*15-Level5InterruptAutovector*/
_init_vector, /*16-Level6InterruptAutovector*/
_init_vector, /*17-Level7InterruptAutovector*/
_init_vector, /*18-SpuriousInterrupt*/
/*vectors0x19-0x37unassigned,reserved*/
0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
/*puttimeratvector0x460x40fromICRand6forOC3*/
0,0,0,0,0,0,OC3_Isr/*OC3_Isrvectorat0x46addressat0x8c*/
};
static@portvoid_init_vector(void)
{}
Listing6-1:TheVectorInitializationRoutinevector.c
Wehavealreadyseenthe@portcommandinChapter5.The
@farcommandisuniquetotheCosmiccompiler.Thiscommand
notifiesthecompilerthatthepointerassociatedwiththecommandis
nottheusual16-bitpointer.An@farpointerisanextendedpointer.
This20-bitpointerwillbeplacedintothefirsttwomemorywords
by the vector.c routine. The rightmost 4 bits in word 0 is the
programcounterextensionPK,sothattheplacementofthe20-bit
294 Chapter6 Large Microcontrollers
programcounterinthislocationwillprovideproperinitializationof
theprogramcounter.
Intheexampleabove,theinterruptserviceroutineOC3_Isris
placedintheaddress0x46.Unfortunately,thereisnoeasywayto
accomplishthisplacement.Thestructureaddressmustbecounted
byhandandthepointerplacedatthecorrectlocation.Thestructure
members are initialized only up to the vector with the highest ad-
dress.Notethatthestructureisglobal,sothatitsmemberswillallbe
initialized to zero unless otherwise assigned. Notice also that the
vectorsuptovectornumber0x18areinitialized.Thesevectorsin-
cludealloftheprogram-generatedexceptions.Theseareasarewhere
onewouldexpectmostoftheproblemstooccurindebuggingapro-
gram.Thevectornumbers0x19 through0xff areleftinitializedto
0.Thesevectorsareallaccessedbyeithertheinternalmodulesor
fromexternalinterrupts.Iftherearenohardwareproblemswiththe
system, it is unlikely that external devices will cause uncalled-for
interrupts,andifoneoftheinternalmodulescausesaninterruptwith
anuninitializedvector,theCPU16willaccesstheuninitializedinter-
ruptvector.
One other problem can arise when debugging programs that
involveuser-specifiedinterrupts.Intheeventthattheisraddress
is improperly placed in the vector table, the program will become
lostwhenevertheinterruptoccurs.Ifsuchaprogramexhibitsbizarre
behavior,agoodtrickistoplaceabreakpointattheaddress0.Ifthe
vectoriswrong,aninterruptwilltakethepropervectorwhichwill
contain a 0 and attempt to execute the code at the address 0.The
breakpointatthislocationwillstopexecutionandgiveyouaclueas
totheprogramerror.Abreakpointat_init_vectorcanalsobe
useful to determine where the program is when an unexplained
exceptionoccurs.
IfacompilerprovidesamechanismthatcompliestotheANSI
standardandonethatdoesnot,itisbettertochoosetheANSIstan-
dardmechanismratherthanthenonstandardapproach.Forexample,
ANSIstatesnothingabouthowtoestablishavectortable.Theabove
approachisbutoneofseveralthatcanbeusedtohandletheplace-
mentofthevectorsinthevectortable.Anotherapproachistousethe
vector macro that is found in hc16.h . The disadvantage to the
vectormacroisthatitcanplaceavectorintoRAMonly.Oftenwith
TheMC68HC16 295
embeddedcontrols,itisnecessarytoplacethevectorsintoROM.In
thatcase,theuseoftheroutinevector.cisthebestapproach.
The use of the @port command is certainly not found in the
ANSIstandard.Itispossibletocreateacompleteinterruptservice
routinewithouttheuseofthe@port.However,ifCisusedtothe
maximum, the isr will have some built-in inefficiencies. For ex-
ample,thelanguagehasnodirectregistercommandssoitisnecessary
tocreateafunctionthatsavesthestatusofthecomputeronentryto
the routine, and another to restore the machine status prior to the
returnfromtheinterrupt.Also,aspecialfunctionmustbecreatedto
executethe RTIinstructionattheendoftheinterruptservicerou-
tine.Theseassemblyroutinescanbecreatedasfunctioncallsand
savedintheheaderfile.Whentheyareused,itiswisetostudycare-
fullythecodegeneratedbythecompilertomakecertainthatthere
arenoerrorsinthecode.Forexample,ifafunctionshouldhappento
clearsomespaceonthestackforlocalstorage,theplacementofan
RTIinstructionintheCcodesequencewouldcausethereturnop-
erationtobeexecutedbeforethestackisrestored.Suchanerrorwill
causeseriousproblemsinsystemperformanceifnotcorrected.
Boththe@far andthe@port commandsarenotincompliance
withtheANSIstandard.Itisrecommendedthatyouusethesecom-
mands sparingly because their use causes nonportable code to be
generatedwiththecompiler.Sofarinthistext,wehaveusedtwo
significantlydifferentcompilers.Eachcompilermanufacturerclaims
thattheircompilercompliestoANSI.InthecaseoftheC6805com-
piler from Byte Craft, it probably conforms as closely as can be
expectedforsuchaprimitivemachine.BoththeMC68HC11andthe
MC68HC16compilerscomplymorecloselytothestandardthanthe
C6805.Bothofthesemachinesaresomuchmorecomputerthatone
shouldexpectveryclosecompliance.Anyextensiontothebasiclan-
guage should be used with care. The above two commands are
desirableandprovideusefulfunctionsfortheembeddedcontrolfield.
TheCosmiccompilersalsohaveanextensionthathasnotbeen
usedinthistext.Thewayinwhichtheydefinetheinternalregisters
tothemachineisnotstandard,anditdoesnotpermitveryefficient
useofbitmanipulationbythecompiler.Theapproachusedhereis
showninthevariousheaderfileswrittenfortheparts.Thecompiler
writerassumesthattheuseofaconstructlike
296 Chapter6 Large Microcontrollers
#defineABLE(*(Register*)0x2000)
is too complicated for most programmers to understand. The ap-
proach that they use is nonportable, and the latter approach is
completelyportableamongANSIcompliantcompilers.Itisrecom-
mended that, even though the header files contain some code that
mightbedifficulttoexplain,youshouldusetheapproachpresented
heretocreatecodethatisasportableaspossible.
Someofthesectionsthatfollowwillshowhowportablecodecan
be used. Examples from both the MC68HC11 and the MC68HC05
willbeusedontheMC68HC16,andyouwillseethatmuchofthe
codewillbetransferredwithlittlechange.Wherewouldyouexpect
changes? Recall the recommendation that each program be broken
intothreesections:theinitializationsection,theapplicationssection,
andtheasynchronousservicesection.Eachsectionwillbesubjectto
somechangewhenmovingfromonemachinetoanother,buttheap-
plicationssectionwillprobablysufferlittlechangeandtheothertwo
sectionswillseethemostchangeswhenthecodeismoved.Forex-
ample,youwillseethattheinitializationoftheMC68HC16issomewhat
differentfromthatoftheMC68HC11,buttheinterruptservicerou-
tineswillbenearlythesame.Infact,insomecasestheisrforthe
twopartsisidentical.Ontheotherhand,thewaythatthingsarehandled
ontheMC68HC05issodifferentthattheinitializationandisrwill
probablyhavetobecompletelyrewrittenwhenmovingcodetooneof
thelargermachines.However,herethemachine-independentportions
oftheapplicationsroutinecanbemovedwithlittlechange.
SystemIntegrationModule(SIM)
Abriefexaminationofthenamesofmostofthemoduleswill
revealtheiruse.Thereisonenotableexceptionwhatisasystem
integrationmodule(SIM)?TheSIMissortoftheinterfacebetween
theIMBandtheoutsideworld.Itisveryuseful,andcontainsmuch
ofthecircuitrythatahardwaredesignerwouldhavetoincorporate
tomakeacomputeroutofamicroprocessor.Theobjectofthechip
designerwiththeintroductionoftheSIMwastomakeitpossibleto
use the MC68HC16 in a system with a minimum of external cir-
cuitry.Thissectionisnottoprovideyouwithacompletedescription
of the SIM.The SIM Reference Manual is a 200-page document,
andImnotintendingtoduplicatethatmanualhere.Thefollowing
SystemIntegrationModule(SIM) 297
paragraphseachcontainabriefdescriptionoftheseveralblocksfound
withintheSIM.Thesetupandcontroloftheseblocksareallcon-
trolledbytheregistersdescribedintheSIMbookontheCD-ROM.
SystemConfigurationandProtection
Thismodulemonitorsmanyofthethingsthatcangowrongwith
theoperationoftheMC68HC16.Internalandexternalsignalscan
begeneratedthatsignalanerrorhasoccurred.Resetsignalscanbe
originatedfromseveralsources.Theresetstatusmonitorkeepstrack
ofthesourceofthelatestresettohelpwithdebugoperations.The
halt monitor responds to a HALT signal on the internal bus. This
monitor, if properly enabled, can request a reset.The bus monitor
andthespuriousinterruptmonitorcaneachrequestabuserror.The
busmonitorrespondsprimarilytoanunansweredasynchronousbus
transferrequest.Suchasequenceisusuallytheresultofaprogram
accesstounimplementedmemory.Ifproperlyenabled,thespurious
interruptmonitorcaninitiateabuserror.
There are two time-based functions in the system configuration
andprotectionsectionoftheSIM.Thefirstisasoftwarewatchdog
timer.Thistimerrequiresthattheprogramaccessamemorylocation
withacodesequence.Thisaccessresetsatimer.Withaproperpro-
gram,thespeciallocationinmemoryisaccessedroutinelyinthenormal
execution of the program and the timer should never overflow. If it
does, there is probably a system error that is corrected by a system
reset.Theperiodicinterrupttimerisusedwheneverasimpleclocking
sequenceisneeded.Wewillseeuseofthistimerinalatersection.
SystemClock
ThesystemclockprovidestimingsignalsfortheIMBandallofthe
internal modules of the microcontroller. The time base for the
microcontrollercanbea32768-kHzreferencecrystal,a4.194-MHz
crystal,oranexternalclocksignal.Ifeitherofthecrystaloscillatorsare
usedthereisaninternalphase-lockedloopfrequencymultiplierthatwill
multiplytheoperatingfrequencytothefinalsystemclockfrequency.
ExternalBusInterface
TheexternalbusinterfacetransfersinformationbetweentheIMB
andexternaldevices.Thisinterfacesupportsa16-bitdatabus,uptoa
298 Chapter6 Large Microcontrollers
24-bitaddressbus,athree-linefunctioncontrolsignalbus,controlsig-
nalsfordynamicbussizing,andhandshakingforexternalbusarbitration.
Interrupts
TheCPU16containsathree-wire,seven-levelinterruptsystem.
These interrupts are interfaced to the SIM through the IMB. The
outsideworldisinterfacedintotheSIMassevenindividualinterrupt
lineswhicharemultiplexedontothethree-wirelinewithintheSIM.
TherearealsotwosourcesofinterruptfromwithintheSIMitself.
Theseinterruptsarefromtheperiodicinterrupttimerandthesoft-
warewatchdogtimer.
ChipSelects
There are many signal lines on the microcontroller that might
notbeneededwithatypicalsystem.Forexample,addresslines20
through23allfollowtheconditionofaddressline19.Perhapsnot
alloftheexternalinterruptlinesareneeded.Oftenthefunctioncon-
trollinesthatcanbeusedtodecodethenatureofabuscyclei.e.,
eitherdataorprogramaccessarenotused.Altogetherthereare12
signallinesthatcanbeimplementedaschipselects.Thislinewill
assertwhenthereisanaccesswithinamemoryrangespecified.
ResetandSystemInitialization
Themicrocontrollerhasseveralsourcesofreset.Theresetand
systeminitializationsectiondirectstheseveralresetstotheproper
operation,andrecordsthesourceoftheresets.Also,whenthesys-
tem is reset initially, the state of several pins on the system bus is
analyzedtodeterminethemodeofthepartwhenitexitsthereset
sequence.
GeneralPurposeI/O
Thereare16SIMpinsthatcanbeconfiguredasgeneral-purpose
input/outputsignals.TheseportsareportsEandF,andthepinsare
all multiply assigned. Port E pins, for example, are bus control
pins,andPortFpinshaveaseconduseastheexternalinterrupt
inputstothesystem.
APulseWidthModulationProgram 299
APulseWidthModulationProgram
While the MC68HC16 has a built-in pulse width modulation
(PWM)system,itissometimesdesiredtoachievemoreflexiblereso-
lutionthancanbeobtainedwiththebuilt-insystem.Therefore,itis
not unreasonable that one would want to use the general-purpose
timertocreateaPWM.PriortowritingthecodeforaPWMinthis
manner, we should look at the basic time period of the processor.
Unlessotherwisedirected,allofthetimersintheGPTaredrivenby
thesystemclock.Thissignalispassedthroughaprescalercontrolled
bythebitsCPR2throughCPR0intheregisterTMSK2.Thedefault
prescalervaluewillcauseaclockratetotheGPTofthesystemclock
dividedbyfour.
Thequestionnowistheclockrate.Recallthattheclockcontrol
is a portion of the SIM.Within the SIM there is a register named
SYNCR. The clock frequency is controlled by the three bit fields
namedW,X,andYinthisregister.Whenoperatingatalowcrystal
frequencybetween 25 and 50 kHzthe formula for the system
frequencyisgivenby
2w+x
)
]
F = F
,
4 y +1
)(
2
s r

(
]
whereyhasavaluebetween0and63,andbothwandxcanhave
valuesof0or1.Withafrequencyfof32767andtheW,X,andY
defaultvaluesof0,0,and63,respectively,thedevicewillcomeout
ofresetwithasystemfrequencyof8.388MHz.Tobeabletogetthe
finestresolutionforourtimingfunctions,letusplantooperatethe
systemclockfrequencyatitsmaximumvaluebychangingthevalue
of X from its default value of 0 to 1. This change will cause the
systemfrequencytobe16.776704MHz.Thefrequencyoftheinput
into the GPT is one-fourth this value or 4.194176 MHz. The time
periodforthisfrequencyis238nanoseconds.
ThecodeforaPWMontheMC68HC11wasshowninChapter5.A
programthatimplementsaPWMontheMC68HC16isshownbelow.
/*ThisprogramprovidesapwmoutputtoOC3.Theperiod
willbetheintegervaluefoundinpwm_period,andthe
ontimewillbetheintegervaluefoundinpwm_count.
Keeppwm_countlessthanpwm_period.*/
300 Chapter6 Large Microcontrollers
#includehc16.h
#includegpt.h
#includesim.h
#definePERIOD0x1000
#defineON_TIME 0x0800
#defineGPT_IARB 5
#defineGPT_IRL 6
#defineGPT_VBA 4
/*functionprototypes*/
@portvoidOC3_Isr(void);/*thePWMisr*/
WORDpwm_period=PERIOD,pwm_count=ON_TIME;
main()
{
/*Theinitializationportionoftheprogram*/
SYNCR.X=ON;/*settheclockfreqto16.78MHz*/
SYPCR.SWE=OFF;/*disablethewatchdog*/
GPT_MCR.IARB=GPT_IARB; /*pick an IARBfortheTimers*/
ICR.IRL=GPT_IRL; /*interruptlevel6*/
ICR.VBA=GPT_VBA; /*vectorsstartat0x40*/
OCONM.OCONM3=ON; /*sentOC1outtopin*/
CONM.OCONM5=ON; /*coupleOC1toOC3*/
TMSKON.OC3I=ON; /*enabletheOC3interrupt*/
OCOND.OCOND5=ON; /*turnonOC3whenOC1occurs*/
TCTLON.OL3=ON;/*toggleOC3whenOC3occurs*/
TOC1=TCNT+pwm_period;/*setOC1totheperiod*/
TOC3=TOC1+pwm_count;/*setOC3timeon*/
cli(); /*enablethesysteminterrupts*/
/*theapplicationsportionoftheprogram*/
FOREVER
{
}
}
/*Theasynchronousserviceportionoftheprogram*/
@portvoidOC3_Isr(void)/*thePWMisr*/
APulseWidthModulationProgram 301
{
TFLG1.OC1F=OFF; /*resetOC1interruptflag*/
if(OC1D.OC1D3==ON)/*complimentOC1D3*/
OC1D.OC1D3=OFF;
else
OC1D.OC1D3=ON;
TFLG1.OC3F=OFF; /*resetOC3interruptflag*/
TOC1+=pwm_period;
TOC3=TOC1+pwm_count;
}
Listing6-2:ElementaryPWMProgramForTheMC68HC16
Inkeepingwiththenewusageofheaderfilesforwritingcode
fortheMC68HC16,theheaderfileshc16.h,gpt.h,andsim.h
areincludedintheaboveprogram.Thesefilescontaindefinitionsof
allregistersneededfortheimplementationofthisprogram.Youshould
includehc16.hwitheveryprogramorfunctionthatyouwritefor
thispart.Inthiscase,mostoftheprograminvolvesregisterswithin
thegeneralpurposetimer,sogpt.hisincluded.Thereisoneregis-
teraccessedfromthesystemintegrationmodule.Therefore,theheader
sim.hisalsoincluded.
TheMC68HC16containsasoftwarewatchdog.Thepartcomes
outofresetwiththewatchdogenabled.Therefore,unlessaprogram
periodicallyaccessesthewatchdog,thepartwillexecuteawatchdog
reset.Thisperiodicresetwillmakedebuggingoftimingoperations
difficult.Thewatchdogisdisabledinthefirstinstructionoftheini-
tialization of the program. The next three instructions are
MC68HC16-specificinstructions.
TheMC68HC16hasaseven-levelinterruptsystemsimilartothe
MC68000familyofparts.Theseventhlevelisthehighestpriority
and is the only nonmaskable interrupt for the part.The remaining
levelsareprogressivelylowerpriorityuntilthelevel0isfound.At
levelzero,nointerruptisbeingprocessed,andthisleveliswherethe
processorusuallyoperates.Whenaninterruptoccurs,thehardware
level of the interrupt is placed in the interrupt priority field of the
coderegister.Furtherinterruptsofthedesignatedlevelorlowerwill
remainpendinguntilaRTIinstructionrestorestheIPfieldtoalower
level.This approach provides for priority selection among several
internalorexternalinterruptsources.
302 Chapter6 Large Microcontrollers
Another potential problem occurs when two internal modules
areassignedthesameprioritylevel.Inthiscase,asecondlevelof
arbitrationissetuptochooseamongtheseseveralmodules,inthe
eventthatmorethanonemodulerequestsaninterruptatthesame
time.Themodulecontrolregisterofeachmodulehasafieldcalled
IARB.This 4-bit field is assigned by the programmer and it is an
arbitrationlevelthatwillbeappliedwhentheprocessormustselect
betweentwoequalpriorityinterruptsthatoccursimultaneously.The
interruptingmodulewiththelargestIARBvaluewillbegivencon-
troloftheprocessor.TheIARBfieldcancontainvaluesfrom0to
15.Whenthemoduleisbeingused,itsIARBfieldmustbeassigned
anon-zerovalue,andnotwomodulescancontainthesameIARB
value.Thecodeline
GPT_MCR.IARB=GPT_IARB;/*pick an IARBfortheTimers*/
placesavalue5intotheIARBofthegeneralpurposetimer.
Theinterruptlevel6isassignedtotheGPTbythecodeline
ICR.IRL=GPT_IRL; /*interruptlevel6*/
andthevectorbaseaddressisassignedavalueof40bythecodeline
ICR.VBA=GPT_VBA; /*vectorsstartat0x40*/
Themeansbywhichthevectorassignmentisaccomplishedin
the GPT is different from that for the remaining modules in the
MC68HC16.FortheGPT,a4-bitvectorbaseaddressfieldisfound
intheinterruptconfigurationregister.Avectorisan8-bitvalue.
Thevectorassignmentisaccomplishedwhenthevalueplacedin
theVBAfieldoftheICRisusedasthehighnibbleofan8-bitnum-
ber.ThelowerfourbitsarespecifiedbythecontentsofTable6-2.
ThereyouwillnotethatthevectoraddressofOC3 isat0xV6.When
thecontentsoftheVBAfieldis4,thenthevectorforOC3is0x46.
Thevectoraddressistwicethevalueofthevectoror0x8cinthis
case.ThatisthereasonthattheaddressOC3_Isrisplacedinthe
address0x8cinthevectorinitializationroutine.
Youwillnotethateachinterruptinthetimerwillbeassigneda
vector with the most significant nibble of the value placed in the
VBAfieldoftheICR.Thereisaprearrangedpriorityamongthese
severalinterrupts.Oneinterruptcanbemovedtothehighestpriority
amongtheseveraltimerinterruptsifdesired.Thepriorityadjustbits
APulseWidthModulationProgram 303
Table6-2:GPTInterruptPrioritiesAndVectorAddresses
Name Function Priority Vector
Level Address
AdjustedChannel 0(highest) 0xV0
IC1 InputCapture1 1 0xV1
IC2 InputCapture1 2 0xV2
IC3 InputCapture3 3 0xV3
OC1 OutputCapture1 4
0xV4
OC2 OutputCapture2 5
0xV5
OC3 OutputCapture3 6
0xV6
IC4 OutputCapture4 7
0xV7
IC4/OC5 InputCapture4/OutputCapture5 8
0xV8
TCF TimerOverflow 9
0xV9
PAOVF PulseAccumulatorOverflow 10
0xVA
PAIF PulseAccumulatorInput 11(lowest)
0xVB
PABfieldintheICRallowsthisshift.Forexample,ifthenumber6
were placed in the PAB field, then the priority of OC3 would be
shiftedfrom6to0,where0isthehighestpriorityofthe11levels
withtheGPT.Inthiscase,thevectorforOC3wouldbelocatedat
0x40, and the vector address would be 0x80. None of the other
interruptvectorsorprioritieswouldbechangedbythisoperation.
Theremainingcodeoftheinitializationsectionoftheabovepro-
gramisalmostthesameasthatfoundinListing5-5.Theregisterand
bitnamingconventionsusedwiththeMC68HC16aresuchthatthe
code written for the MC68HC11 can be used directly on the
MC68HC16.Thereisonechange.IntheMC68HC11,itwasneces-
sarytosettheDDRA7bittoallowtheoutputfromOC1toshowupon
thepinPA7.TheGPThasadifferentoutputpinarrangementonthe
MC68HC16anditdoesnotrequiretheuseoftheDDRAregisteratall.
Oneadditionalmodification:Acli()instructionwasusedin
Chapter5toenablethesysteminterrupts.Thereisnosinglebitin
theMC68HC16thatcanbeusedtoenabletheinterrupts.The3-bit
fieldintheconditioncoderegisternamedIPsetsthelevelofinter-
ruptthatcanbeacknowledged.Sincethereisnoequivalentinstruction,
amacrodefinitionofaninstruction
#definecli()(andp$ff1f\n)
isincludedintheheaderfilehc16.h.Thereisalsoamacro
#definesei()(orp$00e0\n)
304 Chapter6 Large Microcontrollers
Thesetwomacrosaccomplishtheequivalentofthesameinstruc-
tionsfortheMC68HC16.Thecli()instructionclearsthebitsof
the IP to zero, so that any interrupt will be acknowledged by the
processor. The sei() instruction set the IP bits so that only a
nonmaskableinterruptwillbeacknowledged.Additionalmacroscan
bewrittenthatenabletheprogrammertosettheinterruptlevelany-
wherebetween1and7ifneeded.
RecallthatwiththeMC68HC11thetworegistersTFLG1andTFLG2
weredifferentfromtheusualregistersinthepart.Toresetbitsinthese
registers,itisnecessarytowriteonestothedesignatedbitsratherthan
zeros. On the MC68HC16, this anomaly has been corrected. On the
MC68HC16,toresetbitsintheTFLG1andTFLG2registersthepro-
grammustwritezerostotheappropriatebits.Thatchangeshowsupin
twolocationsintheOC3_Isrroutine.Themuchmorelogical
TFLG1.OC1F=OFF;
.
.
TFLG1.OC3F=OFF;
instructionsareusedhere.Otherwise,theremainderoftheinterruptser-
viceroutineshowninListing6-2isthesameasthatfoundinListing5-5.
This portability is what you should expect when changing be-
tweentheMC68HC11andtheMC68HC16familyofparts.Carehas
been used in the design to assure that register names and bitfield
names are common between the families. Therefore, code written
fortheMC68HC11shouldmovetotheMC68HC16withlittlechange.
Theneedforchangeatalliscausedbythefactthatarchitecturesof
thebasicmachinesaredifferent.
EXERCISES
1.ModifytheprogramshowninFigure6-2toallowthePWMrange
tovaryfrom1to0XFFF.Compilethisprogramandtestthecode.
2.Writeamacrothatwillpermittheprogramtoputanarbitraryvalue
between0and7intotheIPfieldoftheconditioncoderegister.
CosmicMC68HC16Compiler 305
Cosmic MC68HC16 Compiler
TheCosmiccompilerfortheMC68HC16isquitesimilartothe
MC68HC11compiler.Itsoperationisthesame.Severalcommand
files are used in the course of executing a compilation, and these
fileswillbeshownhere.Thefirstfileistheprogramthatcompletely
compilesandlinkstheprogram.Thisfileisshownbelow:
c-dlistcs+s+o%1.c
lnkh16<%1.lnk
hexh16-s-o%1.hex%1.h16
pause
Thiscommandfilerequiresasaninputafilewitha.cextension.
Forexample,ifyouweretocompiletheprogramnewpwm.c,you
wouldenter
c:\>compnewpwm
The first line will invoke the compiler and create a listing file, a
sourceassemblylisting,andanobjectfilenamednewpwm.o.The
secondlineinvokesthelinkernamedlnkh16,andrequiresaninput
filenamednewpwm.lnk.The.lnkfileissimilartothatonedis-
cussedinChapter5,andalistingoftheoneforthisprogramisshown
below.
#LinkcommandfileforNEWPWM.c
+h #multi-segmentoutput
-max0xfffff #maximumsize
-ps16-pc. #setupbankingoptions
-onewpwm.h16 #outputfilename
+text-b0 #resetvectorsstart
address
vector.o #vectors
+text-b0x400 #programstartaddress
+data-b0x700 #datastartaddress
crts.o #startuproutine
newpwm.o #applicationprogram
c:/cc16/lib/libi.h16 #Clibrary(ifneeded)
c:/cc16/lib/libm.h16 #machinelibrary
+def__memory=__bss__#symbolusedbylibrary
306 Chapter6 Large Microcontrollers
Heretheentriesarefairlywellexplainedbythecomments.Note
thattwoadditionalinputfilesarerequiredbythislinkfile.Thevec-
tortablevector.oisacompiledversionofthevectorlistinggiven
inListing6-1.Thecrts.oobjectmoduleisanassembledversion
ofthestart-uproutineforthismachine.Bothoftheseroutinesmust
bewrittenandcompiledorassembledforthespecificprogram.Oth-
erwise,thelinkcommandfileisasdiscussedinChapter5.Aversion
ofcrts.sisshownbelow:
;CSTARTUPFOR68HC16
;Copyright(c)1991byCOSMIC(France)
;
.external_main,__memory
.external._main,.__bss__
.public_exit,__stext
.psect_bss
sbss:
.psect_text
__stext:
ldk#.__bss__
tbek
tbxk
tbzk
ldab#0fh ;startofthei/omemoryspace
tbyk ;putitiny
ldx#sbss ;startofbss
clrd ;tobezeroed
bramtest ;startloop
bcl:
std0,x ;clearmemory
aix#2 ;nextword
mtest:
cpx#__memory ;endofmemory?
blobcl ;no,continue
aix#1000h ;4Kstack
txs ;forinstance
jsr_main,#._main;callapplication
_exit:
bra_exit ;loophereifreturn
CosmicMC68HC16Compiler 307
;
.end
Intheabovecode,theEK,XK,andZKregistersareinitialized
tothevaluefoundin.__bss__.TheinitialvalueofYKissetto
0xf.TheYregisterwillbeusedbythecompilertocontainanoffset
toallofthedatacontainedinthecontrolregistersfoundintheheader
files.Therefore,theYKregistermustbesettothetopmemoryblock
inthecomputermemoryspace.
UsingtheSCIPortionoftheQueuedSerialModule
Thequeuedserialmodule(QSM)containstwoparts.Thefirstisa
convenient serial communications interface (SCI) which provides
asynchronousserialcommunicationsthatisusedbetweencomput-
ersandotherdevices.TheremainderoftheQSMisaqueuedserial
peripheral interface that is often used for high-speed communica-
tions between computers and peripheral devices. This interface is
strictlysynchronous.
Letsexamineaninterfacebetweentheprogramandaterminal
muchlikethatfoundinChapter5.Here,theinterfacewillsimply
read in a number from the screen and put that number into the
pwm_count value for the PWM program.With this operation in
place,theoperatorcantypeinavalueandchangethePWMontime
atwill.Listing6-3containsaprogramthatwillaccomplishthisend.
#includehc16.h
#includegpt.h
#includesim.h
#includeqsm.h
#includedefines.h
#definePERIOD0x1000
#defineON_TIME 0x0800
#defineSIM_IARB 4
#defineGPT_IARB 10
#defineGPT_IRL 6
#defineGPT_VBA 5
/*setthebaudrate=fclock/32*baud_rate*/
#defineBAUD_SET (32768*512)/(32*38400)
/*functionprototypes*/
@portvoidOC3_Isr(void);
308 Chapter6 Large Microcontrollers
/*Externalvariables*/
WORDpwm_period=0x1000,pwm_count=0x0800,new_input=0;
BYTEnew_character;
main()
{
/*Theinitializationportionoftheprogram*/
/*initializetheSIMregisters*/
SYNCR.X=ON; /*setthesystemfreqto16.78mHz*/
SYPCR.SWE=OFF; /*disablethewatchdog*/
/*initializetheGPT*/
GPT_MCR.IARB=GPT_IARB;/*pickanIARBforthetimers*/
ICR.IRL=GPT_IRL; /*interruptlevel6*/
ICR.VBA=GPT_VBA; /*vectorsstartat0x40*/
OC1M.OC1M3=ON; /*sentOC1outtopin*/
OC1M.OC1M5=ON; /*coupleOC1toOC3*/
TMSK1.OC3I=ON; /*enabletheOC3interrupt*/
OC1D.OC1D5=ON; /*turnonOC3whenOC1occurs*/
TCTL1.OL3=ON; /*toggleOC3whenOC3occurs*/
TOC1=TCNT+pwm_period; /*setOC1totheperiod*/
TOC3=TOC1+pwm_count; /*setOC3timeon*/
/*initializetheSCI
SCCR0.SCBR=BAUD_SET;
SCCR2.TE=ON;
SCCR2.RE=ON;
*/
/*setbaudrateto9600*/
/*enablethetransmitand*/
/*receiveroftheSCI*/
cli(); /*enablethesysteminterrupts*/
/*theapplicationsportionoftheprogram*/
FOREVER
{
if(SCSR.RDRF==ON)/*readindataifitisthere*/
{
new_character=SCDR; /*getnewbyte,resetRDRF*/
while(SCSR.TDRE==OFF) /*waituntiltransmit
bufferempty*/
SCDR=new_character;/*sendoutbyteandresetTDRE*/
/*gotaninput,processit*/
if(new_character>=0'&&new_character<=9')
new_input=10*new_input+new_character-0';
elseif(new_character==\r)
{
/*rejectanynumberoutofrange*/
CosmicMC68HC16Compiler 309
/*andstartoveragain*/
if(new_input>=1&&new_input<=4048)
pwm_count=new_input;
new_input=0;
}
else
new_input=0; /*rejecteverythingelse*/
}
}
}
/*Theasynchronousserviceportionoftheprogram*/
@portvoidOC3_Isr(void)/*thePWMisr*/
{
TFLG1.OC1F=OFF; /*resetOC1interruptflag*/
if(OC1D.OC1D3==ON) /*toggleOC1D3*/
OC1D.OC1D3=OFF;
else
OC1D.OC1D3=ON;
TFLG1.OC3F=OFF; /*resetOC3interruptflag*/
TOC1+=pwm_period;
TOC3=TOC1+pwm_count;
}
Listing6-3:PWMSystemWithKeyboardInput
Theqsm.hheaderfileisincludedtoaddalloftheregisterand
definesneededfortheoperationoftheSCI.Wearegoingtoplace
the operation of the SCI into the applications portion of the pro-
gram.ImplementationoftheSCIrequiresthatabaudratebeselected
andthetransmitenablealongwiththereceiveenablebitsbesetin
theserialcommunicationscontrolregisternumber2.Thebaudrate
issetto38400byplacingaproperlycalculatedvalueintotheSCBR
fieldofSCCR0.Withtheselinesofcode,theserialcommunications
interfaceissetupandreadytowork.
Thecodeinsidetheapplicationportionoftheprogramisessen-
tiallyidenticaltothatfoundinChapter6.Theonlydifferenceisthat
thevariablenamesarechangedtobemorecompliantwiththisappli-
cation.Hereisanotherinterestingcasewherethecodewrittenfor
theMC68HC11willmovedirectlytotheMC68HC16withminimal
change.
310 Chapter6 Large Microcontrollers
This program is a minimum SCI system. The SCI portion of
thischiphascomprehensivecapabilitiesthatarenotexploitedinthe
programabove.Thesecapabilitiesanderror-checkingdevicesareall
availableonthechip,andtheiraccessanduseisexplainedindetailin
the QSM Reference Manual.Access of the various capabilities is
exactlythesameaswasshownaboveinthisprogram.
PeriodicInterrupt
Tomaketheproblemalittlemoreinteresting,letsaddanother
loadtothemachinebymakinguseoftheperiodicinterruptcapabil-
ityprovidedintheSIMtocreateaninterrupt.Withthisinterrupt,we
willbuildatime-of-dayclocksimilartothatdevelopedinChapter4.
Inthiscaseyouwillseethattheapplicationscodedevelopedforthe
MC68HC05willworkfinefortheMC68HC16.Ofcourse,theini-
tializationcodeandtheinterruptserviceroutinewillbecompletely
differentfortheMC68HC16.Thisadditionalcodewillbeputright
intotheprogramlistedinListing6-3.Itisassertedthattherewillbe
noadverseinteractionsbetweenthevarioussectionsofthecode.
#includehc16z1.h
#includegpt.h
#includesim.h
#includeqsm.h
#includedefines.h
#definePERIOD0x1000
#defineON_TIME 0x0800
#defineSIM_IARB 4
#definePIC_PIRQL6
#definePIC_PIV 0X38
#definePIT_PITM 16
#defineGPT_IARB 10
#defineGPT_IRL 6
#defineGPT_VBA 5
/*setthebaudrate=fclock/32*baud_rate*/
#defineBAUD_SET (32768*512)/(32*38400)
#defineTIME_COUNT 1000
#defineMAX_MIN 59
#defineMAX_HOURS12
#defineMIN_HOURS1
#defineNO_WAIT 0
#defineOC2_OFFSET 5
#defineMAX_SEC 59
CosmicMC68HC16Compiler 311
#defineMAX_MIN MAX_SEC
#defineMAX_HOURS12
#defineMIN_HOURS1
/*functionlikemacros*/
#defineget_hi(x)((x)/10+0')
#defineget_lo(x)((x)%10+0')
/*functionprototypes*/
@portvoidOC3_Isr(void);
@portvoidPIT_Isr(void);
voidoutput_time(void);
voidputch(int);
voidsend_out(WORD);
/*Externalvariables*/
WORDpwm_period=PERIOD,pwm_count=ON_TIME,new_input=0;
WORDhrs,mts,sec,been_here=0;
charnew_character;
main()
{
/*Theinitializationportionoftheprogram*/
/*initializetheSIMregisters*/
SYNCR.X=ON; /*setthesystemfreqto16.88mHz*/
SYPCR.SWE=OFF; /*disablethewatchdog*/
SIM_MCR.IARB=SIM_IARB;/*IARBsforeachmodule is
different*/
PICR.PIRQL=PIC_PIRQL; /*putalltimersatlevel6*/
PICR.PIV=PIC_PIV; /*vectoris0x38,addressis0x70*/
PITR.PTP=ON; /*512prescaler*/
PITR.PITM=PIT_PITM; /*divideby16*4,1ticper
second*/
/*initializetheGPT*/
GPT_MCR.IARB=GPT_IARB;/*pickanIARBforthetimers*/
ICR.IRL=GPT_IRL; /*interruptlevel6*/
ICR.VBA=GPT_VBA; /*vectorsstartat0x40*/
OC1M.OC1M3=ON; /*sentOC1outtopin*/
OC1M.OC1M5=ON; /*coupleOC1toOC3*/
TMSK1.OC3I=ON; /*enabletheOC3interrupt*/
OC1D.OC1D5=ON; /*turnonOC3whenOC1occurs*/
TCTL1.OL3=ON; /*toggleOC3whenOC3occurs*/
TOC1=TCNT+pwm_period;/*setOC1totheperiod*/
TOC3=TOC1+pwm_count;/*setOC3timeon*/
312 Chapter6 Large Microcontrollers
/*initializetheSCI*/
SCCR0.SCBR=BAUD_SET;/*setbaudrateto9600*/
SCCR2.TE=ON; /*enablethetransmitand*/
SCCR2.RE=ON; /*receiveroftheSCI*/
cli(); /*enablethesysteminterrupts*/
/*theapplicationsportionoftheprogram*/
FOREVER
{
if(SCSR.RDRF==ON)/*readindataifitisthere*/
{
new_character=SCDR; /*getnewbyte,
resetRDRF*/
while(SCSR.TDRE==OFF)
; /*waituntiltransmit
bufferempty*/
SCDR=new_character; /*sendoutbyteand
ResetTDRE*/
/*gotaninput,processit*/
if(new_character>=0'&&new_character<=9')
new_input=10*new_input+new_character-0';
elseif(new_character==\r)
{
/*rejectanynumberoutofrange*/
/*andstartoveragain*/
if(new_input>=1&&new_input<=4048)
pwm_count=new_input;
new_input=0;
}
else
new_input=0;/*rejecteverythingelse*/
}
if(sec>MAX_SEC)
{
sec=0;
if(++mts>MAX_MIN)
{
mts=0;
if(++hrs>MAX_HOURS)
hrs=MIN_HOURS;
}
}
if(been_here&&!new_input)
{
CosmicMC68HC16Compiler 313
been_here=OFF;
output_time();
}
}
}
voidoutput_time(void)
{
inti;
putch(\r); /*sendoutacarriagereturn*/
putch(\t);
putch(\t); /*taboverthepwm_count*/
putch(\t); /*onthescreen*/
send_out(hrs);
putch(:);
send_out(mts);
putch(:);
send_out(sec);
putch(\r);
}
voidputch(intx)
{
while(SCSR.TDRE==OFF)
; /*waituntildata
registerisempty*/
SCDR=(char)x;
}
voidsend_out(WORDdata)
{
putch(get_hi(data));
putch(get_lo(data));
}
/*Theasynchronousserviceportionoftheprogram*/
@portvoidOC3_Isr(void)/*thePWMisr*/
{
TFLG1.OC1F=OFF; /*resetOC1interruptflag*/
if(OC1D.OC1D3==ON)
OC1D.OC1D3=OFF;
else
OC1D.OC1D3=ON;
TFLG1.OC3F=OFF; /*resetOC3interruptflag*/
TOC1+=pwm_period;
314 Chapter6 Large Microcontrollers
TOC3=TOC1+pwm_count;
}
@portvoidPIT_Isr(void)/*thePITisr*/
{
been_here++;
sec++;
}
Listing6-4:ClockRoutineAddedtoPWM
IfyoucomparethislistingwiththatshowninListing6-3,youwill
find that there are few structural changes to the program.The code
usedtoinitializetheSIMischangedbytheadditionoftheinitializa-
tionoftheperiodictimerinterrupt.Thiscodeisshownbelow.
SIM_MCR.IARB=SIM_IARB; /*IARBsforeachmodule
isdifferent*/
PICR.PIRQL=PIC_PIRQL; /*putalltimersat
level6*/
PICR.PIV=PIC_PIV; /*vectoris0x38,
addressis0x70*/
PITR.PTP=ON; /*512prescaler*/
PITR.PITM=PIT_PITM; /*divideby16*4,1
ticpersecond*/
The interrupt arbitration level field in the SIM module control
registerissetto4.Recallthatthevalueherecanbeanywherebe-
tween 1 and 15, with 15 the highest priority. All active internal
modulesthataretouseaninterruptmusthaveauniqueIARBvalue.
The IARB value for the GPT was set to 5. Note that the interrupt
levelforboththeGPTandthePITissettothelevel6.Therefore,
both sources of timing have the same interrupt priority; however,
since the IARB of the GPT is higher than that of the PIT, in the
event of a simultaneous occurrence of the two interrupts, the GPT
serviceroutinewillbeexecutedbeforethePIT.
TheinterruptvectorforthePITisplacedat0x38.Becausethe
addressofthevectoristwicethevalueofthevector,theinterrupt
vectoraddressis0x70.ApointertothePITinterruptservicerou-
tine will be placed at this address in the vector.c routine. The
periodic timer itself is set up by the next two lines of code. This
clockisdrivenbytheEXTALsignal.Inourcase,thefrequencyof
CosmicMC68HC16Compiler 315
theEXTALsignalis32768Hz,notsomenumberaround16MHz.
Theformulatocalculatetheperiodicinterrupttimeis
T = 4 PITM 511PTP +1
)
/F
pit
(
extal
HerePITMisthe8-bitfieldwiththesamenamefoundinthe
PITR.PTPisasingle-bitfieldinthePITRthatcanhaveavalueof
either0or1.Assuch,ifPTPis1,theprescalervalueof512isused.
Otherwise,whenthereisnoprescaler,thevalueintheparentheses
reducesto1.Withthevaluesplacedinthesefieldsintheabovecode,
i.e.,PTPof1,andPITMof64,andwitha32768-Hzexternalcrys-
tal,theperiodicinterrupttimeshouldbeonesecond.
Twoadditionalblocksofcodeareaddedtotheapplicationssec-
tionofthecode.Thiscodeisshownbelow:
if(sec>MAX_SEC)
{
sec=0;
if(++mts>MAX_MIN)
{
mts=0;
if(++hrs>MAX_HOURS)
hrs=MIN_HOURS;
}
}
if(been_here&&!new_input)
{
been_here=OFF;
output_time();
}
Thefirsteightlinesofcodeherearetakendirectlyfromsimilar
clockingcodefoundinChapter4.Thiscodemerelycountsthetime
inseconds,minutes,andhours.Thesecondblockofcodedetermines
ifaPIThasbeenserviced,andifithas,itresetsthebeen_here
flagthatindicatedthatthePITserviceroutinehasbeenenteredand
thensendsthetimeouttheserialportwhenoutput_time()is
executed.
Hereisacasewhereseveralsubroutinesareusedintheapplica-
tions portion of the program. output_time( ) calls functions
putch( ) and send_out( ). In turn send_out( ) calls
316 Chapter6 Large Microcontrollers
convert_bcd().putch()isstraightforward.Thisroutine
waits until the transmit data register is empty and then stores the
charactertobetransmittedintotheserialcommunicationsdatareg-
ister.Theroutinesend_out()takesthecharacterparameterpassed
toitandcausesittobeconvertedfromintegerformattotwobinary-
coded decimal BCD characters. These two characters are then
convertedtoASCIIcharactersbytheadditionofthecharacter0to
eachandthensenttotheoutput.(Recallthatconvert_bcd()
wasshowninChapter4inListing4-8.)Anotherversionofthisfunc-
tionisshowninListing4-7.Thisalternateversionhasbeentriedin
theprogramaboveanditworksaswellasthefunctionusedabove.
Withthefunctionsputch()andsend_out()available,it
isasimplemattertowritethecodethatwilloutputthetimetothe
centerofthetoplineofthescreen.Itisassumedthatthecursorison
the top line when the program begins to run. The last remaining
modificationistheinterruptserviceroutinePIT_Isr().Within
thisfunction,thebeen_hereflagisset,andthevalueinsecis
incremented.Sincetheapplicationsportionoftheprogramwillpro-
cesssecandresetitwheneveritreachesavalueof60,thereisno
needforothercodeinthisisr.Forinterest,listedbelowistheout-
putfromthecompilerforbothOC3_Isr()andPIT_Isr().
;150@portvoidOC3_Isr(void)/*thePWMisr*/
;151{
.even
_OC3_Isr:
pshmk,z,y,x,d,e
tskb
tbek
tbxk
tbyk
tbzk
;152 TFLG1.OC1F=OFF;/*resetOC1interruptflag*/
ldy #0
bclr-1758,y,#8
;153 if(OC1D.OC1D3==ON)
brclr -1783,y,#8,L102
;154 OC1D.OC1D3=OFF;
bclr-1783,y,#8
CosmicMC68HC16Compiler 317
;155 else
bra L112
L102: ;line155,offset33
;156 OC1D.OC1D3=ON;
ldy #0
bset-1783,y,#8
L112: ;line156,offset41
;157 TFLG1.OC3F=OFF;/*resetOC3interruptflag*/
ldy #0
bclr-1758,y,#32
;158 TOC1+=pwm_period;
ldd _pwm_period
addd-1772,y
std -1772,y
;159 TOC3=TOC1+pwm_count;
addd_pwm_count
std -1768,y
;160}
pulmk,z,y,x,d,e
rti
;161
;162@portvoidPIT_Isr(void)/*thePITisr*/
;163{
.even
_PIT_Isr:
pshmk,z,y,x,d,e
tskb
tbek
tbxk
tbyk
tbzk
;164 been_here++;
incw_been_here
;165 sec++;
incw_sec
;166}
pulmk,z,y,x,d,e
rti
Listing6-5:InterruptServiceRoutines
318 Chapter6 Large Microcontrollers
Lines 150 through 160 above are the interrupt service routine
OC3_Isr()andlines161through166comprisethePIT_Isr().
Themainitemthatisobservedhereisthequalityoftheoptimizerforthe
compiler.Ingeneral,interruptserviceroutines,ISR,mustsavethecom-
pletestatusofthemachinepriortoexecutinganycode.TheCCRalong
withthePCarebothsavedbytheinterruptsequence.Theremainderof
theregistersmustalsobesavediftheISRcanuseanyoftheadditional
registerresourcesofthecomputer.Usuallythiscasewillbefound.Note,
forexample,inOC3_Isr()thefirstinstructionis
pshmk,z,y,x,d,e
Thisinstructioncausesthecontentsofallsignificantregisterstobe
savedonthestack,sothatthestatusofthemachineatthetimethe
interruptoccurredcanberestoredbeforecontrolisreturnedtothe
portionoftheprogramthatwasinterrupted.Thisrestorationiscom-
pletedbythetwoinstructions
pulmk,z,y,x,d,e
rti
whichrefillsalloftheregisterswiththevaluestheycontainedwhen
theISRwasentered,andthertiinstructionrestoresthecondition
code register to the value it had and the program counter is then
restored.Thus,thestatusofthemachineisrestoredandtheprogram
controlisreturnedtotheinterruptedinstruction.Notethattherou-
tinePIT_Isr()compilestoamuchsimplerroutine.Thisroutine
has simply two increment instructions and requires no register re-
sources. The optimizer recognizes this simple operation and does
notsavethestatusbeyondthatsavedwhentheinterruptoccurred.
Thisroutinehasprobablybeenpushedfurtherthanitshouldbe,
fordemonstrationpurposes.Thisroutinedemonstratesmultiplein-
terrupts working simultaneously, keyboard input and output, and
generatesasimplepulse-widthmodulationsignalwhoseonperiod
isdeterminedbyanumberenteredfromthekeyboard.Allofthese
operationsarequitesimilartothoseshowninChapter5;however,
somemajormodificationsinapproacharerequiredtomeetthesev-
eralrequirementsoftheperipheralcomponentsontheMC68HC16.
Let us now look at some other applications often used with
microcontrollers.
Table Look-up 319
Table Look-Up
Oftenintheimplementationofapracticalproblemitisnecessaryto
implement a conversion of data in a completely heuristic manner.
Observationsaremadeandacurveofsortsisfittothedata.Itisthen
desiredtoputafewsamplesofthiscurveintoadatatableandthen
calculatevaluesbetweenthesesampleswithanaccuracythatusually
requiresinterpolationbetweenthepointscontainedinthedatatable.
Suchtablesareusuallysparseinthatthenumberofmeasuredpoints
acrosstherangecoveredbythetablearefew.ThecurveinFigure
6-1showsanexampleofsuchaconversiontable,andthetableitself
isshownasTable6-3.
250
200
150
100
50
0
20 40 80 120 180
Figure6-1:DataConversionCurve
X Y
Table6-3:Look-UpTable
20 5
40 15
80 50
120 120
180 240
Theobjectoftheprogramistodelivertotheprogramanumber
like67andgettheproperresultbackfromthetablelook-uproutine.
Thexvalueof67liesbetweenthe40andthe80entryinthetable.
Therefore,theinterpolationcalculationneededinthiscaseis
320 Chapter6 Large Microcontrollers
Result=15+ 50 15
)
(
67 40
)
=38.625
(
80 40
Noticethatthereisaproductandadivisionthatisthesamefor
allinputvaluesbetween40and80inthiscase.Thiscalculationis
theslopeofthelinebetweenthetwopointsbeinginterpolated.Usu-
allytablelook-upoperationsareusedwheretimeconstraintsonthe
programaregreatsothattheseoperations,multiplyanddivide(es-
peciallydivide),areunwelcomeintheseprograms.Thereisawayto
avoidthedivideoperation.Notethatbetweeneachsetofpointsthe
slopeisaconstant.Therefore,iftheslopeofthelineisbuiltintothe
table,thecalculationwouldinvolveonesubtraction,onemultiply,
andoneaddition.Letusmodifythetableabovetocontaintheslopes
ofthelinesbetweeneachpoint.
20 5 0.5
40 15 0.875
80 50
1.75
120 120 2
180 240
Table6-4:Look-UpTableWithSlopes
Notethattheslopeofthelinerunsfromthelowerpointtothe
nextpoint.Therefore,thereisnoslopeforthelastpoint.Whenthis
tableisbuiltinmemory,itconsistsofaheaderfollowedbyafour-
byteentryforeachentryinthetable.Theheaderconsistsofasingle
bytethatindicatesthelengthofthetable.Inthiscase,sincethetable
startswithanindependentvariablevalueof20,thereareexpectedto
benoinputvalueslessthan20.Ifthereare,however,thevalueof5
willbeusedfortheseoutputvalues.Also,ifthevalueoftheindepen-
dentvariableisgreaterthanthemaximumof180,avalueof240will
be returned from the routine.With data from the above table, the
calculationabovewouldreduceto
Result=15+0.875(67-40)=38.625
which requires a multiply, a subtract and one add. Of course, the
routinewilltruncatethefractionalpartoftheresultsothatthevalue
returnedwillbe38.
Table Look-Up 321
Eachtableentrycontainsfourbytes.Thefirstbyteistheinde-
pendent variable value, often designated as x. The second byte
containsthedependentvariablevalue,usuallycalledy,andthefinal
two bytes contain a floating point format of the slope. The slope
mustbefloatingpoint.Thethirdbytecontainstheintegerpositionof
the slope, and the fourth byte contains the fractional value of the
slope.Withthebinarypointplacedbetweenthethirdandfourthbytes
ofthetableentry,wecanaccomplishsomeinterestingmultiplyop-
erations.Priortolookingatthecodingofthisproblem,letuscomplete
thetableandconverttheslopesintohexadecimalformat.
5
20 5 0x00 0x80
40 15 0x00 0xe0
80 50
0x01 0xc1
120 120 0x02 0x00
180 240
Table6-5:Look-UpTablewithHexadecimalSlopes
HowdoesonebuildatableofthisnatureinC?Ofcourse,itisan
arrayofstructures,oritcouldbeastructurethatcontainsanarrayof
structures.Thelatterapproachwouldbe
structentry
{
charx;
chary;
intslope;
};
structlut
{
charentries;
structentrydata[5];
}_lut={
5,
20,5,0x0080,
40,15,0x00e0,
322 Chapter6 Large Microcontrollers
80,50,0x01c0,
120,120,0x0200,
80,240
};
Notethatinthetableabove,theslopesareenteredinthetableas
two-byteintegers.Thereisnobinarypointintheslope.Theconver-
sionoftheseintegerstofloating-pointnumbersisaccomplishedeasily.
Wemustmerelyrecognizethatthesenumbersareafactorof128too
large, so after the slope is used as a multiplier, the result must be
dividedby128togetthecorrectanswer.Ofcourse,divisionby128
canbeaccomplishedbyashiftrightby8,ormorepracticallymerely
choosingtheleftbyteoftheproduct.
Afunctionthatwillmakeuseofthistableis
chartable_look_up(charx_in)
{
inti;
for(i=0;x_in>_lut.data[i].x&&i<=_lut.entries;i++);
if(i>=_lut.entries)
return_lut.data[_lut.entries-1].y;
elseif(i==0)
return_lut.data[0].y;
else
return_lut.data[i-1].y+(((x_in-_lut.data[i-1].x)*
_lut.data[i-1].slope)>>8);
}
Listing6-6:TableLook-UpRoutine,Version1
Thecompileroptimizerwillrecognizetheshiftrightby8inthe
above function and will merely select the upper byte of the result
ratherthanexecutingtheshiftoperationindicated.
Thisfunctionwascheckedonanevaluationsystemforthesingle
input value of 67 and the result was the expected value of 38. Of
course,thatdidnotcheckthefunctionoveritsfullrangeofopera-
tion. The check over the full range was accomplished on a host
machine.Itisasimplemattertoincludetheabovefunctionandtable
inthefollowingprogram.
#includetlu.h
voidmain(void)
Table Look-Up 323
{
inti;
for(i=0;i<256;i++)
printf( i=%dr=%d\n,i,table_look_up(i));
}
wheretlu.hcontainsthefunctionandthetableabove.Thiscode
compilesandrunsonaMS-DOCPC,andtheresultisasexpected.
Here, the program scans the entire input range and prints out the
resultantvalueateachpoint.Acheckoftheoutputswillshowthat
thefunctionhitsthebreakvalueateachbreak,andcreatesalinear
interpolationbetweenallpoints.Forvaluesaboveorbelowtherange,
theproperoutputisobserved.
Inanormalcontrolsystem,therewilloftenbeneedforseveraltable
look-upoperations.Theabovecodeisnottoogoodinthiscasebecause
thecodetodothelook-upmustberepeatedwitheachtable.Thisextra
codecanbeeliminatedifthefunctiontable_look_up()ispassed
twoparameters:thefirstparameteristheinterpolationvalue,andthe
secondvalueisapointertothelook-uptableasisshownbelow:
chartable_look_up(charx_in,structlut*table)
{
inti;
for(i=0;x_in>table->data[i].x&&i<=table->entries;i++);
if(i>=table->entries)
returntable->data[table->entries-1].y;
elseif(i==0)
returntable->data[0].y;
else
returntable->data[i-1].y+
(((x_in-table->data[i-1].x)*table->data[i-1].slope)>>8);
}
Listing6-7:TableLook-Up,Version2
This form of the table look-up should probably be used in all
cases. Here is another example of where it is wise to examine the
codegeneratedbyacompiler.Itwillnotbelistedhere,buttheas-
semblycoderequiredforListing6-6is182byteslong,andthatfor
listing6-7isbut142bytes.Thisgreatlyimprovedutilityautomati-
callygivesasubstantialsavingsincode.
It was pointed out that the compiler optimizer will sometimes
changethebasiccodedictatedbytheprogrammer.Perhaps,itshould
324 Chapter6 Large Microcontrollers
bestatedthattheoptimizerchangesthecodesuggestedbythepro-
grammer.Oftenwhenyouexaminethecodegeneratedbythecompiler,
the operations that take place will not even resemble those that the
programmer had in mind. This alteration of the code will show up
withshifts,anddividesorproductsofpowersoftwo.Aproperoptimizer
shoulddetermineifamultiplyorashiftisbetterandprovidethebest
code. Often you will find that the compiler optimizer will provide
either fastest execution or minimum code. Usually the two will be
different.Fastercodewillalmostalwaystakemorememory.
Itmayseemthatthelosttimeissmall,butyouwillalwaysfind
thatifyouwantfastcode,youwillnotuseanyloopingconstructs.The
codethatincrementsacounterandteststhecountermustbeexecuted
eachloop.Withouttheloopingconstruct,thiscodeiscompletelyelimi-
nated, and its execution each loop will be completely eliminated.
Therefore,ifyouwantfastcode,youshouldeliminateloopingcon-
structsandrepeatthecodewithintheloopthedesirednumberoftimes.
Thecostofthismoveismorecode.Wehavealsoseenthatrecursive
codecanrequireaninordinantamountoftime.Again,recursivecode
merelycreateshiddenloopingconstructsthatrequirefrequentgenera-
tionofstackframespriortonewfunctioncalls.Theconstructionof
these stack frames and return from functions require time which is
oftenmaskedbytheelegantappearanceofthecode.Usuallyyouwill
producefastercodeifyoufigureawaytoaccomplishthesameend
operationwithoutcallstotheexecutingfunction.
Today, we are at the very beginning of a completely new set of
microcontrollers.ThesemachinesarebasedonRISC(reducedinstruc-
tionsetcomputer)techniques.Donotbemisled.RISCdoesnotreally
meanreducedinstructionset.Theinstructionsetsarecompleteand
extensive.However,thebasicarchitectureofaRISCmachineisquite
different from the older machines like those we have been working
with.Oneofthemaindifferencesisthatthedesignofthemachineis
to provide for the execution of one or more instructions with each
clock cycle.A standard RISC will allow almost one instruction per
clock cycle, and a super scaler architecture will allow two or more
instructionsperclockcycle.Thisoperationisenabledbytheuseof
instructionpipelinesandmultiplearithmeticlogicunits(ALUs).Some-
times, an instruction must use more than one clock to complete an
Table Look-Up 325
instruction.Forexample,anintegermultiplyinstructionmightrequire
fiveclockcycles.Inthatcase,aninstructionpipefiveinstructionslong
wouldbeimplementedwithintheintegerALU.Therefore,amultiply
instructionwouldbelaunchedintotheinstructionpipeforexecution.
Inthemeantime,otherinstructionscouldexecutewhilethemultiplyis
progressingthroughthepipe.
Compileroptimizationforthesemachinesmusttakeintoaccount
allofthepipes,theseparateALUs,andotheruniqueoperationswhen
creatingtherequiredassemblycode.Clearly,astraightforwardcre-
ation of code in the order that might seem to be natural to a
programmerwillnotnecessarilycreatethequickestcodeforaRISC
machine.Here,speedoptimizationconsistsofarrangingthecodeso
that,asnearlyaspossible,themaximumnumberofinstructionsare
launched each clock cycle. This rearrangement of your code will
makeitextremelydifficulttoexaminetheassemblycodeversionof
theprogramandevenmakesenseofit.Solongastheresultsarenot
altered, the optimizer for a RISC machine will move instructions
aroundinthecodestreamtoaccomplishthisend.Therefore,froma
practicalsense,anydebuggingonaRISCmachinewillprobablybe
done with a source level debugger, and not an assembly language
versionoftheprogram.
The chip used in Chapter 8 is of the MCORE family of RISC
microcontrollers.Wewillseemoreoftheabovecommentsinthat
chapter.
EXERCISE
1.Sometimes two input values are needed to specify a parameter.
Forexample,ifyourecallfromChapter5,thechangeinpulseon
timetoproperlycontrolthemotorspeedwasgivenby
p = 3809500
p
2
c
p
createasparsetwo-dimensionallook-uptablewhoseinputsarepand
pandwhichprovidesp
c
astheresultofthreeinterpolations.Isthe
look-uptablebetterthanthecalculationinanywaylesscode,quicker,
etc.?Whywouldyouusealook-uptableinaproblemlikethisone?
326 Chapter6 Large Microcontrollers
Digital Signal Processor Operations
Most microcontrollers, regardless of their basic speed, are not
really able to process signals in real time. The basic speed of the
processorsisfastenoughtoaccomplishmostsignalprocessing;how-
ever,thesetofthingsneededtododigitalsignalprocessingisnot
usuallyavailableintheregularmicrocontroller.Thebasicdigitalsig-
nalprocessor(DSP)functionthatisrequiredissummarizedbythree
actions:1)theprocessormustmultiplytwovalues,2)theprocessor
mustaddtheproductintoavalue,and3)itmustprepareforthenext
multiply.Thissetofoperationsmustexecutequicklyenoughthatthe
computercankeepaheadofthereal-timeinputofdatabeingpro-
cessed.Almost all signal processing operations are based on the
multiply-accumulatesequence.Filtering,correlationoperations,sca-
lar products of vectors, Fourier and other transformations, and
convolutionsarebutafewoftheoperationsthatarebuiltaroundthe
DSPmultiplyandaccumulatesequenceabove.TheMC68HC16fam-
ilyhasanextensiontoitscorethatcanexecutebasicDSPoperations
fastenoughtosupportreal-timefiltering,correlation,andsoforth.
Unfortunately, C compilers do not know of these added func-
tions,sotheCprogrammerwouldseemtobeunabletoincludeDSP
operationsinprograms.Wewillseeherethat,whileitisratherin-
convenient,itispossibletowriteassemblyfunctionsthatwillpermit
the programmer access to the complete DSP capabilities found in
thisfamilyofdevices.
OneofthegoodfeaturesofCisthatitisnotnecessaryforthe
programmertohavedetailedknowledgeofthenatureofthebasic
computerbeingprogrammed.Sofar,wehavehadlittletosayabout
accumulatorsorindexregistersorthelike.Nomore!Wemustnow
getinsideofthecomputertocreatefunctionsthatwillaccomplish
ourDSPneeds.Whenthesefunctionsarecomplete,weshouldbe
abletotreattheDSPoperationsinmuchthesamemannerthatwe
wouldanyotherfunctioncall.TheDSPcontainsfourregistersand
controlsthreebitsintheconditioncoderegister(CCR).Thefirsttwo
registers are called the MAC multiplier input registers H and I, re-
spectively. These registers must be loaded with the multiplier and
the multiplicand to be executed. Data stored in these registers are
signedfractionalbinarynumberswiththeradixpointbetweenbits
15and14.TheproductwillbeaccumulatedintotheMACaccumu-
DigitalSignalProcessorOperations 327
lator M register.This register is 36 bits long. For convenience, the
registerisbrokenintotwoportions,bits35through16andbits15
through0.Wewillseelaterthatdifferentportionsofthisregisterare
moved by different instructions, so that breaking this register into
thetwopartsislogical.
ThelastregisterintheDSPregistermodelistheMACXYmask
register.Automaticselectionoftheaddressesforthenextmultiply
needsmoduloarithmetic.Wewillseemoremoduloarithmeticlater.
The mask register contains the modulo base for both the x and y
indexregisterswhichwillallowfixedcoefficienttables,thatcanbe
manipulated as either single-or two-dimensional arrays, to be tra-
versed automatically during successive multiply and accumulate
instructions.TheDSPregistermodelisshowninFigure6-2below.
H R
I R
A M
A
XMSK YMSK
M
20 16 15 8 7 0 BitPosition
MACMultiplierRegister
MACMultplicanRegister
MACAccumulatorMSB[35-16]
MACAccumulatorLSB[15-0]
MACXYMaskRegister
Figure6-2:MC68HC16DSPRegisterModel
The CCR contains three bits that are associated with the DSP.
Bits14and12areDSPoverflowflags.Theseflagswillbediscussed
indetaillater.Bit4iscalledtheSMbitandistheDSPsaturation
modecontrolbit.
15 3 0
CCR S H N Z V C l1 l2 l3 MV EV SM PK
DSPControlBits
Figure6-3:DSPControlBitsInTheCCR
Theaccumulatoris36bitswiththeradixpointbetweenbits31
and30.WhenaccumulatingintotheMACaccumulatorAM,thereare
328 Chapter6 Large Microcontrollers
twotypesofoverflowthatcanoccur.Thefirstiswhenanaddition
operation, which should always add fractions, causes an overflow
from bit 30 to 31.This type of overflow is reversible because the
arithmeticthatcausedtheoverflowcannotcausemorethana1-bit
overflowerror,andbitsAM[34-31]aretheretoabsorbthistypeof
overflow.Thecontentsofthisregisteraresigned,sothatbit35ofAM
isthesignbit.Themaximumvaluethatcanbeplacedinthe36-bit
AM register is 0x7ffffffff. This value has a decimal value of
15.999969482.Theminimumvalueis0x800000000correspond-
ingto16.WheneverarithmeticinvolvesthebitsAM[34-31]the
EV bit will be set, and the program will know that the bits in
AM[35-31]arethesignedintegerpartofthenumber.Ifsuccessive
operationscausetheoverflowtodisappear,theEVbitwillbereset.
Anothersituationislesstractable.Supposeanoverflowoccursas
a result of an arithmetic operation into the AM that causes bit 34 to
overflowintobit35.Thistypeoferrorisnotreversibleasisthecase
above.Whenthisoverflowoccurs,theMVbitissettonotifythepro-
gramoftheresult.AninternallatchknownasthesignlatchSLwill
containthevalueofA[35]aftertheoverflowhasoccurred.There-
fore,SListhecomplementofthesign-bitwhentheoverflowoccurred.
To communicate with the DSP portion of the MC68HC16, we
havetouseassemblylanguage.InkeepingwiththebasicruletouseC
wheneverpossible,theapproachtobetakenwillbetocreateC-call-
ablefunctionsthataccesstheseimportantcapabilities.Whatfeatures
should we include in these functions? Obviously, all possible func-
tions cannot be conceived.A set of functions that will embody the
mostimportantfeaturesoftheDSPcapabilitieswillbewritten.
Letusexaminehowthiscompilertransfersparameterstoafunc-
tion.Whenmorethanoneparameterispassed,theparametersare
pushed on the stack starting with the right-most parameter in the
functionargumentlist.TheleftmostparameterisputintotheDreg-
ister. If a single parameter is passed, it is placed in the D register
priortothefunctioncall.Withinthefunction,theDandXregisteris
savedonthestack,andthestackpointerisdecrementedbyanamount
neededtoprovidespaceforallofthefunctionvariables.Atthatpoint,
thestackpointeristransferredintotheXregister.Anexampleofthis
codeisshownbelow.Thislittlefunctionreceivesthreeparameters
andmerelyputsthesevaluesintothreelocalvariablelocations.
DigitalSignalProcessorOperations 329
voiddot_product(charlength,int*xdata,int*ydata)
{
inti,*xp,*yp;
xp=xdata;
yp=ydata;
i=length;
}
Listing6-8:SampleParameterHandlingFunction
Thecompiledversionoftheabovefunctionisshownbelow.The
firstimportantinstructionisthe.evenassemblydirectivethatcauses
thecodetofollowtostartonanevenboundary.Codemustbestarted
atanevenaddress.Noteintheprogramabovethatthreeparameters
are passed to the function.After the contents of the X and the D
registersaresaved,thestackpointerisdecrementedby6toprovide
spaceforthevariablesi,*xp,and*yp.Thetwopointerparam-
etersrequire16bitseach,andthecharacterparameterneedsonly8
bits.Theprogram,infavorofgreaterspeed,willstorethevariablei
ina16-bitlocationeventhoughiisonly8bitswide.Atthistime,
thevaluecontainedinthestackpointeristransferredintotheXreg-
ister.Duringthistransfer,thevaluewillbeautomaticallyincremented
bytwosothatthecontentsoftheXregisterwillbepointedtothelast
valuestoredonthestackratherthantothenextemptylocationon
thestackasisfoundinthestackpointer.
1 ;CompilateurCpourMC68HC16(COSMIC-France)
2 .includemacro.h16
3 .list+
4 .psect_text
5 ;1voiddot_product(charlength,int*xdata,int*ydata)
6 ;2{
7 .even
8 _dot_product:
9 pshmx,d
10ais#-6
11tsx
12.setOFST=6
13;3inti,*xp,*yp;
14;4
15;5xp=xdata;
16lddOFST+8,x
17stdOFST-4,x
18;6yp=ydata;
19lddOFST+10,x
330 Chapter6 Large Microcontrollers
20stdOFST-6,x
21;7i=length;
22ldabOFST+3,x
23clra
24stdOFST-2,x
25;8
26;9}
27ldx6,x
28ais#10
29rts
30.public_dot_product
31.even
32.psect_data
33.even
34.psect_bss
35.even
36.end
Listing6-9:CompiledVersionOfParameter-HandlingFunction
ThediagramshowninFigure6-4willhelpyouvisualizewhatis
happeninghere.Ontherightsideofthisdiagramyouwillfindthe
locationatwhichthestackpointerispointedatvarioustimesduring
thefunctioncallanditsexecution.Ontheleftsideofthediagram,
you will see the locations pointed to by the X register.An offset
namedOFSTisestablishedbytheprogram.Thisoffsetwillhavea
valueequaltothespaceemptiedonthestackwiththeaisinstruc-
tion:inotherwords,inthiscaseOFSTwillbe6.Ineverycasefrom
thispointforwardintheprogram,variableandparameteraccesses
willbeindexedrelativetotheXregister,andthetotaloffsetfromthe
XregisterwillbeavalueOFST+kwherekisapositiveornegative
valuethatcorrespondstotheaddressoftheparameterbeingaccessed.
Forexample,theinstruction
lddOFST+8,x
willloadthevalueatx+OFST+8whichyoucanseeinFigure6.4is
thevalue*xdata.Thisvalueisstoredatthelocationx+OFST-4
bytheinstruction
stdOFST-4,x
whichisthelocationwherexpisstoredonthestack.Remember
thateachwordonthestackistwobytes,sothatalloftheoffsetsand
addresswillbeevennumbers.
DigitalSignalProcessorOperations 331
Thecodeinlines16through20abovesavesthevaluesofxdata
andydata inxpandyprespectively.Theoperationsshowninlines
21 through 24 save the 8-bit value found in the B register to the
16-bit location at x+OFST-2. To be certain that the value is not
corruptedbysomegarbagevalueintheAregister,theclrainstruc-
tionisinsertedpriortothetimethatthevalueissaved.
StackContents
SPafterais#-6
Xaftertsx *yp
*xp
length
X+OFST
Xatrts
X
D SPafterfunctioncall
CCR
PC SPbeforefunctioncall
*xdata
*ydata
SPafterpushmx,d
Figure6-4:StackContentsDuringFunctionOperation
Aftertheclosingbraceofthefunctionintheabovelisting,two
importantoperationstakeplace.First,thecontentscontainedinthe
Xregisteronentrytothefunctionarerestoredbytheinstruction
ldx6,x
and the stack pointer content is restored to the value it contained
whenthefunctionwasentered.Atthispointintheprogram,anrts
instructionwillreturntheprogramcontroltotheinstructionfollow-
ing the jsr or bsr instruction used to enter the function code
originally.
Whenthefunctionreturnisexecuted,theregistersD,E,Y,Z,and
CCRareallundefined.A16-bitreturnfromthefunctionwillbereturned
intheDregister,anda32-bitreturnwillbecontainedintheE andtheD
register.TheleastsignificantportionofthereturnisintheDregister.
332 Chapter6 Large Microcontrollers
Whatisadot_product()?Invectoralgebra,adotproduct,
orascalarproduct,operatesonallofthemembersoftwovectors
andreturnsasinglescalarresult.Thisvalueisthemagnitudeofthe
projectionofonevectorontheother.Thefamiliararithmeticform
foradotproductis
n1
c =

a b
k k
0
Notethatallcorrespondingmembersofthetwovectorsaremul-
tipliedandsummed.Theresultisasinglenumber.Anotherimportant
calculationneededtobeaccomplishedbyaDSPiscalledconvolu-
tion.Aconvolutionisthetimedomainoperationofafilter.Mostof
the time, a designer thinks of a filter as operating on the different
frequenciesofthesignalbeingprocessed.Inthefrequencydomain,
ateveryfrequencythefilterhasagainwhichiscomplex.Complex
inthiscasemeansthegainhastwodimensionsthatcanbethoughtof
asmagnitudeandphase.Thesignalalsohasasimilartwo-dimensional
description in frequency.At each frequency, the magnitude of the
filtergainmultipliesthemagnitudeportionofthesignal,andthephase
ofthefiltergainaddstothecorrespondingphaseofthesignal.There
areeasywaystotreatthisoperationinthefrequencydomain.Infact,
thedesignofmostfilterstakesplaceinthefrequencydomain.
However,thefrequencydomainisanartifactthatwecannever
reallygetourhandson.Inreality,thesignalswemustdealwithare
varyingvoltagesorcurrents.Thesevaryingsignalscanbecontinu-
ous,orwhenconvertedtoatractableformforoperationinacomputer,
theyareaseriesofsamples.Letuscallthemx
k
.Herexisthevalue
ofthesignalatsamplepointsk.Nowkmightbethoughtofasre-
latedtotime,andinfactdifferentvaluesofkdocorrespondtosamples
takenatdifferenttimes.Usually,kcorrespondstosamplestakenpe-
riodicallyatcarefullyspaced,equalintervals.
Afilterinthetimedomainhaswhatiscalledaweightingfunc-
tion.TheweightingfunctionisindeedtheFouriertransformofthe
complexfrequencyresponseofthefilter.Inthecontinuousdomain,
thereisamathematicaltrickthatallowstheweightingfunctiontobe
shown.AfunctioncalledaDiracDeltafunctionisdefinedasafunc-
tionthatis0everywhereexceptatonepoint.Theintegralacrossthis
pointisone.Suchafunctionreallydoesnotexist.However,ifsuch
DigitalSignalProcessorOperations 333
afunctionweredeliveredintotheinputofafilter,theoutputofthe
filterwouldbethefilterweightingfunction.
Aswemovetothedigitalrealm,theDiracDeltafunctionisre-
placedbytheKronikerDeltafunction.Thissimplefunction,
k
,is0
forallvaluesofkexceptfork=0whereitsvalueis1.Ifthisfunc-
tionissentthroughadigitalfilter,theoutputobservedistheweighting
functionofthefilter.
Inbothcases,analoganddigital,thefrequencyresponseofthe
filteristheFouriertransformofthefilterweightingfunction.This
dualitybetweenthefrequencyresponseandthetimedomainresponse
makesitpossibletodesignfilterstoaccomplishwhatisreallyde-
sired. Usually, the filter specification is best established in the
frequencydomain.Thedesignerknowswhatfrequenciesaretobe
passedorrejectedbythefilter.Therehasbeenalonghistoryinthe
field of passive network synthesis devoted to the approximation
problem.Howdoesonespecifyafiltertomeetaccuratelyadesired
frequency response? This problem has led to many sophisticated
approaches to the specification by mathematics of a frequency re-
sponse to meet the system need. More important, these frequency
responseshaveanaturethatcanberealizedbyafinitecollectionof
passiveelectricalcomponentsresistors,capacitors,andinductors.
Inotherwords,thesefrequencyresponsesarerealizable.
y
Aseriesofmathematicaltransformationsexistthatcanbeused
totransformfrequencyresponsesdirectlytofilterweightingfunc-
tions.Wewillnotgointothesetransformationshere,butwillrefer
youtoElliottforpracticalmeanstospecifytheweightingfunctions
fordigitalfilters.
7
AmoregeneraltextonthissubjectisbyAntoniou.
8
Thetimedomainresponsecalculationiscalledaconvolution.Ifthereis
asignalx
k
appliedtoafilterwithaweightingfunctionh
k
therewillbean
outputfromthefilterateachtimesample,andthisoutputwillbecalled
k
.Therelationsbetweentheseparametersaregivenbytheequation
n1
h y
k
=

x
ki i
i=0
7
Elliott, Douglas F., Handbook of Digital Signal Processing andApplications:
Academic Press Inc. 1987
8
Antoniou,Andreas, Digital FilterAnalysis and Design: McGraw Hill, 1979
334 Chapter6 Large Microcontrollers
Theconvolutionislittlemorethanaseriesofdotproducts,onedot
productforeachoutputsample.Therefore,ifyouhaveafunctionthat
willcalculateadotproduct,itcanalsocalculateaconvolution.
Anitemofconsequenceistheuseofmodulararithmeticincalcu-
lationofthedataaddresses.Oftentimes,itisdesirabletotraversean
arrayandreturntoitsbeginningautomaticallywhentheendisreached.
Modular arithmetic allows this type of operation.When working in
combinationwithanunusualstepvalue,modulararithmeticwillper-
mit the collection of coefficients from a rectangular array placed in
linearmemoryspace.Herethestepvaluereferstooneofthenumbers
associatedwiththemacorthermacinstruction.Thesetwovaluesare
calledxoandyo.Thisvalueisusedtoincrementtheaddressofthe
correspondingregisterwheneverdataisloadedintoeithertheHorthe
I register.The location of the array in memory should be placed at
speciallocationinmemory.Thislocationisdiscussedbelow.Theef-
fectiveaddressforthenextvaluetobeplacedintheXafterthevalue
isincrementedbythexoregisterisgivenby
IX=(IX)&~XMASK|((IX)+xo)&XMASK
NotethatXMASKhereisan8-bitmaskthatdefinesthelengthof
thecirculararray.Thearraylengthmustbeapoweroftwolessthan
orequalto256.ThevalueplacedinXMASK isonelessthanthearray
length.WhenthecontentsofIX,or(IX),isandedwiththecomple-
mentofthesignextendedvalueofXMASK,thevaluethatisleftisthe
startingaddressofthearray.Thesecondtermabovecausesthecon-
tents in IX to be incremented.As the value in IX is replaced by
((IX)+xo)&XMASKaftereachmultiplyandaccumulateopera-
tion.SinceXMASKmustcontainanumberthatisonelessthana
poweroftworaisedtothen:itsleastsignificantnbitsare1.The
value placed in IX is the address with the n least significant bits
maskedoff.WhenthesetwovaluesareORedtogether,anaddressis
createdthatwillrangefromthebeginningtotheendofthearrayand
thenbacktothebeginninginstepsofxo.Therequirementstomake
thisschemeworkare:
1. Thearraylengthmustbeapoweroftwolessthanorequalto
256.
2. Thearraymustbeginonaspecificaddress.Thisaddressisany
valuewheretheleastnbitsarezero.Herenisdeterminedby
DigitalSignalProcessorOperations 335
n=log2(arraylength)
or
arraylength=2
n
3. Thevalueinxomustbeequaltothestepbetweenadjacent
datasamplesinthearray.
Thisschemecanbeusedtomove,inamodularmanner,around
multiple-dimensionalarraysaswellasone-dimensionalarrays.Let
usnowmodifytheearliercodetoshowhowacircularbuffercanbe
usedtoadvantage.
The above compilations use the default memory model for the
CosmicCcompilerfortheMC68HC16.Thiscomputerhasamemory
addressingspaceof20bits.Inthedesignofthepart,thebasicaddress
registerswereallmade16bitswide,andtheadditionalbitsrequiredto
addressthetotalspacewereplacedinextensionregisters.Therefore,
for each of the addressing registers, the stack pointer, the program
counter,andtheindexregistersX,YandZ,thereisa4-bitextension
register.These registers are called SK, PK, XK, YK, andZK respec-
tively.As mentioned earlier, several of these extension registers are
initializeduponreset,andtheremaindermustbeinitializedpriorto
theexecutionofthemainprogram.Usually,whenacalculationalters
avalueinanextensionregister,thischangetakesplaceseamlessly.It
istypicallynotnecessarytoworryaboutthecontentsoftheextension
registers.Recallinthecodefortheinitializationroutinelistedabove,
crts.s,thatthevaluesforXKandZKweresetto0andthevalue
placedinYKwas0xf.Thereasonforthischoiceisthatthecompiler
automaticallyusestheYregisterasanoffsetwhencalculatingthead-
dresseslistedinthevariousheaderfiles.Sincealloftheseregistersare
inthehighestmemorypage,theYKvalueof0xfisappropriate.
Thedefaultmemorymodeliscalledthecompactmodel,andthe
codeiscompiledinthecompactmodelsothatallcode,data,andstack
memoryspaceiscontainedwithinone65kilobyte(K)memorybank.
Therefore,theinitializedvaluesoftheextensionregistersneednever
change.Ontheotherhand,itissometimesnecessarytochangethe
valuesintheseregisters,anditisdesirabletohavethecompilertake
careofthisbookkeepingwhenneeded.Alloftheadditionalmemory
models will provide this tracking of the extension registers. These
modelsare:small,one65Kbankforcodeandone65Kbankfordata
336 Chapter6 Large Microcontrollers
andstack;program,multiple65Kbanksforcodeandone65Kbank
fordataandstack;data,one65Kbankforcodeandmultiple65K
banksfordataandstack;andfinallyfar,multiple65Kbanksforcode,
data,andstack.Witheachofthesememorymodels,itisnecessaryto
keeptrackandoftenchangethecontentsoftheextensionregisters.As
aresult,withthesemodels,itisnecessarytoalterslightlythestacking
sequence.SuchasequenceisshowninFigure6-5.Thefunctioncall
thatwillcausethestacktobearrangedasisshowninthefigurebelow
has four arguments. From left to right these arguments are xlen,
*xdata,ylen, and *ydata. The lengths are simple character
values,andthepointersinthiscasemustbe20-bitvalues.Ifafunction
calltothisroutineiscompiledwiththesmallmemorymodel,orany
other model with the exception of the compact model, the stacking
willincludetheextensionregistersasshownbelow.
XK
X
D
CCR
PC
*xdatak
*xdata
ylen
*ydatak
*ydata
Xaftertsx
SPafterfunctioncall
StackContents
SPafterXKissaved
SPatrts
SPafterpushmx,d
SPbeforefunctioncall
Figure6-5:StackingSequenceThatPassesExtensionRegisters
TheBregister,whichistherighthandsideoftheDregister,will
containtheleft-mostparameterwhenthefunctioniscalled.There-
fore,theparameterxlenwillbefoundintheleastsignificantbitsof
thelocationlabeledDintheabovestackoutline.Theroutineshown
belowwillmakeuseofboththeXandtheYregisters.Thecompiler
allows for all registers with the exception of the X register to be
DigitalSignalProcessorOperations 337
altered by any function call. Therefore, it is necessary to save the
contentsoftheXregisterpriortoalteringthisregister.
;intcircular_conv(charxlen,int*xdata,charylen,int*ydata)
.even
.setxlen=5
.setxk=11
.setxdata=12
.setylen=15
.setyk=17
.setydata=18
_circular_conv:
pshmx,d
txK ;saveoldxk
pshmd
tsx
clrm;clearthemregister
clra;putylenintoeregister
ldabylen,x ;ylen
addb#-1 ;decrementcounttogetcorrect
tde ;numberofiterations
ldaaxlen,x ;xlenisthecircularpart
asla;oftheconvolution.Create
coma;amaskthatisthecompliment
clrb;oftwicethelength.
tdmsk ;putxleninXMASK
ldabyk,x
tbyk
ldyydata,x ;ydatawithykextension
pshmx ;savex
ldabxk,x
tbxk
ldxxdata,x ;xdatawiththexkextension
ldhi;loadHandIregistersformpy
rmac2,2 ;dormacylentimes
tmer;sendresulttoeandthen
pulmx ;restorex
ldx2,x;restoreittoitsoriginalvalue
338 Chapter6 Large Microcontrollers
pulmd ;restoreoldxk
tbxk
ais#4 ;fixthestack
ted ;datatobereturned
rts ;return
.public_circular_conv
.end
Listing6-10:CircularConvolutionRoutineInAssemblyLanguage
Variable names get lost from the program when executing an
assemblylanguageprogramcalledfromC.Therefore,whenafunc-
tion is entered, the names of the variables are replaced by offsets
fromatablesavedbythecompiler.Programmingfunctionswithout
the aid labels and variable names requires careful attention to the
detailsofstackingandunstackingthesedata.Itisrecommendedthat
when a program is to be prepared, an abbreviated version like the
functiondot_product()abovewhichwillguidetheprogram-
merinsettingupthevariablelocationsinmemorybewritten.In
theaboveroutine,theoffsetOFSTwasnotused,andthevarious
offsetswereassignednamesthatcorrespondtothevariables.This
approachmakesiteasiertounderstandwhattheprogramisdoing
andeasiertowritethecodecorrectly.
ItisimportantthatthecontentsoftheXKregisterberestoredtoits
initialvaluewhenafunctioncallisreturnedtothecallingprogram.
ThecontentoftheX andDregistersissavedonthestackandthevalue
or XK is then saved. The contents of the stack are placed in the X
register,andthisregisterisincrementedbytwosothatitwillpointto
the last data pushed on the stack.The Mregister is cleared, and the
parameterylenismovedintotheEregister.Thisvalueisusedwith
thermacinstructiontotellhowmanytimesthemacinstructionisto
berepeated.Thevalueofxlenisthelengthofthebufferthatcontains
inputdata.Thisbufferisfedcircularlysothatwhenthecalculation
reachesthelastentryinthebufferthepointerintothebufferwillbe
returnedtothetopofthebuffertogetitsnextentry.Thelengthxlen
isthenumberofentriesinthebuffer,butthelengthforthecalculation
must be the number of bytes in the buffer. Therefore, the value of
xlenmustbedoubledpriortothecreationofamasktobeusedin
XMASK.Inthiscase,XMASKvalueiscalculated,andYMASKwhichis
storedastheBregistercontentoftheDregisterismadezero.There-
DigitalSignalProcessorOperations 339
fore,therewillbeacircularbuffercalculationonX,buttherewillbe
nocircularcalculationontheYregister.
AftertheMASKsaresetup,thetwo20-bitpointerregisters,X
and Y, are assigned the values passed as parameters, and then the
product data are put into place. The rmac instruction is then ex-
ecutedthenumberoftimesindicatedbythecontentsoftheEregister.
Theregistercontentsarethenrestoredandtheresultofthesingle-
point convolution is moved into the D register before control is
returnedtothecallingprogram.
Asimpleprogramwaswrittentotesttheoperationofthisfunc-
tion.Thisfunctiondoesnotattempttomakeadigitalfilter,butitrather
setsuptoshowhowthecircularconvolutionworks.Inthiscase,itwas
intendedthattheprogramrunonanEVB16boardthathasanormal
serialinterfacetoanRS232port.Therefore,thedatabeingtestedcan
besentoutoftheserialporttoaterminal.Thepurposeoftheprogram
isreallyquitesimple.Itistoexecuteaconvolutionbetweenashortset
ofcoefficientsandalongsetofdata.Thecoefficientsetis32integers
long, and the data set is 64 integers long. The coefficient data is a
descendingarrayofnumbersthatareintheupperbyteofthenumber.
Thesenumbersstartat31andreducesuccessivelytozero.Thedata
that will be used here are merely the numbers 0 through 63 in the
upperbyteofthenumber.Thesystemissetup,thesystemfrequency
issetto16.78MHz,andthewatchdogisdisabled.Theserialportisset
to9600baudandtheSCItransmitterisenabled.
#includehc16.h
#includesim.h
#includeqsm.h
intputchar(charnew_character);
voiddprint(intc);
voidmain(void)
{
intcircular_conv(char,int*,char,int*);
intdata[64],coef[32],point[64],i,j,*ip;
/*initializetheSIM*/
SYNCR.X=1;/*setthesystemfreqto16.78MHz*/
SYPCR.SWE=0;/*disablethewatchdog*/
/*initializetheSCI*/
340 Chapter6 Large Microcontrollers
SCCR0.SCBR=55;/*setbaudrateto9600*/
SCCR2.TE=1;/*enablethetransmitoftheSCI*/
for(i=0;i<64;i++)
data[i]=i*0x100;
for(i=0;i<32;i++)
coef[i]=(31-i)*0x100;
for(i=0;i<64;i++)
{
ip=data+i;
point[i]=circular_conv(64,ip,32,coef);
}
for(i=0;i<8;i++)
{
for(j=0;j<8;j++)
{
dprint(point[j+8*i]);
putchar();
}
putchar(0xd);
putchar(0xa);
}
}
intputchar(charnew_character)
{
while(SCSR.TDRE==0);/*waituntiltransmitbufferempty*/
SCDR=new_character;/*sendoutbyteandresetTDRE*/
}
voiddprint(intc)
{
if(c<0)
{
putchar(-);
c=-c;
}
if(c/10)
dprint(c/10);
putchar(c%10+0');
}
Listing6-11:ATestProgramforCircularConvolution
DigitalSignalProcessorOperations 341
Next,thecircularconvolutionprogramisexecuted64times.These
resultsarestoredinthearraypoint[].Thisarrayisthensentout
the terminal eight numbers at a time.A few lines of code are ex-
tractedfromFigure6-2tomaketheputchar()function.Finally,
thefunctiondprint()sendsthedataoutoftheserialporttothe
terminal.Theoutputfromthisprogramisasfollows:
6464646464646464
6464646464646464
6464646464646464
6464646464646464
6464646464646464
6464646464646464
6464646464646464
6464646464646464
Thisprogramismerelyatestprogramtoshowthatthecircular
convolutiondoesindeedwork.Thefactthattheoutputdataisalways
the same value, decimal 64, shows that the addresses are handled
correctlyinsideofthecircularconvolution.Letusexaminefirstto
determinewhytheanswershouldbe64.Thecoefficientsanddata
areeach0x100.Twoofthesevaluesaremultipliedandsummed32
or0x20times.Therefore,onewouldexpectthattheresultwouldbe
0x20000. However, you must remember that each of the above
productsisinfacttheproductoftwobinaryfractionalnumbers.The
binary point in each case is between bit numbers 14 and 15. The
productofthesenumberswillyield0x1000,butinthatcase,with
thebinarypointbetweenbits29and30.Actually,thebinarypoint
dictatedbythemicrocontrollerisbetweenbits30and31.Thean-
sweriscorrectedtothisbinarypointlocationintheMregister,and
theresultoftheproductisthen0x20000.Thisnumberissummed
32timesandthefinalresultis0x400000.WhentheMregisteris
movedintotheEregisterandthenintotheDregister,thevaluethat
issavedis0x40,or64,asthetestprogramshowed.
RememberEquation6-1fortheconvolution:
n1
h y
k
=

x
ki i
i=0
342 Chapter6 Large Microcontrollers
Inthisexpression,itseemspossiblethatthexsubscriptcanhavea
negativevalue.Actually,suchacaseisnotpossiblebecauseanega-
tivesubscriptimpliesthatdataisusedbeforeitisavailable.Positive
subscripts correspond to time that has already passed.Values of x
willbezerofornegativesubscripts.Ifthekthsamplecorrespondsto
now,increasingvaluesofiwillgetoldersamplesofx.Thisop-
eration can lead to a little problem in creating the code for the
convolution. The looping construct within the assembly program
above selects the different values of i in the above equation.The
coefficientsh
i
areplacedinmemoryinsuccessiveordersothatan
increase in the value of i will select the correct next coefficient.
However,ifthedatavaluesxwereplacedinmemoryasonewould
naturally expect, the newest value of data would be at the current
arrayindex,andoldvaluesofthedatawouldbeatlesserindexval-
ues.Thisarrangementwillnotworkcorrectly.Thedatamustbeplaced
inthearraybackwardsinordertogettheconvolutiontowork.Older
data must be at higher indices than the current data sample.Also,
whenfillingthearrayinitially,theprogramshouldstartatthetopof
thearrayratherthanthebottom.Theroutinelistedbelowwillstore
thedataproperlyinthearray.
intdata[64];
inthandle_data(charnew_data)
{
staticinti=63;
if(i<0)
i=63;
data[i]=new_data;
returni+1;
}
Listing6-12:ConvenientDataStorageForDSPUse
This routine is integrated into the code shown in Listing 6-11
andusedtotestthecircularconvolution.Thisresultantprogramis
showninListing6-13.Inthiscase,thevariablesdataandcoef
aremovedoutsideofthefunctionmain()tomakethemglobal.
DigitalSignalProcessorOperations 343
#includehc16.h
#includesim.h
#includeqsm.h
intputchar(charnew_character);
voiddprint(intc);
inthandle_data(intnew_data);
intdata[64]@0x2000;
intcoef[32]@0x2100;
voidmain(void)
{
intcircular_conv(char,int*,char,int*);
intpoint[128],i,j,*ip;
/*initializetheSIM*/
SYNCR.X=1; /*setthesystemfreqto16.78MHz*/
SYPCR.SWE=0; /*disablethewatchdog*/
/*initializetheSCI*/
SCCR0.SCBR=55;/*setbaudrateto9600*/
SCCR2.TE=1;/*enablethetransmitoftheSCI*/
for(i=0;i<64;i++)
data[i]=0x00;
for(i=0;i<32;i++)
coef[i]=0x100;
for(i=0;i<64;i++)
{
/*getnewdatause0x100forthistest*/
ip=data+handle_data(0x100);
point[i]=circular_conv(64,ip,32,coef);
}
for(i=0;i<8;i++)
{
for(j=0;j<8;j++)
{
dprint(point[j+8*i]);
putchar();
}
344 Chapter6 Large Microcontrollers
putchar(0xd);
putchar(0xa);
}
}
inthandle_data(intnew_data)
{
staticinti=63;
data[i]=new_data;
i&=63;
return(i==63)?0:i+1;
}
Listing6-13:TestProgramForTheCircularConvolution
Thenthecodetosendthedatatothecircular_conv()is
modifiedslightlytothatshownbelow.
for(i=0;i<64;i++)
{
/*getnewdatause0x100forthistest*/
ip=data+handle_data(0x100);
point[i]=circular_conv(64,ip,32,coef);
}
Thevalue0x100issentintothefunctionhandle_data,and
thereturnistheindexintothearraywherethedatawasstoredinthe
arraydata.Whenthisintegerisaddedtodata,whichisapointertoa
typeint,thepointeripwillpointtothelocationintothearraywhere
thelatestvaluewasstoredinmemory.Undernormalcircumstances,
thispieceofcodewouldbeenteredundercontrolofaclockandthe
datasentintotheroutinehandle_data()wouldbenewinputfrom
ananalogtodigitalconverter.Also,theforstatementisnotexpected
inapracticalapplication.Theoutputfromthisprogramis:
2 4 6 810121416
1820222426283032
3436384042444648
5052545658606264
6464646464646464
6464646464646464
6464646464646464
6464646464646464
OtherMC68HC16Considerations 345
Thedataarraystartsoutempty,andthecoefficientsareeach0x100.
The output is as you would expectit starts and increases linearly
from0to64inthefirst32samples.Theoutputthenremainsat64until
theendofthetest.Thislinearrampisexactlywhatonewouldexpect
whensendingastepfunctionintotheconstantweightingfunction.
Thereisoneimportantpointtobefoundinthisprogram.Itwas
statedearlierthattheprogrammershouldattempttokeepthecodein
Cwheneverpossible.Intheabovecase,weintroducedarathersimple
functioninassemblylanguage.Thefactthattheprogramwasafunc-
tion, and it was necessary to use a large memory model, the code
requiredtohandlethedataasitwaspassedintothefunctionismuch
longerthanyouwouldexpect.Also,theimpliedCcodeinpreparing
themachineforthefunctioncallandthehandlingoftheextension
registersinthemainprogrammakestheoverallprogramlargerthan
expected.Unfortunately,itisnotpossibletoaccesstheDSPwithC,
soifyouwishtodoDSPoperations,assemblylanguageaccessisall
thatyoucanuse.
Other MC68HC16 Considerations
The discussion in this chapter has been dedicated to the
MC68HC16microcontroller.Ofcourse,therearecomponentsofthis
microcontrollerthatarenotcoveredinthischapter.Noattemptwas
madetooutlinetheaccesstotheanalog-to-digitalconverter,several
featuresofthegeneralpurposetimer,theserialperipheralinterface,
or the static RAM. However, the programs shown here do cover
enoughoftheparttodemonstratethattheon-boardperipheralscan
beaccessedfromtheClanguage.Intheapproachused,theheader
filescontainallofthebitfielddefinitionsneededtoaccessanybitor
bitfieldinanycontrolregisterinthepart.
[This is a blank page.]
Chapter 7
AdvancedTopicsinProgramming
EmbeddedSystems(M68HC12)
During the past few years, we have seen an unbelievable
proliferationofembeddedsystemsproducts.Devicesthatcouldonly
be imagined ten years ago are commonplace today and their very
existencedemonstratestheimportanceofCprogrammingforsmall
microcontrollers.Letstakealookatonesuchapplicationandsee
how easily you can develop rather complicated applications on
microcontrollers.
Throughout this text, much emphasis has been placed on the
constructionofsmallfunctionsandthenintegratingthesefunctions
into a working package.This approach is about the only way that
youcanreallyhopetocreateacomplicatedpieceoffirmwareina
sensibletime.Myearlyprojectswouldalwaysstartwithcarefuldesign
ofthewholeproject,partitioningoftheprojectintosensiblemodules,
designofeachmodule,writingthecodeforeachmodule,integration
of the whole project and then, after cleaning up syntax errors, Id
begintotestthewholeprogram.Whatadisaster!Theseprograms
would never work and there would be no hope of ever getting the
packagetorunasaunit.
As I gained experience, I found that the top-down approach I
usedwasprobablysatisfactoryifItemperedtheintegrationofthe
system.Today, I start with a careful design for the whole system.
Thisdesignispartitionedintoconstituentcomponents.Atthatpoint,
anotherlookatthedesignisinordertoseeiftheexistingcomponents
canbefurtherreducedintosensiblecomponents.Atthatpoint,the
lowest-level components are coded. Often these functions are so
simplethattheyworkwhenfirsttested.Wheneverthereisarequired
347
348 Chapter7 Advanced Topics
interfaceforacomponent,Itakethetimewhenitisbeingcreatedto
write stub functions to provide any necessary interface to test the
function.Everysmallfunctionistestedasitiswritten.
Thehierarchyofthesefunctionsisbuiltupward.Thosefunctions
thatmakeuseofthelower-levelfunctionsarecodedandtested,and
soforthuntilthewholeprojectiscompleted.Everyfunctioniswritten
andtestedasitiscreatedsothat,astheprogrambuildsupward,itis
alwaysbasedonknownworkingmodules.Andthisapproachisused
tocompletethewholeprogram.
Ateveryphaseintheconstructionoftheprojectthekeywords
aretest,test,test.Everyfunctionistestedatitscreationand,therefore,
thewholeprojectisbuiltuponrelativelysimple,smallfunctionsthat
have been tested and work. Does this approach guarantee that no
bugswillbebuiltintotheprogram?Doesitguaranteethatthefinal
integratedversionoftheprogramwillworkasdesired?Inbothcases,
the answer is a resounding NO. However, you have at least some
chanceofcreatingaprogramthatcanbedebuggedandwillmeetthe
desiredspecification.Also,youwillfindthatwritingandtestinga
seriesofsmallfunctionsalwaysrequireslesstimethanwritingand
testingtheaggregate,morecomplicatedfunction.
Insummary,makeyourfunctionssmall,testthemuntilthereisno
possibilityofhiddenerrors,revisethemandretestthemalwayswith
theintentofreducingthefunctionsize.Then,whenyouhavecompleted
thefunction,paradeitinfrontofyourpeersandseeiftheycansuggest
waystoimprovethefunctions.Buildyourprojectwithsuchblocks
andyouwillhaveareasonablechanceofmeetingyourdeadlines.
InthischapterontheM68HC12,wewilldiscussprogramming
intothechipapartofthefeaturesofatelephone,orperhapsofan
electronicphonebook.Notethattheproblemdiscussedhereisbuta
smallpartofthecontrolofatelephone.Atelephonebookfunctionis
onecompletemodulethatisapartofthetelephonecontrol.
As it stands, the HC12 has a small amount of EEPROM into
whichaphonebookcanbestored.Thechipalsohasalargeamount
ofFLASHROMinwhichtheprogramisstored.TheFLASHmemory
hassomedisadvantagesthatdiscourageitsusetostorethetelephone
bookdata.Onthesechips,theFLASHmemoryisbrokenintotwo
parts.The smaller portion of the FLASH is called BOOT FLASH
and the larger portion is specified for general program storage. If
youneedtoeraseanymemory,thewholeblock,eithertheBOOTor
AdvancedTopicsinProgrammingEmbeddedSystems(M68HC12) 349
thegeneralprogramstorage,mustbecompletelyerased.Therefore,
if you should want to change the contents of the phone book, the
wholeblockwouldhavetobeerasedandrewritten.Anotherapproach
thatcouldbeusedisjusttoassumethatyouwillhaveenoughFLASH
to write over and discard the memory used and move the entry to
new memory whenever it is changed. This approach, however, is
wastefulofthememory.
TheEEPROMdoesnotsufferthisproblem.Anyindividualbyte
intheEEPROMmemoryblockcanbewritten,read,orerasedwithout
aproblem.Also,theEEPROMcanbeerasedandrewrittenatleast
10,000 times without deterioration. FLASH, on the other hand, is
specified to be able to withstand 100 erase/write cycles during its
lifetime.Allinall,FLASHmakesagoodprogramstoragememory
andEEPROMmakesabetterchangeablenonvolatilememory.
TheCcompilerusedinthischapteristhatprovidedbyCosmic.This
compilerisessentiallythesameasthatseeninChapters5and6except,
ofcourse,itcreatescodefortheM68HC12familyofparts.Onevery
niceextensionofthecompileristheabilitytoidentifyEEPROMinthe
code.Theapproachfollowedhereusesthefollowing#pragma:
#pragmadata[768]@eeprom
It identifies data as an array 768 bytes long that is stored in
EEPROM.Atlinktimeacommandlike
+seg.eepromb0xd00m768
indicatesthattheEEPROMwillbefoundattheaddress0xd00 andit
willbe768byteslong.Thenicefeaturederivedfromthisextensionto
theClanguageisthatanyassignmenttothedataarraywillfirsterase
thebyteandthenstorethedataintothespecifiedlocationautomatically.
ThefactthattheHC12componentthatistobeusedforthisproject
contains a large amount of FLASH and little RAM leads to some
difficultyinwritingcodeforuseonthispart.Therearenodevelopment
environmentsthatcontainsufficientRAMtotestasignificantprogram.
Therefore,priortoexecutingthefirstbyteofcodeonthetargetchip,
you must be more certain than normal that the code will work as
intended.Isolvethisproblembydevelopingmostofthecodeforthe
finalconfigurationtoexecuteinaDOSenvironmentandonlyafterI
haveacompleteworkingprogramisthereanyattempttomoveitinto
thetargetsystem.Codedevelopedinthismannerwasdiscussedinthe
350 Chapter7 Advanced Topics
previous paragraphs. The main difference is that the development
flowwillbeforaDOS-basedsystemandthemicrocontroller-based
codewillbeverycarefullydesignedandtestedandintegratedinto
theprogramasitisdeveloped.Thefinaltestsafterthecodehasbeen
transferredtothetargetsystemwillbelimitedtothoseitemsthatare
specifictothetargetsystemonly.
Letuslooknowatwhatwewouldlikeourphonebookcodeto
do.
The purpose of the program is to allow storage of names and
telephonenumbersintheEEPROMsectionofanM68HC912B32.
This chip has 768 bytes of EEPROM and 32K bytes of FLASH
EEPROM. It has an on-board UART through which all of the
communications with the chip are conducted. One of four single-
lettercommandscanbeenteredintothesystem:
Command Response
n ReceiveaNAMEterminatedbyan<enter>
followedbyaphonenumberalsoterminatedby
an<enter>.
s Displaytheentiredirectorycontents.
a Displaythenextdirectoryentry.
r Deletetheentirecontentsofthedirectory.
Nonvolatilestorageisatapremium.Therefore,alldatastoredin
EEPROMwillbeencodedtocompressthedataasmuchaspractical.
AllnumberswillbestoredinBCDform.Thisapproachrequires4
bitsperstorednumberwhen,infact,3.32bitsperdigitisrequiredif
itisassumedthattheuseofeachnumberisequallylikely.Confusion
canresultwhenanemptynumberisstored,sothevaluestoredfor
thenumber0willbe0xaratherthan0x0.
Alpha,orletter,datawillbecompressedusingaHuffmancode
aswasshowninChapter5.Thiscodewillbewrittenspecificallyto
compressdatafromthenamesfoundinatelephonedirectory.Fre-
quencyofletterusagehereisdifferentfromthatfoundwithgeneral
English text. The decode scheme to be used here will follow the
generalapproachgiveninChapter5.
As a first estimate, the following functions will be required in
puttingthisprogramtogether:
AdvancedTopicsinProgrammingEmbeddedSystems(M68HC12) 351
Monitor Thisfunctionexecutesallofthetimeandreceives
datafromthekeyboard.Itinterpretstheentriesand
passescontroltotheappropriatefunctiontoexecute.
Encode Encodes the alpha data read from the keyboard
withaHuffmancode.
Decode Decodes the Huffman encoded data stored in
FLASHwhenneeded.
Numdup Convertsnumericdatapassedinanarraytothe
modifiedBCDformatandsavesthesedatainthe
FLASHarray,alsoapassedparameter.
Putbcd Converts the encoded numeric data contained in
the passed array toASCII form. Places the con-
verteddatainanarraythatispassedtothefunction.
Getchar Readsinacharacterfromtheserialport.Thisfunc-
tion and putchar() below work with the
standard library input/output functions that will
beusedbytheprogram.
Putchar Sendsacharactertotheserialport.
Get Readsinacharacterstring,eithernumericoral-
phafromtheserialinput.
Printout Prints the contents of the phone book stored in
EEPROM.
Printafter Printsthenextentryinthephonebook.
Saveit Saves the phone book entry in the proper
EEPROMlocation.
Reset ErasesthecontentsoftheEEPROM.
Mostofthesefunctionshavenothingtodowiththeunderlying
computer.Therefore,wewillwritecodethatiscompletelyindepen-
dentofthecomputer.Ifthereiseverapotentialmodificationinthis
codewhenchangingtotheembeddedmicrocontroller,standardcom-
pilercontrolcommandswillbeused.
352 Chapter7 Advanced Topics
Numeric Encoding
Datawillbeenteredfromakeyboardthatisassumedtoprovide
anASCIIcharacterstream.Inoperation,thefirstentrywillbethe
telephone number. As this number is received the coding will be
convertedfromASCIItoamodifiedBCDformat.Themodification
is needed to eliminate trouble with the occurrence of zeros in the
number.TheconventionalBCDencodingforazeroisa0x0thatis4
bits wide. If you should have a double zero, the encoded version
wouldbean8-bitzeroor\0,whichisinterpretedinCasanendof
acharacterstring.Thatconfusestheissueenoughthatitwasdecided
to encode the digit zero as 0xa. The literal interpretation of this
numberisthevalueten.But,withourBCDencoding,thenumber
tenwillneveroccur,soitissafetousethisvalueforthevaluezero.
/*Theasciidataintheconstantarrays[]con
tainsanumber.Thesedataareconvertedtoa
modifiedBCDformandstoredinthearray
array[].Thenumberzeroisstoredas0xa.The
seriesisterminatedwithanullcharacter
followedbyanentercharacter.*/
#include<ctype>
intnumbdup(char * consts,unsigned*array,intlen)
{
char*pq,*sp;
inti;
sp=s; /*uselocalpointer*/
pq=(char *)array;/*convertpointertocharacter*/
for(i=0;i<len;i++)/*emptythearray*/
pq[i]=0;
i=0;
while(*sp!=\0'&&*sp!=\n)/*readuntilterminationchar*/
{
*pq=0;
if(isdigit(*sp))/*converttheinputstwoatatime*/
Numeric Encoding 353
{
if(*sp==0')/*handleazeroinput*/
*sp=0'+0xa;
*pq|=(*sp-0')<<4;
}
else
pq|=0xf0;/*nondigit,markit*/
if(isdigit(*(sp+1)))/*thenextinput*/
{
if(*sp==0') /*treatazero*/
*sp=0'+0xa;
*pq|=(*(sp+1)-0');
}
else
pq|=0xf;/*anothernondigit*/
sp+=2;/*Incrementtheinputdatapointer,*/
pq++; /*theoutputdatapointer,*/
i++; /*andthedatacount*/
}
returni;/*lengthofthearray*/
}
Listing7-1:NumericEncodingRoutine
All of the storage arrays in the EEPROM are of the type un-
signed int. Here the storage of both numeric data and alpha
datarequiresthateverybitofeverystoragelocationbeusedsothat
unsignedisthenorm.Inthecodingroutines,thedataarepassedinas
charactersandthedestinationarraysareunsigned.Therefore,toaid
thelocalbookkeeping,thedestinationarraypointerisimmediately
assignedtoatypechar*andthispointerwillbeusedtostorethe
encodeddata.
The following program provides a simple test for the numeric
coding.Thisprogramhasaseriousproblemthough.Allcomputers
configurememoryineitherabigendianoralittleendianorder.In
the big endian order, the most significant byte, 8 bits, of a 16-bit
address is given the smaller address and the least significant byte
goestothelargeraddress.Thelittleendianorderisjustthereverse.
354 Chapter7 Advanced Topics
Heretheleastsignificantbyteofdataisassignedtothesmallerad-
dressandthemostsignificantbytegoestothelargeraddress.Almost
allMotorolachipsusebigendian,andalmostallIntelchipsuselittle
endian.Therecanbesomeconfusionwhendevelopingcodetorun
on one style of data storage on a machine with the opposite.This
problemisseeninthefollowingprogram.
#include<stdio.h>
main()
{
unsignedarray[25];
inti;
numbdup(123456789098765,array,25);
for(i=0;i<8;i++)
printf(%x,array[i]);
putchar(\n);
}
Listing7-2:NumericEncodeTest
IfthisprogramiscompiledwithaPC(Intel-based)compiler,the
resultwillnotappeartobecorrect.However,iftheprogramiscom-
piledonanHC12,or68HC16,or683XX,or68HC11,or68HC05
compiler,itwillseemtoworkcorrectly.Infact,bothresultsarecor-
rect,onlythenumericrepresentationinmemoryisdifferent.
Numeric Decoding
Oncethenumericdataareencodedandstored,theymustbede-
codedtobeusedbyotherpartsoftheprogram.Thedecoderoutine
iscalledputbcd().Thisfunctionisshownbelow.
voidputbcd(char*s,char*number)
{
intc,i=0;
char*sa;
sa=s;
while(*sa!=\0')
{
NumericDecoding 355
if(isdigit(c=(*sa>>4)+0'))
number[i++]=c;
elseif(c==0'+0xa)
number[i++]=0';
if(isdigit(c=(*sa&0xf)+0'))
number[i++]=c;
elseif(c==0'+0xa)
number[i++]=0';
sa++;
}
number[i++]=\n;
number[i++]=0;
}
Listing7-3:NumericDecodingRoutine
Inthisfunctiontheoutputdataiscallednumber[]andthein-
put is s[].The encoded data in s[] is converted one BCD 4-bit
fieldatatimetoASCIIcharacters.Intheeventthatacharacterre-
ceivedhasavalue0+0xa,itisthenacharacterzeroor0.Each
byteisconvertedfromtwo4-bitBCDvaluestotwoASCIIcharac-
tersthatrepresenttheproperdigits.
Thetestprogramforthisroutineisacombinationoftheencode
testroutinewithonetodecodetheencodeddata.Asonewouldex-
pect,whenboththeencodeandthedecoderoutineareusedtogether,
theresultiscorrect.ThisobservationistrueoneithertheIntelorthe
Motorolastylechip.Theendian-nessofthechipisimmaterialwhen
theentireencode/decodeoperationiscompleted.
#include<stdio.h>
#defineARRAY_SIZE100
intdecode(unsignedM[],char*s);
intencode(char*a,unsigned*array,intlength);
main()
{
chara[ARRAY_SIZE];
intc,i=0;
unsignedarray[ARRAY_SIZE];
chars[ARRAY_SIZE];
356 Chapter7 Advanced Topics
while((c=getchar())!=\n)
a[i++]=c;
a[i]=\n;
encode(a,array,ARRAY_SIZE);
decode(array,s);
printf(%s,s);
}
Listing7-4:NumericDecodeTest
Codingthealphadata
For encoding and decoding the name data to be stored in our
phonebook,wewilluseaHuffmancode.Wesawthedecodingofa
Huffman code in Chapter 5 and the decoding approach used here
willbealmostthesameaswasusedthere.InthediscussioninChap-
ter5therewasnoencodingandthatfeaturemustbeaddedhere.To
dojusticetotheencodingtechnique,itisnecessarytotrytobuildthe
codetoencodethetypeoftextthataphonebookrepresents.Thereis
noreasontosuspectthatacollectionofEnglishnameswillcontain
thesamecharacterfrequencyasstandardEnglishtext.Itisnecessary
tounderstandthefrequencyofoccurrenceofeachletterinthetextto
beencoded.Withthisunderstanding,youcanwriteacodethatas-
signsfewbitstofrequentlyoccurringlettersandmorebitstoletters
thatoccurlessfrequently.
Theprogrambelowreadsindata,countstheoccurrencesoflet-
ters,bothupperandlowercase,inadocument.Theoccurrenceof
letters is sorted in order of decreasing occurrence. These data are
printedout.Theprogramcalculatestheaveragetheoreticalentropy,
bits per character, of each character in the document and displays
thisnumber.Alsoincludedinthecalculationsarethespace, ,char-
acter and the new line, \n, character. These characters cause the
outputtobedistorted,sothecharacter>isusedtoindicateaspace
characteranda<indicatesanewline.Thesedatawillthenbeused
tocreateaHuffmancodeusedtocompressthedatapriortostorage
intheinternalEEPROM.
This particular program, along with many variations, has been
anexerciseusedforyearsinclasses.Itdoesdemonstratesomeim-
portantconsiderations.TheshellsortwasusedinChapters2and5to
sortdata,andherewewilluseitagain.Inthiscase,thedatatobe
CodingtheAlphaData 357
sorted is contained in an array of structures. The structure is
typedefedandcalledatypeEntry.EachinstanceofanEntry
containsanintegervaluecountandacharacternamedletter.The
letteristheactualletterbeingrecordedandcountisthenumber
ofoccurrencesoftheletterinadocument.
Ouralphabetconsistsofthenormal26lettersplusthespaceand
new line characters. Therefore the constant LETTERS is given a
valueof28.
In the main program, the necessary variables are defined. Note
thatthearrayofEntrysnamedletters[]containsLETTERS
entries.Thevariablesusedtocounttheinputdataareinitialized.The
variablecharactersisinitializedtozero.Thecharactermember
ofthearraylettersisinitializedtotheactualcharactervaluesin
orderandthecountvalueisinitializedtozero.Thecharactervalues
inthelasttwoentriesinthearrayareinitializedto>and<respec-
tivelytocorrespondtothespacecharacterandthenewlinecharacter.
When reading the data in, each character is operated on by the
tolower()function.Thisoperationconvertsanyupper-caseletterto
a lower-case letter, but it does not alter any other characters. If the
characterreturnedisaletter,aspaceoranewlinecharacter,itwillbe
processedbythefollowingblock.Otherwise,thecharacterisdiscarded
andanewcharacterisreadinbytheargumentofthewhile()loop.
As the characters to be processed are detected, the corresponding
letters.countisincrementedinthearray.Afterallofthedataare
entered,anEOFisdetected,thedataaresortedandthenprintedout.
Themodificationstotheearliershellsortareminimal.Firstof
all, the array passed to the routine is identified as a type Entry
ratherthananint.Also,thetempvariableisatypeEntry.Then
thecomparisoninthetestargumentoftheinnermostfor()loopis
converted to compare the two v[].count entries. The swap
operationthatfollowsneedsnomodification.
#include<stdio.h>
#include<math.h>
#include<ctype.h>
#defineLETTERS28
typedefstruct{
358 Chapter7 Advanced Topics
intcount;
charletter;
}Entry;
intmain()
{
intc,characters,i;
Entryletters[LETTERS];
doublea,sum;
characters=0;
for(i=0;i<LETTERS;i++)
{
letters[i].count=0;
letters[i].letter=i+a;
}
letters[z-a+1].letter=>;
letters[z-a+2].letter=<;
while((c=getchar())!=EOF)
{
c=tolower(c);
if(isalpha(c)||c==||c==\n)
{
characters++;
if(c>=a&&c<=z)/*counttheletters*/
letters[c-a].count++;
elseif(c==)
letters[z-a+1].count++;/*countthespaces*/
elseif(c==\n)
letters[z-a+2].count++;/*countthe new lines*/
}
}
/*gotallofthedatainandprocesses,printitout*/
shellsort(letters,LETTERS);
printf(\n\n);
printf(Char Frequency Char
CodingtheAlphaData 359
Frequency\n\n);
for(i=0;i<LETTERS/2;i++)
printf(%c %7.4f %c %7.4f\n,
letters[i].letter,
100.*letters[i].count/characters,
letters[i+LETTERS/2].letter,
100.*letters[i+LETTERS/2].count/characters);
printf(Thereare%dcharacters\n,characters);
sum=0.;
for(i=0;i<LETTERS;i++)
{
a=1.*letters[i].count/characters;
a=(a!=0)?a:0.00001;
sum+=-a*log(a);
}
sum/=log(2);
printf(Thetheoreticalaveragebitsperchar-
acteris%f\n,sum);
}
/*shellsort:sortv[0]...v[n-1]intoincreasing
order*/
voidshellsort(Entryv[],intn)
{
intgap,i,j;
Entrytemp;
for(gap=n/2;gap>0;gap/=2)
for(i=gap;i<n;i++)
for(j=i-gap;j>=0&&v[j].count<v[j+gap].count;j-=gap)
{
temp=v[j];
v[j]=v[j+gap];
v[j+gap]=temp;
}
}
Listing7-5:LetterAnalysisProgram
360 Chapter7 Advanced Topics
Thepurposeofthiscodeistocalculatefrequencyofoccurrence
oflettersinadocumentandprovidesomeguidanceastohowwell
thecompressionapproachdevelopedworks.Thisprogramwasrun
withaten-pageinstructionmanualandthenwithatelephonebook
with200entries.Theresultsofthesetwoexecutionsareshownbelow.
Char FrequencyChar Frequency
> 30.5977 l 2.1504
e 9.1109 p 2.0276
t 6.5040 f 1.8257
o 5.2664 u 1.2727
r 5.1523 y 1.2288
i 4.6959 g 1.1762
a 4.6169 b 0.8514
s 4.5730 w 0.5793
n 4.2746 k 0.5617
h 3.0194 v 0.2984
c 2.8263 x 0.2721
d 2.6946 q 0.0351
< 2.2031 j 0.0088
m 2.1768 z 0.0000
Thereare11393characters
Thetheoreticalaveragebitspercharacteris
3.797302
Output7-1:Calculationofentropyforthedocumentmanual.doc
The outputs shown above follow very closely the expected
occurrenceoflettersfoundinthetypicaltechnicaltext.Thebitsper
charactershouldbeabout4.5,butthisvalueisdistortedbecausethe
space character is included in the count, and its very frequent
occurrencesdistorttheoverallaveragesandhencetheentropyper
characterfoundinthedocument.
ShownbelowinOutput2isarepeatofthesamecalculationon
thecontentsofaphonebook.Noteherethatoccurrencesoftheletters
andothercharactersarequitedifferentfromthosefoundabove.Even
thoughthephonebookusedtocreatethetablebelowcontainedonly
about200entries,thesedatawillbeusedtocreateaHuffmancode
to compress the data when storing names into the microcomputer
EEPROM.
CodingtheAlphaData 361
Char Frequency Char Frequency
e 9.2042 d 2.7331
< 7.7572 k 2.3312
> 7.5563 b 2.2106
a 7.5161 y 1.9695
r 7.3151 p 1.8891
n 6.3505 u 1.7685
o 5.6270 g 1.7283
i 5.3859 w 1.2862
l 5.0241 f 1.2460
s 4.5418 j 1.2058
t 4.0595 v 0.8039
c 3.8585 x 0.1206
h 3.2958 z 0.1206
m 3.0547 q 0.0402
Thereare2488characters
Thetheoreticalaveragebitspercharacteris
4.392597
Output7-2:CalculationofEntropyforPhoneBook
Next,aHuffmancodewillbecreatedtoencodethedatafromthe
phone book.A Huffman code is built into a complete binary tree.
Suchatreealwayshastwodescendentsfromeverynodeunlessthe
nodeisaleafnode.Assuch,wheneveraHuffmantreeiscreatedto
encodencharacters,therewillbe2n1nodesinthetree.Figure7.1
showsaninstanceofsuchatree.Thistreeencodesthedatashownin
Output2above.Aswithmosttrees,analysis,orencoding,startsat
therootnodeatthetopofthepage.Wheneveryoutraversetothe
left,acodevalueofzeroisrecorded.Whentraversingtotheright,a
code value of 1 is recorded. For example, the character R will be
encodedas0010,andthecharacterMwillbe111100.Thistableis
constructedandfilledtokeepthemostfrequentlyoccurringletters
atthetopofthetreeandtheleastfrequentlyoccurringlettersatthe
bottom.Therefore,thenumberofbitsforeachcharacterisinversely
proportionaltoitsfrequencyofoccurrence.Thischoicefortheletter
codesrequireslessthanthenumberofbitsonewouldexpectwhen
usingthestandard8bitspercharacter.
362 Chapter7 Advanced Topics
T
E
A R O I N
M S H
G J Y
F W
C
B
D
K
P U V
Z
L
''
'\n'
X Q
Figure7-1:HuffmanTreeforEncodingthePhoneBookData
Wehaveseenabovethattheminimumnumberofbitspercharacter
forthetelephonebookis4.39.Wecannotexpecttoreachthislevel,
butweshouldexpecttobesignificantlyfewerthan8bitspercharacter.
The code corresponding to the tree in Figure 7-1 is shown in the
followingtable:
Character Code
100
\n 101
a 0001
b 0000111
c 000010
d 111110
e 01
f 0000110110
g 000011000
CodingtheAlphaData 363
h 000001
i 1100
j 000011001
k 1111111
l 1110
m 111100
n 1101
o 0011
p 111111001
q 11111101111
r 0010
s 111101
t 000000
u 111111000
v 111111010
w 0000110111
x 11111101110
y 000011010
z 1111110110
Table7-1:HuffmanCodeforCompressingTelephoneBookNames
The encoding routine is shown in Listing 7-6. Contained in the
listingoftheencodingroutineisalook-uptablethatcontainsallofthe
codes.Inthistable,thefirsttwoentriescorrespondtoaspacecharacter
andanewlinecharacter.Thefollowingentriescorrespondtotheletters
inthealphabet.Inotherwords,thethirdentrycorrespondstotheletter
AandtheseventhentrycorrespondstotheletterE.Noticethatthis
tableisdefinedasexternal,butitislabeledstaticsothatthereisno
linkagetothetableoutsideofthefileencode.c.
Inoperation,thisfunctionreceivesthreeparameters.Thefirstis
apointertoanarraythatcontainsthedatatobeencoded.Thisarray
contains a zero terminated string. The second array of unsigned
integers is named array. Its length is the third passed parameter
length.Encodeddataareallloadedintothisarray.Allofthelocal
variables used by encode are straightforward. The variable
bitbaseisanunsignedintwithitsmostsignificantbitsetto
oneandtheremainderofitsbitszero.Whenthefunctionisexecuted,
thearray[]isfirstfilledwithzeros.Thevariableiisinitialized
364 Chapter7 Advanced Topics
to zero and bit is given the value bitbase. Then the code for
each character is retrieved successively. If the character read is a
space,thefirstentryinthetableisused;ifitisanewlinecharacter,
thesecondentryinthetableisused;andifitisanyotherletter,the
letterisconvertedtoanindexintothealphabetandthatparticular
code,offsetbytwo,isusedasthecodestringfortheinputcharacter.
staticchar*code[]={
100,101,0001",0000111",000010",111110",
01",0000110110,000011000",000001",1100",
000011001",1111111,1110",111100",1101",
0011",111111001",11111101111,0010",111101",
000000",111111000",111111010,0000110111",
11111101110",000011010",1111110110
};
#include<ctype.h>
intencode(char*a,unsigned*array,intlength)
{
unsignedi,bit,bitbase=~(~0u>>1);
intc=1;
char*ptr,*pa;
pa=a;
for(i=0;i<length;i++)
array[i]=0; /*initializethearray*/
i=0;
bit=bitbase;
while(c!=\n)
{
c=*pa++;/*assumesfileisnotempty*/
if(isalpha(c=toupper(c))||c==||c==\n)
{
if(c==)
ptr=code[0];
elseif(c==\n)
ptr=code[1];
else
ptr=code[c-A+2];
CodingtheAlphaData 365
while(*ptr!=\0')
{
if(*ptr++==1')
array[i]|=bit;
bit>>=1;
if(bit==0)
{
bit=bitbase;
i++;
}
}
}
}
return++i;/*thelengthofthecodedarray*/
}
Listing7-6:EncodeFunction
Theprogramthenentersawhileloopthatexaminesthecontents
ofthecodereceived.Iftheleftmostentryisacharacter1avalueof
bit is ORed into the location array[i]. In either case,
*ptr==1or*ptr==0,thevalueofbitisreplacedbybit
shifted right by 1. Whenever bit has been shifted until its value
becomeszero,itindicatesthattheunsignedintvaluepointedto
byptrhasbeenfilledandbit isreinitializedtobitbase.Alsoat
thistimei,theindexintoarray[],isincrementedtogetthenext
charactertodecode.
Decodingthealphadata
Theabovefunctionencodesthealphadataenteredinthearray
s[]intoaHuffmancodeofthesamedataandreturnstheencoded
data in the array array[]. Perhaps the easiest way to test the
encoderoutineistoexecuteitinconjunctionwithitscorresponding
decoderoutine.Thedecodeoperationessentiallyrecreatesthetree
shown in Figure 7-1. Rather than a two-dimensional rendition, it
mustbeasingle-dimensionlist.Thelistwillhavebuilt-inmechanisms
for traversing the tree from its root node to the encoded character
basedonthe1and0patternsintheencodeddata.
366 Chapter7 Advanced Topics
RecallinChapter5thedecodeschemeinvolvedintermixingjump
distancesinwiththedecodedcharactersinatable.There,thedecode
operationstartedatthezeroentryinthetable.Thecodebeingdecoded
wasexaminedabitatatime.Ifthecodebitwaszero,thetableindex
wasincrementedbyone.Ifthecodebitwasone,thevalueinthat
tablelocationwouldbeaddedtothetableindex.Wheneverthetable
indexfelltoalocationthatcontainedacharacter,thatcharacterwould
beoutputandtheindexwouldbereturnedtothevaluezero.
Thatapproachisfineforrelativelysmallalphabets,asusedin
Chapter 5. Here, we are using the full alphabet, which makes the
creationofthetableaboveextremelycomplicated.Anotherapproach
wasusedthistime.Westillhaveatablethatcontainsjumpinstructions
intermixedwithcharacterstobeoutput.Thecharacterstobeoutput
areeachORedwiththehexvalue0x80.Theprintablecharacters
hereareallidentifiedwiththeleastsignificant7bitsofthecharacter.
Therefore,atestforacharacteristodetermineifthevaluefoundin
thetablehasavaluewhenANDedwith0x80.
Eachnumericentryinthenodetableisbrokenintotwonibbles.
Theleft4bitscorrespondtothejumpwhenacode0isfoundandthe
right4bitscorrespondtothejumpwhenacode1isfound.Inother
words,thedecodeoperationstartsatthebeginningofthenodetable.
Ifthefirstbitoftheencodeddataisa0,thevaluefoundinthemost
significant4bitsofthedataisaddedtothenodetableindexandthe
decodingiscontinuedfromthatpointinthenodetable.Iftheencoded
dataisa1thecontentsoftheleastsignificant4bitsisaddedtothe
node table index. Whenever the node table index is changed, the
value of that location is tested to see if the most significant bit is
turnedon.Ifso,thatbitisturnedoffandtheresultissavedinoutput
array.Otherwise,theprocessisrepeatedfromthatlocationuntilan
outputcharacterisfound.Atthattime,thenodetableindexisreset
tozeroandtheprocessrepeateduntilanewlinecharacterisdetected.
Thenthenullcharacterisputontheendoftheoutputdataandcontrol
isreturnedtothecallingprogram.
Onelittleproblemwiththisapproach:Thenumberthatcontains
the jump data can never have its most significant bit turned on.
Therefore,themaximumjumpwhentheencodedbitis0isseven.
Thisrestrictiondidnotcauseanydifficultywhenwritingthistree.In
fact,mostofthetimethejumpcausedbya0bitwas1or2.This
CodingtheAlphaData 367
restrictiondidcauseafewlongerjumpscorrespondingto1.Overall,
thetablewasquiteeasytoconstruct.
staticconstcharnode[]={
0x1d,0x21,E|0x80,0x41,0x21,O|0x80,R|0x80,0x21,
A|0x80,0x1e,0x21,H|0x80,T|0x80,0x14,0x21,\n|0x80,
|0x80,0x14,0x21,N|0x80,I|0x80,0x1f,L|0x80,0x12,
C|0x80,0x21,B|0x80,0x14,0x12,G|0x80,J|0x80,0x12,
Y|0x80,0x12,F|0x80,W|0x80,0x14,0x12,M|0x80,
S|0x80,0x12,D|0x80,0x15,0x15,0x12,U|0x80,P|0x80,
K|0x80,0x12,V|0x80,0x12,Z|0x80,0x12,X|0x80,
Q|0x80
};
intdecode(unsignedM[],char*s)
{
unsignedmask,maskdo=~(~0u>>1);
chari=0,k=0,l=0; /*listhenodepointer,
iisthebytepointer,
Misthemessagepointer*/
mask=maskdo;
while(k!=\n)
{
if((mask&M[i])==0)
l+=node[l]>>4;
else
l+=node[l]&0xf;
if(node[l]&0x80)
{ /*ifaprintable,senditout*/
*s++=(k=node[l]&0x7f);
l=0; /*alsogototherootnode*/
}
if((mask>>=1)==0)/*ifthemaskis0,turn
onMSB*/
{
mask=maskdo;
i++;/*andgetthenextbytefrommessage*/
}
}
368 Chapter7 Advanced Topics
*s=0;
returni;
}
Listing7-7:HuffmanDecodingData
Theabovefunctionistestedinconjunctionwiththeencoderoutine
withthefollowingrelativelysimpleprogram.Inthiscode,provision
ismadetoenteralineoftextfromthecomputerkeyboard.Thistext
isterminatedwhenanewlinecharacterisdetected.Thesedataare
thensenttotheencoderoutine.Theencoderoutinereturnstheencoded
datainthearrayarray[].Thisarrayispassedtothedecoderoutine.
Thereturninformationfromdecodeiscontainedinthearrays[].
Thisstringisthenprintedouttothescreen.
#include<stdio.h>
#defineARRAY_SIZE100
intdecode(unsignedM[],char*s);
intencode(char*a,unsigned*array,intlength);
main()
{
chara[ARRAY_SIZE];
intc,i=0;
unsignedarray[ARRAY_SIZE];
chars[ARRAY_SIZE];
while((c=getchar())!=\n)
a[i++]=c;
a[i]=\n;
encode(a,array,ARRAY_SIZE);
decode(array,s);
printf(%s,s);
}
Listing7-8:Encode/DecodeTestRoutine
Theaboveprogramechoestheinputstringtothecomputerscreen.
Alllower-caselettersareconvertedtouppercaseintheprocess.
CodingtheAlphaData 369
Readdatafromthekeyboard
Afunctionget()isusedtoreaddatafromakeyboardintoa
data buffer. This function is used in the monitor.A problem with
many such functions is that they do not provide proper protection
fromabufferoverflowasthedataarereadin.Thestandardlibrary
functionfgets()almostmeetstheneedsofthisfunctionandmore.
The more in this case is the reason that we should not use the
fgets()inthiscase.Thisfunctionispartofthestandardlibrary
and as such, it requires the definition of an input.The most often
usedinputfilehereistheonenamedstdin.Whenweconstruct
thissystem,wedonotwanttoincludeallofthesideeffectsofadding
thestandardlibrarytooursystem.Therefore,inthiscase,itisprobably
besttowritethefunctionget()fromscratch.
The function get() is shown below. This function takes two
parameters.Thefirstisapointertoacharacterstringwheretheinput
dataaretobestoredandthesecondisthelengthofthisarray.Inthe
eventthattheinputdatasizeexceedsthearraysize,thedataarrayis
filledwithzeros.Otherwise,thenewlinecharacterisplacedonthe
endofthestringandthestringisterminatedwithanullcharacter.
voidget(char*a,intn)
{
/*readinfieldandterminatethereadwith an \n */
inti=0,c;
while((c=getchar())!=\n&&i<(n-1))
a[i++]=c;
if(i<n-1)
{
a[i++]=\n;
a[i]=\0';
}
else /*inputdidnotterminatesoonenough*/
for(i=0;i<n;i++)
a[i]=0;
}
Listing7-9:get()InputDataRoutine
370 Chapter7 Advanced Topics
Thisfunctionistestedwiththefollowingprogram:
#include<stdio.h>
voidget(char*,int);
#defineLENGTH15
main()
{
chardata[LENGTH];
get(data,LENGTH);
if(data[0]==\0')
printf(Bufferoverflow\n);
else
puts(data);
}
Listing7-10:get()TestRoutine
Thisprogramreadsinalineofdataandechoesthestringtothe
computer screen. If the length of the input data is longer than the
specifiedlength,theBufferoverflowmessageisprintedtothescreen.
TheMonitorProgram
The next program to be written is the monitor routine. This
functionexecutesallofthetimeandreceivesdatafromthekeyboard.
Itwillinterprettheentriesandpasscontroltotheappropriatefunction
to execute. In building all of the functions, monitor(),
printafter(),printout(),andreset(),therearealarge
numberofconstantsandfunctionprototypesthatmustbeincluded
ineachfunction.Alloftheseitemswillbecollectedtogetherintoa
singleheaderfiletobeincludedineachfunction.Thisheaderfileis
shownbelowasListing7-11.Thisfilestartswiththeusualmultiple
inclusion protection. The code for this program will be tested
completelyonaDOS-basedsystembeforeitiscompiledforusefor
thefinalmicrocontroller.Thereareacoupleofitemsneededforthe
DOS-based system that are not needed for the microcontroller.
Therefore,theparameterDOSisdefinedatthebeginningoftheheader
TheMonitorProgram 371
fileandcertainlinesofthefilewillbeincludedorexcludeddepending
onthedefinitionofthisparameter.
It is intended to store the data in a linked list in memory. The
linkedlistwillhaveanodecalledanEntry.AnEntrycontainstwo
charactersthatwillbeindicesintothedataarray.Thefirstmemberis
theindextothedatainthedataarray.Thesecondmemberisanindex
tothenextEntryforthenextdataentry.Anarrayof35Entryswill
bestoredinEEPROMalongwithanarrayof698(=76835*2)chars
tostorethenonvolatiledata.Thereare768bytesofEEPROMonthe
particularM68HC912B32chipthatweareusinghere.
AstructuretypenamedEproiscreatedtoholdthecollections
of Entrys and the remaining data for the data storage area. This
structurewillbeforcedtotheaddress0xd00atlinktime.Itwill
alsobeidentifiedasEEPROMsothatassignmentstothismemory
areawillcompiletostoragetoEEPROMratherthanwritestonormal
datamemory.Thefirstthreeentriesinthedata[]arrayaredevoted
to special uses. data[0] contains the next open index into the
data[]array,data[1]containsanindextothebeginningofthe
list and data[2] contains the number of entries in the list. To
simplifyboththecodewritingandrememberingoftheusesofthese
memory locations, I used macros to define useful names for these
locations.Alsoincludedhereisanoldfavorite,theFOREVERloop.
#defineDOS
#ifndefPHONE_H
#definePHONE_H
#ifdefDOS
#include<stdio.h>
typedefunsignedintWORD;
enumBool{FALSE,TRUE};
#defineFOREVERwhile(TRUE)
#endif
#include<stdlib.h>
#include<string.h>
typedefstruct{
unsigneddataindex;
372 Chapter7 Advanced Topics
unsignednext;
}Entry;
#defineALEN 30
#defineNLEN 16
#defineDLEN 35
#defineEEPROMLEN 768
#defineDATAPROM EEPROMLEN-DLEN*sizeof(Entry)
#defineEND 0xff
typedefstruct{
Entryheader[DLEN];
unsigneddata[DATAPROM];
}Epro;
#defineNEXT_OPENepro->data[0]
#defineSTART_OF_LISTepro->data[1]
#defineLIST_ENTRIESepro->data[2]
voidsaveit(char*,char*,Epro*);
voidprintout(Epro*);
voidprintafter(Epro*);
voidreset(Epro*);
intencode(char*,unsigned*,int);
intdecode(unsigned*,char*);
voidget(char*,int);
intnumbdup(char*const,unsigned*,int);
voidputbcd(char*,char*);
#ifndefDOS
voidinituart(void);
voidputchar(int);
intgetchar(void);
voidputs(char*);
#endif
#endif
Listing7-11:PhoneBookHeaderFile
TheMonitorProgram 373
Thefinalportionofthisheaderfileisacollectionofallofthe
functionprototypesneededforthisprogram.Whenthisprogramis
moved from the DOS-based system to the microcontroller-based
system,itisnecessarytoremovethefirstlineoftheaboveheader
file. There are three functions found in the standard input/output
librarythatwillberewrittenforthisprogram.Thesefunctionsare
inituart(), putchar(), getchar() and puts(). The
function prototypes for these functions are included and will be
discardedwhentheparameterDOSisnotdefined.
The monitor program is shown below in Listing 7-12. In the
header file above, a structure was typedefed as an Epro.This
structureisthesizeoftheEEPROMonboardthechip.Anexternal
instanceofanEpro,namedable,iscreatedanditwillbeusedas
adestinationforallofthenonvolatilestoreddataintheprogram.
Insidethemain()program,twoarraysarecreated:onearrayto
storethenameenteredfromthekeyboardandtheothertostorethe
phonenumberenteredfromthekeyboard.Also,theexternalstructure
will be passed around from function to function via a pointer.This
pointer is created and initialized to the structureable.Also, if the
parameterDOSisnotdefined,thefunctioninituart()isexecuted
toenabletheuseoftheUARTonthemicrocontrollerwhenitisneeded.
After this initialization is completed, control is passed into a
FOREVER loop where it will remain so long as the computer
continuestorun.Withinthisloop,aninputisreadfromthekeyboard.
Itisassumedthatthekeyboardinputwillreadinthedataandreturn
ASCIIcharacters.IfthesystemisapartofatelephoneoraPDA,the
inputroutinewillhavetoreadinthekeyboarddataandconvertitto
the correctASCII value prior to its use in the following program.
Therefore,getchar()inthefollowingprogramcanbeafunction
that reads data from a serial port or some other program that will
inputthedatafromwhateverkeyboardisusedwiththesystem.Inside
oftheFOREVERloop,acharacterisreadinandthenitistestedin
aswitch()/casesequence.Thecurrenttestvaluesaren,a,
s, and r. These inputs are commands that determine what the
programwilldo:
Command Action
n Readinanumber/namesequence,encodethese
dataandsavetheminthenonvolatilearray.
374 Chapter7 Advanced Topics
r Reset the system and erase the EEPROM array
whichdestroysallstoredinformation.
s Displayallstoreddatainsequence.
a Displaythenextstorednumberandname.
Thefunctionsthatperformthesevariousoperationsarediscussedin
thefollowingsections.Allofthecasechoicesmerelycalltherequired
functionwiththeexceptionofthencommand.Thencommand
callsthefunctionget()twicetoreadinthenumberfollowedby
thename.Thesedataarestoredinthedesignatedarraysandthetwo
arrays containing the data are passed to the function saveit()
alongwithapointertothenonvolatilestructureable.Otherwise,the
program remains in the FOREVER loop, exiting the loop only to
executecommandsenteredfromthekeyboard.
/*monitor.cistheinitialprogramthatisbeing
developedtouseontheHC12.Theendproduct
canbeusedasapartofaPDAoratelephone
thatrequiresthatyouenternamesandphone
numbers.Theseentriesaretobesavedin
nonvolatileRAMsuchasflashorEEPROM,
perhapsboth. Inordertosavememoryspace,
encodingofthestoreddatawillbeused.All
numberswillbestoredasBCDdigitsand
letterswillbestoredasaHuffmancode.It
isassumedthatletterfieldsandnumber
fieldswillnotcontainmixeddata.
Thecodeinthisprogramisprogrammed
fortheDOSbasedsystem.Noprintfisused,
butotheri/ofunctionsareusedasneeded.It
isassumednowthatanyinputwillbe
receivedasserialdatafromaserialport
onthechip.
Thisparticularprogramreadsdatain
fromthekeyboard.Thenumericfieldis
writtenfirstandthealphafieldiswritten
second.Ifitisanumericfield,thedata
areconvertedtoBCDandstoredinan
allocatedmemoryfield.Ifitisalphadata,
itiswrittentoanallocatedmemoryfield.
TheMonitorProgram 375
Anyencodingordecodingisdoneinthestor-
ageroutines.
T.VanSickleAugust1,2000*/
#includephone.h
Eproable;
main()
{
charname[ALEN];
charnumber[NLEN];
Epro*epro;
intc;
#ifndefDOS
inituart(); /*initializetheuartto9600b/s*/
#endif
epro=&able;
reset(&epro);
FOREVER
{
c=getchar();
fflush(stdin);/*neededforthePowerCcompiler*/
switch(c)
{
casen: /*newentry*/
puts(Enternewnumberandname\n);
get(number,NLEN);
get(name,ALEN);
saveit(name,number,&epro);
break;
casea:/*printthenextentry*/
printafter(&epro);
break;
cases:/*showall*/
printout(&epro);
376 Chapter7 Advanced Topics
break;
caser:/*resetthesystem*/
reset(&epro);
break;
}
}
}
Listing7-12:MonitorProgram
TheSAVEIT()Routine
The saveit() function receives the data entered from the
keyboardinmonitor(),encodesthesedataandsavestheresultin
EEPROMforlateruse.Thisprogramissetuptosavethedataina
linkedlist.ThelinkedlistisanarrayDLEN,foundinphone.h,long
and each member of the list is of the type Entry. These data are
storedinthemaindataarrayandaccesstothesedataismadethrough
thevaluesstoredinthecorrespondingEntryforeachsetofdata.
Intheheaderfilephone.h,severalmacrosaredefinedthatmakeit
somewhateasiertocodethisfunction.Thefirstthreeentriesinthedata
arrayareusedforspecialpurposes.Therefore,thesevaluesarerenamed
asmacrostomakethecodemoreunderstandable.Thesemacrosare:
#defineNEXT_OPENepro->data[0]
#defineSTART_OF_LISTepro->data[1]
#defineLIST_ENTRIESepro->data[2]
Usefulnamescannowbeusedratherthanthecrypticactualnames
ofthesevariousmemorylocations.
Onentrytothisfunction,boththenameandnumberparameters
are encoded and the result is saved in the array name[] and
number[]respectively.Thenextblockofcodedeterminesifthere
isenoughroomintheEEPROMarraytostoreallofthedata.Inthe
eventthatthereisnotenoughroom,themessage***buffer
full*** issenttotheoutputandcontrolisreturnedtothemonitor
programwhenreturnisexecuted.
/************************************************
Thisprogramworksinconjunctionwithmoni-
tor().Itreceivestheinputfoundinmonitor
TheSAVEIT()Routine 377
whichthensendstheinformationtothisfunction,
saveit().Thedatathatarrivesisintheformof
twobinarystrings.Thefirststring,thename,is
Huffmanencodedandthesecondstring,thephone
number,isbcdencoded.Thesedataaretobe
storedintheEEPROM.Alinkedlistthatuses
indiciesratherthanpointersisused.TheEEPROM
isbrokenintotwofields.Thefirstfieldisan
arrayofthetypeEntry.ThisarrayisDLENlong.
Thenextfieldisanarraythatcontainsthere-
mainderoftheEEPROM.Thisarrayisanarrayof
typeunsigned.Itwillmostlycontaindatathat
hasbeenencoded.Thefirstthreeentriesinthe
arrayarespecial.Thefirstfieldcontainsthe
indextothenextunusedentryinthearray.The
secondfieldistheindextothestartofthelist
andthefinalfieldcontainsthenumberofentries
inthelist.
************************************************************************/
#includephone.h
voidsaveit(char*s,char*n,Epro*epro)
{
inti,j,sl,nl;
unsignedname[ALEN];
unsignednumber[NLEN];
sl=encode(s,name,ALEN);/*encodeboththe nameand*/
nl=numbdup(n,number,NLEN);/*thenumber*/
/*storeencodeddataontheendofthearray*/
if(NEXT_OPEN+sl+nl>DATAPROM)/*donotoverwrite thearray */
{
puts(***bufferfull***\n);
return;
}
for(i=NEXT_OPEN,j=0;j<sl;i++,j++)
epro->data[i]=name[j];/* save thename thenthenumber*/
378 Chapter7 Advanced Topics
for(j=0;j<nl;i++,j++)/*atNEXT_OPEN */
epro->data[i]=number[j];
epro-
>header[LIST_ENTRIES++].dataindex=NEXT_OPEN;
NEXT_OPEN+=sl+nl;
if(LIST_ENTRIES>=1)/* no entriesinlist never0*/
epro->header[LIST_ENTRIES-1].next=LIST_ENTRIES;
}
Listing7-13:Thesaveit()Function
IfthereisenoughroomintheEEPROMarraytostorethenew
data, the encoded name and the encoded number are both written
into the array at the appropriate location. Recall that the encode
routinesreturnthelengthsoftheencodeddata.NEXT_OPENisthe
nextunusedentryinthearray.Afterthedataarewrittentothearray,
thenewvalueforNEXT_OPENiscalculatedbyaddingthelength
ofthetwoencodedarraystotheoldvalue.
Finally,ifthereismorethanoneentryinthearraytheindexfor
thenewentry,LIST_ENTRIES,willbeputinthenextlocationof
thepreviousentry,epro->header[LIST_ENTRIES-1].next.
Theprintout()andtheprintafter()Functions
Thesetwofunctionsarealmostthesame.Therefore,theywillbe
discussedtogether.Inbothcases,controlisreturnedtothecalling
programiftherearenodatatobeprintedout.Theprintout()
routinestartsatthebeginningofthelistandprintstheentirecontents
of the EEPROM. Prior to the printout, the contents are decoded.
Bothdecoderoutinesreturnanewlinecharacterattheendofthe
datastreamalongwithanullcharactertoindicatetheendoftheline.
Noticeintheprintout()function,thedatastartsatthestartof
thelistandcyclesthroughallofthecontentsofthelist.
#includephone.h
voidprintout(Epro*epro)
Theprintout()andtheprintafter()Functions 379
{
charna[ALEN],nu[NLEN];
inti,j,k,count=0;
if(LIST_ENTRIES==0)
return; /*noentries*/
k=START_OF_LIST;
do
{
i=epro->header[k].dataindex;
j=decode(&epro->data[i],na);
puts(na);
putbcd(&epro->data[i+j+1],nu);
puts(nu);
k=epro->header[k].next;
count++;
}
while(count<LIST_ENTRIES&&count<DLEN);
}
Listing7-14:Theprintout()Function
Listing 7-15 contains the printafter() routine. Here, the
routinecyclesthroughthedata,decodesitandprintsitoutoneEntry
atatime.Inthiscase,theparameterkisstaticanditstartswiththe
value0.ThisisthevalueoftheindextothefirstEntryinthearray.
After each output, k is incremented and so is count. Whenever
count attains the value LIST_ENTRIES, all of the data in the
memory has been printed out.Then count is restored to 0 along
withthevalueofkbeingsetto0.Thisactioncausesthedatainthe
arraytobeprintedoutonefieldatatimeandwhenallofthedataare
sentout,itisrestoredtothebeginningofthearrayandrecycled.
#includephone.h
voidprintafter(Epro*epro)
{
charna[ALEN],nu[NLEN];
intj,i;
statick=0,count=0;
380 Chapter7 Advanced Topics
if(LIST_ENTRIES==0)
return; /*noentriestodecode*/
i=epro->header[k].dataindex;
j=decode(&epro->data[i],na);
puts(na);
putbcd(&epro->data[i+j+1],nu);
puts(nu);
k++;
if(++count==LIST_ENTRIES)
{
count=0;
k=0;
}
}
#ifdefDOS
voidputs(char*s)
{
char*sp;
sp=s;
while(*sp!=\n&&*sp!=\0')
putchar(*sp++);
putchar(\n);
}
#endif
Listing7-15:Theprintafter()Function
WhendevelopingandtestingthisprogramwiththeDOSsystem,
Ifounditnecessarytoincludethenewputs()function.Whenthe
program is moved to operate on the HC12, it will be necessary to
include separate i/o functions to be discussed below. The i/o
functions are not included in the DOS version of the program.
Therefore, the puts() function that is added to the end of the
printafter()functionaboveisincluded.Thislittlefunctionwill
be discarded whenever the parameter DOS is not defined. In that
case,thei/ofunctionsshouldbeincluded.
Reset 381
Reset
Theresetfunctionisdependentonthesystembeingused.When
programming for the DOS-based system, the array that represents
theEEPROMisputintoastatethatsimulateserasedEEPROM.Then
thefirstthreeentriesinthearraydata[]areinitializedtotheproper
values.Recallthatdata[0]willalwayscontaintheindextothe
next open entry in the data[] array. This index is defined by a
macro in the phone.h file to be NEXT_OPEN. The next two
membersdata[0]anddata[1]containtheindextothestarting
index into the header array, START_OF_LIST and the number of
entries in the list LIST_ENTRIES respectively. The first three
membersofthisarrayareusedasdescribedabove.Thefirstavailable
memberforstorageofdataisattheindex3.Therefore,NEXT_OPEN
is assigned a value of 3 and both START_OF_LIST and
LIST_ENTRIESareinitializedto0.Remember,thatthisdataarray
isthesecondmemberofastructureofthetypeEpro.Anexternal
instance of this structure named able is defined in the file
monitor.h,andapointertothisstructure eproisalsodefined
there.
Thereset()functionisthefirstinthisprogramthatrequires
codefortheDOSimplementationthatdiffersfromtheHC12.When
theEEPROMisinitialized,allbitsinthememoryareturnedon:the
memory is filled with 0XFFFF. Therefore when simulating this
memory,theinitializationwillfillthememorysimilarly.Thereisa
library function in the Cosmic library, eepera(), that erases the
memory.Therefore,whencodingfortheHC12,thisfunctionwillbe
used.Thecodeforthereset()functionisshowninListing7-16.
#includephone.h
voidreset(Epro*epro)
{
inti;
#ifdefDOS
memset(epro,0xff,EEPROMLEN);
/*makearrayslooklikeEEPROM*/
#else
eepera();/* erase theEEPROMwithlibraryfunction*/
382 Chapter7 Advanced Topics
#endif
/*Startthelinkedlist*/
NEXT_OPEN=3;/*nextopenentryinthelist*/
START_OF_LIST=0;/*startofthelist*/
LIST_ENTRIES=0;/*numberofentriesinthelist*/
epro->header[0].dataindex=NEXT_OPEN;/*start
thelist*/
for(i=0;i<DLEN;i++)
epro->header[i].next=END;
}
Listing7-16: TheResetFunction
Input/Output Functions
Therearethreeinput/outputfunctionsthatareusuallyfoundin
the standard I/O library that we will replace with microcontroller
specificcodehere.Thesefunctionsareputchar(),getchar(),
and puts(). In the first two instances, rather than sending and
receiving data from devices like stdout and stdin, all output
willgototheserialportontheHC12andinputwillcomelikewise
fromtheserialport.Therefore,theseroutineswillhavetobewritten
from scratch. In addition to the direct input/output functions, an
initializationfunctionthatenablestheserialportwillbeneeded.This
functionmustsetthebitratefortheserialportandenableboththe
UARTtransmitterandreceiver.Thisfunctionisasfollows:
#includehc12.h
#defineBAUD9600 52
#defineBAUDREG*(BYTE*)&SC0BDL
voidinituart(void)
{
BAUDREG=BAUD9600; /*Setthebitrate*/
SC0CR2.TE=ON; /*turnontransmitter*/
SC0CR2.RE=ON; /*andthereceiver*/
}
Input/Output Functions 383
Thechoiceforbitrateforthissystemis38.4kbitspersecond.To
achievethisrate,thebaudratedivisorvalueisgivenby
BR=E
clk
/16BaudRate
TheEclockforthesystemis8MHz.Therefore,thedivisor,BR,is
52whenroundedtothenearestintegervalue.
TheregisterSC0BDLisdefinedintheheaderfilehc12.hasa
typeRegister,oracollectionofeightindividualbits.Inthiscase,
itismoreunderstandabletoputthedataintothisregisterasachar
ratherthanasasetofbits.Thetypeofthislocationcanbechanged
toatypeBYTEeasily,usingthelineofcode
#defineBAUDREG*(BYTE*)&SC0BDL
Readthislineofcodefromrighttoleft.Itsaystocastapointertothe
memorylocationSC0BDLontoapointertoatypeBYTEandthen
dereferenceit.Therefore,wheneverthedefinednameBAUDREGis
used,itaccessestheBYTEcontentsfoundattheaddressSC0BDL.
Thisaddressisdefinedintheheaderfilehc12.h.
ThenexttwolinesofcodeturnthebitsTEandREinSC0CR2
on.WhenthesebitsareON,boththeUARTtransmitterandreceiver
willwork.
The next function is putchar(). This routine sends the
designatedBYTEtotheserialport.Itisnecessarytowaituntilany
datainthetransmitdataregisterhasbeencompletelyprocessedbefore
sendingnewdatatothisregister.Thefirstlineofcodedoesnotallow
thevalueofSC0DRLtobealtereduntilthetransmitdatareadybit,
TDRE, is set. Then the value x is stored in the location SC0DRL,
whichcausesthedatatobesenttotheserialport.
voidputchar(BYTEx)
{
while(!SC0SR1.TDRE)
;/*waituntilregisterisready*/
SC0DRL=x;/*sendthedataout*/
}
ThelastoftheI/Ofunctionsisgetchar().Thegetchar()
functionisalittlelongerthantheputchar()function.Thisdifference
iscausedbythefactthatwhenacharacterisreadinfromtheserial
port it should be immediately echoed back. Therefore, the entered
384 Chapter7 Advanced Topics
data are stored in the memory location a and sent out with the
instructionputchar(a) beforeitisreturnedtothecallingprogram.
BYTEgetchar(void)
{
BYTEa;
while(!SC0SR1.RDRF)
;/*Waitfordataready*/
a=SC0DRL;
putchar(a); /*echothedataand*/
returna; /*thenreturnit*/
}
Finally,theputs()functionfromthestandardlibrarydoesnot
terminatetransmissionwhenitdetectsanewlinecharacter.Forproper
operationinthisprogram,itshould,sothefollowingfunctionwas
written.Noticethatthisfunctionterminateswhenevereitheranew
linecharacterorazerocharacterisdetectedintheinputstring.Like
thestandardlibraryputs()itoutputsanewlinecharacterregardless
oftheterminationofthedata.
voidputs(char*s)
{
char*sp;
sp=s;
while(*sp!=\n&&*sp!=\0')
putchar(*sp++);
putchar(\n);
}
Aninterestingobservation:IfyoulookinChapters4,5,6,and8
you will find similar routines for other chips. In every case, the
functions,eventhoughtheyareforabroadrangeofdifferentchips,
arethesameatestimonialtotheuseofahigh-levellanguagelike
Ctoprogramourmicrocontrollers.Alistingofthesethreefunctions
iscollectedtogetherinListing7-17shownbelow.
#includeHC12.H
#defineBAUD9600 52
Input/Output Functions 385
#defineBAUDREG*(BYTE*)&SC0BDL
voidinituart(void)
{
BAUDREG=BAUD9600;/*Setthebitrate*/
SC0CR2.TE=ON; /*turnontransmitter*/
SC0CR2.RE=ON; /*andthereceiver*/
}
voidputchar(BYTEx)
{
while(!SC0SR1.TDRE)
;/*waituntilregisterisready*/
SC0DRL=x; /*sendthedataout*/
}
BYTEgetchar(void)
{
BYTEa;
while(!SC0SR1.RDRF)
;/*Waitfordataready*/
a=SC0DRL;
putchar(a); /*echothedataand*/
returna; /*thenreturnit*/
}
voidputs(char*s)
{
char*sp;
sp=s;
while(*sp!=\n&&*sp!=\0')
putchar(*sp++);
putchar(\n);
}
Listing7-17:TheInput/OutputRoutinesUsedwiththe
M68HC912B32Chip
386 Chapter7 Advanced Topics
YouwillnoticethatthefileshowninListing7-17istheonlyfile
inwhichtheheaderfilehc12.hisincluded.Noneoftheothercode
dependsinanywayonthebitfieldstructuresthatcontrolallofthe
peripheralsonthechip.Thereareafewplacesthroughoutthecode
wheretherearesomespecificdifferencesbetweenthetwoprograms.
Thefirstlineofcodeintheheaderphone.his
#defineDOS
Thislineisleftintactwhenevertheprogramiscompiledtorununder
DOS.WhentheprogramiscompiledtorunontheHC12,thislineis
removed.Thensequenceslikethefollowingfoundinmonitor.c
#ifndefDOS
inituart();/*initializetheuartto9600b/s*/
#endif
will cause the execution of inituart() to be ignored when
compiled for DOS but it will be included when the program is
compiled for the HC12. Such inclusions will be found throughout
thevariousfunctionsthatarelinkedtoformtheprogram.
PuttingItAllTogether
Theaboveprogramswereallcompiled,linkedandtestedwith
theDOS-basedcompilerprovidedbyMIXSoftware
1
.Thisreliable
compiler created satisfactory test code to run on any PC-style
computer.Wheneverythingwasworkingasdesired,thecodewas
movedtotheHC12system.Thecompilerusedinthiscasewasthe
COSMIC compiler
2
. This compiler was provided by the same
companythatprovidedthecompilersusedinChapters5and6.Cosmic
providestwosoftwarepackagesthatareveryuseful.Thefirstiscalled
IDEA12. This package is a so-called Integrated Development
Environment,IDE.WithintheIDE,youcanspecifythingslikethe
defaultdirectory,andprovidealistoffilesforamakeutility.The
make utility will compile all source files that are newer than the
correspondingobjectfiles.Therefore,asyoudebugvariousfilesin
1
MixSoftware,1132CommerceDrive,Richardson,TX75081,(972)783-6001.
2
CosmicSoftware,400W.CummingsPark,Ste.6000,Woburn,MA01801-6512,(781)932-2556x15.
PuttingItAllTogether 387
your program, you can automatically compile only those files
modifiedsincetheywerelastcompiled.
There are a couple of additional files needed to complete the
programforthephonebook.Thefirstistheinterruptvectortable.
Thevectortableisstoredinnonvolatilememoryonthissystem,and
assuch,itisbesttowriteaCprogramthatcreatesthistable.This
littleprogramiscompiledandlinkedjustlikeanyothermodulein
the program. It will be linked as a constant section at the address
0xFFCE.TheinterruptvectortableprogramisshowninListing7-
18.Thereisonlyoneexternalmoduletobelinkedtothisparticular
table.Itis_stext().Thefunctionprototypeforthisfunctionis
includedatthebeginningoftheprogram,anditsnameisplacedin
the proper vector location. Recall from our earlier discussion of
complicateddeclarationsthatthelineofcode
void(*const_vectab[])()
tellsusthat_vectabisanarrayofconstantpointerstofunctions
thatreturnthetypevoid.Theaddressesofthevariousentriesinthe
arrayofpointerstofunctionsbeginatthememorylocation0xFFCE.
Theremainderofthevectorsthatfolloweachhaveaspecificuse,
andiftherewereaninterruptserviceroutineneededfortheprogram,
itsaddresswouldbeplacedinthecorrespondinglocation.
/*INTERRUPTVECTORSTABLE68HC912B32
* Copyright(c)1997byCOSMICSoftware
*/
void_stext(); /*startuproutine*/
void(*const_vectab[])()={ /*0xFFCE*/
0, /*Reserved */
0, /*BDLC */
0, /*ATD */
0, /*SCI1 */
0, /*SCI0 */
0, /*SPI */
0, /*Pulseaccinput*/
0, /*Pulseaccoverf*/
0, /*Timeroverf */
0, /*Timerchannel7*/
388 Chapter7 Advanced Topics
0, /*Timerchannel6*/
0, /*Timerchannel5*/
0, /*Timerchannel4*/
0, /*Timerchannel3*/
0, /*Timerchannel2*/
0, /*Timerchannel1*/
0, /*Timerchannel0*/
0, /*Realtime */
0, /*IRQ */
0, /*XIRQ */
0, /*SWI */
0, /*illegal */
0, /*copfail */
0, /*copclockfail */
_stext /*RESET */
};
Listing7-18:M68HC912B32VectorTable
Listing7-19showsthenextfunctionthatmustbeincludedfor
operationontheM68HC12.Thisstart-upprogramisnamedcrts.s.
The.sextensionindicatesthatthefunctionisanassemblylanguage
function.Thisisthesumtotalofallassemblycodeneededforthe
program discussed in this chapter. Rather than give a line-by-line
description of the code, we will see that the initial portion of the
programinitializesthesectionnamedbsstoallzeros.Thissection
iswhereallstaticandexternalmemoryarestored.Thenthestack
pointerisinitializedtothevaluedesignatedas__stackandthen
controlispassedtothefunctionmain().Ifmain()shouldreturn,
which it should not, the instruction following main() forms an
infiniteloopthatbranchestoitselfanddoesnothing.
; CSTARTUPFORMC68HC12
; Copyright(c)1996byCOSMICSoftware
;
xdef _exit,__stext
xref _main,__sbss,__memory,__stack
;
__stext:
PuttingItAllTogether 389
clra ;resetthebss
clrb
ldx #__sbss ;startofbss
bra loop ;startloop
zbcl:
std 2,x+ ;clearword
loop:
cpx #__memory;uptotheend
blo zbcl ;andloop
lds #__stack ;initializestackpointer
jsr _main ;executemain
_exit:
bra _exit ;stayhere
;
end
Listing7-19:Crts.sCProgramStart-UpFunction
Anylinkerforanembeddedsystemrequiressometypeoflinker
commandfile.Thecommandfileforthisapplicationisasfollows.
# linkcommandfilefortestprogram
# Copyright(c)1996byCOSMICSoftware
#
+seg.text-b0x8000-n.text#programstartaddress
+seg.const-a.text#constantsfollowprogram
+seg.data-b0x800 #datastartaddress
+seg.eeprom-b0xd00-m768#identifyEEPROMblock
+def__sbss=@.bss #startaddressofbss
crts.o #startuproutine
monitor.o #applicationsprograms
saveit.o
encode.o
decode.o
reset.o
numbdup.o
putbcd.o
priout.o
priafter.o
serial.o
390 Chapter7 Advanced Topics
get.o
C:\COSMIC\CX12\lib\libi.h12
C:\COSMIC\CX12\lib\libm.h12
+seg.const-b0xffce#vectorsstartaddress
vector.o #interruptvectors
+def__memory=@.bss #symbolusedbylibrary
+def__stack=0xc00 #stackpointerinitialvalue
Listing7-20:LinkerCommandFile
This file can be broken into three sections. The first section
specifies all of the important memory locations needed for the
program.Thefirstinstructionidentifiesthetextsectionasbeginning
at the hex address 0x8000. That is the beginning of the FLASH
EEPROMonthischip.Thedesignationtextidentifiestheexecuting
portionoftheprogram.Thenextlinesaysthatallprogramconstants
shall be placed in the text section. Since the text section is
placedininternalnonvolatileFLASH,nothinginthissectioncanbe
changedbytheprogram.
TheinternalRAMonthispartisthe1024bytesbeginningatthe
hexaddress0x800.TheendingaddressofRAMis0xBFF.Thenext
instructionplacesdata,variablesandstackatthestartingaddress0x800.
Jumptotheendofthiscommandfile.Notethattheparameter__stack
isgivenavalueof0xC00.ThisvalueisusedbecausetheM68HC12
stackpointerpointsatthetopofthestackratherthanthenextopen
locationonthestackaswasseenwiththeM68HC11familyofparts.
ThefinalsegmentdesignationisthatoftheEEPROMlocation.This
segmenthasabeginningaddressof0xD00anditcontains768bytes.
Thenextsectionofthefilecontainsthefilestobelinked.There
aretwelveapplicationsfilestobelinked.Withtheexceptionofthe
crts.ofile,thesefilesarethosecreatedandtestedearlierinthis
chapter.Aftertheapplicationprogramfiles,twostandardcompiler
librariesareincluded.Theselibrariescontainallfunctionsneededto
completetheprogram.
Thelastsectionlinksthevectortablediscussedabovetothecorrect
address in the program, establishes the value for the initial stack
pointer,andrememberstheaddressoftheendofthebss sectionfor
useintheprogram.
Theprogramwascompiled,linkedandansrecord ofthecode
created.ThiscodewasloadedintoanM68EVB912B32evaluation
Summary 391
board.Loadingthecodeintothisboardrequirestheuseofanother
developmentboard,anHC12FLASHPROGRAMMER.Thisboard
containsanM68EVB912B32boardalso.Thecodeisdownloaded
into the programmer board and from there it is transferred to the
FLASHmemoryonthesecondevaluationboard.Thiscombination
workedtoprogramtheFLASH,anditmustbenotedthatthefinal
programworkedasdesignedafteroneerrorwascorrected.
Summary
In writing this chapter, I have attempted to show that modular
developmentofaprogramcanyieldverysatisfyingresults.Theprogram
herewasreducedtoseveralrelativelysmallfunctionsthatcouldeach
bedevelopedandtestedseparately.Thenthesefunctionswereintegrated
one-by-one to build the whole program.This is not to say that this
approachislesswork.Severalofthemoduleslistedabovearevery
complicatedandrequirecarefuldesigntomakecertainthattheywork
as desired. Some of these modules require almost invention. For
example,themeansusedtoexpresstheHuffmantableinthedecode
routine needed several different starts before a satisfactory one was
found.RecallthatthecompletebinarytreeneededtoexpressaHuffman
coderequires2n1nodeswherenisthenumberofitemsbeingencoded.
Ifeltthatitwasdesirabletoexpressthistreebyanarraywithnomore
than2n1members.ThearrayshowninListing7-7containsexactly
2n1 bytes. It took six different tries to arrive at this particular
representation,andhencethecodetodecodethedata.
The reward was that the final code worked in the embedded
productwithalmostnoerror.
[This is a blank page.]
Chapter 8
MCORE,aRISCMachine
ReducedInstructionSetComputer(RISC)machinesarethenew
architecturerage.First,theRinRISCisanabsolutemisnomer.When
firstlearningtheM68000machine,aCISC(ComplicatedInstruction
SetComputer),Ifoundacontrollerwithabout70instructions.The
MMC2001, a RISC, has about 110 instructions, and it has no
instructionsforthecomplexaddressingmodesthatmaketheCISC
machinesoeasytoprogram.TheRISChasitsadvantagesthough.
Most of the RISC instructions require only one clock cycle per
instructionwhiletheCISCtypicallyrequiressixclocksperinstruction
with a range of two clocks to twenty-four clocks per instruction.
Therefore,aRISCchipwitha33-MHzclockwillexecutemorethan
thirty-onemillioninstructionspersecond,obviouslymuchfasterthan
asimilarspeedCISC,whichwouldprobablyexecutelessthansix
million instructions per second. However, the RISC machine will
requiremoreinstructionstoexecutethesameprogram.Overall,the
RISCmachineisalmostalwaysfasterthanthecorrespondingCISC,
eventhoughtheRISCrequiresmorememorytoimplementthesame
code.
TheRISC/CISCdichotomywillbethesourceofnearlyreligious
debateuntilthenextbigarchitecturechangeisintroduced.Thistext
isnotaimedatcomparisonofdifferentarchitectures.Thegoalisto
helpyouwritecodeforthechipsintheClanguage.Nowtheproblem
becomesoneoffindinganappropriatecompilerforthechip.
Thecompiler/debuggercombinationusedinpreparingthecode
foundinthischapterisprovidedbyDIABandSDS.
12
Thesesoftware
1
Diab Data, Inc., (650) 571-1700, fax (650) 571-9068, email info@ddi.com, www.ddi.com
2
Software Development Systems, Inc., (630) 368-0400, fax (630) 990-4641,
email sales@sdsi.com, www.sdsi.com
393
394 Chapter8 MCORE, A RISC Machine
systemsareavailableasdemonstrationsystemsfromtherespective
manufacturers. Contact them directly for information on
demonstrationsystems.
AphotoofthedevelopmentsystemisshowninFigure8.1.The
host computer in this case is a laptop computer. The Extended
BackgroundDebugInterface,EBDI,isconnectedtothecomputer
serial port. A flexible cable connects the EBDI to the AXIOM
demonstrationboardthatcontainstheMCOREchip,theMMC2001.
AdditionalperipheraldevicessuchasakeypadoranLCDdisplay
panelcanbeconnecteddirectlytotheAXIOMboard.Therearetwo
serialportsontheAxiomboard.Theseserialportscanbeusedby
anyprogramthatneedsserialaccess.
Figure8-1:DevelopmentSystem
DelayRoutine
395
Delay Routine
Inthecourseofthischapter,wearegoingtoseeseveralsmall
routinesandprogramsthatcanbeusedtoaccomplishsomeuseful
tasks.Oneroutinethatisoftenusefulisadelayroutine.Thereare
severalwaystoimplementadelay.Amostimportantfeatureofany
delayroutineisthatitmustbeaccurateanditmustnotdependon
countinganumberofinstructioncyclestomeasurethedelay.Almost
allmicrocontrollershavetimersubsystemsthatcanbeusedtocontrol
thesedelays.
Adelayprogramhastocauseanexecutingprogramtosuspend
executionforaspecifiedtime.Whatistheprogramtododuringthis
time?The simplest approach is to have the delay program merely
executealoopuntilthetimehaspast,andthisisthefirstapproach
that we will use. If your program consumes essentially all of the
computerresources,suchanapproachisverywasteful.Thecomputer
willmerelyexecuteatightloopduringtheentiredelayandexitthe
loop when the delay is completed. The computer is unable to do
anythingelseduringthedelay.
Thereisasecondapproachthatreturnscontrolofthecomputer
tothecallingprogramandallowsotheroperationstoexecuteduring
thedelaytime.Thisapproachusesasemaphoretocontrolexecution
ofthecallingprogram.Wewillseethisapproachshortly.
Listing 8.1 is the code for the function void delay(int
time).Thisfunctionmakesuseoftheprogrammableintervaltimer,
PIT, portion of the on-board timer found on the MMC2001. The
timer is driven by a 32768-Hz crystal oscillator. The frequency
generatedbythisoscillatorisdividedbyfour.Therefore,thetime
periodofclocksenteringthePITis1/8192seconds,or122.070312
microseconds.ThisistheresolutionofthePITonthischip.There
aretworegisters,thePITdataregister,ITDR,andthePITalternate
dataregister,ITADR.ThedatawrittentotheITDRisretainedandis
transferredtotheITADRthenexttimethattheITADRunderflows,
indicatingcompletionofthespecifiedtimesequence.Atthattime,
the contents of the ITDR are written to the ITADR, and the PIT
interruptflagITIFisset.Iftheinterruptsequenceisenabled,acore
processorinterruptisrequested.Otherwise,thesystemcanbepolled
todeterminewhenthetimehasexpired.Thisapproachisusedinthe
followingprogram.
396 Chapter8 MCORE, A RISC Machine
#includemmc2001.h
#includetimer.h
/***************************************************
Delaybytmilliseconds.Thedataherearepassed
asanintbecause,thisroutingtiesupthe
computerthewholedelaytime.Analternatemeans
shouldbeusedifalongdelayisneeded.This
routineusesthePITwhichcountsatabout122us
perticks.Itisnotveryaccuratebecause,the
countisat1/8192seconds,morenearly122.070312
usticks.Notgoodenoughtomakeaclock,but
goodenoughtocontrolafewmilliseconds.
Thismodificationassumesthatthepitisenabled
andshallremainenabled. TVS6/2000
****************************************************/
voiddelay(WORDt)
{
UWORDnow,next;
UWORDcount;
count=(long)t*1000;/*makethedelayinus*/
count/=122; /*122uspertick*/
ITCSR.EN=ON; /*enablethepit*/
while(count>0)/*thereareprobablyfasterwaystodo*/
{ /*this,butwhocares,you are killingtime*/
now = ITADR;/*anddontcareforspeed*/
do
{
next=ITADR;
}while(now==next);/*waituntilnexttick*/
count;
}
ITCSR.EN=OFF; /*delayisdonedontneedthepitnow*/
}
Listing8-1:Delayroutine
Thefunctionparametertimeisthedelaytimeinmilliseconds.
The clocking rate for the counter is each 122.0 microseconds.
Thereforethetimeisconvertedtocountswhenitisdividedby122.
ThePITisthenenabledwiththeinstruction
ITCSR.EN=ON; /*enablethepit*/
DelayRoutine
397
ThisratherclumsyloopreadsthevaluecontainedinITADRintothe
variablenow.Thisregisteristhenreadintothelocationnextuntil
thevalueinITADRischangedbytheclock.Thatshouldoccur122
microsecondslater.Atthistime,countisdecremented.Whencount
becomes0thetimehasexpired.
Thevariablesnowandnextarebothdeclaredtobevolatile.This
declarationisnecessarytoavoidlossofthewholeloopwhenthecodeis
optimized.ThevariableITADRisdeclaredtobevolatileintheheader
file.Thatdeclarationdoesnotguaranteetothecompilerthatthevariables
willeverchange,sotheoptimizercouldwellremovethecode
now=ITADR;/*anddontcarehowfastyourtestis*/
do
{
next=ITADR;
}while(now==next);/*waituntilnexttick*/
duringtheoptimizationphase.Thatwouldmakethewholefunction
ratherpointless.
Semaphore
Thisdelayfunctionisusedinlatercodetoimplementdebounce
routines.A more practical delay routine can be implemented with
theuseofasemaphore.Here,wearegoingtodevelopasemaphore
thatfollowsthatdevelopedinReusableSoftwareComponents.
3
We
willnotcreateasemaphoreobjectasdoneinthattext,buttheprogram
willfollowtheitemsshownthere.
Asemaphoreismerelyaflagthatisattachedtoaprocesslikea
programorafunction.Thesemaphoreissetandthecallingprogramis
notabletoproceeduntilthecalledprogramresetsthesemaphore.This
resetisusuallydoneinaninterruptserviceroutineimplementedinthe
calledprogram.Letslookattheelementsofasemaphorefirst.
Whenasemaphoreisset,itusuallymarksaresourceasbusy.Itis
interesting,butyouwillfindthatmanysemaphoresareusedaround
interruptserviceroutinesandwhileinterruptsarebeingused.Oftena
strange race condition can occur that will cause a semaphore to be
improperlyset.SupposethatIwanttosetaflag,semaphore,toindicate
thataresourceisbusy.Theprocessofsettingthesemaphoreistofirst
ReusableSoftwareComponents,TedVanSickle,PrenticeHall,UpperSaddleRiver,NJ,1997
3
398 Chapter8 MCORE, A RISC Machine
read the contents of the semaphore and then, if it is in the proper
condition,itwillbeset.Interruptscancomeasynchronouslyatany
time.Supposethatintheprocessofattachingasemaphore,thestatus
oftheinterruptisreadtobetested,and,priortomarkingthesemaphore
asused,aninterruptoccurs.Withinthisinterruptroutine,italsocould
requireaninterrupt.Inthiscase,theinterruptthatwasbeingprocessed
bytheearlierroutinewillseemtobeavailable,butitisnot.Infact
when control is returned to the initial portion of the program, the
semaphore will be again marked as busy, and now two completely
differentprocesseswillbothassumecontroloverthesamesemaphore.
/*Acalltoattach_semaphore(a)willattempttoattach
safelyasemaphore.Ifasemaphorecanbeattached,a
semaphorenumberwillbereturned.Otherwise,a-1is
returnedandnosemaphorecannowbeattached.When
attach_semaphore(n),where0<=n<10,isexecuted,an
attemptismadetoattachthesemaphorespecifiedbythe
number.Ifitisnotavailable,a1isreturned.After
thesemaphoreisattached,usethesemaphorenumberasa
parameteronallothersemaphorefunctioncalls.Function
release_semaphore()returnsthesemaphoretotheavail-
ablesemaphorepool.Thefunctionsemaphore_status()
returnsTRUEwhenthesemaphoreisNOTavailable,andthe
functionwait_for_semaphore()waitsinatightloopuntil
thesemaphorebecomesavailable*/
#includemmc2001.h
#defineNumber_of_semaphores10
#defineMinus_one-1
/*functionprototypes*/
intattach_semaphore(void);
voidrelease_semaphore(int);
intsemaphore_status(int);
voidwait_for_semaphore(int);
staticvolatileintsemaphore[Number_of_semaphores];
intsave;
intattach_semaphore(intr)
{
inti;
DelayRoutine
399
/*saveinterruptstatus*/
asm(mfcrR1,PSR\nlrwR2,save\nstwR1,(R2,0)\n);
/*disableallinterrupts*/
Disable_Interrupts();
Disable_Fast_Interrupts();
/*requestspecificsemaphore*/
if(0<=r&&r<Number_of_semaphores&&semaphore_status[r]&&r!=a)
returnMinus_one; /*itisnotavailable*/
else
{
semaphore[r]=TRUE;
/*reenableinterrupts*/
asm(lrwr2,save\nldwR1,(r2,0)\nmtcrR1,PSR\n);
returnr; /*returnsemaphorenumber*/
}
for(i=0;(i<Number_of_semaphores)&&(semaphore[i]!=0);i++)
;/*findanunusedsemaphore*/
if(i>=Number_of_semaphores)
{
/*reenableinterrupts*/
asm(lrwr2,save\nldwR1,(r2,0)\nmtcrR1,PSR\n);
returnMinus_one; /*nosemaphoreavailable*/
}
else
{
semaphore[i]=TRUE; /*marksemaphoreasused*/
/*reenableinterrupts*/
asm(lrwr2,save\nldwR1,(r2,0)\nmtcrR1,PSR\n);
returni; /*returnsemaphorenumber*/
}
}
voidrelease_semaphore(inti)
{
semaphore[i]=FALSE;
}
intsemaphore_status(inti)
{
returnsemaphore[i];
}
voidwait_for_semaphore(inti)
{
400 Chapter8 MCORE, A RISC Machine
while(semaphore[i]==TRUE)
;
}
Listing8-2:Semaphorefunctions
Thisproblemisavoidedbydisablingallinterruptspriortoreading
the semaphore state during the attachment process. Interrupts are
disabledandenabledbysettingandclearingbitsinthePSRregister
onthecoreprocessor.Ifyouexaminethemmc2001.hheaderfile,
there are four macros, Enable_Interrupts(),
Enable_Fast_Interrupts(), Disable_Interrupts()
andDisable_Fast_Interrupts()defined.Thesemacros
areallwritteninassemblylanguagebecausetheClanguagecannot
accesscorecontrolregistersdirectly.Intheattach_semaphore()
routineabove,thereisonelineofassemblycodeasfollows
asm( mfcrR1,PSR\nlrwR2,save\nstw R1,(R2,0)\n);
ThesethreeassemblyinstructionssavethecontentsofthePSRreg-
isterinthememorylocationnamedsave.Thecode
asm( lrwr2,save\nldwR1,(r2,0)\nmtcrR1,PSR\n);
movesthecontentsofthememorylocationsave backintothePSR.
The bits that enable both the fast interrupts and the conventional
interruptsarecontainedinthisregister.Therefore,thecodeasshown
intheattach_semaphore()routinesavesthecurrentlyenabled
interrupts,disablesallinterrupts,andafterthestatusofthesemaphore
isestablishedandsetproperly,restoresthePSRtoitsoriginalvalue.
Whenthesemaphoreisattached,itismarkedtrueinthearrayof
available semaphores. The function release_semaphore()
marks the semaphore as FALSE. The program can query the
semaphoretodetermineifitisbeingused.Thisfunctionreturnsthe
valuesavedinthespecifiedlocationinthearrayofsemaphoresthat
isTRUEwhenthesemaphoreisbeingused.Thefinalfunctionisto
wait_for_semaphore().Whenthisfunctionisentered,control
willremaininthefunctionuntilthespecifiedsemaphoreisreleased.
It is important that you do not attempt to wait for an unattached
semaphore.Inthatcase,controlwillneverbereturnedtothecalling
program.
DelaysRevisited
401
Delays Revisited
Withsemaphoresavailable,wecanimproveonthedelayfunction
by removing the wait loop from within the function to the calling
function,whereitsusecanbedictatedbytheprogram.Inthiscase,
thecallingfunctionwillcreateasemaphoreandsendthesemaphore
tothedelayfunction.Theproposeddelayfunctionis
includemmc2001.h
#includetimer.h
#includeintctl.h
/***********************************************************
Delaybytmilliseconds.Thisdelaycontrolsasemaphore
thatwillbeexaminedbythecallingprogram.Whenthe
semaphoreisreleased,thedelayiscompleted.Itis
assumedthatfastinterruptsareenabledwhenthisfunc-
tioniscalledandthattheinterrupthandlerhasbeen
appropriatelysetup.
*****************************************************************/
staticintsem;/*thisvariableneedstobefileglobal*/
voiddelay(WORDt,intsemaphore)
{
longcount;
sem=semaphore; /*savesemaphoresoisrcanseeit*/
ITCSR.EN=ON; /*enablethepit*/
ITCSR.OVW=ON; /*enablewritethrough*/
/*aninterruptwilloccurintmilliseconds*/
count=(long)t*1000;/*makethedelayinus*/
ITDR=count/122; /*122uspertick*/
ITCSR.ITIE=ON; /*enablepitinterrupt*/
FIER.EF8=ON; /*enablethefastinterrupts*/
}/*returntothecallingprogram,wearedonehere*/
voidpit_isr(void)/*interrupt occurs whendelaytimeexpires*/
{
ITCSR.ITIF=ON; /*turninterruptflagoff*/
ITCSR.ITIE=OFF; /*disablethePITinterrupt*/
ITCSR.EN=OFF; /* disablethePIT*/
FIER.EF8=OFF; /*disablethepitfastinterrupt*/
release_semaphore(sem);/*releasesemaphoretocallingprogram*/
}
Listing8-3:AlternateDelayRoutine
402 Chapter8 MCORE, A RISC Machine
Theprogramthatcallsthedelay()functionabovehassome
responsibilitiesinmakingthisfunctionwork.Thisdelayisusingthe
PITinterrupt.Mostofthecodenecessarytoimplementtheinterrupt
iscontainedinthedelayfunction.Thereare,however,acoupleof
itemsthathavetobetakencareofoutsidethedelayroutine.Thefirst
istoplacetheaddressoftheinterrupthandlerintothefastinterrupt
vector.Also,thesystemfastinterruptsmustbeenabled.Youwillsee
thesemattersaretakencareofinthefollowingtestfunction.
Inthepreviousroutine,thesemaphorenumberissavedexternally
sothatitcanbeaccessedbytheinterruptserviceroutine.Nextthe
PITisenabledandtheITDRtoITADRwritethroughisenabledso
thatthevaluewrittentotheITDRisthevaluetobecounteddownin
thetimer.Thecountvalueisnextcalculated.Remember,thecounter
isdrivenat8192Hz.Thisvalueisobtainedbycountingtheoutput
fromacrystal-controlledoscillatorrunningat32768Hzby4.The
timepercountisapproximately122microseconds.Thedelaytime
passedtothefunctionisinmilliseconds,sotocalculatethecount
valuetobeplacedintotheITDR/ITADR,theprogramfirstconverts
thedelaytimetomicrosecondsbymultiplyingitby1000.Then,the
countvalueiscalculatedbydividingthemicrosecondsby122.This
valueiswrittentotheITDRanditisautomaticallywrittenthrough
totheITADRwhereitiscounteddownbythehardware.
Theremainingcodeinthedelay()routineenablesthePITinterrupt
andalsoenablesthefastinterrupt,bit8,thatisconnectedtotheoutput
fromthePIT.Controlisthenpassedbacktothecallingprogram.
#includemmc2001.h
#includeserial.h
#defineFAST_AUTOVECTOR0x3000002c
/*functionprototypes*/
voidhandler(void);
intattach_semaphore(void);
voidwait_for_semaphore(int);
main()
{
UWORDcount=0;
intsemaphore;
DelaysRevisited
403
inituart(38400);
Enable_Fast_Interrupts();
vector(handler,FAST_AUTOVECTOR);
while(count++<300)
{
if((semaphore=attach_semaphore())==-1)
{
puts(semaphoreattachmenterror\n);
exit(0);
}
delay(1000,semaphore);
wait_for_semaphore(semaphore);
printd(count);
putchar(\r);
}
}
Listing8-4:DelayTestRoutine
Thedelaytestroutinefirstinitializestheon-boardUARTsothat
signalscanbesenttoaterminalandthenenablesthefastinterrupts
andplacesthehandleraddressintheFAST_AUTOVECTORlocation
asneeded.Themaintestattachesasemaphore,executesadelayof
1000milliseconds,waitsforthedelaytoexpireandprintsavalueto
thescreen.Thissequenceisplacedinaloopthatisexecuted300times.
Notethatitisimportantthatattach_semaphore()bechecked
fora 1return.Ifnot,youcouldattempttoattachtoomanysemaphores,
andyourcodewouldnotcatchtheerror.Intheabovecase,theprogram
wasexitedwiththeexit()function.Itisnotusuallynecessaryto
aborttheprogramwhenthereisnosemaphorewhenoneisneeded.
Youcanmerelywaitforasemaphorewithanyvaluebetween0and9.
Whenthatsemaphoreisreleased,youcanproceedwitharequestto
attachasemaphoreanditshouldthensucceed.
Theattachsemaphoreisinthecallingprograminthiscase.The
semaphorenumberissenttothedelayprogramwhereitisinturn
passedtothepitinterruptserviceroutine.Whentheinterruptservice
routine,aftertheproperdelay,isexecuted,thespecifiedsemaphore
isreleased.Therefore,inthecallingprogram,thewaitforsemaphore
routine is executed until the semaphore is released. If needed, the
semaphore status can be polled synchronously by the program to
determine when the delay time has expired. In other words, the
404 Chapter8 MCORE, A RISC Machine
computerdoesnothavetositinawaitloopuntilthedelaytimeis
overtoimplementthedelay.
Thetwodelayfunctions,thoseshowninListings8-1and8-3,
areexamplesofcodethatareveryclosetothemicrocontroller.The
applicationprogramshowninListing8-4isthetypeofprogramthat
couldalmostbeviewedasdivorcedfromthemicrocontroller.In8-4
thetwooperations
Enable_Fast_Interrupts();
vector(handler,FAST_AUTOVECTOR);
are clearly processor dependent, but these processor dependent
functionsarewrittenasfunctions,orfunction-likemacros.Therefore,
ifitisnecessarytomovetoanotherprocessor,itisnecessaryonlyto
adjustthecontentsofthesefunctionstomaketheprogramusable.
Thetwodelayfunctions,ontheotherhand,areamasscollectionof
processor-specific commands that would have no meaning if the
processorweretobechanged.Itisagoodideawhenwritingcode
forembeddedmicrocontrollerstocollecttogetheralloftheprocessor
specificcodeintofunctionsbythemselvesandallowthegeneralcode
tobeasfreefromprocessorspecificsaspossible.Wewillseethis
ideainthefollowingsectionwhereseveralgeneralfunctionsinterface
withseveralprocessor-specificfunctions.
Serial Input/Output
Serial input/output is an important capability of almost all
microcontrollersthatallowstheprogrammerorusertocommunicate
with the processor. Most of these functions are rather simple to
implement.Someofthefunctionsarequiteprocessor-specificand
othersaremoregenerallyapplicabletomanymicrocontrollers.As
mentionedabove,itisimportantthatyousplitthesefunctionsapart
sothatasmuchofthecodethatyougenerateaspossibleisportable.
Letuslookatthefunctionscontainedinserial1.c.
/***********************************************************
TheseroutinesimplementaserialportontheMMC2001.
TheUART1isusedandthedefaultissetto9600b/s,8bit,
noparity,and1stopbit.Thebaudrateispassedasan
integertotheinituart()function.Thereareseverali/o
functionsincluded.Theseare:
Serial Input/Output
405
inituart() Initializestheuarttothepassedbaud
rateandsets8bit,noparity,andone
stopbit.
getchar() testsforreceivereadyandecho
getch() noecho
getce() noreadytestorecho
kbhit() returnsTRUEifakeyhasbeenhit,
FALSEotherwise
putchar() Testsfortransmitready
puts() sendsouttheindicatedstring
gets() readsinastringintothebuffer
getse() readsinastringandechos
printd() convertanunsignedlongintegertoan
asciistringrepresentationofadecimal
integerandsenditouttheserialport
printx() convertanunsignedlongintegertoan
asciistringrepresentationofa
hexidecimalintegerandsenditoutthe
serialport
*********************************************************************/
#includemmc2001.h
#includeuart.h
#includeserial.h
#defineU1SRint(*(volatileunsignedshort*)(0x1000a086))
enum{TRDYint=8192};
#defineU1RXint(*(volatileunsignedshort*)(0x1000a000))
enum{CHARRDYint=32768};
#defineCLOCK_FREQ32000000L
/*thefunctions*/
/*InitializetheUART1*/
voidinituart(intbaud)
{
/*Parityisdisabledatresetbydefault*/
/*stopbitsissetto1bydefault*/
/*assumesa32mHzsystemclock*/
U1CR1.UARTEN=ON; /*Turntheuarton*/
U1CR1.TXEN=ON; /*enabletransmitterandreceiver*/
U1CR1.RXEN=ON;
U1CR2.IRTS=ON; /*ignorerequesttosend*/
U1CR2.WS=ON; /*8bitword*/
/*Baudrate=CLOCK_FREQ/16/baud=*/
U1BRGR.CD=(UHWORD)(CLOCK_FREQ/16/baud);
406 Chapter8 MCORE, A RISC Machine
U1PCR.PC3=ON; /*connectalli/opinstotheuart*/
U1PCR.PC2=ON;
U1PCR.PC1=ON;
U1PCR.PC0=ON;
U1DDR.PDC1=ON;/*makeoutputpinfortheuart*/
} /*probablynotneeded*/
/*sendacharacterouttheserialportwhenitisready*/
staticvoidput(BYTEx)
{
while((U1SRint&TRDYint)==0)
; /*waituntilcharacterisready*/
U1TX.DATA=x;/*sendthedataout*/
}
/*readinandechoacharacterthroughtheserialport*/
BYTEgetchar(void)
{
BYTEa;
while((U1RXint&CHARRDYint)==0)
; /*waittillcharacterisready*/
a=U1RX.DATA;
putchar(a);
returna;
}
/*readinacharacterwithnoecho*/
BYTEgetch(void)
{
BYTEa;
while((U1RXint&CHARRDYint)==0)
; /*waittillcharacterisready*/
a=U1RX.DATA;
returna;
}
/*readinacharacterfromtheserialport.Donot
checkforthecharacterready.Thisroutineshouldbeused
withkbhit().*/
BYTEgetce(void)
{
returnU1RX.DATA;
}
Serial Input/Output
407
/*returnTRUEwhenakeyhasbeenhitandFALSEotherwise*/
intkbhit(void)
{
returnU1RX.CHARRDY;
}
/*convertalongtoaseriesofasciicharacters
andsenditouttheserialport*/
voidprintd(unsignedlongx)
{
if(x/10)
printd(x/10);
putchar(x%10+0');
}
/*sameasabovebutoutputhexidecimal*/
voidprintx(unsignedlongx)
{
if(x/16)
printx(x/16);
putchar(x%16+((x%16>9)?(a):(0)));
}
Listing8-5:SerialInput/OutputFunctions
Atthebeginningoftheprogram,theusualheadersareincluded.
In this case, mmc2001.h is needed to identify the address of the
UART,theheaderuart.hcontainsallofthedefinitionsneededfor
the UART registers, and the serial.h header contains function
prototypesforalloftheserialinput/outputfunctions.Thesefunctions
arefordemonstrationpurposesonly.Theyallwork.Ihaveusedthese
functions at 115200 bit rates and had no problems. None of them
haveanybuilt-intestsforerrorsonreceptionlikeparitytests,framing
errors, or overrun errors. These tests need to be included and the
errors handled properly if you want to have a production quality
input/outputlibrary.
In the text that follows, each of the several small functions
contained in the above listing will be described individually. The
firstfunctionistheinituart()function.
#includemmc2001.h
#includeuart.h
#includeserial.h
408 Chapter8 MCORE, A RISC Machine
#defineCLOCK_FREQ32000000L
/*InitializetheUART1*/
voidinituart(intbaud)
{
/*Parityisdisabledatresetbydefault*/
/*stopbitsissetto1bydefault*/
/*assumesa32mHzsystemclock*/
U1CR1.UARTEN=ON; /*Turntheuarton*/
U1CR1.TXEN=ON; /*enabletransmitterandreceiver*/
U1CR1.RXEN=ON;
U1CR2.IRTS=ON; /*ignorerequesttosend*/
U1CR2.WS=ON; /*8bitword*/
/*Baudrate=CLOCK_FREQ/16/baud=*/
U1BRGR.CD=(UHWORD)(CLOCK_FREQ/16/baud);
U1PCR.PC3=ON; /*connectalli/opinstotheuarts*/
U1PCR.PC2=ON;
U1PCR.PC1=ON;
U1PCR.PC0=ON;
U1DDR.PDC1=ON; /*makeoutputpinfortheuart*/
}
Listing8-6:Theinituart()Function
Eachofthesefunctionswillhavethesamethreeheaderfunctions
shown in Listing 8-6. In this case, the function requires the clock
speedofthechip.Thisspeedcanbeanything,andinourparticular
case,itis32MHz.ThemacrodefinitionCLOCK_FREQmakesthis
value32000000.Ifyoueverchangetheclockspeedofthecomputer,
thisvalueshouldbechanged.Theseveralinstructionsinthefunction
are all commented with their operations. This function should be
executedwhenevertheserialI/Osystemistobeusedbyaprogram.
Passthedesiredbaudratetothefunctionasaninteger.Theinteger
sizeontheDIABcompilerusedforthissystemis32bits;therefore,
therewillbenooverflowproblemforanyoftheusualchoicesfor
baudrates.
Followingtheinituart()functionabove,thereistheseries
offivefunctionsshowninListing8-7.Thesefunctionsareallplaced
togetherbecausetheyeachaccesson-boardfeaturesoftheMCORE
chip.Almostalways,itisbesttocollectoperationsthataccesson-
boardregistersthatcontrolperipheraldevicesintoindividualfunctions
thatcanbecalledfromtheapplicationsportionoftheprogram.This
way,thedetailedfeaturesofthechiparetightlycontainedinfunctions
Serial Input/Output
409
thatcanbeeasilychangedifthechipitselfischanged.Thedefines
andenumssetatthebeginningofListing8-7arefromthetopofthe
serial1.cprogram.Thevaluesestablishedbythesedevicesare
usedinthefunctionsofListing8-7.These#definesandenums
wouldnotbenecessaryifthecompilerworkedasexpected.Generally,
ifyouwanttowaituntilitissafetosendacharacterouttheserial
port,thecodethatyoumightuseis
while(U1SR.TDRY==0)
; /* waithereuntilTDRYis1*/
ThiscodewillcausethecomputertositinaloopwhiletheTDRYbit
foundinU1SRis0.Unfortunately,thecodecreatedbythecompiler
failedtoreloadthevalueofthebitinsidetheloop,sothecomputer
wentintoaninfiniteloopwhenitexecutedthiscode.
TherearealwayswaysaroundsuchproblemsandwithCitisnot
usuallynecessarytojumptoassemblylanguagewhensuchaproblem
is found. Notice the code below. Rather than the argument shown
above,theargumentwasconvertedtoasimplebit-wiseAND,which
didcompilecorrectly.Remember,theadditionofa#defineoran
enum in your code does not add or subtract from the executable
codeinyourprogram.
The first two functions shown below are put() and
getchar().Thefunctionput()sendsacharactertotheserial
portnumber1ontheboard.Itworkswiththefunctionputchar(),
whichworksexactlythesameastheputchar()functionthatyou
are used to using in your programs. Here putchar() sends a
charactertotheserialportratherthantothedevicestdout.The
functiongetchar()receivesacharacterfromtheserialport1.In
C,whena\ncharacterissenttotheoutputtheprogramexecutes
acarriagereturnandalinefeed.Therefore,tomakegetchar()
herethesame,youwillseeinthenextgroupoffunctionsthatthe
datareceivedbygetchar()istested.Ifitisa\ncharacter,two
characters,\nand\r,aresenttotheserialport.Otherwise,
the character passed to the function is sent to the serial port.This
operationmimicstheoperationofthenormalgetchar(),butit
alsorequiresaspecialfunctiontooutputthecharactertotheserial
port.Thefunctionput(BYTEx)isthatfunction.Sincethefunction
put() is never to be used outside of this file, it is designated as
static.
410 Chapter8 MCORE, A RISC Machine
Thefunctiongetchar()readsasinglecharacterfromtheserial
port.Thisfunctionalsomimicsthegetchar()thatyouareused
tousing,becauseitechoesthecharacterreceivedtotheserialport
output.Theremightbeanoccasioninwhichyouwanttoreadina
characterwithoutechoingittotheserialoutput.Inthatcase,youcan
usegetch()shownbelow.Thisfunctionworksexactlythesame
asgetchar()butitdoesnotechothedatareceived.
#defineU1SRint(*(volatileunsignedshort*)(0x1000a086))
enum{TRDYint=8192};
#defineU1RXint(*(volatileunsignedshort*)(0x1000a000))
enum{CHARRDYint=32768};
/*sendacharacterouttheserialportwhenitisready*/
staticvoidput(BYTEx)
{
while((U1SRint&TRDYint)==0)
; /*waituntilregisteravailable*/
U1TX.DATA=x;/*sendthedataout*/
}
/*readinandechoacharacterthroughtheserialport*/
BYTEgetchar(void)
{
BYTEa;
while((U1RXint&CHARRDYint)==0)
; /*waittillcharacterisready*/
a=U1RX.DATA;
putchar(a);
returna;
}
/*readinacharacterwithnoecho*/
BYTEgetch(void)
{
BYTEa;
while((U1RXint&CHARRDYint)==0)
; /*waittillcharacterisready*/
a=U1RX.DATA;
returna;
}
Serial Input/Output
411
/*readinacharacterfromtheserialport. Donot
checkforthecharacterready.Thisroutineshould
beusedwithkbhit().*/
BYTEgetce(void)
{
returnU1RX.DATA;
}
/*returnTRUEwhenakeyhasbeenhitandFALSEotherwise*/
intkbhit(void)
{
returnU1RX.CHARRDY;
}
Listing8-7:DirectI/OFunctions
ThelasttwofunctionsshowninListing8-7areusefulwhenyou
needtoexitafunctionifthereisanasynchronouskeyboardhit.The
functionkbhit()returnsalogicalTRUEorFALSE.Itsreturnshould
beusedastheargumenttoanif() orwhile()test.Wheneverthe
keyboardistouched,kbhit()returnsaTRUE.Thatmeansthata
characterhasbeenenteredintothekeyboard.Ifyouneedtoreadand
usethevalueentered,thetesttodetermineifacharacterisreadyis
notnecessary.Therefore,thefunctiongetce()waswrittentoread
inthevaluecontainedinthedataregisterwithoutinvolvingatestto
showthatthereisacharacterreadytoberead.Thesetwofunctions,
kbhit()andgetce()shouldbeusedtogether.
Thenextfourfunctionsshownbelowalsoaccesstheserialinput
andoutput,buttheyallusethefunctionsaboveforthedirectaccess
andhavenocomputerspecificcode.Thefunctionputchar()checks
to determine if the parameter x is a \n. If it is, the function
put()iscalledtwicewitha\nanda\rargument.Otherwise,
thecharacterpassedtothefunctionissenttoput()whereitissent
totheserialport.
/*Sendacharactertotheserialportwhentheportis
available.Ifa\nisreceivedsenda\nfollowedby
a\rsequence.*/
voidputchar(BYTEx)
{
if(x==\n)
412 Chapter8 MCORE, A RISC Machine
{
put(\n);
put(\r);
}
else
put(x);
}
/*sendastringtotheserialport*/
voidputs(BYTE*a)
{
while(*a!=\0')
putchar(*a++);
}
/*Thisfunctionreadsastringintothebuffera.The
lengthofthebufferismax.Ifthestringislessthan
maxlong,thefunctionreturnsthenumberofcharacters
entered.Ifthestringislongerthanthebuffer,the
bufferisfilledanda-1isreturned.Theinputstring
isterminatedbyeithera\nora\r.*/
intgets(BYTE*a,intmax)/*noecho*/
{
inti=0,c;
do /*readindataabyteatatime*/
{
*a++=c=getch();
}while(c!=\n&&c!=\r&&++i<max-1);
*a=\0'; /*makeitastring*/
return(i>=max)?-1:i;
}
/*sameasgets()butdataenteredareechoed*/
intgetse(BYTE*a,intmax)/*withecho*/
{
inti=0,c;
do
{
*a++=c=getchar();
}while(c!=\n&&c!=\r&&++i<max-1);
*a=\0';
return(i>=max)?-1:i;
}
Listing8-8:GeneralSerialInput/OutputFunctions
Handling Interrupts
413
Thenextthreefunctionscanbeusedtosendandreceivestrings
throughtheserialport.Touseputs(),youuseastringargument.
Thisfunctionwillsendcharactersfromthestringuntilitfindsazero
value in the string. The get string functions perform similar to the
standard fgets() function. The difference between gets() and
getse()isthatgetse()echoesthecharactersreadintotheserial
output.Otherwisethesetwofunctionsareidentical.Youpassgets()
twoparameters.Thefirstisapointertoacharacterarrayandthesecond
isthedimensionofthisarray.Ascharactersarereadintotheprogram,
theyarestoredinthecharacterarray.Thestringinputisterminatedby
eithera\nora\rcharacter.Theinputwillalsobeterminated
whentheinputcharacterstringisonelessthanthesizeofthearraysize.
Whenterminationisdetected,theinputisterminatedwithacharacter
zero,makingthedataastring.Thereturntothecallingprogramwillbe
1intheeventthatthecharacterarraywascompletelyfilled.Otherwise,
thereturnisthenumberofcharactersenteredintothecharacterarray.
The functiongets() reads data from the serial port with the
getch() function. This input does not echo the data entered.
getse()usesthegetchar()toreadthedatain.getchar()
alwaysechoestheinputdatatotheserialoutput.
The above routines were separated into a series of individual
functions,whichwerecombinedintoanarchivelibraryfile.Thisfile
isfoundontheCDROMunderthenamelibserio.a.Thisfile
canbelinkedduringthelinkingoperationlikeanyotherlibraryfile.
Handling Interrupts
AlloftheonboardperipheralsfoundontheMMC2001thatneed
accesstointerruptsaresetuptousethecoreprocessorAutoVector
capability.ShowninTable8-1isacopyoftheinterruptvectortable.
ThevectortableisplacedatalocationcalledtheVBA,VectorBase
Address,whenthechipisinitialized.Youwillnotethatthetableis
0x200, two hundred hex bytes, long. The vector numbers are
consecutive.Thevectoraddressesmoveinstepsof4andareusually
dealtwithashexadecimalvalues.Thistablemustbefilledinsome
waywhentheprogramisinitialized.Eachvectorwillcontaintheaddress
of the function executed when the corresponding exception occurs.
Mostofthesevectorsareself-explanatory.OfimporthereistheFast
InterruptAutovectorlocation.Notethattheoffsetofthisvectoris0x2c.
414 Chapter8 MCORE, A RISC Machine
TheuseofthistableissimilartothatshownwiththeMC68HC16
family.Here,though,wewillconcentrateontheuseoftheautovector.
The autovector is accessed when an interrupt is called with the
autovector line to the core processor asserted. When this type of
interrupt is executed, control of the processor is automatically
transferred to the function addressed contained in the autovector
vector.Noteinthetablethattherearetwoautovectorlocations,the
normal autovector and the fast autovector. The DIAB compiler
automatically encodes interrupts to use the fast autovector, so the
offsetvectorlocationis0x2cfromtheVectorBaseAddress.
The MMC2001 has an internal peripheral called the Interrupt
Controller. This device handles all interrupt sources from the on-
boardperipherals.Thereareseveral32-bitregistersintheInterrupt
Controller.You will notice in the MMC2001 Reference Manual,
Section10,thattheseregistersareeachjustcollectionsof32single
bits.Theseregisterscontrolinterrupts.Thefirstregisteriscalledthe
Interrupt Source Register, INTSCR. Whenever an interrupt is
requestedbythiscontroller,itisassignedalevelfrom0to32andthe
correspondingbitintheINTSCRisset.Therearetwointerruptenable
registers:NormalInterruptEnable,NIERandFastInterruptEnable,
FIER.Theprogrammustsetthecorrespondingbitinoneofthese
registerstoenableaninterrupttobedetected.
When an interrupt is requested, the corresponding bit in the
INTSCR is set and this register is automatically ORed with the
InterruptEnableregisters.Theresultsoftheseoperationsarestored
in the proper Interrupt Pending Register. These registers, NIPND
andFIPND,thencontainabitpatternthatshowallofthepending
interruptsforthesystem.
ThereisoneveryconvenientinstructionavailableintheMCORE
instructionset.Thisinstruction,FF1,indicatesfindthefirst1setin
amemorylocation.Thisinstructionusesthesystembarrelshifterand
requiresonlyoneclockcycle.Thepriorityoftheseveralinterrupting
sourcesisestablishedbytheirindividualbitlocationsinthevarious
registersinthecontroller.IntheFIPNDregisters,bit31containsthe
status of the highest priority pending interrupt, etc. When the FF1
instructionisexecutedontheFIPND,theresultidentifiesthebitnumber
of the highest priority pending fast interrupt. Table 8-2 shows the
interruptassignmentsofallon-boardperipheralsonthischip.
Handling Interrupts
415
TheFF1instructionreturnsa0ifbit31issetand31ifbit0is
set. It also returns a 32 if no bit is set in the designated memory
location.Therefore,ifthePITisthehighestrequestedinterrupt,the
contentsoftheFIPNDregisterarestoredinR3,andtheinstruction
FF1R3
isexecuted,R3willcontainthenumericvalue24.Wecanusethis
sequencetovectortothecorrectinterruptserviceroutine.Consider
the code shown in Listing 8-9.This function is a general-purpose
interrupthandlertocontroltheautovectoraccess.Theprogramstarts
withthenormalfileinclusions.Inthiscase,theinterruptcontroller
isbeingusedsotheheaderintctl.hisincluded.Thecodethat
followsmustaccessthecontentsofthefastpendinginterruptregister
FPIND.TheaddressofthisregisterisplacedintothelocationfIpnd1
forconvenientaccessbytheassemblyprogramthatisgeneratedlater.
ThenextentrydefinesastructTable,whichcontainsanarrayof
32pointerstofunctionsthatrequirenoparametersandreturnthetype
void.Aninstanceofthisstructureiscreatedandnamedtable.The
32 entries in the array are each filled with a pointer to the function
unused_vector().Itisdifficulttodecidewhattofillunusedvectors
with.Thechoiceofzeroisnotrealistic.Whenaninterruptoccursthat
needsoneofthesevectors,controlispassedtotheaddresscontained
inthevector.Ifthevectorcontainszero,thecomputergoestozeroand
startsexecutinginstructionsfoundthere.Theprogramwillsurelyrun
amuckuntilwhoknowswhenifitistoldtoexecutethecodefoundat
zero!Iusuallycreateasimpleinterruptserviceroutinethatdoesnothing
to help here. The function in the listing below is called
unused_vector().Inthiscase,ifanuninitializedinterruptoccurs,
it will be ignored and control will be passed back to the executing
program.Thisparticularapproachhasthedrawbackthatyouarenever
aware of the occurrence of uninitialized interrupts unless you put a
breakofsomesortintheunused_vector()routine.
Inpractice,youwillneedtoplacethenamesofinterruptservice
routinesinthepropervectorlocationsshownbelow.Wewilldothis
inlatercodetoshowyouhow.
#includemmc2001.h
#includeintctl.h
UWORDconstfIpnd1=INTCTL_+0X10;
416 Chapter8 MCORE, A RISC Machine
voidhandler(void);
voidunused_vector(void);
staticstructTable{
void(*vector[32])(void);
};
structTabletable={
unused_vector,/*31unused*/
unused_vector,/*30unused*/
unused_vector,/*29unused*/
unused_vector,/*28INT7*/
unused_vector,/*27INT6*/
unused_vector,/*26INT5*/
unused_vector,/*25INT4*/
unused_vector,/*24INT3*/
unused_vector,/*23INT2*/
unused_vector,/*22INT1*/
unused_vector,/*21INT0*/
unused_vector,/*20ISPI*/
unused_vector,/*19UART1receive*/
unused_vector,/*18UART0receive*/
unused_vector,/*17UART1transmit*/
unused_vector,/*16UART0transmit*/
unused_vector,/*15PWM5*/
unused_vector,/*14PWM4*/
unused_vector,/*13PWM3*/
unused_vector,/*12PWM2*/
unused_vector,/*11PWM1*/
unused_vector,/*10PWM0*/
unused_vector,/*9unused*/
unsued_vector,/*8PIT*/
unused_vector,/*7Time-of-dayalarm*/
unused_vector,/*6KPPcontrol*/
unused_vector,/*5UART0RTS_DELTA*/
unused_vector,/*4unused*/
unused_vector,/*3unused*/
unused_vector,/*2software3*/
unused_vector,/*1software2*/
unused_vector /*0software1*/
};
#defineDo_Interrupt()asm(subiR0,32\nsubiR0,28\n \
stmR1-R15,(R0)\nlrwR2,table\n\
lrwR3,fIpnd1\nldwR3,(R3,0)\n\
ldwR3,(R3,0)\nFF1R3\nlsliR3,2\n\
Handling Interrupts
417
adduR2,R3\nldwR2,(R2,0)\n\
jsrR2\nldmR1-R15,(R0)\n\
addiR0,32\naddiR0,28\nrfi\n)
voidunused_vector(void)
{}
voidhandler(void)
{
Do_Interrupt();
}
Listing8-9:AutovectorInterruptHandler
Followingthetableinitialization,thereisanassemblylanguage
sequence. This sequence is #defined as the function
Do_Interrupt(),whichiscalledintheinterruptserviceroutine
handler().Thefirstfiveassemblyinstructionsclear120byteson
thestack,enoughtosavethecontentsofregisters1through15,and
Table8-1ExceptionVectorAssignments
Vector Vector
Assignment
Number(s) Offset(Hex)
0 000 Reset
1 004
Misalignedaccess
2
008 Accesserror
3 00C
Dividebyzero
4 010 Illegalinstruction
5 014 Privilegeviolation
6 018 Traceexception
7 01C Breakpointexception
8
020 Unrecoverableerror
9 024 Softreset
10 028 INTautovector
11 02C FINTautovector
12
030 Hardwareaccelerator
13 034 (Reserved)
14
038
15
03C
16-19 040-04C Trap#0-3InstructionVectors
050-07C Reserved
32-127 080-1FC Reservedforvectored
interruptcontrolleruse
20-31
418 Chapter8 MCORE, A RISC Machine
save these registers on the stack. The following two assembly
instructionsloadtheaddressoftableintoR2andtheaddressof
fIpnd1 into R3.We want the contents of the value found in the
FPINDregister.Therefore,wemustdereferencethevalueinR3twice,
once to get the address of FPIND and then to get the contents of
FPIND.Thisvaluehasabitsetforeverypendingfastinterrupt.When
thisvalueisoperatedonbytheFF1instruction,theregisterR3will
containthe32minusthebitnumberofthehighestprioritypending
interrupt.Ifyoulookathowtable()isconstructed,youwillfind
thatthehighestpriorityinterruptsarelistedfirstdowntothelowest
priority.Eachentryinthetablerequiresfourbytestoholdafunction
pointerwiththissystem.Therefore,wemustmultiplythevaluefound
inR3by4,shiftitleft2,andthenaddtheresulttothevalueinR2to
findtheaddressofthedesiredinterruptserviceroutine.
Allofthatisexactlywhatisdonewiththeassemblylanguage
insertshownabove.ThelastinstructionjsrR2passescontrolof
thecomputertothespecifiedinterruptserviceroutine.Ifyoulookat
the C code generated by handler() you will find first that the
necessarycomputerstatusissavedandthentheassemblycodeinthe
macroDo_Interrupt()isexecuted.Thelastinstructionhereis
thejsrR2instructionmentionedabove.Afterthecodeneededfor
the interrupt service routine is completed, control is returned to
handler() where the machine status is restored and control is
returned to the interrupted program with an rfi, return from fast
interrupt,instruction.
Thecompilerhasa#pragmainterruptisr_function.This
#pragmacausesthefunctionspecifiedbytheisr_functionto
becompiledasaninterruptserviceroutine.Thesefunctionssavea
portion of the machine status, execute the code specified in the
isr_function,andrestorethemachinestatusbeforereturning
totheinterruptedprogramwithanrfiinstruction.Whenwritinga
generalfunctionsuchastheoneabove,itwasfoundthatthepartial
statussavewasnotenough.Nofunctionscouldbecalledfromwithin
the interrupt service routine. This limitation was too great for a
general-purposehandlerlikethatabove,sointhisroutine,theentire
statusofthecomputerissavedandrestoredratherthanthepartial
save and restore generated by the #pragma. It is safe to execute
functionswithintheinterruptserviceroutinesinthehandlerabove.
AClockProgram
419
Table8-2InterruptControllerAssignments
Bit
Number
Use
0,1,2 Software
3
unused
4 unused
5 UART0RTS_DELTA
6 KPPcontrol
7 Time-of-dayalarm
8 PIT
9 unused
10 PWM0
11 PWM1
12 PWM2
13 PWM3
14 PWM4
15 PWM5
16 UART0transmit
17 UART1transmit
18 UART0receive
19 UART1receive
20 ISPI
21
INT0
22 INT1
23 INT2
24 INT3
25 INT4
26 INT5
27 INT6
28 INT7
29 unused
30 unused
31 unused
AClockProgram
Aclockprogramisanexcellentprogramfordemonstratingthe
useofinterruptsonamicrocontroller.TheMMC2001hasarather
extensivetimersubsystem.Itisbrokenintothreeparts.Thereisa
timeofdayclock,TOD,withabuilt-inalarm,awatchdogtimerand
a programmable interval timer, PIT. We will use the PIT in this
example.Briefly,thetimersaredrivenbyaseparateclock.Theclock
here is a 32768-Hz clock controlled by a watch crystal.TheTOD
420 Chapter8 MCORE, A RISC Machine
clockisdrivenbythelow-frequencyoscillatorfrequencydividedby
128 or 256 Hz.The watchdog and the PIT are both driven by the
low-frequency oscillator frequency divided by 4 or 8196 Hz. The
TODkeepstrackofthetimeasthenumberofsecondssinceaspecified
time, perhaps midnight. There is no provision for automatic roll-
over of the registers at the end of the day, so if you want to work
frommidnighteachday,youmustresettheTODclocktozeroeach
midnight.Thisclockalsohasan8-bitfractionalsecondregisterin
additiontotheregular32-bitsecondcountregister.
Thealarmsystemalsocontainsan8-bitfractionalsecondregister
and a 32-bit second register.When the time in the alarm registers
matchesthetimeinthetimeofdayregister,aflagissetthatcanbe
polledoraninterruptcanberequested.
ThePITsystemcontainsaregisterthatiscounteddown.When
thisregisterunderflows,itcanbereloadedautomatically,setaflag
to be polled, or request an interrupt. Loading this register is done
througharegistercalledtheITDR,theIntervalTimerDataRegister.
Ifabitisset,datawrittentotheITDRwillautomaticallytransferto
the ITADR, the register that counts down. When this register
underflows,thecontentsoftheITDRisautomaticallytransferredto
theITADR.ThecontentsoftheITDRcanbechangedatanytime,
and it can be changed without altering the contents of the ITADR
untilthenextunderflow.
TheITADRisclocked8192timespersecond,approximately122
microseconds.Sinceitisclockedanexactnumberoftimespersecond,
itispossibletocountinexactsecondintervals.Itmakesnodifference
howyoubreakupthetimeintervals,theclockwilldecrementexactly
8192timesinonesecond.Therefore,ifyouwantabasicintervaltime
forotherusesinthesystem,youcancauseinterruptstooccuratthis
fasterrateandthencountthenumberofinterruptsuntilyouachieve
the magic number of 8192 ticks each second. For example, many
systemsneeda1or2millisecondtimeinterval.Thesystemcanbeset
tointerruptaboutevery2millisecondsandthenintheISR,acounter
incremented.Thiscountercountstoabout500eachsecondandcanbe
easilyusedinaclockcontroller.Ofcourse,aboutisnotallowed.
The interrupt time must be 0.001953125 seconds and there will be
exactly512interruptspersecond.
The program starts out with the creation of a function that we
willcallkeep_time().Thisfunctionisexecutedrepeatedlyinside
AClockProgram
421
ofaloop.Therearefourexternalvariables,hours,seconds,minutes,
and count accessed by keep_time(). The variable count is
incremented in an interrupt service routine that is executed each
1.953125milliseconds.TheconstantTIME_COUNTwillhaveavalue
of511.WhencountbecomesgreaterthanTIME_COUNT,count
isresettozeroandtheparametersecondsareincremented.When
seconds exceeds the value 59, seconds is reset to zero and
minutesisincremented.Whenminutesexceeds59,itisresetto
zero and hours is incremented. Finally, when hours becomes
greater than 12, it is reset to 1 which corresponds to one oclock.
Onceeachsecond,thefunctionoutput_time()isexecuted.
#includemmc2001.h
#includetimer.h
#defineTIME_COUNT 511
#defineMAX_SECONDS 59
#defineMAX_MINUTES MAX_SECONDS
#defineMAX_HOURS 12
#defineMIN_HOURS 1
/*functionprototypes*/
voidoutput_time(void);
voidkeep_time(void);
/*externalglobalvariables*/
WORDseconds,minutes,hours,count;
/*themainapplicationsprogram.countisincrementedin
theisr512timeseachsecond.Therefore,thisroutine
mustbeexecutedatleastonceeverytwomilliseconds.*/
voidkeep_time(void)
{
if(count>TIME_COUNT)
{
count=0;
if(++seconds>MAX_SECONDS)
{
seconds=0;
if(++minutes>MAX_MINUTES)
{
minutes=0;
if(++hours>MAX_HOURS)
hours=MIN_HOURS;
422 Chapter8 MCORE, A RISC Machine
}
}
output_time();
}
}
Herewearestartingtowriteaprogram.Therefore,itissmartto
doallthingscorrectly.Forexample,wewillattempttoavoidmagic
numbersbydefiningmnemonicsforthenumbersusedintheprogram.
Also,wheneveranewfunctioniswritten,itsfunctionprototypewill
beimmediatelyinsertedintoafunctionprototypelistatthebeginning
oftheprogram.Aseriesofexternalvariablesisused.Itisusually
bettertouselocalvariableswhenworkingwithparametersinseveral
different functions. In that case, the parameters can be passed as
argumentstothefunctionswhentheyarecalled.Thisapproachavoids
debug problems where it becomes difficult to determine where
variables are changed in different functions. In the case here, the
variableshours,minutes andsecondsarechangedinonlyone
function,keep_time(),andthevariablecountischangedonly
intheinterruptserviceroutineortheresettimefunction.Therefore,
thereisnouncertaintyastowherethevariablesarechanged.
Note the structure of the if() statements in the function
keep_time().Thenestingofthesestatements
if()
{
.
if()
{
.
if()
{
.
}
}
}
causesthefirsttesttobeexecutedeverytimethefunctionisexecuted.
TheargumentofthefirsttestmustbeTRUEwhenthesecondtestis
executed,andtheargumentofthesecondtestmustbeTRUEwhen
the third test is executed, and so forth. Most of the time when the
functionisexecuted,thetotaleffortrequiredbytheabovenestedif
AClockProgram
423
sequenceistheoutsidetestonly.Suchanarrangementwillrequirea
minimumamountofcomputertimeeachtimethefunctionisexecuted.
Manyprogrammerswillnotnesttheabovetestssothateachtestis
executed each time the function is called. It works, but it requires
morecomputerresourcesthanthenestingshownabove.
Inthefunctionkeep_time()above,notethatthearguments
oftheseveralif()statementsallinvolveagreaterthantest.This
particularapproachismorerobustthananytestthatinvolvesanis
equaltotest.Inallcasesbutthehours,thetestedparameterisreset
to zero. Therefore, the zero is counted in the sequence and the
maximumvalueisonelessthanthenumberthatmightbeexpected.
For example, the range of seconds is 0..59 not 1..60, the range of
countis0..511not1..512.Whentherespectivecountexceedsthe
specifiedmaximumvalue,theparameterisresettoitsminimumvalue.
Iflightningshouldstrikethechipandthevalueofsecondsbesetat
100, the greater than test would fix the error the next time that
secondweretested.Intheeventthatanisequaltotestwereused,
itwouldbealongtimebeforethesecondswouldcountthrougha
wrap-aroundandbeequaltotheMAX_SECONDSvalueagain.
Alsonotetheifargument
if(++seconds>MAX_SECONDS)
{
The seconds are first incremented and then the test is completed.
Thissequencecouldbecompletedintwostatements,
seconds=seconds+1;
if(seconds>MAX_SECONDS)
{
Some people prefer the latter approach, but the two approaches
accomplishexactlythesamething.Theimportantitemisthatseconds
mustbeincrementedbeforethetestiscompletedratherthanafter.
Atthebottomofthesecondsloop,acalltooutput_time()
is executed.This function will send the current time to the output
device.Hereagain,thecalltooutput_time()couldbeplaced
anywhere in the loop, but the bottom, as is shown above, is best
becausetheoutputtakesplaceafteralloftheparametersareupdated
andthetimedisplayedwillbenowratherthanbeforealloftheupdates
arecompleted.
424 Chapter8 MCORE, A RISC Machine
AClockProgram
Letusnowlookatoutput_time().Forthisprogram,wewill
sendthetimetotheserialporttobedisplayedonaterminal.Allof
theparametershours,minutes,andsecondseachhavearangeof0or
1tosomemaximumtwo-digitvalue.Therefore,thesenumberswill
containonlytensandunits.Therewillbenohundredsorthousands
orfractions,orminussignsforthatmatter.Toconvertthesevaluesto
characterstobesenttoafunctionlikeputchar(),wehavetodo
twothings.Firstcountthenumberoftens,convertthisnumbertoan
ASCIIdigitanduseitasanargumenttoputchar().Thencalculate
thenumberofunitsinthenumber,convertittoanASCIIdigitand
sendittoputchar().Thesetwooperationsarerelativelyeasyto
program.Infact,theselittlefunctionscanbewrittenasfunction-like
macroseasily,asfollows:
#definehi(x)((x)/10+0)
#definelo(x)((x)%10+0)
Remember,thevaluepassedtothesetwomacrofunctionsmustlie
between0and99.Thefirstfunctionhi(x)determinesthenumber
oftensinthenumberandconvertstheresulttoanASCIIdigitby
adding the character zero to the result. The second calculates the
numberofunitsinthenumberbycalculatingthenumbermodulo10.
ThisvalueisconvertedtoanASCIIdigitwhenthecharacterzerois
added.
With these two little macros in hand, the output_time()
functioniseasytowrite:
voidoutput_time(void)
{
putchar(\r);
putchar(hi(hours));
putchar(lo(hours));
putchar(:);
putchar(hi(minutes));
putchar(lo(minutes));
putchar(:);
putchar(hi(seconds));
putchar(lo(seconds));
}
The output_time() function consists of a series of
putchar()functioncalls.Thefirsthasanargument\r.This
commandcausesthecursoronthescreentobereturnedtoitsleftmost
AClockProgram
425
position.Thenexttwocallssendthehourstothescreen.Thena
colonisprinted.Thissequenceisrepeatedfortheminutes andthe
secondsexceptnocolonissentoutaftertheseconds.
Our next problem is to set up the PIT. The PIT is to interrupt
onceeach1.953125milliseconds.TheclockthatdrivesthePITruns
at8192Hzandweneedaclockrateof512Hz.Therefore,weneed
tocount16clockticksbetweeninterrupts.IwillcallthistimeTWO_MS
inthefollowingcode.Thefunctionbelowisaninitializationfunction
to set up the PIT to operate as needed. Recall, data written to the
ITDRistransferredtotheITADRwhentheITADRunderflows.Data
writtentotheITDRisautomaticallytransferredtotheITADRifthe
OVWbitissetwhentheITDRiswritten.Thisbitwillbesetfirstand
thenthevalueTWO_MSiswrittentotheITDR.Next,thereloadmode
isenabledbysettingtheRLDbitintheITCSRregister.Inthismode,
thevalueintheITDRisautomaticallyreloadedintotheITADRwhen
theITADRunderflows.Thisoperationassuresaperiodicinterruptat
theperiodsetbythevaluestoredintheITDR.
TheinterrupthandlershowninthesectionHandlingInterrupts
will be used here. Recall that function contains a general-purpose
interruptserviceroutinethatcanbeusedforanyoftheautovector
interruptsintheMMC2001.Forourpurposeshere,theinterruptvector
number 8 in Listing 8-9 will have to be changed from
unused_vectortothenameofthePITinterruptserviceroutine.
Wewillcallthatroutinepit_isranditwillbewritteninthenext
section.Themacrofunctionvector()inthemmc2001.h header
file will be used to put the address of the header into the Fast
Autovectorvectorlocation.AlsointheInterruptHandlersectionyou
willfindTable8-1.Thistableshowstheallocationoftheinterrupt
vectorsinthebasevectortable.Thistableisplacedinaspecified
locationbythelinkerprogram.Withtheset-upusedforourprograms
inthisbook,IplacedthesystemRAMattheaddress0x30000000.
Thefirst0x200entriesinthistablearethevectortablewhoseoutline
isshowninTable8-1andwhosevaluesareestablishedbytheinterrupt
handler routine in Listing 8-9. There you will note that the Fast
InterruptAutovectorisoffset0x2cintothevectortable.Therefore,
the address of the FAST_AUTOVECTOR in our program must be
0x3000002c.Thenextinstructioninthecodebelowwillplacethe
addressofthepit_isrinterruptserviceroutineinthisaddress.
426 Chapter8 MCORE, A RISC Machine
#includeintctl.h
#defineTWO_MS 15
/*initializethePIT*/
voidpit_init(void)
{
ITCSR.OVW=ON;/*set-upITDR to ITADRoverload*/
ITDR=TWO_MS;/*interrupteachtwomilliseconds*/
ITCSR.RLD=ON;/*enablereloadmode*/
ITCSR.ITIF=ON;/*cleartheinterruptflag*/
ITCSR.ITIE=ON;/*enablethepitinterrupt*/
FIER.EF8=ON; /*enabletheAVECinterrupt*/
ITCSR.EN=ON; /*enablethepit*/
}
Thefinalfourinstructionsinthepit_init()functiongetthe
chipreadytoreceiveinterruptsfromthePIT.Thefirst
ITCSR.ITIF=ON;/*cleartheinterruptflag*/
clearstheinterruptflagITIF.Itisaquirkofthechipthattheinterrupt
flagisclearedbywritinga1tothechipratherthana0.Thisflag
should be cleared prior to enabling the interrupts for both the
autovectorandthePIT.Ifthisbitissetwhentheinterruptsareenabled,
thesystemwillimmediatelyrespondtotheinterruptandthataction
is not usually what is wanted. The next instruction turns on the
interruptenableflagITIEforthePIT.Thefastinterruptbit8issetin
the FIER register of the interrupt controller and finally, the PIT is
turnedonwhenthebitENissetintheITCSR.TheFIERregisteris
identifiedintheintctl.hheaderfile.Afterthiscodeisexecuted,
thePITissetupandreadytointerruptevery16ticksofthe8192-Hz
clock.
Ofcourse,wewillneedaninterruptserviceroutine.Whenthe
InterruptHandlerisused,theinterruptserviceroutineneednotbe
concerned with saving the system status. That is handled by the
interrupt handler.All that is needed in this case is to turn off the
interruptflagintheITCSRandincrementthevalueofcount.The
entireinterruptserviceroutineis
AClockProgram
427
/* inthisisr,allthatmustbedoneistoturnoffthe
pitinterruptrequestbitandincrementtheglobal
parametercount*/
voidpit_isr(void)
{
ITCSR.ITIF=ON;/*ONclearstheinterruptbitinthese
registers*/
count++;
}
The interrupt handler takes care of restoring the status prior to
returningtotheinterruptedprogram.
The next logical function that we will need is the function
main().Mainisbrokenintotwoparts,theinitializationportionof
theprogramandtheapplicationsportionoftheprogram.Thefirst
threeinstructionsaretheinitializationportionoftheprogram.Here,
theserialI/Osystemisinitializedandthebaudrateissettothevalue
BAUD_RATE.Thepit_init()routinewrittenaboveisexecuted
and then the system fast interrupts are enabled with the assembly
languagemacrofunctiondefinedintheheaderfilemmc2001.h.
#defineBAUD_RATE 38400
#defineFAST_AUTOVECTOR0x3000002c
main()
{
inituart(BAUD_RATE); /*initializetheUART*/
pit_init(); /*initializethePIT*/
vector(handler,FAST_AUTOVECTOR);/*puthandleraddress
inFAST_AUTOVECTOR.*/
Enable_Fast_Interrupts();
FOREVER
{
keep_time(); /*keeptrackofthetime*/
if(kbhit())
reset_time();
}
}
Theapplicationportionoftheprogramisquitesimple.Itissimply
aFOREVERloopthatrepeatedlyexecuteskeep_time().Alsoin
theloop,atestismadetodetermineifakeyhasbeentouchedonthe
terminal attached to the serial port. If it has, the function
reset_time()isexecutedwheretheclocktimecanbeset.
428 Chapter8 MCORE, A RISC Machine
The function reset_time() follows. Recall from earlier
discussionsthatthefunctiongetch()waswrittenspecificallyto
readinacharacterfromtheserialportafterthefunctionkbhit()
indicates that the keyboard has received an input. This function,
getch(),isusedhere.Thecharacterreadinissavedinthelocation
candthenaswitch/casestatementissetuptodeterminewhattodo
withtheinput.Itisassumedthatthelettersm,M,h,andHarethe
validinputs.WheneitheranmoranMisreceived,theminuteswill
beincremented.DetectionofeitheranhoranHwillcausethehours
tobeincremented.Anyotherinputwillmerelybediscarded,sothere
isnoneedforadefaultstatementintheswitch/casesequence.Ifan
m, either upper or lower case, is detected, the minutes will be
incremented. If the incremented value exceeds MAX_MINUTES,
minuteswillberesetto0.Similarlyifanhisdetected,thehourswill
beincrementedandiftheincrementedvalueexceedsMAX_HOURS,
hoursisresettoMIN_HOURS.Afterthesetransactionsarecompleted,
the function output_time() is executed. Without this final
functioncall,thesettingofthetimewillbeveryjumpy,definitely
notsmooth.
voidreset_time(void)
{
intc;
c=getch();
switch(c)
{
casem:
caseM: if(++minutes>MAX_MINUTES)
minutes=0;
break;
caseh:
caseH: if(++hours>MAX_HOURS)
hours=MIN_HOURS;
break;
}
output_time();/*sendout a new timeaftereachchange*/
}
Thatistheendoftheprogram.Theprogramseemsquitesimple,
andithasbeentestedthoroughly.Shownbelowisthewholeprogram
AClockProgram
429
pulledtogetherintoasinglelisting.Severalitemshavebeenmoved
aroundinthislistingtomakethewholeprogrameasiertofollow.
#includemmc2001.h
#includetimer.h
#includeintctl.h
#includeserial.h
#defineTIME_COUNT 511
#defineMAX_SECONDS 59
#defineMAX_MINUTES MAX_SECONDS
#defineMAX_HOURS 12
#defineMIN_HOURS 1
#defineFAST_AUTOVECTOR0x3000002c
#defineTWO_MS 15
#defineBAUD_RATE 38400
#definehi(x)((x)/10+0')
#definelo(x)((x)%10+0')
/*functionprototypes*/
voidoutput_time(void);
voidkeep_time(void);
voidreset_time(void);
voidpit_init(void);
voidpit_isr(void);
voidhandler(void);
/*externalglobalvariables*/
WORDseconds,minutes,hours,count;
/*themainapplicationsprogram.countisincrementedin
theisreverytwomilliseconds.Therefore,thisroutine
mustbeexecutedatleastonceeverytwomillisecondsto
keeptheoutputstotheserialportsmooth.*/
voidkeep_time(void)
{
if(count>TIME_COUNT)
{
count=0;
if(++seconds>MAX_SECONDS)
{
seconds=0;
if(++minutes>MAX_MINUTES)
{
430 Chapter8 MCORE, A RISC Machine
minutes=0;
if(++hours>MAX_HOURS)
hours=MIN_HOURS;
}
}
output_time();
}
}
voidoutput_time(void)
{
putchar(\r);
putchar(hi(hours));
putchar(lo(hours));
putchar(:);
putchar(hi(minutes));
putchar(lo(minutes));
putchar(:);
putchar(hi(seconds));
putchar(lo(seconds));
}
/*initializethePIT*/
voidpit_init(void)
{
ITCSR.OVW=ON; /*set-upITDRtoITADRoverload*/
ITDR=TWO_MS; /*interrupteachtwomilliseconds*/
ITCSR.RLD=ON; /*enablereloadmode*/
ITCSR.ITIF=ON;/*cleartheinterruptflag*/
ITCSR.ITIE=ON;/*enablethepitinterrupt*/
FIER.EF8=ON; /*enabletheAVECinterrupt*/
ITCSR.EN=ON; /*enablethepit*/
}
/*inthisisr,allthatmustbedoneistoturnoffthepit
interruptrequestbitandincrementtheglobalparameter
count*/
voidpit_isr(void)
{
ITCSR.ITIF=ON;/*ONclearstheinterruptbitinthese
registers*/
count++;
}
main()
AClockProgram
431
{
inituart(BAUD_RATE);/*initializetheUART*/
pit_init(); /*initializethePIT*/
vector(handler,FAST_AUTOVECTOR);
/*puthandleraddressinFAST_AUTOVECTOR.*/
Enable_Fast_Interrupts();
FOREVER
{
keep_time(); /*keeptrackofthetime*/
if(kbhit())
reset_time();
}
}
voidreset_time(void)
{
intc;
c=getch();
switch(c)
{
casem:
caseM: if(++minutes>MAX_MINUTES)
minutes=0;
break;
caseh:
caseH: if(++hours>MAX_HOURS)
hours=MIN_HOURS;
break;
}
output_time();/*send out a new timeaftereachchange*/
}
Listing8-10:CompleteClockRoutine
Notethatinthisprogramtheonlyfunctionsthathavedirectaccess
tothememoryofthecomputerarethosethatinvolvethePIT.The
pit_init()routineistrulychipspecificasisthepit_isr().
Alloftheotherroutinescouldbeusedonjustaboutanycomputer.It
is always good to place the chip-specific routines in functions by
themselves.Thenwhenyouneedtochangetoanotherchip,allofthe
chip-specificcodeislumpedtogetherandthegeneral-purposecode
iseasytoliftandmovetothenewprogram.
All #define object-like and function-like macros are placed at
theheadoftheprogram.Also,alistoffunctionprototypesisincluded.
432 Chapter8 MCORE, A RISC Machine
Everyfunctionintheprogramwiththeexceptionofmain()hasa
functionprototypeatthebeginningoftheprogram.Inthiscase,the
functions are all void functions that require no arguments. It is
important, however, that every programmer get into the habit of
placingtheseprototypesatthebeginningoftheirprograms,eitherin
theformofaheaderfileoradirectlistingintheprogram.
Keyboard
The MMC2001 chip has a built-in keyboard interface. This
interface can be either synchronously polled by the program, or it
can be asynchronously controlled through the use of an interrupt.
Wewillexaminetheasynchronouscontrolhere.Thisprogramrequires
threeparts.Thefirstistheinitializationroutine.Thisroutinesetsup
theoperationofthekeyboardtocauseaninterruptwheneverakeyis
depressed.Theinterruptservicedetectswhichkeyisdepressedand
savesitinabuffer.Theprogramalsosavesasemaphorepassedto
theinitializationroutine.Thissemaphoreisreleasedwhentheendof
a line is detected in the input. Then the main program prints the
buffertotheterminalscreen.
Theinitializationroutineisshownbelow:
#includemmc2001.h
#includekeypad.h
#includeintctl.h
staticintsemaph;
staticBYTE*data,*savedata;
staticintleng;
/*keyboardinitializationroutine*/
voidkpinit(intsem,BYTE*s,intlength)
{
KPCRN.LOROWS=0xf; /*enablekeypadrows*/
KPDRB.COLUMNS=0x0; /*write0toKPDR[15:8]*/
KPCRN.LOCOLS=0xf; /*makecolsopendrain*/
KDDRN.LOCOLS=0xf; /*makecolsoutputs*/
KDDRN.LOROWS=0x0; /*androwsinputs*/
KPSR.KPKD=ON; /*clearKPKDstatusflag*/
KPSR.KDSC=ON; /*clearkeydepresssynchronizer*/
KPSR.KDIE=ON; /*setKDIEbittoenabledepress
Interrupt*/
Keyboard
433
KPSR.KRIE=OFF; /*disablereleaseinterrupt*/
FIER.EF6=ON; /*enableFastInterruptnumber6*/
semaph=sem; /*savethesemaphore*/
data=s;
savedata=s; /*andarrayinformationfor*/
leng=length; /*useintheisr*/
}
Itisexpectedthatthecallingprogramwillattachasemaphore
and provide a buffer into which the input data will be stored.The
semaphoreispassedtotheinitializationroutineassem,andthearray
byapointertoitsfirstelementanditslength.Weplantousea4by
4 matrix keyboard. This keyboard will be connected to the least
significantfourrowsandcolumnsofthekeyboardcontrollerinterface.
Thereareseveralregistersthatattachtotheseinterfaces.TheKPCR
isacontrolregister,theKPDRisthedataregister,andtheKDDRis
thedatadirectionregister.Increatingtheheaderfileforthekeyboard
controller, I added an extra letter, N or B, to these pseudovariable
names to indicate that they have been broken into groups of bits
ratherthanaregisterofsinglebits.Aregisternamethathastheletter
Nappendedissplitintotwo8-bitfieldsnamedCOLUMNS andROWS.
Those with a letter B appended are split into four fields named
HICOLS,LOCOLS,HIROWSandLOROWS.Therefore,thecommand
KPCRN.LOROWS=0xf;
willcausetheleastsignificantbitsoftheROWSfieldinKPCRtobe
setto1.
Thecommentsaboveexplainthevariousactionsthattakeplace
intheinitializationroutine.TheKeyPadDataRegister,KPDR,isa
registerthatconnectstotheexternalkeyboardinterface.Themost
significant8bitsaretoconnecttocolumnsandtheleastsignificant
bits connect to the rows. The plan is to detect cross connections
betweenacolumnandarow.Thecolumnsserveasoutputsandthe
rowsinputs.Therefore,thecolumnswillbesetasopendrainandas
outputsthroughthedatadirectionregister.IntheKBSR,KeyBoard
Status Register, the Key Pad Key Depressed bit, KPKR, is set
whenever the system detects a depressed key. This bit is reset by
writing a 1 to it. On both key depress and key release, there is a
synchronizerthataimstohideanykeybouncethatmightoccur.The
keydepresssynchronizerisclearedbywritinga1toKPSR.KDSC.
434 Chapter8 MCORE, A RISC Machine
Nextthekeydepressinterruptisenabledandthekeyreleaseinterrupt
is disabled.The parameters passed to the initialization routine are
nowsavedinstaticexternalvariables.Theseparametersareusedin
theinterruptserviceroutine.
Thecolumnoutputsonthefourleastsignificantbitsareallsetto
zerosothatanykeydepressionwillcausethenormallyhighinputs
sensedbythekeyinputstobepulledlow.Thisactionwillinitiatethe
keydepresssynchronizeroperation.Approximatelyfourmilliseconds
later,iftheinputkeyhasthesamestate,akeydepressedinterrupt
willberequested.Thekeyreleaseoperatessimilarly.Aslongasa
keyremainsdepressed,nothinghappens.Whenthekeyisreleased,
the key release synchronizer initiates its action. If the key has the
same state after the synchronizer time-out, a key release interrupt
canberequested.Fortheseoperationstowork,thecolumnoutputs
mustallbeheldatzero.
It is most convenient to use both the key depress and the key
releaseinterruptsforthetaskathand.Eachtimeakeyisdepressed,
itisdetectedandthepositionofthekeyinthekeypadissavedina
buffer. Conditions to cause a key release interrupt are then set up.
Thencontrolisreturnedtotheinterruptedprogram.Whenthekeyis
released, a key release interrupt is requested, and in the interrupt
serviceroutine,akeydepressinterruptissetupsothatthenextkey
presswillbedetected.Eachtimeakeypositionisenteredintothe
buffer,thenextpositioninthebufferismarkedwitha0xff.
Ispeakofthekeyposition.Intheinterruptserviceroutinebelow,
it is first tested to determine if the interrupt was caused by a key
depress or a key release. If it is a key depress interrupt, control is
immediatelypassedtoaforloop.Withinthisloop,thecolumnsare
firstloadedwitha0xe,whichwillhavethethreehighestbitsinthe
column high and the least significant bit low. A test checks to
determineifallofthecolumnbitsarehigh.Ifnotthevalueofcolumn
isimpressedonKPDRB.COLUMNS.Thenexttestchecksthevalue
foundonKPDRB.ROWS.Ifthereisnobuttondepressedthatconnects
column 1 with any of the rows, the result will be 0xff.Therefore,
controlwillgotothenextcolumn.Ifthevaluefoundonrowsisnot
0xff,theleastsignificantfourbitswillindicatetherowinwhichthe
switchisdepressed.Then,therowandcolumndataiscombinedinto
asinglevaluethatisstoredinthedataarray.Thecolumncontains4
Keyboard
435
bits,asdoestherow.Thesebitsarepackedintoasingle8-bitvalue
bytheinstruction
c=*data++=(~(KPDRB.COLUMNS<<4|(KPDRB.ROWS&0xf)))&0xff;
Thecolumnvalueisshiftedleftbyfourbitsandtheresultisbitwise
ANDedwiththerowvalue.Thesevaluesaretheones-complement
ofthevalueswewant,sotheones-complementistaken.Thefinal
resultisANDedwithamaskof0xfftodeleteanybitsoutsideofthe
eightbitsneededforthefinalresult.Thisresultisstoredinthearray
backinthecallingprogram.Alsoatthistime,theresultisstoredina
localvariableforlateruse.Thecountofthenumberofcharacters
enteredintothearrayareincremented.Ifthisvalueexceedsthelength
ofthearray,thereisanerrorandtheinputiscompletelyterminated
whentheprogramisrestartedatitsverybeginning.
#defineCOL_00x0e
/*keyboardinterruptserviceroutine*/
voidkb_isr(void)
{
UHWORDcolumn,input;
staticBYTEc;
if(KPSR.KPKD) /*ifakeyhasbeendepressed*/
{
for(column=COL_0;column!=0xf;column=(column<<1|0x1)&0xf)
{
KPDRB.COLUMNS=column;
/*killsometime*/
if(KPDRB.ROWS!=0xff)
{
c=*data++=(~(KPDRB.COLUMNS<<4|
(KPDRB.ROWD&oxf)))&0xff;
if(++n>=leng) /*dataexceedthearray*/
{
puts(inputdataoverflow\n);
_start(); /*baderror,restartthe
program*/
}
}
}
*data=0xff;/*neededtoterminatedecode*/
if(c==0x11)/*=reachedtheendoftheinput*/
436 Chapter8 MCORE, A RISC Machine
{
decode(savedata);
release_semaphore(semaph);
}
KPDRB.COLUMNS=0X0;/*write0toKPDR[15:8]*/
KPSR.KDIE=OFF;/*disablekeydepressinterrupt*/
KPSR.KRIE=ON; /*enablekeyreleaseinterrupt*/
}
else /*keyreleasewasdetected*/
{
KPSR.KPKR=ON;
KPSR.KPKD=ON; /*clearkeyreleaseanddepress*/
KPSR.KRSS=ON; /*setkeyreleasesynchronizer*/
KPSR.KDSC=ON; /*clearkeydepresssynchronizer*/
KPDRB.COLUMNS=0X0;/*write0toKPDR[15:8]*/
KPSR.KDIE=ON; /*enablekeydepressinterrupt*/
KPSR.KRIE=OFF;/*disablekeyreleaseinterrupt*/
}
}
Noticeinthecodeabovethatafterthecolumnsvalueissetand
before the row values are tested, there is a comment to kill some
time. It turns out that some time is required to allow propagation
fromthecommandtotheelectricalconnectionontheexternalswitch.
Thedelay()routinewithanargumentof1,a1-msdelay,worked
well, but this routine also uses the PIT. It is intended to use this
routine with the clock shown in the earlier section, so it is very
inconvenient to use the clock. Therefore, a series of instructions
aroundthekeyboardcontrollerwereputtogetherthatwoulduseup
thenecessarytime.Theseinstructionswouldhavetobeexecutedto
setupcorrectconditionspriortothereturnfrominterrupt,soitisnot
toomuchawasteofcomputerresources.Togetenoughdelay,Iused
some of these instructions more than one time. The code for this
timedelayisshownbelow.Thelastsixlinesofcodearerequiredto
setupfortheexitfromtheisr,andthefirstfourareduplicatesneeded
toroundoutthetime.
KPSR.KRSS=ON;
KPSR.KPKD=ON; /*flipandflopsomeinnocuousbits*/
KPSR.KDIE=OFF; /*justtokilltimetosynchronize*/
KPSR.KRIE=OFF; /*thecommandwithdataarrivalat*/
KPSR.KPKR=ON; /*thechipsedge*/
KPSR.KPKD=ON;
KPSR.KRSS=ON;
Keyboard
437
KPSR.KDSC=ON;
KPSR.KDIE=OFF;
KPSR.KRIE=OFF;
Afterthekeypositionisdetected,anditsvaluestoredinthearray,
thevalue0xffisplacedinthenextlocationinthearray.Thisvalueis
usedinthedecoderoutinethatchangesthekeypositionstoASCII
charactersfordisplay.Aterminationcharacterisneededtoshowthe
endoftheinputdatahasbeenreached.Thereisan=,equalsignon
thekeyboard,anditwasdecidedtouseitastheterminationcharacter.
Wewillseelaterthatthepositionvalueforthe=symbolis0x11.
Therefore,ifthevaluecis0x11atthispointinthecodeflow,itis
timetodecodethebuffercontentsandproceedfurther.Afterthedata
aredecoded,thesemaphoreisreleasedandcontrolisreturnedtothe
interruptedprogram.TheCOLUMNSbitsareallsettozero,thekey
depressinterruptisdisabledandthekeyreleaseinterruptisenabled
priortothereturn.
Itturnsoutthatitisnexttoimpossibletogetyourfingeroffa
key soon enough to allow this code to work without detecting the
key release. The key release interrupt is set up in the key depress
interruptserviceroutine.Themainoperationthattakesplaceinthe
keyreleaseisristodisablethekeyreleaseinterruptandsetupfor
akeydepressinterrupt.Withoutthisapproach,eachtimethekeyis
depressed,itwillgetthroughtheisrseveraltimesbeforethekeyis
releasedandthebufferwillbefilledwithduplicatevalueseachtime
theisrisexecuted.Thelastsevenlinesofcodeintheisrabove
areexecutedinthekeyreleaseisr.
Thedecodefunctionconvertsavaluethatrepresentstheposition
ofthedepressedkeyonthekeyboardtoanASCIIrepresentationof
thecharacter.Thepositiondataisan8-bitunitwiththeupper4bits
representingthecolumnandthelower4representingtherow.Only
onecolumnorrowbitshouldbeenabledatatime.Morethanone
roworcolumnisenabledifmultiplekeyshavebeendepressed.The
acceptablerowandcolumnvaluesare1,2,4,and8.Thecircuitry
fixestherowvalueof1correspondingtothebottomrowwiththe
value8asthetoprow.Also,theright-mostcolumncorrespondsto
column 1 and the left-most column corresponds to column 8.The
innerrowsandcolumnsfollowthepatternestablishedabove.Alook
atthekeyboardhasthetoprow,readfromlefttoright,containing
438 Chapter8 MCORE, A RISC Machine
+,7,8,and9.Thenextrowcontains-,4,5,and6.The
thirdrowfromthetopcontains*,1,2,and3.Thebottomrow
/,0,.,and=.Rememberthattheright-mostcolumniscolumn
1inthepositionandthebottom-mostrowisrow1.Therefore,one
canbuildamatrixasshownbelowthatconvertsthepositionofthe
keytoitsASCIIvalue.Nowthepositionsmustbeindicesintoatwo-
dimensionalarrayratherthanthepositionvalues.Thedecoderoutine
mustconvertthepositionvaluestoindices.
The decode routine works on an array that contains several key
positions.Thisdataarrayisterminatedwithacharacter0xff.Thestring
ispassedasapointertothebeginningofthestring.Inthefunction,the
valueofthepointeriscopiedtoanotherpointertoatypeBYTEthatis
usedintheprogram.Awhileloopisenteredwhichwillwalkthe
lengthofthearraythatcontainsallofthekeypositiondata.Thisloop
isterminatedwhenthedata0xffisfoundintheinputarray.Eachpiece
ofinputdataisnowsplitintotwoparts,therowsandthecolumns,and
aswitch/casestatementisusedtoconvertthe1,2,4,8valuesthatthe
inputdatacontainsintothe0,1,2,3valuesusedforindicesintothe
two-dimensional array. In the event of a multiple key hit, a default
value of 4 is passed to either the row or column. These values are
testedfor,priortoaccesstothekeys[][]array.Ifa4isfoundin
either case, the decode loop is skipped to the next character. This
approachdoesnotpreventerrorsindecoding,butitdoeskeepcontrol
andallowstheproceduretoberestarted.
staticconstBYTEkeys[][4]= {{=,.,0',/},
{3,2',1',*},
{6,5',4',-},
{9,8',7',+}};
/*thekeypositiondecoderoutine*/
staticvoiddecode(BYTE*s)
{
intr,c;
BYTE*p=s;
while(*p!=0xff)
{
switch(*p&0xf)
{
case8: r=0;
Keyboard 439
break;
case4: r=1;
break;
case2: r=2;
break;
case1: r=3;
break;
default:r=4;
}
switch(*p&0xf0)
{
case0x10: c=0;
break;
case0x20: c=1;
break;
case0x40: c=2;
break;
case0x80: c=3;
break;
default: c=4;
}
if(r==4||c==4)
break; /*gotamultiplekeyhit,skipit*/
*p++=keys[r][c];
}
*p=\0';
data=savedata;
}
Lastly,afterthecharacterisreadfromthearrayandstoredinto
thearray,theloopiscontinued.Whentheloopisterminated,anull
characteriswrittentothenextentryinthearray.Thischaracterisa
stringterminatorandthedatacanbeusedassuchwithanyofthe
input/output functions. In the initialization routine, two values of
pointerstothearraya[]weresaved.Thevaluesavedindatahas
beencorruptedbynowanditisnecessarytorestoreittoitsoriginal
valuebyassigningsavedatatodata.
Next, we have to test the code above. The following program
tests the keyboard initialization and isr routines. To use these
routines,youmustfirstadjustthecodeintheprogramhandler()
andrecompileit.Thiscodemustbelinkedtothefollowingprogram.
Theaddressoftheroutinekb_isr()mustbeplacedinthespecified
location in the vector table found with the handler() function.
440 Chapter8 MCORE, A RISC Machine
This location is entry number 6 in the vector table. The main()
function is broken into two sections, the initialization, and the
applications section. In initialization, inituart() establishes
connection with the serial I/O functions. The function
attach_semaphore(a)connectsasemaphoretothisprocess.
Thissemaphoreispassedtothekpinit()functionalongwitha
pointer to the beginning of the array a[] and also its length.The
addressoftheinterrupthandlerisplacedintotheautovectorlocation
bythevector()functioncall,andfinallythefastinterruptsare
enabledwhenEnable_Fast_Interrupts()isexecuted.
Inthemain()applicationloop,theprogramwaitsfortherelease
of the semaphore sem that was attached earlier.At this time, the
keyboardhandlerhascollectedabufferofdataandhasdetectedthe
input of an =.Also, the decode has been completed so that it is
possibletoexecuteputs(a)tosendthecontentsofthebufferto
theserialport.Afterthedataarewrittentotheoutput,tocontinue
operation,itisnecessarytoreattachtheoriginalsemaphoreifitis
available and proceed. This particular program will remain in the
innerloopforeverreadinginputsfromthekeyboardandoutputting
themtotheserialportwheneveran= buttonisdepressed.
Usually at this point, a single listing of the whole program is
includedinthetext.Itisaduplicateofthevarioussmallersegments
shownabove.HereIwillrefertotheprogramlistingthatiscontained
on the CD-ROM. It can be found under the directory chapter8
andhasthenamekbinit.c.
IntegratingKeyboardandClock
Thenextpieceofcodewillintegratethekeyboardwiththeclock
developedearlier.Thepurposeofthisprogramistoshowtheeaseof
integratingthesetwoprogramsandtheuseofmorethanoneinterrupt
simultaneouslywiththeinterrupthandlerdevelopedearlier.Themain
changeintheclockprogramwillbetoalterthereset_time()
function.Thisnewfunctionwillreceiveinputsfromthekeypad.The
codedevelopedintheprevioussectioncanbeused,butitwillhave
tobealteredsignificantlytobeofuseinthisprogram.Here,wewill
want to set up the keyboard input to interrupt when any key is
depressedandsendaflagtotheexecutingprogramwhenoneortwo
appropriatekeyshavebeendepressed.Letusincreasetheminutes
IntegratingKeyboardandClock
441
whenthe1buttonisdepressedandthehoursincreasewhenthe2
button is depressed. The program will need the interrupt service
routine, but the recording of the data into a buffer and all of the
attendantdecodingisunnecessaryhere.Wewilluseasingleglobal
variabletosetwhenacorrectkeyisdepressed.Thatisallrequired
forthisapplication.
Letsstartwiththeinitializationroutine.Thisinitializationroutine
needstodoevenlessthanwasneededearlier.Considerthecode:
/*keyboardinitializationroutine*/
voidkpinit(void)
{
KPCRN.LOROWS=0xf; /*enablekeypadrows*/
KPDRB.COLUMNS=0x0; /*write0toKPDR[15:8]*/
KPCRN.LOCOLS=0xf; /*makecolsopendrain*/
KDDRN.LOCOLS=0xf; /*makecolsoutputs*/
KDDRN.LOROWS=0x0; /*androwsinputs*/
KPSR.KPKD=ON; /*clearKPKDstatusflag*/
KPSR.KDSC=ON; /*clearkeydepresssynchronizer*/
KPSR.KDIE=ON; /*setKDIEbittoenabledepress
Interrupt*/
KPSR.KRIE=OFF; /*disablereleaseinterrupt*/
FIER.EF6=ON; /*enableFastInterruptnumber6*/
}
Themainchangeobservedisthatnoparametersarepassedtothe
initialization function and none of the variables saved earlier are
needed here. Otherwise, this function is identical to the earlier
kpinit()function.
The changes made in kb_isr() are instructive. There is no
substantivechangeinthefunctionuntilafterthedepressedkeyhas
beendetected.Forthisprogram,weareinterestedonlyinthedetection
ofa1ora2.Thesedigitscorrespondtothepositionvalues0x42
and0x22respectively.Afterthekeyhasbeendetected,asimplecase
statementconvertsthesespecificvaluestotheproperdigits.Ifthe
position numbers are not one of the expected values, *data is
assignedavalueofzero.Thisvalueisusedbythemain()program
todeterminewhenakeyhasbeendepressed.
/*keyboardinterruptserviceroutine*/
voidkb_isr(void)
{
UHWORDcolumn,input;
442 Chapter8 MCORE, A RISC Machine
staticBYTEc;
if(KPSR.KPKD) /*ifakeyhasbeendepressed*/
{
for(column=COL_0;column!=0xf;column=(column<<1|0x1)& 0xf)
{
KPDRB.COLUMNS=column;
/*killsometimehere*/
if(KPDRB.ROWS!=0xff)
{
c=(~(KPDRB.COLUMNS<<4|
(KPDRB.ROWS&0xf)))&0xff;
}
}
if(c==0x22)
*data=2';
elseif(c==0x42)
*data=1';
else
*data=0;
c=0;
KPDRB.COLUMNS=0X0;/*write0toKPDR[15:8]*/
KPSR.KDIE=OFF; /*disablekeydepressinterrupt*/
KPSR.KRIE=ON; /*enablekeyreleaseinterrupt*/
}
else /*keyreleasewasdetected*/
{
KPSR.KPKR=ON;
KPSR.KPKD=ON; /*clearkeyreleaseanddepress*/
KPSR.KRSS=ON; /*setkeyreleasesynchronizer*/
KPSR.KDSC=ON; /*clearkeydepresssynchronizer*/
KPDRB.COLUMNS=0X0;/*write0toKPDR[15:8]*/
KPSR.KDIE=ON; /*enablekeydepressinterrupt*/
KPSR.KRIE=OFF; /*disablekeyreleaseinterrupt*/
}
}
Thecodeexecutedbytheisrwhenakeyisreleasedisunchanged
fromearlier.
AddingaDisplay
AccesstotheLCDportisthroughamemory-mappedregister.
Thisregistercontainstwobyte-widefields,onecalledCOMMAND
AddingaDisplay
443
and the other DATA. This register is at address 0x2c3ffff0. The
followingtypedefand#definemakesthislocationavailableto
theprogram.
typedefstruct{
BYTECOMMAND :8;
BYTEDATA :8;
}Lcddrv;
#defineLCDDRV(*(Lcddrv*)(0X2C3FFFF0))
AccesstothismemoryareaisthroughChipSelectnumber3.This
ChipSelectmustbesetupandenabled.Thefollowinginitialization
functionallowsaccesstotheabovememoryaddress.Thechipselect
controlregistersarenotsettoaspecifiedvalueatreset.Itisbestto
putaspecifiedvalueintothisregister,0,andthensetthenecessary
bits.Thefirsttwolinesofcodeinthefollowingfunctionputazero
intotheaddressCS3CR.Thefieldsinthechipselectcontrolregister
allowsinsertionofwaitstatesfrom0to15.Fifteenwasusedhere
becausethememorylocationisrarelyaccessed;whenaccessed,it
deals with the outside world, and the long wait state will not
appreciablydegradethecomputerperformance.Anextradeadcycle
isaddedwhenthereisawritetothisaddress.Theaccessistoa16-
bitport.Thelastinstructionenablesthechipselectnumber3.
/*setupmemorytoaccesstheLCD*/
voidinitperip(void)
{
UWORD*CS3CRX=(UWORD*)&CS3CR;
*CS3CRX=0; /*zerothewholeregister*/
CS3CR.WSC=3; /*3waitstates*/
CS3CR.EDC=ON; /*extradeadcycleonwrite*/
CS3CR.EBC=ON; /*enablebytewriteaccessonly*/
CS3CR.DSZ=2; /*16bitport*/
CS3CR.CSEN=ON; /*chipselectenabled*/
}
Therearetwooutputfunctionsthatareuseful.Thesefunctionsare:
/*RoutinesfortheLCDDisplay*/
/*sendacommandtotheLCD*/
voidLCDCommand(BYTEcommand)
444 Chapter8 MCORE, A RISC Machine
{
LCDDRV.COMMAND=command;
delay(25);
}
/*senddatatotheLCD*/
voidLCDData(BYTEdata)
{
if(data==\r)
LCDDRV.DATA=0X01;
else
LCDDRV.DATA=data;
delay(25);
}
Thesefunctionsdoessentiallythesamething.Themaindifference
isthattheCommandfunctionwritestotheupperbyteofthespecified
addressandtheDatafunctionwritestothelowerbyteofthisaddress.
OneotherspecialoperationhasbeenputintotheDatafunction.If
thedatastringcontainsa\rcharacter,itisintendedthatthecursor
shouldbereturnedtothebeginningoftheline.The0x01command
doesjustthat.Otherwise,thedatareceivedissenttothescreenfor
display.Itisrecommendedthata25-msdelaybeexecutedaftereach
writetotheLCDsystem.Thisdelayisincludedinbothoftheabove
functions.
A sequence of events is needed to bring the LCD display into
operation. The code below first executes the initialization routine
abovesothattheLCDdisplayisconnectedtothecomputer.There
immediatelyfollowsarepeatedexecutionoftheLCDcommand0x03
threetimes.TheseinstructionspreparetheLCDdisplayforoperation.
There follows a series of commands: set the display for 2 by 40
characterdisplay,turnthedisplayoff,clearthedisplayandmovethe
cursortothehomeposition,automaticallyincrementcursorposition
aftereachwrite,turnthedisplayandcursoron,andfinallyshiftthe
cursorrightaftereachinput.Thesecommandsareallexecutedby
thefollowingcode.
/*initializetheLCD*/
InitLCD()
{
inti;
initperip(); /*initializememoryblock*/
for(i=0;i<3;i++)
AddingaDisplay
445
LCDCommand(0x03);/*getthingsturnedon*/
LCDCommand(0x3c);/*2x40display*/
LCDCommand(0x08);/*displayoff*/
LCDCommand(0x01);/*cleardisplayandhomecursor*/
LCDCommand(0x06);/*incrementcursorposition*/
LCDCommand(0x0f);/*Displayandcursoron*/
LCDCommand(0x14);/*Shiftcursorright*/
}
ThefunctionLCDData()shownaboveperformstheessential
operationoftheputchar()thatwehaveusedsooftenabove.In
ourprogramabove,weusedputchar()everywhere.Itseemsthat
weshouldhaveaseparatecommandfortheLCDdisplay,butatthe
sametime,itwouldbedesirablethatwecouldwritetotheLCDwith
a putchar() and not have to worry about changing all of the
occurrencesofputchar()intheearliercode.Awayaroundthis
problemistouseasimplemacro
#defineputchar(a)LCDData(a)
andnowwecanuseputchar()inplaceofLCDData().Ofcourse,
itisimportantthatwedonotlinkserial1.ototheprogram,and
theinclusionofserial.hisnolongerneeded.
Oneitemthatmustbeconsideredhereistheuseofthefunction
delay().Recallthatdelay() usesthepittoclockthedelaytime.
ThefunctioninListing8-1turnsthepitonatthebeginningofthe
operationandoffattheend.Wecannotallowthisfunctiontoturn
thepitoffbecausethepitisbeingusedbythebasicclockfunction.
Therefore,thetwolinesofcode
ITCSR.EN=ON;
.
.
.
ITCSR.EN=OFF;
mustberemovedfromthedelayroutine.Thefunctionnowwillwork
correctly,anditwillnotinterferewiththeoperationofthebasicpit
operationusedbytheclock.Thismodifiedfunctionisdelay2.c
ontheCD-ROM.
Usually,acompletelistingoftheprogramisincludedinearlier
chaptersofthistext.Inthiscase,thecodeisapproximately250lines
long,anditisnotsoimportanttoseethisamountofcode.Itisall
446 Chapter8 MCORE, A RISC Machine
shown above in bits and pieces. The complete listing is found in
newclock.cfoundontheCD-ROMintheChapter8directory.
Summary
Thedevelopmentsinthischaptershowanincrementalapproach
to producing a program. The whole project was understood at the
beginningofthechapter,butratherthantrytodevelopthewholeproject,
aseriesofsmalltasksweredevelopedandtested.Thecomplexityof
eachoftheseindividualtaskswasminimal.Often,thecoderequired
foreachportionwasbutadozenorsolineslong.Suchanapproachis
often the best approach to the development of complex code. This
approachisnotmineithasbeenaroundaslongasIcanremember.
Withanynewproject,youshouldanalyzethewholeprojectand
startthedevelopmentbybreakingtheprojectintotasks.Then,break
intosubtasksandrepeattheprocessuntilthetasksaresosimplethat
the code to implement them is trivial. Then step back a level and
repeattheprocess,makingcertainthatthecodeimplementationisas
simpleaspossibleatalltimes.Asthiscodeisintegrated,eachmodule
shouldbecompiledandtested.Therefore,yourprogramwillbebuilt
oftestedmodules.Neverattempttowriteabigblockofcodewithout
firsttestingthevarioussmallblocksthatcomprisethewholeprogram.
Index
!=,notequaloperator,17,26
#,preprocessorcommandidentifier, 2
#asm,152
#define,16,431
#endasm, 152
#pragma,115,349,418
%,modulooperator,24
%d,integerformat,5,7
&&,andoperator,26
&,address-ofoperator,65
*,multiplicationoperator,24,66
-,subtractionoperator,24
/,divisionoperator,24
@far,295
@port, 295
\?,escapesequenceforquestionmark,15
\\,escapesequenceforbackslash,15
\,escapesequenceforsinglequote,15
\,escapesequencefordoublequote,15
\a,escapesequenceforbellcharacter,15
\b,escapesequenceforbackspace,15
\f,escapesequenceforformfeed,15
\n,escapesequencefornewline,2,15,409,411
\ooo,escapesequenceforoctalnumber,15
\r,escapesequenceforcarriagereturn,15,409,
411
\t,escapesequenceforhorizontaltab,6,15
\v,escapesequenceforverticaltab,15
\xxx,escapesequenceforhexadecimalnumber,
15
{, block or compound statement beginning in-
dicator,2
||,oroperator,26
},terminatorofcompoundstatement,3
,filenamedelimiter,2
+,additionoperator,24
<,lessthanoperator,26
<=,lessthanorequaltooperator,26
==,equalityoperator,26
>,greaterthanoperator,26
>=,greaterthanorequaltooperator,26
15-bittimer,130,166
16-bittimer,130,166,178-181,
programming, 186-195
A
abs(x),56
accessingfiles,110
acos(x),117
ADC,132-133
analog-to-digital converter (ADC), 132-133,
195-201, 288
AND,26
ANSIstandard,294
argument, function, 51
arithmeticlogicunit(ALU),124
arithmetic operators, 24-25
arithmetic shift, 29
arrayboundarychecking,19,74
arrayindex,19
array initialization, 80
array, 18-19
array, multidimensional, 80-87
ASCIIcharacters,352
asin(x),117
assemblycodescallablebyC6805,150
assemblylanguageforMC68HC12,388
assembly language for MC68HC16, 328-332,
338,345
assembly language, 152
assignment operators, 32
association, 7
447
C
448 Index
associativityofoperators,34-35
asynchronoustimeservice,251
asynchronous, 126
atan(x), 117
atan2(x,y), 117
auto,9
automatic variables, 12-13
autovector interrupt handler, 416-417
autovector, 414
Axiomdemonstrationboard,394
B
backgrounddebugmode,147
BAUDregister,276
BCDencoding,207-209,352
binaryoperator,26
binarytreesort,95
binarytree,238
bitfield,107,108-109
bit manipulations, 108
bitwiseAND,28
bitwiseoperator,28
bootFLASHmemory,348
boundarychecks,74
breakkeyword,9,48
bubblesort,74
C6805compiler,150,295
calloc, 115
casekeyword,9
castoperator,28,114
char,9,15
character constants, 15-18
charactertests,117
chip-specific routines, 431
circular convolution program, 341
clearinterruptflagroutine,426
CLIinstruction,174
clockprogramforMMC2001,419,429-431
clock, 297
codingtips,137-148
comments, 17
compilers,52,63,150,221-230,305-318,386,
393,414
compound statement, 3
computer operating properly (COP), 131, 167,
219
concatenation, 74
conditional expression, 33
constkeyword,9-10
constant, 8-11
continuekeyword,9,48
controllingDCmotor,254
conversion commands, 112
convolution,332,334,341
cos(x),117
Cosmiccompiler,221-230,285,293,295,305-
318,335,349,386
counterregister,184
CPU16coreprocessor,288,289-296
D
data compression, 237-245
datastoragememory,159
datefunction,81,119
DCmotorcontrol,255-275
debouncing, 255, 275
debugging programs with user-specified inter-
rupts,294
declaration statement, 4
decrement operators, 30-32
defaultkeyword, 9
deference operator, 66
definition statement, 4
delayroutineforMMC2001,395-397,401,436,
446
development boards, 136
development environment for microcontroller
programming, 134-137
Diabcompiler,393,414
diagnostics, 119
digitalinput/output, 131
digitalsignalprocessor,287
digital-to-analog converter (DAC), 209
DiracDeltafunction,335
display,LCD,443-446
dokeyword,9
Index 449
do/while construct, 39-42
Do_interrupt(),417-418
dotproduct,332
doublekeyword,9,28
DSPoperationswithmicrocontrollers,326-345
M68HC16and,326-345
DSPregistermodel,327
dynamic debounce, 275
dynamic memory allocation, 101
E
EBDI,394
EEPROM,128,153,155,159
Programming, 159
EKregister,290
elsekeyword,9
enum,9,20-22
erasable programmable read-only memory
(EPROM),127,153-154
escapesequence,15
exception vector table, 290-291
exceptions, 125
exclusiveOR,28
exit,60
expandedbus,155
expression, 24-34
ExtendedBackgroundDebugInterface,394
externkeyword,9,15
externalstaticvariable,13-14,58
F
factorial, 62
fastinterruptenableregister(FIER),414
FFIinstructionforMMC2001,414
fgets,111,413
Fibonaccinumber,62,77
FIERregister,426
filter, 332
FIPNDinterruptpendingregister,414
flags,113
FLASHmemory,128,153
floatkeyword,9
floatingpointvariabletype,4,11
forkeyword,9
forloop,38-39
FOREVERloop,174,427
formatting, 113
Fouriertransform,333
fp,110
fputs,111
fractions, handling, 25
free(),115
function argument, 51
functionprototype,52,432
functions,8,51-61
G
generalpurposetimermodule(GPT),288,314
generalpurposetimer,129
genericpointer,69
getstringfunctions,413
getce()function,411
getch function, 413
getchar,17,382-383,409,413
getsfunction,72,413
getse function, 413
gotokeyword,9,48
greaterthantestvs.isequaltotest,423
H
handlinginterruptsonMMC2001,413-419
Harvard architecture, 124
HC11E9.Hheaderfile,258
hc16.hheaderfile,290
headerfiles,116,171,211-221
hexadecimal numbers, 11
Hoare, C.A.R., 231
Huffmancode,237-244,350,356,361-368
I
IARBfield,302
ifkeyword,9
if/else, 42-44
if-elseifsequence,44-48
450 Index
include, 2
inclusiveOR,28
increment operators, 30-32
indexregisters,290
index,ofarray,19
initialization section of program, 188
inituart()function,409
inputcapture,130,185
MC68HC11family,253
input/output, 110, 129-134, 382-386
memory-mapped, 129
int,2,9,11
integervariabletype,3
integratingkeyboardandclock,440-443
inter-modualbus(IMB),288
interrupt controller, 414, 419
interruptflagclearroutine,426
interrupt handler routine for MMC2001, 415-
417,425
interruptpendingregister,414
interrupt request, 125
interrupt service routine, 125, 252, 294, 415,
425-426
interruptsourceregister(INTSCR),414
interruptvectors,290
interrupts, processing, 220, 301-302
forMMC2001,413-419
IRQ,125
isalnum(c), 117
isalpha(c), 117
iscntrl(c), 117
isdigit(c), 117
isgraph(c), 117
islower(c), 117
isprint(c), 117
ispunct(c), 117
ISR,125,220
isr_function, 418
isspace(c), 117
isupper(c), 117
isxdigit(c), 117
ITADR,395,402,420,425
ITDR,395,402,420,425
ITIEflag,426
ITIFflag,426
J
jsrR2instruction,418
K
kbhit()function,411
KBSRregister,432
KDDRregister,432
keep,14
keydepresssynchronizer,434
keyreleaseinterrupt,434
keyboardinterfaceforMMC2001chip,432-440
keywordsinC,9
KPCRregister,432
KPDRregister,432
KPKRregister,432
KronikerDeltafunction,333
L
label, 48
lastin,firstout(LIFO),59
LCDdisplayroutines,445
leftshiftoperator,29
letteranalysisprogram,359
libraryfunctions,80,116,223
libserio.aarchivelibraryfile,413
localstaticvariables,13
log(x),118
log10(x), 118
logic analyzer, 137
logicalAND,26
logical operator, 26
logicalOR,26
logicalshift,29
long,9-10,28
longjmp function, 49
look-uptablewithslopes,320-322
loopingconstruct,6
eliminating, 325
lvalue,69,85
Index 451
M
M68HC08,149
MACmultiplierinputregisters,326
macrodefinition,56,60,102
main(),1,2,3,51,427
malloc,12,101-102,114
maskedROM,127,153
mathfunctions,117
MC68300, 288
MC68HC05 microcontroller, 142, 149
MC68HC05EVM, 152
MC68HC05EVS, 142
MC68HC11/12,149,211-286,347-391
MC68HC16,149,287-296
MC68HC16EVB, 146
MCORE architecture, 131, 393-446
memory models,336
memoryallocation,4,10
memory management, 114-116, 156
memorytypes,153
memory-mapped I/O, 129
microcomputer, 123
microprocessor, 123
MIXcompiler,386
MMC2001 microcontroller, 393
macrosfor,400
mmc2001.hheader,400,407
mnemonics, 140, 422
modular arithmetic, 334
modular program development, 347-349, 391
monitor routine, 370-376
motorcontrolroutines,255-275
multidimensional arrays, 82-83
N
names,8
nestedfunctions,52
nestedifstatements,422
Newtonloop,38
NIPNDinterruptpendingregister,414
noisespikes,219
noisyswitches,255
normalinterruptenableregister(NIER),414
nullpointer,76,98
null,19,60
Number-to-character conversion, 424
numeric encoding/decoding, 352-356
O
onetimeprogrammable,128
ones complement, 28
operators, 24-34
optimizing code, 325
OPTIONregister,159
OR,26
OTPchip,128,154
outputcompare,130-131,185,246-253
output_time function, 428
P
P&EMicrocomputerSystems,Inc.,146
pagezero,158
parameters,copiesof,52
periodic interrupt, 309-315
phonebookprogram,360
PIT(seealsoprogrammableintervaltimer),314-
315,395,402,419-420,425
pointers, 65-121
andfunctionarguments,70
arraynameas,69
assigning, 69
comparing, 68
incrementing/decrementing, 69
null,98
subtracting, 69
tofunctions,84
typevoidasappliedto,69
PORTA,85,109,132
portablecode,296,404
pragmadirectives(C6805compiler),151
pragma, 151
precedence,7,30,33,34-36
preprocessorcommand,2
print formatting, 113
printf,2,3,5,7,18,112
printing routine, 378-380
programcounter(PC),289
452 Index
programflowandcontrol,36-51
programmemory,159
programmable interval timer (PIT), 314-315,
395,402,419-420
programmable timer, 246-251
programming hierarchy, 347-348
prototype,function,52,432
PSRregister,400
pull(),60
pulse width modulation program for
MC68HC11, 245-251
pulse width modulation program for
MC68HC16, 297-302
pulse width modulator (PWM), 201-207, 247-
253,255,268
push(),60
put()function,409,411
putchar,111,382-383,411
putsfunction,382,384,413
Q
queued serial peripheral interface module
(QSPI),288
queuedserialmodule(QSM),305-308
quicksort,231
R
RAM,153
randomaccessmemory,153
readingdatafromthekeyboard,371
read-only memory, 127
realtimeinterrupt(RTI),168,176
realloc, 115
recursion,61-63,96,157
recursivecode,324
reedswitch,268
re-entrant function, 61
register,9,13
relational operator, 26-27
reset function, 381-382
resetsignal,125,169
resettimefunction,428
returnfrominterrupt,126
return,9
rfiinstruction,418
rightshiftoperator,29
RISCmicrocontrollers,324,393-446
ROM,127,153
RTI,168,176
RTS,176
rvalue,69
S
savingdatatoEEPROM,376-378
SCCR1/SCCR2, 276
semaphore,397-400,403,433
semicolon,useofinC,53
sequencepoint,11
serial communications control registers, 276
serial communications data register, 276
serialcommunicationsinterface(SCI),133
MC68HC11 family, 275-285
MC68HC16family,308
serial communications status register (SCSR),
276
serialI/O,133
withMMC2001,404-413
serialperipheralinterface(SPI),133
serialport,382
SETINCLUDE,2
setjmpfunction,49,119
Shell, D.L., 230
short,9-10
signals, 119
signed, 9-10
sin(x),117
sinh(x),117
sizeof,9,34,81
SoftwareDevelopmentSystems(SDS),393
softwarewatchdog,301
sort,74-76,230-237
bubble, 74
entry,230
quick,75,230-237
Shell,75,230-231,234,236,356
square,56
SRAM,288
Index 453
stackpointer(SP),289
stack,59
standardI/O,119
static variables, 13-15
static,9,58
stdio.hheader,2,3,17,52,116
stdlib.hheader,101
STOPinstruction,169
storageclasses,12-15
strcat(s,t), 117
strchr(s,c), 117
strcmp(s,t), 117
strcpy(s,t), 117
stringoperations,117
string,2,19
strlen,72
strncat(s,t,n), 117
strncmp(s,t,n), 117
strncpy(s,t,n), 117
strrchr(s,c), 117
structFILE,110
struct,9,20,23-24
structuretag,88
structures, 87-106
pointersto,88
self-referential, 95
types,92
switchbounce,255-258,268
switch,9,20,49-51
synchronous, 126
SYNCRregister,299
systemintegrationmodule(SIM),288,296-297
chipselects,298
externalbusinterface,297
generalpurposeI/O,298
interrupts, 298
reset and initialization, 298
systemclock,297
system configuration and protection mod-
ule,297
T
table look-up, 318-325
tag,88
talloc,97,102
tan(x),11
TCNT,246,254
TCR, 168-169
telephonebookfunction,348
terminal emulator, 145
testing philosophy, 348
testingusingevaluationboards,142
TFLG1/2registers,304
timeofday(TOD)clock,419
time-of-day(TOD)clock,131
timercontrolregister(TCR),181
timercounterregister,246
timerprocessorunit(TPU),130
timerstatusregister(TSR),182
timer subsystems, 129-131, 166-173, 245-288,
419
TOF,168
tolower(c), 117
toupper(c), 117
TPU,130
tracebuffer,136
typeconversions,27-28
type declaration, 9-12
type,9,52
typedef,9,93
U
UART,276
unaryoperators,25
uninitialized interrupts, 415
union,9,20,22-23,107-108
universal asynchronous receiver transmitter
(UART),276
unsigned, 9
utility functions, 118
V
variabletypes,4
variable, 8-10
vector assignment, 303
vector initialization routine, 293
vectortable,125,387-388
454 Index
void,3,9,53,86
volatile,9,11,227
VonNeumannarchitecture,124,129
W
waitroutine,409
WAIT,169
watchdogtimer,131,301,419
weightingfunctionsfordigitalfilters,333
while,9,17,36-38,72
EmbeddedTechnology Series
Programming Microcontrollers
inC,SecondEdition
byTedVanSickle
INCLUDESWINDOWS95/98CD-ROM.
Completelyupdatedneweditionofaclassic
forembeddedsystemsdesignersand
programmers.ItcoversCbasics,advancedC
topics,microcontrollerbasicsandusage,and
givesexamplecode,usingtheMotorolafamily
ofmicrocontrollers,includingRISCmachines.
TheCD-ROMcontainsthecodefromthe
book,afullsetofMotorolasmicrocontroller
documentationinPDFformat,andafully
searchableelectronicversionofthetext.
1-878707-57-4 $59.95
Embedded Controller
HardwareDesign
byKenArnold
INCLUDESWINDOWSCD-ROM.This
practicaltutorialintroducesthereadertothe
designofembeddedmicroprocessor-and
microcontroller-basedsystems.General
topicscoveredinthebookincludedevice
architecture,interfacing,timing,memory,I/O,
aswellasdesignanddevelopmenttech-
niques.Thebookpresentsthelatest
application-orientedinformationconcerning
thisrapidlychangingareaoftechnology.
1-878707-52-3 $49.95
ControllingtheWorldwith
YourPC
byPaulBergsman
INCLUDESPCDISK.Awealthofcircuits
andprogramsthatyoucanusetocontrolthe
realworld.Connecttotheparallelprinterport
ofyourPCandmonitorfluidlevels,control
steppermotors,turnappliancesonandoff,
andmuchmore.Theaccompanyingdiskfor
PCscontainsallthesoftwarefilesinready-to-
useform.Allschematicshavebeenfully
tested.Greatforembeddedsystems
engineers,aswellasstudentsandscientists.
1-878707-15-9 $35.00
CIRCUIT REFERENCES
Ourlistofcircuitreferencesanddesign
cookbookscontainsvaluableaidsfor
embeddeddesigners.
TheForrestMims
Engineers Notebook
byForrestMimsIII
Revisededitionofaclassicbyworldsbest-
selllingelectronicsauthor.Hundredsofuseful
circuitsbuiltfromICsandotherparts.
1-878707-03-5 $19.95
TheForrestMimsCircuit
Scrapbook,VolumesIandII
byForrestMimsIII
Moregreatesthitscircuitdesignsfrom
ForrestMims.VolumeIcontainsdigitalPLLs,
intervaltimers,lightwavecommunicators,and
muchmore.VolumeIIcontainscomparators,
dataloggers,laserdiodedevices,fiberoptic
sensors,powersupplies,andmuchmore.
Vol.I:1-878707-48-5 $19.95
Vol.II:1-878707-49-3$24.95
TheIntegratedCircuit
Hobbyists Handbook
byThomasR.Powers
Thiscomprehensivecookbookofcircuit
applicationsisconvenientlycross-indexedby
deviceandapplication.Containsamplifiers,
filters,bustransceiversandbusbuffersfor
digitalinterfacing,counters,comparators,FSK
modulatorsanddecoders,oscillators,and
muchmore.
1-878707-12-4 $19.95
Simple, Low-Cost
ElectronicsProjects
byFredBlechman
Containsawealthoffullytestedelectronics
designprojectsusingcommonlyavailable
parts,eachwithcircuittheory,partslists,and
designandtestingguidelines.
1-878707-46-9 $19.95
Visitourwebsiteformoregreattechnical
booksonallsubjects!
www.LLH-Publishing.com
[This is a blank page.]

You might also like