<<

PIC-MDS PIC Development System Training Manual Copyright © 1996, 1998 Sirius microSystems. All rights reserved.

Second Printing.

Parallax is a Trademark of Parallax, Inc. PICmicro™ is a Registered Trademark of Inc. in the U.S.A. and other countries.

No part of this publication may be reproduced, stored in a retrieval system, or transmitted, in any form or by any means, mechanical, electronic, photocopying, or recording, or otherwise, without the prior written permission of Sirius microSystems.

Sirius microSystems has taken care to trace ownership of copyright material contained in this text. However, Sirius microSystems will gladly accept any information that enables them to rectify any reference or credit in subsequent editions.

For conditions, permissions and other rights under this copyright, contact Sirius microSystems:

Sirius microSystems 172 Harvard Road Waterloo, ON N2J 3V3 Canada tel.: 519.886.4462 fax: 519.886.4253 http://www.siriusmicro.com

ISBN 0-9681220-0-0 (Training Manual) ISBN 0-9681220-1-9 (Teacher’s Reference)

Disclaimer of Liability This manual and the program included herein are written for the Sirius microSystems PICmicro™ Development System and are provided on an “as is” basis, without any warranty, either expressed or implied. These materials are provided for educational use only, and Sirius microSystems does not assume any liability for damages, either incidental or consequential, arising out of the application, use, or misuse of any of its software or hardware products. Sirius microSystems reserves the right, without further notice, to make changes to any of its training materials, software or hardware referred to in this manual in order to improve its function, design or reliability.

Printed in Canada. Table of Contents

1 What are ?...... 9 10Microcontroller Features ...... 10 Input/Output Ports ...... 10 Input Devices ...... 11 Output Devices ...... 12 Memory ...... 12 Clock Circuit ...... 15 Processing Unit ...... 15 Watch-Dog Timer ...... 15 Chapter Summary...... 16 Questions ...... 17 Assignments ...... 17

2 How do Microcontrollers Work? ...... 19 Processing Unit ...... 19 Memory ...... 20 The Outside World Connection ...... 20 How do Programs get into the Microcontroller? ...... 20 Chapter Summary...... 21 Questions ...... 22

3 The Microchip PIC family of Microcontrollers ...... 23 The PICmicro™ Product Range ...... 23 The 18-pin PIC16CXX Product Line ...... 24 The PIC16F84 ...... 25 Program EEPROM ...... 25 Data EEPROM ...... 25 RAM ...... 26 Input/Output Ports ...... 26 TMR0 ...... 26 (WDT) ...... 27 Power-Up Reset Timer (PWRT) ...... 27 Oscillator ...... 27 RAM Register Files ...... 28 STATUS ...... 28 PCL & PCLATH ...... 28 IND0 & FSR ...... 28 INTCON ...... 28 Option ...... 28 EEDATA & EEADR ...... 28 EECON1 & EECON2 ...... 28 The PIC16C711 ...... 29 Program EPROM ...... 29 Analog-to-Digital Converter ...... 29 Chapter Summary...... 30 Questions ...... 31 Assignment ...... 31

©1998 Sirius microSystems 3 4 Features of the PIC-MDS Development System ...33 Power Supply Circuit ...... 35 J1 ...... 35 VR1 ...... 35 JU1 ...... 35 JU2 ...... 36 External I/O Connectors ...... 36 CON1 ...... 36 PICBUS ...... 37 Microcontroller Related Circuits ...... 37 Microcontroller Socket ...... 37 H2 ...... 37 Reset Button ...... 38 Y1 ...... 38 JU3 ...... 38 JU6 ...... 39 VR3 & VR4 ...... 39 Matrix Keypad ...... 39 LED Output Indicator Bar Graph ...... 40 Intelligent LCD Display ...... 40 VR2 ...... 40 RS-232 ...... 40 JU5 ...... 40 H3 ...... 41 Serial EEPROM ...... 41 JU4 ...... 41 PIC-MDS Default Jumper Locations...... 41 Questions ...... 42

5 Writing a Simple Program ...... 43 Examining Source Code—Microchip Code ...... 44 Source Code Conventions ...... 45 Some Other Common Source Code Conventions ...... 46 Examining the Program ...... 47 The Maclib Directive ...... 47 The Device and ID Directives ...... 47 The ORG Directive ...... 47 Program Code ...... 48 Ending the Editing Process ...... 49 Chapter Summary...... 49 Questions ...... 50 Assignment ...... 50

6 Assembling a Program ...... 51 Assembling the Program ...... 51 Object Code ...... 54 Chapter Summary...... 54 Questions ...... 55 Assignment ...... 55

Table of Contents 4 ©1998 Sirius microSystems 7 Downloading a Program ...... 57 Which Microcontroller Should I Program? ...... 57 Programming ...... 57 Downloading the Object Code...... 59 Running the Program ...... 60 Reprogramming PIC Microcontrollers...... 60 Chapter Summary...... 60 Questions ...... 61 Assignment ...... 61

8 Looping ...... 63 Infinite loops...... 63 Finite Loops ...... 65 Nested Loops...... 66 Calculating Execution Times ...... 68 Chapter Summary...... 70 Questions ...... 71 Assignment ...... 72

9 Switch Input Programming ...... 73 Interfacing to Switches ...... 73 Counting Switch Activations ...... 76 Switch Debouncing ...... 78 Interfacing to Matrix Keypads ...... 80 Chapter Summary...... 84 Questions ...... 85 Assignment ...... 86

10 Calls and Includes...... 87 Include, CALL and RETURN ...... 87 Reading ROM Data Tables using Calls ...... 91 Chapter Summary...... 96 Questions ...... 97 Assignment ...... 98

11 ...... 99 Registers and Flags ...... 100 TMR0 Interrupt ...... 100 INT Interrupt ...... 101 Port B Change Interrupt...... 101 EEPROM Interrupt ...... 101 A/D Converter Interrupt ...... 102 Interrupt Service Routines ...... 102 Using Interrupts to Wake-up on Key Press ...... 103 Managing Multiple Tasks using the TMR0 Interrupt ...... 106 Chapter Summary...... 111 Questions ...... 112 Assignment ...... 112

©1998 Sirius microSystems 5 12 Using the LCD Display ...... 113 The LCD Interface ...... 113 LCD Enable ...... 115 LCD Register Select ...... 115 LCD Read/Write ...... 115 LCD Commands ...... 115 LCD Initialization ...... 116 LCD Display Addressing ...... 117 Absolute Addressing...... 118 Relative Addressing ...... 118 Displaying LCD Characters ...... 118 Creating Custom Characters ...... 125 CGRAM ...... 125 Chapter Summary...... 129 Questions ...... 130 Assignment ...... 130

13 Using the PIC16F84 Data EEPROM ...... 131 Using the PIC16F84 Data EEPROM .. 131Reading From and Writing To the Data EEPROM ...... 132 Chapter Summary...... 137 Questions ...... 138 Assignment ...... 138

14 Troubleshooting ...... 139 Identifying and Isolating Faults ...... 139 Validating Your Hardware ...... 139 I/O Requirements...... 139 Shared I/O Lines ...... 140 “Playing” the Computer ...... 140 Displaying Intermediate Values ...... 141 External Triggers...... 141 Commenting Out Code ...... 141 Isolating Faults within Subroutines ...... 142 Taking Breaks and New Approaches ...... 142 Memory Page Boundaries ...... 142 A/D Converter Troubleshooting ...... 144 Simulators and Emulators ...... 144 Programming for Easy Troubleshooting ...... 144 Plan, Plan, and Plan ...... 144 Code and Debug Individual Program Tasks ...... 144 Modularize Your Code ...... 145 Comments...... 145 Chapter Summary...... 145 Questions ...... 146 Assignment ...... 146

Table of Contents 6 ©1998 Sirius microSystems 15 RS-232 ...... 147 RS-232 Basics ...... 147 Receiving RS-232 Data ...... 149 Transmitting RS-232 Data ...... 154 Chapter Summary...... 158 Questions ...... 159 Assignment ...... 159

16 A/D Conversion ...... 161 The PIC16C711 A/D Converter ...... 161 ADCON0 Register ...... 162 ADCON1 Register ...... 163 Measuring Voltage using the A/D Converter ...... 163 Chapter Summary...... 170 Questions ...... 171 Assignment ...... 172

17 Interfacing to a Serial EEPROM ...... 173 The 93LC56 Serial EEPROM ...... 173 The Serial EEPROM Data Frame...... 174 Serial EEPROM Instructions...... 174 Using the SEEPROM...... 175 Chapter Summary...... 181 Questions ...... 182 Assignment ...... 182

18 The Watch Dog Timer ...... 183 Handling Software Faults using the WDT ...... 184 Enabling the WDT ...... 186 Waking the PIC using the WDT ...... 186 Chapter Summary...... 188 Questions ...... 189 Assignment ...... 189

Apendix A - PIC-MDS Installation and Setup ...... A1 PIC-MDS Professional Package...... A3 PIC-MDS Professional ...... A3 PIC-MDS Hobbyist Package...... A3 PIC-MDS Hobbyist ...... A3 PIC-MDS Requirements ...... A4 Windows 3.x and Windows 3.11 for Workgroups ...... A4 Windows 95 ...... A4 OS/2 Warp v.3 and OS/2 Warp Connect ...... A4 Installing the Software ...... A4 If you are using the PIC-MDS with the EPIC ...... A4 If you are using the PIC-MDS with a third-party programmer...... A5 PIC-MDS Setup ...... A5 Connecting the EPIC Programmer ...... A5 Connecting the PIC-MDS ...... A7 Assembling and Downloading Programs ...... A8

©1998 Sirius microSystems 7 Appendix B - Troubleshooting ...... B1 Troubleshooting ...... B3 Software Installation ...... B3 If the installation program does not work correctly: ...... B3 If the installed files are not in the volume or directory expected: .... B3 Assembling Programs with ASM ...... B3 If you get a “Bad Command or File Name” message: ...... B3 If you get a “Fatal : [302] Unable to Open File” message: ...... B4 “Error filename.SRC 1 : [202] Illegal Character” message: ...... B4 Starting the EPIC Programmer Software ...... B4 If you get a “Bad Command or File Name” message: ...... B4 If you get a “Programmer Not Found” message: ...... B4 If the object code of the file does not appear in the EPIC window: B5 Downloading Programs ...... B5 If you get a “Verify Error at ” message: ...... B5 Assembling, Downloading and Running Programs...... B5 If the PIC-MDS Chapter examples don’t work:...... B5 Converting PIC-MDS Source Code ...... B6 for Third-Party Tools ...... B6 If you use a third-party assembler: ...... B6

Appendix - PIC Macro Assembler Reference...... C1

Appendix D - Parallax Instruction Set Reference ...... D1

Program Pull-out References

Data Sheets

Table of Contents 8 ©1998 Sirius microSystems What are 1 Microcontrollers?

What are Microcontrollers?

A microcontroller is essentially an entirely self-con- tained computer on a chip. Like personal computers, microcontrollers have memory, processing units, and in- put/output circuitry. Unlike personal computers, micro- controllers don’t have keyboards, monitors, disk drives or mice—and programs are not loaded into microcon- trollers to change their function from playing games to calculating finances. In fact, microcontrollers are pro- grammed to perform only one very specific task. Mi- crocontrollers are computers designed to control spe- cific processes or products. Applications that use mi- crocontrollers include household appliances, electronic It’s hard to believe, yet this devices, automobile subsystems, electronic instrumen- single chip microcontroller tation, and even certain parts or functions of personal is a complete computer. computers.

Microcontrollers are small and inexpensive allowing them to be built into, or Microcontrollers are ‘embedded’ into, other devices to make these products more intelligent and easier to computers designed to use. One microcontroller can replace a number of separate parts, or even a complete control specific processes circuit. Product manufacturers stand to gain the following benefits by incorporating or products. a microcontroller in their design: • increased reliability due to one microcontroller replacing many parts • reduced inventory, simplified product assembly and smaller end products • greater product flexibility and adaptability since features are programmed into the microcontroller and not built into hardware • rapid product changes by changing the program and not the hardware

Microprocessors such as the Intel Pentium™ get more main-stream attention, but microcontroller manufacturers such as Microchip sell hundreds of microcontrol- lers for every sold. Chapter 1 ©1998 Sirius microSystems 9 Microcontrollers Microcontroller Features

Electronic designers Outside World have a great deal of choice when deciding on a micro- controller for their next Micro-Controller Input Output project. A large number of Block Diagram Circuitry Circuitry microcontroller families exist, with even greater variations within each fam- Permanent Temporary ily. Manufacturers tailor Memory Memory the features of each micro- controller or microcontrol- ler family to specific types of applications. It becomes Clock Processing Unit easy for a designer to Circuit choose just the features and memory size that are re- Timer quired for the application, Circuitry

keeping costs low by not block1 buying unneeded capabil- ity. Microcontrollers contain all of these functions on a simgle silicon chip. In general, all microcontrollers share some basic features. As a computer-on-a- chip, microcontrollers contain input circuitry to interface with their environment, a processing unit that executes the control program, permanent memory to hold the control program, temporary memory to hold operating variables, a clock circuit to orchestrate operations, a timing circuit (usually called a watchdog timer) for reliabil- ity, and output circuitry to interface to other devices or processes. Optional features might include specialized timing and pulse circuits, communication capability, ana- log input/output connections, or other inputs and outputs tailored to specific sensors or transducers. In the paragraphs that follow, we will compare each of the basic features of a microcontroller with those found in personal computers. We’ll do this by looking at two typical control applications: a microwave oven, and an automotive engine control computer.

Input/Output Ports

Most microcontrollers have built-in input/output (I/O) circuitry that makes it easy for input and output devices to be added to them. Their input ports have special UARTs—Universal Asyn- features such as counters, comparators, serial UARTs, or analog-to-digital convert- chronous Receiver Trans- ers. Microcontroller output ports can often supply higher current to output devices mitters—are used in serial than standard and ordinary logic circuitry. By adapting the communications. microcontroller’s I/O circuitry to special applications, the need for external circuitry is reduced, allowing a single microcontroller to take the place of many other compo- nents.

Personal computers normally use I/O cards to add the type of functionality that comes built into microcontrollers. For example, most microprocessors found in per- sonal computers have general purpose I/O circuitry and require a serial/parallel I/O Microcontroller Features PB ©1998 Sirius microSystems card to connect to modems, mice, printers and scanners. A SCSI or IDE interface card allows the microprocessor to connect to hard disks and CD-ROM drives. cards allow connections to networks. In a personal computer, the device or applica- tion determines the type of interface card required to a attach a peripheral to the general purpose microprocessor.

In the case of microcontrollers, the expected input and output devices and appli- cation determine the processor itself, since the processor incorporates all of the I/O circuitry. Often, microcontroller manufacturers produce different versions of the same basic microcontroller model by changing the type of I/O ports it includes.

It’s easier to under- stand this concept if we use a simple analogy. If a housing contractor is ready to buy a new vehi- cle for his (or her) busi- ness, a pick-up truck would be better able to carry lumber and bricks than a Ferrari. In micro- controller families, just as in real life, choose the de- vice to fit the purpose. Duh Homes went out of business shortly after young Harry took over while his father vacationed in the Carribean.

Input Devices

Personal computers have standardized input de- vices—you wouldn’t buy one without a keyboard or a Tachometer mouse. You might add a joystick or scanner to your com- puter. Since microcontrollers are embedded into so many Throttle Position products, their input devices reflect the function that the Sensor product performs. An engine control computer requires Exhaust very little in the way of input from the user, but still has Temperature Sensor many input sensors. These would include throttle posi- tion sensors, crankshaft position or speed sensors, oil and coolant temperature sensors, exhaust gas sensors and even wheel-speed sensors. The obvious input de- vice on a microwave oven would be the keypad on the front of the unit. The door switch of a microwave is an Micro-Controller Input Output equally important input device—just try (no, don’t try) Block Diagram Circuitry Circuitry cooking something with the door open! Some microwave ovens also include temperature probes or humidity sen- Permanent Temporary Memory Memory sors. It is the microcontroller’s job to know not only how to cook your food, but also when it is safe to cook Clock Processing Unit it, and when the food is done cooking. Circuit

Timer Circuitry

input2

Chapter 1 ©1998 Sirius microSystems 11 Microcontrollers Output Devices

The output of a per- Key Pad Time C sonal computer is usually L Power R displayed on a monitor, or

30 1 2 5 sec min min min 7 Segment Display can come from a speaker

10% 30% 50% 100% as sound, or can be in the The 7-segment display, form of a print-out. Micro- beeper and magnetron are 1 2 3 S T output devices specific to a Door 4 5 6 A controllers also connect to Switch R a variety of devices spe- microwave oven. 7 8 9 T Magnetron cific to the application. For 0 Stop example the front panel display on a microwave in- dicates the cooking time Beeper Micro-Controller Input Output and mode that was se- Block Diagram Circuitry Circuitry lected, but the microcon- troller also modulates the power of the magnetron Permanent Temporary Memory Memory used to cook your food. The engine control compu- ter outputs ignition spark timing, fuel injector duty Clock Processing Unit Circuit cycle, and cooling fan op- eration. A number of to- Timer tally different output de- Circuitry vices can be controlled by input3 one microcontroller.

Memory

Outside World Personal computers come with two types of memory: permanent memory and temporary memory. One type Hard Micro-Controller Input Output Block Diagram Circuitry Circuitry of permanent memory—the Basic Input/Output System, Disk or BIOS—is a read-only memory (ROM) that contains Permanent Temporary Memory Memory programs which tell the microprocessor how to interact with its peripheral devices, such as the monitor or key- board. Hard disks are another form of permanent stor- Clock Processing Unit Circuit age for application programs. The applications are cop- ROM RAM Timer ied from hard disk to temporary memory, or random- Circuitry BIOS block1 access memory (RAM). While the computer is turned on, the RAM contains one or more active programs. When the computer is turned off, the contents of RAM Processing Unit are erased, so all programs and data must be saved in mo1 permanent memory. Personal computers load Microcontrollers have both permanent and tempo- one or more application rary memory on-chip. As in personal computers, ROM programs stored on hard is the permanent memory that remembers its operating disk into RAM. The micro- programs while the device is off. Since microcontrollers processor then executes the have no hard disk storage, and usually only one operat- application programs from the computer’s RAM. I/O Devices and Memory PB ©1998 Sirius microSystems ing program, ROM is the only permanent memory they need. RAM is used only as a ‘scratch pad’ to hold tem- porary data and changing input or output variables. A Microcontrollers use ROM microwave might use RAM to store the current cook- to store their operating ing mode and the cooking time remaining. An engine Program program. A small amount ROM controller would use RAM to hold a digital value rep- of RAM is necessary to resenting the temperature, speed, or position of all of hold variables and chang- ing data. the inputs. The ROM in both the microwave oven and RAM the engine control computer holds the control program that makes them work.

Even though both personal computers and micro- Processing Unit controllers use the same types of memory for similar M02 functions, the relative amounts of memory are far dif- ferent. It is not uncommon for a personal computer to have from 500 Mb (million 1 kilobyte is actually 210 or ) to over 1 Gb (billion bytes) of permanent storage on the hard disk. RAM 1 024 bytes. A megabyte is ranges from 4 Mb to 128 Mb or more depending on the expected application pro- 220 or 1 048 576 bytes. grams. Microcontrollers have far less memory, typically 512 bytes to 4 kb (thousand bytes) of ROM, and 20 to 512 bytes of RAM. Each contains one instruction, or one number or character. Why is there such a great difference in memory size be- tween computers and microcontrollers?

The memory size difference between com- puters and microcontrollers relates mainly to the size and function of the devices. Microcon- trollers must be self-contained. Therefore, all of a microcontroller’s memory must fit onto a small silicon chip in addition to the input/out- put circuitry and the processing unit itself. There just isn’t room on the chip for a large amount of memory. Also, the microcontroller has only one function and needs only one program which occupies a small amount of ROM. Since there is only one active program, a large amount of RAM is not needed to hold a copy of the active program, and the program can be executed di- In a typical microcontroller die, rectly from ROM. A small amount of RAM is memory takes up a comparatively necessary only to hold any changing informa- large amount of space. tion during program execution. Courtesy of Microchip Technology, Inc. Personal computers, on the other hand, require a temporary memory large enough to hold a control program (the operating system of the computer—for example, Windows 95, or MacOS) as well as any application programs (such as a word proc- essor) and temporary data (the file being edited). The operating system is called upon to hold information about how to use all of the input/output devices attached to the computer as well, also requiring memory. The hard disk, or permanent memory, must hold all of the programs and all of the data while the computer is off. For this reason, the hard disk is much larger than the RAM.

The difference in memory size between microcontrollers and computers can also be partially attributed to differences in the sizes and types of processing units. The ‘bit-width’ determines how large a binary number the processing unit can handle. Chapter 1 ©1998 Sirius microSystems 13 Microcontrollers Typical computer micro- ROM RAM ROM RAM processors are 32-bit or BIOS 8 bit BIOS 32 bit even 64-bit giving them a rich instruction set and many features—ideal for running many types of pro- grams. Computers typi- cally also have wide ‘buses’ or groups of wires 8-Bit Processing Unit 32-Bit Processing Unit bit that connect to the memory and peripherals. A 32-bit Microcontrollers require less memory than microprocessors with wide buses. wide (8-bits to a byte, so this is a 4 byte bus) is used to transport instructions and data to the 32-bit processor. The computer memory needs to be bit because it must feed four bytes at a time to the microprocessor.

Microcontrollers can be 32-bit, but since most control programs are fairly sim- An embedded version of the ple and straightforward, 8-bit and 16-bit processors are very widely used. Loading 32-bit PowerPC microcon- one byte at a time into an 8-bit processor requires four times less memory than troller is being used as an engine control computer in loading 4 bytes at a time into the microprocessor in the personal computer. The trade- some current cars. off is that a one-byte number can encode fewer instructions than a 4 byte number, resulting in reduced instruction flexibility in the microcontroller.

Microcontrollers can contain four types of ROM: mask ROM, OTP ROM, EPROM, or EEPROM. Mask ROM is programmed with the designer’s application program during the chip manufacturing stage. As such, mask ROM is very cost effective for large quantities of a microcontroller with the same program. Since mask ROM is permanent, a designer must be sure that no more changes are required to the program before committing to mask ROM. OTP (one-time-programmable) ROM allows the designer to program the microcontroller during assembly of the product. Code changes can be made at any time during the assembly cycle, giving the designer more flexibility and extra peace of mind for fixing the inevitable bugs. OTP ROM microcontrollers are only slightly more expensive than mask ROM versions, making them ideal for small to medium size production runs. EPROM (erasable-program- mable ROM) microcontrollers are programmed during assembly like OTP micro- controllers, but can also be erased with exposure to ultraviolet light. EPROM micro- controllers are distinguishable by their ceramic chip packages with a clear window The window of the PIC on the top. Since this elaborate packaging is more expensive than the typical plastic 16C711 allows ultraviolet chip package, EPROM microcontrollers are most often used during program devel- light to enter and erase the opment or whenever changes are required to be made in the field. Engineers and EPROM. designers can test and evaluate new programs and then just erase the programs to continue development. Finally, EEPROM (electrically erasable-programmable ROM) microcontrollers can be erased and re-programmed electrically, without ultraviolet light and so benefit from cheaper packaging. EEPROM microcontrollers can be embedded into complex assemblies and programmed or erased without removing them from the circuit making them extremely flexible. Most EEPROM microcontrol- lers have a finite number of program/erase cycles, so continuous re-programming is not recommended.

Memory PB ©1998 Sirius microSystems Clock Circuit Outside World

The clock oscillator circuit is a required part of any processing unit, including Micro-Controller Input Output those found in microcontrollers. The clock circuit generates a high frequency square Block Diagram Circuitry Circuitry wave that is used to synchronize all internal operations. It is essentially the ‘orchestra Permanent Temporary conductor’ or ‘traffic cop’, ensuring that all parts of the processing unit maintain Memory Memory synchronization.

Clock Processing Unit Circuit Most microcontrollers include built-in clock circuits that can generate a range of Timer clock frequencies. A few external components are used to create the clock signal or Circuitry to select the clock frequency. Clock signal frequencies can range from a few hertz to block1 over 20 MHz. As with everything else in life, there are trade-offs involved in select- ing the clock frequency. Running the microcontroller at a higher clock frequency results in the microcontroller accomplishing a task more quickly than at a lower clock frequency. Lower clock frequencies, however, reduce electrical current drain as well as operating power (and the heat produced during operation) prolonging battery life as well as potentially increasing the lifetime reliability of the microproc- essor.

Processing Unit Outside World

The processing unit is the most important part of the microcontroller and defines Micro-Controller Input Output the features, functions and ease of programmability of the device or system to be Block Diagram Circuitry Circuitry created. Electronic designers swear by their favourite microcontrollers with an al- Permanent Temporary most religious fanaticism, claiming theirs is the fastest, or the cheapest, or the most Memory Memory easy to use. It’s often very difficult to convert a seasoned programmer to another

Clock Processing Unit ‘religion’. Circuit

Timer The function of the processing unit is to execute the control program. In any Circuitry block1 microcontroller, the processing unit reads the instructions from the ROM (permanent memory), decodes each instruction, and carries out one or more operations for each instruction. The speed at which these operations occur is controlled by the clock circuit.

Watch-Dog Timer Outside World

Watch-dog timers were developed because control programs or devices can fail. Micro-Controller Input Output Block Diagram Circuitry Circuitry When your personal computer software fails it’s relatively easy to recover. At most, you may lose a portion of a file and a few minutes of time while you restart your Permanent Temporary computer. When the microcontroller operating your pacemaker fails, waiting in line Memory Memory to see your doctor for a CTRL-ALT-DEL reset isn’t a desirable option!

Clock Processing Unit Circuit Watch-dog timers are oscillator circuits independent of the main oscillator and Timer are always running. Your program must be designed to reset the watch-dog timer Circuitry block1 during its execution. If your program fails, the watch-dog timer will time out and reset the microcontroller, restarting your program from a known state.

Chapter 1 ©1998 Sirius microSystems 15 Microcontrollers Chapter Summary

Microcontrollers are built in many varieties to perform very specific functions, whereas personal computers are available with only a small variety of general pur- pose microprocessors. Microcontrollers are more suited to specific control tasks where size and cost is a concern. Because a microcontroller is a single chip computer, a microcontroller can offer a single-chip solution to a design problem. While they are single-chip computers, microcontrollers are nowhere near as powerful as microcom- puters. Microcontrollers typically have less memory, lower operating speeds, and most often run only a single program. Their advantages are that they are small, inexpensive, complete computers with integrated I/O circuitry.

Personal Computer Microcontroller Size Laptop to Desktop Pea size to VHS tape Memory External - 10’s of Mb Internal - 100’s of bytes Processor 32 - 64 bit 4 - 32 bit Clock Speed 133 MHz - 575 MHz DC - 50 MHz Price $100.00 - $1000.00 $2.00 - $20.00 Power Requirements 0.5 W - 10 W 10 µW - 1 W Programming Numerous (Basic, C, Limited to Assembly, C, Languages C++, Java, etc.) Basic, Forth Complexity of design Very complex Simple Application General purpose Dedicated to specific purpose

Chapter Summary PB ©1998 Sirius microSystems Questions

1. What types of household appliances can benefit from microcontrollers?

2. What parts of personal computers would contain microcontrollers?

3. Why does a microcontroller require far less RAM than a personal computer?

4. Why are the cheapest microcontrollers OTP?

5. How do microcontroller and personal computer input/output devices differ?

6. Compare and contrast the uses of RAM and ROM in personal computers and microcontrollers.

Assignments

1. Create a chart similar to that on the opposite page comparing a typical compu- ter system to one of the PICmicro™ family microcontrollers. Use a databook or distributor catalog to find some of the information.

2. Describe a project that you would like to build that uses a microcontroller. State why the project is ideally suited to using a microcontroller.

3. Sketch a large block diagram of a micro-controller and include a short state- ment describing the function of each block within each.

Office productivity improved greatly after the introduction of the PICranialTM Brain interface network adapters.

Chapter 1 ©1998 Sirius microSystems 17 Microcontrollers Notes PB ©1998 Sirius microSystems How do Microcontrollers 2 Work?

Microcontrollers work the same way that any computer works. They read an instruction from memory, determine its meaning, and perform the operation(s) speci- fied by the instruction. This is known as a fetch-decode-execute cycle and this cycle takes place thousands or even millions of times each second. All computer proces- sors repeat this simple cycle when executing programs.

Processing Unit

As shown in the block diagram, the ROM Dual Memory Stack contains the program instructions. The Pro- Harvard architecture is the term used to describe gram Counter tells the Instruction Fetch/De- ROM RAM microcontrollers which code unit which memory location to address. Contains Contains have separate memory The instruction in the memory location that Program Data stacks ( Instructions the points to is decoded and ranges) for permanent sent to the ALU (arithmetic/logic unit). The memory, temporary ALU executes the instruction by performing memory and I/O devices. simple arithmetic or logic operations on bi- To the nary numbers. The results of these operations outside world are stored in a working register (W) or to I/O Port memory. Results are never stored to ROM be- cause ROM is Read Only Memory. When the cycle is complete, the Fetch/Decode unit gets the next instruction from memory. Processing Unit Fetch/Decode Unit The clock oscillator circuit advances the program counter. Unless the program counter ALU is modified by the previous instruction, the next instruction in the program sequence is fetched, W decoded and executed. After this, the next in- Program Counter struction is fetched, decoded and executed, and so on. The entire operation of any computer boils down to just three words: fetch, decode and execute! That’s it. Chapter 2 ©1998 Sirius microSystems 19 How do Micro- controllers work Memory

Memory is organized as a sequentially Single Memory Stack numbered stack of storage locations. Each Microprocessors with a RAM memory location has its own unique address. single, continuous memory Contains Some microcontrollers have places for stack (or memory address Data RAM, ROM and I/O circuitry assigned in range) are said to have a a single memory stack, while others have memory mapped architec- separate RAM, ROM and I/O stacks. When ture. ROM Contains there is only one memory stack, the micro- Instructions To the controller is said to have a memory mapped outside architecture (see right diagram). When there world I/O Port are separate memory stacks for instructions (ROM) and data (RAM) the microcontrol- ler is said to have a Harvard architecture. All PICmicro™ microcontrollers use Processing Harvard architecture. Unit Fetch/Decode Unit Note that when they are separated, the ALU microcontroller must distinguish between RAM and ROM memory locations. This is W done by using specific memory or I/O in- structions to address each type of memory. Program Counter

The Outside World Connection

I/O ports connect a microcontroller to the outside world. All ports have a memory location or address which can be accessed by the processing unit. I/O ports are unique in that external signals or the processor can modify their contents. In contrast, only the processor can modify the memory contents. When the processor modifies the I/O port contents, they appear as a voltage on the external pins of the microcontroller. Most microcontroller I/O ports can be programmed to be either inputs or outputs.

How do Programs get into the Microcontroller?

Microcontroller programs are most often written as assembly language mne- monics called source code (see the Data Sheets for a list of all mnemonics). Mnemon- ics are short (3-5 letter) command representations that help programmers to remem- ber the function of instructions. An assembler program converts mnemonics into machine code. Machine codes are binary numbers that the microcontroller interprets as instructions. This binary number representation is called object code and is pro- grammed into the microcontroller ROM using a programmer. Programmers are hard- ware devices that connect to your PC and have a socket that accommodates the microcontroller.

Memory 20 ©1998 Sirius microSystems ;VISINE.SRC V1.0 Simple addition and vision test :020000000528D1 program for Chapter 2. :10000A00502058208C010C0814200038031910289D :10001A006C208C0A0828183068204520102882078E ;Demonstrates use of registers, small characters and :10002A0053346934723469347534733420344D343A :10003A006934633472346F345334793473347434B6 Device PIC16C71,HS_OSC,WDT_OFF,PROTECT_OFF, PWR :10004A0065346D347334203426342034E434453432 ID ‘X+Y=’ :10005A006E34673469346E346534653472346934A5 :10006A006E34673420344C3461346234733400346F ORG 00h ;Reset Vector :10007A008E011A308F008E0B40288F0B4028080003 GOTO 05h ;Jump over interrupt ve :10008A008E018F01043090008E0B49288F0B49286E 010100101000101100010001000 ORG 05h ;Actual program starts :10009A00900B492808008316F83085050001860070 :1000AA00831205110800383068203D203830682056 ;Hardware Equates :1000BA003D20383068203D200C306820013068200F :1000CA000630682008000510860071208128051076 X EQU 0Ch ;X is a label given to :1000DA00860071200514812885148316FF30860056 Y EQU 0Dh ;Y is the label for the :1000EA00831205150000861B782805118316000166 Result EQU 0Eh ;Register 0E is labelle :1000FA008600831285100800051500000511080006 :084000004C0043004400540091 ;Software Equates :02400E001A0096 Source code is converted by an Object code which is downloaded Machine code, the form of assembler program into... to a programmer which programs instructions the microcontroller the microcontroller using... understands.

Some programmers use PC-based simulators to verify the operation of their pro- grams. Simulators allow a programmer to examine internal registers and program flow, helping them to find bugs. Since program execution is simulated and the micro- controller does not run in the target system, real-world timing problems may not be uncovered by a simulator.

Another popular PC-based debugging tool is an emulator. An emulator connects to your microcontroller target circuit in place of your microcontroller. The emulator has functions similar to a simulator with the added bonus of actually running the program in your target system. As a general rule, emulators are more expensive than simulators.

Microcontroller to be programmed The computer downloads machine code to the programmer which ‘burns’ the code into the micro- controller.

Microcontroller Progammer

Programming Socket

Chapter Summary

All microcontrollers execute programs by performing math or logic operations in a fetch-decode-execute cycle. Instructions are fetched from ROM, and can modify RAM or I/O ports. Likewise, the contents of RAM and I/O can affect program in- structions. Programs are written in assembly mnemonics, converted to object code by the assembler program, and programmed into the processor with a programmer. Simulators are often used to examine the program flow during execution to check for errors. Chapter 2 ©1998 Sirius microSystems 21 How do Micro- controllers work Questions

1. Why is the result of an operation never stored to ROM?

2. What relationship does clock speed have to program operation?

3. Explain the difference between assembler and downloader software.

4. How do ports differ from memory locations?

5. What are the advantages of using an emulator vs. a simulator?

While ‘burning’ microcontrollers for the PICranialTM brain interface, Dr. von Netzkopf utilized the services of many beta testers.

Questions 22 ©1998 Sirius microSystems The Microchip PIC family 3 of Microcontrollers

The Microchip PICmicro™ family of microcontrollers is well established and Harvard architecture allows inexpensive. PICmicro™ microcontrollers have been used for many applications in- simultaneous access to both cluding computer mice, remote controls, and caller-ID decoders. The reasons that the RAM and ROM. RISC PICmicro™ family is so popular are due to low cost, high-speed devices and inex- stands for Reduced Instruc- pensive development tools. Its speed stems from its architecture—a modified Harvard tion Set Computer. architecture—and its RISC-like instruction set. RISC computers are characterized by having a small instruction set in which each instruction executes very quickly. In this case, every instruction is a single word long and executes in a single clock cycle. Actually, instructions that modify the program counter require two instruction The PICmicro™ Product Range cycles to complete.

Microchip, the manufacturer of PIC microcontrollers, have three ranges of PICmicro™ microcontrollers (mcu’s) to choose from. The PIC16C5X series of parts make up the low-end, the more powerful PIC16CXX chips form the mid-range line and the PIC17CXX family completes the high-end. The chart below outlines the various PICmicro™ families.

PIC MCU Program Data I/O Clock Peeripherals Pric Families Memory Memory Pins Speed Range ROM RAM (MHz) (qty.1) (Words) (Bytes)

PIC12C5XX512-2k204-7360-24T-21-8-bittimer,WD$2.00The main factor that PIC16C5X12-bitcore $15.00distinguishes the three PICmicro™ families is the instruction size of the core: PIC12C67X512-8k326-36860-54,-21to38-bittimers$4.00-12-bit in the low-end, 14- PIC16C55X14-bitcore WDT,8-bitA/D,DAC,$25.00 PIC16C6X comparators,USART,bit in the mid-range, and PIC16C7X SPI/I2C,EEPROM,16-bit in the high-end. PIC16C9X capture/compare/ PIC14000 PWM,LCDdrivers PIC17C4X2k-16k2332-902333,48/16-bittimers$13.00- PIC17C75X16-bitcore WDT,12-bitA/D,$35.00 SPI/I2C,USART, capture/compare/ PWM,expandable Chapter 3 - The ©1998 Sirius microSystems 23 Microchip PIC family of Microcontrollers The 18-pin PIC16CXX Product Line

PICmicro Program Data Clock A/D Analog Brown EEPROM Timers MCU ROM RAM Speed chan. Comp. Out (Bytes) (Words) (Bytes) (MHz) Reset

PIC15C554 5012 802-- - -1+WD T

PIC16C55610024802-- - -1+WD T

PIC16C558280481022-- - -1+WD T

PIC16C6116024302-- - -1+WD T

PIC16C6205012802-2Y-e s 1+WD T

PIC16C62110024802-2Y-e s 1+WD T

PIC16C622280481022-2Y-e s 1+WD T

PIC16C71160243024- - -1+WD T

PIC16C71056123024-Y-e s 1+WD T

PIC16C711180246024-Y-e s 1+WD T

PIC16C7152804810224-Y-e s 1+WD T

PIC16CR835612301-- -6T 41+WD

PIC16C8416024301-- -6T 41+WD

PIC16F835612301-- -6T 41+WD

PIC16F8418024601-- -6T 41+WD

This chart compares the features of all current 18-pin mid-range PICmicro™ mcu’s. Any of these PICmicro™ mcu’s can be used in the PIC-MDS.

The PICmicro Development System (PIC-MDS) has been developed for the mid- range, 18-pin PICmicro™ devices. The PIC-MDS Professional comes with both the PIC16C711 and PIC16F84. The PIC-MDS Hobbyist system includes only the PIC16F84. The PIC16F84 can be programmed and erased while in the PIC-MDS. The PIC16C711 requires an ultraviolet light source for erasure. We’ll examine the features of these two chips in more detail in a moment. Bear in mind that any 18-pin PIC highlighted in the chart above will work in the PIC-MDS.

The charts shown list only a small sampling of the large variety of PICmicro™ microcontrollers available. Visit the Microchip Technology, Inc. website (http:// www.microchip.com), or contact your local Microchip Distributor for the latest lit- erature.

The 18-pin PIC16CXX Product Line 24 ©1998 Sirius microSystems The PIC16F84

The PIC uses Harvard architecture which means separate RAM and ROM stacks. In the PIC they are different widths.

represents a connection to the outside world.

Program EEPROM

The PIC16F84 has 1 k (1024) locations of EEPROM or Flash ROM, and can be programmed and erased while in the PIC-MDS. Remember that ROM stores instruc- tions for the microcontroller. Since each instruction takes one memory location, your program can have no more than 1024 instructions. Each instruction is 14 bits long, therefore each ROM location is 14 bits wide. ROM locations are addressed in hexa- decimal and range from 0000h to 03FFh (0 to 1023 in decimal). Interrupts are a technique by which the current Two ROM locations are special. Location 0000h is called the Reset Vector. This program is temporarily is where the PIC16F84 begins executing instructions immediately after a reset. Lo- placed on hold while the cation 0004h is called the Interrupt Vector. The PIC16F84 begins executing instruc- processor performs another tions from here immediately after an interrupt. set of instructions in response to an event. See Chapter 11 - Interrupts for Data EEPROM more information.

The PIC16F84 also has 64 bytes of 8-bit data storage EEPROM. This memory Data EEPROM is ideal for is suited to storing values that need to be restored on power-up. Both the program storing user definable and data EEPROM areas are electrically erasable. While the data EEPROM can be passwords or configuration changed by the program executing in the microcontroller, the program EEPROM data. can only be written to by the programmer or downloader. Chapter 3 - The ©1998 Sirius microSystems 25 Microchip PIC family of Microcontrollers RAM

The PIC16F84 has 68 general purpose RAM locations. Each is 8-bits wide. General purpose RAM locations begin at address 0Ch and extend to 4Fh. Microchip calls RAM locations File Registers.

There are 16 other RAM locations known as hardware registers. Some are used internally, while others extend to the outside world as I/O ports. Notice that file register locations 00h through 0Bh have memory addresses on both page 0 and page 1. The RP0 bit in the Status register (03h) determines the active page—0 equals page 0, 1 equals page 1. Some page 0 registers are repeated in page 1 for programming convenience. Though not implemented in the PIC16F84, the microcontroller is capa- ble of accessing two more memory pages via the RP1 bit.

Input/Output Ports

The PIC16F84 has two input/output (I/O) ports. Each port pin can be programmed to be either an input or an output. Some port pins have more than one function. All port pins can source up to 20 mA of current and are able to sink up to 25 mA. The PIC can easily drive LEDs, speakers and small relays without adding external driver transistors. Not all pins can handle high current simultaneously (see the PIC data sheets for details on the I/O ports).

The assembler also recog- Port A is a five bit wide digital port labelled RA.0 to RA.4. Pin RA.4 can be used nizes the labels PORTA.0 - as an input to the real time clock counter/timer (TMR0 or RTCC) or can be used as PORTA.4 and PORTB.0 - a digital I/O pin. TMR0 can also generate an interrupt. PORTB.7 in addition to RA.X and RB.X. See the Port B is an 8-bit digital I/O port. All port B pins have an internal pull-up resis- EPIC .INC files for a list of tor that can be enabled when port B pins are set to be inputs. The internal pull-up all pre-defined labels for each particular processor. resistors eliminate the need for external resistors, saving parts and circuit board space. Pin RB.0 (INT) can double as an interrupt source. Pins RB.4 through RB.7 can be set to generate an interrupt on a change in input state. This feature is useful for The PIC instruction set has waking up the PIC from sleep when a key is pressed. a SLEEP command which stops processing until an I/O ports A and B are file registers 05h and 06h. Two other registers, TRISA interrupt occurs. While (05h on page 1) and TRISB (06h on page 1), contain the direction bits which control asleep, a PIC uses very the flow of data through the ports. A ‘1’ bit in the TRISX register denotes that pin as little current. an input, a ‘0’ bit denotes an output.

TMR0

TMR0 was once known as RAM register location 01h on page 0 contains TMR0, the counter/timer. It can RTCC—the Real Time be fed from either pin 3 (RA.4), or from the internal clock. An 8 bit prescaler— Clock Counter. which divides the incoming signal by a pre-programmed amount—can be applied to the TMR0 input. Incoming clock signals can be divided by: 2, 4, 8, 16, 32, 64, 128 or 256 depending on the prescale value. The prescaler value is set in the OPTION register (01h on page 1). The prescaler is shared with the watchdog timer (WDT), and if used for WDT is unavailable for use by TMR0.

RAM and I/O 26 ©1998 Sirius microSystems With TMR0 set to count external signals, it can count external events such as bottles moving down an assembly line, the rotations of a tire, or the number of times your desk drawer has been opened. With TMR0 counting internal clocks, you could use TMR0 to measure the width of a pulse if you turn on TMR0 when a signal on a pin goes high and turn it off when the signal transitions back to low. This technique can be applied to measure pulse widths as small as 100 µs and frequencies up to 50 MHz.

Watchdog Timer (WDT)

The Watchdog Timer (WDT) is an independent free running oscillator completely While WDT is self con- self-contained on the chip. Being independent of the main clock means that if the tained and requires no main oscillator is halted by the SLEEP command, the PIC can be ‘awakened’ by the external parts, the main continually running watchdog timer. clock oscillator requires external components (see The Watchdog timer has a nominal period of 18 ms (which is equivalent to a Oscillator, below). frequency of 55 Hz) but can vary from 9 ms to 40 ms depending on temperature and applied voltage. A prescaler, shared with TMR0, can be applied to the Watchdog timer to change its period.

The Watchdog can used to force a reset after either a software fault—the proces- sor may be stuck in an endless loop, or static discharge may have corrupted register memory—or to wake the processor from a SLEEP command.

If not needed, WDT may be turned off via the configuration fuses. Configuration fuses are set by the programmer or downloader during programming.

Power-Up Reset Timer (PWRT)

The power-up reset timer is used to provide a nominal 72 ms delay after power is first applied. This allows the power supply 72 ms to stabilize before the reset signal is issued to the micro-controller. It is controlled via the configuration fuses.

Oscillator

The clock oscillator circuit in the PIC16F84 is very flexible. Four oscillator options are available: quartz crystal, ceramic resonator, resistor-capacitor combina- tion (RC), or external clock input. The oscillator socket on the PIC-MDS allows you to plug in quartz crystals or ceramic resonators.

Quartz crystal and external clock inputs allow the highest speed and the most Capacitors have wide accurate timing. Ceramic resonators are cheaper but slightly less accurate than quartz tolerances and both resistor crystals. RC combinations are cheapest but suffer from timing inaccuracies depend- and capacitor values ent on temperature and the power supply voltage. The chosen oscillator option is set change with temperature. via configuration fuses blown during programming.

Chapter 3 - The ©1998 Sirius microSystems 27 Microchip PIC family of Microcontrollers RAM Register Files

As mentioned earlier, RAM is divided into the hardware register file and general- purpose storage locations. We have already seen how some of the register files have been used (PORTA, PORTB, TRISA, TRISB, TMR0, and OPTION ). We’ll look at some of the other important registers.

STATUS The STATUS register (03h) holds arithmetic flags, page select bits and the mi- crocontroller’s reset status. More detail on STATUS can be found in the PIC16F84 Data sheets.

PCL & PCLATH PCL (02h) stands for Program Counter Low. It holds the lower 8 bits of the program counter. Remember that the PIC16F84 can have as many as 1024 instruc- tions in ROM (program) memory. Addressing 1024 locations requires 10 bits. The upper two bits are stored in PCLATH (0Ah bits 0 and 1).

IND0 & FSR IND0 (00h) is the first (and only) INDirect addressing register. It is used in conjunction with FSR (04h), the File Select Register, to indirectly access data.

A reference to IND0 retrieves the contents of the address location stored in FSR. This allows a programmer to increment FSR and access subsequent locations by using the IND0 address as the target of the instruction. For example, if FSR contains 20h, addressing IND0 will access RAM location 20h. Indirect addressing is particu- larly useful for look-up tables.

INTCON The INTerrupt CONtrol register (0Bh) enables or disables interrupts and con- tains most of the interrupt flag bits.

OPTION The OPTION register (01h on page 1) controls prescaler divisors, TMR0 trigger levels and signal source, as well as the Port B pull-up resistors.

EEDATA & EEADR The PIC16F84 has 64 bytes of EEPROM data memory which can be changed by the program, unlike the program EEPROM which can only be changed by the programmer. EEDATA (08h) holds the data to be written to or read from the location specified by EEADR (09h).

EECON1 & EECON2 EECON1 (08h on page 1) is the EEPROM data memory control register. EECON2 (09h on page 1) is used during EEPROM data writes.

RAM Register Files 28 ©1998 Sirius microSystems The PIC16C711

Many of the parts of the PIC16C711 are identical to the PIC16F84. The differ- ences reflect the addition of a four-channel A/D converter and the use of EPROM program memory rather than EEPROM. The PIC16C711 has no EEPROM data memory.

Program EPROM

The PIC16C711 EPROM memory is identical in size to that of the PIC16F84 (1k words). Unlike the PIC16F84, the PIC16C711’s EPROM memory is erased by Erasing a PIC16C711 takes exposure to ultraviolet light. Be sure to cover the window after programming so that 5-10 minutes of exposure ambient light won’t affect the operation of the PIC. under ultraviolet light.

The Reset and Interrupt Vectors are in the same locations as the PIC16F84.

Analog-to-Digital Converter

The PIC 16C711 is one of the few members of the PICmicro™ family with a built-in 8-bit analog-to-digital converter (A/D). In many cases it is cheaper to use a PIC16C711 than to use a PIC with an external A/D. The A/D converter can translate an analog voltage into a binary number.

Port A of the PIC16C711 can be configured to read two, three or four analog inputs. Conversions require a minimum of 20 µs. The A/D clock can be fed by its Chapter 3 - The ©1998 Sirius microSystems 29 Microchip PIC family of Microcontrollers own RC oscillator or from the master clock through an internal clock divider under control of the ADCON0 (08h) file register. Using the RC oscillator allows conver- sions to take place while the micro-controller is asleep, which provides the best con- version accuracy.

The A/D is controlled through two RAM regis- ters, ADCON0 (08h) and ADCON1 (08h on page 1), and the result is placed in the A/D result file register ADRES (09h).

The A/D is particu- larly useful when measur- ing the voltage from a strain gauge, liquid level sensor, temperature sensor, light sensor, or perhaps even for measuring brain- While trying out the new PIC-Your-BrainTM brain wave wave activity. analyser, Bob realizes that he should never have removed the ground prong from his oscilloscope’s power cord.

Chapter Summary

The PIC16F84 and PIC16C711 are identical except: • the memory on the PIC16F84 is electrically erased, the PIC16C711 requires exposure to ultraviolet light • the PIC16F84 has an additional 64 bytes of EEPROM data space • the PIC16C711 has a 4-channel A/D converter • the maximum clock speed of the PIC16F84 is 10 MHz, the PIC16C711 has a 20 MHz maximum clock speed

It’s easiest to develop programs on the PIC16F84 becasue the EEPROM memory allows quick erasing and reprogramming. The PIC16F84 can also be programmed in-circuit, without removing it from the PIC-MDS and plugging it into the program- mer. All necessary programming signals are supplied to the PIC through the In- Circuit programming cable.

If your program requires high speed operation, or A/D conversion, then the PIC16C711 must be used.

A/D Converter 30 ©1998 Sirius microSystems Questions

1. What is the maximum size of program you could place inside a PIC16F84 or PIC16C711?

2. What is the location of the instruction that will be executed immediately after a reset?

3. What is the maximum number of variables that could be stored in RAM?

4. What is the purpose of a watchdog timer? Why is the watchdog given its own oscillator?

5. What is the advantage of EEPROM program memory?

6. Explain how an application might use EEPROM data memory.

7. Why is program memory wider than data memory?

8. Air bag sensors respond to rapid decelerations that occur within 30 ms. Can a PIC16C711 measure at least 20 analog samples within a 30 ms window to determine whether or not to inflate the bag?

Assignment

1. You’ve developed a touch-tone dialer program using the PIC-MDS and a PIC16F84. The program is 487 bytes long. What other PICs could be used instead of the PIC16F84? Check supplier catalogs to find the least expensive PIC.

2. You have 6 relays to connect to PIC16F84. Each relay coil requires 20 mA to activate. Examine the data sheets and determine how many relay coils can be active simultaneously on Port B. How many of these relays could be connected to Port A?

Chapter 3 - The ©1998 Sirius microSystems 31 Microchip PIC family of Microcontrollers Notes 32 ©1998 Sirius microSystems Features of the PIC-MDS 4 Development System

The PIC-MDS contains everything you need to develop your own mid-range PICmicro™ microcontroller applications. The advantage of the PIC-MDS is that was designed with typical microcontroller input/output (I/O) circuitry already pre- wired to the microcontroller, so that users can spend their time concentrating on code development and not on hardware debugging. This chapter explains the operation of each of the devices on the PIC-MDS board. Refer to the schematic on the next page to examine the circuitry for each item.

2-Line 16-Character LCD Display with 80 character memory and Buffered LED RS-232 Serial display shows 2.1mm Power Jack programmable characters driver/receiver power and port 12 VAC or 18 VDC status (500mA) input RS-232 input/ output header Screw terminal strip allows access to all RS-232 transmit/ port signals and receive select jumper power supplies. LCD contrast adjust potentiometer Variable DC adjust potentiometer Serial EEPROM Crystal or ceramic resonator socket Fixed 5V regulator PICBUS expansion header

Processor ZIF socket

5VDC internal/ 16 key matrix EPIC in-circuit external select keypad with Hardware programming jumper customizable reset button header key legends Variable DC Two variable internal/external Variable DC analog input select jumper regulator potentiometers

Chapter 4 - Features ©1998 Sirius microSystems 33 of the PIC-MDS Development System 34 ©1998 Sirius microSystems Power Supply Circuit

The power supply of the PIC-MDS is capable of supplying both the microcon- troller and external circuitry with a range of voltages. Two independent regulators provide a fixed +5VDC output as well as a variable DC output. The variable DC output can be connected to the 5V microcontroller power supply to run the microcon- troller at a lower voltage than 5V using a user-supplied jumper. Each power supply voltage is present at the PICBUS expansion connector (H1) for external circuitry.

Electrical current is supplied to the PIC-MDS through the 2.1mm co-axial power jack (J1) or from pins 1 and 3 of the screw terminal strip (CON1-1 & CON1-3). Pin 3 of the screw terminal strip (CON1-3) is the ground connection. Pin 2 of the screw terminal strip (CON1-2) in conjunction with the ground (CON1-3) allows an exter- If you add high current external circuitry to the nal power supply to provide the regulated +5VDC for the microcontroller. PICBUS or CON1, power the PIC-MDS from an The PIC-MDS power supply accepts either AC or DC input. The on-board power external power supply supply will produce the necessary DC voltages for the PIC-MDS. The PIC-MDS is attached to screw termi- designed to work with either of the following AC adapters: nals 2 and 3 on CON1. The PIC-MDS AC power supply Input Voltage Output Voltage Output Current can supply only 300 mA to the PIC-MDS and external 120 VAC 9-12 VAC 300 mA circuitry. 120 VAC 12-18 VDC 300 mA

Note that using AC adapters with higher output voltages will increase the power dissipation of the regulators and will cause them to get quite hot during operation.

J1 J1 is a 2.1mm co-axial power jack This jack supplies current from an AC or DC wall adapter to the bridge rectifier (D1) and the regulator circuitry (C1-6, U1, U2, The screw terminal strip etc.). J1 also contains a normally closed switch connected to the 16-pin screw termi- pins are numbered from the nal strip (CON1-1). When no wall adapter is plugged into J1, current from pin 1 of top of the PIC-MDS. the screw terminal strip (CON1-1) flows through J1 to the rectifier. Therefore, pin 1 or CON1-1 is closest to J1, and pin 16 VR1 or CON1-16 is closest to C5. Potentiometer VR1 is used to adjust the variable DC power supply. The range of the variable DC power supply is from 1.3V to approximately 3V less than the volt- age into J1.

JU1 Default position: REG

3-pin shorting jumper, JU1, selects the voltage source for any circuits connected to the variable DC power supply. In the REG position, the variable DC voltage is derived from the variable DC regulator (U1). In the CON1 position, the variable DC voltage is taken from pin 2 of the screw terminal strip (CON1-2).

Chapter 4 - Features ©1998 Sirius microSystems 35 of the PIC-MDS Development System JU2 Default position: REG

The 3-pin shorting jumper, JU2, selects the fixed +5VDC voltage source. In the REG position, the fixed +5VDC voltage is derived from the 5V regulator (U2). In the CON1 position, the fixed +5VDC voltage is taken from pin 2 of the screw terminal Warning: Do not exceed strip (CON1-2). +6VDC on CON1-2 when JU2 is set to CON1 input When the fixed +5VDC voltage source is present, the LED at the top of the LED or you will destroy your bar graph (LED1-PWR) lights. PIC microcontroller.

External I/O Connectors

The PIC-MDS has two external I/O expansion connectors. The 16-pin screw terminal strip (CON1) allows for quick and easy connections from external circuit components to the PIC I/O ports. The PICBUS expansion header (H1) allows exter- nal circuits to be connected more permanently to the PIC microcontroller. The PICBUS includes both power supplies as well as the PIC reset line (MCLR) and is geared to adding microcontroller peripherals to the PIC-MDS.

CON1 CON1 is the 16-pin screw terminal strip at the extreme left of the PIC-MDS. Three power supply connections and 13 microcontroller I/O pins are brought out to the screw terminals for ease of connection to external devices. The pinout of CON1 is shown below:

Note that the input to CON1-2 is affected by both +9V to +18VDC input — CON1-1 the JU1 and JU2 settings. +5VDC or variable DC — CON1-2 CON1-2 can provide Ground — CON1-3 either the external +5VDC supply or the external RA0/AIN0 — CON1-4 variable DC supply—but RA1/AIN1 — CON1-5 not both at once! RA2/AIN2 — CON1-6 RA3/AIN3/VREF — CON1-7 RA4/RTCC — CON1-8 RB0/INT — CON1-9 RB1 — CON1-10 RB2 — CON1-11 RB3 — CON1-12 RB4 — CON1-13 RB5 — CON1-14 RB6 — CON1-15 RB7 — CON1-16

External I/O Connectors 36 ©1998 Sirius microSystems PICBUS The PICBUS connector on the PIC-MDS is compatible with the PICBUS con- nectors on the PIC-PROTO boards from microEngineering Labs. It is a 26-pin header connector socket at the right side of the PIC-MDS. The pinout of H1 is shown below:

Note that the PIC-MDS does not come with a connector for the PICBUS header. A number of different RA4/RTCC — H1-1 H1-2 — MCLR/VPP styles of header plugs RA0/AIN0 — H1-3 H1-4 — +5VDC/VDD and sockets will fit into RA1/AIN1 — H1-5 H1-6 — Variable DC the PICBUS connector. RA2/AIN2 — H1-7 H1-8 — Ground RA3/AIN3/VREF — H1-9 H1-10 — Ground RB0/INT — H1-11 H1-12 — RC7 RB1 — H1-13 H1-14 — RC6 RB2 — H1-15 H1-16 — RC5 RB3 — H1-17 H1-18 — RC4 Connected to opposite RB4 — H1-19 H1-20 — RC3 RBx pin on PIC-MDS RB5 — H1-21 H1-22 — RC2 RB6 — H1-23 H1-24 — RC1 RB7 — H1-25 H1-26 — RC0

Microcontroller Related Circuits

The PIC microcontroller is essentially connected to all of the circuitry on the PIC-MDS board. The following parts of the PIC-MDS relate most directly to the PIC microcontroller.

Microcontroller Socket The PIC microcontroller socket (U3) is either an 18-pin zero-insertion-force (ZIF) socket (in the case of Attention Hobbyist users: the PIC-MDS Professional), or an 18-pin DIP socket you will find that a ZIF (PIC-MDS Hobbyist). Pin 1 is the pin closest to the U3 socket for U3 reduces the likelihood of broken IC label on the PIC-MDS board. leads when removing and inserting PICs. H2 The EPIC In-Circuit programming header (H2) al- lows the EPIC programmer from microEngineering Labs to plug directly into the PIC-MDS to speed the pro- gram/test/erase process and to save wear and tear on the microcontroller and socket (U3). By connecting the Chapter 4 - Features ©1998 Sirius microSystems 37 of the PIC-MDS Development System The PIC16C711 can also EPIC programmer to the be programmed through the PIC-MDS, a PIC16F84 In-Circuit programming can be programmed and header, but requires UV erased without removing it light for erasure. from the microcontroller socket on the PIC-MDS board. Simply connect H2 to the programming header on the EPIC programmer (J3) with the supplied 10- pin ribbon cable.

Pin 1 of H2 is at the lower left of the header and is denoted by a triangular arrow on the outside of the header shroud. Pin 1 of the programming header (J3) on the EPIC programmer is also at the lower left (far- The PIC-MDS connected to the EPIC programmer thest away from the 25-pin through the 10-pin programming cable. Be sure to parallel connector). Be connect the cable in the proper orientation. sure to connect the 10-pin If you purchased the PIC-MDS with the EPIC program- programming ribbon cable mer, refer to the Quick Start sheet for information on how in the proper orientation. to get up and running fast!

It is sometimes necessary Reset Button to press and hold the Reset button while starting the The Reset button (S1) pulls the PIC MCLR line low when pressed, causing a EPIC software. This is hardware reset. During a hardware reset, the PIC microcontroller stops executing the because the EPIC pro- current program and changes all I/O ports to inputs. When the Reset button is re- grammer programs the PIC leased, the microcontroller begins executing its program from the beginning of memory, using RB.6 and RB.7. The effectively restarting the program. EPIC software expects these two pins to be inputs. Y1 If your program uses RB6 and RB7 as outputs, the Y1 is the crystal oscillator/ceramic resonator socket. Crystal oscillators and two- EPIC software can’t pin ceramic resonators plug into the two outer socket pins (Y1-1 and Y1-3 on the interrogate the PIC. By schematic). Y1-2 is a ground pin and is used for 3-pin ceramic resonators. holding the Reset button, these two pins float, The PIC-MDS is supplied with a 10 MHz crystal. The values of the external essentially becoming oscillator components C7, C8 and R5 have been chosen to operate the PIC-MDS inputs. properly at frequencies from 4 to 20 MHz. To operate the PIC-MDS at a clock frequency other than 10 MHz, or to use a ceramic resonator instead of a crystal oscillator, simply install the crystal or resonator in Y1.

JU3 Default position: RUN

Three-pin shorting jumper JU3 changes the source of the +5VDC power supply for the microcontroller only. In the RUN setting, the PIC-MDS fixed +5VDC supply Microcontroller Related Circuits 38 ©1998 Sirius microSystems powers the PIC microcontroller (as well as all other circuitry on the PIC-MDS). In the PROG setting, the microcontroller is powered by the EPIC programmer (all other PIC-MDS circuitry is still powered by the fixed +5VDC supply).

This jumper allows you to take advantage of the ZIF socket on the PIC-MDS as an add-on to the EPIC programmer. When set to PROG, the EPIC programmer powers only the microcontroller, not the rest of the PIC-MDS. Since the EPIC pro- grammer was not made to power external circuitry, setting JU3 to PROG prolongs the battery life of the EPIC.

JU6 Select only one of RA2, Default positions: RA0 - Open RA3 or RA4 at a time. RA1 - Open Otherwise you will short RA2 - Shorted two or more PIC outputs RA3 - Open together, potentially RA4 - Open damaging the PIC through excessive output current. The 10-pin jumper block JU6 has two purposes. The RA0 and RA1 positions connect the analog input potentiometers (VR3 and VR4) to the PIC RA.0 and RA.1 inputs, respectively. When not using the analog input capability of the PIC16C711, leave RA0 and RA1 open to eliminate interference from the analog voltage levels set by VR3 and VR4.

The RA2, RA3 and RA4 positions of JU6 select which of the microcontroller Port A lines is connected to the LED labelled JU6 on the LED bar (LED1). By default, the JU6 LED monitors the LCD enable line on RA2. Moving the shorting RA2 is also the LCD jumper from RA2 to RA3 or RA4 allows you to monitor those pins using the LED. enable line. Removing the jumper from RA2 lets the VR3 & VR4 enable line float and may cause unreliable operation. VR3 and VR4 are analog input potentiometers meant to simulate analog sensors when using the PIC16C711’s built-in A/D converter. Disable VR3 and VR4 when not using the analog input capability of the PIC16C711, or when using the PIC16F84. To disable VR3 and VR4 simply remove the jumpers from JU6-RA0 and JU6- RA1.

Matrix Keypad

KB1 is a 4X4 matrix keypad connected to Port B of the PIC microcontroller. All switches are normally open and will not interfere with the operation of any programs that do not use the keypad. Resistors R6-R9 provide short-circuit protection in case two Port B pins are set to output and become shorted by a pressed keypad switch.

The key caps can easily be removed by gently lifting the left or right side of the clear plastic cover. This makes it easy for you to add your own custom key legends.

Chapter 4 - Features ©1998 Sirius microSystems 39 of the PIC-MDS Development System The LEDs will display the LED Output Indicator Bar Graph state of the PIC I/O ports regardless of whether they LED1, a 10-seg- are outputs or inputs. By — indicates +5VDC is present connecting external ment LED (Light Emit- — displays state of RA2, 3 or 4 circuits to the PIC inputs ting Display) bar graph, — displays state of RB0 you can use the LEDs as is used to indicate that logic probes to monitor the fixed +5VDC power — displays state of RB1 your inputs. supply is operating as — displays state of RB2 well as to monitor the — displays state of RB3 status of the microcon- — displays state of RB4 — displays state of RB5 troller I/O lines. The — displays state of RB6 LEDs are connected as — displays state of RB7 shown.

Intelligent LCD Display

Disable the LCD by making The LCD display (LCD1) is a 2-line by 16-character intelligent display with an RA2 (LCD Enable) an 80 character memory. A built-in microcontroller gives the LCD display intelligence output and setting it low. At by allowing it to control the cursor, address specific character positions, shift the power-up all PIC I/O ports display contents left or right and program custom characters. are set as inputs. An undefined input on RA2 The LCD display uses RA0, RA1 and RA2 as its Register Select, Read/Write can activate the LCD and and Enable control signals, along with RB0-7 for character or command data. When adversely affect your disabled, the LCD display will not interfere with other circuitry connected to Port B, program. RA0 or RA1.

VR2 Potentiometer VR2 is the LCD contrast control. Rotate this potentiometer until the LCD displays the most readable image.

RS-232 Serial Port

Note that you cannot use U6 is an RS-232 serial line driver/receiver and translates the PIC microcontrol- U6 to transmit and receive ler’s +5V logic to bipolar RS-232 levels. It connects to pin RA4 of the PIC to allow serial data at the same time transmission or reception of standard RS-232 data. Note that many new computers because only one PIC I/O will accept +5V (TTL) logic levels allowing you to use any PIC I/O pin for serial line (RA4) is connected to data transmission (over limited distances). U6 guarantees the correct voltage and it. drive capability as specified by the RS-232 standard.

JU5 Default position: open

Transmit/receive select jumper, JU5, is a 3-pin shorting jumper used to select whether RA4 is connected as a serial input or output. Removing the shorting jumper plug, or connecting it to only one pin of JU5, disables the serial port. Putting the jumper in the Rx position couples incoming RS-232 data to RA4. Putting the jumper in the Tx position allows RA4 to output RS-232 data. LED, LCD Display, Serial Port 40 ©1998 Sirius microSystems H3 H3 is the RS-232 serial cable connection header. A user-supplied 3-pin plug can connect this header to external RS-232 serial devices. Refer to the schematic dia- gram at the beginning of this chapter for the pinout of H3.

Serial EEPROM Remember that the PIC16F84 also has an on- Applications that require long-term data or variable storage can store informa- board 64 byte EEPROM. tion in the serial EEPROM. Its 256 bytes of memory are non-volatile, and can be programmed by the PIC microcontroller. The serial EEPROM is controlled by the Like the LCD, disable the signals on RA0, RA1 and RA3. The serial EEPROM is similar to the LCD display in EEPROM by making RA3 that it uses Port A wires for its control signals—the Chip Select, Clock, Data In and an output and setting it Data Out lines. low.

JU4 Default position: X8

3-pin jumper JU4 sets the data memory organization of the serial EEPROM. In the X8 setting, the serial EEPROM accesses memory in 8-bit bytes. When the jumper is closest to the JU4 label, the serial EEPROM accesses memory in 16-bit words.

PIC-MDS Default Jumper Locations

The full-size parts layout drawing, above, shows the default locations of all jumpers for most of the program examples. Each program lists the required jumper locations.

Chapter 4 - Features ©1998 Sirius microSystems 41 of the PIC-MDS Development System Questions

1. Which pins of the screw terminal strip would be used to connect a 15VDC lab power supply?

2. What connections and jumper settings of JU1 and JU2 should be used for the following:

a) a 9V battery powering the PIC-MDS board and a 12V battery providing adjustable power to circuits on the PICBUS

b) a 12V car lighter adapter powering only the PIC-MDS board

c) a 5V regulated lab power supply powering the PIC-MDS and a variable lab power supply powering PICBUS circuits

d) two D cells supplying power to a low-power PIC microcontroller

e) a 6V battery supplying 3V to a low-power PIC microcontroller through the on-board variable DC power supply

3. Can you put shorting jumpers on both JU6-RA3 and JU6-RA4 at the same time? Why or why not?

The default jumper settings on the previous page work for mostof the programs in this text when using the supplied AC adapter.

Hmm...Was that JU1 to JU3 for 5V operation, except with batteries and when bypassing the regulator attached to CON1-3, or was it...?

Questions 42 ©1998 Sirius microSystems Writing a Simple 5 Program

Recall from Chapter 2 that the first step in programming a microcontroller is If you have not yet in- writing the program source code, after which the source code is converted to object stalled the PIC-MDS code by an assembler program. The PM assembler supplied with the PIC-MDS pro- software do so now. See the gramming packages supports two dialects of PIC instructions. Quick Start! sheet for instructions. One dialect is the official Microchip instruction set and syntax, the other is com- patible with the Parallax’s 8051-like instruction set. Each has its advantages and Parallax, Inc. is a supplier disadvantages. of PIC development tools.

If you are familiar with the Microchip instruction set, or have programmed Motorola family microcontrollers, you may find it easier to use the Microchip com- mand syntax and examples. If you have programmed Intel family microcontrollers or microprocessors (or want to), you may find it easier to use the Parallax command syntax and examples. If you are new to the PIC microcontrollers, we suggest that you read both until you find one that you are more comfortable with.

Mxicrochip Instruction Syntax Parallax8051-likeSynta

stimilartoMotorolaformatsimilartoIntelforma

fmewinstructionstolearnmoreinstructionstochoosefro

mdanyexampleprogramsnotaswidesprea

instructionsreflectoneinstructionmayexecuteone microcontrolleractionsormoreMicrochipinstructions

The PIC-MDS system, including this manual and all example programs, pro- The Microchip Code vides source code and descriptions in both instruction sets. Chapters using the Mi- sections are printed on crochip instruction set and syntax are identified by the Microchip Code footer at the white paper, and the bottom of the page. Likewise, chapters using the Parallax instruction set and syntax Parallax Code sections are are identified by the Parallax Code footer at the bottom of the page. printed on blue paper. Chapter 5 ©1998 Sirius microSystems Microchip Code 43 Writing a Simple Program Here is the same pro- gram routine written in Main BTFSC PORTA.4 ;Check Port A bit 4 for a low both Microchip (top) and GOTO Main ;If we’re here, bit 4 is high Parallax-compatible INCF PORTB ;If bit 4 is low, increment Port B (bottom) source code. Wait_for_High BTFSS PORTA.4 ;Check Port A bit 4 for a high Notice that the program GOTO Wait_for_High ;If we’re here, bit 4 is still low written in Microchip GOTO Main ;Bit 4 went high, wait for next bounce code requires more Microchip assembly source code example. instructions to be entered in order to do the same thing as the Main JB PORTA.4,Main ;Loop while Port A bit 4 is high Parallax code. However, INC PortB ;If we’re here, bit 4 is low so both programs assemble ;increment Port B to count the ;transition and, to six machine instruc- tions, meaning that the Wait JNB PORTA.4,Wait ;Loop until Port A bit 4 goes high Parallax code hides JMP Main ;Bit 4 went high, wait for next bounce some of the microcon- Parallax-compatible assembly source code example. troller operations. Examining Source Code—Microchip Code

EDIT is available from The example programs have been written using the DOS text editor EDIT. You within an MS-DOS session can, of course, use any text editor, but our instructions describe EDIT. Let’s look at in Windows-95. If you use the source code for a simple program that displays a binary number on the LEDs. an editor or word processor other than EDIT to write From the MS-DOS prompt, change to the EPIC directory using the command: source code files, make sure that you save them in DOS Text or ASCII format. cd \picmds [enter] Open the OUTPUT.ASM file for editing by typing:

edit output.asm [enter] Your screen should look like this. Use the cursor keys or mouse to move the cursor through the text as we examine the program.

If you have not used EDIT before, you may want to take a quick look at the Help menu at the top-right hand side of the screen.

Examining Source Code 44 Microchip Code ©1998 Sirius microSystems Source Code Conventions

Notice the way that text is organized in columns. Any text beginning in the very first column is considered a Label, and is a part of the Label Field. The next three columns contain the Instruction Field, Data Field and Comment Field. Comments may also begin in the first column if they are prefixed with a semicolon (;).

Labels are names given to subroutines or sections of source code. By giving Initialize, Main and Done parts of a program names, other program instructions can jump to or reference the are the three labels used in named parts. Most assemblers place some sort of limit on the length of labels, as well OUTPUT.ASM. as the characters that can be used to define labels. PM has a limit of 32 characters.

The PM assembler supplied with the PIC-MDS packages also allows the use of local labels. Local labels are prefixed with a colon (:) and remain as a label specific Local labels are explained in more detail in Chapter to the previous non-local label. For example, you could have two different subrou- 10 - Calls and Includes. tines labelled :Loop, one within a labelled Countdown and another within a subroutine labelled Countup. The assembler knows that a call to :Loop from within Countdown should reference only that :Loop, and not the :Loop in Countup.

;Description

; This program demonstrates port output. It initializes all port B pins ; to be outputs and then places a pattern on port B to illuminate LEDs.

;Jumper Settings Assemblers usually only ; JU2 5VDC internal/external select REG require a single space or ; JU1 Variable DC internal/external select REG punctuation symbol to ; JU3 Processor power select jumper RUN ; JU4 EEPROM X8/X16 organization select N/A separate columns. Using ; JU6 Port A LED output and analog input RA0 OFF nicely spaced columns ; RA1 OFF makes it far easier for ; RA2 ON you to read your source ; RA3 OFF ; RA4 OFF code. Set Tab stops ; JU5 RS-232 receive/transmit select N/A where you would like your columns to begin. ;Requirements

; This is a simple program that requires no prior setup.

Maclib ‘Pf8x.INC’ ;Library file for PIC16C84 and PM assembler ;Comment this line out for other assemblers

Device PIC16F84,HS_OSC,WDT_OFF,PROTECT_OFF,PWRT_ON ID ‘OUTP’

ORG 00h ;Reset Vector location GOTO Initialize ;Start program after Interrupt vector

ORG 05h ;One location past Interrupt vector

Initialize BSF RP0 ;Select memory register page 1 CLRF TRISB ;Make Port B output by clearing TRISB BCF RP0 ;Go back to register page 0

Main MOVLW 01010101b ;Move 01010101b into W and MOVWF PORTB ;output pattern to LEDs on Port

Done SLEEP ;Stop executing the program Label Instruction Data Comment Field Field Field Field Chapter 5 ©1998 Sirius microSystems Microchip Code 45 Writing a Simple Program The second column is the Instruction Field. Instructions can be either microcon- troller instructions or instructions for the assembler, called assembler directives. The Appendix D shows the instruction set of the PIC microcontroller is described in the PIC16F8x data sheets. Parallax instruction set Remember that the PM assembler supports two instruction sets, Microchip and Par- mnemonics. allax. The term directive is used for assembler commands so that they are not con- fused with microcontroller instructions (See Appendix C for more details).

The column following the Instruction Field is the Data Field. Data fields contain data used by the instructions. In the case of the PIC microcontrollers, data can be a file register, a bit within a file register, a label, or a number—called a ‘Literal’ by Microchip. Some instructions have no data. If an instruction needs multiple pieces of data, they are separated by a comma.

Now may be a good time to The base unit of number is optionally specified by the suffixes b and h—binary brush up on binary and and hexadecimal. A number with no suffix is considered to be a decimal number. hexadecimal. Any good Therefore, the data 12, 00001100b and 0Ch are all the same. Note that if the first digital textbook will digit of a hexadecimal number is not numeric, it must be prefixed with a 0, even if it explain number systems. makes a three-digit number. For example, 0FDh is acceptable, but FDh generates an error because it is interpreted as a label by the assembler.

The last field is the Comment Field. Comments always have a semicolon as their first character and can be placed anywhere in the program. Comments are one of the most important code conventions you should develop. Well written comments de- scribe the operation of your code, or the operation and requirements of subroutines. Without comments, it can be very difficult to decipher the source code that you cre- ated just a few days ago.

Some Other Common Source Code Conventions

Some conventions are used to make a programmer’s life easier. You’ll adopt your own favourite conventions as you become more proficient. In general, conven- tions are any action that make it easier to review and understand any program, espe- cially the one that you wrote a few months ago! Here are some of the conventions used in this manual:

• file naming - *.ASM for source files, *.LST for list files, *.HEX for object files • name, revision level and revision date as the first line of a program • tabs - every 4 or 8 spaces • instructions in upper case - the code is more visible • comments explaining every line of code • a comment paragraph explaining routines - comment fields are very small • “_” as space character - max_int_power is easier to read than maxintpower

Remember, conventions are anything that you find makes the code easier to read.

Source Code Conventions 46 Microchip Code ©1998 Sirius microSystems Examining the Program

The Maclib Directive

Maclib ‘P84.INC’ ;Library file for PIC16C84 and PM assembler ;Comment this line out for other assemblers

After the disclaimer and description comments, the first part of the program is Maclib is unique to the PM the Maclib directive. Maclib is short for Macro Library. A macro library contains assembler shipped with the labels corresponding to the hardware locations of a particular microcontroller. In this EPIC programmer and case, the Maclib directive includes references for the PIC16C84 and PIC16F84 allows easy upgrades to microcontrollers. When you write a program for a different microcontroller, you will new microcontrollers—just reference a new .INC file. need to include the proper file in the Maclib directive. P84.INC works with the PIC16C84 and PIC16F84, The Device and ID Directives but the newer PF8X.INC works with the PIC16F83 as well. Device PIC16C84,HS_OSC,WDT_OFF,PROTECT_OFF,PWRT_ON ID ‘OUTP’

The next line of the program is the Device Directive. The Device directive sets a number of parameters for the microcontroller. The first item in the Device directive tells the assembler to create a program for the PIC16C84 microcontroller. You could change this to PIC16C711—the other type of microcontroller supplied with the PIC- MDS—or to any other mid-range PIC microcontroller you wanted to program (see Chapter 3).

The data following the microcontroller type sets the configuration fuses in the See Chapter 3 for other microcontroller. In this case the directive sets high speed oscillator operation options set by the configu- (HS_OSC), watch-dog timer off (WDT_OFF), code-protect off (PROTECT_OFF), ration fuses. Code-protect and power-up reset timer on (PWRT_ON). prevents a standard downloader/programmer The ID directive sets the four identification bytes. These could be anything from from reading your pro- gram. This provides a a name or serial number to the number of Sundays until Christmas. Note that the ID degree of protection from bytes are not protected by code-protect. copying. There are people who claim to be able to A common use of the ID bytes is to hold the name or name and revision level of read any code-protected a program. The ID bytes of a microcontroller can be read by a programmer, letting microcontroller. you know at a glance what the chip is programmed to do.

The ORG Directive

ORG 00h ;Reset Vector location

The ORG directive tells the assembler where in ROM memory to begin placing The ORG directive can also instructions. It is the ORiGin for all subsequent code. We place the origin at location specify the origin of the 00h because the mid-range PIC-micro™ family always executes the instruction at RAM register memory. location 00h after a power-up or reset. Location 00h is called the Reset Vector.

Chapter 5 ©1998 Sirius microSystems Microchip Code 47 Writing a Simple Program Location 04h is the Interrupt Vector. The microcontroller will execute the in- Program ROM struction here if an interrupt is generated. It’s good practice to leave location 04h free 0000 GOTO 05 so that you can add interrupt capability to your programs at a later date. This pro- 0001 gram jumps past the Interrupt Vector and begins at location 05h. 0002 0003 0004 ORG 00h ;Reset Vector location GOTO Initialize ;Start program after Interrupt vector 0005 BSF RP0 0006 CLRF TRISB ORG 05h ;One location past Interrupt vector 0007 BCF RP0 Initialize BSF RP0 ;Select memory register page 1 0008 MOVLW 0101.. CLRF TRISB ;Make Port B output by clearing TRISB 0009 MOVWF PortB BCF RP0 ;Go back to register page 0 000A SLEEP 000B The GOTO Initialize instruction has been stored in location 00h because it is the 000C next instruction following the ORG 00h directive. Therefore, the first instruction executed by the microcontroller at power-up or after a reset is not ORG 00h, but GOTO Initialize. Remember, ORG 00h is an assembler directive, not a microcon- troller instruction. 03FE 03FF The assembler would normally place the next instruction after GOTO Initialize in location 01h, the next available memory location. The microcontroller, however, This memory map shows has jumped to a location pointed to by the label Initialize. Since ORG 05h precedes where instructions would the Initialize label, the memory location 05h contains the BSF RP0 instruction, and load into program ROM is the location of the next instruction to be executed.

Program Code

Initialize BSF RP0 ;Select memory register page 1

CLRF TRISB ;Make PortB output by clearing TRISB BCF RP0 ;Go back to register page 0 The three instructions following the Initialize label set Port B of the microcon- troller as output.

The P84.INC file knows First, BSF RP0 (Bit Set in File Register, Register Page Select Bit 0 in the Status that RP0 is the fifth bit of Register) sets RAM register page 1 as the active page (refer to the PIC16F84 block the Status register and diagram on page 17). Then, CLRF TRISB (Clear File Register, in what Microchip automatically substitutes calls the Port B Tristate Register) clears the Port B data direction register, making this location for any Port B an output port. A zero bit in a data direction register makes that port bit an reference to RP0. P84.INC output. Similarly, a one bit in a data direction register makes that port bit an input also substitutes a file register location for the (0=Output, 1=Input). Finally, BCF RP0 (Bit Clear in File Register, Register Page data TRISB. Select Bit 0) sets the RAM register page 0 as the active page.

Main MOVLW 01010101b ;Move 01010101b into W and MOVWF PORTB ;output pattern to LEDs on Port Once again, the P84.INC file knows the file register Main is a label that is commonly assigned to the first line of program code. The location of Port B and lines following the Main label move a constant into Port B which light the LEDs in substitutes this into the an alternating on-off pattern. program during assembly.

Examining the Program 48 Microchip Code ©1998 Sirius microSystems MOVLW 01010101b (Move Literal into Working Register) moves the binary number 01010101 into the Working Register. The PM assembler also accepts hexa- decimal and decimal numbers. The equivalent commands would be MOVLW 55h or MOVLW 85. Remember that a hex number beginning with A through F must have a preceding zero in order not to be interpreted as a label by the assembler.

MOVWF PORTB (Move Working Register to File Register, Port B) copies the 01010101 W Port B number in the Working Register to the Port B File Register. The Port B file register is connected to the LEDs (refer to the schematic on page 26).

Done SLEEP ;Stop executing the program

Since our program is now finished, we tell the microcontroller to stop executing instructions. Notice that the SLEEP instruction requires no data. The SLEEP com- mand maintains all active outputs but stops program execution by stopping the microcontroller clock. Power requirements during sleep mode are minimal.

Ending the Editing Process

To exit the EDIT program, select Exit from the File menu.

If you inadvertently made any changes to the program, EDIT will ask you if the changes should be saved. Select No to keep the original program intact.

The next step in the programming process is assembling the source code file to produce an object code file. After the object code file is created, it can be downloaded to the microcontroller. Chapter 6 will lead you through program assembly, and Chapter 7 shows you how to download your program to the microcontroller.

Chapter Summary

Source code is a text file that contains microcontroller instructions and assem- bler directives. Recall from Chapter 2 that source code is the code from which the list file and object code are derived.

Directives are assembler instructions which set device parameters and memory locations. Directives are not stored in memory, but are used by the assembler and programmer. Instructions and their data make up the program that will eventually be stored in memory, and define what the microcontroller will do.

Labels can be used to differentiate program parts or subroutines, and comments should be used to make the instructions and routines more understandable.

Chapter 5 ©1998 Sirius microSystems Microchip Code 49 Writing a Simple Program Questions

1. What is the difference between a directive and an instruction?

2. What are the requirements for a label field?

3. Must comments be placed in the comment field?

4. Why can we not make the directive ORG 05h the first line of code?

5. What is the result of omitting the SLEEP instruction at the end of the pro- gram?

Assignment

1. Follow the steps below to write a simple program which illuminates the first four LEDs (RB0 to RB3). Save the program as TOPFOUR.ASM and set the microcontroller ID locations to ‘TOP4’.

Step 1. Start the EDIT program. Step 2. Enter the program comment and Device directives. Step 3. Examine OUTPUT.ASM and the schematic diagram on page 26 to determine the commands needed to illuminate the top four LEDs. Step 4. Save your program using the Save As option from the File menu.

As you continue to program you will become more comfortable with the assembly instructions. Really! Flip to the Data Sheets to see all of the other instructions you don’t yet know.

BSF RP0 CLRF TRISB BCF RP0 MOVLW 01010101b MOVWF PORTB SLEEP... the only thing I understand is SLEEP!

Questions 50 Microchip Code ©1998 Sirius microSystems Assembling 6 a Program

The function of an Assembler is to convert text source code into numeric ma- chine language instructions for the microcontroller. For example, the hexadecimal digits 2805h represent the GOTO Initialize statement in the program, below. Al- though we understand the meaning of the instruction GOTO Initialize, the microcontroller understands only the numeric instructions contained in the object code.

ORG 00h ;Reset Vector location GOTO Initialize ;Start program after Interrupt vector All programs can be found in the Pull-Out Program ORG 05h ;One location past Interrupt vector References section. Initialize BSF RP0 ;Select memory register page 1 CLRF TRISB ;Make Port B output by clearing TRISB From OUTPUT.ASM in Chapter 5.

The assembler program converts your source code to object code in two passes. During the first pass the assembler checks for correct instruction syntax, duplicate label names, and assigns numeric values to symbols. In the example above, the label Initialize is replaced with the numeric address 05h during assembly. During the sec- ond pass, the assembler converts all instructions to their numeric machine codes.

Assembling the Program

Follow the steps, below, to assemble the OUTPUT.ASM source code from Chapter If you have not installed 5. From the MS-DOS prompt, change to the PICMDS directory by typing: the PIC-MDS software, do so now. See the Quick Start! sheet for details. cd \picmds [enter] The assembler program is called PM.EXE. The batch file ASM.BAT calls PM.EXE using default settings. Typing ASM filename will assemble the program. Assemble OUTPUT.ASM by typing:

asm output [enter] Chapter 6 ©1998 Sirius microSystems Microchip Code 51 Assembling a Program Your screen should display the following:

C:\PICMDS>asm output When ASM.BAT calls PM, C:\PICMDS>pm -l output the -l option creates a List PICmicro Macro Assembler 3.01, (C) 1995, 1998 microEngineering Labs, Inc file. See Appendix C for 11 words used more assembler options. C:\PICMDS>

The assembler has created two new files from your source code: the assembly listing, OUTPUT.LST, and the object code, OUTPUT.HEX. Let’s examine the list file first. Type the following to start the MS-DOS editor:

C:\PICMDS>edit output.lst [enter]

Notice that the List file contains a copy of your source code file along with three extra columns of text. The assembler PM.EXE numbers every line of source code, and identifies each memory address and its contents. If there were any errors during assembly, PM would report the line number at which the error occurred.

34 ;Requirements 35 36 ; This is a simple program that requires no prior setup. 37 38 39 Maclib ‘PF8x.INC’ ;Library file for PIC16C84 and PM assemble 40 ;Comment this line out for other assembler Line number 41 42 Device PIC16F84,HS_OSC,WDT_OFF,PROTECT_OFF,PWRT_ON 43 =554F ID ‘OUTP’ 44 Address 45 ORG 00h ;Reset Vector location 46 0000- 2805 GOTO Initialize ;Start program after Interrupt vec 47 48 ORG 05h ;One location past Interrupt vecto 49 50 0005- 1683 Initialize BSF RP0 ;Select memory register page 1 Address Contents 51 0006- 0186 CLRF TRISB ;Make Port B output by clearing TR 52 0007- 1283 BCF RP0 ;Go back to register page 0 53 54 0008- 3055 Main MOVLW 01010101b ;Move 01010101b into W and 55 0009- 0086 MOVWF PORTB ;output pattern to LEDs on Port 56 57 000A- 0063 Done SLEEP ;Stop executing the program

Assembling the Program 52 Microchip Code ©1998 Sirius microSystems The first item in the address column (=554F) is not an address at all. It is pro- grammer information representing the microcontroller type. Addresses are not pre- Program ROM ceded by an equal sign. 0000 2805 0001 Notice that the address and address content areas of comments and directives 0002 (such as Device or ORG 00h) are blank. Directives and comments do not generate instructions or associated data for the program ROM. Remember, directives are in- 0003 structions for the assembler, not instructions for the microcontroller. 0004 0005 1683 The first generated address is on line 46 of the list file and contains 2805h. 2805h 0006 0186 is the machine code equivalent of GOTO Initialize. By examining the List file, you 0007 1283 can see each machine code instruction and its exact location. The memory map at 0008 3055 right graphically shows the ROM addresses and contents. 0009 0086 000A 0063 The list file demonstrates the result of the ORG directives. For example, the 000B ORG 05h directive on line 48 generates no instruction for the program ROM. Rather, 000C it tells the assembler that the next instruction (BSF RP0, or 1683h) should be placed in location 0005h.

BSF RP0 also has the label Initialize associated with it. The assembler will assign location 0005h to this label on the first assembly pass. During the second 03FE pass, any instructions which reference Initialize will be replaced with 0005h. For 03FF example, GOTO Initialize in line 46 converts to GOTO (28) Initialize (05). The OUTPUT.ASM pro- Some patterns in the list file are obvious. 28xx is the machine code for GOTO, gram loads into the PICs and xx86 alters RP0. The job of the assembler is to convert all of the mnemonics to memory as shown above. numeric machine code. These numbers represent our program. In fact, numbers are the only thing the microcontroller understands. Before assemblers, programmers would painstakingly convert each mnemonic to a machine code number by hand. This brings a whole new meaning to the phrase ‘some assembly required’!

Microhard Inc. Assembly by . the NumbersTM cordless assembler

A typical day in the life of a programmer at MicroHard Inc., where their corporate motto is: “If it’s hard to understand, it’s ‘cause we programmed it by hand!” Chapter 6 ©1998 Sirius microSystems Microchip Code 53 Assembling a Program Object Code

The object code is the other file created by the assembler. Object code is the numeric form of your program saved in ASCII format. The EPIC programmer uses this object code to program the microcontroller.

If you were to examine the object code file, you would see the numeric instruc- tion equivalents that make up your program.

Type ‘edit output.hex’ from the MS-DOS prompt to examine the object code file. Since object code is only used by programmer/ downloaders, we won’t spend too much time looking at it.

If you examine the numbers carefully, you’ll find the 2805 (GOTO Initialize) and the 1683 (BSF RP0), etc. The object code is stored in an Intel Merged Hex format with the low byte followed by the high byte (so 2805 becomes 0528). Pro- grammer information and checksums are interspersed throughout.

PM can also generate binary output, map and symbol files. If you need to know more about these options, see Appendix C for the details.

Chapter Summary

The function of an assembler is to convert text source code mnemonics into numeric machine codes. The machine codes generated by the assembler are found in both the listing and object code files.

Listing files can be used to verify the location of instructions and their addresses.

Object code is used by the programmer to download your program into the mi- crocontroller.

Object Code 54 Microchip Code ©1998 Sirius microSystems Questions

1. What is the function of an assembler?

2. How does the assembler generated list file differ from the source code file?

3. Why is the ‘GOTO Initialize’ in line 46 of OUTPUT.ASM a better way of coding than ‘GOTO 05h’?

4. Why does the assembler read your source code two times?

5. What address does the assembler assign to the label ‘Main’ on line 54?

Assignment

1. Following the steps described earlier, assemble TOPFOUR.ASM. Examine the list file. How many instructions were produced?

Chapter 6 ©1998 Sirius microSystems Microchip Code 55 Assembling a Program Notes 56 Microchip Code ©1998 Sirius microSystems Downloading 7 a Program

The next—and long awaited step after writing the program source code and assembling it to product object code—is to download our object code into the micro- controller. Once this is done, we can see the program at work.

Which Microcontroller Should I Program?

The PIC-MDS Professional system comes with both the PIC16C711 and PIC16F84 microcontrollers, but is capable of programming any of the 18-pin mid- range (16Cxx series) PICmicro™ microcontrollers. The PIC-MDS Hobbyist sys- tems include only the PIC16F84 microcontroller. Since you will be writing and test- The older PIC16C84 and ing a number of programs in the next few chapters, you will need at least one eraseable the PIC16F84 are electri- PIC. The PIC16F84 is EEPROM-based (Electrically Eraseable Read Only Memory) cally compatible and can and can be quickly and easily erased while in-circuit. be used interchangeably.

If you need analog input capability, you may want to use the EPROM-based When using an EPROM PIC16C711 or one of the other PIC16Cxx family. These microcontrollers are avail- microcontroller with a able in OTP (one time programmable) and windowed versions. Make sure that you window, always cover the use one in a ceramic package with a window as specified by the -JW suffix in the part window after programming. number. Otherwise, you will know exactly what Microchip means by one time pro- Because silicon is photo- sensitive, light striking the grammable! To erase EPROM microcontrollers, you will need an uv (ultraviolet chip die through the light) EPROM eraser. UV erasers are available from most electronic distributors. window can affect the microcontroller’s opera- tion. Black electrical tape Programming is an opaque and easily removable window cover- We will program a PIC16F84 with the OUTPUT program we just assembled. ing. At this time, connect the EPIC programmer to your personal computer’s with a 25-pin male to female DB-25 cable, and attach the 12 VAC wall adapter. Make sure that the EPIC programming socket is empty until the programming soft- ware is executed. Also be sure that the EPIC Programmer is placed on an insulated surface to prevent the circuit traces and pins on the bottom of it from shorting to each other. Chapter 7 ©1998 Sirius microSystems Microchip Code 57 Downloading a Program The EPIC programmer can be operated from batteries instead of using the 12 VAC wall adapter. If you choose to power the EPIC Programmer with two 9 volt batteries, plug each battery onto the battery snaps. Connect the 2 pin shorting jumper to the 2 pin “Batt ON” jumper. It is a good idea to check the battery voltage from time to time, especailly if you are having difficulty programming parts.

WARNING: Do not connect a battery across the centre snaps. Doing so shorts out the battery and may cause it to explode.

The EPIC programmer can program 18-pin mid-range PICs either in its own programming socket, or through the microcontroller socket of the PIC-MDS. Pro- gramming PICs in the PIC-MDS requires that you plug in the wall adapter and that you connect the 10-pin programming ribbon cable to the EPIC programmer. The cable attaches to the PIC-MDS in only one way. However, make sure that the cable connects to the EPIC programmer properly, as shown in the photograph below:

JU3, the RUN/PROGram jumper near the program- ming header on the PIC- MDS should remain in the RUN setting during programming. This isolates the power supplies of the PIC-MDS and EPIC and prevents the EPIC from having to power the PIC- MDS.

On both the PIC-MDS and EPIC, pin 1 of the programming ribbon cable header is at the lower left when the writing on the boards is upright. Make sure that you connect the EPIC end of the ribbon cable properly, with pin 1 of the cable closest to the word programmer.

The programmer should now be powered up and ready to program your PIC. Note that the EPIC LED may be lit at this point. This is no cause for alarm. The LED should go out as soon as the EPIC programming software is started. Do not insert or remove a microcontroller from the EPIC or PIC-MDS when the LED is on.

Programming 58 Microchip Code ©1998 Sirius microSystems Downloading the Object Code

From the MS-DOS prompt, start the EPIC program by typing:

epic output.hex [enter] Your computer screen should look like the one shown below:

If you see a message stating ‘Programmer not Found’, press and hold the RESET button on the PIC- MDS while selecting Retry. On start-up, EPIC checks for the presence of a PIC. If the PIC is blank, all I/O pins are inputs and the check completes properly. If the PIC has previously been programmed and PORTB.6 and PORTB.7 were set as outputs, the check will fail. Holding RESET forces all I/O pins to input and lets EPIC find the programmer.

Your program object code will be visible in the blue portion of the screen, along with the address locations of the fist instruction of each line of object codes. Along the right, in the turquoise section of the screen are the configuration fuses settings selected by the Device directive in your program. These settings are the defaults for the OUTPUT program, but can be changed by clicking on them with a mouse. Chap- ter 3 and the PIC data sheets explain all of the configuration fuse meanings.

We’re now ready to program a PIC16F84. Place the PIC16F84 into the pro- gramming socket of the PIC-MDS with pin 1 at the top-left. Before starting to pro- gram the PIC, make sure that the EPIC Device section matches the one in the dia- gram, above.

Select the Program button now. The EPIC software reads all of the PICs memory Any of the grey buttons on locations to verify that it really is blank, and then programs it. If the PIC in the the EPIC screen can be programming socket contains a previous program, EPIC warns you of this and asks selected with the mouse or if the PIC should be programmed anyway. Select ‘OK’ to continue programming. by pressing and holding the Alt key along with the highlighted letter of the A few second later, you will see the message ‘Programming Complete’ at the button. bottom of the blue section of the screen.

As the microcontroller gets programmed, EPIC verifies the contents of each memory location by reading the the memory location and comparing its contents to the original object code. If the instruction from the memory location and does not match the object code, a problem has occurred and EPIC produces a verify error. You may also use the Verify command to compare the memory of a PIC with an object code program at any time.

Chapter 7 ©1998 Sirius microSystems Microchip Code 59 Downloading a Program Running the Program

If you programmed the PIC while in the PIC-MDS, the PIC will execute the program as soon as programming has stopped. If you programmed the PIC in the EPIC programmer, gently pry the PIC from the programming socket, insert it into the PIC-MDS and apply power by connecting the plug from the wall adapter. If you don’t see the proper You should immediately see the binary number 10101010 displayed on the eight display, try pressing the RESET button. While LEDs. Congratulations on writing, assembling and programming your first PIC RESET is pressed all LEDs microcontroller program! should be on. If this doesn’t happen, or the output pattern is not displayed Reprogramming PIC Microcontrollers upon releasing RESET, see Appendix B, Troubleshoot- As you progress through this text, you will need to reprogram your PIC. If you ing. leave the PIC16F84 in the microcontroller socket of the PIC-MDS you can effort- lessly program it with new programs. The only exception, of course, is programs requiring analog input. The PIC16C711 can be programmed while in the PIC-MDS but must be removed for erasure under ultraviolet light.

Chapter Summary

Programming a microcontroller requires that the object code program be downloaded to the microcontroller. Downloading is most easily accomplished by connecting the EPIC programmer to the PIC-MDS through the programming ribbon cable. Remember to press and hold the RESET button if you get a ‘Programmer not Found’ error when starting EPIC. After programming, the PIC immediately executes the program.

Running the Program 60 Microchip Code ©1998 Sirius microSystems Questions

1. What precautions must be taken before placing a PIC into the EPIC program- mer?

2. When is erasing necessary?

3. How is the PIC16C711 erased?

Assignment

1. Erase and program your microcontroller with both the TOPFOUR program that you wrote and assembled previously. Verify its operation by running the program in the PIC-MDS board.

Remember to put your PIC into the programming socket the right way around, or you’ll find out why programming is also nicknamed “burning”!

Chapter 7 ©1998 Sirius microSystems Microchip Code 61 Downloading a Program Notes 62 Microchip Code ©1998 Sirius microSystems 8 Looping

One of the most fundamental programming concepts is looping. If you’ve pro- grammed in BASIC or another high level language you’re probably familiar with the concept. Basically, looping allows a programmer to repeat code again and again. Loops can go on forever (infinite) or they can repeat a finite number of times. We’ll first examine infinite loops.

Infinite loops

Infinite loops do not end and have the following structure:

This is an example of Pseudo-code. Pseudo-code Start code, is code programmers write more code, and still more code to identify the flow and Go to Start structure of programs.

Microcontroller programs almost always have this basic structure. Remember that microcontrollers run a program designed for a specific purpose. Most microcon- troller applications involve monitoring and controlling a continuous process. In order to keep the program running continuously a GOTO instruction is often used to tell the microcontroller to repeat code from the beginning of the program.

For example, the microcontroller in a computer mouse will check the button and roller positions and send this information to a personal computer. The simplified pseudo-code for the mouse might look like:

Start Send button 1 state Send button 2 state Send X roller motion Send Y roller motion Go to Start

Chapter 8 ©1998 Sirius microSystems Microchip Code 63 Looping Let’s look at a simple program which demonstrates an infinite loop. The pro- gram COUNT.ASM sequentially displays the binary numbers from 0 to 255 on the LED bar graph display. The count will repeat as the Port B register ‘rolls-over’ from 255 to 0, very much like a car odometer. The pseudo-code for COUNT.ASM is:

Initialize Set Port B for output Clear Port B

Loop Increment Port B Go to Loop

You may wish to pull out the program COUNT.ASM from the Pull-Out Pro- gram References Section as we describe it.

Maclib ‘P84.INC’ ;Library file for PIC16C84 and PM assembler ;Comment this line out for other assemblers

Device PIC16C84,HS_OSC,WDT_OFF,PROTECT_OFF,PWRT_ON ID ‘CNT ‘

ORG 00h ;Reset Vector location GOTO Initialize ;Start program after Interrupt vector

ORG 05h ;One location past Interrupt vector

The program begins with the familiar Maclib, Device and ID directives. These are followed by the ORG 00h and GOTO Initialize instructions that form the Reset code of many example programs (refer to Chapter 5 for more detail).

Initialize BSF RP0 ;Select memory register page 1 CLRF TRISB ;Make Port B output by clearing TRISB BCF RP0 ;Go back to register page 0 CLRF PORTB ;Turn off LEDs by clearing Port B

The Initialize routine prepares Port B for output and clears the LEDs.

Loop INCF PORTB ;Add 1 to Port B register GOTO Loop ;and do it again, and again...

Done SLEEP ;Stop executing the program

INCF PORTB (Increment the File Register, Port B) adds one to the contents of the Port B register. Since Port B is connected to the LED bar graph, the value in Port B immediately appears on the LEDs. GOTO Loop forms the infinite loop structure.

Assemble and download this program as you did with OUTPUT.ASM in Chap- To see the current count, ter 6 and Chapter 7. When the PIC microcontroller executes this program, all of the just remove the crystal LEDs will appear to be lit. Because there is no delay after the increment instruction, from its socket. This stops each count appears on the LED only for as long as it takes to execute the GOTO the clock and displays the Loop and the next INCF PORTB—about one-millionth of a second at a 10 MHz count. When you reinsert clock speed! the crystal, the program continues!

Infinite Loops 64 Microchip Code ©1998 Sirius microSystems Finite Loops

Finite loops execute a set number of times and can have two structures. The first checks for a condition, and either repeats or exits the loop based on the result of the conditional check. In pseudo-code:

Label code, more code, and still more code If condition, go to Label Otherwise, code, code, and more code

An example of this first structure might be a burglar alarm. The microcontroller might check a number of sensors, and if one or more are tripped sound an alarm. The pseudo-code follows:

Check If sensor 1 open, go to Alarm If sensor 2 open, go to Alarm If sensor 3 open, go to Alarm Go to Check

Alarm Activate Siren If correct code entered, go to Alarm_Off Go to Alarm

Alarm_Off Deactivate Siren Go to Check

The second structure requires a variable which is modified during loop execu- Of the 35 PIC mnemonics, tion. The modification of this variable should make a condition true or false. The 13 are commonly used to check for the condition should occur immediately after the modification because modify variables before subsequent instructions can affect this condition. Again, the microcontroller repeats making a decision based on or exits the loop based on the condition. The pseudo-code looks like: conditions. They are: ADDWF, ADNWF, COMF, DECF, DECFSZ, INCF, INCFSZ, IORWF, MOVF, Initialize variable RLF, RRF, SUBWF, and XORWF. See the PIC data Label code, sheets for more instruction more code, and still more code. details. Modify variable If condition, go to Label Otherwise, code, code, and more code

An example of this structure can be found in a digital clock. The Hours variable might be set to ‘12’ and the Minutes variable to ‘00’. Every 60 seconds, the Minutes variable is incremented. When the Minutes variable becomes ‘60’, it is reset to ‘00’ and the Hours variable is incremented. When the Hours variable becomes ‘13’ it is reset to ‘01’. The pseudo-code follows on the next page: Chapter 8 ©1998 Sirius microSystems Microchip Code 65 Looping Hours = 12 Minutes = 00

Main Wait 60 seconds Increment Minutes If Minutes = 60, go to Inc_Hours Go to Main

Inc_Hours Minutes = 00 Increment Hours If Hours = 13, go to Reset_Hours Go to Main

Reset_Hours Hours = 01 Go to Main

The number of times that this second type of finite loop structure executes can be accurately determined. For this reason, it is found in timing and counting applica- tions. Contrast this with the first type of finite loop structure, which exits when a condition is true, rather than when a set number of loops has occurred.

Nested Loops

The program DELAY.ASM modifies COUNT.ASM to include a finite loop de- The total number of loops in a nested loop = inner lay routine. The finite delay includes a nested loop. A nested loop is a loop within a loops X outer loops. loop. The total number of loops executed in a nested loop is the product of the inner loop and the outer loop. This gives programmers the ability to easily execute more Nested loops are also than 256 loops. The inner loop executes 256 times (as does Port B in the COUNT.ASM useful for array or matrix program) and the outer loop executes once for each time the inner loop cycles through applications. For example, 256 loops. In the DELAY.ASM program, the outer loop variable, Counter2, decre- keeping track of keyboard ments 256 times resulting in a total loop count of 65 536 loops (256 X 256) before rows and columns. incrementing the count on the LEDs. In pseudo-code:

Initialize Clear Counter1 and Counter2 Set Port B for output Clear Port B

Main Increment Port B

innerLoop loop Decrement Counter1 If Counter1 > 0, go to Loop outer loop Decrement Counter2 If Counter2 > 0, go to Loop Go to Main

You may find it useful to pull out DELAY.ASM from the Pull-Out Program References Section as we examine DELAY.ASM in detail.

Actually, labels are sym- After the directives, you’ll notice the Hardware Equates comment. The EQU bols—they are assigned a (EQUate) directive, assigns values to labels and symbols. A label is a memory loca- numeric address value by tion that the program can jump to, and a symbol is simply characters which have the assembler during been assigned a numeric value. assembly.

Finite Loops 66 Microchip Code ©1998 Sirius microSystems ;Hardware Equates An ‘=’ can be used in Counter1 EQU 0Ch ;First delay counter register place of the EQU directive. Counter2 EQU 0Dh ;Second delay counter register

At assembly time, the equate statement assigns the value 0Ch to the symbol Counter1, which is also the first unused address location in the RAM register file. Similarly, 0Dh is assigned to the symbol Counter2.

Don’t confuse Program memory locations 000Ch and 000Dh with RAM Register File locations. The Program memory contains only program instructions, not the variables used by programs.

The variables Counter1 and Counter2 will be stored here.

The equates section is followed by the initialization code commonly used in pre- vious example programs.

Initialize BSF RP0 ;Select memory register page 1 CLRF TRISB ;Make Port B output by clearing TRISB BCF RP0 ;Go back to register page 0 CLRF PORTB ;Clear Port B register CLRF Counter1 ;Clear Counter1 register (0Ch) CLRF Counter2 ;and Counter2 register(0Dh)

The initialize routine prepares Port B for output, clears the LEDs, and clears the Counter1 and Counter2 variables. When power is applied to the microcontroller, the unused RAM file registers are not automatically cleared to zero. They contain ran- dom data and should be cleared before use.

Chapter 8 ©1998 Sirius microSystems Microchip Code 67 Looping Main INCF PORTB ;Add 1 to Port B register Loop DECFSZ Counter1 ;Decrement Counter1 and check for 0 GOTO Loop ;If not 0, decrement Counter 1 again DECFSZ Counter2 ;If 0, decrement Counter2 GOTO Loop ;If Counter2 is not 0, decrement ;Counter1 another 256 times GOTO Main ;Update the LEDs after 65536 counts INCF PORTB (Increment the File Register, Port B) adds one to the contents of the Port B register. Since Port B is connected to the LED bar graph, the value in Port B immediately appears on the LEDs.

DECFSZ Counter1 (Decrement File Register, Counter1, and skip the next in- DECFSZ and INCFSZ are struction if zero) is a combined variable modification and jump instruction. Since commonly used for loops. this is a common loop structure, Microchip includes a number of single instruction words which accomplish both the modification and jump functions.

Before DECFSZ Counter1 executes, Counter1 contains the data 00h (it was cleared in the initialize section). When DECFSZ Counter1 executes for the first time, Counter1 will contain FFh (a decrement from 00h causes a roll-back to FFh). Since FFh is not equal to zero, the GOTO Loop instruction which follows is not skipped. This inner loop will continue until Counter1 equals 0—256 loops later. When Coun- ter1 finally reaches zero, the DECFSZ Counter1 (Decrement File register, Counter1, and Skip the next instruction if the file register is Zero) skips the GOTO Loop in- struction and DECFSZ Counter2 is the next instruction to be executed.

When DECFSZ Counter2 executes for the first time, Counter2 contains the value FFh. Since FFh is not equal to zero, the GOTO Loop instruction which follows is executed next, which starts the inner loop a second time. After 256 more counts of the inner loop, Counter2 will decrement to FEh. For each decrement of Counter2, Counter1 has decremented 256 times.

Eventually, Counter1 and Counter2 both reach zero. In this case, the DECFSZ Counter2 instruction causes the microcontroller to skip the GOTO Loop instruction and GOTO Main is the next instruction to be executed.

Again, the total number of loops executed by a nested loop is inner loops X outer loops. In DELAY.ASM this nested loop takes a relatively long time and allows us see the transitions between successive LED increments.

Calculating Execution Times

The speed at which code executes is dependent on the oscillator clock speed and number of machine cycles executed. Instructions require either 1 or 2 machine cycles to execute. A machine cycle is an internal clock used by the PIC to synchronize internal events and is equal to four oscillator clock cycles. Therefore the period of one machine cycle equals 4 times the main oscillator period.

Clock Period Oscillator Clock One Machine Cycle Nested Loops 68 Microchip Code ©1998 Sirius microSystems Since, 1 Period = f

If the PIC-MDS clock oscillator frequency is 10 MHz, the oscillator period would be: 1 ¸ 10 MHz = 100 ns. A machine cycle would therefore take 4 X 100 ns = 400 ns.

The number of machine cycles needed to execute an instruction depends on the instruction type. Any instruction that modifies the program counter requires two machine cycles to execute. All other instructions require only one machine cycle. Let’s calculate the exact time taken by the nested loop in DELAY.ASM. Number of machine cycles

Main INCF PORTB ;Add 1 to Port B register 1 (2 if skip) Loop255 X DECFSZ Counter1 ;Decrement Counter1 and check for 0 GOTO Loop ;If not 0, decrement Counter 1 again 2 255 X DECFSZ Counter2 ;If 0, decrement Counter2 1 (2 if skip) GOTO Loop ;If Counter2 is not 0, decrement 2 ;Counter1 another 256 times GOTO Main ;Update the LEDs after 65536 counts 2

The inner loop will take three cycles to execute, and will execute a total of 255 times. The 256th time takes only two cycles, because the 00h result in Counter1 causes DECFSZ to modify the program counter. GOTO Loop is skipped.

The total number of machine cycles executed in the inner loop is:

(255 X 3) + 2 = 767

After 767 inner loop machine cycles, the outer loop adds three cycles to get back to the inner loop. The outer loop executes 255 times, including the inner loop. On the 256th loop, Counter2 will equal zero and the DECFSZ command will skip the GOTO Loop instruction, taking two cycles. Algebraically:

(255 X (767 + 3)) +2 = 196 352

Finally, GOTO Main adds another two cycles giving a total delay until the next increment of 196 354 machine cycles.

Since a 10 MHz clock produces a 400 ns machine cycle time, the overall delay between LED increments is:

196 354 cycles X 400 ns = 78.5416 ms (or a frequency of 12.7 Hz)

In COUNT.ASM, the number of machine cycles used to increment the LEDs is three. INCF PORTB requires 1 cycle, GOTO Loop requires two. This means that LEDs are updated every 3 X 400 ns = 1.2 ms (or at 833.3 kHz)!

The PIC16C711 supplied With a 10 MHz clock, the execution time of programs can be calculated down to with the PIC-MDS Profes- 400 ns periods. Although this level of accuracy is not always required, knowing how sional can be clocked at up to calculate cycle times exactly is crucial for timing sensitive applications. to 20 MHz, giving a 200 ns cycle time. That’s 5 million ! Chapter 8 ©1998 Sirius microSystems Microchip Code 69 Looping Chapter Summary

Loops are used to repeat commonly used sections of code and to count. Loops can be infinite, or be dependent on conditions. Finite loops deliberately modify a variable and branch depending on the occurance of a condition. Microchip provides a number of commands which combine variable modification with a conditional branch. Nested loops allow for the efficient execution of a large number of loops.

The time taken by loops is dependent on the instructions used and the number of machine cycles taken by those instructions. For the PIC microcontrollers, one ma- chine cycle is four times the oscillator clock period. Most instructions complete in one machine cycle. Those that modify the program counter always take two machine cycles to complete.

After much frustration, Suzette finally executes the looping of her code.

Chapter Summary 70 Microchip Code ©1998 Sirius microSystems Questions

1. Where in a program would you expect to find commands which form an infi- nite loop? Select from the following:

at the beginning near the middle near the beginning and end near the end really doesn’t matter, could be anywhere

Explain the reasoning you used to choose your answer.

2. Why do variables need to be initialized as part of a finite loop structure?

3. When does the DECFSZ instruction require 2 cycles? When does it require 1?

4. Examine the PIC16F8x Data Sheets and list all of the instructions that com- bine variable modification and conditional branching.

5. Draw arrows showing program flow in the BLIP.ASM code below. BLIP.ASM is supplied on the PIC-MDS disk so that 6. Calculate the length of time for each blip and the delay between blips. you can run it and see what it does.

;Hardware Equates Counter1 EQU 0Ch ;First delay counter register Counter2 EQU 0Dh ;Second delay counter register Counter3 EQU 0Eh ;Third delay counter register

ORG 00h ;Reset Vector location GOTO Initialize ;Start program after Interrupt vector ORG 05h ;One location past Interrupt vector

Initialize BSF RP0 ;Select memory register page 1 CLRF TRISB ;Make Port B output by clearing TRISB BCF RP0 ;Go back to register page 0 CLRF PORTB ;Clear Port B register CLRF Counter1 ;Clear Counter1 register (0Ch) CLRF Counter2 ;and Counter2 register (0Dh)

Main MOVLW 0FFh ;Load W with ones to turn on LEDs MOVWF PORTB ;and write to Port B register MOVLW 03h ;Load W with 3 MOVWF Counter2 ;and preset Counter2 before Loop_On

Loop_On DECFSZ Counter1 ;Decrement Counter1 and check for 0 GOTO Loop_On ;If not 0, decrement Counter1 again DECFSZ Counter2 ;If 0, decrement Counter2 GOTO Loop_On ;If not 0, do Counter1 loop

CLRF PORTB ;Turn off LEDs by clearing Port B MOVLW 0Dh ;Load W with 13 MOVWF Counter3 ;and preset Counter3 before Loop_Off

Loop_Off DECFSZ Counter1 ;Decrement Counter1 and check for 0 GOTO Loop_Off ;If not 0, decrement Counter 1 again DECFSZ Counter2 ;If Counter1=0, decrement Counter2 GOTO Loop_Off ;If not 0, do Counter1 loop DECFSZ Counter3 ;If Counter2=0, decrement Counter3 GOTO Loop_Off ;If not 0, do Counter1 & 2 loops From BLIP.ASM GOTO Main ;If 0, go to Main Chapter 8 ©1998 Sirius microSystems Microchip Code 71 Looping Assignment

1. Write a program which will sweep a single LED across the LED bar graph display continuously. (Hint: Look at the rotate instructions)

2. Modify the program, above, to sweep the LED back and forth across the LED bar graph display.

3. Write a program which will generate a 440 Hz, 50% duty cycle square wave on an output port pin. You can connect a piezo audio transducer (or a speaker in series with a 270 W resistor, or preferably a 1 mF capacitor) between the output port pin and ground on the screw terminal to hear this tone.

4. Write a program which will generate a beep every second. Make the beep duration 250 ms.

Assignment 72 Microchip Code ©1998 Sirius microSystems Switch Input 9 Programming

Microcontroller applications often depend on receiving and acting upon inputs. Many of these inputs come from other binary digital devices and are in the form of a voltage (0V or +5V) on an I/O pin. Common binary input devices include pushbuttons, Although the PIC-MDS key switches, rotary switches, rotary position encoders, slotted opto-isolators, ma- system uses +5V for its trix keypads, RS-232 transceivers, and infra-red remote receivers. power supply and logic high state, many of the PICmicro™ processors can run at 2-6V. We’ll repre- Interfacing to Switches sent this voltage as V+.

Switches represent one of the most common microcontroller interfaces. Most switches provide two contacts which close or open when activated. Normally open (N.O.) pushbuttons provide closed contacts when activated and normally closed (N.C.) switches provide open contacts when activated. Both types of switches can be used to “Active high” means that provide active high or active low inputs to a microcontroller. the PIC reads a high (V+) voltage when the switch is The diagram below shows how a normally open pushbutton can be wired to activated, and a low (0V) provide an active low input to a microcontroller. The pull-up resistor provides a logic voltage otherwise. Active low inputs are the opposite. one (or V+) level to the microcontroller input when the switch is not activated. When the switch is pressed, the switch connects the microcontroller input to ground. The pull-up resistor prevents the power supply (V+) from being shorted directly to ground.

Port B of the PIC16Cxx microcontrollers contains built-in, user controllable pull-up resistors. This keeps external part counts to a minimum. The nominal value of these internal pull- ups is 20 kW .

Chapter 9 - Switch ©1998 Sirius microSystems Microchip Code 73 Input Programming This next diagram shows how a normally closed pushbutton can be used to pro- vide a logic high level when activated. Once again, the pull-up resistor performs the same function of providing a logic high when the switch is open, and preventing a short circuit when the switch is closed.

Let’s look at the program ALARM.ASM which uses a piece of wire as a switch. An LED is turned on if the input wire is disconnected from ground. The structure of this program could be used as the basis of an alarm circuit. The pseudo-code for the program is as follows:

main if wire disconnected from ground, turn on LED and jump to main otherwise, turn off LED and jump to main

If the LED turns on, it indicates that someone has broken the alarm loop.

ALARM.ASM uses the programmable internal pull-up resistors on Port B. This means that an external pull-up resistor is not needed and allows a single piece of wire to act as our switch.

Interfacing to Switches 74 Microchip Code ©1998 Sirius microSystems Although they are a part of the PIC, our program must enable the pull-up resis- tors in order to use them. The pull-ups are only active when the port pin is an input. Output ports have no need for pull-ups unless they are open-collector outputs. PORTA.4 is the only open-collector output on the PIC16C711 and PIC16F84. RA.4 is pulled up by R3 in the PIC-MDS—a 4.7 kW Before running ALARM.ASM you resistor. See the schematic will need to make a connection to the PIC- in Chapter 4. MDS terminal strip (CON1) to create the alarm loop. Attach a wire to the PIC-MDS as shown so that CON1-9 (PortB.0) is con- nected to CON1-3 (GND). Remove the wire from either terminal to simulate the break- ing of the alarm loop.

You may wish to pull out the program ALARM.ASM from the Pull-Out Program References section as we describe it.

Remember, RP0 is the Initialize BSF RP0 ;Select register page 1 register page selection bit. MOVLW 00000001b ;Load W with desired I/O pattern Setting RP0 selects register MOVWF TRISB ;Move W to TRISB to make bit 0 input page 1. ;(1=input, 0=output) BCF RBPU ;Enable Port B pull-up resistors ;(OPTION.7 on register page 1) The symbol RBPU has been BCF RP0 ;Back to register page 0 assigned to be Option.7 by CLRF PORTB ;Turn off all LEDs the .INC file. The Initialize section of the program configures the PORTB tristate register, enables the pull-up resistors and turns off the LEDs on Port B. Note how the MOVLW 00000001b instruction sets only PORTB.0 as an input. The BCF RBPU (Bit Clear in File register, Port B Pull-Up enable) instruction clears bit 7 in the Option register. Clearing Option.7 enables the pull-up resistors on all Port B inputs.

Note that both TRISB and the OP- If you haven’t yet done so, TION register are on register page 1. Al- consider reading the though the TRISB and OPTION regis- Microchip data sheets now. ters are both on the PIC block diagram, They provide invaluable there is no indication of where the RBPU insight into the inner workings of the PICmicro™ bit is. RBPU is defined in the .INC file family of microcontrollers. as Option.7, but referencing RBPU does not automatically select register page 1. It is up to you to select register pages, so it is imperative to check the data sheets before using register bits that you are un- familiar with. As you gain more experi- ence with the PIC family, you will get a better idea of the location of key regis- ters and control bits.

Chapter 9 - Switch ©1998 Sirius microSystems Microchip Code 75 Input Programming Remember, the .0 in Main BTFSC PORTB.0 ;Check Port B bit 0 for a low PORTB.0 is Microchip’s GOTO LED_On ;If we’re here, bit 0 is high way of checking a single BCF PORTB.1 ;If bit 0 is low, turn off LED bit in a file register—not GOTO Main ;Check bit 0 again the whole register. LED_On BSF PORTB.1 ;Turn on LED on bit 1 GOTO Main ;Check bit 0 again

The Main routine of ALARM.ASM checks our wire and determines whether or not to light the LED. BTFSC PORTB.0 (Bit Test File register, Skip the next instruc- tion if Bit is clear) is a combination condition test and branch instruction, and checks the state of the input at Port B, bit 0. If the input is low—or clear, as it would be if the wire is connected—the GOTO LED_On instruction will be skipped, and the BCF PORTB.1 (Bit Clear File register, PORTB.1) instruction will be executed. Clearing Since PORTB.0 is an input, a Port B bit turns off the LED associated with it. This part of the program has one the LED connected to function: if the wire is connected from PORTB.0 to ground, the LED on PORTB.1 is PORTB.0 will show the turned off. state of the input wire. The LED on PORTB.1 shows If the wire is disconnected from ground, the input will be pulled high (or set) by the output from the PIC. the internal pull-up resistor, and the GOTO LED_On instruction will be executed next. The PIC jumps to the BSF PORTB.1 (Bit Set File register, PORTB.1) instruc- tion and lights the LED on Port B.

Assemble and download the program ALARM.ASM and verify that it works.

Counting Switch Activations

Counting how many times an event has occurred is another common microcon- troller application. Programs which count how many times a switch has been pressed must take into account one significant characteristic of many switches, namely con- tact bounce. Every time switch contacts close, they may make and break many times before settling down to their final state. The duration of each contact bounce depends on the switch but can be up to a few milliseconds. Remember that instructions take Software switch de-bounc- only 400 to 800 ns to execute at a 10 MHz clock rate (see Chapter 8). Since the ing is cheaper than hard- microcontroller can easily execute over 2000 instructions per millisecond it is fast ware solutions. enough to count each contact bounce as a switch closure. To avoid this, a short software delay is used to de-bounce the switch, and count only one switch closure.

Contact Bounce

V+

V+

0 V

Pressed Released

This diagram represents typical switch contact bounces. Your results may vary—widely!

Counting Switch Activations 76 Microchip Code ©1998 Sirius microSystems BOUNCE.ASM is a program which will count the number of times a switch bounces. Program a PIC16F84 with BOUNCE.ASM. BOUNCE.ASM uses PORTA.4 as the input and displays the Wait! Since the PIC only number of bounces on the LEDs in binary. has built-in pull-ups on Before running BOUNCE.ASM, connect Port B, and BOUNCE.SRC a wire or switch to ground (CON1-3) and uses Port A, don’t we need PORTA.4 (CON1-8). The program dis- a pull-up resistor? Yes, and plays a cumulative count of each switch PORTA.4 is pulled up by contact bounce to ground. To reset the count R3 on the PIC-MDS—a 4.7 to zero, press the RESET button on the kW resistor. See the sche- PIC-MDS. matic in Chapter 4.

You should notice that a wire connecting PortA.0 to ground bounces many times. Try a few different switches and note how many times they bounce.

Pull BOUNCE.ASM from the Pull-Out Program References section as we ex- amine how it works. The pseudo-code looks like this:

Initialize variables & ports

Main If PortA.4 is high, go to main Otherwise, increment Port B

Wait If PortA.4 is low, go to Wait Otherwise, go to main

Counting Contact Bounce

V+

V+

0 V

Pressed Note that BOUNCE.SRC cannot just check for a low to increment Port B. It must wait until the input bounces high before counting the next low bounce.

Wait for Inc. Inc. Inc. Inc. Inc. activation count count count count count & wait & wait & wait & wait & wait for for for for for high high high high high

Chapter 9 - Switch ©1998 Sirius microSystems Microchip Code 77 Input Programming Initialize BSF RP0 ;Select register page 1 MOVLW 00010000b ;Load W with the desired I/O pattern MOVWF TRISA ;Make Port A bit 4 input ;(1=input, 0=output) CLRF TRISB ;Make Port B output BCF RP0 ;Back to register page 0 CLRF PORTB ;Turn off all LEDs

The Initialize section of the program configures the PORTA and B tristate regis- ters, and turns off the LEDs on Port B.

Main BTFSC PORTA.4 ;Check Port A bit 4 for a low GOTO Main ;If we’re here, bit 4 is high INCF PORTB ;If bit 4 is low, increment Port B

Wait_for_High BTFSS PORTA.4 ;Check Port A bit 4 for a high GOTO Wait_for_High ;If we’re here, bit 4 is still low GOTO Main ;Bit 4 went high, wait for next bounce

Main waits for PORTA.4 to go low before incrementing the count on Port B. Then the PIC then executes the Wait_for_High loop until PORTA.4 returns high.

BTFSC PORTA.4 (Bit Test File register, Skip the next instruction if bit Clear) will skip the GOTO Main instruction if PORTA.4 is low. A low on PORTA.4 repre- sents a contact bounce to ground. When this happens, INCF PORTB (Increment File register) adds one to the contents of Port B. Note that the Port B register not only connects to the LEDs, but is also used to store our count.

You can use BOUNCE.SRC After incrementing Port B, BTFSS PORTA.4 (Bit Test File register, Skip the to check switches for next instruction if bit Set) will execute GOTO Wait_for_High as long as PORTA.4 contact bounce by connect- remains low. When PORTA.4 goes high, BTFSS PORTA.4 will skip GOTO ing a switch between Wait_for_High and GOTO Main will execute next, repeating the program. PORTA.4 and ground. Some switches rarely bounce while others may bounce more than ten Switch Debouncing times. If our applications are going to use switches, our programs obviously need to be able to accommodate the contact bouncing that occurs. The software method of switch debouncing involves waiting for a switch activation, and then pausing for a few milliseconds before checking to see if the button is still activated. By that time the contacts should have settled down and the activation can be sensed by the program. Noise can be generated by If the code finds the switch is not activated when it checks for the second time, the electrostatic discharge first detection was likely noise and should not be registered as a switch activation. (ESD) from people, or can be induced from high DBOUNCE.ASM demonstrates switch debouncing. The pseudo-code is: currents being switched nearby. Microchip recom- mends 100 W series resistors on inputs to Initialize variables & ports keyswitches for ESD protection. Main If PortA.4 is high, go to main Otherwise, execute debounce delay If PortA.4 has returned high, go to main Otherwise, increment Port B Go to main Switch Debouncing 78 Microchip Code ©1998 Sirius microSystems DBOUNCE.ASM uses the same connections as BOUNCE.ASM. Assemble, download and execute DBOUNCE.ASM to verify its operation. You should be able to quickly touch and release the wire (or a switch) to PORTA.4 (CON1-8) and cause Port B to increment only once.

Pull out DBOUNCE.ASM as we examine it, below:

;Hardware Equates

Counter1 EQU 0Ch ;First delay counter variable Counter2 EQU 0Dh ;Second delay counter variable

ORG 00h ;Reset Vector location GOTO Initialize ;Start program after Interrupt vector

ORG 05h ;One location past Interrupt vector The Equates section assigns register file locations to our two delay counter vari- ables. The standard Reset Vector code follows the equates.

Initialize BSF RP0 ;Select register page 1 MOVLW 00010000b ;Load W with the desired I/O pattern MOVWF TRISA ;Make Port A bit 4 input ;(1=input, 0=output) CLRF TRISB ;Make Port B output BCF RP0 ;Back to register page 0 CLRF PORTB ;Turn off all LEDs CLRF Counter1 ;Clear location Counter1 (0Ch) MOVLW 40h ;Load W with preset for counter 2 MOVWF Counter2 ;Store W to Counter2 (0Dh)

Initialize configures the Port A and B tristate registers, setting PORTA.4 as input and all of PORTB as output.

Counter1 and Counter2 are set to 00h and 40h, respectively. This provides an overall loop delay of 64 (40h) loops of 256. Counter1 decrements from 00h, to FFh, then FEh, and so on back to 00h, providing 256 inner loops.

Main BTFSC PORTA.4 ;Check Port A bit 4 for a low GOTO Main ;If we’re here, bit 4 is high Main waits for PORTA.4 to drop low. When it does, the GOTO Main instruction is skipped and the Delay subroutine code executes.

Delay DECFSZ Counter1 ;If we’re here, bit 4 is low GOTO Delay ;Let’s wait at least 20 ms for the DECFSZ Counter2 ;contacts to settle GOTO Delay

MOVLW 40h ;Once delay is done, reset counter 2 MOVWF Counter2 ;Store W to Counter2 (0Dh)

The Delay routine is a two-level deep nested loop that executes 16 384 times, wasting 48 512 processor cycles. At a 10 MHz clock speed this provides a delay of approximately 19.4 ms—a typical debounce delay time. When the delay loop is com- pleted, Counter2 is re-initialized by MOVLW 40h and MOVWF Counter2 so that it restarts from 40h rather than 00h. Chapter 9 - Switch ©1998 Sirius microSystems Microchip Code 79 Input Programming BTFSS PORTA.4 ;Is Port A bit 4 still low? INCF PORTB ;If so, increment Port B Wait_for_High BTFSS PORTA.4 ;Wait for Port A bit 4 to go high GOTO Wait_for_High ;If low, keep checking GOTO Main ;If high, go back to Main BTFSS PORTA.4 checks the input, and only increments Port B if PORTA.4 is still low after the debounce delay. Next, the BTFSS PORTA.4 after the Wait_for_High label causes GOTO Wait_for_High to be executed while PORTA.4 is low. Only when PORTA.4 goes high will GOTO Main be executed.

Interfacing to Matrix Keypads

Matrix keypads are wired in a row-by-column arrangement in order to reduce the number of input/output lines needed to interface them to a microcontroller. In a non-matrix keyboard each button requires its own input line. A matrix keypad is organized such that each key connects to a row and column in a matrix of wires. The number of lines needed for the matrix keypad is equal to the sum of the columns and the rows. The number of switches that can be connected in a matrix is the product of columns and rows.

Rows Cols. Sw. Lines Matrix Keypad 2244 2365 3396 34127 44168 45209 ... etc.

Note that for fewer than four switches there are no input/output line savings when using a matrix.

The software technique used to scan matrix keypads connected to microcontrol- lers involves the use of both input and output signals. The rows are connected to the output pins, and the columns to the inputs. A ‘0’ output is placed on one row, and ‘1’s are placed on the remaining rows. If a key in the ‘0’ row is pressed, the ‘0’ appears at Eight non-matrix switches the row-column intersection. Column inputs are scanned sequentially, looking for a require eight separate ‘0’. If no ‘0’ is found, the first row is set to a ‘1’ before the second row is lowered to lines—the same number ‘0’ and the columns are scanned again. used to interface sixteen matrix switches on the PIC- If a key in a row is not pressed, the input wires are effectively floating. For this MDS. reason, pull-up resistors are required to pull the inputs up to the power supply high level. The PIC’s programmable internal pull-ups allow us to interface to matrix keypads without adding any external components! Interfacing to Matrix Keypads 80 Microchip Code ©1998 Sirius microSystems The diagram shows an You could, conversely, example of key scanning. output on the columns and After making the top row scan the rows for a low and scanning the col- keypress. We don’t do this, umns, each of the inputs however, since the columns of the keypad in the PIC- would be sensed as a ‘1’ MDS are wired to the Port since none of the top row B pins which have interrupt keys are pressed. The pro- capability. gram would then advance the low to the second row.

As soon as the first column is scanned, the low will be sensed. The pro- gram now knows that the key at the intersection of row two, column one is being pressed.

The pseudo-code for a routine which will scan 16 keys, determine which was pressed, and assign a number to the key pressed looks like this:

Initialize variables and ports

Main Place a low on first row Set key counter to 1

Column_Check If column 1 low, go to Done Otherwise increment key_counter If column 2 low, go to Done Otherwise increment key_counter If column 3 low, go to Done Otherwise increment key_counter If column 4 low, go to Done Otherwise increment key_counter

Row_Set If key_counter > 16, go to Main Otherwise, set next row low Goto Column_Check

Done add any code that will use the key press value stored in key_counter The program KEYSCAN.ASM is a program which does just this and displays the key pressed on the LEDs as a binary number for approximately 0.5 seconds. A clever feature of this program is that is Port B is shared between the LEDs and keypad (see the schematic of the PIC-MDS in Chapter 4). Port B is reconfigured to Sharing two or more be an output port during the display phase, and half input and half output during devices on a microcontrol- keypad scanning. ler’s I/O ports is an effi- cient way of using I/O. The In order to protect two Port B outputs from being shorted by a key press, each PIC-MDS also shares Port row includes a series 2.2 kW resistor (see the schematic in Chapter 4). B with the LCD display. Chapter 9 - Switch ©1998 Sirius microSystems Microchip Code 81 Input Programming ; Col. 1 2 3 4 ; Row +----+----+----+----+ ; Port B.0----1--| 1 | 2 | 3 | 4 | The key numbers are ; +----+----+----+----+ assigned by the order in ; Port B.1----2--| 5 | 6 | 7 | 8 | which the matrix scanning ; +----+----+----+----+ takes place. ; Port B.2----3--| 9 | 10 | 11 | 12 | ; +----+----+----+----+ ; Port B.3----4--| 13 | 14 | 15 | 16 | ; +--+-+--+-+--+-+--+-+ ; Port B.4------+ | | | ; | | | ; Port B.5------+ | | ; | | ; Port B.6------+ | ; | ; Port B.7------+ The opening comments of KEYSCAN.ASM show the keypad row-column con- nections to Port B (as does the schematic) as well as the number assigned to each key.

;Hardware Equates

Counter1 EQU 0Ch ;Delay counter register Counter2 EQU 0Dh ;Delay counter register Counter3 EQU 0Eh ;Delay counter register Key EQU 0Fh ;This register will hold a number from ;0-15 representing the last key pressed

ORG 00h ;Reset Vector location GOTO Initialize ;Start program after Interrupt vector

ORG 05h ;One location past Interrupt vector The Hardware Equates section sets up variables for a delay counter and for the key return code. The standard reset code follows the variable equates.

Initialize BSF RP0 ;Select register page 1 MOVLW 0F0h ;Set keypad column connections to input ;(Port B.4-7) and row connections to ;output (Port B.0-3) MOVWF TRISB ;Write to Port B tristate register BCF RBPU ;Enable pull-ups on inputs BCF RP0 ;Go back to register page 0 CLRF Counter1 ;Clear delay loop counters CLRF Counter2 MOVLW 08h ;Preload Counter3 delay loop counter MOVWF Counter3 ;for 1/2 second delay Initialize sets half of Port B to input and the other half to output with the MOVLW 0F0h and MOVWF TRISB instructions. BCF RBPU enables the internal pull-ups, but they are only active on the input pins (PORTB.4-PORTB.7). Remember that pull-ups are needed to hold column inputs high when keys are not pressed. Next, the counter variables are cleared and pre-loaded as indicated by the comments in order to provide a half second display delay.

Main CLRF Key ;Clear Key register and INCF Key ;Increment Key MOVLW 0Eh ;Output 0 to first row only, MOVWF PORTB ;Output to Port B NOP ;Wait for signals to settle Main resets the Key register to one by using the CLRF Key and INCF Key Interfacing to Matrix Keypads 82 Microchip Code ©1998 Sirius microSystems instructions. The MOVLW 0Eh and MOVWF PORTB instructions place a low on PORTB.0, the top row of the keypad.

The NOP (No OPeration) instruction is very important, although it seems to do nothing. Whenever the state of an output pin is changed, time must be given for that Though BCF and BSF output to settle to the new value before the pin is read. The capacitance of a load on appear to be output an output pin requires time to charge or discharge to its new value. A NOP instruc- instructions, they are tion can provide a one cycle delay—long enough for an output to stabilize. Even very actually read-modify-write low I/O capacitances can introduce a read error because a port write occurs at the instructions. They read the very end of an instruction cycle, and a port read occurs at the very beginning of a entire port value, modify one bit, and write the value cycle. Therefore, any port write immediately followed by a port read should be sepa- back to the port. Separate rated from by a NOP or other non-port modifying instruction so the pin can settle. these and subsequent port read instructions with NOPs. Col_Check BTFSS PORTB.4 ;Check first column for low GOTO Dispkey ;and if low, display key INCF Key ;If no key press, increment key number BTFSS PORTB.5 ;Check second column for low GOTO Dispkey ;and if low, display key INCF Key ;If no key press, increment key number BTFSS PORTB.6 ;Check third column for low GOTO Dispkey ;and if low, display key INCF Key ;If no key press, increment key number BTFSS PORTB.7 ;Check fourth column for low GOTO Dispkey ;and if low, display key INCF Key ;If no key press, increment key number The Col_Check routine matches the pseudo-code quite closely. The Done label in the pseudo-code has been replaced with Dispkey, which displays the value in Key on the LEDs for half a second. INCF Key updates the key variable after each check.

Row_Set MOVLW 11h ;Load W with number of keys + 1 SUBWF Key,0 ;and compare with current key value BTFSC Z ;If keys + 1 = current key then GOTO Main ;no key was pressed

BSF C ;Set carry bit RLF PORTB ;so that row 1 is high during rotate GOTO Col_Check ;and check next column

If no key in the first row is found to be pressed, the Row_Set subroutine will The ‘,0’ in SUBWF Key,0 execute. Row_Set checks to see that the Key variable has not been incremented past denotes that the result of the number of keys on the keypad (11h equals 17 decimal) by checking if Key equals the operation will be stored 17. It does this by subtracting 11h from the Key variable using MOVLW 11h and in W. A ‘,1’ suffix will store SUBWF Key,0 (SUBtract W from File register Key, leaving the result in W). If Key the result in the file register equals 17, the result of the subtraction will be zero and the Z bit of the Status register used in the operation. The PM assembler also recog- will be set. BTFSC Z (Bit Test File register, and Skip the next instruction if the nizes ‘,W’ as a suffix to specified bit is Clear) tests the Z bit of the Status register and returns to Main if no leave the result of the keys were pressed, beginning the key scanning again. operation in W. Not specifying a destination If the Key variable is below 17, Z will not be set and the BSF C (Bit Set File suffix leaves the result in register, Carry Bit) instruction executes. RLF PORTB (Rotate Left File register) the file register by default. shifts all bits in Port B one position to the left through the Carry bit. This moves the C Port B C Port B

Before RLF PORTB After RLF PORTB Chapter 9 - Switch ©1998 Sirius microSystems Microchip Code 83 Input Programming low from row one to row two. Following the rotate, Col_Check scans the four key- pad columns again. If no key press is detected, Row_Set repeats, checking for the highest key code and setting the next row low.

Dispkey BSF RP0 ;Select register page 1 CLRF TRISB ;Set Port B to output BCF RP0 ;Go back to register page 0

MOVF Key,0 ;Put value of Key into W MOVWF PORTB ;and display on LEDs

If a key is pressed, the low found during Col_Check causes the program to execute the Dispkey subroutine. Dispkey reconfigures all Port B pins to be outputs and then moves the contents of the key variable to Port B.

Delay DECFSZ Counter1 ;3-level nested loop GOTO Delay ;gives approx. 1/2 second delay DECFSZ Counter2 GOTO Delay DECFSZ Counter3 GOTO Delay

GOTO Initialize ;We’re done. Reset Port B and delay ;counters

Delay is a three-level nested loop providing approximately half a second to view the key return code. Following the time delay, the program begins again at Initialize so that Port B is reconfigured and the delay counters are reset.

Chapter Summary

Switches are common input devices for microcontrollers. They can be normally open or normally closed and are used with pull-up resistors to provide a logic high or logic low to the microcontroller when activated.

Switches exhibit contact bounce and this may adversely affect some programs. Debouncing is easily done in software by using a short time delay.

Keypads are commonly wired in a matrix to save on I/O lines. Matrix keypads require row and column scanning to determine the key pressed.

Interfacing to Matrix Keypads 84 Microchip Code ©1998 Sirius microSystems Questions

1. What is the function of a pull-up resistor?

2. In the switch circuit below, what is the level of the output both during activa- tion and during release?

3. Does bouncing occur on activation, release or both? Explain your reasoning.

4. Explain the concept behind switch debouncing.

5. You are working on a simplified television remote control with five buttons: power, volume up, volume down, channel up and channel down. Show how you would wire the buttons to a microcontroller. Explain why you chose ma- trix or non-matrix wiring.

6. Explain the concept behind matrix keypad scanning.

7 You are designing a simple serial output keyboard. If you dedicate one I/O line to the serial output, what is the maximum number of key switches that can interfaced?

When Grog began working in the Quality Control department at Zerocks Information Systems, certain product lines showed signs of severe switch contact bounce.

Chapter 9 - Switch ©1998 Sirius microSystems Microchip Code 85 Input Programming Assignment

1. Find at least five different switches and using the BOUNCE program make a chart of the average number of bounces they produce both on activation and release.

2. Using ALARM.ASM as a guide, create a program to indicate not only when a circuit is open, but to flash an LED if the circuit was opened and reconnected.

3. Modify your program, above, so that a key press on the keypad clears the flashing LED.

4. Modify the program further still so that a four-digit code disables the LED.

Assignment 86 Microchip Code ©1998 Sirius microSystems Calls and 10 Includes

Most microcontrollers include instructions that allow you to jump to a subrou- tine and return to your main program routine when the subroutine is finished. Calling subroutines from your main program has a number of advantages. First, commonly used sections of code can be written as subroutines which can later be re-used by other programs (for example, a keypad scanning routine). Second, subroutines make your programs modular—you can quickly write a new program by stringing together existing subroutines. Third, they save typing and, more importantly, debugging since the same pre-tested subroutine can be used again, and again. Finally, code becomes simpler to read because you can get an overview of the program by reading through the subroutine calls, not all of the subroutine instructions.

Include, CALL and RETURN

The INCLUDE directive and the CALL and RETURN instructions are needed to incorporate subroutines in your programs. The INCLUDE directive pastes the file referred to by it into your program, at the location of the INCLUDE statement. The included file is inserted into your code at assembly time.

CALL (CALL subroutine) is the instruction that causes program execution to continue at the subroutine memory location, similar to a GOTO. Unlike a GOTO, however, CALL pushes the memory location of the next instruction to be executed after the call onto the stack in the processing unit. When the subroutine finishes executing, a RETURN (RETURN from subroutine) instruction can pop the memory location saved in the stack into the Program Counter, and the PIC continues execut- ing the program from the instruction following the CALL instruction. RETURN is always the last instruction executed in a subroutine.

The stack in the mid-range PICmicro™ family is an eight-level, first-in, last-out With an eight level stack a subroutine can call another memory. If a CALL occurs within a called routine, the address of the next return subroutine, which can call memory location is pushed onto the stack on top of the first memory location. As another subroutine, and so such, the second memory location will be the first to be popped off the stack by the on, a maximum of eight RETURN instruction—similar to stacks of dinner plates at a buffet restaurant. times. Chapter 10 ©1998 Sirius microSystems Microchip Code 87 Calls and Includes Scanning a matrix keypad is just the kind of application that is suited to being written as subroutine. KEYSCLB.ASM is a program which accomplishes the same task as KEYSCAN.ASM in Chapter 9, but uses the INCLUDE directive along with CALL and RETURN. Let’s look at the pseudo-code for KEYSCLB.ASM first.

Initialize variables

Start Notice how much Call keypad initialize subroutine smaller the main program has become by Main using calls to the Call keypad scanning subroutine If no key was pressed, go to Main subroutine rather than Otherwise, set Port B to output writing the subroutine Display key for 0.5 s as part of the main Go to Start program code. The keypad initialize and scanning subroutines look like:

Initialize Set PORTB.0-3 as output and PORTB.4-7 as input Return

Scan Place a low on first row Set key counter to 1

Column_Check If column 1 low, Return Otherwise increment key_counter If column 2 low, Return Otherwise increment key_counter If column 3 low, Return Otherwise increment key_counter If column 4 low, Return Otherwise increment key_counter

Row_Set If key_counter > 16, go to No_Keys Otherwise, set next row low Goto Column_Check

No_Keys Clear key_counter Return

Normally, program pseudo-code does not need to show the subroutine’s pseudo- code. We have included the matrix key scanning pseudo-code to highlight the execu- tion sequence. When subroutines are written, they can be documented with their own comments, pseudo-code, or flow charts.

The PIC-MDS comes with a The real power behind subroutines lies in the fact that it is not necessary for you number of pretested to understand the inner workings of the subroutine in order to use it. As long as you subroutines to assist you in understand what the subroutine does and how to call it, you can use it in your code. programming. You may wish to pull out both KEYPAD.LIB and KEYSCLB.ASM from the Pull-Out Program References section as we describe how KEYSCLB.ASM calls KEYPAD.LIB to perform the matrix keypad scanning. Include, CALL and RETURN 88 Microchip Code ©1998 Sirius microSystems ;Hardware Equates

Counter1 EQU 0Ch ;Delay counter register Counter2 EQU 0Dh ;Delay counter register Counter3 EQU 0Eh ;Delay counter register

;Equates required by KEYPAD.LIB Key EQU 0Fh ;This register will hold a number from ;0-15 representing the last key pressed Counter1-3 are variable locations used by the three-level, 0.5 s display delay loop. The Key variable is used by the included KEYPAD.LIB subroutine library.

The calling program—in this example, KEYSCLB.ASM—must define the file Now might be a good time register locations that its included subroutines use. To find out which subroutine to read over the comments variables require registers, you must read the comment sections of the subroutine in the KEYPAD.LIB libraries. These comments also explain the function and use of the subroutines. subroutine library.

Although the Included library files can define register locations by using EQUate statements, the subroutine library file has no way of knowing if these locations have already been assigned by your program. Therefore, the PIC-MDS subroutines re- quire that the calling program assigns all register locations to variables.

ORG 00h ;Reset Vector location GOTO Initialize ;Start program after interrupt vector

ORG 05h ;One location past interrupt vector

Include ‘KEYPAD.LIB’ ;KEYPAD.LIB subroutines go here The Include directive inserts the file specified within quotes at the exact location of the Include statement. In this example, the instructions in the file KEYPAD.LIB will be placed into program memory starting at location 0005h.

106 ORG 00h ;Reset Vector loc 107 0000- 2825 GOTO Initialize ;Start program af 108 109 ORG 05h ;One location pas If you look further down 110 111 Include ‘KEYPAD.LIB’ ;KEYPAD.LIB subro the .LST file, you will find * 1 ;KEYPAD.LIB v1.1 Last Modified on May 20, 1996 the first instruction of the * 2 * 3 ;These program subroutines were written for the Sirius Mi KEYPAD.LIB file, or 1683h * 4 ;microcontroller development system (http://www.siriusmic * 5 (BSF RP0), at location * 6 ;Sirius MicroSystems provides this software on an “as is” 0005h. * 7 ;warranty, either expressed or implied. All Sirius MicroS

After assembly, the KEYSCLB.LST file will show the included files. Included files have an asterisk beside their line number to denote that they were not a part of the original source code.

Placing Include directives at the beginning of your program is a convention that makes it easy to find the files that have been included into your program. The include statement can, however, be placed anywhere in your program. Care must be taken so that the include file does not disrupt or break into any existing code. For this reason, another convention is to place the Include directives at the end of the program.

Chapter 10 ©1998 Sirius microSystems Microchip Code 89 Calls and Includes Initialize CALL KB_Port ;Library call to initialize Port B for ;keypad input CLRF Counter1 ;Clear delay loop counters CLRF Counter2 MOVLW 08h ;Preload Counter3 delay loop counter MOVWF Counter3 ;for 1/2 second delay The KB_Port label references a subroutine that is a part of the KEYPAD.LIB include file. You will not find the KB_Port subroutine in KEYSCLB.ASM. KB_Port sets Port B for keypad input, and when KB_Port returns, CLRF Counter1 is the next instruction to be executed. Let’s examine KEYSCLB.LST to see what takes place in the hardware stack when this call instruction occurs.

113 0025- 2005 Initialize CALL KB_Port ;Library call to 114 ;keypad input 115 0026- 018C CLRF Counter1 ;Clear delay loop 116 0027- 018D CLRF Counter2 117 0028- 3008 MOVLW 08h ;Preload Counter3 118 0029- 008E MOVWF Counter3 ;for 1/2 second d

Processing The CALL KB_Port instruction pushes the Unit Fetch/Decode Unit address of the next instruction (CLRF Coun- ter1) on to the stack before loading the Pro- ALU gram Counter with the address of KB_Port. Though most PIC instruc- W After address 0026h is saved on the stack, ex-

tions execute in one cycle, Program Counter ecution begins at KB_Port (location 0005h). any instruction that 0026 modifies the Program Counter requires two Processing After the KB_Port subroutine has finished, Unit cycles. CALL and RETURN Fetch/Decode Unit its RETURN instruction pops the top stack both need two cycles. ALU address back into the program counter. Pro- gram execution continues at the address loca- W tion immediatley following the CALL (0026h). Program Counter 0026

Main CALL KB_Scan ;Library call to scan keypad MOVF Key,0 ;Load value of Key into W BTFSC Z ;Check for no key GOTO Main ;If Z set, no key so scan again KB_Scan is another subroutine in the included KEYPAD.LIB subroutine library. KB_Scan scans the keypad, and returns a value in the Key variable. If a key is pressed, the value returned in Key is a number from one to sixteen. If no key is pressed, the value returned in Key is zero. Examine the KEYPAD.LIB library file for details.

MOVF Key,0 and BTFSC Z check to see if the Key value is equal to zero, and if Key is zero, KB_Scan is called again. The MOVF Key,0 instruction is used with BTFSC Z to ensure that the Z flag accurately reflects the value in Key. If you exam- ine KB_Scan closely, you will find that no instructions modify the Z flag after Key is cleared. However, it is good programming practice to force flag updates before con- ditional checks, since previous instructions and subroutines may have corrupted the flags. This is especially important with subroutines that you have not created or thoroughly examined.

Include, CALL and RETURN 90 Microchip Code ©1998 Sirius microSystems Actually, MOVF Key,0 is Dispkey BSF RP0 ;Select register page 1 not needed as W contains CLRF TRISB ;Set Port B to output Key from the earlier check. BCF RP0 ;Go back to register page 0 However, if memory allows, MOVF Key,0 ;Put value of Key into W adding the MOVF instruc- MOVWF PORTB ;and display on LEDs tion allows you to make If the Key value is not zero, BTFSC causes GOTO Main to be skipped and the modifications within or Dispkey routine executes next. Dispkey sets all of Port B to output, and displays the before Dispkey without key value on the Port B LEDs. worrying about the con- tents of W changing. This convention results in more robust code which can be Delay DECFSZ Counter1 ;3-level nested loop more easily modified. GOTO Delay ;gives approx. 1/2 second delay DECFSZ Counter2 GOTO Delay DECFSZ Counter3 GOTO Delay

GOTO Initialize ;We’re done. Reset Port B and delay ;counters Delay is a 3 level nested loop which ensures that the key value remains on the LEDs for about 0.5s

Like most of us, Gus was already familiar with the stack concept of last-in, first-out.

Reading ROM Data Tables using Calls

A ROM data table is a list of constants in program memory. These constants can be musical tunes, delay values, ASCII characters, default parameters, serial num- bers, sine wave look up tables, or any constant required by your program. ROM tables should not be confused with RAM data tables which contain dynamic values stored in file registers or the PIC16F84’s Data EEPROM. Although LCD.LIB is described in more detail in Chapter 12, that shouldn’t Our example for ROM data tables is the KEY.ASM program which displays the deter you from using it. key value on the LCD display. In addition to demonstrating data tables it also uses One of the advantages of two subroutine libraries (LCD.LIB and BIN2DEC.LIB) that you are not yet familiar subroutines is that they with. contain pre-written code that works! You only need Pull out KEY.ASM from the Pull-out Program References section and find the to know how to call the highlighted sections of code as we describe them. subroutines and define the variables they require. Chapter 10 ©1998 Sirius microSystems Microchip Code 91 Calls and Includes ;Hardware Equates

ORG 0Ch ;Start of File register area

;Equates required by KEYPAD.LIB: KEY.ASM uses DS to Key DS 1 ;Key code return register dynamically allocate ;Equates required by BIN2DEC.LIB and DEC2BIN.LIB: registers instead of Hundreds DS 1 ;Hundreds digit EQUate. See the text for Tens DS 1 ;Tens digit the advantages and disad- Ones DS 1 ;Ones digit vantages of doing this. ;Other equates Counter DS 1 ;character counter for LCD Counter1 DS 1 ;general purpose counter Counter2 DS 1 ;general purpose counter Counter3 DS 1 ;general purpose counter As discussed earlier, ORG sets the ORiGin for program instructions. ORG can also be used to set the origin for file register memory. In KEY.ASM, above, ORG 0Ch points to the first free file register location (0Ch). The DS (Define Space) direc- tives which follow the ORG assign file register locations to the referenced symbols.

In KEY.ASM, for example, the variable Key is assigned a one byte location at 0Ch. Hundreds follows at 0Dh. In contrast with EQU, using DS to define variable locations makes the locations dynamic—the assembler assigns locations as needed at assembly time. EQU requires you to assign each location.

The advantage of using DS is that variables can be created and removed without manually reassigning their addresses. The disadvantage of using DS is that variable locations may not be known until assembly time. Another consideration when using DS is that the ORG used to define the beginning of file register space also defines the beginning of program memory. A subsequent ORG statement must be used to reset the pointer to program memory.

ORG 00h ;Start program at Reset Vector

CLRF Key ;Clear Key storage register CALL LCD_Port ;Set up ports for LCD output CALL LCD_Init ;Initialize LCD and clear screen GOTO Initialize ;Continue with initialize routine

ORG 05h ;Continue after interrupt vector

Include ‘LCD.LIB’ ;LCD subroutines go here Include ‘KEYPAD.LIB’ ;followed by Keypad subroutines Include ‘BIN2DEC.LIB’ ;and Binary to Decimal conversion

Initialize CALL DisplayInit ;Display “Key Pressed:” on LCD The ORG 00h directive resets the origin to the beginning of program memory.

Up to this point, the first instruction following ORG 00h has been a GOTO which will jump over the interrupt vector. This program shows how you can cram an Interrupts are described in extra three words of program code into the space from 0000h to 0003h. Remember more detail in Chapter 11. that the Interrupt Vector is still at location 0004h. Therefore, CLRF Key, CALL Actually, this program will LCD_Port, CALL LCD_Init, and GOTO Initialize occupy the first four locations of be modified in Chapter 11 program memory. The fifth location (0004h) is jumped over by the GOTO Initialize to use interrupts. and is left blank for use as an interrupt vector if needed. Reading ROM Data Tables using CALLs 92 Microchip Code ©1998 Sirius microSystems Notice again that the Include directives occur after the ORG 05h directive. All three included subroutine library files are located in program memory starting with LCD.LIB at location 0005h.

CLRF Key initializes the Key register to zero. CALL LCD_Port configures Ports A and B for LCD use. Chapter 12 and the LCD.LIB subroutine explain the operation of LCD.LIB in more detail. For now, all you need to know to use the LCD display is that you must first initialize the ports for LCD use by calling LCD_Port, and then initialize the LCD by calling LCD_Init. After this, load W with an ASCII character value and call LCD_Data to display the character. Commands to set cursor position, scroll the display, set line number and cursor options are also loaded in W, but LCD_Reg is called rather than LCD_Data. Also, LCD.LIB calls a delay subroutine called Delay_5ms. You must include a five millisecond or longer delay subroutine with this name in your calling program.

Delay_5ms ;Delay loop used to initialize LCD

CLRF Counter1 ;Wipe first counter MOVLW 1Ah ;Load W with Timer Constant MOVWF Counter2 ;for Counter2

:Loop DECFSZ Counter1,1 ;Decrement first counter GOTO :Loop ;256 times DECFSZ Counter2,1 ;Decrement, second counter GOTO :Loop ;from constant, above RETURN

The Delay_5ms subroutine in KEY.ASM assumes a clock speed of 16 MHz. You can change MOVLW 1Ah to increase or decrease the delay to match your clock frequency. The delay can be longer than 5 ms, but not shorter—so you can leave the MOVLW 1Ah unchanged for slower clock speeds.

After the LCD is initialized, GOTO Initialize is the next instruction to be ex- ecuted. The GOTO Initialize calls DisplayInit. You may wonder why a CALL DisplayInit is not used in place of GOTO Initialize. Remember that DisplayInit is a subroutine and therefore the last instruction executed will be a RETURN. Return causes the execution of the instruction following the CALL to occur—in this case there is no instruction at 0004h, the interrupt vector, where the program execution would return had a CALL DisplayInit been used.

DisplayInit ;Writes ‘Key Pressed:’ to first line of LCD using ;LCD display library (LCD.LIB).

MOVLW LCDCLR ;Send LCD clear display code CALL LCD_REG ;to LCD as a command MOVLW LCDLine1 ;Send LCD line one address to CALL LCD_REG ;LCD as a command CLRF Counter ;Reset character counter DisplayInit writes the words ‘Key Pressed:’ on the LCD using a Data Table read. The first part of DisplayInit sends commands to the LCD display which clear the display and set the cursor to the first character of line 1. In preparation for the data table read, CLRF Counter resets the data table pointer to zero.

Chapter 10 ©1998 Sirius microSystems Microchip Code 93 Calls and Includes Get_Char MOVF Counter,0 ;Get character offset into W CALL Message ;use it to get character IORLW 00h ;RETLW won’t affect flags so use OR to BTFSC Z ;check for end of message RETURN ;and finish if done CALL LCD_Data ;If not done, send character to LCD INCF Counter,1 ;Add 1 to Counter GOTO Get_Char ;Do it again for next character

Message ADDWF PCL ;Offset program counter by adding W RETLW ‘K’ ;Message RETLW ‘e’ RETLW ‘y’ RETLW ‘ ‘ RETLW ‘P’ RETLW ‘r’ RETLW ‘e’ RETLW ‘s’ RETLW ‘s’ RETLW ‘e’ RETLW ‘d’ RETLW ‘:’ RETLW 0 ;End of message marker The Get_Char loop reads one character at a time from the data table, compares the character value to zero—a check to see if the end of data has been reached—and sends the character to the LCD for display.

The first time through the loop, Counter is zero. The CALL Message jumps to At this point, two levels of Message where the ADDWF PCL (ADD W to File register, Program Counter Low Stack are used: one for the byte) adds the value of counter to the low byte of the Program Counter. What isn’t CALL DisplayInit and one obvious at this point is that the Program Counter is already pointing at the location of for CALL Message. the RETLW ‘K’ instruction. Microprocessors typically increment the Program Counter to the next location after having read the current location.

Therefore, the ADDWF PCL adds zero to the location of the Program Counter, so the Program Counter continues to point to the memory location containing RETLW ‘K’. RETLW ‘K’ (RETurn from subroutine with Literal in W) returns execution of the program to the line following CALL Message with the ASCII value of ‘K’ in W.

With W now containing the first character from the table, the character needs to Since subroutines may be checked to see if it equals zero, representing the end of data. RETLW does not, modify flags during however, update the Z flag based on the contents of W. IORLW 00h (Inclusive OR execution, RETURNs do Literal with W) is a non-destructive way of checking W for zero and updating the Z not change the status of the flag—subtracts, adds and ANDs can also be used. flags so your calling program can check them. If the RETLW character is not zero, BTFSC Z skips the RETURN, and CALL LCD_Data is executed next. Calling LCD_Data writes the character in W to the LCD display. INCF Counter,1 increments the data table counter so that the next character will be read by CALL Message. GOTO Get_Char starts the table read process again with the new value of Counter in W.

When CALL Message executes the second time, W will contain one. ADDWF PCL adds one to the PCL this time, offsetting the Program Counter to the line con- taining RETLW ‘e’. Each successive time through the Get_Char loop, INCF Coun- ter,1 causes ADDWF PCL to return and display the next character, until the zero character is returned. This process shows how the Message data table is read.

Reading ROM Data Tables using CALLs 94 Microchip Code ©1998 Sirius microSystems Main ;This program loop scans the keypad using KEYPAD.LIB and ;gets the key value from Key register. BIN2DEC.LIB is used ;to convert the binary key number to three decimal digits. ;Each decimal digit is converted to ASCII by adding 30h and ;is sent to the LCD display.

MOVF Key,0 ;Get key code in W CALL BIN_DEC ;and convert to decimal CALL LCD_Port ;Set up ports for LCD output MOVLW 8Dh ;Send address of hundreds digit CALL LCD_REG ;to LCD display data RAM MOVLW 30h ;Load constant to convert to ASCII ADDWF Hundreds,1 ;and add to hundreds digit ADDWF Tens,1 ;add to tens digit ADDWF Ones,1 ;and add to ones digit MOVF Hundreds,0 ;Get hundreds digit into W CALL LCD_Data ;and send it to LCD MOVF Tens,0 ;Get tens digit into W CALL LCD_Data ;and send it to LCD MOVF Ones,0 ;Get ones digit into W CALL LCD_Data ;and send it to LCD CALL KB_Port ;Set up Port B for keypad input CALL KB_Scan ;Read Port B for key press GOTO Main ;Do it again! Finally, we can examine the main program routine. MOVF Key,0 is placed here to load W with the key value from a later call to KB_Scan. The first time through Main, Key will be zero since it has been cleared by the very first instruction after ORG 00h. CALL BIN_DEC converts the value in W to three decimal digits—one You can examine the for each of the hundreds, tens and ones digits. The result of the conversion is stored comments in the in the previously defined Hundreds, Tens and Ones registers. BIN2DEC.LIB and DEC2BIN.LIB files for a CALL LCD_Port is executed again, since the call to KB_Port in Main modifies detailed explanation of the port configuration. MOVLW 8Dh loads W with the address location of the thir- how they work. teenth (0Dh equals 13, and 80h is the start of line 1) character position on line one of the LCD display. The call to LCD_REG sends the 8Dh command to move the cursor to the specified position.

MOVLW 30h and ADDWF Hundreds,1 converts the binary number in Hun- dreds to an ASCII number. The digits 0-9 are encoded in ASCII as values 30h-39h. The tens and ones digits are also converted, and in each case the ‘,1’ specifies that the Remember, a ‘,0’ stores the result is stored in the file register, and not in the working register. Note how W still result of operations in W. contains 30h after each addition.

With the ASCII equivalent of the numbers now in Hundreds, Tens, and Ones, the following MOVF and CALL LCD_Data instructions write the numbers to the LCD display. The cursor automatically moves to the next position after each character is written.

Finally, CALL KB_Port and CALL KB_Scan reconfigure the ports for matrix key scanning and return a key value in the Key register. GOTO Main restarts the process and updates the LCD display with the current value of Key.

Notice how calls to included files greatly simplify the Main code. Main calls subroutines to control and write to the LCD display, convert numbers from binary to decimal, and scan the matrix keypad, but the details of these operations do not clutter the Main code. As such the Main code is easily readable and understandable.

Chapter 10 ©1998 Sirius microSystems Microchip Code 95 Calls and Includes Chapter Summary

CALL is a powerful instruction that lets you jump to program subroutines. A RETURN command in the called subroutine returns execution to the instruction following the CALL. CALLing and RETURNing is different from GOTO, which simply redirects program execution.

The Include directive allows you to easily insert previously written subroutines into your program and execute them with either CALLs or GOTOs.

RETLW is a variation of RETURN that loads W with a constant before return- ing execution to the calling routine. RETLW is ideally suited to reading data tables from program memory.

Chapter Summary 96 Microchip Code ©1998 Sirius microSystems Questions

1. Why must every called subroutine have a RETURN instruction?

2. Can a subroutine have more than one RETURN? Explain.

3. What limits whether a subroutine can be called from within a subroutine?

4. How does RETLW differ from RETURN?

5. Why can RETLW not be used in the Data EEPROM of the PIC16F84?

6. Describe what the assembler does when it encounters an Include directive.

7. Explain why the included library is corrupted in the program segment, below:

ORG 00h ;Start program at Reset Vector GOTO Initialize ;Continue with initialize routine

Include ‘KEYPAD.LIB’ ;followed by Keypad subroutines

ORG 05h ;Continue after interrupt vector

Initialize BSF RP0 ;Select register page 1 CLRF PORTB ;Set Port B to output

8. What variables must be defined by your calling program in order to use each of the following subroutine libraries:

KEYPAD.LIB BIN2DEC.LIB DEC2BIN.LIB LCD.LIB ATOD.LIB EEPROM.LIB RS232RX.LIB RS232TX.LIB SEEPROM.LIB

Chapter 10 ©1998 Sirius microSystems Microchip Code 97 Calls and Includes Assignment

1. Using a data table and KEYPAD.LIB, write a program to light the LED corre- sponding to the number of the key pressed (from Key one to eight). For exam- ple, pressing key one should light LED RB0, pressing key two should light LED RB1, etc.

2. Write a program to display the numbers 01 to 99 in BCD (binary coded deci- mal) on the Port B LEDs. For example, pressing key 1 followed by key 6 should display the value 00010110 on the LEDs.

3. Write the pseudo-code for digital lock program subroutine that compares six digits entered on the keypad to six numbers stored in a data table. If the correct code is entered the subroutine should clear a file register bit named Code_Ok, otherwise Code_Ok should be set to one.

4. Write the subroutine using the pseudo-code described in 3, above. Define Code_Ok as a single bit in the file register Alarm_Bits. You can do this by:

Alarm_Bits EQU 0Ch Code_Ok EQU Alarm_Bits.0 5. Write alarm code which displays the message ‘Enter Code’ and checks the next six digits entered from the keypad against values stored in the data table using the subroutine from 4, above. If the correct code is entered, your pro- gram should display ‘Access Granted’, otherwise display ‘Access Denied’.

Assignment 98 Microchip Code ©1998 Sirius microSystems 11 Interrupts

Interrupts are microcontroller hardware responses to specific events. When an interrupt event occurs, the microcontroller hardware temporarily suspends the cur- rent program in order to handle the interrupt. Once the interrupt has been serviced, normal processing resumes. This process is very similar to calling a subroutine and then returning to the calling code except that hardware events, not software calls, trigger a call to the interrupt service routine. Interrupt events can be internal or exter- nal. Internal interrupt triggers include timer/counter (TMR0) overflow, the comple- TMR0 can count external tion of an EEPROM write, and the completion of an A/D conversion. External events events (counter mode) or that cause interrupts are a change on PortB.0 (INT), a change on PortB.4-7 (Port B internal processor cycles Change), or an overflow of the timer/counter (TMR0). (timer mode), but not at the same time. An interrupt is Interrupts are ideally suited to processing random events as they occur, and then generated whenever TMR0 overflows. returning to the previous task. In essence, this enables an efficient form of multi- tasking. In interrupt-driven programs, the processor focuses on one main task until an interrupt occurs. As soon as an interrupt occurs, the processor always executes an interrupt service routine, and, once finished, the main program resumes execution from where it was interrupted. For example, the keypad interface programs in the previous chapters repeatedly polled the keypad for user input. Polling is inefficient if other processing must take place while waiting for a key press. That is, your program spends valuable clock cycles checking for key presses—clock cycles that may be needed for a complex math routine, for example. With interrupts, the program can perform other tasks and respond to a key press only when it occurs, because the keypress itself forces the program to read the keys. The only time the key scanning code would execute when using interrupts is in response to a key press.

The response of the microcontroller to an interrupt is similar to that of the CALL RETFIE (RETurn From instruction. During an interrupt the microcontroller finishes the current instruction, Interrupt, & Enable pushes the address of the next instruction onto the stack, and performs an automatic interrupts) is most com- call to the Interrupt Vector at memory location 0004h—which is where you would monly used. An interrupt either put the interrupt service subroutine, or a GOTO to the routine. The interrupt disables further interrupts so that interrupt processing service routine should determine the cause of the interrupt, respond appropriately, isn’t interrupted. RETFIE and exit with a RETURN or RETFIE instruction. The RETURN or RETFIE in- re-enables interrupts struction pops the top address off the stack so that processing can continue from whereas a RETURN does where the microcontroller was interrupted. not. Chapter 11 ©1998 Sirius microSystems Microchip Code 99 Interrupts Interrupt Registers and Flags

Interrupts are controlled through registers and flags. A number of registers con- tain interrupt control bits, and the INTCON register (0Bh or 8Bh) contains most interrupt flag bits. Interrupt control bits enable and configure interrupts. Interrupt flag bits signify that an interrupt event has occurred. Interrupts connect to the PIC16F84 microcontroller Interrupt Logic through the logic at right. T0IF T0IE T0IF is the TMR0 Interrupt Wake-up if in Flag, and T0IE is the SLEEP TMR0 Interrupt Enable bit. INTF Likewise, the INT pin INTE (PORTB.0) has a flag and Interrupt to CPU enable bit, as do PORTB RBIF (RB) change interrupts, RBIE and the data EEPROM. EEIF The PIC16C711 has A-to-D EEIE ADIF and ADIE inputs instead of EEIF and EEIE. GIE

The Global Interrupt Enable (GIE) bit in the INTCON register enables all inter- rupts. Each interrupt flag has a corresponding enable bit that must be set in order for the interrupt to pass on to the final AND operation with GIE. Notice also, that each interrupt can wake the processor from a SLEEP instruction, even with GIE cleared.

EEIF signifies the comple- The interrupt flags and enable bits are found in the INTCON register with the tion of an EEPROM Data exception of EEIF in the PIC16F84 and ADIF in the PIC16C711. write. ADIF signifies the completion of an A/D INTCON Register conversion. GIE EEIET0IEINTERBIE T0IF INTF RBIF bit 7 bit 0

TMR0 Interrupt A Timer 0 (TMR0) interrupt flag is generated when the TMR0 register over- flows from FFh to 00h. Timer 0 can be fed by either the internal instruction cycle clock or by an external clock on the PortA.4 pin. The INTCON register bit T0IE enables the timer 0 interrupt, and T0IF is the timer 0 interrupt flag bit. The OPTION register controls the TMR0 clock source, the clock edge used, and the prescaler divisor. OPTION Register Pages 16-17 of the PIC16F8X data sheets RBPU INTEDGT0CST0SEPSA PS2 PS1 PS0 summarize the OPTION bit 7 bit 0 and INTCON register bits. 0 Clock Out (fosc/4) M 1 U RA4/T0CKI 1 X M U TMR0 Register T0SE 0 X 8-bit Prescaler

T0CS T0IF PSA Interrupt Registers PS2PS1PS0 and Flags 100 Microchip Code ©1998 Sirius microSystems Setting the timer 0 Clock Select bit (T0CS, or OPTION.5) selects a transition on the PortA.4 pin, whereas clearing T0CS selects the internal instruction cycle clock. When using an external clock (T0CS is set), setting T0SE selects a high to low clock transition to increment the TMR0 register. Conversely, clearing T0SE increments TMR0 on a low to high clock transition.

When cleared, the Prescaler Assignment Bit (PSA, or OPTION.3) divides the See page 16 of the TMR0 clock source by a programmable prescaler value of 2 to 256. The prescaler PIC16F8X data sheet for divisor is selected using bits PS0, PS1 and PS2. To increment TMR0 on every clock prescaler assignments. (without a prescaler), the PSA bit must be set, assigning the prescaler to the Watch Note: The prescaler may be Dog Timer (WDT). assigned to either TMR0 or WDT, but not both. When TMR0 is set to count internal cycles, it can provide accurate time delays while allowing other processing to still take place. TMR0 can count external events to a maximum frequency of 50 MHz.

In the PIC-MDS, PortA.4 is connected to the serial receiver input. A serial char- acter arriving from an external device can overflow TMR0, generating an interrupt.

INT Interrupt PortB.0 is also known as the interrupt pin (INT). The INTF flag is generated whenever a transition matching the interrupt edge setting (INTEDG, or OPTION.6) occurs. The INT interrupt is enabled by the interrupt enable bit (INTE) and GIE.

A single event generated by an external peripheral such as a limit switch can be sensed using the INT pin.

Port B Change Interrupt When set as inputs, PortB.4-7 were designed to generate an interrupt in response to any change in signal level from the last level read. RBIF and RBIE are the flag and enable bits, respectively.

The Port B change interrupt is ideally suited to scanning keypads for a change, even while the PIC is in SLEEP mode. The PIC-MDS uses PortB.4-7 as inputs for the matrix keypad, so that any key press can generate an interrupt.

Waiting for a PortB change while putting the PIC to ‘sleep’ is an effective way of prolonging battery life. The PIC SLEEP instruction stops the processor clock, greatly reducing power consumption. A television remote control can save battery power by ‘sleeping’ most of the time, and ‘waking up’ in response to a key press.

EEPROM Interrupt

The EEIF interrupt flag bit (EECON1.4) is set when a write to the EEPROM Refer to Chapter 13 for Data Memory of the PIC16F84 is finished. EEIE (INTCON.6) gates the EEIF inter- more information on the rupt. An EEPROM interrupt is useful since a write to the EEPROM can take a Data EEPROM. considerable amount of time. A typical EEPROM write takes 10 ms. In 10 ms a 10 MHz PIC16F84 can execute 25 000 instructions! Chapter 11 ©1998 Sirius microSystems Microchip Code 101 Interrupts A/D Converter Interrupt The ADIF flag (ADCON0.1) is set when the A/D converter in the PIC16C711 has finished its conversion. The A/D interrupt is gated by ADIE (INTCON.6). Al- though the A/D converter is quite fast, interrupt capability is provided so that the PIC can be put to sleep to minimize switching noise during conversion. See Chapter 16 for more information on the A/D converter.

Interrupt Service Routines

Unlike a planned CALL, an interrupt can occur during the execution of any part of your program, totally disrupting your program’s normal execution. The job of an Interrupt Service Routine (ISR) is to transparently respond to the interrupt before restarting your program from where it was interrupted. The ISR does this by deter- mining the cause of the interrupt, doing some action related to the interrupt (servicing the interrupt), and clearing the appropriate interrupt flag bit before exiting and re- turning control to your main code.

Although servicing the interrupt seems to be the primary task of the ISR, an equally important requirement is that the ISR leave the processor state unchanged. For example, the ISR code is just a new set of software commands that execute within the processor after an interrupt. If, during the execution of the ISR, any proc- essor registers are modified by the ISR, their contents must be restored to pre-inter- rupt values before returning to your program. Otherwise, your program will not work as expected after returning from the interrupt.

Saving and restoring registers without modifying their contents is not as straight- forward as it first seems. The W register contents must be saved first, as all other See 8.10, page 49 in the registers pass through W on the way to their temporary storage locations. But, sim- PIC16F8X data sheets for ply moving W to another register can corrupt the Z flag, modifying the STATUS more information. register, and potentially invalidating a math operation in progress before the inter- rupt. Microchip’s recommended code sequence provides a way to save and restore registers without modifying them. We’ll examine this code in detail in our examples.

First, let’s examine the pseudo-code of a typical interrupt serviced routine:

Save Store W in temporary register Store STATUS in temporary register Store PORTB in temporary register if needed Store other registers if needed

Service_Interrupt Determine cause of interrupt Service interrupt . . Clear interrupt flag The interrupt automatically clears GIE, disabling Restore interrupts so that your ISR Restore other registers if saved Restore PORTB if saved is not interrupted. RETFIE Restore STATUS combines a RETURN and Restore W BSF GIE. Return and enable interrupts Interrupt Service Routines 102 Microchip Code ©1998 Sirius microSystems Using Interrupts to Wake-up on Key Press

KEY.ASM from Chapter 10 spent most of its time scanning the keypad waiting for the user to press a key. Instead of constantly polling the keypad, KEYINT.ASM puts the PIC to ‘sleep’ and uses the Port B Change interrupt to wake the processor from ‘sleep’ whenever a key is pressed.

Although interrupt code is more complex than polling, it provides the following advantages: • processor current is reduced from 8 mA during polling to less than 0.05 mA when asleep • SLEEP can be replaced by other code routines, so the PIC doesn’t waste its time waiting for a key press

Since KEYINT.ASM performs no processing other than executing the SLEEP instruction, no registers need to be saved or restored during the interrupt service routine.

Pull KEYINT.ASM from the Program References Section as we describe it.

ORG 00h ;Start program at Reset Vector

CLRF Key ;Clear key storage register CALL LCD_Port ;Set up ports for LCD use CALL LCD_Init ;Initialize LCD and clear screen GOTO Initialize ;Continue with initialize routine The CLRF Key instruction presets the Key register with the no-key code. The next two CALLs initialize the LCD for later use. GOTO Initialize continues initiali- zation after the interrupt service routine with a call to DisplayInit.

Initialize CALL DisplayInit ;Display “Key Pressed:” on LCD The operation of DisplayInit is described in Chapter 10 in the description of KEY.ASM. After returning from DisplayInit, Nap_Time is the next routine to be executed.

Nap_Time MOVLW 8Dh ;Send address of hundreds digit CALL LCD_REG ;to display data RAM MOVLW ‘Z’ ;Load ASCII character Z CALL LCD_Data ;and send it to LCD MOVLW ‘Z’ ;Re-load ASCII character Z CALL LCD_Data ;and send it to LCD MOVLW ‘Z’ ;One more time! CALL LCD_Data ;and send it to LCD

CALL Init_Port_B ;Get Port B ready for interrupts

Rather than displaying ‘000’ during a no-key press, Nap_Time displays ‘ZZZ’ to indicate that the PIC is going to sleep. CALL Init_Port_B configures Port B for key scanning and enables the Port Change interrupt.

Chapter 11 ©1998 Sirius microSystems Microchip Code 103 Interrupts Init_Port_B ;Sets Port B up for keypad scanning. RB0-3 are low outputs ;and RB4-7 are inputs with pull-ups enabled. When a key ;press occurs, one of the RB4-7 inputs goes low, generating ;and interrupt.

CALL KB_Port ;Set Port B for keypad scanning

CLRF PORTB ;Make outputs low MOVLW 08h ;Set only RB port change interrupt MOVWF INTCON ;and write to interrupt register RETFIE ;Return and enable interrupts Init_Port_B first calls KB_Port to configure the Port B tristate registers and pull-up resistors for the keypad. CLRF PORTB clears the keypad output lines so that a key press will generate a change on one of the Port B input lines. Remember, Port B inputs are pulled-up and normally read as a high. If the Port B outputs were also high, pressing a key would not change the level on the input pins, consequently not generating a Port Change interrupt.

Moving 08h into INTCON sets only the Port B Change enable (RBIE, or INTCON.3). This allows the RBIF flag to be passed on to the GIE gate. Finally, RETFIE (RETurn From Interrupt, and Enable all interrupts) returns execution to Main and simultaneously enables all interrupts by setting GIE. RETFIE is usually also the last instruction of any interrupt service routine.

The NOP is often placed after a SLEEP as the Main SLEEP ;Shut down and wait for key press NOP instruction following a GOTO Main SLEEP is always executed upon wake-up. The CALL After initialization, Main executes putting the PIC to sleep. Pressing a key on the to the ISR occurs after the keypad will change the state of PortB.4-7 and generate both an interrupt and wake up NOP has executed. (See from sleep signal. Normally an interrupt would cause the PIC to push the address of 8.12 on pg. 51 of the the NOP onto the Stack, but the SLEEP instruction pre-fetches the NOP and ex- PIC16F8X data sheets) ecutes it before the ISR, and leaves the address of GOTO Main on the stack.

ORG 04h ;Interrupt service routine starts

Check_RBIF ;When an interrupt occurs, Check_RBIF confirms it was ;generated by RB Port Change. If not, and other interrupts ;are enabled, they must get serviced in the Other_Int ;routine. When a valid key arrives, it gets displayed, ;then the port is re-configured for keypad input. Exiting ;this interrupt service routine, re-enables interrupts.

BTFSS RBIF ;Check for RB port change interrupt GOTO Other_Int ;If cleared, check other interrupts CALL Delay_5ms ;Wait key to settle CALL Delay_5ms ;10 ms should be enough time CALL KB_Port ;Set up Port B for keypad scanning CALL KB_Scan ;Scan keys for key press MOVF Key,0 ;Check Key register for 0 - no key BTFSC Z ;by testing the Z flag GOTO Nap_Time ;If no key was returned, user let go ;so we display ZZZ to indicate sleep

CALL BIN_DEC ;If key returned, convert to decimal

CALL LCD_Port ;Set up ports for LCD output MOVLW 8Dh ;Send address of hundreds digit CALL LCD_REG ;to display data RAM Using Interrupts to Wake-up on Key 104 Microchip Code ©1998 Sirius microSystems Press MOVLW 30h ;Load constant to convert to ASCII ADDWF Hundreds,1 ;and add to hundreds digit, ADDWF Tens,1 ;add to tens digit ADDWF Ones,1 ;and add to ones digit MOVF Hundreds,0 ;Gets hundreds digit into W and CALL LCD_Data ;send it to LCD MOVF Tens,0 ;Get tens digit into W and CALL LCD_Data ;send it to LCD MOVF Ones,0 ;Get ones digit into W and CALL LCD_Data ;send it to LCD

CALL KB_Port ;Set up Port B for keypad scanning CLRF PORTB ;and get ready for Port B change MOVF PORTB,0 ;Update Port B input latches BCF RBIF ;Clear the Interrupt flag RETFIE ;and return

Other_Int RETFIE ;Return and enable global interrupts This is the interrupt service routine for KEYINT.ASM. The ISR immediately services the interrupt without saving the contents of any registers. In this case no other event could have caused the interrupt, but BTFSS RBIF is included to show how you can check to see which event caused the interrupt. If RBIF is not set, you can use GOTO Other_Int to poll INTCON, determine what caused the interrupt, and service it appropriately. Here, Other_Int returns to the previously executing code and enables further interrupts via the RETFIE instruction because all other interrupts are This double-check ensures disabled. that nothing has corrupted the INTCON register. After confirming that a port change caused the interrupt, CALL Delay_5ms is used twice to allow the keys to finish bouncing before they are scanned. CALL KB_Port and CALL KB_Scan configure Port B for keypad use and determine which key is being pressed. The variable Key contains the key return code and is placed into W via the MOVF Key,0 instruction. When a key is being pressed, BTFSC Z will skip GOTO Nap_Time as the key return code is not zero. When the key is released the key return code will be zero and GOTO Nap_Time will display the ‘ZZZ’ to Actually, the PIC will goto indicate sleeping between key presses. sleep while the key is being held, but the LCD contin- CALL BIN_DEC converts the value in W (key return code) from binary to BCD ues to display the key code digits which are stored in the Hundreds, Tens and Ones variables. at this time.

CALL LCD_Port is required because of the CALL KB_Port earlier. The LCD cursor is told to move to position 8D via the MOVLW 8Dh and CALL LCD_Reg instructions. 8Dh is the 14th position on line 1 of the LCD.

Adding 30h to the Hundreds, Tens and Ones variable converts them to ASCII, and then the MOVF and CALL LCD_Data instructions send the Hundreds, Tens and Ones digits to the LCD.

Next, CALL KB_Port configures Port B for keypad scanning, CLRF PORTB clears Port B outputs in preparation for the Port Change, and MOVF PORTB,0 performs a Port B read. The read is necessary to update the Port B input latches. When interrupts are re-enabled, the Port B Change interrupt continuously compares the value of Port B to the value stored in the input latches. Reading Port B updates the input latches so that they reflect the key being held. When interrupts are re- enabled, the PIC won’t generate a new Port Change Interrupt until the key is re- leased. Chapter 11 ©1998 Sirius microSystems Microchip Code 105 Interrupts Finally, BCF RBIF clears the Port B Change Interrupt flag just before RETFIE returns to Main and re-enables interrupts. The interrupt flag should be cleared just before exiting the ISR. If the interrupt flag is cleared too early, an ISR operation could set the flag, causing an interrupt to be re-triggered immediately after exiting the ISR causing an endless interrupt loop.

Include ‘BIN2DEC.LIB’ ;Binary to Decimal conversion routin Include ‘KEYPAD.LIB’ ;Key pad scanning routines Include ‘LCD.LIB’ ;LCD subroutine library

If you really wanted to In KEYINT.ASM, the Include directives are placed at the very end of the code. place the included files at Since KEYINT.ASM uses interrupts, placing the Include directives at location the top of the program, you 0005h— as was done with KEY.ASM—would have written over the interrupt serv- could either place a GOTO ice routine beginning at location 0004h. in location 0004h to redirect the interrupt to a new location, leaving the includes at location 0005h, Managing Multiple Tasks using the TMR0 Interrupt or you could just add the includes between the ISR 0 Clock Out (fosc/4) and main code—just don’t M 1 U use ORG to force the RA4/T0CKI 1 X M U TMR0 Register includes to a specific T0SE 0 X address. 8-bit Prescaler

T0CS T0IF

PS2PS1PS0 PSA

CLOCK.ASM demonstrates two tasks running concurrently. The program cy- cles a single LED across the LED bar graph and uses the TMR0 interrupt to keep track of how long the program has been running. This elapsed time is displayed on the LCD. Before explaining the program code, let’s look at how CLOCK.ASM uses the TMR0 register.

See page 16 of the Timer 0 (TMR0) is set to count internal oscillator clocks by clearing T0CS. PSA PIC16F8X data sheet for is cleared so that the instruction cycle clock (Clock Out in the diagram) is divided by prescaler assignments. the 8-bit prescaler. PS2, PS1 and PS0 are set to divide the input clock by 256. The Note: The prescaler may be end result of this is that TMR0 increments at a rate of 9765.6 times per second (at a assigned to either TMR0 or 10 MHz clock oscillator frequency). WDT, but not both. Let’s look at how this is calculated. A 10 MHz clock is divided by four internally to generate the 2.5 MHz instruction cycle clock. Dividing the 2.5 MHz instruction cycle clock by a prescaler of 256 yields the 9765.6 Hz TMR0 clock.

TMR0 increments on every input clock. TMR0 generates an interrupt after 256 counts. At the 9765.6 Hz rate, interrupts are generated at a rate of 38.15 Hz (9765.6÷256).

We chose 60 Hz because Often, TMR0 is modified to provide interrupts at a specific rate. CLOCK.ASM that is the North American pre-loads TMR0 to 93 to provide an interrupt rate close to 60 Hz. By doing this, power line frequency, TMR0 increments from 93 to 256—instead of from 0 to 256—generating an over- which just might be useful flow after 163 counts (256-93). With an input clock rate of 9765.6 Hz to TMR0, for other projects. interrupts will be generated at 59.91 Hz (9765.6÷163). Managing Multiple Tasks using the 106 Microchip Code ©1998 Sirius microSystems TMR0 Interrupt Refer to CLOCK.ASM in the Program References Section as we describe its operation.

We know that servicing the Temp_W DS 1 ;Temporary registers Temp_Status DS 1 ;used to save values during interrup TMR0 interrupt will disrupt Temp_TRISB DS 1 ;service routine (ISR) The ISR the LED cycling on Port B. Temp_TRISA DS 1 ;will save their values on entry All of the Port B registers Temp_PortB DS 1 ;and restore them on exit. must be saved, and later Temp_PortA DS 1 restored. In the Equates section, these Temp_ registers are noteworthy because the CLOCK.ASM ISR saves and restores the contents of all the registers that it uses.

MOVLW 60 ;Preload sixtieths MOVWF sixtieth ;with 60

CALL LCD_Port ;Set up ports for LCD use CALL LCD_Init ;Initialize LCD and clear screen CALL Disp_Init ;Display “Elapsed time:” on line 1 CALL Disp_Time ;Display time on line 2

CALL TMR0_Init ;Initialize Real Time Clock Counter ;Timer 0 (TMR0) and enable interrupt

In the Initialize subroutine the Counter variables are cleared, and sixtieth is set to 60 by the MOVLW 60 and MOVWF sixtieth instructions. The ISR decrements six- tieth to determine when one second has passed. CALLS to initialize the LCD and display the text ‘Elapsed time:’ and ‘00:00:00’ on the LCD follow. The CALL TMR0_Init sets TMR0 to generate an interrupt 59.91 times per second.

TMR0_Init ;Assign prescaler to TMR0 and preload TMR0 for 60 Hz ;interrupts.

CLRWDT ;Clear WDT and prescaler BSF RP0 ;Select register page 1 MOVF OPTION,0 ;Load W with current OPTION reg. ANDLW 11000111b ;Clear T0CS, T0SE and PSA bits ;T0CS=OPTION.5, Counter select ;0=Timer mode, 1=Counter mode ;T0SE=OPTION.4, Source Edge select ;0=Rising edge, 1=Falling edge ;PSA=OPTION.3, Prescaler Assignment ;0=TMR0, 1=WDT IORLW 00000111b ;Set PS2, PS1 and PS0 ;000=/2, 001=/4, ...111=/256 MOVWF OPTION ;Set OPTION register with new value BCF RP0 ;Return to register page 0

MOVLW 93 ;Load W with 93 because incrementing MOVWF TMR0 ;TMR0 from 93-256 takes 1/60s

MOVLW 20h ;Enable only the TMR0 interrupt MOVWF INTCON ;and write to INTCON

RETFIE ;Return and enable global interrupts

TMR0 and the watchdog timer (WDT) share the prescaler. The CLRWDT in- struction is recommended by Microchip to ensure that a WDT time-out does not occur while assigning the prescaler to TMR0.

Chapter 11 ©1998 Sirius microSystems Microchip Code 107 Interrupts The technique makes the Unlike KEYINT.ASM where the registers are loaded with an absolute value, code more portable. That CLOCK.ASM loads the current state of OPTION into W and modifies only the is, it can be used in other required bits, leaving the others unchanged. The MOVF OPTION,0 loads OPTION programs with little or no into W and the ANDLW 11000111b clear the bits 4, 5 and 6 of OPTION leaving the modification. remaining bits unchanged. IORLW 00000111b sets bits 0, 1 and 2 in OPTION leav- ing the remaining bits unchanged. MOVWF OPTION stores W into the OPTION register.

MOVLW 93 and MOVWF TMR0 pre-loads TMR0 with the preset value 93. 93 will cause TMR0 to generate interrupts 59.91 times per second as described earlier. INTCON is loaded with 20h so that only the TMR0 interrupt is enabled.

RETFIE ends the TMR0_Init initialization routine. It enables interrupts and re- turns to Initialize.

BSF RP0 ;Select Register Page 1 CLRF TRISB ;Make Port B output BCF RP0 ;Back to Register Page 0

MOVLW 01h ;Light up the first LED MOVWF PORTB ;on Port B BCF C ;Clear the Carry

Main ;This code runs when the Interrupt service routine isn’t ;running and cycles a single LED across the display.

:Loop DECFSZ Counter3,1 ;Decrement first counter GOTO :Loop ;256 times DECFSZ Counter4,1 ;Decrement, second counter GOTO :Loop ;from constant, above

RLF PORTB ;Rotate PORTB to the left GOTO Main ;Do it again and again and ...

It takes ~80 ms to complete Here, Port B is set for output and begins to cycle the LED. The scan rate of the the delay loop for the LED. LED is determined by the nested loop. At this point interrupts have been enabled and Four interrupts will have when TMR0 overflows (~16.7 ms later) the ISR takes control of the PIC. occurred and been serviced before the LED moves to the next position! Check_T0IF ;When an interrupt occurs, Check_T0IF confirms it was ;generated by a TMR0 overflow. If not, and other interrupts ;are enabled, they must get serviced in the Other_Int ;routine. When TMR0 overflows sixtieth is decremented and ;checked for equalling zero. If Zero then Seconds, Minutes ;and Hours are updated and displayed. Otherwise, interrupts ;are re-enabled and execution continues.

Save MOVWF Temp_W ;Save W in Temp_W SWAPF Status,0 ;Swap Status halves into W MOVWF Temp_Status ;and save Status in Temp_Status

MOVF PORTA,0 ;Load W with Port and TRIS contents MOVWF Temp_PortA ;and save to temporary registers MOVF PORTB,0 MOVWF Temp_PortB BSF RP0 MOVF TRISA,0 MOVWF Temp_TRISA MOVF TRISB,0 MOVWF Temp_TRISB BCF RP0

Managing Multiple Tasks using the 108 Microchip Code ©1998 Sirius microSystems TMR0 Interrupt The Save routine must be the first part of the ISR to execute. As mentioned earlier, W and the STATUS registers must be saved without altering their contents. MOVWF Temp_W stores the contents of W into one of the previously defined storage registers. SWAPF STATUS,0 (SWAP nybbles of File register, store result in W) copies the contents of the STATUS register into W with upper and lower nybbles exchanged. SWAPF is used because a MOVF modifies Z which is one of the STATUS register bits. With STATUS now in W, albeit with reversed nybbles, it is moved to a temporary storage register by MOVWF Temp_Status.

The subsequent series of MOVF and MOVWF instructions save the contents of the PORT and TRIS registers. With all of the important registers now saved, the ISR can service the interrupt.

ISR BTFSS T0IF ;Check for TMR0 interrupt GOTO Other_Int ;If cleared, check other interrupts

DECFSZ sixtieth ;Has 1 second elapsed? GOTO Exit ;If not, use Exit to leave ISR MOVLW 60 ;If zero, reset sixtieth counter MOVWF sixtieth ;to 60 INCF Seconds ;Update seconds and SUBWF Seconds,0 ;check for overflow (Seconds=60) BTFSS Z ;by testing Z GOTO Update_Clock ;If Z=0, update clock with new time

CLRF Seconds ;If Z=1, Seconds is 60, reset to 0 MOVLW 60 ;reload W with 60 INCF Minutes ;Update Minutes and SUBWF Minutes,0 ;check for overflow (Minutes=60) BTFSS Z ;by testing Z GOTO Update_Clock ;If Z=0, update clock with new time

CLRF Minutes ;If Z=1, Minutes is 60, reset to 0 MOVLW 24 ;Load W with 24 INCF Hours ;Update Hours and SUBWF Hours,0 ;check for overflow (Hours=24) BTFSS Z ;by testing Z GOTO Update_Clock ;If Z=0, update clock with new time

CLRF Hours ;If Z=1, reset hours to 00

Update_Clock CALL LCD_Port ;Reconfigure Ports for LCD and CALL Disp_Time ;display the new time

The BTFSS T0IF and GOTO Other_Int form the structure needed to test INTCON and select the appropriate interrupt to service. In this case, only the TMR0 interrupt is enabled, but this type of check can used to identify the cause of an interrupt if more than one is enabled.

DECFSZ sixtieth determines if 60 interrupts have occurred and exits the ISR if not. After 60 interrupts, the elapsed time on the clock is updated.

The time is updated by first incrementing Seconds, and checking for an over- flow to 60. If an overflow occurs, Minutes is incremented, again checking for an overflow to 60. If an overflow occurs, Hours is incremented. Hours is checked for an overflow to 24. If Hours overflows, the Hours, Minutes and Seconds are all reset to zero. Finally, the calls in Update_Clock display the updated time on the LCD.

Chapter 11 ©1998 Sirius microSystems Microchip Code 109 Interrupts Exit ;Reloads TMR0 so the next 60th second time-out can generate ;an interrupt and restores all registers.

MOVLW 93 ;Preload W for 60 Hz delay MOVWF TMR0 ;and save to TMR0 BCF T0IF ;Clear TMR0 interrupt flag and

Restore MOVF Temp_PortA,0 ;Restore registers from temporary MOVWF PORTA ;registers MOVF Temp_PortB,0 MOVWF PORTB BSF RP0 MOVF Temp_TRISA,0 MOVWF TRISA MOVF Temp_TRISB,0 MOVWF TRISB BCF RP0

SWAPF Temp_Status,0 ;Swap Status halves to W MOVWF Status ;and return Status to pre-interrupt ;value SWAPF Temp_W,1 ;Swap halves of Temp_W SwAPF Temp_W,0 ;Swap Temp_W back to W

RETFIE ;Return and enable interrupts

Other_Int ;Insert other interrupt checks here

RETFIE ;Return and enable global interrupts To end the interrupt, Exit reloads TMR0 with the 1/60th second delay value and clears the T0IF flag.

The Restore subroutine restores the contents of the Port and Tris registers to the values they contained before the interrupt.

SWAPF Temp_Status,0 moves the saved STATUS register (with its nybbles re- versed) into W in its correct order. The MOVWF STATUS instruction copies W— containing the saved Status—back to the STATUS register. MOVWF does not affect any of the STATUS register flags.

Finally, W must be restored. Since MOVF cannot be used since it can affect the STATUS register flags, two SWAPFs are used to restore W. SWAPF Temp_W,1 reverses the order of the nybbles in Temp_W, leaving the result in Temp_W. This must be done because the W register itself cannot be swapped. The next SWAPF Temp_W,0 swaps the nybbles back to their original form and leaves the result in W.

Once all of the registers have been restored, RETFIE returns execution to Main where the LED scanning continues.

CLOCK.ASM demonstrates how easily the PIC can accomplish two tasks at the same time. What is not as apparent, however, is exactly how much unused processor time is available for use by other tasks. Updating the clock uses less than 1% of the processor’s time! By exploiting interrupts, you can cram a lot of functionality into a simple microcontroller.

Managing Multiple Tasks using the 110 Microchip Code ©1998 Sirius microSystems TMR0 Interrupt Chapter Summary

Interrupts are used to place one program subroutine on hold while another program subroutine automatically responds to the hardware event that caused the interrupt. The PIC16F84 can be interrupted by Timer 0 overflows, transitions of the INT pin, changes on PortB.4-7, and completed EEPROM writes. The PIC16C711 includes the same interrupt sources except that the EEPROM write complete inter- rupt is replaced with an A/D conversion complete interrupt.

The INTCON and OPTION registers control most interrupt functions. All in- terrupts have an interrupt enable and an associated interrupt flag. The enable bit does not suppress the generation of the flag, but only the generation of an interrupt. All interrupts are gated with the Global Interrupt Enable bit (GIE).

Interrupts cause the execution of the instruction at location 0004h—the Inter- rupt Vector. An interrupt service routine located here must: • save all registers they modify • determine the cause of the interrupt and service it • clear the interrupt flag • restore all registers to their original values

Interrupts can be used to wake the processor from sleep (reducing power con- sumption), manage multiple concurrent tasks, and allow the PIC to respond to un- predictable events as they occur.

No matter how complex the interrupt code became, Phil was always impressed by how quickly Spike could locate the errors.

Chapter 11 ©1998 Sirius microSystems Microchip Code 111 Interrupts Questions

1. Describe how interrupt-driven input differs from polling an input for a change.

2. What are the four interrupt sources for the PIC16F84?

3. List the pseudo-code steps to enable the INT interrupt for a falling-edge input on RB.0.

4. How does the GIE bit affect a wake-up from a SLEEP? Refer to the interrupt logic diagram and the Microchip data sheets.

5. Explain why it is important to update the Port B input latches before enabling the Port B change interrupt.

6. How much error does the displayed time in CLOCK.ASM have due to soft- ware? How can it be made more accurate?

Assignment

1. Write the pseudo-code for a program which incorporates interrupts and flashes an LED at a set rate. When a button on the keypad is pressed the flashing rate should change to a new rate determined by the number of the key pressed. Include the pseudo-code for the ISR.

2. Write the program outlined in 1.

3. Write the pseudo-code for a program which uses TMR0 to generate an inter- rupt after 10 ms have elapsed.

4. Write the pseudo-code for a program which uses a transition from high to low on the INT (PORTB.0) pin to display the text ‘INT pin interrupt’ on the LCD display. Otherwise, the LCD should be cleared and a single LED should be scanning across the bar graph display from PORTB.1 to PORTB.7 (PORTB.0 will be needed to generate the interrupt).

5. Write the pseudo-code for a program which accepts a 60 Hz input clock on PORTA.4 and displays the elapsed time on the LCD in hours, minutes, sec- onds, and tenths of seconds. When a key is pressed, generate a Port B change interrupt. The ISR should determine which event caused the interrupt. If TMR0 generated the interrupt, the elapsed time routine should be serviced. If a key press caused the interrupts, they key pressed should either increment or decre- ment the hours, minutes, seconds, or tenths of seconds variables.

6. Write the programs outlined in 4 and 5.

Questions and Assignments 112 Microchip Code ©1998 Sirius microSystems Using the 12 LCD Display

The PIC-MDS includes an intelligent 2-line by 16-character LCD display. Intel- ligence is provided by an on-board controller chip based on the Hitachi HD44780— LCD displays using the a common LCD controller. The LCD controller: HD44780 controller and its derivatives are widely • displays ASCII characters as well as some Kanji and Greek characters available. The techniques • can shift characters left or right on the display used in this chapter apply to any LCD using this • provides absolute and relative character position addressing controller family. • has a 40 character memory for each line of the display • supports cursor movement and appearance • allows 8 custom characters to be programmed • can be connected to a microcontroller using a 4-bit or 8-bit interface

Adding LCD capability to your projects is remarkably easy, once you know how to communicate with the LCD controller. This chapter will give two examples of using the LCD. The first program displays the ASCII character entered using the keypad and demonstrates character positioning. The second uses custom characters to demonstrate cursor cell animation and display scrolling.

Before we examine the code, we need to understand how the LCD is connected to the microcontroller and the function of the internal LCD registers.

The LCD Interface

In the PIC-MDS, the LCD display is connected to both Port A and Port B of the microcontroller (refer to the schematic segment on the next page). Port A is used to activate the LCD control lines, and Port B connects to the LCD data lines.

As you look at the schematic, notice that the LCD data lines are shared with the keypad (and with the LED’s—see Chapter 4). Sharing Port B like this takes advan- tage of the PIC’s ability to easily and rapidly reconfigure ports. KEY.ASM, KEYINT.ASM and CLOCK.ASM have all used Port B for more than one function. Chapter 12 Using ©1998 Sirius microSystems Microchip Code 113 the LCD Display A section of the PIC-MDS schematic showing the LCD and Keypad connections to the PIC microcontroller.

LCD Controller Commands COMMANDRSR/W DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0 DESCRIPTION Clear Display 0 0 0 0 0 0 0 0 0 1 Clears display and sends cursor to home position. Return Home 0 0 0 0 0 0 0 0 1 • Returns cursor to home position, leaving characters. Entry Mode 0 0 0 0 0 0 0 1 Inc. 0 Sets cursor increment/dec- rement mode. Display Cont. 0 0 0 0 0 0 1 Disp. Curs. Blink Display and cursor on/off control, and cursor blink. Shift Mode 0 0 0 0 0 1 D/C R/L • • Sets cursor and display shift direction. Function Mode 0 0 0 0 1 Data Lines Font • • Sets data width, number of lines and character font. CGRAM Addr. 0 0 0 1 CGRAM Address Sets character generator MSB LSB RAM (CGRAM) address. DDRAM Addr. 0 0 1 DDRAM Address Sets display data RAM MSB LSB (DDRAM) address. Read Busy 0 1 Busy RAM Address Reads LCD Busy Flag MSB LSB RAM Write 10 RAM Data Writes data to RAM MSB LSB RAM Read 11 Reads data from RAM MSB RAM Data LSB

Inc. - Increment or decrement cursor position. 1=increment, 0=decrement Disp. - Display On/Off control. 1=on, 0=off Curs. - Cursor On/Off control. 1=on, 0=off Blink - Cursor blink. 1=blinking, 0=underscore D/C - Shift display or cursor. 1=shift display, 0=shift cursor R/L - Right/left shift direction. 1=shift right, 0=shift left Data - Interface data bus width. 1=8 bits, 0=4 bits Lines - Number of display lines. 1=2 lines, 0=1 line Font - Font select. 1=5X10 dots, 0=5X7 dots Busy - Busy Flag. 1=busy, 0=ready • - Not used.

This chart summarizes the LCD controller commands used by LCD.LIB, the LCD subroutine library. The LCD Interface 114 Microchip Code ©1998 Sirius microSystems Port A connects to the LCD control lines is as follows:

PORTA.2 LCD Enable (LCDE in LCD.LIB) LCD.LIB is the subroutine PORTA.0 LCD Register Select (RS in the chart, and LCDRS in LCD.LIB) library that controls the PORTA.1 LCD Read/Write (R/W in the chart, and LCDRW in LCD.LIB) LCD. Its use is described later in this chapter. LCD Enable LCD Enable is an active-high input on the LCD. When low, the LCD is disabled and all other LCD I/O lines are in the high impedance state—effectively disconnect- ing the LCD display from the PIC. The LCD Enable line must be pulsed high in order to write or read commands or data to the LCD. The duration of this pulse must be at least 500 ns. The LCD_Enable routine in LCD.LIB pulses the enable line.

LCD Register Select RS on the LCD selects either command mode (when RS=0) or character read/ write mode (when RS=1). CALL LCD_Reg is used to write commands to LCD registers. The CALL LCD_Reg subroutine in LCD.LIB ensures that RS is low be- fore pulsing the enable line. Similarly, CALL LCD_Data is used to write characters to the LCD. The CALL LCD_Data subroutine in LCD.LIB sets RS high before pulsing the enable line.

LCD Read/Write The R/W line determines whether a read or write to the LCD takes place. If R/W is high (R/W=1) the contents of LCD RAM will be read and if R/W is low (R/W =0) the LCD RAM will be written. The R/W line along with the RS line must be set prior to issuing the enable pulse.

LCD Commands

LCD.LIB has predefined command equates, shown below. These equates are derived from the LCD Controller Commands table at left. To send a command to the LCD, load W with the command equate and CALL LCD_Reg. LCD_Reg controls the RS and R/W lines, and pulses the enable to complete the command.

Chapter 12 Using ©1998 Sirius microSystems Microchip Code 115 the LCD Display LCD Initialization

If you use other types of Before the LCD can be used, the LCD controller (the HD44780 on the LCD) LCD displays based on the must be initialized for the correct display format. We’ll configure the display on the HD 44780 controller, or if PIC-MDS to use 8-bit data, two display lines, and a 5X7 character matrix. The you want to use the LCD in LCDFunction equate of 38h configures the LCD for these settings. This value is 4-bit mode, you will need derived from the LCD Controller Commands chart, under the Function Mode com- to modify the LCDFunction mand. equate. Refer to the LCD4BIT.LIB library file Initialization must follow a specific order, which is shown below in pseudo-code. for details. Calling LCD_Init in LCD.LIB does this for you.

The LCD controller is reset LCD_Init Send LCDFunction data (38h) to LCD in software by three pulse the LCD enable line successive writes of 38h. wait 5 ms The LCD controller should automatically be reset on Send LCDFunction data (38h) to LCD pulse the LCD enable line power-up. We’ve included wait 5 ms the software reset just in case the power supply rise Send LCDFunction data (38h) to LCD time does not meet the pulse the LCD enable line wait 5 ms controller reset require- ments. Send LCDFunction data (38h) to LCD pulse the LCD enable line The fourth 38h sets the wait 5 ms LCD function register. The Send LCDOn data (C0h) to LCD next three writes turn on pulse the LCD enable line the LCD display, clear the display, and set the cursor Send LCDCLR data (01h) to LCD pulse the LCD enable line into increment mode. The LCD is now ready for use. Send LCDInc data (06h) to LCD Pulse the LCD enable line

Return

The first part of the LCD_Init subroutine is shown below:

We will represent called LCD_Init ;LCD initialization instructions from the Optrex data book. library routines as greyed- ;Sets LCD functions for DMC16207 display, performs soft- out text to indicate that the ;ware reset, clears memory and turns the display on. code can be found in ‘.LIB’ files. MOVLW LCDInit ;Load W with initialize LCD code CALL LCD_Reg_Init ;and send it to LCD CALL Delay_5ms ;...and wait MOVLW LCDInit ;Load W with initialize LCD code CALL LCD_Reg_Init ;and send it to LCD again CALL Delay_5ms ;...and wait MOVLW LCDInit ;Load W with initialize LCD code CALL LCD_Reg_Init ;and send it to LCD again CALL Delay_5ms ;...and wait MOVLW LCDFunction ;Load W with initialize 8-bit code CALL LCD_Reg ;and send it to LCD From LCD.LIB CALL Delay_5ms ;...and wait

LCD Initialization 116 Microchip Code ©1998 Sirius microSystems ;Change the constant in the next line to set how the displa ;is activated. eg. LCDOn, CursOn, CursBlink. The Constant i ;from the LCD software commands, above.

MOVLW LCDOn ;Command for display on & cursor of

CALL LCD_Reg ;Send it to LCD MOVLW LCDCLR ;Load W with clear LCD code CALL LCD_Reg ;and send it to LCD MOVLW LCDInc ;Load W with increment mode code CALL LCD_Reg ;and send it to LCD RETURN

You may have noticed two major differences when comparing the library code with the pseudo-code. First, the LCDInit constant is actually the same as the LCDFunction constant. They have been equated separately so that the LCDFunction constant can be changed for other display types without changing the initialization code.

Next, two slightly different routines, LCD_Reg and LCD_Reg_Init, are used to pulse the enable line of the LCD controller after writing the LCD command. LCD_Reg checks the LCD controller’s busy flag before enabling the command write and can- not be used during initialization. LCD_Reg_Init ignores the state of the LCD busy flag during a software reset, blindly performing writes. After 5ms, the LCD control- ler is ready to receive the next initialization command.

LCD Display Addressing

Each line of the LCD display has forty characters of Display Data RAM (DDRAM) associated with it. The forty RAM locations are organized as a circular buffer so that the last location wraps around and ends up beside the first. Of these forty characters, sixteen are visible in the display window. Sixteen characters are visible in a 2X16 display. If After the LCD is initialized by calling LCD_Init, the first character that is writ- we had a 2X20 display, the ten to the LCD is placed into DDRAM at location 80h. first 20 characters (DDRAM addresses 80h to 93h) would be visible. LCD Character Position (DDRAM Address) Larger displays use the 3940 19210311451361471581612 17 18 same DDRAM addresses.

Visible Display Window

After writing one character, the DDRAM address increments to 81h automati- cally, since LCD_Init sets Entry Mode to increment. Subsequent characters fill suc- cessive locations up to A7h (the 40th position) and eventually wrap around to C0h on the second line. Remember that display locations past 8Fh are not visible on a sixteen character display. To make these characters visible, the display contents can be shifted left or right. Moving the equates LCDLeft or LCDRight into W and issuing a CALL to LCD_Reg shifts the display one position left or right. The diagram on the next page illustrates the result of a display shift to the left. Chapter 12 Using ©1998 Sirius microSystems Microchip Code 117 the LCD Display LCD Character Position (DDRAM Address) 401210311451361471581617912 18 19

Visible Display Window after Display Shift

Notice that the display shift commands shift both lines of the LCD display in the specified direction.

Absolute Addressing Characters can be written to specific LCD locations (DDRAM Addresses) using the DDRAM Address command. The LCDLine1 and LCDLine2 equates incorporate the DDRAM Address command. The default position of LCDLine1 and LCDLine2 is at the beginning of DDRAM.

By adding an offset value of between 00h and 27h to the LCDLine1 and LCDLine2 equates, characters can be placed anywhere in DDRAM. For example, to display a character at the very last position on line 2 of the LCD, you would move the equate A more efficient method of LCDLine2 to W, add 0Fh to W, and then issue a call to LCD_Reg. doing this is moving the character position—in this Relative Addressing case CFh—directly to W before CALLing LCD_Reg. Movements can be made to the left or right of the current cursor position using the CURSLeft and CURSRight commands. Cursor refers to the current DDRAM location, and can be indicated on the LCD by an underscore ‘_’ or a blinking block if the cursor is on. Sending the CURSOn command displays the cursor as an under- score, and sending CURSBlink activates the blinking cursor.

Cursor movement occurs regardless of whether the cursor is on, off or blinking. Each time the CURSLeft or CURSRight command is sent, the cursor moves one position to the left or right.

Displaying LCD Characters

The program ASCII.ASM displays the LCD character corresponding to a three digit value (0-255) entered from the keypad. ASCII.ASM demonstrates LCD initiali- zation, LCD command writes, LCD character writes, absolute cursor positioning and the auto cursor increment mode.

Assemble and download ASCII.ASM can be used to view all of the characters the LCD is able to display. ASCII.HEX to a Codes 032-127 display the standard ASCII character set, and codes from 128-255 PIC16F84. Characters show some Kanji, Greek, accents and other characters. Codes 0-7 display custom will not display until all characters, codes 8-15 repeat the custom characters, and codes 16-31 are blank. three digits have been entered. Pull ASCII.ASM from the Pull-out Program References section as we dissect it.

Displaying LCD Characters 118 Microchip Code ©1998 Sirius microSystems ;Equates required by BIN2DEC.LIB and DEC2BIN.LIB: Hundreds DS 1 ;Hundreds digit Tens DS 1 ;Tens digit Ones DS 1 ;Ones digit

;Other equates Counter DS 1 ;LCD character counter

Counter1 DS 1 ;LCD delay counter Counter2 DS 1 ;LCD delay counter

Key DS 1 ;Key return code variable

Digit DS 1 ;ASCII digit counter variable Let’s begin by examining the Equates section. Hundreds, Tens, and Ones store the three digits that make up the character code. They also happen to be the variable names required by DEC2BIN.LIB. The subroutine Dec_Bin, in DEC2BIN.LIB, con- verts the three decimal digits in Hundreds, Tens, and Ones to an equivalent binary number.

Counter1 and 2 variables are used by the LCD Delay_5ms subroutine. Counter is used to read a data table containing text for line 1. Key is used to hold the key return code after a scan of the keypad. ASCII.ASM remaps the value in key so that only the digits 0-9 are entered from the keypad. Digit keeps track of how many digits of the code have been entered.

ORG 00h ;Start program at Reset Vector

CLRF Key ;Clear Key return variable CLRF Counter1 ;and delay counters CLRF Counter2 GOTO Initialize ;Continue with initialize routine

ORG 05h ;One location past Interrupt Vector

Include ‘DEC2BIN.LIB’ ;Decimal to Binary conversion routin Include ‘KEYPAD.LIB’ ;Keypad scanning subroutine library Include ‘LCD.LIB’ ;LCD subroutine library

After clearing some of the variables, GOTO Initialize jumps over the included subroutines. Initialize continues with CLRF Digit.

Initialize ;This subroutine initializes the LCD display and writes ;a message on to line 1 and ‘=’ on to line 2. The cursor ;is turned on to indicate where input will be shown.

CLRF Digit ;Clear digit counter CALL LCD_Port ;Set up ports for LCD use CALL LCD_Init ;Initialize LCD and clear screen CALL Disp_Init ;Send first line

The LCD_Port and LCD_Init subroutines are parts of LCD.LIB. LCD_Port configures Ports A and B for use with the LCD. As seen earlier, LCD_Init initializes the LCD (by sending the LCDFunction as outlined by the LCD_Init pseudo-code), clears the display, resets the cursor to the home position (position 1 of line 1), and sets cursor increment mode. Let’s take a closer look at LCD_Port.

Chapter 12 Using ©1998 Sirius microSystems Microchip Code 119 the LCD Display LCD_Port ;Initializes the Port B tristate buffers as outputs for ;LCD data lines. Sets Port A to digital (on PIC16C71) and ;sets the LCD Register Select, Read/~Write, and Enable ;lines to outputs.

If you use LCD.LIB with BSF RP0 ;Select memory register page 1 the PIC16C711, remove the semicolons from the ;the next two lines are for the PIC16C711 only and should b commented-out code. The ;removed for the PIC16F84 (PM produces an error when this ;is assembled for the ’84). ‘711 powers up with Port A in analog mode. Before ;MOVLW 03h ;1’s set Port A to digital using the LCD, Port A must ;MOVWF ADCON1 ;Write W to ADCON1 (88h) be configured for digital MOVLW 11111000b ;Set lower 3 bits of RA to output. ANDWF TRISA ;digital output in TRISA CLRF TRISB ;Set Port B to output BCF RP0 ;Go back to register page 0 From LCD.LIB BCF LCDE ;Keep LCD Enable line off RETURN ;Ports are now set up for LCD LCD_Port sets the lower three pins of Port A as outputs. ANDing the literal into TRISA does this without disturbing the upper two pins of Port A. All of Port B is used as outputs to send data and commands to the LCD. (Remember, a call to LCD_Init, which we’ve already described, follows LCD_Port.)

Call Disp_Init, the last Initialize command, can now display the text ‘ASCII Code=Char.’ on the first line of the LCD.

Disp_Init ;Writes ‘ASCII Code=Char.’ to the first line of the LCD ;display using LCD display library (LCD.LIB).

CLRF Counter ;Reset character counter Get_Char MOVF Counter,0 ;Get character offset into W CALL Message ;use it to get character IORLW 00h ;RETLW won’t affect flags so use OR BTFSC Z ;check for end of message RETURN ;and finish if done CALL LCD_Data ;If not done, send character to LCD INCF Counter,1 ;Add 1 to Counter GOTO Get_Char ;Do it again for the next character

Message ADDWF PCL ;Offset program counter by adding W RETLW ‘A’ ;Message RETLW ‘S’ RETLW ‘C’ RETLW ‘I’ RETLW ‘I’ RETLW ‘ ‘ RETLW ‘C’ RETLW ‘o’ RETLW ‘d’ RETLW ‘e’ RETLW ‘=’ RETLW ‘C’ RETLW ‘h’ RETLW ‘a’ RETLW ‘r’ RETLW ‘.’ RETLW 0 ;End of message The Disp_Init subroutine is basically the same as Get_Char in Key.ASM (see Chapter 10 for a more detailed explanation). The Counter variable points to the position of the character in the Message data table. Each time the loop calls Message, Counter offsets the Program Counter to retrieve the next character from the table. Displaying LCD Characters 120 Microchip Code ©1998 Sirius microSystems RETLW returns the numeric value for the character in quotation marks in W. The CALL LCD_Data instruction writes the character value in W to the current position of the LCD DDRAM.

LCD_Data ;Load W with the ASCII character code to send to LCD. ;LCD_Data outputs the character to the LCD and blips ;the enable line with LCD_Enable to complete the send.

BCF LCDRS ;Enter register mode MOVWF PORTB ;and send W to LCD on Port B CALL LCD_Check ;Check LCD busy flag BSF LCDRS ;Enter ASCII mode GOTO LCD_Enable ;Send ASCII character From LCD.LIB LCD characters are written to the display by placing the ASCII value on Port B, setting the LCDRS line, and pulsing the LCD enable line. Before writing a new character, the LCD must have finished the last operation. CALL LCD_Check moni- For more detail, examine tors the busy flag and returns when the LCD is not busy. the LCD.LIB file.

After the CALL to LCD_Data writes the character, Counter increments. If the returned character is zero, BTFSC Z does not skip to CALL LCD_Data, but instead returns to the calling subroutine.

Using the technique of marking the end of the message with a specific charac- ter—zero in this case—allows this subroutine to be used for messages of varying lengths. Zero is a good character to use as a marker since it sets the Z flag. Unfortu- nately, RETLW does not affect any flags. Thus, the returned character is first OR’ed with 00h because IORLW will set flags.

You can’t use the name Send_Equals MOVLW LCDLine2 ;Load W with address of line 2 (C0h) ‘Send=’ as a label, since ADDLW 0Ah ;and offset cursor to position 11 CALL LCD_REG ;Send cursor position to LCD ‘=’ means EQUate. MOVLW ‘=’ ;Load W with ASCII ‘=’ CALL LCD_Data ;and send to LCD for display

The Send_Equals routine positions an equals sign at line two, position eleven. Loading LCDLine2 loads the first DDRAM address of line two into W. Adding 0Ah to W increases the DDRAM address in W by 10. The call to LCD_Reg moves the cursor to DDRAM position CAh, the 11th position on the LCD.

LCD_Reg ;Load W with LCD software constant from table, above. ;LCD_Reg outputs the command to the LCD and blips the ;enable line with LCD_Enable to complete the command.

BCF LCDRS ;Enter register mode MOVWF PORTB ;and send W to LCD reg. on Port B CALL LCD_Check ;Check LCD busy flag GOTO LCD_Enable ;Send register command From LCD.LIB LCD commands are written to the LCD by placing the command word on Port B, clearing the LCDRS line, and pulsing the LCD enable line. Once again, CALL LCD_Check ensures that the LCD has completed its last operation by checking the busy flag.

Send_Equals finishes by loading W with the code for ‘=’ and the call to LCD_Data writes this code to the current DDRAM address. Chapter 12 Using ©1998 Sirius microSystems Microchip Code 121 the LCD Display Set_Cursor MOVLW LCDLine2 ;Load W with address of line 2 (C0h) ADDLW 06h ;and offset cursor to position 7

CALL LCD_REG ;Send cursor position to LCD

Cursor_On MOVLW CursOn ;Load W with cursor on command (0Eh) CALL LCD_REG ;and send to LCD

CALL KB_Port ;Configures Port B for keypad Set_Cursor moves the current DDRAM address to position 7 of line 2 in the same way the ‘=’ sign DDRAM address was set.

Cursor_On turns on the underscore cursor by loading the CursOn equate into W and sending it to the LCD through the call to LCD_Reg. An underscore cursor is the default cursor used by LCD.LIB. To use the blinking cursor, replace CursOn with the equate CursBlink.

After setting up the LCD, KB_Port is called to reconfigure the I/O ports for the keypad.

Get_Key CALL KB_Scan ;Get Key return code MOVF Key,0 ;Check Key return code BTFSC Z ;for no key press (0=no key) GOTO Get_Key ;If no key pressed, try again

CALL Delay_5ms ;Wait for key to settle CALL Delay_5ms CALL Delay_5ms CALL Delay_5ms

CALL KB_Scan ;Read Key code after settling MOVF Key,0 ;Read Key code into W CALL Key_Remap ;and Remap key codes MOVWF Key ;Save new Key code to key The Main program routine retrieves and debounces keystrokes. The call to KB_Scan returns a value in Key. If Key equals zero, no key has been pressed, and GOTO Get_Key executes forming a wait loop.

Once a key has been pressed, Get_Key calls Delay_5ms four times to provide a 20 ms debounce delay. LCD.LIB requires a 5 ms delay routine called Delay_5ms anyway, and calling it four times provides 20 ms for the key switch contacts to settle. After the delay, KB_Scan is called again to obtain the now stable key return code. The Key code is loaded into W for remapping by the Key_Remap subroutine.

Remember, KEYPAD.LIB The reason for remapping the keypad is that a zero key value is needed. Keys are provides key codes from 1 easily remapped using a ROM data table. Remapping also eliminates key boundary to 16, and a key code of 0 indicates that no keys are pressed. ; Old key from KB_Scan gets remapped to new key values: ; +----+----+----+----+ +----+----+----+----+ ; | 1 | 2 | 3 | 4 | | 1 | 2 | 3 | 0 | ; +----+----+----+----+ +----+----+----+----+ ; | 5 | 6 | 7 | 8 | | 4 | 5 | 6 | 0 | ; +----+----+----+----+ ----> +----+----+----+----+ ; | 9 | 10 | 11 | 12 | | 7 | 8 | 9 | 0 | ; +----+----+----+----+ +----+----+----+----+ ; | 13 | 14 | 15 | 16 | | 0 | 0 | 0 | 0 | Displaying LCD ; +----+----+----+----+ +----+----+----+----+ Characters 122 Microchip Code ©1998 Sirius microSystems checking in the program. The key values returned from the Key_Remap routine can be directly input into the Hundreds, Tens and Ones variables without modification.

The NOP instruction is Key_Remap ADDWF PCL ;Use old Key to offset PC NOP ;No Key=0 code occupies the memory RETLW 1 ;old key 1 remapped to new key 1 location that represents the RETLW 2 ;old key 2 remapped to new key 2 result of adding 0 (from W) RETLW 3 ;old key 3 remapped to new key 3 to PCL. Since W will be a RETLW 0 ;old key 4 remapped to new key 0 RETLW 4 ;old key 5 remapped to new key 4 value from 1 to 16, the RETLW 5 ;old key 6 remapped to new key 5 NOP is needed to offset the RETLW 6 ;old key 7 remapped to new key 6 data table. RETLW 0 ;old key 8 remapped to new key 0 RETLW 7 ;old key 9 remapped to new key 7 RETLW 8 ;old key 10 remapped to new key 8 RETLW 9 ;old key 11 remapped to new key 9 RETLW 0 ;old key 12 remapped to new key 0 RETLW 0 ;old key 13 remapped to new key 0 RETLW 0 ;old key 14 remapped to new key 0 RETLW 0 ;old key 15 remapped to new key 0 RETLW 0 ;old key 16 remapped to new key 0

The Key_Remap data table works similarly to the Message data table. Note the NOP as the first entry. Even though a zero key value would never be passed to Key_Remap, we must account for a zero offset here so that the other Key values remap properly.

This jump table is similar MOVF Digit,0 ;Get digit count in W to the Case command in ADDWF PCL ;and offset PC with digit GOTO Digit1 ;First time through, write Hundreds some programming lan- GOTO Digit2 ;next, Tens guages. GOTO Digit3 ;then, Ones

When the first key is returned, Digit contains the value zero. The Digit value is loaded into W for use in a jump table. A jump table is similar to a data table except that instead of returning a value, it executes a GOTO based on the value in W. Since W is zero the first time this table executes, the PIC will be redirected to the Digit1 subroutine by the first GOTO.

Digit1 CALL LCD_Port ;Configure Ports for LCD MOVF Key,0 ;Get Key return code MOVWF Hundreds ;and store in Hundreds variable ADDLW 30h ;Convert Key to ASCII CALL LCD_Data ;and display on LCD INCF Digit ;Add one to digit counter GOTO Release ;Wait for user to release key

Digit2 CALL LCD_Port ;Configure Ports for LCD MOVF Key,0 ;Get Key return code MOVWF Tens ;and store in Tens variable ADDLW 30h ;Convert Key to ASCII CALL LCD_Data ;and display on LCD INCF Digit ;Add one to digit counter GOTO Release ;Wait for user to release key Digit1 and Digit2 are similar in function. They reconfigure the PIC I/O ports for the LCD, retrieve the Key value in order to save it in Hundred or Tens, and change the Key value to its ASCII equivalent by adding 30h to it. CALL LCD_Data then displays this ASCII digit and moves the cursor to the next DDRAM address. After incrementing the Digit counter, GOTO Release waits for the key to be released. Chapter 12 Using ©1998 Sirius microSystems Microchip Code 123 the LCD Display Release ;This is the opposite of the first key check. It waits for ;the Key code to be zero and pauses for the debounce delay.

CALL KB_Port ;Set Port B for keypad use Wait CALL KB_Scan ;Scan keypad MOVF Key,0 ;Check key for 0 BTFSS Z ;And if Z=1 key has bee released GOTO Wait ;Otherwise, wait for release CALL Delay_5ms ;Wait for key to settle CALL Delay_5ms CALL Delay_5ms CALL Delay_5ms GOTO Main ;Get next digit The Release subroutine reconfigures the I/O ports for keypad scanning before performing a key scan. While a key is being pressed, the GOTO Wait line executes. When the key is released, another 20 ms debounce delay occurs. Without this delay, a key bounce on release would be interpreted as the next keystroke entered by the program.

Now that the first digit has been retrieved, stored in the Hundreds variable, and displayed on the LCD, GOTO Main starts the process again for the second digit.

The second digit is processed similarly, except that it is stored in the Tens vari- able. After returning to Main for the third digit, the Digit3 subroutine executes.

Digit3 CALL LCD_Port ;Configure Ports for LCD MOVF Key,0 ;Get Key return code MOVWF Ones ;and store in Ones variable ADDLW 30h ;Convert Key to ASCII CALL LCD_Data ;and display on LCD

Move_Cursor MOVLW LCDLine2 ;Load W with address of line 2 (C0h) ADDLW 0Ch ;and offset cursor to position 13

CALL LCD_REG ;Send cursor position to LCD

CALL Dec_Bin ;Converts Hundreds, Tens Ones to bin CALL LCD_Data ;and display on LCD

CLRF Digit ;Reset digit counter

Reset_Cursor MOVLW LCDLine2 ;Load W with address of line 2 (C0h) ADDLW 06h ;and offset cursor to position 7

CALL LCD_REG ;Send cursor position to LCD The third digit is saved to the Ones variable and is displayed on the LCD in the same way as the first and second digits were. The Move_Cursor subroutine moves the DDRAM address to point to position 13 on line 2 of the LCD so that the charac- ter just entered can be displayed on the opposite side of the ‘=’ sign.

When Dec_Bin is called, the binary digit values stored in Hundreds, Tens and Ones are converted into a single binary number which is returned in W. The call to LCD_Data displays the this character represented by this number on the LCD.

Before exiting the Digit3 routine, the Digit counter is reset and the cursor is repositioned to the DDRAM address C6h (the Hundreds digit location). After Digit3 finishes, execution falls through to the Release subroutine. After debouncing, execu- tion returns to Main so the next character code can be entered.

124 Microchip Code ©1998 Sirius microSystems Creating Custom Characters

We now know how to display any of the ASCII, Kanji or Greek characters on the LCD. There are times, however, when other special characters are needed. CUSTOM.ASM demonstrates how to create custom characters, perform single char- acter cell animation, and scroll messages.

First, assemble and download CUSTOM.ASM to a PIC16F84. Once you see what it does, we’ll look at how custom characters are programmed.

CGRAM ASCII data values 0-7 display custom characters defined in the CGRAM ad- dresses. CGRAM is used to store custom generated characters. You can program a total of eight custom characters.

There are actually 64 CGRAM locations. Each custom character is stored in eight successive CGRAM locations. A CGRAM address command is made up of three fields as shown in the CGRAM Custom Character Programming diagram.

The first field (bits 7 and 6) contains 01 to denote the CGRAM addressing com- Refer back to the LCD mand mode. CGRAM address bits 5, 4 and 3 designate the ASCII character code Controller Commands being programmed. These three bits accommodate the definitions for eight character chart to see why bits seven codes (000-111). Finally, CGRAM address bits 2, 1 and 0 specify one of the eight and six are 0 and 1. rows of the character being defined (Character Row Select bits).

At each CGRAM address, data CGRAM Custom Character Programming corresponding to one line of the cus- CGRAM Address bits CGRAM Data bits tom character must be stored. The 7 6 5 4332211007 6 5 4 character chart at left shows how char- 0 1 0 0 0 0 0 0 0 0 0 00000 acter 0 (Truck1) in the program is de- 0 1 0 0 0 0 0 1 0 0 0 0001 1 0 1 0 0 0 0 1 0 0 0 0 00011fined. 0 1 0 0 0 0 1 1 0 0 0 01111 0 1 0 0 0 1 0 0 0 0 0 01111 Each character is a 5X8 cell. The 0 1 0 0 0 1 0 1 0 0 0 11010 Character Row Select bits are used to 0 1 0 0 0 1 1 0 0 0 0 00111select the row being defined. The data 0 1 0 0 0 1 1 1 0 0 0 00010 based on the character bitmap must

CGRAM ASCII Char. Character be written to the CGRAM address for Address Char. Row Bitmap each row. In pseudo-code, this char- Mode Code Select acter would be programmed as shown:

In CUSTOM.ASM, this Load W with LCDCGRAM (CGRAM starting address - 01000000b) procedure is accomplished CALL LCD_Reg to write CGRAM address to LCD using a ROM data lookup Load W with character data for row 1 (00000000b) table. Like DDRAM, CALL LCD_Data to write data to CGRAM address 01000000b CGRAM addresses auto- matically increment after Load W with character data for row 2 (00000011b) CALL LCD_Data to write data to CGRAM address 01000001b CGRAM is written. As . character rows are written, . CGRAM increments into . the next character. Load W with character data for row 8 (00000010b) CALL LCD_Data to write data to CGRAM address 01000111b Chapter 12 Using ©1998 Sirius microSystems Microchip Code 125 the LCD Display Pull-out and refer to the CUSTOM.ASM program as we describe it.

Initialize ;This subroutine initializes the LCD display and programs ;the custom characters by calling Prog_Character.

CALL LCD_Port ;Set up ports for LCD use CALL LCD_Init ;Initialize LCD and clear screen CALL Prog_Character ;Load LCD with custom characters

After the ports have been configured for LCD use and the LCD has been initial- ized, Prog_Character is called to program the custom characters.

Prog_Character ;Loads the custom character data into the LCD Character ;Generator RAM. CGRAM is ASCII characters 0-7. Each charact ;is loaded as a bit-map, one line at a time. The cursor ;auto-increments to the next CGRAM location after each ;write.

MOVLW LCDCGRAM ;Send LCD CGRAM address (40h) to CALL LCD_REG ;LCD as a command CLRF Counter ;Reset character counter Get_Char MOVF Counter,0 ;Get character offset into W CALL Characters ;use it to get character data CALL LCD_Data ;If not done, send character to LCD INCF Counter,1 ;Add 1 to Counter MOVLW 64 ;Load W with number of char. bytes SUBWF Counter,0 ;and compare with Counter BTFSC Z ;by checking Z flag RETURN ;If Counter=64, we’re done GOTO Get_Char ;Do it again for the next character

Characters ADDWF PCL ;Offset PC with Counter in W

Truck1 RETLW 00000000b ;Row 1, ASCII character 00 RETLW 00000011b ;Row 2, ASCII character 00 RETLW 00000011b ;Row 3, ASCII character 00 RETLW 00001111b ;etc. RETLW 00001111b RETLW 00011010b RETLW 00000111b RETLW 00000010b

Truck2 RETLW 00001111b ;Row 1, ASCII character 01 RETLW 00001111b ;Row 2, ASCII character 01 RETLW 00001111b ;etc. RETLW 00001111b . . . Man4 RETLW 00000000b ;Row 1, ASCII character 07 RETLW 00000000b ;Row 2, ASCII character 07 RETLW 00000001b RETLW 00000011b RETLW 00000001b RETLW 00000011b RETLW 00000001b RETLW 00000000b ;Row 8, ASCII character 07 MOVLW LCDCGRAM and CALL LCD_Reg set the LCD to the first CGRAM address. The Counter variable is used to point to and return the custom character row data from the ROM data table.

CALL Characters and CALL LCD_Data retrieves the current row data from the data table and writes it to CGRAM. CGRAM automatically increments to the next address. Counter is incremented by INCF and is used to determine when the end of Creating Custom Characters 126 Microchip Code ©1998 Sirius microSystems CGRAM data has been reached, as well as to point to the next row data in the data table.

MOVLW 64 loads W with the number of CGRAM addresses to be programmed. 64 is the number of charac- SUBWF Counter,0 subtracts W from Counter, leaving Counter unchanged. If the ter rows in the data table. result is zero, Counter equals 64 and CGRAM is programmed. Otherwise, BTFSC Z skips the RETURN and the next character is programmed into CGRAM.

MOVLW LCDLine1 ;Load W with Line 1 address MOVWF Position ;Save W in Position register CALL LCD_REG ;and send to LCD as command MOVLW 04h ;Load W with Man1 Character code MOVWF Counter ;and save in LCD character counter

Walk ;Makes a little man walk across the screen by successively ;writing each of the 4 Man characters into the same cursor ;position and then moving the cursor 1 position to the ;right before repeating.

MOVF Counter,0 ;Get current Man Character CALL LCD_Data ;and send to LCD MOVLW CursLeft ;Load W with Cursor Left shift CALL LCD_Reg ;command and send to LCD CALL Delay ;Wait a bit INCF Counter ;Increment to next Man Character MOVLW 08h ;Load W with number of last Man SUBWF Counter,0 ;and check for last count BTFSS Z ;by checking Z GOTO Walk ;If not at last Man, display next ma

MOVLW ‘ ’ ;If at last Man, Load W with ‘ ‘ CALL LCD_Data ;to clear character INCF Position ;Increment cursor position variable MOVLW 04h ;Load W with Man1 Character MOVWF Counter ;and save to character counter MOVLW 90h ;Load W with last visible position SUBWF Position,0 ;and compare with Position BTFSS Z ;by checking Z GOTO Walk ;If not at last position, do it agai

CALL Delay ;If done, wait before rolling Truck

After the Prog_Character routine completes, both W and the Position variable are set to 80h by the LCDLine1 equate. Position is used to keep track of the DDRAM address—the character position of the man on the display. Calling LCD_Reg sets the LCD to line 1, position 1. Then the ASCII value of the first Man character (04h) is The Man 1-4 characters loaded into the Counter variable. have been programmed as ASCII characters 4-7. The Walk routine successively writes each of the four Man characters into one DDRAM address to create an animation. Then, the current DDRAM address is cleared and the four Man characters are written to the next DDRAM address. The result is the appearance of motion within each character position, and also across the LCD.

MOVF Counter,0 and CALL LCD_Data move the ASCII code of the current Man character to the LCD display. MOVLW CursLeft and CALL LCD_Reg move the cursor back to the last DDRAM address so the next Man character can overwrite the first. A nested delay loop is used to keep the current Man character on the display long enough for you to see it.

Chapter 12 Using ©1998 Sirius microSystems Microchip Code 127 the LCD Display Next, Counter is incremented and compared with 08h. If Counter is not equal to 08h, the four Man characters have not been displayed and the GOTO Walk is ex- ecuted. If Counter equals 08h, all four Man characters have been displayed, and the current position must be cleared.

MOVLW ‘ ’ and CALL LCD_Data write a space character to clear the cell address. MOVLW 04h and MOVWF Counter reset Counter to ASCII code 04h— the first Man character.

INCF Position updates the position counter in preparation for a check to see if the end of the LCD screen has been reached. While Position is less than 90h, the GOTO Walk command executes, continuing the loop that displays the four Man characters in the next DDRAM cell. When Position reaches 90h, the Man has reached the end of the screen and a short delay occurs before the Roll routine executes.

Roll ;Scrolls a Truck back across the screen continuously by ;writing the 4 Truck characters off the screen (cursor was ;left at position 90h by Walk) and then scrolling the ;screen to the left. Since the display was cleared earlier ;you will see only the Truck. The line length is 40 chars. ;Every 40 display shifts, the Truck comes around again. The :Next loop could have been replaced by four CLRF Counter ;Clear character counter variable independent MOVLW and :Next MOVF Counter,0 ;Load W with counter CALL LCD_Data opera- CALL LCD_Data ;and send character to LCD INCF Counter ;Increment Counter register tions. This would have MOVLW 04h ;Load W with number of Truck chars. taken about the same SUBWF Counter,0 ;and compare with counter amount of PIC program BTFSS Z ;by checking Z memory. GOTO :Next ;If not done, send next Truck char. :Loop MOVLW LCDLeft ;If done, load W with LCD shift left CALL LCD_Reg ;command and send to LCD CALL Delay ;Wait a bit GOTO :Loop ;Keep scrolling the display In Roll, the LCDLeft command is used to scroll the entire DDRAM contents from right to left generating the illusion of motion. Also of note is that the Truck characters are written off the visible display screen (locations 90h to 93h) and are scrolled into the visible window. Since DDRAM is configured in a circular fashion, the Truck drives by every forty display shifts.

The Counter variable is used to hold the ASCII character code to be displayed. Counter is cleared to start at ASCII character 00h—the front of the Truck from the CGRAM Custom Character Programming chart. The ASCII code is moved into W The Walk routine exits and CALL LCD_Data places the first Truck character at the current DDRAM loca- when the DDRAM address tion (90h from the end of the Walk subroutine). The LCD DDRAM pointer auto- increments to 90h. matically increments to the next address. Counter is incremented and checked before the next ASCII character, Truck2, is written to DDRAM.

After all four Truck characters have been written to DDRAM, the :Loop subrou- tine shifts the DDRAM contents left by writing the LCDLeft equate as a command. A nested delay loop separates successive shifts and completes the illusion of motion.

Notice the colon (:) in front of the :Loop label. The colon denotes that :Loop is a local label. Both this :Loop and :Next belong to the Roll routine.

128 Microchip Code ©1998 Sirius microSystems Delay ;Delay between Man & Truck movements

:Loop DECFSZ Counter1,1 ;Decrement first counter GOTO :Loop ;256 times DECFSZ Counter2,1 ;Decrement, second counter GOTO :Loop ;256 more times RETURN

Delay_5ms ;Delay loop used to initialize LCD

CLRF Counter1 ;Wipe first counter MOVLW 1Ah ;Load W with timer Constant MOVWF Counter2 ;for Counter2

:Loop DECFSZ Counter1,1 ;Decrement first counter GOTO :Loop ;256 times DECFSZ Counter2,1 ;Decrement, second counter GOTO :Loop ;from constant, above RETURN The Delay and Delay_5ms subroutines also include :Loop labels. The PM as- sembler associates each :Loop label with the routine in which it resides. You can re- Not all assemblers support local labels. use local label names, and as long as they are placed in separate routines, they won’t be mistaken for one another when they are called.

Chapter Summary

LCDs have a number of features dependent on their internal controller. In order to use LCDs you need to know the commands necessary to operate the LCD control- ler.

In the PIC-MDS, three Port A lines connect to the LCD control lines. Port B connects to the LCD data bus. LCD.LIB contains the subroutines which configure the ports, intitialize the display, and write commands and data to the LCD.

The LCD displays a window of 16 characters in a 40 character long circular buffer. This DDRAM buffer is addressable and can be shifted left or right to provide text scrolling.

Eight custom characters can be programmed into the LCD CGRAM.

Chapter 12 Using ©1998 Sirius microSystems Microchip Code 129 the LCD Display Questions

1. What is the difference between absolute and relative character addressing?

2. How many custom characters can be programmed into the LCD CGRAM?

3. Describe the function of the three LCD control signals.

4. How is it possible for the LCD to share Port B with the keypad and LEDs?

Assignment

1. Read the LCD.LIB include file and describe the function of each subroutine.

2. In pseudo-code, list the steps required to display the words ‘Hello World!’ on the LCD.

3. Modify the program ASCII.ASM so that one key backs the cursor up by one position to fix entry mistakes.

4. Modify ASCII.ASM to be a decimal to binary conversion calculator. Instead of displaying the ASCII character equivalent to the digits entered, display the binary equivalent of the three digits. eg. entering 142 displays 10001110

5. Write a program that scrolls a message across the LCD display.

6. Program a set of custom characters to provide a vertical bargraph display in one character position of the LCD. For testing, entering the numbers 1-8 on the keypad should indicate eight different levels on the bar graph.

After you have read and fully understood this entire chapter, you’ll find your brain has ex- panded to approximately five times its normal size.

130 Microchip Code ©1998 Sirius microSystems Using the PIC16F84 13 Data EEPROM

One of the unique features of the PIC16F84 is its internal data EEPROM. The 64 bytes of EEPROM can be used to store data that must be retained while power is off such as passwords, operating defaults, tuning parameters or current operating modes. In contrast, the RAM registers lose their contents when power is off.

For example, a PIC16F84 can be used to replace the mechanical timer in a wash- ing machine. During the operation of the washing machine, the data EEPROM can be programmed with the current operating cycle: wash, rinse or spin. If power fails during the rinse cycle, the PIC16F84 in the washing machine will know enough to continue the rinse cycle when power returns, closely emulating a mechanical timer.

Using the PIC16F84 Data EEPROM

The PIC16F84 data EEPROM is not accessed in the same way as a file register. Instead, four file registers—EEDATA (08h), EEADR (09h), EECON1 (88h) and EECON2 (89h)—control access to the EEPROM.

EEADR is the data EEPROM address pointer and holds a value representing one of the sixty-four possible storage location addresses. EECON1 contains flags

These four file registers control access to the data EEPROM, here.

Chapter 13 ©1998 Sirius microSystems Microchip Code 131 Using the PIC16F84 Data EEPROM that control EEPROM reads (RD) and writes (WR), along with the write enable (WREN), write error (WRERR), and interrupt flag (EEIF) bits. EEDATA contains the data to be written to, or the data previously read from the EEPROM address pointed to by EEADR. EECON2 is used during EEPROM writes.

When the PIC16F84 is first powered up, the WREN bit is cleared, disabling writes to data EEPROM. The WREN bit must be set before EEPROM writes can EEPROM.LIB takes care of place. This protects the EEPROM contents during power up. To safeguard your data all of these details. from unwanted changes during a power down, brown-out or software failure, clear the WREN bit after storing your data. EEPROM writes also require that a specific sequence of bytes is written into EECON2 (see page 34 of the PIC16F8X data sheets).

EEPROM writes typically take 10 ms—or 25,000 processor cycles at 10 MHz. Writing successive values into the data EEPROM requires that you either poll the EEIF or WR bits, or use interrupts in your EEPROM write routine.

Reading From and Writing To the Data EEPROM

The program NVMEM.ASM displays the contents of the first four data EEPROM locations and prompts the user to enter a four-digit code. This code is stored in the first four data EEPROM locations before a power down message appears on the LCD display. After removing and reapplying power the program runs again, display- ing the previously entered four-digits. NVMEM.ASM demonstrates how values can be saved and restored despite power interruptions.

Pull NVMEM.ASM and EEPROM.LIB from the Program References section.

;Hardware Equates

ORG 0Ch ;Start of File register area

Counter DS 1 ;LCD character counter

Counter1 DS 1 ;LCD delay counter Counter2 DS 1 ;LCD delay counter

Key DS 1 ;Key return code variable

The Counter variable contains the offset used to retrieve characters from the data tables in the Disp_Line1, Disp_Line2 and Disp_Done subroutines. Counter1 and Counter2 are used in the 5 ms delay loop required by LCD.LIB. The Key variable contains the key return code used by KEYPAD.LIB.

Include ‘EEPROM.LIB’ ;EEPROM subroutine library Include ‘KEYPAD.LIB’ ;Keypad scanning subroutine library Include ‘LCD.LIB’ ;LCD subroutine library

After initializing the Key and Counter variables and resetting the program Ori- gin to 0005h, the EEPROM, KEYPAD and LCD libraries are included. Reading From and Writing To the Data 132 Microchip Code ©1998 Sirius microSystems EEPROM Initialize ;This subroutine initializes the LCD display and writes ;a message on to line 1 and ‘=’ on to line 2. The cursor ;is turned on to indicate where input will be shown.

CALL LCD_Port ;Set up ports for LCD use CALL LCD_Init ;Initialize LCD and clear screen CALL Disp_Line1 ;Send first line message to LCD Program initialization continues by calling the subroutines necessary to initialize the LCD. Disp_Line1 displays the message “Old Data: ” on line one of the LCD.

Disp_Line1 ;Writes ‘Old Data: ‘ to the first line of the LCD ;display using LCD display library (LCD.LIB).

CLRF Counter ;Reset character counter :Get_Char MOVF Counter,0 ;Get character offset into W CALL Message1 ;use it to get character IORLW 00h ;RETLW won’t affect flags, use OR to BTFSC Z ;check for end of message RETURN ;and finish if done CALL LCD_Data ;If not done, send character to LCD INCF Counter,1 ;Add 1 to Counter GOTO :Get_Char ;Do it again for the next character

Message1 ADDWF PCL ;Offset program counter by adding W RETLW ‘O’ ;Message1 RETLW ‘l’ RETLW ‘d’ RETLW ‘ ‘ RETLW ‘D’ RETLW ‘a’ RETLW ‘t’ RETLW ‘a’ RETLW ‘:’ RETLW ‘ ‘ RETLW 0 ;End of message

Disp_Line1 retrieves characters stored in the program memory by using a data table read. The Counter variable holds the character offset for the Message1 data table. The :Get_Char loop retreives one character at a time from Message1, sends the This structure is introduced character to the LCD for display, and increments the Counter variable before retriev- and described in detail in ing the next character. The loop exits with a RETURN when a “0” is read from the Chapter 10. data table.

Send_Old ;Reads EEPROM addresses 0-3 and writes the contents to the ;LCD display.

CLRF EEADR ;Select EEPROM address 00 :Loop CALL EE_Read ;Call EE_Read to place data into MOVF EEDATA,0 ;EEDATA, and read EEDATA into W CALL LCD_Data ;Copy W to LCD DDRAM INCF EEADR ;Increment to next EEPROM address MOVLW 04h ;Load W with number of data bytes SUBWF EEADR,0 ;and compare with EEADR BTFSS Z ;by checking Z GOTO :Loop ;If not at EEADR 04, get next data

Line2 MOVLW LCDLine2 ;Load W with line 2 DDRAM address CALL LCD_Reg ;and write to LCD CALL Disp_Line2 ;Send second line message to LCD The Send_Old routine reads the data from the first four EEPROM addresses. The ASCII characters equal to each data value are displayed. If the EEPROM in the Chapter 13 ©1998 Sirius microSystems Microchip Code 133 Using the PIC16F84 Data EEPROM All new PIC16F84 proces- PIC16F84 has never been programmed, you will likely see four blocks which repre- sors have FFh in the sent the character equal to the value 255. CLRF EEADR resets the EEPROM ad- EEPROM. The assembler dress pointer to 00h. CALL EE_READ reads the contents of the location specified can set the contents of the by EEADR and copies the contents into EEDATA. EEPROM at programming time. See Appendix C for information. EE_Read ;Sets the RD bit in EECON1 to read the contents of EEADR ;into EEDATA.

BSF RP0 ;Select memory register page 1 BSF RD ;Set the EECON1.RD bit to read BCF RP0 ;Return to memory register page 0 From EEPROM.LIB RETURN Reading data from the EEPROM requires that EEADR contains the address to be read and is completed by setting the RD bit in EECON1. The contents of the EEPROM location are transferred to the EEDATA register and can be read by the next program instruction. The PIC16F84 automatically clears the RD bit in prepara- tion for the next read.

Following the RETURN in EE_Read, MOVF EEDATA,0 transfers the data read from the EEPROM into W so that CALL LCD_Data can display a character equal to its ASCII value. EEADR is then incremented and compared with 04h, causing the first four locations (00h to 03h) to be read. If EEADR is less than 04h, the result of the SUBWF EEADR,0 instruction is not zero and the BTFSS Z does not skip the GOTO :Loop. Therefore, while EEADR equals 0, 1, 2 or 3, the GOTO :Loop in- struction executes and the value returned in EEDATA is displayed. After the four locations have been displayed, the Line2 routine displays the message “New Data: ” on the second line of the LCD.

The Disp_Line2 subroutine is a copy of the Disp_Line1 subroutine, but uses the Message2 data table.

MOVLW CursOn ;Load W with Cursor On command CALL LCD_Reg ;and write to LCD

Get_New ;Wait for key presses and after a debounce delay stores th ;ASCII value of the current key codes in EEPROM memory fro ;address 0-3.

CLRF EEADR ;Reset EEADR to the beginning CALL KB_Port ;Configure Port B for keypad

Get_Key CALL KB_Scan ;Get Key return code MOVF Key,0 ;Check Key return code BTFSC Z ;for no key press (0=no key) GOTO Get_Key ;If no key pressed, try again CALL Delay_5ms ;Wait for key to settle CALL Delay_5ms CALL Delay_5ms CALL Delay_5ms

CALL KB_Scan ;Read Key code after settling MOVF Key,0 ;Read Key code into W CALL Key_Remap ;and Remap key codes After the message “New Data: ” has been displayed, the cursor is turned on by the MOVLW CursOn and CALL LCD_Reg instructions. The CursOn command activates the underscore cursor at the current CGRAM address—which is always

Reading From and Writing To the Data 134 Microchip Code ©1998 Sirius microSystems EEPROM the address after the last character written. In this case, the cursor appears in the second space after the colon, since the last character of the message is a space.

CLRF EEADR resets the EEPROM address pointer to zero in preparation for entering and storing the four new character values. CALL KB_Port prepares Port B for the matrix keypad and CALL KB_Scan returns the key code in Key.

MOVF Key,0 transfers the key code to W and updates the Z flag. If the value of Key is zero, the BTFSC Z instruction does not skip the GOTO Get_Key instruction and the process loops until a key is pressed.

When a key is pressed, the four CALL Delay_5ms instructions provide a 20 ms delay for the key to settle so it is not bouncing when read the second time. Instead of writing a 20 ms delay routine, we chose to call the Delay_5ms routine required by LCD.LIB four times.

Once the key has settled, it is re-read and remapped to an ASCII value by the Key_Remap subroutine.

Key_Remap ;Changes key codes into ASCII values.

ADDWF PCL ;Use old Key to offset PC NOP ;No Key=0 code RETLW 30h ;key 1 remapped to ASCII 30h ‘0’ RETLW 31h ;key 2 remapped to ASCII 31h ‘1’ RETLW 32h ;key 3 remapped to ASCII 32h ‘2’ RETLW 33h ;key 4 remapped to ASCII 33h ‘3’ RETLW 34h ;key 5 remapped to ASCII 34h ‘4’ RETLW 35h ;key 6 remapped to ASCII 35h ‘5’ RETLW 36h ;key 7 remapped to ASCII 36h ‘6’ RETLW 37h ;key 8 remapped to ASCII 37h ‘7’ RETLW 38h ;key 9 remapped to ASCII 38h ‘8’ RETLW 39h ;key 10 remapped to ASCII 39h ‘9’ RETLW 41h ;key 11 remapped to ASCII 41h ‘A’ RETLW 42h ;key 12 remapped to ASCII 42h ‘B’ RETLW 43h ;key 13 remapped to ASCII 43h ‘C’ RETLW 44h ;key 14 remapped to ASCII 44h ‘D’ RETLW 45h ;key 15 remapped to ASCII 45h ‘E’ RETLW 46h ;key 16 remapped to ASCII 46h ‘F’

The Key_Remap subroutine is a data table that changes keycodes to ASCII Key remapping is ex- values before they are stored in the EEPROM. This way, the EEPROM holds data plained in more detail in that can be immediately displayed on the LCD without requiring conversion. the ASCII.ASM program found in Chapter 12.

MOVWF EEDATA ;Save new Key code in EEDATA CALL EE_Write ;Write key data to current EEADR CALL EE_Wait ;and wait for write to finish

CALL EE_Read ;Read current EEADR to check ;that EEDATA was written properly

CALL LCD_Port ;Configure Ports for LCD MOVF EEDATA,0 ;Get saved Key code from EEPROM CALL LCD_Data ;and display on LCD

The remapped key value is stored in the EEDATA register by MOVWF EEDATA. The CALL to EE_WRITE stores the contents of the EEDATA register into the EEPROM location pointed to by EEADR. The first time through, EEADR will be 00h since it was cleared at the start of the Get_New routine. Chapter 13 ©1998 Sirius microSystems Microchip Code 135 Using the PIC16F84 Data EEPROM EE_Write ;Writes the contents of EEDATA to EEADR as specified in ;the PIC16F84 data sheets after enabling WREN. After ;writing the data, WREN is cleared, disabling accidental ;writes.

BSF RP0 ;Select memory register page 1 BSF WREN ;Enable EEPROM writes MOVLW 55h MOVWF EECON2 ;Write 55h to EECON2 MOVLW 0AAh MOVWF EECON2 ;Write AAh to EECON2 BSF WR ;Set EECON1.WR bit BCF WREN ;Disable any further writes BCF RP0 ;Return to memory register page 0 From EEPROM.LIB RETURN

EE_Write must first enable EEPROM writes by setting the WREN (WRite ENable) bit. The contents of EEDATA will be written into the EEPROM address specified by EEADR by setting the WR (WRite) bit . On power-up, the WREN bit is cleared, preventing unwanted EEPROM writes.

However, before the WR bit can be set—to write EEDATA into the EEPROM— a unique pattern of bits must be written to EECON2. See page 34 of the PIC16F8X data sheets for more detail. Following this peculiar initialization of writing 55h and 0AAh to EECON2, BSF WR initiates the internal PIC16F84 write sequence. The write sequence can take up to 10 ms to complete. When the internal sequence is complete, the contents of EEDATA have been transferred to the address in EEADR, and the PIC clears the WR bit and sets the EEIF bit.

After initiating the write using BSF WR, BCF WREN disables further EEPROM writes, safeguarding the data from being overwritten by program errors, brown-outs or erratic behaviour on power-down. Even though the write sequence initiated by BSF WR may not be complete, it is safe to disable further EEPROM writes.

Since the RETURN from EE_Write occurs before the internal EEPROM write sequence is complete, subsequent EEPROM writes cannot occur until the previous write has finished. A wait loop is provided by EE_Wait.

EE_Wait ;Wait for an EE_Write to finish by checking the EEIF ;flag bit in EECON1.

BSF RP0 ;Select memory register page 1 :Wait BTFSS EEIF ;Check EEIF for a high (1=finished) GOTO :Wait ;If low, wait for EEIF to go high BCF EEIF ;Clear EEIF after write is done BCF RP0 ;Return to memory register page 0 From EEPROM.LIB RETURN The completion of an EEPROM write is indicated by the PIC clearing WR and setting EEIF. EE_Wait monitors the EEIF interrupt flag bit. Before the next write can take place, the EEIF flag must be reset by software. A program could also moni- tor the WR bit, since the WR bit is cleared automatically after the write sequence finishes.

Following the RETURN from EE_Wait, the CALL to EE_Read retreives the recently written data from the EEPROM to verify that the value of the key press is stored properly. Although the program does no real checking, reading back the Reading From and Writing To the Data 136 Microchip Code ©1998 Sirius microSystems EEPROM EEPROM data allows you to verify the keypress. In this case, the recently written Remember, all of this is value is displayed on the LCD by CALL LCD_Port, MOVF EEDATA,0 and CALL still part of the write LCD_Data. sequence initiated about two pages back.

CALL KB_Port ;Set Port B for keypad use Wait CALL KB_Scan ;Scan keypad MOVF Key,0 ;Check key for 0 BTFSS Z ;And if Z=1 key has been released GOTO Wait ;Otherwise, wait for release CALL Delay_5ms ;Wait for key to settle CALL Delay_5ms CALL Delay_5ms CALL Delay_5ms Like the key press code, the key release code waits for the key to settle when you remove your finger from the keypad. The only change from the key press code is the BTFSS Z which causes the loop to wait until the key is released. Once the key is released, 20 ms is provided for settling time by calling Delay_5ms four times.

INCF EEADR ;Increment to next EEPROM address MOVLW 04h ;Load W with number of data bytes SUBWF EEADR,0 ;and compare with EEADR BTFSS Z ;by checking Z GOTO Get_Key ;If not at EEADR 04, get next data CALL LCD_Port ;Reconfigure ports for LCD MOVLW LCDLine1 ;Load W with line 1 DDRAM address CALL LCD_Reg ;and write to LCD CALL Disp_Done ;Display done message SLEEP

At this point, the first value has been entered from the keypad, saved in the EEPROM, read from the EEPROM, and displayed on the LCD. The EEADR regis- ter is now incremented by INCF EEADR so that the process can repeat for the next three characters.

Until four characters have been entered, MOVLW 04h, SUBWF EEADR,0 and You may have noticed that BTFSS Z cause the execution of GOTO Get_Key to repeat the key scanning, storing, Disp_Done is slightly retrieval, and display process. When the fourth value has been retrieved via the GOTO different from other data Get_Key instruction, the result of SUBWF EEADR,0 will be zero and the zero flag tables. It uses a technique will be set. The BTFSS Z will then cause GOTO Get_Key to be skipped, and the re- explained in Chapter 14 maining commands set up the LCD and call Disp_Done to display the message “Power that overcomes memory down now.”. The SLEEP command at the end of the main line code places the page boundry problems that would otherwise PIC16F84 into low power sleep mode. prevent this code from working. The result is that the NVMEM.ASM program has now placed four new values, representing the four keys pressed on the keypad, into the internal EEPROM. Re- moving power from the microcontroller will not erase these values. Try it and see.

Chapter Summary

The internal EEPROM can retain its data while power to the PIC is off. The 64 bytes of EEPROM data are accessed using the EEDATA and EEADR registers along with EECON1 and EECON2. EECON1 contains control, flag and interrupt bits. Writing 55h and AAh to EECON2 in the manner specified by microchip (pg. 34 of the PIC16F8X data sheets) performs EEPROM writes. Chapter 13 ©1998 Sirius microSystems Microchip Code 137 Using the PIC16F84 Data EEPROM Questions

1. Examine the PIC16F8x data sheets to determine how long data will remain in the Data EEPROM.

2. List three applications that would benefit from the use of the Data EEPROM.

3. How much time, and how many clock cycles, does it take to store one byte in the Data EEPROM? Assume a clock speed of 4 MHz.

Assignment

1. Using pseudo-code or a flow chart, describe the operation of an interrupt serv- ice routine that stores successive bytes of data after waiting for the previous write to finish.

2. Write the program for a programmable combination lock that stores the pass code in the Data EEPROM. Use a 5-digit pass code to open or close the lock. Assign one key on the keypad to change the pass code only when the lock is unlocked. Display the state of the lock using either an LED or the LCD.

Questions 138 Microchip Code ©1998 Sirius microSystems 14 Troubleshooting

By this time you probably have the necessary skills to write reasonably complex programs. This chapter will help you develop the skills needed to troubleshoot them.

Identifying and Isolating Faults

The key to troubleshooting your software is identifying and isolating faulty sec- tions of code. There are a number of techniques useful for identifying, narrowing down and isolating faults. However, no one technique works all of the time. Each of the techniques explained below will help you to identify and isolate faults.

Validating Your Hardware

It makes no sense to troubleshoot software if your problem is in hardware. Using a development system such as the PIC-MDS gives you the advantage of knowing that the built-in hardware is at the very least wired correctly (really, we’ve tested it!). What’s more, the included software routines will let you verify the operation of the PIC-MDS hardware.

There comes a time, however, when you must strike out into uncharted territory and interface your PIC-MDS to new hardware. Before connecting new hardware to the PIC-MDS, there are a number of points to keep in mind.

I/O Requirements Before starting to troubleshoot software, make sure that input devices provide signals at the proper level—a logic 0 should be from 0 V to approximately 0.8 V, and a logic 1 should be from approximately 2 V to 5 V. At the very least confirm the presence of signals by monitoring the LEDs on the PIC-MDS. Better still, confirm signal presence, amplitude and waveform using a voltmeter, logic analyser, or oscil- loscope.

Chapter 14 ©1998 Sirius MicroSystems Microchip Code 139 Troubleshooting Test and examine all output circuitry to ensure that each PIC pin is not sinking more than 25 mA or sourcing more than 20 mA. Also, keep in mind that Port A can sink a maximum of 80 mA and can source a maximum of 50 mA. Likewise, Port B can sink a maximum of 150 mA and source a maximum of 100 mA. Lastly, the overall power dissipated by the PIC16F84 cannot exceed 800 mW.

Shared I/O Lines

Refer to the schematic in On the PIC-MDS, RA.2 and RA.3 are used to enable the LCD and Serial chapter 4 for details. EEPROM, respectively. Any external devices that enable either one of these two lines will cause unpredictable results on any of the lines connected to the LCD or Serial EEPROM. Since the LCD connects to all of Port B as well as three out of the five Port A pins, enabling it inadvertently can cause problems. Always disable the LCD and serial EEPROM if you’re not using them.

Since the keypad keys are normally open, they are, in essence, disconnected from the PIC-MDS, if not pressed. If pressed, a key will short one of the four row lines to one of the column lines on Port B. Resistors have been added to ensure that short circuit conditions do not occur. Nevertheless, your code might fail if someone were to press a key and inadvertently supply an input from a keypad row line to a keypad column line rather than obtaining its input from an external source. If you’re going to obtain input from Port B, make sure users are not prompted to use the keypad. If you wish to use the keypad and need to obtain external input, you may use only Port A.0, 1, or 4. Or, use half of the keypad thereby freeing up half of the Port B lines.

Similarly, while scanning for a key press, half of Port B is set to output and half to input. Make sure that devices connected to Port B outputs can have their lines temporarily scanned and that Port B inputs are disconnected (i.e. placed into high impedance or disabled). Again, if this presents a problem, use Port A.0, 1, or 4. For an example of how to share the keypad and LCD on Port B see ASCII.ASM as discussed in Chapter 12.

All owners of the PIC-MDS If your application requires you to use your own hardware design, use a design are permitted to use the similar to that of the PIC-MDS whenever possible—you know it works, and the PIC-MDS circuitry shown library routines will save you a lot of time in developing software. in Chapter 4 and the library routines included on disk in their microcon- troller designs. “Playing” the Computer

Once you are certain that your faults lie in software, you can begin to examine your code line by line. “Playing” the computer involves recording the state of each register as you determine the results of each instruction. Start with a print out of your source code and a blank piece of paper. Use the paper to record register contents before and after each instruction. Don’t take anything for granted—use the instruc- tion descriptions in the Data Sheets to determine the result of each instruction and the state of any affected flags.

As you can imagine, playing the computer is very time consuming. You would never want to simulate the execution of your entire program, only those sections that you believe may be faulty. Use some of the techniques which follow to narrow your troubleshooting to specific sections of code.

Validating Your Hardware 140 Microchip Code ©1998 Sirius MicroSystems Displaying Intermediate Values

If at all possible, use the built-in LEDs or LCD display on the PIC-MDS to monitor relevant register, port or bit values. Often, faulty code produces unexpected register values and program branches. One method to verify that your program is operating correctly up to a specific point is to insert code which writes the contents of a register out to the LEDs and then puts the microcontroller to SLEEP.

Using the LEDs is simple and quick. Make sure that you set Port B to output (if necessary), move the contents of the register that you are interested in examining to W, then copy them to Port B before issuing a SLEEP instruction to halt execution at this point. If the LEDs display the expected result, the program is functioning cor- rectly up to this point. You can then remove or comment out this code and place similar display code further down in your program.

The LCD allows you to display the contents of many more registers than the LEDs, but has the drawbacks of increased code complexity and the corruption of the W and Status registers. If the contents of W, or for that matter any registers, are important, save them in temporary file registers before accessing the LCD routines. Also, remember that values sent to the LCD are displayed as their equivalent ASCII character. At the risk of further increasing code complexity, you can convert values In almost all cases, using to decimal digits (using BIN2DEC.LIB), and add 30h to each digit to convert them to the LEDs will be simpler. ASCII digits.

External Triggers

Monitoring an unused I/O pin configured as a hardware flag or trigger can tell you two things. By setting an output pin high at the start of a subroutine and clearing it at the end of the subroutine you have a way of determining not only that the subrou- tine executes, but also how long it takes to execute, and whether execution is consist- ent. For long subroutines you can see this by using an LED connected to a port pin, but for short subroutines you will obviously need an oscilloscope or logic analyser.

These external flags or triggers can also be used to provide a reference by which to monitor other signals. This is especially useful for triggering oscilloscopes or logic analysers when monitoring external signals like serial data streams.

Commenting Out Code

When a program appears to do nothing, a common cause is an undesired branch out of the main program flow. This may be caused by an error in your branch logic, or a computed GOTO over a memory page boundary—this is explained later in this Chapter. If you comment out or branch over suspect code and program flow returns, then the bypassed code is most likely at fault.

Commenting out existing routines and placing alternative routines after them is Some people like to use an easy way to evaluate the effects of program modifications. different cases or tab stops to indicate modified code.

Chapter 14 ©1998 Sirius MicroSystems Microchip Code 141 Troubleshooting Isolating Faults within Subroutines

Once you have an indication that a particular subroutine is faulty, much of the work of troubleshooting is already finished, although you’ll find that isolating and fixing the fault within a subroutine will take the majority of your time. To isolate the fault within a subroutine, use the techniques already discussed. Playing the computer is much easier when you’re not trying to simulate the operation of your entire pro- gram. Similarly, commenting out code, displaying intermediate values, and setting external triggers will all help you in debugging your routine.

Another item to bear in mind is the validity of the data being fed to the subrou- tine. If a subroutine is being fed erroneous data by a previous routine, its results will also be in error. To determine if this is occurring, temporarily force load any variable registers used by the subroutine before the subroutine executes. This way, you know that at the very least the starting data is valid.

Taking Breaks and New Approaches

Never underestimate the benefit of a good stretch, coffee break, lunch break, nap or vacation as a troubleshooting tool. You may find that your subconscious mind will come up with the solution if given a bit of time. More often, looking at your problem in a new way will lead you to the correct solution.

One of the best ways of uncovering bugs is to try to explain the operation of your software to a colleague. This approach forces you to systematically break down and justify your code and logic. If your unfortunate victim is still paying attention, they may question your logic and assumptions to reveal your error. Most often, simply explaining your code (and the errors within) will allow you to recognize the fault.

Memory Page Boundaries

The mid-range PIC microcontrollers use a 13-bit address space capable of ad- dressing 8k X 14 bits of program memory. Since the PIC uses 8-bit wide data regis- ters, the program counter is divided into two parts, PCLATH and PCL. PCL, or the program counter low byte, specifies a range of 256 memory addresses representing one memory page. PCLATH, or the program counter high latch, is a 5-bit register controlling the active memory page. The actual address specified by the program counter is written as PCLATH:PCL and is the combined 13 bit address of PCLATH and PCL. For example, if PCLATH contained 03h, and PCL contained 10h, the resultant program counter value would be 310h. On the PIC16C711 and PIC16F84, only the first 1k addresses are implemented—equivalent to 4 memory pages.

Memory page boundaries occur whenever PCL rolls over from FFh to 00h and can present a problem during a table read when using the ADDWF PCL instruction. ADDWF is known as a computed GOTO and is used by the data table read code in previous chapters. The problem occurs only when the ADDWF PCL instruction is in one memory page, and the result of the computed GOTO lies in the next memory page. Adding an 8-bit value to PCL will not cause PCLATH to increment if PCL

Isolating Faults within Subroutines 142 Microchip Code ©1998 Sirius MicroSystems rolls over. The result is that the computed GOTO still points within the current memory page, and not to the next page as it should. Fortunately, all other GOTOs and branches correctly modify PCLATH so that the correct address is selected.

This precise problem occurs in the NVMEM.ASM program within the Disp_Done subroutine. Disp_Done uses a table read to display the message “Power down now.” on the LCD.

238 00E7- Disp_Done ;Writes ‘Power down now.’ to the first line of the LCD 239 ;display using LCD display library (LCD.LIB). 240 241 00E7- 018C CLRF Counter ;Reset character counter 242 00E8- 3000 :Get_Char MOVLW HI Message3 ;Move the High Byte of Message3 243 ;location into W 244 00E9- 008A MOVWF PCLATH ;and Move it into PCLATH 245 00EA- 30F6 MOVLW Message3+1 ;Move message address + 1 into W 246 00EB- 070C ADDWF Counter,0 ;Calculate offset address and 247 00EC- 1803 BTFSC C ;see if it overflows 248 00ED- 0A8A INCF PCLATH ;If so, increment PCLATH 249 00EE- 20F5 CALL Message3 ;Jump to the data table 250 251 00EF- 3800 IORLW 00h ;RETLW won’t affect flags so use O This table read code allows 252 00F0- 1903 BTFSC Z ;check for end of message 253 00F1- 0008 RETURN ;and finish if done data tables to be placed 254 00F2- 205A CALL LCD_Data ;If not done, send character to LC 255 00F3- 0A8C INCF Counter,1 ;Add 1 to Counter anywhere in memory, even 256 00F4- 28E8 GOTO :Get_Char ;Do it again for the next characte across page boundaries. 257 258 00F5- 0082 Message3 MOVWF PCL ;W contains low program counter 259 ;byte and points to next location 260 ;plus Counter offset 261 00F6- 3450 RETLW ‘P’ 262 00F7- 346F RETLW ‘o’ 263 00F8- 3477 RETLW ‘w’ 264 00F9- 3465 RETLW ‘e’ 265 00FA- 3472 RETLW ‘r’ 266 00FB- 3420 RETLW ‘ ‘ 267 00FC- 3464 RETLW ‘d’ 268 00FD- 346F RETLW ‘o’ 269 00FE- 3477 RETLW ‘w’ 270 00FF- 346E RETLW ‘n’ 271 0100- 3420 RETLW ‘ ‘ 272 0101- 346E RETLW ‘n’ 273 0102- 346F RETLW ‘o’ 274 0103- 3477 RETLW ‘w’ 275 0104- 342E RETLW ‘.’ 276 0105- 3420 RETLW ‘ ‘ 277 0106- 3400 RETLW 0 ;End of message

Notice in the list file generated by the assembler that the Message3 data table straddles a page boundary—addresses 00FF - 0100h. Compare this code with Disp_Line1 or Disp_Line2 in NVMEM.ASM and you will see that this table does not use the ADDWF PCL instruction to compute the GOTO. Instead, this subroutine determines whether or not to increment PCLATH by adding the offset to the table’s starting PCL value and checking for an overflow via the Carry bit. If an overflow occurs, then a page boundary has been crossed within the table and the PCLATH register must be incremented.

Notice that the above table read code will work in any memory page because the upper five bits of the table address are loaded into PCLATH before computing the GOTO. In contrast, an ADDWF PCL instruction that results in PCL rolling over leaves PCLATH unchanged. Therefore, a computed GOTO using ADDWF PCL across a page boundary results in the execution of instructions within the same page as the ADDWF PCL instruction—not the next page as expected.

To overcome memory page boundary problems with data tables, either use code that checks for and corrects page crossings (as in the example above), or make sure that your data tables and ADDWF instructions are in the same memory page—check the .LST file and use NOP instructions or rearrange code as necessary. Chapter 14 ©1998 Sirius MicroSystems Microchip Code 143 Troubleshooting A/D Converter Troubleshooting

The PIC16C711 Port A.0-3 lines can be set as digital I/O or analog inputs for the internal A/D converter. When using a Port A pin as both an analog input and a digital output, you must keep the following points in mind. Enabling A/D operation on a Port A pin does not configure the pin as an input. Before using a Port A output pin as an A/D input, the pin must first be configured as an input, then an A/D input. Your code may sometimes work without first configuring Port A pins as inputs because at power up all PIC I/O lines are set to input.

Simulators and Emulators

There are programs available that will simulate the operation of your program. Simulators are computer programs that can step through code, instruction by in- struction, while displaying the contents of registers, I/O latches, and memory. Obvi- ously, simulators are extremely useful in debugging as they can play the computer Some simulators use far better and faster than you could. The disadvantage of simulators is that they do stimulus files to emulate not run your code in real time, and, being inside your computer, have no way of external hardware signals. interacting with I/O devices that you may want to use with your microcontroller.

Emulators, on the other hand, do not suffer the limitations of simulators. Emula- tors incorporate circuitry that replaces the PIC in your target system. They run your software program in your hardware in real time. Furthermore, they allow you to stop the execution of your program and examine registers and memory at any point. Their only disadvantage is high cost.

Programming for Easy Troubleshooting

There are a number of programming techniques that make troubleshooting easier. By now, the benefit of using and reusing tested and proven subroutine libraries should be apparent. Why keep reinventing the wheel when simply adapting existing code to fit your application is a better alternative. The following suggestions will help you in developing your software.

Plan, Plan, and Plan Before you begin any programming task, make sure that you understand exactly what the program needs to do. Pay particular attention to any hardware devices that the microcontroller will need to interact with. Having specification sheets for any devices that you will be interfacing to is very useful.

Use pseudo-code and flowcharts to outline the program’s structure and break the program into identifiable and manageable tasks.

Code and Debug Individual Program Tasks After identifying program tasks, write the code for each individual task and verify that it works as expected. Then, join interdependent tasks into larger code segments. A psychological benefit of this approach is that you meet with small successes often. Bringing small successes together ensures larger successes. A/D Converter Troubleshooting 144 Microchip Code ©1998 Sirius MicroSystems Modularize Your Code When writing your software routines, keep in mind that you may wish to use them in other programs or with similar hardware. Writing program subroutines to incorporate similar structures, as well as using similar entry and exit parameters helps to improve the understanding of your programs. Easily changeable variables, defines in the equates at the beginning of the program, make for minor code changes when adapting your subroutines for different hardware.

Comments Good comments do not explain what the instructions are doing as much as they explain how and why the instructions in a routine are being used together. Subrou- tines are often preceded by extensive comments that explain the purpose of the sub- routine, important registers, registers modified, calling protocols and variables.

Another good use of comments is to record the revision history of your program. Use comments to keep track of which routines are working and debugged, any rou- tines that were modified to accommodate hardware changes, and work yet to be done. Heed this advice and your successors will profusely praise your programming prowess!

Chapter Summary

Effective troubleshooting entails systematically isolating and identifying pro- gram or hardware faults. Various techniques such as validating your I/O hardware, simulating program execution, halting program operation at specific points and dis- playing intermediate values help in uncovering program flaws.

Writing code in a manner that simplifies testing and debugging lessens the need for troubleshooting. Planning ahead, and writing code in manageable sections helps to ensure working code.

Be aware of unique hardware dependencies that may affect the operation of your software—the memory page boundary and A/D configuration are examples.

Chapter 14 ©1998 Sirius MicroSystems Microchip Code 145 Troubleshooting Questions

1. What is the central philosophy of troubleshooting?

2. Why halt the program when displaying intermediate values?

3. When would it be desirable to use the LCD to display intermediate values?

Assignment

1. Take any existing program of your own (working or not) and add code to display intermediate values in at least three different places.

2. Use an external trigger and an oscilloscope to time the execution of a subrou- tine in one of your programs.

Mr. Bugs Quasher was particularly good at debugging code using the “playing the computer” troubleshooting technique.

Questions 146 Microchip Code ©1998 Sirius MicroSystems RS-232 Serial 15 Communication

The RS-232 serial communication standard has attained widespread use and many devices can transfer data or be controlled using RS-232 signals. Typical de- vices include: computers, printers, plotters, modems, bar-code readers, operator in- terface terminals, motor controllers, data loggers, LCDs, GPS receivers, milling machines, PLCs and many more. This chapter will demonstrate how to send and receive RS-232 serial data.

RS-232 Basics

The RS-232 standard specifies the connector type, handshaking protocols and electrical characteristics for a serial communications link. The traditional RS-232 connector is a 25-pin DB-25, although recently the 9-pin DB-9 connector has be- come common on PCs. The PIC-MDS has a 3-pin header that you can connect to either a DB-9 or DB-25 connector as required. One pin transmits serial data, another pin receives serial data, and the third pin is a signal ground. Most RS-232 devices can be configured to communicate using only these three lines. Below is a diagram showing how to connect a DB-25 or DB-9 connector to the PIC-MDS 3-pin header.

Depending on the device or communication software used, you may only need to connect Transmit Data, Receive Data and Signal Ground. The other wires simulate hardware handshaking for devices that require it.

Chapter 15 RS-232 ©1998 Sirius MicroSystems Microchip Code 147 Serial Communication Handshaking can be used to start or stops the flow of data. Handshaking is necessary if a device cannot finish processing a character before the next character arrives. The RS-232 standard specifies hardware handshaking, but handshaking can be implemented using either hardware or software techniques. Hardware handshaking uses a number of the signal lines on the previous page to coordinate data flow and is UART stands for Universal usually implemented using a dedicated UART or serial communications interface. Asynchronous Receiver Transmitter, and is an IC Software handshaking relies on the transmission of special XON (Transmit on) dedicated to serial I/O. and XOFF (Transmit off) characters, which are sent and received using just the transmit and receive data lines. Therefore, a full-duplex, controlled serial communi- cations link can be established using only three lines—transmit, receive and ground. This makes software handshaking relatively easy to implement.

The RS-232 transmit and receive examples in this Chapter demonstrate serial communication without handshaking. Handshaking is usually not necessary when transmitting small amounts of data, or when the data can be processed at high speeds.

The RS-232 electrical signal is bipolar, unlike the unipolar 5 V TTL level sig- nals used by most computer systems. RS-232 voltage levels are also opposite to their equivalent TTL logic levels. For this reason, the PIC-MDS is equipped with a MAX232 level translator (see the schematic in Chapter 4). The diagram below shows the same RS-232 data frame as both TTL and RS-232 signal levels.

The serial ports on some PC’s will accept 5 V as a space, and 0V as a mark, eliminating the need for a dedicated level translator such as the MAX232. The clamping diodes on the PIC I/O pins allow RS-232 levels to be input directly as long as a series limiting resistor is used, again eliminating the need for a level translator. However, in both cases, the logic of the TTL waveform must be reversed.

An RS-232 data frame consists of a start bit, a number of data bits, an optional parity bit, and a stop bit. Most modern RS-232 devices communicate using eight data bits, no parity, and one stop bit—otherwise known as 8n1.

Note that the TTL logic level during the idle time between frames is 5 V. The start bit is always a logic 0, making it easy to determine when a frame begins. Even when frames follow one another, with no idle time, the logic 1 stop bit ensures there will be a high to low transition to mark the start of the next frame. After the start bit, the data bits are sent in least-significant to most-significant bit order. RS-232 Basics 148 Microchip Code ©1998 Sirius MicroSystems Receiving RS-232 Data

Since serial data bits are sent sequentially, receiving the data correctly is a matter of sampling the data bits at the correct times. The serial signal’s bit per second (bps) rate can be used to calculate the bit time, or the duration of each bit. The default data rate used by the RS-232 library programs is 9600 bps. We can calculate the bit time as follows:

The RS-232 receive and transmit library files support all common bps rates.

Once the bit time is known, receiving RS-232 data can be described by the fol- lowing pseudo-code:

Wait for the receive data line to drop low Wait ½ bit time Is receive data line still low? (Is it a Start bit or noise?) If not, low pulse was noise If low, wait 1 bit time Sample data bit 0 Wait 1 bit time Sample data bit 1 : Wait 1 bit time Sample data bit 7 Wait 1 bit time Is receive data line high? (Stop bit) If not, a framing error has occurred If high, data received

Examine the timing diagram, below, for a visual representation of the sample points used to receive RS-232 data: (Shown in postive logic or TTL form.)

The transmitted character shown here is 41h, or the ASCII character ‘A’.

Chapter 15 RS-232 ©1998 Sirius MicroSystems Microchip Code 149 Serial Communication The RECV232.ASM program uses RS232RX.LIB to receive serial characters and display them on the first line of the LCD. To test this program, use a terminal Make sure your terminal program on a personal computer connected to the PIC-MDS by a cable as described program is transmitting at earlier. Also, ensure that JU5 is on the Rx setting.We’ll examine the program begin- 9600 bps, 8 data bits, no ning with the hardware equates. parity and 1 stop bit—8n1.

;Hardware Equates

ORG 0Ch ;Start of File register area

;Counter equates CharAddress DS 1 ;Holds current LCD DDRAM address CharCounter DS 1 ;Counts characters before scroll Counter1 DS 1 ;Delay counter for Delay_5ms Counter2 DS 1 ;Delay counter for Delay_5ms

;Equates required by RS232RX.LIB Counter DS 1 ;Bit delay counter BitCounter DS 1 ;RS232 bit counter register Receive DS 1 ;Received byte storage register

;Other equates LCD_Length EQU 16 ;Number of characters per LCD line

The CharAddress, CharCounter and LCD_Length variables are used by the LCD scrolling routines. These variables, described later, allow the first 16 characters re- ceived to fill the LCD. Subsequent serial characters cause the previously received characters to scroll across the display from right to left. Counter1 and Counter2 are used by LCD.LIB to provide the 5 ms LCD initialization delay.

The RS232RX.LIB subroutine library requires the Counter, BitCounter and Receive variables. Counter is used to generate bit time delays and BitCounter keeps track of the number of received bits. Received data bits are shifted through the Re- ceive register. After eight bits are received, the Receive register contains the trans- mitted character.

ORG 00h ;Start program at Reset Vector

CALL LCD_Port ;Set up ports for LCD use CALL LCD_Init ;Initialize LCD and clear screen CALL Receive_Port ;Set RA.4 for serial input

At the start of the program, the LCD is initialized and cleared. The CALL to Receive_Port uses RS232RX.LIB to set RA.4 for serial input.

Receive_Port ;Sets PORTA.4 to input. Make sure PIC-MDS JU5 is set to Rx

BSF RP0 ;Select memory register page 1 MOVLW 00010000b ;Load W with bit to make RA.4 input IORWF TRISA ;and OR with Port A tristate reg. From RS232RX.LIB BCF RP0 ;Return to memory register page 0 RETURN

The Receive_Port subroutine sets TRISA.4 using an OR operation that leaves the other TRISA bits unchanged.

Receiving RS-232 Data 150 Microchip Code ©1998 Sirius MicroSystems GOTO Initialize ;Jump over interrupt vector

ORG 05h ;Program starts after interrupt vec

Include ‘LCD.LIB’ ;LCD subroutine library Include ‘RS232RX.LIB’ ;RS-232 receive library

Initialize ;Prepare character counters and LCD for data

MOVLW LCD_Length ;Load W with number of LCD characte MOVWF CharCounter ;and save in CharCounter then subtr DECF CharCounter ;1 to account for 0 position

MOVLW CursBlink ;Load W with constant to blink curs CALL LCD_Reg ;and write to LCD as a command

MOVLW LCDLine1 ;Load W with DDRAM address of line MOVWF CharAddress ;and save in CharAddress variable CALL LCD_Reg ;before writing it to the LCD After the include statements for the LCD and RS232RX library files, the Initial- ize routine begins. Initialize loads the CharCounter variable with LCD_Length (16 in this case) and then decrements CharCounter by 1 so that display scrolling begins after 15 characters have been received.

Next, the LCD cursor is enabled in blinking mode, and the LCD DDRAM ad- dress is set to the first character of line 1. The CharAddress variable also holds the current LCD address, so that it can be used to reset the DDRAM address after forty characters have been received. Saving CharAddress in a memory register frees the Forty characters is the program from having to interrogate the LCD to determine the current character ad- length of the LCD DDRAM dress. buffer. See Chapter 12 for more information.

Main ;Receive serial characters in Receive buffer

CALL Receive_Wait ;Wait for and receive one serial by

MOVF Receive,0 ;After receiving, check character f BTFSC Z ;an error (Receive=00h) GOTO Main ;If no character, wait again

The Main subroutine calls Receive_Wait in RS232RX.LIB. Receive_Wait waits for a start bit and attempts to grab one serial character. It is important to note that Receive_Wait does not return to the calling program until either a serial character is received, or a false Start bit occurs—indicating a glitch on the RS-232 line. If a serial error occurs, the Receive register is reset. The MOVF Receive,0 and BTFSC Z instructions checks for this zero condition and a return to Main executes if the receive register is zero.

Receive_Wait ;Wait for PortA.4 to change from high to low indicating th ;start of serial data.

BTFSC Serial_Input ;Check serial input pin GOTO Receive_Wait ;If high, wait for low From RS232RX.LIB

The two instructions of Receive_Wait simply wait for the RS-232 signal line drop low. Receive_Data, which follows on the next page, samples the RS-232 data.

Chapter 15 RS-232 ©1998 Sirius MicroSystems Microchip Code 151 Serial Communication Receive_Data ;After PortA.4 drops low, test for a start bit by delaying ;for half the Bit_Time and then checking PortA.4 for the lo ;start bit. Then wait for the Bit_Time and read each bit in ;Carry. Rotate Carry into the Receive byte and repeat the ;delay, Carry and rotate until eight DataBits have been ;received. The Receive register stores the received byte. I ;framing error occurs (only a simple check for a stop bit i ;done) the contents of the Receive regsiter will be 00h and Assigning the label ;the Receive_Data routine will return with 00h in W. Receive_Data to a section MOVLW DataBits ;Load W with number of data bits of the Receive_Wait MOVWF BitCounter ;and save in BitCounter register subroutine makes it easier MOVLW Half_Bit ;Load W with half of bit delay time to adapt the RS232RX.LIB CALL BitDelay ;and wait for 1/2 bit subroutines for interrupts. BTFSC Serial_Input ;Check for low start bit again GOTO Receive_Error ;If high, error occurred-exit with The serial input pin RA.4 can be configured to :Next_Bit MOVLW Bit_Time ;Load W with bit delay time generate an interrupt on CALL BitDelay ;and wait until middle of next bit the falling edge of the RS- BTFSS Serial_Input ;Check serial input pin for 1 BCF C ;If serial input is 0, clear Carry 232 Start bit. BTFSC Serial_Input ;Check serial input pin for 0 BSF C ;If serial input is 1, set Carry RRF Receive ;Rotate Carry into received data by DECFSZ BitCounter ;Decrement bit counter & check for GOTO :Next_Bit ;If not 0, get the next bit

MOVLW Bit_Time ;Load W with bit delay time CALL BitDelay ;and wait until middle of stop bit BTFSS Serial_Input ;Check for high stop bit GOTO Receive_Error ;If low, we have a framing error From RS232RX.LIB RETURN ;Otherwise return The first two instructions load the BitCounter variable with the number of data bits that will be received—typically 8. Then, the BitDelay subroutine is called to provide a delay of ½ bit time. The variable Half_Bit is defined in the Software Equates See Appendix C - PIC section of RS-232RX.LIB. The PM assembler supports in-line math operators, mak- Macro Assembler Refer- ence, Section 9, for more ing it easy to define Half_Bit from Bit_Time: math operators.

Bit_Time EQU 01Eh ;Serial Bit delay from table above From RS232RX.LIB Half_Bit EQU Bit_Time/2 ;Half of the Bit delay After returning from the BitDelay subroutine, the serial input pin is checked again to ensure that it is still low, signifying a valid Start bit. If not, the program goes to the Receive_Error subroutine.

Once a valid Start bit is received, BitDelay is called again with a full Bit_Time value in W. When BitDelay finishes, the PIC is ready to sample bit 0. The next four lines sample Serial_Input and set or clear the depending on the state of the pin defined by Serial_Input. These four lines always take four clock cycles to ex- ecute, regardless of the state of Serial_Input. This coding prevents cumulative timing errors.

After the Carry flag has been set or cleared according to value sampled, RRF Receive rotates the Carry bit into the upper bit of the Receive register.

BitCounter keeps track of the bits remaining to be received. The process repeats in a loop until BitCounter is zero and all eight bits have been received. After another Bit_Time delay the Stop bit is sampled. The Receive_Wait subroutine returns unless a Stop bit does not occur, in which case a receive error is generated. Receiving RS-232 Data 152 Microchip Code ©1998 Sirius MicroSystems The Receive_Error section of the subroutine will execute if either the Start bit is not low during its mid-point sample, or if the Stop bit is not high during its mid-point sample. An invalid Start bit is probably due to induced noise on the RS-232 line, whereas an invalid Stop bit is probably due to incorrect baud rate or data length settings. Either of these two conditions indicate that a framing error has occured and that the received data is suspect. If this is the case, the receive buffer is cleared. To We chose to return 00h check for an error, your program can check the Receive character for a zero on because it’s easy to check. return. See the Main routine for the error checking code. After the Receive_Wait subroutine has received all eight bits of an RS-232 char- acter it places the received value into the Receive register. The LCD_Write section of RECV232.ASM will display the character.

LCD_Write ;Write the character in Receive buffer to LCD display

MOVF Receive,0 ;Move received character into W & CALL LCD_Data ;write to current DDRAM address INCF CharAddress ;Add 1 to DDRAM address counter MOVLW 0A8h ;Load W with last DDRAM address +1 SUBWF CharAddress,0 ;and subract from CharAddress BTFSC Z ;to see if 40 characters are full GOTO Line_Reset ;If so, reset LCD to start of line

MOVF CharCounter,1 ;Check Character counter for end BTFSC Z ;of visible screen by checking Z GOTO Scroll ;If at end, scroll display left DECF CharCounter ;If not, decrement CharCounter GOTO Main ;and wait for next character

The first fifteen characters fill line one of the LCD. After the first fifteen charac- ters are sent to the LCD, each new character is followed by a command to scroll the LCD left so that the oldest characters scroll off the visible display. After forty char- acters, the LCD DDRAM buffer is full and must be reset to its starting value of 80h. The LCD_Write, Scroll, and Line_Reset subroutines perform these tasks.

LCD_Write moves the character from Receive to the W register and displays the character by calling LCD_Data. INCF CharAddress keeps track of how many char- acters have been placed into the LCD DDRAM. Each line of the LCD has forty DDRAM addresses and can hold forty characters. Remember from Chapter 12 that the first DDRAM location is 80h. After forty characters have been received and displayed, CharAddress will equal A8h. MOVLW 0A8h and SUBWF CharAddress,0 checks that the DDRAM address is forty characters past 80h, at which point the LCD is reset to the start of DDRAM by GOTO Line_Reset.

Line_Reset ;If 40 characters have been written to DDRAM, scroll the ;display contents left and reset DDRAM to line 1.

MOVLW LCDLeft ;Load W with LCD shift left command CALL LCD_Reg ;and write to LCD MOVLW LCDLine1 ;Load W with first DDRAM address MOVWF CharAddress ;and save in CharAddress register CALL LCD_Reg ;before writing it to LCD GOTO Main ;Wait for more serial data

Line_Reset scrolls the contents of the LCD left, and resets the DDRAM address to 80h, so that it can again be filled with forty new characters. Chapter 15 RS-232 ©1998 Sirius MicroSystems Microchip Code 153 Serial Communication Scroll ;Scroll display left to keep new characters in LCD window

MOVLW LCDLeft ;Load W with LCD shift left command CALL LCD_Reg ;and send to LCD GOTO Main ;Wait for next character If forty characters have not yet been displayed, the last five lines of LCD_Write determine whether or not to scroll the display. CharCounter keeps track of the re- maining character positions to be filled before scrolling is required. After the first 15 characters, scrolling is required, CharCounter is 0, and Scroll executes for all subse- quent characters.

Transmitting RS-232 Data

Transmitting RS-232 data is relatively straightforward. As with RS-232 recep- tion, the bit time needs to be calculated from the serial bits per second rate. As shown in the diagram below, transmitting RS-232 signals involves setting a bit, waiting for the bit time, sending the next bit, waiting, and so on until all bits have been sent:

The program XMIT232.ASM sends the message “Key XX Pressed” to the PIC- MDS serial output each time a key is pressed. XX is replaced by a number represent- Make sure your terminal ing the key pressed on the keypad. To test this program, connect the PIC-MDS to a program is set to receive at personal computer running a terminal program and make sure that JU5 is set to Tx. 9600 bps, 8 data bits, no Use one of the serial cables described at the start of the chapter. parity and 1 stop bit—8n1.

;Equates required by BIN2DEC.LIB: Hundreds DS 1 ;Hundreds digit Tens DS 1 ;Tens digit Ones DS 1 ;Ones digit

;Equates required by KEYPAD.LIB: Key DS 1 ;Key return code register

;Equates required by RS232TX.LIB: Counter DS 1 ;Serial bit delay counter BitCounter DS 1 ;RS232 bit counter register Transmit DS 1 ;Transmit byte storage register

See Chapter 9 for more XMIT232.ASM uses three library files. KEYPAD.LIB scans the keypad and details on KEYPAD.LIB returns a value from 1 to 16 representing which key was pressed—or 0 if no key was and BIN2DEC.LIB. pressed. BIN2DEC.LIB is used to convert the value returned by KEYPAD.LIB to three decimal digits. Transmitting RS-232 Data 154 Microchip Code ©1998 Sirius MicroSystems RS232TX.LIB requires three variables. Counter is used to generate bit time delays, BitCounter counts tranmitted bits, and Transmit is a register that holds the byte to be transmitted.

CALL Transmit_Port ;Configure PortA.4 as serial output CALL KB_Port ;Configure Port B for keypad scanni GOTO Get_Key ;Jump over interrupt vector

XMIT232.ASM begins by calling Transmit_Port in the RS232TX.LIB library to initialize RA.4 as an output. Next, the call to KB_Port in KEYPAD.LIB initializes Port B to scan the keypad. GOTO Get_Key jumps over the interrupt vector and the library include statements.

Transmit_Port ;Sets PORTA.4 to output. Make sure PIC-MDS JU5 is set to T

BSF RP0 ;Select memory register page 1 MOVLW 00001111b ;AND configuration byte with Port A ANDWF TRISA ;tristate reg. to make RA.4 an outp BCF RP0 ;Return to memory register page 0 BSF Serial_Output ;Set serial line high RETURN From RS232TX.LIB Similar to Receive_Port in RS232RX.LIB, Transmit_Port sets PortA.4 to out- put without modifying the settings of the other Port A pins. This is accomplished by ANDing Port A with 00001111b.

Get_Key ;Wait for a key stroke, debounce it and convert it to thre ;decimal digits.

CALL KB_Scan ;Get Key return code MOVF Key,0 ;Check Key return code BTFSC Z ;for no key press (0=no key) GOTO Get_Key ;If no key pressed, try again

CALL Delay ;Wait for key to settle CALL KB_Scan ;Read Key code after settling MOVF Key,0 ;Read Key code into W CALL Bin_Dec ;and convert to decimal The Get_Key routine uses KB_Scan to scan the keypad until a key is pressed. Once a key has been pressed, CALL Delay waits for the key to settle before another call to KB_Scan captures the key value. Since KB_Scan returns the key pressed value in the Key register, MOVF Key,0 copies the key code into W. The call to Bin_Dec converts the binary key code into three decimal digits which are stored in the registers Hundreds, Tens and Ones.

Convert_ASCII ;Add 30h to offset the BCD numbers into ASCII.

MOVLW 30h ;Load ASCII offset into W and ADDWF Tens ;add to Tens and ADDWF Ones ;Ones registers to make ASCII numbe By adding 30h to the Tens and Ones registers, the numeric values stored in them are converted to their corresponding ASCII characters. This is done so that ASCII characters, not binary numbers, are transmitted to the receiving serial terminal.

Chapter 15 RS-232 ©1998 Sirius MicroSystems Microchip Code 155 Serial Communication Transmit_Key ;Transmit the word ‘Key ‘

MOVLW ‘K’ ;Load W with ASCII code for ‘K’ and CALL Transmit_Data ;send out of serial port MOVLW ‘e’ ;Load W with ASCII code for ‘e’ and CALL Transmit_Data ;send out of serial port MOVLW ‘y’ ;Load W with ASCII code for ‘y’ and CALL Transmit_Data ;send out of serial port MOVLW ‘ ‘ ;Load W with ASCII code for ‘ ‘ and CALL Transmit_Data ;send out of serial port The Transmit_Key routine relies on Transmit_Data in RS232TX.LIB to send characters for the word “Key ”. The ASCII value for each letter is generated by the assembler when the letter is enclosed in quote marks.

Transmit_Data Drop PortA.4 from high to low to indicate the Start Bit a ;delay for one Bit_Time. Rotate the Transmit buffer right ;into Carry and set or clear the serial output pin based on ;Carry. Wait for another bit time and continue rotating and ;transmitting until all eight bits have been sent. Finally, ;send a stop bit.

MOVWF Transmit ;Save character in W to buffer MOVLW DataBits ;Load W with number of data bits MOVWF BitCounter ;and save in BitCounter regsiter BCF Serial_Output ;Send Start bit NOP ;and pad routine to be same length NOP ;as :Next_Bit code so Bit_Time is NOP ;accurate NOP NOP NOP NOP

:Next_Bit MOVLW Bit_Time ;Load W with bit delay time CALL BitDelay ;and wait one bit duration RRF Transmit ;Rotate Transmit byte into C BTFSS C ;Check Carry for a 1 BCF Serial_Output ;If C=0, clear serial output BTFSC C ;Check Carry for a 0 BSF Serial_Output ;If C=1, set serial output DECFSZ BitCounter ;Decrement bit counter & check for GOTO :Next_Bit ;If not 0, get the next bit

MOVLW Bit_Time ;Load W with bit delay time CALL BitDelay ;and wait until end of last bit BSF Serial_Output ;Set serial line high for Stop bit MOVLW Bit_Time ;Load W with bit delay time CALL BitDelay ;and wait a bit RETURN

Transmit_Data begins by moving the character in W to the Transmit register. Next, the number of data bits to be transmitted is saved in the BitCounter register and the serial output pin is set low to initiate the Start bit. The seven NOP instructions add a short time delay and are followed by a call to BitDelay in the :Next_Bit subrou- tine. BitDelay holds the Start bit low for one bit time. These NOPs plus the BitDelay subroutine form the exact delay required for one bit.

The remainder of the :Next_Bit subroutine rotates the Transmit register right, cycling each bit into the Carry flag. The next four lines check Carry and set or clear the Serial_Output pin depending on the state of Carry. These four lines always take four clock cycles to execute, regardless of the state of Serial_Input. This coding prevents cumulative timing errors. Transmitting RS-232 Data 156 Microchip Code ©1998 Sirius MicroSystems DECFSZ BitCounter keeps track of how many bits have been transmitted and Remember, Databits is used repeats the :Next_Bit routine until BitCounter is zero. The next call to BitDelay to set BitCounter to the holds the last data bit for one bit time. BSF Serial_Output sets the output pin high to number of bits to be generate the Stop bit and the final call to BitDelay holds the Stop bit for just under transmitted —typically 8. one bit time.

Notice that NOPs are not needed to pad the Stop bit. Returning from the Transmit_Data routine, loading a new character into W, and calling Transmit_Data again takes five processor clock cycles—equivalent to 5 NOPs—and the Start bit is not sent until after the fourth instruction in Transmit_Data. In total, this adds a nine clock delay to the BitDelay routine. When sending characters sequentially this pro- duces a Stop bit slightly longer than one bit time, allowing close to the maximum possible serial throughput.

Transmit_Num ;Transmit the two key return code ASCII digits.

MOVF Tens,0 ;Load W with ASCII Tens digit and CALL Transmit_Data ;send out of serial port MOVF Ones,0 ;Load W with ASCII Ones digit and CALL Transmit_Data ;send out of serial port

Once the letters “Key ” have been sent to your serial terminal, Transmit_Num sends the key code previously saved in the Tens and Ones registers.

Transmit_Mesg ;Transmit the word ‘ Pressed’, followed by the character ;codes for carriage return (13) and line feed (10).

CLRF CharCounter ;Clear message character counter Get_Char MOVF CharCounter,0 ;Get current character count in W CALL Message ;and retrieve message character MOVWF Transmit ;Store returned character in Transm MOVF Transmit,1 ;and check transmit for end of BTFSC Z ;message marker by checking Z GOTO Wait ;If message done, wait for key rele CALL Transmit_Data ;If not, send current character INCF CharCounter ;Increment the character counter GOTO Get_Char ;and get the next character

Finally, Transmit_Mesg reads the Message data table to send the word “ Pressed” Data table reads were first as well as a carriage return and line feed to the serial device attached to the PIC- described in Chapter 12. MDS. CharCounter keeps track of the data table offset, and the end of Message is marked by a zero byte. When the end of message zero byte is read from the data table, BTFSC Z causes GOTO Wait to execute instead of being skipped.

Wait ;Wait until the user releases the pressed key.

CALL KB_Scan ;Scan keypad MOVF Key,0 ;Check key for 0 BTFSS Z ;And if Z=1 key has been released GOTO Wait ;Otherwise, wait for release CALL Delay ;Wait for key to settle GOTO Get_Key ;Wait for next key The Wait routine loops until the key is released, indicated by Key being returned as zero, and the subsequent delay ensures that any bounces on key release are ig- nored. After the delay, the program is ready to transmit the next key press.

Chapter 15 RS-232 ©1998 Sirius MicroSystems Microchip Code 157 Serial Communication Chapter Summary

RS-232 serial communication is a common way to transmit data between de- vices. Serial data is assembled into data frames consisting of one Start bit, the data, and one or more Stop bits. Serial data is transmitted sequentially at one of a number of common bit rates, and usually as a reverse-logic, bipolar signal. Serial transcievers such as the MAX232 on the PIC-MDS automatically convert these signals to and from TTL logic levels.

The RS232RX.LIB and RS232TX.LIB progams implement simple serial recep- tion and transmission without handshaking. For a complete discussion of RS-232 communications refer to the latest EIA RS-232 standard publication, or textbooks dealing with serial communication systems.

Chapter Summary 158 Microchip Code ©1998 Sirius MicroSystems Questions

1. What are the common serial bps rates?

2. In TTL levels, why is the Start bit always low?

3. Why does RS232RX.LIB sample the RS-232 input in the middle of a bit time?

4. You have designed a pressure monitoring sensor which must transmit 8 bits of pressure data to a computer every 1 ms. What is the minimum common bps rate needed.

5. How does RS232RX.LIB need to be modified if the MAX232 transciever is not used. That is, assume the PIC is directly connected to the transmitting RS- 232 device through a series resistor.

Assignment

1. Write a program to transmit a message repeatedly to a serial terminal at a bps rate other than 9600 bps. Make sure that your message begins on a new line each time it is transmitted.

2. Write a program that will illuminate each of the eight LEDs in response to a unique ASCII character. For example, sending a “1” could light the LED on RB0.

3. Create a program that uses interrupts to receive RS-232 data. Use the negative going edge of the Start bit to initiate the interrupt.

4. Wire a 10kW ohm resistor in series with the serial output wire of a terminal to an available port pin on the PIC. Write a program that will use this pin to receive serial characters, modify them by adding 1, and retransmit the modi- fied character back to the terminal forming a simple data encryption system.

Chapter 15 RS-232 ©1998 Sirius MicroSystems Microchip Code 159 Serial Communication Notes 160 Microchip Code ©1998 Sirius MicroSystems 16 A/D Conversion

Up until this chapter, we’ve dealt with interfacing to binary digital devices. Our world, however, is an analog place where quantities such as voltage, liquid-level, or temperature don’t have clearly defined points. In order to measure and work with analog quantities in the PIC, they must first be converted to digital numbers. Ana- log-to-digital (A/D) conversion circuits add a whole new dimension to microcontroller applications. A microcontroller with an internal A/D converter can sense heat, light, sound level, position, resistance, voltage, current, or many other real-world signals.

The PIC16C711 is equipped with an internal 8-bit, 4-channel A/D converter that allows it to convert an externally applied voltage between 0V and 5V into an One of the four analog eight-bit number from 00h to FFh. Using the PIC16C711 costs less than interfacing inputs can be used as an an external A/D converter to a microcontroller without an A/D such as the PIC16F84. external reference voltage The PIC16C711 with its built-in A/D converter also provides savings in code size, (Vref), changing the circuit board real-estate, and assembly costs. conversion range to 0V and Vref instead of 0V and 5V, effectively scaling the This chapter will explore how to read, scale and display multiple analog voltages analog conversion. set via the trim pots RA0 and RA1. Analog voltages received from these pots will be displayed on the LCD as numbers from 0 to 255. One channel will be converted to a numeric voltage and the other will be displayed as a bar graph on the LED display.

The PIC16C711 A/D Converter

The PIC16C711 has only one A/D converter that is multiplexed to four I/O lines on Port A as shown below:

The channel select bits (CHS[1:0]) are part of the ADCON0 (08h) register, and the port configuration bits (PCFG[1:0]) are part of the ADCON1 (88h) register.

Chapter 16 ©1998 Sirius microSystems Microchip Code 161 A/D Conversion ADCON0 Register

The two channel select bits CHS1 and CHS0 are part of the ADCON0 (A/D control 0, address 08h) register and control which PIC I/O pin is connected to the internal A/D converter. The other bits of the ADCON0 register are shown below:

The input sample is held on The A/D converter is a successive approximation type and uses 10 clock cycles an internal hold capacitor to complete one conversion. Each conversion clock must take at least 2.0 ms and during conversion. The should take no more than about 8 ms for best accuracy. The A/D converter clock minimum and maximum select bits (ADCS1 and ADCS0) select clock rate fed to the A/D converter. The conversion clock times clock rate can be divided from the oscillator clock in increments of 2, 8 or 32, or be ensure that the hold fed from an internal RC oscillator as shown in the chart below: capacitor has had sufficient time to fully charge before conversion and that the C0lock Source ADCS1, charge does not leak off 2TOSC00 during conversion. 8TOSC01

32TOSC10 R1COSC1

In our example program, ADCS1 and ADCS0 are set to 10, providing a clock divider of 32. Using a 10 MHz clock oscillator, we can calculate an appropriate clock source as shown:

The ADON bit can be used turn the A/D converter on or off. When the A/D converter is off, power is removed from the A/D converter circuitry, lowering the PIC’s current consumption. The A/D converter must be turned on, by setting ADON, before initiating a conversion.

Do not set the GO/~DONE The GO/~DONE bit start the conversion process and also indicates its comple- bit in the same instruction tion. Setting GO/~DONE starts the conversion, and this bit will remain high during that sets ADON. conversion. When the conversion is complete, GO/~DONE drops to zero.

ADIF is the A/D conversion complete interrupt flag bit. It gets set when the conversion is finished and must be cleared in software. Interrupt-driven operation allows the A/D conversion to take place in the background, or while the processor is asleep if RCOSC is set as the clock source. The A/D interrupt caused by the comple- tion of the A/D conversion will wake the processor from sleep. ADCON0 Register 162 Microchip Code ©1998 Sirius microSystems ADCON1 Register

ADCON1 contains the two port configuration bits which select not only the internal or external reference voltage, but also whether Port A inputs are analog or digital. By default, Port A.0-3 pins are set to analog input on power-up. When using the LCD or Serial EEPROM library routines with the PIC16C711 it is important to explicitly set the port configuration bits to digital mode. Note that this is not neces- sary when using the PIC16F84, as Port A can only be digital. The table below shows how PCFG1,0 set Port A pins to analog or digital and select the analog reference as either VDD or an external reference applied to RA.3.

P0CFG1,0 R1A.R2A.R3A.RFA.RE

0g0AgnaloAgnaloAgnaloAVnaloDD

0g1AgnaloAgnaloAVnaloREFRA.3 The external reference voltage applied to VREF 1g0AgnaloAlnaloDligitaDVigitaDD should be within 3V and 5V. 1l1DligitaDligitaDligitaDVigitaDD For best accuracy, connect a dedicated voltage reference to this pin, not just a resistor voltage Measuring Voltage using the A/D Converter divider.

The VMETER.ASM program uses the PIC16C711 as a voltmeter to measure and display the voltage supplied by potentiometers RA.0 and RA.1. VDD is used as VREF, the analog reference voltage.

For any voltage from 0V to 5V the binary value will be a corresponding number from 00h to FFh, or from 0 to 255. VMETER.ASM displays the raw binary data A voltmeter to connected to measured from each channel on line 1 of the LCD. Since most applications require measure the voltage of more than just a raw number, VMETER.ASM demonstrates two methods of scaling. RA.0 or RA.1 will not show First, the RA.0 voltage is scaled in software from 0.00 to 5.00 and displayed on the the same value as on the LCD, representing the actual voltage from 0V to 5V. Second, the RA.1 voltage is display. RA.0 and RA.1 scaled and is displayed as an 8-step bar graph on the LEDs. serve double-duty as both analog inputs and as digital outputs for the LCD. Pull out the VMETER.ASM code as we examine it in detail. The meter will measure the average of the analog and The Hardware Equates section begins by setting aside memory locations needed digital signals on these by the included libraries and variables in VMETER.ASM. Of note are the equates pins. for BIN2BCD.LIB.

;Equates used by BIN2BCD.LIB

HighByte DS 1 ;High byte of number LowByte DS 1 ;Low byte of number

TenThous DS 1 ;Ten thousands BCD digit ThouHund DS 1 ;Thousands & Hundreds BCD digit TensOnes DS 1 ;Tens and Ones BCD digit ShiftCounter DS 1 ;Counter for BCD conversion shifts Chapter 16 ©1998 Sirius microSystems Microchip Code 163 A/D Conversion BIN2DEC.LIB converted BIN2BCD.LIB converts a 16-bit binary number (stored in the two registers an 8-bit binary number into HIGHBYTE and LOWBYTE) into a 5-digit BCD number. This 5-digit number is three separate BCD digits. stored in three locations: TenThous, ThouHund, and TensOnes. The lower 4 bits BIN2BCD.LIB converts a (lower nybble) of TensOnes contains the least significant BCD digit, the upper nybble 16-bit number into five contains the next most significant digit, and so on for ThouHund, and TenThous. BCD digits. BIN2BCD.LIB is used here because VMETER.SRC works with The Software Equates section defines constants that are used in the program. values larger than 8 bits when scaling voltages. Initialization begins at address 0000h and continues after the included library files. The LCD71.LIB subroutine library makes its first appearance here. Remember that the PIC16C711 powers up with Port A in analog input mode. LCD71.LIB is a variant of LCD.LIB where the LCD_Port subroutine configures Port A for digital output. The Initialize routine continues by displaying static text on the LCD.

Main ;Configures A-D converter by initializing Port A to be ;analogue intsead of digital, setting the clock divider, ;and selecting the A-D channel.

CALL AD_Port ;Initialize A-D converter & Port A Main begins by calling the AD_Port initialization subroutine in ATOD.LIB.

AD_Port ;Initializes ADCON1 for analog input on RA0 and RA1 with ;VDD as the voltage reference and turns A/D converter on.

BSF RP0 ;Select memory page 1 MOVLW 00000011b ;OR this byte with TRISA to enable IORWF TRISA ;required analog pins as inputs MOVLW 02h ;Make RA0 and RA1 analog inputs by MOVWF ADCON1 ;writing this byte to ADCON1 (88h) BCF RP0 ;Back to page 0 BSF ADON ;Turn A/D converter on From ATOD.LIB RETURN AD_Port first sets RA.0 and RA.1 as input pins by ORing the literal 00000011b with TRISA. Now that RA.0 and RA.1 are inputs, the MOVLW 02h into ADCON1 sets RA.0 and RA.1 as analog inputs. Notice that these two steps set only RA.0 and RA.1 as analog inputs—the other Port A bits are left unchanged in case they were ATOD.LIB does not turn off previously set as digital I/O. Finally, BSF ADON turns on the A/D converter in the A/D converter. For low preparation for a conversion. current consumption you may wish to turn the A/D off after the conversion is MOVLW ADCLK32 ;Get clock divider for high speed complete (just remember to CALL AD_Clock ;from ATOD.lib and set A-D turn it on again for the next The MOVLW ADLCK32 and CALL AD_Clock instructions load the clock di- conversion). vider selection bits ADCS0 and ADCS1. ATOD.LIB equates ADCLK2, ADCLK8, ADCLK32 and ADCLKRC to 2TOSC, 8TOSC, 32TOSC and RCOSC, respectively.

AD_Clock ;Sets ACDS0 and ADCS1 bits in ADCON0 based on the number ;in W. Load W with a clock divider constant from the ;list, above. Read ADRES before calling AD_Clock.

MOVWF ADRES ;Use ADRES as temporary storage MOVLW 3Fh ;Load W with 0011 1111 ANDWF ADCON0,1 ;AND with ADCON0 to clear high bits MOVF ADRES,0 ;Get clock divider bits from ADRES IORWF ADCON0,1 ;OR with ADCON0 to set clock bits From ATOD.LIB RETURN Measuring Voltage using the A/D 164 Microchip Code ©1998 Sirius microSystems The AD_Clock subroutine uses the A/D conversion result register, ADRES (09h), ADRES in the ’711 along as a temporary register to store the clock divisor constant that was held in W when with EEDATA and EEADR AD_Clock subroutine was called. The W register is then available for the ANDLW in the ’84 can be used as 3Fh operation that is needed to clear the ADCS0 and ADCS1 bits without affecting general purpose RAM the lower six bits. After clearing the two ADCS bits W is reloaded with the clock registers. divisor from ADRES before the IORWF ADCON0,1 operation which copies the ADCLK32 constant into the ADCS0 and ADCS1 bits without corrupting the bottom six bits in ADCON0. By using ADRES for temporary storage, the ATOD.LIB rou- When the conversion is tines use none of the standard RAM registers (0Ch to 2Fh) as variables. finished, be sure to read the contents of ADRES before calling the AD_Clock or MOVLW ADCH0 ;Get channel 0 constant and AD_Channel subroutines. CALL AD_Channel ;set A-D channel Both of these subroutines use ADRES for temporary Since we would like the first A/D conversion to retrieve the voltage supplied by storage and will wipe out RA.0, MOVLW ADCH0 and CALL AD_Channel select channel 0 as the A/D input. your conversion result.

AD_Channel ;Sets CHS0 and CHS1 bits in ADCON0 based on the number in ;W when AD_Channel was called. Load W from channel constants ;list, above. Read ADRES before calling AD_Channel.

MOVWF ADRES ;Use ADRES as temporary storage MOVLW 11100111b ;Load W with 1110 0111 and ANDWF ADCON0,1 ;AND with ADCON0 to clear CHS0/1 MOVF ADRES,0 ;Get channel select bits from ADRES IORWF ADCON0,1 ;OR with ADCON0 to set channel bits From ATOD.LIB RETURN

Once again, ADRES is used to store W while an AND operation clears the CHS0 and CHS1 bits in ADCON0. After the contents of ADRES are reloaded into W, they are ORed with ADCON0 to set the requested A/D channel. ATOD.LIB predefines ADCH0, ADCH1, ADCH2 and ADCH3 as valid A/D inputs.

MOVF Bargraph,W ;Display Bargraph value on LEDs while MOVWF PORTB ;waiting for next conversion

Call Delay_5ms ;Wait for track & hold to settle CALL AD_Poll ;Start conversion, & wait until done MOVF ADRES,W ;Load conversion result into W and MOVWF Analog0 ;save in Analog0 for voltage display

By this point, the A/D inputs have been configured, the A/D clock divisor has been selected and the A/D channel has been chosen. Instead of initiating an A/D conversion, the program first moves the contents of the Bargraph register to Port B and then calls a 5 ms delay routine. There are two reasons that this was done.

First, since Port B is shared with the LCD, LED flicker occurs whenever the The first time the Main LCD is accessed. In order to minimize LED flicker, writing the Bargraph value to routine runs, Bargraph the LED before the CALL to Delay_5ms ensures that the LEDs will display undis- contains 00h. Subsequent turbed for 5 ms. Second, the PIC-MDS has a 1kW resistor in series with the loops through main will potentiometers connected to RA.0 and RA.1. These resistors reduce the effects of display the bargraph value the potentiometers RA0 and RA1 on Port A when it is used as a digital I/O port. equivalent to RA.1’s setting. Unfortunately, the resistors also increase the time constant of the internal hold ca- pacitor, increasing the time required to charge the capacitor to the input voltage. The 5 ms delay (part of LCD71.LIB) provides more than enough time to charge the hold capacitor, and is a convenient delay. Chapter 16 ©1998 Sirius microSystems Microchip Code 165 A/D Conversion Once the 5 ms delay finishes, the CALL to AD_Poll initiates the conversion.

AD_Poll ;Sets GO_DONE bit in ADCON0 to start the A/D conversion ;and keeps polling the bit until the conversion is ;complete. Get the result of the conversion from ADRES.

BSF GO_DONE ;Start A/D conversion :Loop BTFSC GO_DONE ;Check GO_DONE for end of conversion GOTO :Loop ;and keep checking until done From ATOD.LIB RETURN AD_Poll sets the GO/~DONE bit in ADCON0, and repeatedly loops until it goes low approximately 3.2 ms later. When GO/~DONE goes low, the conversion result is available in ADRES (09h).

For interrupt-driven operation you would only need to set the GO/~DONE bit after enabling A/D interrupts (see Chapter 11). When the conversion is done, the ADIF flag in ADCON0 is set, and your interrupt service routine can take over.

On return to VMETER.ASM, the result in ADRES is immediately stored in Analog0 for later processing. Then channel 1 is sampled in the same way as channel 0 using the following code.

MOVLW ADCH1 ;Get channel 1 constant and CALL AD_Channel ;set A-D channel MOVF Bargraph,W ;Display Bargraph value on LEDs while MOVWF PORTB ;waiting for next conversion

CALL Delay_5ms ;Wait for track & hold to settle CALL AD_Poll ;Start conversion, & wait until done MOVF ADRES,W ;Load conversion result into W and MOVWF Analog1 ;save in Analog1 After both channels have been sampled, the following code displays the raw value of channel 0 on the LCD.

CALL LCD_Port ;Reconfigure Ports for LCD use MOVLW LCDLine1+Ch0_Data ;Send channel 0 data starting CALL LCD_Reg ;address to LCD as a command MOVF Bargraph,W ;Display Bargraph value on LEDs while MOVWF PORTB ;waiting for bcd conversion MOVF Analog0,W ;Load channel 0 result into W and MOVWF LowByte ;save into LowByte register CALL Display_Num ;Let Display_Num display BCD digits First, the CALL to LCD_Port (in LCD71.LIB) reconfigures the analog input pins on Port A to digital output pins in order to provide the LCD control signals. MOVLW LCDLine1+Ch0_Data loads W with the LCD line 1 starting DDRAM location and offsets it by the Ch0_Data software equate at the start of this program. This ensures that any LCD data is displayed after the “Ch0:” text.

After the CALL to LCD_Reg, the LED bar graph on Port B reflects the last number sent to the LCD. The subsequent MOVF Bargraph,W and MOVWF PORTB rewrites the last Bargraph value to the LEDs.

Next, the value in Analog0 needs to be converted to three ASCII digits for dis- play. After moving Analog0 to the LowByte register, the CALL to Display_Num converts the raw 8-bit result to ASCII and displays it on the LCD. Measuring Voltage using the A/D 166 Microchip Code ©1998 Sirius microSystems Display_Num ;Converts the 8-bit A/D result to BCD and displays the ;hundreds, tens and ones digits on the LCD at the current ;LCD cursor address.

CLRF HighByte ;Clear HighByte before converting CALL BIN_BCD ;result to BCD MOVF ThouHund,W ;Load thousands & hundreds digits in ANDLW 0Fh ;W and clear thousands nybble ADDLW 30h ;Add ASCII offset to generate number CALL LCD_Data ;and display on LCD SWAPF TensOnes,W ;Load tens & ones digit in reverse ANDLW 0Fh ;and clear ones nybble ADDLW 30h ;Add ASCII offset to generate number CALL LCD_Data ;and display on LCD MOVF TensOnes,W ;Load tens and ones digits in ANDLW 0Fh ;W and clear tens nybble ADDLW 30h ;Add ASCII offset to generate number CALL LCD_Data ;and display on LCD RETURN ;Return when done Before calling BIN_BCD (in BIN2BCD.LIB) the Display_Num subroutine clears HighByte. As mentioned previously, BIN_BCD converts the 16-bit word stored in the HighByte and LowByte registers into five BCD digits—necessary to represent numbers up to 65,535. Since we only need 8-bit quantities to represent the A/D result (0-255) we need to ensure that HighByte is clear. Later on, a call to BIN_BCD does put numbers into HighByte.

Once the conversion to BCD is complete, each of the three least significant digits—hundreds, tens and ones—is processed in the same way. First, the BCD digit is extracted from the byte using an AND operation. For the Hundreds digit, stored in the lower nybble of ThouHund, ANDLW 0Fh clears the upper nybble leaving just SWAPF TensOnes,W not the number of hundreds. Next, ADDLW 30h adds the ASCII offset to the number to only swaps the high and convert it to an ASCI code and finally, CALL LCD_Data displays the digit at the low nybbles, but also loads current LCD DDRAM address. The routine returns control to Main once all three the result into W. digits have been displayed.

MOVLW LCDLine1+Ch1_Data ;Send channel 1 data starting CALL LCD_Reg ;address to LCD as a command MOVF Bargraph,W ;Display Bargraph value on LEDs while MOVWF PORTB ;waiting for bcd conversion MOVF Analog1,W ;Load channel 1 result into W and MOVWF LowByte ;save into LowByte register CALL Display_Num ;Let Display_Num display BCD digits The next section of Main repeats the above process to display the raw channel 1 conversion result on the LCD.

MOVLW LCDLine2+Ch0_Volts ;Send channel 0 voltage starting CALL LCD_Reg ;address to LCD as a command MOVF Bargraph,W ;Display Bargraph value on LEDs while MOVWF PORTB ;waiting for scaling CALL Scale_Voltage ;Convert Ch.0 result to voltage and CALL Display_Volts ;display the result on the LCD The code above displays the result of the channel 0 conversion as a voltage. This subroutine is very much like the routines that prepare the LCD to display the raw channel data. The LCD DDRAM address is loaded, and Bargraph updates the LEDs to overwrite the LCD command that would otherwise remain displayed on the LEDs. The CALL to Scale_Voltage converts the 0-255 result into a 0V - 5V value as shown in the source code on the next page. Chapter 16 ©1998 Sirius microSystems Microchip Code 167 A/D Conversion Scale_Voltage ;Scales the result of the A/D conversion such that there are ;only 251 states instead of 256. This way the result can be ;multiplied by two to give a result from 0 to 500 representi ;a voltage of between 0.00 and 5.00 volts. For display, a ;decimal point is just inserted after the first digit by the ;Display_Volts subroutine.

MOVF Analog0,W ;Load W with the A/D result and SUBLW 250 ;check if it’s greater than 225 by BTFSS C ;testing the Carry flag DECF Analog0 ;If so, subtract one from the result MOVF Analog0,W ;Repeat the above process, comparing SUBLW 200 ;the A/D result with successively BTFSS C ;smaller values DECF Analog0 MOVF Analog0,W SUBLW 150 BTFSS C DECF Analog0 MOVF Analog0,W SUBLW 100 BTFSS C DECF Analog0 MOVF Analog0,W SUBLW 50 BTFSS C DECF Analog0

CLRF HighByte ;Clear HighByte register for multiply MOVF Analog0,W ;Reload W with scaled result and MOVWF LowByte ;save result in LowByte register BCF C ;Clear Carry before multiplying by 2 RLF LowByte ;Shift LowByte left to multiply RLF HighByte ;Shift Carry into HighByte CALL BIN_BCD ;and convert to BCD RETURN ;Return when done A value that varies from 0 to 250 is easier to work with than a value that varies from 0 to 255. Simply subtracting 5 from any conversion result limits the maximum value to 250, but introduces very large errors for small results. For example, for a conversion result of 10, subtracting 5 results in a 50% error. Obviously, for results of 5 or less, the error would be unacceptably large. However, if we distribute the sub- traction as five individual subtractions of 1, spread out over the range of possible values, we can limit the error to no more than 2%. The Scale_Voltage routine sequentially subtracts one from the conversion result for every multiple of 50 that the result contains (see the flowchart in the left margin).

Scale_Voltage starts by moving the analog result into W. SUBLW 250 subtracts W from 250 and clears C (the Carry/Borrow flag) if a borrow occurred. For exam- This is one way to scale a ple, if W was 255, the subtraction would require a borrow, and C would be cleared. voltage from a range of 0- BTFSS C checks the state of the Carry/Borrow flag and causes the DECF Analog0 255 to a range of 0-250. instruction to execute whenever a borrow occurs, subtracting one from Analog0. For more accuracy, you MOVF Analog0,W starts the same process again but with W being compared to can supply a calibrated 200. In this way, any result over a multiple of 50 has one subtraction performed for reference voltage to RA.3 each multiple of 50. To see the subtraction take place, examine the LCD as you run (VREF) and configure the VMETER.ASM. Turn the RA.0 potentiometer so that the raw data is less than 50, A/D to accept an external VREF. and slowly increase the potential on RA.0 watching the voltage on the LCD. For each increase in the raw data, the voltage increases by 0.02V. As you reach 50, the voltage display is 1.00V. Increasing RA.0 to 51, the voltage still reads 1.00V, since a subtraction has taken place. By further increasing RA.0 and you will be able to see the subtraction take place at result values of 100, 150, 200 and 250. Measuring Voltage using the A/D 168 Microchip Code ©1998 Sirius microSystems To complete the scaling to 5V, the analog result (0-250) is copied into LowByte and multiplied by two using the RLF LowByte instruction. The following RLF HighByte instruction rotates the C flag—containing LowByte’s most significant bit before its rotate—into HighByte in preparation for the conversion to BCD. The contents of HighByte and Lowbyte now hold a 9-bit number that ranges from 0 to 500. To display the calculated voltage, the Display_Volts routine inserts a decimal point after the hundreds digit of the BCD result.

Display_Volts ;Displays the result of the BCD scaled voltage as a decimal ;number at the current LCD cursor address.

MOVF ThouHund,W ;Load thousands & hundreds digits in ANDLW 0Fh ;W and clear thousands nybble ADDLW 30h ;Add ASCII offset to generate number CALL LCD_Data ;and display on LCD MOVLW ‘.’ ;Load W with ASCII code for “.” CALL LCD_Data ;and display on LCD SWAPF TensOnes,W ;Load tens & ones digit in reverse ANDLW 0Fh ;and clear ones nybble ADDLW 30h ;Add ASCII offset to generate number CALL LCD_Data ;and display on LCD MOVF TensOnes,W ;Load tens and ones digits in ANDLW 0Fh ;W and clear tens nybble ADDLW 30h ;Add ASCII offset to generate number CALL LCD_Data ;and display on LCD MOVLW ‘V’ ;Load W with ASCII code for “V” CALL LCD_Data ;and display on LCD RETURN ;Return when done The Display_Volts routine works in the same way as Display_Num, other than adding a decimal after the first number, and the letter ‘V’ after the last number. Adding ASCII characters is as easy as enclosing them in quotation marks. The as- sembler converts the letter within the quotes to its ASCII value for display.

RRF Analog1 ;Divide channel 1 result by 2 RRF Analog1 ;again = divide by 4 RRF Analog1 ;again = divide by 8 RRF Analog1 ;again = divide by 16 RRF Analog1 ;again = divide by 32 MOVLW 07h ;Clear upper 5 bits of result by Like the Scale_Voltage ANDWF Analog1,W ;ANDing with zero, leave 3 bit result subroutine, the repeated CALL Bar_Table ;in W to look up 1 of 8 patterns division by two results in a decrease in conversion The next part of the Main routine displays the RA.1 input as a bargraph. To do accuracy. In this case the this, the 8-bit conversion result is repeatedly divided by two in order to produce a 3- accuracy decreases from 1 bit number. Since three bits corresponds to eight binary states, the three bit number part in 256 to 1 part in 8. is used to light each of the eight LEDs according to a look-up table in Bar_Table.

The successive RRF Analog1 operations, above, perform the division by two. Since rotate operations are circular, and rotate bits through C and back into the register, MOVLW 07h and ANDWF Analog1,W are required to clear the upper five bits of Analog 1 before calling Bar_Table. In Bar_Table, an ADDWF PCL instruc- tion uses the 3-bit conversion result to offset the program counter, returning a con- stant that illuminates the appropriate segments of the LED bar.

Bar_Table ADDWF PCL ;PCL=PCL+W to generate offset RETLW 10000000b ;Bottom LED on RETLW 11000000b ;Bottom 2 LEDs ... Chapter 16 ©1998 Sirius microSystems Microchip Code 169 A/D Conversion MOVWF PORTB ;Output LED pattern to LED bar MOVWF Bargraph ;and to Bargraph register for update

CALL AD_Delay ;Wait to minimize display flicker GOTO Main ;and do it again Finally, after copying the LED bar graph constant to Port B, the bar graph con- stant is copied to the BarGraph register. As shown earlier, the BarGraph register refreshes the LEDs with the correct LED pattern after the LCD routine writes to Port B. Remember, the LEDs display all Port B activity and we try to minimize LED flicker by overwriting the LCD commands as soon as possible.

Before the Main routine loops back to the beginning, there is a CALL to AD_Delay. This extra 25 ms delay gives the LCD some time to settle, and helps to minimize LED flicker.

Chapter Summary

Analog-to-digital conversion allows microcontrollers to measure and control real-world applications that supply a varying voltage to the processor. The A/D con- verter in the PIC16C711 will convert any voltage into an 8-bit number within two to eight microseconds. Up to four analog sources can be connected to Port A of the PIC16C711, and the single internal A/D converter can process the voltage on each channel independently.

For many uses, scaling is required to convert the A/D result into a more useful form. Scaling usually results in a loss of conversion accuracy, which is typically not critical for simple control tasks. Supplying the A/D converter with an external preci- sion reference voltage can eliminate the need for software scaling, improving con- version accuracy.

In the PIC-MDS, the Port A pins are shared between digital and analog devices. Resistors isolate the analog potentiometers from Port A, increasing the time con- stant required to charge the internal A/D hold capacitor. For high speed conversions, it is necessary to design a board that dedicates the Port A pins to the analog devices connected to them.

Although this chapter certainly gives you a start on A/D conversion, many vari- ables can affect the quality of a conversion result. Fortunately, there are many good books and articles available that provide a more thorough look at A/D conversion.

Measuring Voltage using the A/D 170 Microchip Code ©1998 Sirius microSystems Questions

1. What is the percentage accuracy of an 8-bit conversion? How does this com- pare to the percentage accuracy of a 4-bit conversion?

2. List the steps necessary to initialize the PIC16C711 for conversion with an external VREF. If only one analog input is required, can the remaining Port A pins be used as digital I/Os?

3. How would the use of a 4 MHz crystal affect the operation of the A/D con- verter? What about a 1 MHz crystal?

4. Calculate the maximum possible sampling frequency for a software loop that converts an input, compares the result with a threshold constant, and repeats the loop until the threshold has been exceeded. Assume 4 MHz operation.

5. A liquid level sensor returns an analog voltage from 0V to 5V corresponding to a liquid level from 0mm to 1000mm. Using the internal 8-bit A/D con- verter, what is the minimum resolution we could hope to achieve? What is the most likely practical resolution?

Poor Tony Spicuzzi spent 10 years and thousands of dollars refining “Spicuzzi’s Jacuzzi Temp-o- matic” temperature controller only to find out it can now be replaced with a $5.00 PIC.

Chapter 16 ©1998 Sirius microSystems Microchip Code 171 A/D Conversion Assignment

1. Modify the VMETER.ASM program to update the bar graph and LCD only if one of the analog voltages changes.

2. Write a program that displays the A/D result on the bar graph using 9 LEDs.

3. Create the flowchart for a program subroutine that would display the leading zeros in the raw A/D result as blanks.

4. Write a program to display the voltage on one of the potentiometers as a per- centage, where 0% equals 0V and 100% equals 5V.

5. Write a program that flashes an alarm LED when an input threshold is ex- ceeded. Use one potentiometer to set the threshold value, and the other as the input being checked.

Assignment 172 Microchip Code ©1998 Sirius microSystems Interfacing to a 17 Serial EEPROM

The serial EEPROM, as its name suggests, is a nonvolatile electrically erasable programmable memory that is accessed serially. Although interfacing to a serial memory is slower and somewhat more complicated than interfacing to a conven- tional memory, serial have the advantage of requiring very few signal and control lines. For example, a non-serial 256 X 8-bit memory would require eight address lines, eight data lines and a few control signals, easily exceeding the number of I/O lines on a small microcontroller. The 93LC56 (256 X 8-bit) serial EEPROM SEEPROM.LIB also on the PIC-MDS is an eight-pin chip that uses only three wires to interface to a supports the 512 X 8-bit microcontroller. 93LC66 SEEPROM.

The 93LC56 Serial EEPROM

The 93LC56 is one of a family of serial EEPROMs (SEEPROMs) manufac- tured by Microchip Technology, Inc. The 93LCxx family uses a 3/4-wire interface known as Microwire®, and range in memory capacity from 128 X 8-bits to 512 X 8- bits. The schematic segment below shows the interface connection more clearly.

The 3/4-wires used in the interface are pins 1-4. Chip select (CS) is brought high to select the device. Clock (CLK) is used to synchronously clock data in and out of the serial EEPROM at a rate of up to 2 MHz. Data in (DI) and During reads, a dummy 0 data out (DO) carry data in appears on DO while the and out of the SEEPROM last address bit is being and can be tied together, clocked into DI. R11 hence the name 3/4-wire in- ensures that DI remains terface. Resistor R11 pre- valid. See the 93LC56 data vents a short circuit condi- sheets for more informa- tion during reads. tion. Chapter 17 ©1998 Sirius microSystems Microchip Code 173 Interfacting to a Serial EEPROM The Serial EEPROM Data Frame Storing or retrieving SEEPROM data requires the transmission of a data frame A READ operation obvi- of either twelve or twenty data bits based on the type of SEEPROM instruction. ously involves receiving the Data bits after transmitting the first part of the frame.

The serial data frame begins with a start bit (S). Unlike RS-232 serial communi- Timing is not critical in cation—asynchronous serial communication—the start bit does not signify the start synchronous communica- of a timed data transmission. Instead, the SEEPROM uses synchronous communica- tion. In fact, you can stop tion in which the start bit (applied to DI) must be held high during a rising clock pin the clock in the middle of a (CLK) transition. The remaining frame bits are clocked in sequentially as shown. transmission and continue later—something that would guarantee data loss in asynchronous communi- cation.

OP1 and OP0, the next two bits that are clocked in, are op-code bits that select one of the SEEPROM instructions to be performed.

The X/A8 through A0 bits specify the address on which the instruction should act, and make up the rest of the non-data instruction frame. The nine address bits allow for 512 address locations. Since the 93LC56 SEEPROM only has 256 address

locations, the X/A8 bit holds a dummy value in order to keep the data frame size constant.

Finally, D7 through D0 provide data if needed by the instruction, or represent data clocked out of the SEEPROM during a Read.

Serial EEPROM Instructions The 93LCxx family of SEEPROMs are controlled by seven instructions:

EWDS • Erase Write Disable, prevents any changes to the SEEPROM contents WRAL, WRITE and READ and is the power-up default setting. require a full instruction WRAL • Write All, fills all memory locations with the specified data. frame to be transmitted. All ERAL • Erase All, erases all memory locations. of the other instructions EWEN • Erase Write Enable, allows changes to the SEEPROM memory. require a partial data WRITE • Writes the supplied data to the specified address. frame, since no data is READ • Reads the data from the specified address. required. ERASE • Erases the contents of the specified address.

For data protection during power-up conditions, the default SEEPROM power- up state is EWDS. Before writing or erasing any data in the SEEPROM, an EWEN instruction must be issued. It’s highly recommended to finish a write with EWDS, which prevents any data modification during power-down or brown-outs. The 93LC56 Serial EEPROM 174 Microchip Code ©1998 Sirius microSystems Using The SEEPROM

SEETEST.ASM is a utility to test and program 93LC56/66 SEEPROMs. It dis- plays a SEEPROM address and its contents on the top line of the LCD, and prompts for the four buttons in the top row of the keypad on the bottom line of the LCD. Using the buttons you can increment or decrement the SEEPROM address, select a specific address, or change the contents of any address. Assemble, download and run SEETEST.ASM to try it out for yourself.

Pull out SEETEST.ASM as we explain its operation. To begin, lets examine some noteworthy equates.

Addrh DS 1 ;SEEPROM high address byte Addrl DS 1 ;SEEPROM low address byte

;Equates required by SEEPROM.LIB

SEEAddrh DS 1 ;SEEPROM high address byte SEEAddrl DS 1 ;SEEPROM low address byte SEEClock DS 1 ;SEEPROM clock counter register SEEData DS 1 ;SEEPROM data storage byte Addrh and Addrl, as the comments suggest, are registers used to hold the high and low address bytes of the current SEEPROM address. SEEPROM.LIB uses simi- lar equates, namely SEEAddrh and SEEAddrl. During SEEPROM access, the con- tents of the SEEAddrh and SEEAddrl registers are shifted out to the SEEPROM with the result that after the shift, these registers no longer contain the original ad- After every SEEPROM dresses. Since the SEETEST program needs to know the current SEEPROM ad- access, SEEAddrh and dress (so that it can be incremented or decremented), and SEEAddrh and SEEAddrl SEEAddrl are cleared by are lost in the shift, Addrh and Addrl maintain a pointer to the current SEEPROM SEEPROM.LIB address.

The SEEClock register is used to count the number of data bits transmitted in each serial frame. SEEData stores the data to be written to the SEEPROM or con- tains the data after a READ instruction.

The Update_Status routine Update_Status ;Displays the current SEEPROM address and data on the top li is the main program ;of the LCD and the Menu options on the bottom line. routine in SEETEST.ASM. . It always displays the . address and the data MOVF Addrh,W ;Load W with high address byte stored in that address on ANDLW 01h ;Clear upper seven bits CALL Hex_Remap ;and convert to ASCII for LCD line one of the LCD, and CALL LCD_Data ;and display on LCD displays the prompts on line two of the LCD. The first part of the Update_Status routine displays the words “Addr:” and “Data:” on the top line of the LCD, and positions the LCD cursor after the word “Addr:” in preparation for displaying the actual memory address. MOVF Addrh,W loads the upper SEEPROM address byte (in this case, 0, as Addrh was cleared during initiali- zation) into W. ANDLW 01h clears the upper seven bits of W, isolating the A8 address bit. The call to Hex_Remap converts the value in W to a single ASCII char- acter code in preparation for the display of the first address digit on the LCD. The CALL to LCD_Data displays the first digit of the SEEPROM address as a hexadeci- mal digit on the LCD. Chapter 17 ©1998 Sirius microSystems Microchip Code 175 Interfacting to a Serial EEPROM SWAPF Addrl,W ;Switch Addrl nybbles and copy to W ANDLW 0Fh ;Clear upper nybble before CALL Hex_Remap ;converting to ASCII for CALL LCD_Data ;display on LCD The next lines of the program display the second hexadecimal address digit contained in the upper nybble of Addrl. First, Addrl is copied into W with its upper and lower nybbles exchanged. Next, ANDLW 0Fh wipes out the top four bits, pre- paring the value for the call to Hex_Remap. Finally, CALL LCD_Data displays the ASCII digit corresponding to the hexadecimal address’ second digit.

MOVF Addrl,W ;Load W with low address byte again ANDLW 0Fh ;Clear upper nybble before CALL Hex_Remap ;converting to ASCII for CALL LCD_Data ;display on LCD A similar process is used to display the last hexadecimal digit of the SEEPROM address. After these lines execute, the three digits of the current SEEPROM address have been displayed on the LCD. The next section of the code reads the SEEPROM and displays the contents of the current address on the LCD after the word “Data:”.

CALL SEE_Port ;Set up Port A for SEEPROM use MOVF Addrl,W ;Copy low address byte to MOVWF SEEAddrl ;SEEPROM low address byte MOVF Addrh,W ;Copy high address byte to MOVWF SEEAddrh ;SEEPROM high address byte MOVLW SEERead ;Send SEEPROM Read byte command CALL SEE_Command ;to SEEPROM

CALL SEE_Port readies the three I/O lines the PIC will use to communicate with the SEEPROM. The I/O lines connecting to the SEEPROM chip select and clock are set to output, and the line connected to data is set to input.

As explained previously, Addrl and Addrh are copied into SEEAddrl and SEEAddrh in preparation for the read command. The read is initiated by passing the SEERead value (from the EQUates) through W to the SEE_Command subroutine.

If you find your brain The CALL to SEE_Command begins a process of parsing and shifting the serial swelling as it did in Chap- data frame to the SEEPROM. Remember that the SEEPROM data frame contains a ter 12, remember that you command op-code, address bits, and, if necessary, data bits. The SEEPROM re- don’t need to know exactly sponds to seven command instructions, as shown in the chart on the next page. how the subroutines work Notice that the serial data frame diagram shown earlier indicates that only two bits in order to use them. It’s are used to encode SEEPROM commands. Clearly, two bits are insufficient to en- when you need to interface code seven commands. The way in which the extra commands are encoded, as shown the PIC to a new peripheral by the chart, is to extend the op-code bits whenever the op-code is 00. XOP and that you’ll need to figure 0 XOP represent the extended op-code bits. out all of its idiosyncrasies. 1 For those of you still interested, read on! In extended instructions,

XOP1 and XOP0

overwrite the X/A8 and

A7 bits. Both instruc- tions remain the same overall length. Using the SEEPROM 176 Microchip Code ©1998 Sirius microSystems Although the op-code is sometimes extended with two extra bits, the data frame itself cannot change in length. The extended op-code bits simply overwrite the ad- dress bits X/A8 and A7. Fortunately, the four commands encoded by extended op- code bits are global commands and do not require a specific address. The remaining address bits are sent merely to maintain the required 12- or 20-bit data frame size.

SEEPROM instruction formatting.

S - Start bit OPn - non-extended op-code bits XOPn - extended op-code bits

7B - 7-bit address flag X/A8 - dummy or A8 address bit A7-A0 - address bits

The 7B bit in the chart represents the 7-bit address flag used only within SEEPROM.LIB. When this bit is set, it indicates that extended op-code bits are present, and that only seven more dummy bits in the address field are needed to complete the 12- or 20-bit data frame. The 7B flag was added to make command parsing within SEEPROM.LIB easier and is not transmitted to the SEEPROM.

Now that we know how op-codes encode the instruction sent to the SEEPROM, we’ll examine the SEEPROM.LIB code that assembles the data frame. The first data that will be displayed by SEETEST.ASM resides at address 000h. The code on the previous page would have loaded SEEAddrh and SEEAddrl as shown below:

Recall from the previous page, that just before the Call to SEE_Command, W was loaded with the constant SEERead (C0h). The first instruction in SEE_Command ORs the SEERead constant into SEEAddrh, and the result is shown below the code. IORWF copies W into SEE_Command ;This subroutine parses the SEEPROM command op-code, compl SEEAddrh without chang-

. ing the A8 bit. . IORWF SEEAddrh ;Store command to top bits of SEEAd From SEEPROM.LIB

Chapter 17 ©1998 Sirius microSystems Microchip Code 177 Interfacting to a Serial EEPROM The reason for copying the SEEPROM command into the top of the SEEAddrh register may not be immediately apparent. Since only the least significant bit of

SEEAddrh is required to hold A8, the remainder of the register is empty. We use the upper four bits of SEEAddrh to build the first part of the serial data frame. Remem- ber, a SEEPROM transmission must be either 12- or 20-bits. The upper 4 bits of SEEAddrh, plus all 8-bits of SEEAddrl complete a 12-bit data frame. A 20-bit frame adds eight more data bits, stored in SEEData. The only thing left to do, to make the transmission of the start of the There is actually another data frame easier, is to move ei- reason for moving A 8 ther A8 to the upper nybble of instead of the other three SEEAddrh, or to move the Start bits. For extended op- Bit, and op-code bits to the codes, we can just add the lower nybble so that they can extended bits after the op- easily be shifted in succession. code bits without worrying Since moving A requires only about whether to shift 8 three or five command bits the movement of one bit, not three, we do just that. The end down to beside A8. But then, having five command result is illustrated at left: bits requires that only seven address bits follow The flowchart below shows how commands are decoded by SEE_Command in (to complete the 12-bit SEEPROM.LIB. In addition to decoding the instruction, SEE_Command also as- frame), complicating things sembles the data in SEEAddrh and SEEAddrl in preparation for serially shifting the even more. And, to confuse data frame out to the SEEPROM. See the pull-out section for complete details. you even further, none of this is actually done in this order. But, the flowchart will give you an idea of how we figure out what the command is, and, since we know the command, how many bits to shift.

This flowchart shows the process of SEEPROM command decoding in SEEPROM.LIB.

Using the SEEPROM 178 Microchip Code ©1998 Sirius microSystems Calling SEE_Command not only parses the command and shifts out the serial data frame, but also determines whether or not to use the SEEData register for Reads and Writes. If a Write or Write All command is sent, the contents of SEEData are also shifted out by SEE_Command. In this case, however, the Read command in- structs SEE_Command to retrieve the data from the SEEPROM and shift it into SEEDATA. Once the data from the requested address has been read into SEEData, You do remember that this the code below displays the contents of SEEData on the LCD. whole discussion started because of a SEEREAD instruction about three CALL LCD_Port ;Set up Ports for LCD use pages back, don’t you? MOVLW LCDLine1+Data ;Set LCD character position to CALL LCD_Reg ;start of data display area SWAPF SEEData,W ;Switch nybbles of SEEPROM data to W ANDLW 0Fh ;Clear upper nybble before CALL Hex_Remap ;converting to ASCII for CALL LCD_Data ;display on LCD

MOVF SEEData,W ;Load W with SEEPROM data byte ANDLW 0Fh ;Clear upper nybble before CALL Hex_Remap ;converting to ASCII for CALL LCD_Data ;display on LCD Since the LCD and SEEPROM share some of the PIC’s PORT A lines it is necessary to call LCD_Port before setting the LCD cursor position via the Call to LCD_Reg. Next, the two Data nybbles are displayed in the same way as the address digits were previously. Now, the line one address and data display is complete.

MOVLW LCDLine2 ;Send LCD line 2 character address CALL LCD_Reg ;to LCD as a command MOVLW Menu_Msg ;Load W with Menu message offset CALL Disp_Message ;and call display message routine

CALL KB_Port ;Set Port B for keypad use CALL KB_Scan ;and scan keys for key press MOVF Key,W ;Load Key return code into W MOVWF KeyTemp ;and save in temporary register

MOVLW 01h ;Copy short key repeat delay into MOVWF Delay ;Delay register The next section of code displays the soft function key prompts on line 2 of the LCD by using a table read—the same manner in which messages have been dis- played in previous example programs. Then Port B of the PIC is set up for keypad scanning, and the returned key code is stored in the KeyTemp register. To finish the Update_Status subroutine, the constant 01h is stored in the Delay register. Delay is used to count loops for the pause between key repeats if a key is held down, and a count of 01h represents the short delay between repeats, not the initial long delay.

The Wait_for_Key subroutine checks for a key press in the top row of the key- pad. These are the keys corresponding to the soft-key prompts. If a key has been pressed, Wait_for_Key first determines which key has been pressed. For the first Only the first two keys— two keys, a check is made to determine if this is an initial press, or a key that has ”Dwn” and “Up”— been held from the previous operation. When the key is first pressed, the Delay implement key repeat. The counter is set to 20h from 01h. Next, the Repeat_Delay subroutine is called to im- action for the last two keys plement the key delay. In this case, the delay between an initial key press and the is described in the next first repeat is thirty-two times longer than the delay between successive repeats. paragraph. Following the key delay, the action corresponding to the key press—either incrementing or decrementing the SEEPROM address—is performed.

Chapter 17 ©1998 Sirius microSystems Microchip Code 179 Interfacting to a Serial EEPROM The actions resulting from an “Sel” or “Chg” key press are only slightly differ- ent from the previously described key processing, with the difference being that these two keys do not implement a key repeat. Instead, pressing the “Sel” key enters a subroutine that allows a user to immediately enter an address by pressing three keys, and pressing the “Chg” key allows a user to change the data at the current address with the next two key presses. The program flow showing the process of key determination is illustrated in the following flowchart.

Key decoding flowchart.

If the first key is pressed, the Addr_Down subroutine decrements the Addrl register as long as its value is greater than zero. Likewise, the Addr_Up subroutine allows the second key to increment the SEEPROM address up to 1FFh.

The “Sel” soft key calls the Addr_Set subroutine. Addr_Set first displays ques- tion marks and a blinking cursor where the three address nybbles (about to be en- tered) are displayed. Next, the keypad is configured to obtain the three nybbles needed in order to define the new address. The subroutine then checks to see if the first Remember, SEEPROM nybble is either a zero or a one, and loops until a zero or one is entered. Once the addresses fall within the three nybbles have been read from the keypad, their values are placed in the Addrh range of 000h to 1FFh. The and Addrl registers. After waiting for the last key to be released, the key 3 decoding first digit can only be zero routine returns program control to Update_Status, which displays the newly entered or one. address as well as the SEEPROM memory contents of this address on the display. Using the SEEPROM 180 Microchip Code ©1998 Sirius microSystems The Data_Set routine behaves similarly to Addr_Set. The difference is that only two digits are entered, representing the two data nybbles. The two digits entered by the user are saved in the SEEData register and are written to the SEEPROM by the code, below.

CALL SEE_Port ;Configure Port A for SEEPROM MOVLW SEEEWEN ;Send Erase/Write Enable command CALL SEE_Command ;to SEEPROM MOVF Addrl,W ;Copy Addrl byte to MOVWF SEEAddrl ;SEEAddrl MOVF Addrh,W ;Copy Addrh byte to MOVWF SEEAddrh ;SEEAddrh MOVLW SEEWrite ;Send data write command CALL SEE_Command ;to SEEPROM MOVLW SEEEWDS ;Send Erase/Write Disable command CALL SEE_Command ;to SEEPROM Writing data into the SEEPROM is just a bit more involved than reading data, if only because the SEEPROM must be write-enabled first. CALL SEE_Port configures the PIC to communicate with the SEEPROM. CALL SEE_Command transmits the SEEEWEN (SEEprom Erase/Write ENable) command, which must precede any erase or write. SEEAddrl and SEEAddrh are loaded with the current SEEPROM address from Addrl and Addrh, respectively. Remember that the addresses stored in Addrl and Addrh are copied to SEEAddrl and SEEAddrh because once the data frame is shifted out, SEEAddrl and SEEAddrh no longer contain valid addresses. Since the SEEPROM is now write-enabled, with SEEAddrh and SEEAddrl loaded with the address to be written to, and with SEEData holding the data to be written, the SEEWrite command can now be issued. After the write command is complete, the final command to be sent is SEEEWDS (SEEprom Erase/Write DiSable). For maxi- mum data integrity, Microchip recommends that SEEPROM erase and write be disa- bled unless an erase or write is taking place.

After the write operation, program control is once again passed to the Update_Status routine. When Update_Status displays the current SEEPROM ad- dress and data, it actually re-reads the contents of the address just written in order to provide verification that the data entered was correctly stored.

Chapter Summary

Serial EEPROMs are serially-accessed, non-volatile electrically erasable pro- grammable memories. Their advantage is the use of few I/O lines (typically three or four), at the expense of a more complex software interface. The PIC-MDS supports the 93LC56 (256-byte) and 93LC66 (512-byte) Microwire® SEEPROMs.

93LCxx SEEPROMs are controlled by serially transmitting one of seven com- mands in the form of 12- or 20-bit data frames. SEEPROM commands allow for: • erase/write enable and disable, • write, read and erase of specific addresses, • global write and erase of the entire SEEPROM.

The SEETEST.ASM program allows you to enter and verify data in every memory location of either the 256- or 512- byte SEEPROMs. Chapter 17 ©1998 Sirius microSystems Microchip Code 181 Interfacting to a Serial EEPROM Questions

1. What is the minimum amount of time in which a read can be performed?

2. Why are SEEPROMs said to use a 3/4-wire interface?

3. Examine the data sheets to find the typical length of time taken by an erase or write command. What is the maximum length of time for a write command?

4. At a typical write cycle time, and assuming that you perform successive writes, how long would it take to reach the specified endurance of the 93LC56?

Assignment

1. Modify CLOCK.ASM to store the current time whenever a key is pressed, or an I/O line activates. Store the time that each event occurs in successive SEEPROM registers. Use SEETEST.ASM to examine the stored times.

Interfacing devices like serial EEPROMs to the PIC can make you feel a bit like you’re being buried in mounds of new information. Without a good guide or data sheets, you’ll feel like there are a few crabs in the mound with you!

Questions and As- signment 182 Microchip Code ©1998 Sirius microSystems 18 The Watch Dog Timer

Watch Dog Timers (WDT) are often a feature of microcontrollers used in real- time control systems. The main purpose of the WDT is to improve the reliability of the control software by providing a periodic time-out signal that is used to reset the PIC—as if the PIC were just powered-up. Instead of allowing the WDT to reset the processor, however, it is imperative that the software periodically resets the WDT in order to continue normal program execution. If for some reason the program fails to reset the WDT, then the WDT time-out signal issues a RESET, restarting program execution from the power-up state. In the PICmicro family, the WDT can also wake the PIC from SLEEP. Waking the PIC from sleep does not cause a power-up reset, but rather operation continues from the instruction following the SLEEP instruc- tion.

The WDT in the mid-range PICmicro family is a counter fed from a continu- ously running, on-chip R/C oscillator, which issues a WDT time-out approximately Both Vdd level and tem- every 18 ms. The WDT time-out signal can be fed to an 8-bit postscaler counter, perature affect the time-out which can extend the time-out period to approximately 2.3 seconds. The WDT period of the R/C oscillator. postscaler is also the TMR0 prescaler. Therefore, assigning the postscaler to WDT Because of this, don’t count prevents TMR0 from using the prescaler, and vice-versa. For clarity, the diagram on the WDT for precise below shows only the register bits required in setting the WDT. See Chapter 11 for timing. a diagram showing how these same bits can select TMR0 options.

In this chapter, we’ll demonstrate two WDT programs. One shows how to use the WDT to perform a RESET during failed program execution, and the other shows the use of WDT in waking the PIC from SLEEP.

Chapter 18 ©1998 Sirius microSystems Microchip Code 183 Watch Dog Timer Handling Software Faults using the WDT

The pseudo-code for a typical WDT-enabled program is shown below.

Initialize Enable WDT

Main Code . . Clear WDT

GOTO Main Code

All WDT-enabled programs must, as part of their regular execution, reset the WDT periodically. Failure to do this, of course, will result in the WDT timing out and resetting the PIC. Think of the WDT as a ticking time-bomb. Your program needs to reset the counter before the counter expires, which would reset your pro- gram. In a simple program, where all tasks can be completed before a time-out, a single CLRWDT instruction at the end of your code is sufficient. Otherwise, your code must ensure that the WDT is cleared before a time-out occurs by including CLRWDT instructions within all of its subroutines.

The program TIMEOUT.ASM demonstrates not only how the PIC can be reset by the WDT, but also how to determine whether the reset occurred because of a WDT time-out or power-up/MCLR (depressing the RESET button). Being able to distinguish the cause of a reset provides your program with the ability to be self- monitoring—it can indicate to the user that a software or hardware fault triggered an unintended reset. Pull out TIMEOUT.ASM as we examine the program flow.

Initialize ;Continue by initializing the LCD display.

CALL LCD_Port ;Set up Ports for LCD use

BTFSS TO ;Check WDT Time Out flag and GOTO WDT_Message ;skip WDT and LCD init if reset by

After initializing a few registers and the setting up the ports for LCD use, TIMEOUT.ASM begins execution by determining the cause of the last reset. It does this by checking TO, the Status register Time Out bit. If TO is set, the PIC restarted from a power-up or MCLR reset, and execution continues by initializing the WDT. Of TO is low, a message indicating that the WDT generated the reset is displayed on the LCD.

Init_WDT CLRWDT ;Clear Watchdog Timer BSF RP0 ;Select register page 1 MOVLW 0FFh ;Set Option register for WDT with MOVWF Option ;1:128 prescaler (maximum prescaler BCF RP0 ;Return to register page 0 Assuming a power-up reset occurred, the program configures the WDT with the maximum prescaler/postscaler value, which sets a time-out period of approximately 2.3 seconds. Before doing this, the CLRWDT instruction assures us that no unin- tended resets will occur as the prescaler/postscaler is changed.

Handling Software Faults using the WDT 184 Microchip Code ©1998 Sirius microSystems After initializing the LCD and displaying the reset and power-up messages, the Wait_for_Key subroutine checks for key strokes.

Wait_for_Key ;Checks for a key press. If no keys are pressed, WDT is res

CALL KB_Port ;Set up Ports for keypad scanning CALL KB_Scan ;Get Key return code MOVF Key,W ;Load Key code into W to set flags BTFSC Z ;and check for 0 (0=no key) GOTO Reset_WDT ;If no key pressed, reset WDT

If no keys are pressed, execution continues by resetting the WDT.

Reset_WDT ;Resets the WDT, setting the TO flag.

CLRWDT ;If no key pressed, clear Watchdog GOTO Wait_for_Key ;and check for another key press

The Wait_for_Key and Reset_WDT routines form a tight program loop—check for a key press, and if none, reset the WDT before checking for the next key press. This loop takes far less time than the WDT time-out period to execute, demonstrat- ing normal WDT operation.

Key_Release ;Waits for the key to be released. If a key is held for 2-3 ;seconds, the WDT will time out since there is not CLRWDT ;instruction inside this wait loop.

CALL KB_Scan ;Scan keys for key press MOVF Key,W ;Check Key return code for no key BTFSS Z ;by checking for 0 (0=no key) GOTO Key_Release ;If key is held, check again If a key is pressed, program flow remains within the Key_Release subroutine for the duration of the key press. Note that because there is no CLRWDT instruction within the Key_Release subroutine, one of two things will happen. If the key is pressed and released within the WDT time-out period, program operation continues in the normal way by having the Reset_WDT subroutine reset the WDT, and Wait_for_Key check for the next key press. If, however, a key is pressed and held for the duration of the WDT period, the WDT will time-out, clear the Status TO bit, and issue a device reset. When the PIC restarts program execution, the TO bit check in the Initialize routine will cause the program to branch to the WDT_Message routine, which changes the LCD to show the WDT as the cause of the last reset.

The importance of this program is that it demonstrates the additional level of programming necessary to cope with the potential loss of control due to WDT op- eration. Put simply, when and if the WDT times out, your program is no longer doing what you programmed it to do. How gracefully your program recovers from the unintended reset is now determined by the code that follows your TO bit check. Complicating the whole matter is that you don’t know at which point your pro- gram’s execution it was reset. If nothing else, this factor alone necessitates that you carefully plan your program’s structure in order to accommodate the WDT and en- sure that your initialization code configures the I/O to a known state, leaving noth- ing to chance. For all of its benefits, you cannot just enable the WDT because you think it’s a good idea—your code needs to be written for it!

Chapter 18 ©1998 Sirius microSystems Microchip Code 185 Watch Dog Timer Enabling the WDT Before programming a PIC with TIMEOUT.ASM, let’s take a look at where the WDT is enabled. PIC programs themselves have no control over the WDT. Enabling or disabling the WDT is accomplished by the programmer or downloader when the device configuration bits are programmed. The Device directive in the code controls the configuration bits.

See Appendix C for more information on the Device Device PIC16F84,HS_OSC,WDT_ON,PROTECT_OFF,PWRT_ON directive. In the Device directive above, the command WDT_ON instructs the assem- bler to enable the WDT in the PIC’s con- figuration bits. The EPIC downloading software (at right) allows you to override any of these settings at programming time. Whenever programming a PIC with a WDT-enabled program, it’s a good idea to double-check the device settings to en- sure that the WDT will indeed be turned on. Alternatively, a single click can dis- able the WDT in a WDT-enabled program for debugging.

Waking the PIC using the WDT

If a WDT-enabled PICmicro™ processor is put to sleep, the WDT will wake the PIC from sleep at the end of its time-out period. The WDT will not cause a device reset when the PIC is asleep. Another simple WDT program illustrates this.

When WDTIMER.ASM is first started, a 16-bit wake-up counter is reset to zero before the WDT is enabled. Then, the number of wake-up cycles is displayed on the LCD. Next, the PIC goes to sleep. At the end of the WDT period, the PIC wakes up, increments the wake-up count on the LCD, and goes back to sleep. Had a device reset occurred, the wake-up counter which was initialized at the start of the program would also be reset, and the wake-up count would never increment. Pull out WDTIMER.ASM to examine it as we dissect the code.

Initialize ;Continue by initializing the LCD display.

CLRF Wake_UpH ;Continue clearing registers CLRF Wake_UpL CALL LCD_Port ;Set up Ports for LCD use

Init_WDT CLRWDT ;Clear Watchdog Timer BSF RP0 ;Select register page 1 MOVLW 0FEh ;Set Option register for WDT with MOVWF Option ;1:64 prescaler BCF RP0 ;Return to register page 0

The Initialize subroutine clears the upper and lower bytes of the 16-bit wake-up counter. Like the TIMEOUT.ASM program from earlier in the chapter, Init_WDT Handling Software Faults using the WDT 186 Microchip Code ©1998 Sirius microSystems clears the WDT before setting a prescaler/postscaler in the Option register. This time, the WDT time-out period is approximately 1.15 seconds.

MOVLW 1 ;Increment Wake-Up counter low byte ADDWF Wake_UpL ;using Add instruction BTFSC C ;Check Carry for roll-over INCF Wake_UpH ;and increment high byte if set

MOVF Wake_UpL,W ;Copy Wake-Up counters to LowByte a MOVWF LowByte ;HighByte for BCD conversion MOVF Wake_UpH,W MOVWF HighByte

CALL Bin_BCD ;Convert to BCD

After initializing the LCD and displaying the “Wake-up #:” message on the top line, and the “Processing” message on the bottom line, the Main subroutine incre- ments the Wake_UpL and Wake_UpH counters. Using ADDWF instead of INCF allows us to check the C flag for the Wake_UpL roll-over. If Wake_UpL rolls over, Wake_UpH is incremented. After the increment, the wake-up counters are copied to LowByte and HighByte for conversion to BCD.

MOVLW Wake_Ups ;Send starting address of wake-up CALL LCD_Reg ;counter to LCD MOVF TenThous,W ;Load W with lower nybble of ANDLW 0Fh ;Ten thousands digit ADDLW 30h ;Convert it to ASCII and CALL LCD_Data ;display it on the LCD MOVLW Wake_Ups and CALL LCD_REG send the starting position of the wake-up count to the LCD. The next four instructions isolate the first BCD nybble of the 16-bit number, add 30h to convert it to an ASCII number, and display the number on the LCD. Similar groups of instructions display the remaining four digits of the wake-up count.

MOVLW LCDLine2 ;Send line 2 starting address CALL LCD_Reg ;to LCD CALL Delay_5ms ;Add a 20ms pause to see Processing CALL Delay_5ms CALL Delay_5ms CALL Delay_5ms

After the wake-up count is displayed, a pause is added by calling the Delay_5ms subroutine. The only purpose of the delay is to lengthen the amount of time that the “Processing” message appears on the LCD. Otherwise the processing itself takes so little time that the “Sleeping” message would never appear to change.

MOVLW Sleep_Msg ;Load W with Sleeping message offse CALL Disp_Message ;and display it on line 2 of LCD

SLEEP ;Sleep until WDT expires NOP ; GOTO Main ;On WDT wake-up, display next count

Finally, the “Sleeping” message is displayed, and the PIC is put to SLEEP. After the WDT time-out period expires, execution continues at the start of Main, where the “Processing” message is displayed before updating the wake-up count. Chapter 18 ©1998 Sirius microSystems Microchip Code 187 Watch Dog Timer Chapter Summary

The WDT is an independent timer that, when enabled, can reset the PIC or periodically wake the PIC from sleep. Programs can use the WDT as a safety device that will reset the PIC in case of a stuck code condition. If the CLRWDT instruction is not issued by a program before the WDT time-out period expires, the WDT will reset the PIC. WDT-enabled programs require greater planning on the part of the programmer, since a method of handling both unintended resets as well as unknown I/O states must be implemented to ensure proper code operation.

Using the TO bit, WDT-enabled programs can determine the cause of the device reset and can respond appropriately. Programs should also be tested for the effect of unanticipated I/O delays, such as a stuck key or sensor.

If the PIC is asleep, the WDT time-out merely wakes the PIC from sleep rather than causing a device reset.

If you ignore it, the WDT will blow your program back to its start!

Chapter Summary 188 Microchip Code ©1998 Sirius microSystems Questions

1. Why is it important that the WDT has its own internal R/C oscillator? Why can’t the WDT use the PIC’s oscillator?

2. Using pseudo-code, show how to set up the WDT for use as an approximately 20 ms long switch debounce delay.

3. The WDT is not a bullet-proof method of ensuring a device reset during a software failure. If a programming error leaves the PIC stuck in a loop, what software conditions must have been met, both before and during the loop, to ensure that the WDT resets the device?

Assignment

1. Modify the program TIMEOUT.ASM so that holding a key does not cause a WDT time-out. This change would represent normal WDT operation, in which there should never be a time-out.

2. Implement a long time period delay using the WDT. Compare the number of registers required as counters for a five-minute delay timer using the WDT, with that of a five-minute delay timer implemented in software delay loops. Assume 10MHz operation.

Chapter 18 ©1998 Sirius microSystems Microchip Code 189 Watch Dog Timer Notes 190 Microchip Code ©1998 Sirius microSystems PIC-MDS Installation A and Setup

Appendix A ©1998 Sirius microSystems A-1 PIC-MDS Installation and Setup A-2 ©1998 Sirius microSystems Congratulations on your purchase of the Sirius microSystems PIC-MDS. The instructions in this chapter will guide you through the installation and setup of the PIC-MDS hardware and software. First, ensure that you have everything in your PIC-MDS package.

PIC-MDS Professional Package • PIC-MDS circuit board with ZIF socket • PIC16C711 microcontroller • PIC16F84 microcontroller • 10 Mhz crystal • EPIC Programmer • 6 ft., DB-25 m-f parallel port extension cable • 6 in., 10-conductor in-circuit programming ribbon cable * Wall adapters are • 2-120 VAC wall adapters * shipped with orders to • PIC-MDS Programs and Software Libraries diskette North America only. The • EPIC Programmer diskette EPIC Programmer requires • PIC-MDS Microcontroller Development System Training Manual 12 VAC at 500 mA. The PIC-MDS can operate on 9-12 VAC, 12-15 VDC, or PIC-MDS Professional an external power supply • PIC-MDS circuit board with ZIF socket at 300 mA. See Chapter 4. • PIC16C711 microcontroller • PIC16F84 microcontroller • 10 MHz crystal • 120 VAC wall adapter * • PIC-MDS Programs and Software Libraries diskette • PIC-MDS Microcontroller Development System Training Manual

PIC-MDS Hobbyist Package • PIC-MDS circuit board kit • Assembling and Testing Your PIC-MDS booklet (green) • PIC16F84 microcontroller • 10 MHz crystal • EPIC Programmer • 6 ft., DB-25 m-f parallel port extension cable • 6 in., 10-conductor in-circuit programming ribbon cable • 2-120 VAC wall adapters * • PIC-MDS Programs and Software Libraries diskette • EPIC Programmer diskette • PIC-MDS Microcontroller Development System Training Manual

PIC-MDS Hobbyist • PIC-MDS circuit board kit • Assembling and Testing Your PIC-MDS booklet (green) • PIC16F84 microcontroller • 10 MHz crystal • 120 VAC wall adapter * • PIC-MDS Programs and Software Libraries diskette • PIC-MDS Microcontroller Development System Training Manual

Appendix A ©1998 Sirius microSystems A-3 PIC-MDS Installation and Setup PIC-MDS Requirements

To use the PIC-MDS you will need and IBM PC or compatible computer with: • Microsoft® MS-DOS • a standard parallel port • 1 MB of free hard disk space to install the software (recommended)

The EPIC Programmer software is designed to be run from MS-DOS only, us- ing a standard parallel port. Some newer system boards with built-in ECP/EPP par- allel ports may not work properly with the EPIC Programmer software. If the EPIC Programmer software give repeated “Programmer not found” messages or had dif- ficulty programming microcontrollers, try to disable the ECP/EPP parallel port fea- tures in the system board BIOS setup utility or purchase a standard parallel port card for your computer.

The EPIC Programmer software is dependent on accurate timing which can only be guaranteed when it is run from MS-DOS. We do not recommend running the EPIC Programmer software from within other multi-tasking operating systems. Due to the wide variety of computer systems and the complexity of multi-tasking operating systems we can support only those customers running the EPIC Program- mer software from MS-DOS. However, below are some suggestions which may help you to run the EPIC Programmer software from other operating systems:

Windows 3.x and Windows 3.11 for Workgroups From the Main Group start an MS-DOS session in full-screen mode. Do not attempt to run the EPIC Programmer software from within a DOS Window on the See the appropriate Program Manager screen. Microsoft or IBM manuals or Help files for more Windows 95 and Windows 98 information on MS-DOS sessions. Although not From the Start Button perform a Shut Down and select “Restart the computer in recommended, we have MS-DOS mode” from the list of Shut Down choices. After the computer restarts, been able to run the EPIC run the EPIC software from MS-DOS mode. Programmer software from each of the three operating OS/2 Warp v.3 and OS/2 Warp Connect systems at right. Start a DOS Full Screen session in which the HW_Timer setting has been set to On and Video_Retrace_Emulation is set to OFF. Run the EPIC Programmer soft- ware in full-screen mode.

Installing the Software

If you are using the PIC-MDS with the EPIC Programmer... Insert the diskette labelled “PIC-MDS Programs and Subroutine Libraries” into your floppy diskette drive. At the MS-DOS prompt type:

a:\install c: [Enter] Where a: is the identifier of your floppy diskette drive and c: is the identifier of the hard disk drive that you with to install the PIC-MDS software on to. PIC-MDS Require- ments A-4 ©1998 Sirius microSystems The installation program creates a directory named “PIC-MDS” on the speci- fied hard disk drive and copies the program source files (*.SRC) and library files (*.LIB) into this directory. When this is complete, the installation program prompts you to insert the “EPIC Programmer” diskette.

Remove the “PIC-MDS Programs and Subroutine Libraries” diskette from your floppy disk drive and insert the “EPIC Programmer” diskette. Press any key to continue the installation.

After inserting the “EPIC Programmer” diskette and pressing a key, the instal- lation program copies the PIC Macro Assembler software (PM.EXE), EPIC Pro- grammer software (EPIC.EXE) as well as a demonstration program and a number of text files to the PIC-MDS directory. Finally, the installation program creates a subdirectory named INC within the PICMDS directory and copies the microcon- troller device type include files into it.

At this point the PIC-MDS software installation is complete. The diagram be- low indicates the program directory structure:

Hard Disk Drive

PICMDS *.ASM - Microchip source code files #*.ASM - Parallax source code files *.LIB - subroutine library files PM.EXE - PIC Macro Assembler program EPIC.EXE - EPIC Programmer INC P*.INC - PIC device type include files

If you are using the PIC-MDS with a third-party programmer... Insert the “PIC-MDS Programs and Subroutine Libraries” diskette into your floppy disk drive and copy all of the source files (*.ASM) and library files (*.LIB) into the directory on you hard disk that contains your PIC assembler software or you other PIC source code programs.

PIC-MDS Setup

Connecting the EPIC Programmer To prepare the EPIC Programmer for use you will need: • EPIC Programmer • 6 ft., DB-25 m-f parallel port extension cable • 12 VAC, 500 mA output wall adapter or two 9 V batteries

Remove the EPIC Programmer from is package and set it on a non-conductive surface. Attach one end of the included 25-pin male to 25-pin female printer exten- sion cable to the 25-pin connector on the EPIC Programmer. Appendix A ©1998 Sirius microSystems A-5 PIC-MDS Installation and Setup Connect the other end of the 25-pin cable to the parallel printer port on your computer.

CAUTION: Make sure that you connect the programmer to a parallel printer port. Connecting the programmer to a serial port may result in damage to the serial port or the programmer.

If you use a 12 VAC adapter to power the EPIC Programmer, remove the shorting block from the jumper labelled “Batt ON”. Plug the AC adapter into a receptacle and connect the round coaxial plug into the power jack on the top right of the EPIC Programmer.

If you use two 9 V batteries to power the EPIC Programmer, connect the shorting jumper across the “Batt ON” header and plug the batteries into the battery snaps.

WARNING: Never connect a battery across the centre snaps. This may cause the battery to overheat and explode.

One or both of the LEDs on the EPIC Programmer may now be lit.

With your computer running, make sure that you are in the directory that con- tains the PIC-MDS software by typing:

cd \picmds [Enter] Start the EPIC Programmer software by typing:

epic [Enter] If the EPIC Programmer is properly connected to your computer you should see the EPIC Programmer screen appear on your computer. Both LEDs on the EPIC Programmer board should now be off.

This is the EPIC Program- mer screen that appears when the EPIC Program- mer is properly installed.

PIC-MDS Setup A-6 ©1998 Sirius microSystems If you see the “Programmer not found” message make sure that the EPIC Programmer is connected to your parallel printer port and that the cable is firmly seated. Then check that the AC adapter is plugged in and select “Retry”.

The EPIC Programmer software and hardware is fully installed and ready to program a microcontroller.

Connecting the PIC-MDS To prepare the PIC-MDS for use you will need: • PIC-MDS • 6 in., 10-conductor in-circuit programming ribbon cable • wall adapter or power supply • PIC16C711 or PIC16F84 microcontroller • 10 MHz crystal

Remove the PIC-MDS from is package and set it on a non-conductive surface. Attach the included 10-pin In-Circuit programming cable to the In-Circuit program- ming header (H2) on the PIC-MDS. Note: The cable should extend away from the PIC-MDS.

Position the EPIC Pro- grammer and PIC-MDS as The In-Circuit program- shown in the picture and ming cable allows you to connect the other end of program and erase a the 10-pin In-Circuit pro- PIC16F84 microcontroller gramming cable to the in the PIC-MDS circuit connector labelled “J3” on board. You do not need to the EPIC Programmer. plug the microcontroller Note: The cable should into the programming extend over the EPIC Pro- socket on the EPIC Pro- grammer. In-Circuit Cable grammer and transfer it to the PIC-MDS after pro- gramming. PIC16C711 Before installing the microcontrollers can be microcontroller into the Batt ON Jumper programmed in the PIC- PIC-MDS, make sure that MDS, but require UV light both LEDs on the EPIC for erasure. Programmer are off.

Now, carefully take the PIC16F84 processor out of its packaging and insert it into the processor socket (U3) on the PIC- 10 MHz Crystal MDS making sure that pin 1 of the PIC16F84 is closest to the label U3. If you Pin 1 have a green ZIF socket, lift the handle to the vertical position before inserting the PIC16F84. Once the PIC16F84 is in the socket, push the handle back down to the horizontal position. Appendix A ©1998 Sirius microSystems A-7 PIC-MDS Installation and Setup CAUTION: Make sure that the notch and the Microchip logo on the PIC16F84 are closest to the label U3 on the PIC-MDS circuit board. Inserting the PIC16F84 into the PIC-MDS backwards may result in damage to the proc- essor or the PIC-MDS.

Plug the 10 MHz crystal into the crystal socket labelled Y1 on the PIC-MDS.

At this time, connect the plug from the PIC-MDS AC adapter into the coaxial power jack (J1) or connect a power supply to CON1 (see Chapter 4). The LED at the top of the LED bar graph display (labelled PWR) should light up. Note: Some or all of the other LEDs may also be lit. The LCD display may contain one line of block characters. This is normal.

The PIC-MDS hardware is now connected to the EPIC Programmer and is ready to program a PIC16F84 via the in-circuit programming cable, or to run the program in a previously programmed PIC microcontroller.

Assembling and Downloading Programs

If you are familiar with programming microcontrollers, you may want to con- tinue from step 3 of the Quick Start! sheet. Otherwise, chapters 5, 6 and 7 lead you through writing, assembling and downloading your first program. Chapters 1 and 2 provide some background on how microcontrollers work. Chapters 3 and 4 describe the PIC family and the PIC-MDS in detail.

PIC-MDS PIC Microcontroller Development System Training Manual

PIC-MDSPIC Microcontroller Development System Training Manual

Yes, it’s finally time to read the manual! PIC-MDS Setup A-8 ©1998 Sirius microSystems B Troubleshooting

Before resorting to incantations, rituals and spells, try the advice in this section. Then call the wizards at Sirius microSystems.

Appendix B ©1998 Sirius microSystems B-1 Troubleshooting B-2 ©1998 Sirius microSystems Troubleshooting

If you should encounter a problem with your PIC-MDS, EPIC Programmer or the included software, please look in this section for descriptions that most closely resemble the symptoms you observe before contacting Sirius microSystems for tech- nical support. Try the suggestions listed and if applicable re-read the section or sections of the training manual that describe the operation you were trying to per- form when you came across the problem.

Software Installation

If the installation program does not work correctly:

• Make sure the “PIC-MDS Programs and Subroutine Libraries” diskette is in your floppy diskette drive and that your floppy diskette drive can read 3.5” high-density diskettes. • Start the installation program by typing:

a:\install c: [Enter] where a: is the device descriptor of your floppy diskette drive and c: is the directory on your hard disk to which you would like to install the PIC-MDS software. • Make sure that you insert the diskette labelled “EPIC Programmer” when re- quested and press any key. • Make sure that you are installing the program from MS-DOS and not an MS- DOS session in Windows 3.x, Windows 95 or OS/2 Warp.

If the installed files are not in the volume or directory expected:

• Make sure that you specify a destination volume or directory name after the install command (see above).

Assembling Programs with ASM

If you get a “Bad Command or File Name” message:

• Make sure that you start the PM software from within the PICMDS subdirectory on you hard disk, or that you create a path to the PICMDS directory. Type:

cd \picmds [Enter] to make the PICMDS directory the current directory. Then type:

asm filename [Enter] where is the name of the source text file that you wish to assemble. filename • You do not need to type the .ASM extension after . filename

Appendix B ©1998 Sirius microSystems B-3 Troubleshooting If you get a “Fatal : [302] Unable to Open File” message:

• Make sure that the filename you typed following ASM exists and has a .ASM filename extension. • Make sure that any called subroutine files are in the PICMDS directory and that the names of the subroutine files are spelled properly in the source code.

If you get a “Error filename.ASM 1 : [202] Illegal Character” message:

• make sure that the file specified as filename.ASM is an MS-DOS format text file or has been saved as MS-DOS text by a Word Processing program.

Starting the EPIC Programmer Software

If you get a “Bad Command or File Name” message:

• Make sure that you start the EPIC software from within the PICMDS subdirectory on your hard disk, or that you create a path to the PICMDS directory. Type:

cd \picmds [Enter] to make the PICMDS directory the current directory. Then type:

or epic [Enter] epic filename.hex [Enter] to start the EPIC Programmer software, or in the second case to start the EPIC Programmer software with an object file to download.

If you get a “Programmer Not Found” message:

• If a previously programmed PIC microcontroller is in the microcontroller socket on the PIC-MDS board, you may have to press and hold the “RESET” button on the PIC-MDS while selecting “Retry” from the “Programmer not found” message window. • Check that the 25 pin male-female cable is properly seated into both the compu- ter parallel printer port and the EPIC programmer connectors. • Make sure that you are running the EPIC software from MS-DOS, and not from an MS-DOS session in Windows 3.x, Windows 95 or OS/2 Warp. • If you are using an AC wall adapter, check that the correct adapter (usually 12 VAC 500 mA) is plugged into a working receptacle and that its 2.1 mm coaxial connector is plugged into the EPIC Programmer. Also make sure that the “Batt ON” shorting jumper has been removed from the EPIC Programmer. • If you are using two 9 V batteries, check that the batteries have sufficient charge and that the shorting jumper connects the two pins of the “Batt ON” header on the EPIC Programmer. • If the EPIC Programmer is connected to the PIC-MDS via the In-Circuit pro- gramming ribbon cable, make sure that the PIC-MDS is connected to an appro- priate power supply and is operating. Also, make sure that the PIC-MDS has a microcontroller in the microcontroller socket as well as a crystal in Y1.

Assembling Programs with ASM B-4 ©1998 Sirius microSystems If the object code of the file does not appear in the EPIC window:

• The ASM batch file assembles the source code file (*.ASM) to produce a list- ing file (*.LST) and an object code file (*.HEX). Make sure that you specify the object code filename with an .HEX extension. Note: EPIC also supports an .OBJ extension.

Downloading Programs

If you get a “Verify Error at ” message:

• Make sure that you are programming a blank microcontroller, or a PIC16C84 which is electrically erasable, and that the microcontroller is properly plugged into the microcontroller socket on the PIC-MDS or the programming socket on the EPIC Programmer. • If the microcontroller to be programmed is in the PIC-MDS, make sure that the In-Circuit programming ribbon cable is correctly attached to both the PIC-MDS and the EPIC Programmer. See the picture on the Quick Start! sheet. • Check that the 25 pin male-female cable is properly seated into both the compu- ter parallel printer port and the EPIC programmer connectors. • If you are using an AC wall adapter, check that the correct adapter (usually 12 VAC 500 mA) is plugged into a working receptacle and that its 2.1 mm coaxial connector is plugged into the EPIC Programmer. Also make sure that the “Batt ON” shorting jumper has been removed from the EPIC Programmer. • If you are using two 9 V batteries to power the EPIC Programmer, check that the batteries have sufficient charge and that the shorting jumper connects the two pins of the “Batt ON” header on the EPIC Programmer. • Make sure that you are running the EPIC software from MS-DOS, and not from an MS-DOS session in Windows 3.x, Windows95 or OS/2 Warp.

Assembling, Downloading and Running Programs

If the PIC-MDS Chapter examples don’t work:

• Make sure that power is applied to the PIC-MDS. The top LED in the LED bar graph display lights when power is on. If this LED is off, compare the jumper settings on the PIC-MDS with the defaults shown in Chapter 4 and reset the jumpers on the PIC-MDS before reapplying power. • If you use a power supply instead of the wall adapter, check your connections to the terminal strip with the schematic in Chapter 4. Also, ensure that JU1 and JU2 are set properly. • Make sure that the PIC microcontroller is in the microcontroller socket on the PIC-MDS and that a crystal or resonator is in the crystal socket, Y1. • Check the jumpers and the JU6 jumper block in particular to ensure that they match the defaults shown in Chapter 4.

Appendix B ©1998 Sirius microSystems B-5 Troubleshooting • Make sure that the program source files haven’t been inadvertently modified. Compare the source code to the original program source code in the Pull-Out Program References section and if needed copy the original files from the “PIC- MDS Programs and Subroutine Libraries” diskette to your PICMDS directory. For example, if the OUTPUT.ASM program from Chapter 5 doesn’t light the LEDs in a 10101010 pattern, the OUTPUT.ASM code in your PICMDS direc- tory may have been modified. Copy the original from the PIC-MDS Programs and Subroutine Libraries disk to your PICMDS directory by typing:

copy a:\output.asm c:\picmds [Enter]

• Read the comments at the beginning of the source code. Jumper settings and special requirements are explained here. • Check to make sure that the bottom of the PIC-MDS is clean and free of debris and that the PIC-MDS is resting on a non-conductive surface.

Converting PIC-MDS Source Code for Third-Party Tools

If you use a third-party assembler:

• Comment out or remove the “MACLIB” directive. While most other assem- blers do not require you to explicitly specify the target device, the MACLIB directive allows the PIC Macro Assembler (PM.EXE) to easily accommodate new Microchip microcontrollers. • Check your assembler documentation to see if the “DEVICE” directive is sup- ported. Parallax and microEngineering Labs assemblers use the DEVICE di- rective to set configuration fuses and ID bytes. • Check the default radix of your assembler. PM assumes a default decimal radix if no suffix follows the number. • PM uses a suffix to denote a numerical radix. For example, 11 represents eleven, 11B represents the number three and 11H represents the number seventeen. Some assemblers require a prefix or an alternate suffix. • Both PM and Parallax tools support local assembly labels. Local labels are prefixed with a colon (:). If your assembler does not support local labels, change each local label to a unique label.

Assembling, Downloading and B-6 ©1998 Sirius microSystems Running Programs PIC Macro Assembler C Reference

Appendix C ©1996 microEngineering Labs C-1 PIC Macro Assembler Reference Copyrights and Trademarks

Copyright © 1996, microEngineering Labs.

Parallax is a trademark of Parallax, Inc. PIC is a Registered Trademark of Microchip Technology, Inc.

Disclaimer of Liability microEngineering Labs is not responsible for special, incidental, or consequential damages resulting from any breach of warranty, or under any legal theory, including lost profits, downtime, goodwill, damage to or replacement of equipment or property, or any costs for recovering, reprogramming, or reproducing any data used with microEngineering Labs' products.

C-2 ©1996 microEngineering Labs Table of Contents

1. Assembler Overview C-7 Compatibility ...... C-7 Operation ...... C-7 Symbol Names ...... C-7 Numbers ...... C-7 Strings ...... C-7

2. Command Line Options C-7 2.1. Usage ...... C-7 2.2. The PM Environment Variable ...... C-8 2.3. Options ...... C-8 2.3.1. Option -C ...... C-9 2.3.2. Option -D ...... C-9 2.3.3. Option -ELext ...... C-9 2.3.4. Option -EMext ...... C-9 2.3.5. Option -EOext ...... C-9 2.3.6. Option -ESext ...... C-9 2.3.7. Option -EIext ...... C-9 2.3.8. Option -G# ...... C-10 2.3.9. Option -Ipath ...... C-10 2.3.10. Option -Lname ...... C-10 2.3.11. Option -OB ...... C-10 2.3.12. Option -OH ...... C-10 2.3.13. Option -Q ...... C-10

3. Pseudo-Ops C-11 3.1. CODE ...... C-11 3.2. DATA...... C-11 3.3. EEPROM ...... C-11 3.4. ABS ...... C-11 3.5. ORG...... C-11 3.6. DS...... C-12 3.7. DB...... C-12 3.8. DW ...... C-12 3.9. EQU ...... C-12 3.10. =...... C-12

4. Conditional Assembly C-12 4.1. IF...... C-13 4.2. ELSEIF ...... C-13 4.3. ELSE ...... C-13 4.4. ENDIF ...... C-13 Appendix C ©1996 microEngineering Labs C-3 PIC Macro Assembler Reference 4.5. IFDEF ...... C-13 4.6. IFNDEF ...... C-13 4.7. IFB ...... C-13 4.8. IFNB...... C-13

5. Macro Facility C-14 5.1. REPT ...... C-14 5.2. IRPC ...... C-14 5.3. IRP ...... C-14 5.4. MACRO ...... C-14 5.5. LOCAL ...... C-14 5.6. EXITM ...... C-15 5.7. ENDM ...... C-15

6. File Controls C-15 6.1. INCLUDE ...... C-15 6.2. MACLIB ...... C-15

7. File and Listing Controls C-16 7.1. TITLE ...... C-16 7.2. PAGE ...... C-16 7.3. LIST ...... C-16 7.4. NLIST...... C-16 7.5. MTLIST ...... C-16 7.6. NMTLIST ...... C-16 7.7. CLIST...... C-17 7.8. NCLIST ...... C-17 7.9. LALL ...... C-17 7.10. XALL ...... C-17 7.11. SALL ...... C-17

8. Device Controls C-17 8.1. DEVICE ...... C-17 8.1.1. Fuse Specifier ...... C-17 8.1.2. Core Specifier ...... C-18 8.1.3. Reserved Options ...... C-18 8.2. ID ...... C-18 8.3. RESET...... C-19

9. Expressions C-19 9.1. Calculations ...... C-19 Table of Contents C-4 ©1996 microEngineering Labs 9.2. Operators ...... C-19 9.2.1. Bit Extension ...... C-20 9.2.2. Modulus ...... C-20 9.2.3. Shift Right...... C-20 9.2.4. DEF & REF...... C-20 9.3. Numeric Constants ...... C-21 9.4. String Constants ...... C-21 9.5. List Quoting...... C-21 9.6. Identifiers ...... C-22 9.6.1. Identifiers Starting with ‘:’ ...... C-22 9.6.2. Identifiers Starting with ‘$’ ...... C-22 9.6.3. Identifiers Starting with ‘_’ ...... C-22 9.6.4. Identifiers Starting with ‘@’ ...... C-22 9.7. System Variables ...... C-22 9.7.1. $ ...... C-22 9.7.2. DEVICE ...... C-23

10. File Formats C-23 10.1. Source File...... C-23 10.2. Map File ...... C-23 10.3. Binary Output File ...... C-23 10.4. Merged Intel HEX File ...... C-23 10.4.1. PIC16C5x Device Descriptor ...... C-24 10.4.2. PIC16Cxx Device Descriptor...... C-24 10.5. Symbol Table File...... C-25 10.6. Listing File...... C-25

11. Assembling Existing Parallax Code C-26

12. Warnings C-27 100 Attempt to Skip MultiByte @ Address ...... C-27 101 Use of Local Label Prior to Use of Non-Local Label ...... C-27 102 Code Crosses Boundary @ Address ...... C-27 104 Called Addresses must Reside in Lower Half of Page ...... C-27 105 Bit Addresses are the Same ...... C-27 106 Register Addresses are the Same ...... C-27

13. Errors C-28 200 Instruction Restricted to 14-Bit Core ...... C-28 201 ‘Character’ Expected...... C-28 202 Illegal Character ‘Character’ ...... C-28 203 ‘—’ or ‘++’ Expected ...... C-28 204 ‘W’ Expected as First Parameter ...... C-28 205 Illegal Use of Keyword ‘Keyword’...... C-28 206 CHECKSUM Not Supported in 14-Bit Core ...... C-28 208 Illegal Use of SUB Instruction ...... C-28

Appendix C ©1996 microEngineering Labs C-5 PIC Macro Assembler Reference 209 Indirect Jump Expected in Form of ‘PC+W’ ...... C-29 210 Bit Addresses Must Differ...... C-29 211 Poorly Formed Numeric Constant ‘Token’...... C-29 212 Extra Tokens on End of Line...... C-29 213 IRPC Expected Id or String Constant ...... C-29 214 IRPC Missing Replacement Parameter ...... C-29 215 Attempt to Redefine Macro ‘Identifier’ ...... C-29 216 Attempt to Redefine Macro Parameter ‘Identifier’ ...... C-29 217 Attempt to Generate Code in Non-Code Segment ...... C-29 218 Address Limit of Address Exceeded ...... C-30 219 Collision in HEX File @ Address...... C-30 220 Illegal Bit Number ...... C-30 221 Illegal Bit Address ...... C-30 222 Illegal Destination Specifier...... C-30 223 Illegal TriState File Register Address Register ...... C-30 224 Keyword Directive Only for Use in Macros ...... C-30 225 Undefined Symbol ‘Identifier’ ...... C-30 226 Numeric Constant or Symbol Name Expected ...... C-31 227 Divide by Zero ...... C-31 228 Modulus by Zero ...... C-31 229 Device Doesn’t Support EEPROM...... C-31 230 Collision in EEPROM @ Address ...... C-31 231 Attempt to Redefine ‘Identifier’ ...... C-31 232 File Name Expected ...... C-31 233 String Expression Expected for Title ...... C-31 234 Identifier Expected ...... C-31 235 Opcode Expected Instead of ‘Token’ ...... C-31 236 Label ‘Identifier’ Undefined in Pass 0 ...... C-32 237 IRP Missing Replacement Parameter ...... C-32

14. Fatal Errors C-32 300 Too Many Errors ...... C-32 301 Out of Memory ...... C-32 302 Unable to Open File ‘Filename’...... C-32 303 Unable to Create File ‘Filename’...... C-32 304 No Source File Specified ...... C-33 305 Unable to Write to File ‘Filename’ ...... C-33 306 Page Width must be 80 to 255 Columns ...... C-33 307 Illegal Device Type ...... C-33 308 Macro Buffer Overflow ...... C-33

15. Internal Errors C-33 400 Attempt to Free Non-Allocated Memory [Pointer] ...... C-33 401 Attempt to Reference Non-Allocated Memory [Pointer] .... C-33 402 Attempt to Pop Empty Symbol Table Stack ...... C-33 403 Attempt to Exit on Empty File Stack ...... C-33 404 Attempt to Pop Empty Macro Stack ...... C-33 405 Macro Stack Error ...... C-33 406 Attempt to Pop Empty Conditional Assembly Stack ...... C-33 407 No Function Handler for ‘Keyword’ ...... C-33

Table of Contents C-6 ©1996 microEngineering Labs 1. Assembler Overview

Compatibility Microchip & Parallax Instruction Sets Microsoft Compatible Macros Supports all 12-bit (16C5x) and 14-bit (16Cxx) PICs

Operation Two-Pass Assembly Operator precedence in evaluation of expressions Conditional Assembly Listing Controls Separate Code, Data and EEPROM Segments

Symbol Names Symbols up to 32 of the following characters : : @ $ _ A-Z 0-9 First character must be legal character other than 0-9. Special Uses : $ Reserved for Debugger Commands _ Reserved for @ Temporary Labels : Local Labels Case sensitivity is optional. Program labels must begin in column 1. Non-labels must not begin in column 1.

Numbers Default Radix is 10. All numbers must begin 0-9. An alternate radix may be selected with one of the following suffixes : B Binary O Octal H Hexadecimal Radix suffixes are not case sensitive. All numbers are kept in 32 bit two’s com- plement form (-231 to 231-1).

Strings Strings are enclosed by a matching pair of single or double quotes. No string operations are allowed.

2. Command Line Options

2.1. Usage

PM can be invoked from the DOS command line using the following command format :

PM Options filename Appendix C ©1996 microEngineering Labs C-7 PIC Macro Assembler Reference Zero or more options can be used to modify the manner in which the assembler processes the input file. Options begin either with a slash ( ‘/’ ) or a minus ( ‘-’ ). The character following the minus is a letter which selects the option. Additional charac- ters may be needed by some options to supply additional information. No spaces may occur within an option. Options not recognized by the assembler will generate errors and be ignored.

The first parameter not starting with a minus or a slash is assumed to be the filename. Extra parameters are ignored.

If PM is invoked with no options and no filename, a brief help screen is dis- played.

2.2. The PM Environment Variable

With programming tools, a programmer will often want certain options to be invoked consistently. This usually requires the programmer to invoke these options each time the tools is used. While batch files and makefiles can reduce this tedium, problems can also occur due to DOS limits on the length of command lines.

In order to alleviate these problems, the assembler uses a DOS environment variable named PM. This contains a string of command line options which are im- plicitly selected whenever the assembler is invoked. It uses the same format as the options selected on the command line. Once these have been processed, then normal command line options are processed and the file is assembled. Thus, you can use PM to override the assembler defaults and then use the command line to override PM defaults. This allows a great deal of customization to the assembler.

For example, suppose you want the PIC Macro Assembler to look more like the original Parallax assembler. No problem - simply add the following to your AUTOEXEC.BAT :

set PM=-EOOBJ This changes the extension of the output filename from ‘HEX’ to ‘OBJ’.

2.3. Options

Option Option Description C Identifiers to be Case Sensitive D Generates Listing, Symbol Table, and Map File Ecext Sets filename extension for specified file type L = Listing File M = Map File O = Output File I = Input File S = Symbol Table G# Set maximum error count Ipath Set default INCLUDE/MACLIB directory

Command Line Options C-8 ©1996 microEngineering Labs Option Option Description Lname Generate listing (listing filename is optional) Of Set output format B = Binary H = Merged Intel HEX Q Force use of explicit extension of source filename

2.3.1. Option -C By default, all items in PM are case insensitive. Thus, MIXED, Mixed, mixed, and mIXEd would all be treated as the same label or macro. When the -C option is invoked, identifiers are case sensitive. In this mode, the sample identifiers would all be treated as unique. In either mode, and pseudo-ops are always case insen- sitive. This mode is generally intended for use by compilers where case is important (such as C).

2.3.2. Option -D PM normally assembles a source file and outputs an executable equivalent of the program. When the -D option is invoked, a listing, a map and a symbol table are also generated. This options is mainly used to generate information for debuggers.

2.3.3. Option -ELext 2.3.4. Option -EMext 2.3.5. Option -EOext 2.3.6. Option -ESext The names for listing, map, output and symbol table files are generated auto- matically by the assembler. These names are created by taking the base name of the source file (up to 8 characters) and appending an extension indicating file type. The default extensions are :

File Type Default Extension Listing LST Map MAP Output HEX or BIN Symbol Table SYM

These files are placed in the current directory. The -E options allows these de- fault extensions to be changed. If the specified default is longer than 3 characters, it is truncated without warning or error. This option can be used to make the outputs of PM easier to use with various debugging platforms.

2.3.7. Option -EIext Whenever the assembler is invoked, it checks the name of the source file for an extension. If one is explicitly defined, it is used. If none is defined, then the assembler appends a default input extension to the filename. By default, this extension is SRC. The -EI option can be used to change this default to any three letter combination. If the specified default is longer than 3 characters, it is truncated without warning or error. Appendix C ©1996 microEngineering Labs C-9 PIC Macro Assembler Reference The -Q option can be used to force the programmer to always specify the filename extension, if any. Thus, -Q negates the use of the -EI option.

2.3.8. Option -G# PM can generate an unlimited number of warning. For the sake of clarity, how- ever, it limits the number of errors that can be generated. By default, PM terminates with a fatal error if 15 or more errors occur. Using the -G option, this value may be changed to any arbitrary number.

2.3.9. Option -Ipath Whenever the assembler encounters an INCLUDE or MACLIB directive, a search is conducted for the specified file. If a path is explicitly specified, that directory is searched. If the file is not found, a fatal error is generated.

If no path is specified, the file is first sought in the current directory. If not found there, then the system header directory is searched. By default, this directory is the INC subdirectory of the directory from which PM is executed. If also not found here, a fatal error is generated.

The -I option can be used to specify the new path of this default directory. When invoked, the path specified by the -I option is not checked for validity. Thus, specify- ing a non-existent or erroneous path can cause header files to seem to mysteriously disappear (i.e. the assembler can’t find them because the directory doesn’t exist).

2.3.10. Option -Lname When used, the -L option causes the assembler to generate a listing file in addi- tion to the normal executable image generated. When used by itself, the listing is placed in a file whose name is created by appending the listing extension (default is LST) to the base name of the source file. If the -L options is used to specify a filename, the listing is generated to the named file.

Note that even if the -D option (which by default generates a listing) is used, the -L option can still be valuable, because it allows you to specify the name and path of the listing file.

2.3.11. Option -OB By default, PM generates Merged Intel HEX format for the executable image. The -OB option allows the assembler to generate 16-bit binary format. 2.3.12. Option -OH

The -OH option forces PM to generate the executable image in the Merged Intel HEX format. This option is mainly useful to override the use of the -OB option that might be specified in the PM environment variable.

2.3.13. Option -Q Normally, when no extension is explicitly specified for the source, PM appends a default extension to the filename (SRC by default). The -Q option prevents this and forces the programmer to explicitly define the extension (if any) of the source filename. Command Line Options C-10 ©1996 microEngineering Labs 3. Pseudo-Ops

3.1. CODE

CODE [ Expr ]

The code segment manages the program space of the PIC. The CODE pseudo-op selects the code segment as the current segment. All bytes generated in the code segment are placed in the executable image file. The optional expression may be used to set the load pointer for the code segment.

3.2. DATA

DATA [ Expr ]

The data segment manages the RAM space of the PIC. The DATA pseudo-op selects the data segment as the current segment. Generation of code or initialized data in this segment results in an error (due to the Harvard architecture of the PIC). Thus, DS is the only usable pseudo-op in the data segment. The optional expression may be used to set the load pointer for the data segment.

3.3. EEPROM

EEPROM [ Expr ]

The EEPROM segment manages the EEPROM space available in the 8x family of PICs. The EEPROM pseudo-op selects the EEPROM segment as the current segment. Generation of code in this segment results in an error (due to the Harvard architecture of the PIC). Thus, DS, DB and DW are the only usable pseudo-ops in the EEPROM segment. The optional expression may be used to set the load pointer for the EEPROM segment.

3.4. ABS

ABS [ Expr ]

Sets the current segment to the absolute segment. This is the default segment and operates in the mode most familiar to programmers as “absolute” assembly. All bytes generated in this segment are placed in the executable image file. The DS command merely advances the load pointer. The optional expression may be used to set the load pointer for the absolute segment.

3.5. ORG

ORG Expr

Sets the load pointer for the current space. The user may get the current value of the load pointer for the current segment via the system variable $.

Appendix C ©1996 microEngineering Labs C-11 PIC Macro Assembler Reference 3.6. DS

DS Expr

Advances the load pointer by the specified value. DS is normally used to allocate space within the data or EEPROM segments. When used in the EEPROM segment, no data is generated in the HEX file for the allocate locations. This allows EEPROM locations to be allocated that will not be programmed (assuming your programmer doesn’t unconditionally program all EEPROM locations).

3.7. DB

DB (Expr|String) { , (Expr|String) }

Stores one or more constant bytes in the current segment. In the case of numeric constants, the resulting values (truncated to 8 bits, if necessary) are stored. String constants are stored as consecutive bytes.

Since the PIC cannot store data in the code space directly, each byte generated in the code segment is actually stored as a RETLW instruction. Bytes generated in the EEPROM segment are stored merely as data. And, of course, bytes generated to the data segment result in errors.

3.8. DW

DW Expr { , Expr }

Stores the resulting value in the current segment. The value is truncated to 16- bits. The least significant byte is stored first. Each byte is generated in the same manner as the DB pseudo-op.

3.9. EQU 3.10. =

Label EQU Expr Label = Expr

Assigns a numeric value to the specified symbol. The two operations are similar, except it is an error to redefine a symbol created using the EQU pseudo-op. Symbols created using the = may be reassigned value without error.

4. Conditional Assembly

Note: PM requires that all symbols be defined at the end of the first pass. In order to meet this requirement, the evaluation of all conditional assembly constructs must be consistent in both passes. Thus, unlike other assembler features, conditional as- sembly may not assemble correctly if it relies on forward references.

Pseudo-Ops C-12 ©1996 microEngineering Labs 4.1. IF 4.2. ELSEIF 4.3. ELSE 4.4. ENDIF

IF Expr ... ELSEIF Expr ... ELSE ... ENDIF

Assembly continues following the first true (i.e. non-zero) expression in the se- ries of IF and ELSEIF statements and continues until the next statement in the IF..ELSE..ENDIF chain. If no statement is true and an ELSE statement is present, the code between ELSE and ENDIF is assembled. The IF and ENDIF terms are mandatory. One ELSE and multiple ELSEIF terms are optional.

4.5. IFDEF 4.6. IFNDEF

IFDEF Label IFNDEF Label

The IFDEF and IFNDEF statements may be substituted for the IF term in the IF..ELSE..ENDIF construct. IFDEF evaluates true if the specified symbol is de- fined. IFNDEF evaluates true if the specified symbol is not defined. There are no IFDEF/IFNDEF replacements for the ELSEIF statement.

The DEF operator may be used for more complicated variations on the IFDEF/ IFNDEF pseudo-ops.

4.7. IFB 4.8. IFNB

IFB [ Item ] IFNB [ Item ]

The IFB and IFNB statements may be substituted for the IF term in the IF..ELSE..ENDIF construct. IFB evaluates true if an item is listed on the line follow- ing the IFB statement. IFNB evaluates true if no item is listed on the line following the IFNB statement. There are no IFB/IFNB replacements for the ELSEIF state- ment.

Comments are treated as blanks in the evaluation of IFB and IFNB statements. These constructs are mainly useful in macros to test whether a parameter has been specified by the caller or has been omitted.

Appendix C ©1996 microEngineering Labs C-13 PIC Macro Assembler Reference 5. Macro Facility

5.1. REPT

REPT Expr Body ENDM

The body of the macro is repeated the number of times specified by the numeric expression. The REPT macro is executed immediately.

5.2. IRPC

IRPC Param , String Body ENDM

The body of the macro is repeated once for each character in the specified string. The specified parameter is substituted on each expansion with the scanned character. The IRPC macro is executed immediately.

5.3. IRP

IRPParam , < Expr { , Expr } > Body ENDM

The IRP macro is similar to the IRPC macro, except that items from the speci- fied list (bracketed with < and >) are substituted for the specified parameter. The IRP macro is executed immediately.

5.4. MACRO

Label MACRO Param { , Param } Body ENDM

Unlike other macro types, MACRO merely creates a template for later macro expansions. MACRO accepts up to 32 identifiers as parameters. Whenever found in the body (even in quotes), these parameters are substituted with the value specified when the macro is invoked. Macros are invoked just as any other pseudo-op or opcode. Parameters specified in the definition but not assigned values when invoked are left unsubstituted. This allows macros with a variable number of parameters if used with the IFB and IFNB conditional assembly constructs.

Since a macro’s name is a label, it must begin in column 1.

5.5. LOCAL

LOCAL Symbol { , Symbol } Macro Facility C-14 ©1996 microEngineering Labs Allows the creation of local symbols in any macro type. A unique temporary symbol is created for each local symbol for every expansion of the macro’s body. Any number of LOCAL statements may be defined, but they must immediately fol- low the macro definition (REPT, IRPC, IRP or MACRO pseudo-op). Local symbols take the form @@NNNN, where NNNN is a four digit decimal number assigned sequentially from 0000.

5.6. EXITM

Allows premature abortion of macro expansion. This is useful for implementing loops whose lengths are not determinant.

5.7. ENDM

All macro definitions are terminated by the ENDM pseudo-op.

6. File Controls

6.1. INCLUDE

INCLUDE String

The INCLUDE statement is replaced with the contents of the specified file. If no path is specified, the file is searched for first in the current directory. If not found, then the system header directory is searched. If still not found, an error results.

By default, the system header directory is the INC subdirectory of the directory from which PM.EXE is executed. This directory contains files defining important constants and macros for each of the PICs supported. This can be changed by the use of the -I command line option.

6.2. MACLIB

MACLIB String

MACLIB is identical in operation to INCLUDE, except that the file is only parsed on the first pass. This is intended for use on include files that contain only macro and symbol definitions.

Avoid the use of MACLIB if the file includes any opcodes. If used on such a file, the file will affect assembly on the first pass, but not on the second. This can create major discrepancies in the second pass of assembly and usually results in a large number of confusing error.

Appendix C ©1996 microEngineering Labs C-15 PIC Macro Assembler Reference 7. File and Listing Controls

7.1. TITLE

TITLE String

Specify the title at the top of every page in listing file.

7.2. PAGE

PAGE Expr , Expr PAGE Expr PAGE

If the first parameter is defined, it sets the page width for the listing. The page width must be between 80 and 255 characters (default is 132). Characters beyond this width are truncated from the listing. If the second parameter is defined, it sets the page length of the listing (default is 60). If the page length is set 0, no automatic page breaks are generated.

If the PAGE pseudo-op is used without parameters, it forces a page break in the listing.

7.3. LIST 7.4. NLIST

If the -L option is used, the listing counter is initialized to 1. Otherwise, it de- faults to an initial value of 0. LIST increments the listing counter. NLIST decrements the listing enable counter. Whenever the listing counter is positive, lines are gener- ated for the listing.

This simple arrangement allows a greater flexibility in listing control than did earlier versions of PM. For example, the source file may contain listing controls without unconditionally generating a listing.

7.5. MTLIST 7.6. NMTLIST

If the MTLIST pseudo-op is used, enough lines are generated to display all bytes generated by the listed statement. This is the default.

If the NMTLIST is pseudo-op is used, only one line is listed for each line of source code. If a line generates more than 4 words of code, additional bytes are not displayed and the line is marked with an ‘#’.

File and Listing Controls C-16 ©1996 microEngineering Labs 7.7. CLIST 7.8. NCLIST

The CLIST pseudo-op forces all portions of IF..ELSE..ENDIF constructs to be listed. This is the default.

The NCLIST pseudo-op forces only those portions of IF..ELSE..ENDIF con- structs that are assembled to be listed. The conditional statements themselves are always listed, although nested IF..ELSE..ENDIF constructs in unassembled blocks of code are not listed.

7.9. LALL 7.10. XALL 7.11. SALL

If LALL pseudo-op is used, all lines of a macro expansion are listed. This is the default.

If XALL pseudo-op is used, only those lines of a macro expansion which gener- ate code are listed.

If SALL pseudo-op is used, no lines of a macro expansion are listed.

8. Device Controls

PM was written to be compatible with all 12-bit and 14-bit PICs. The assembler was designed to handle the architectural limits of both core types. Each program must specify which core and a specific set of capabilities by using the DEVICE statement.

8.1. DEVICE

DEVICE Expr { , Expr }

The DEVICE pseudo-op takes one or more comma separated 32-bit expressions as parameters. The bits 31 and 30 of each value distinguishes one of four separate processor specifications. These two bits determine how the remaining thirty bits of that value are interpreted.

8.1.1. Fuse Specifier If the upper two bits of a parameter are 00, this word defines the configuration fuses. PM allows arbitrary control of a 14-bit fuse word. When a fuse specifier is used, two actions are taken:

• The current fuse value is ANDed with the upper 16 bits of the 32 bit word. • The resulting fuse value is then ORed with the lower 16 bits of the 32 bit word.

Appendix C ©1996 microEngineering Labs C-17 PIC Macro Assembler Reference This system allows one or more values to be chained together to control various bit locations in the fuses. These may occur in any order or even in multiple DEVICE statements. The actual values used to set the fuses are normally defined in the header file defined for a particular component or family of components. Below is a partial table containing the most common fuse specifiers. For a full list, consult the device header for your particular device.

DEVICE Parameter Description RC_OSC RC Oscillator HS_OSC HS Oscillator XT_OSC XT Oscillator LP_OSC LP Oscillator BOD_ON Brown-Out Detection Enabled BOD_OFF Brown-Out Detection Disabled PROTECT_ON Code Protection Enabled PROTECT_OFF Code Protection Disabled WDT_ON Watch Dog Timer Enabled WDT_OFF Watch Dog Timer Disabled

8.1.2. Core Specifier The core specifier defines the processor’s core type (12 bit or 14 bit) and the amount of ROM/EEPROM available. This information is needed to generate core appropriate instructions and to perform range checking on addresses.

Additionally, an arbitrary 8-bit numeric code may be assigned to the processor. While PM doesn’t use this information, it is embedded in the output file and this information is used by some simulators, programmers, and other third party develop- ment tools. There is no standardization (among tool providers) on these numbers.

No attempt is made to provide RAM availability information. The asymmetry of data pages makes it difficult to perform error checking without generating warnings on valid instructions.

Unlike fuse specifiers, a core specifier must be set in one value - it lacks the running accumulation effect of fuse specifiers.

8.1.3. Reserved Options The two remaining DEVICE fields (10 and 11) are reserved for future use. Any DEVICE value containing these upper 2 bits will generate an error.

8.2. ID

ID Expr ID String ID CHECKSUM

Each PIC has a 16-bit (12-bit core) or 28-bit (14-bit core) ID. This value can be set in one of three methods. A numeric expression or string constant can be used for either core type. For 12-bit cores only, the reserved word CHECKSUM may be used. Device Controls C-18 ©1996 microEngineering Labs This forces the Parallax PIC Programmer to compute the checksum of the PIC code space.

8.3. RESET

RESET Expr

Each time a PIC is powered up or reset, the PC is set to a determinant spot. It is assumed that the programmer will use this knowledge to get his program to start executing whenever the PIC is ready. The most common method of doing this is to place a GOTO instruction at this spot. In the 12 bit core, execution begins with the last word of ROM. In the 14 bit core, execution begins at 0000h.

The RESET pseudo-op places a GOTO at the correct address determined for the current processor type (as set by the DEVICE pseudo op). The RESET command is most commonly used in programs for 12-bit cores.

9. Expressions

9.1. Calculations

Even though PIC processors only handles 8-bit math and use 11-bit or 13 bit addresses, PM performs all calculations and stores all constants 32-bit, two’s com- plement form.

No string operations are available.

9.2. Operators

Operator Function Unary Precedence ( ) Grouping Operators x 1 REF Label Reference x 2 DEF Label Defined x 2 - Unary Minus x 2 + Unary Plus x 2 ~ Bitwise NOT x 2 ! Logical NOT x 2 HI MSB of Word x 2 LO LSB of Word x 2 * Multiply 3 / Divide 3 % Modulus 3 >> Shift Right 4 << Shift Left 4

continued on next page..

Appendix C ©1996 microEngineering Labs C-19 PIC Macro Assembler Reference Operator Function Unary Precedence - Subtract 5 + Addition 5 = Equivalence 6 <> Inequality 6 < Less Than 6 > Greater Than 6 <= Less Than or Equal 6 >= Greater Than or Equal 6 & Bitwise AND 7 ^ Bitwise XOR 8 | Bitwise OR 8 . Bit Address Operator 9

Expressions are resolved from left to right using operator precedence to resolve ambiguities in evaluation. The precedence of each operator is shown. Operators with the highest precedence (i.e. those which are evaluated first) are show as precedence_1.

9.2.1. Bit Extension Whenever bits in a number are inverted, this inversion occurs in all 32 bits. This causes the bit-wise inversion and negation of byte-sized numbers with 1’s in the upper bits. This, however, isn’t usually a problem, since opcodes usually truncate calculated values to the appropriate size without generating warnings or errors.

9.2.2. Modulus Modulus is the proper name for what you may have learned in school as the “remainder”. In short, it is value that is “left over” when one integer value is divided by another. In systems which support signed numbers, there is some ambiguity as to the sign of the remainder for negative numbers. PM returns a modulus with the same sign as the dividend.

9.2.3. Shift Right Shift right is often used as a fast-divide for binary values (e.g. shifting right by 3 bits is the same as dividing by 8). Since PM works with signed numbers, a number shifted right will retain the value of the 32nd bit (i.e. sign extension).

9.2.4. DEF & REF DEF ( LabelList ) REF ( LabelList )

In order to allow PM to simulate a linking library, the DEF and REF operators are defined. The DEF operator returns true (1) if the specified label(s) have been defined earlier in the program. Similarly, the REF operator returns true (1) if the specified label(s) have been used (referenced) earlier in the program. Both return 0 if the tested condition is false.

To increase flexibility, more than one label may be tested. In fact, logical opera-

Expressions C-20 ©1996 microEngineering Labs tors (‘|’ for OR and ‘&’ for AND) and parenthesizes have are supported for complex label lists.

9.3. Numeric Constants

All numbers default to radix 10. All numbers (regardless of radix) must begin with digits 0-9. Other bases may be selected by appending the following suffixes. Suffixes are not case sensitive.

B Binary O Octal H Hexadecimal

9.4. String Constants

PM supports string constants mainly for the purpose of generating strings of RETLWs (via the RETW opcode and DB pseudo-op). Strings may be enclosed by either single ( ‘ ) or double ( “ ) quotes. If single quotes are used, then double quotes may be used freely within the string, and vice versa. Single quotes may not appear within a single quoted string and double quotes may not appear within a double quoted string.

String constants may also be used to drive the IRPC macro pseudo-op. On each expansion of the IRPC macro, the replacement parameter is replaced with an unquoted character. When used as a parameter for macros defined using the MACRO pseudo- op, the quoted string is passed unmodified (quotes intact).

9.5. List Quoting

The IRP macro is driven by a list of comma separated items bracketed with < and > characters. This item can be so useful, that < and > have been given a special “quoting” function in macros. When the < character is encountered in the parameter list for a macro defined using the MACRO pseudo-op, the parameter is considered to contain all characters up to the next >. This type of bracketing may not be nested. When this parameter is substituted, the < and > are stripped from the substitution.

1 defb1 macro list 2 irp item, 3 db item 4 endm 5 endm 6 7 defb2 macro list 8 db list 9 endm 10 11 defb1 <1,”One”,2,”Two”> + irp item,<1,”One”,2,”Two”> + db item + endm + 000- 801 db 1 + 001- 84F 86E 865 db “One” + 004- 802 db 2 + 005- 854 877 86F db “Two” 12 defb2 <1,”One”,2,”Two”> + 008- 801 84F 86E 865 db 1,”One”,2,”Two” 00C- 802 854 877 86F Appendix C ©1996 microEngineering Labs C-21 PIC Macro Assembler Reference 9.6. Identifiers

Identifiers are the names used as program labels, variables and macro names. Although they can be any length, only the first 32 characters are significant and they must be unique in these 32 characters. Identifiers differing only in the 33rd or later character are considered identical. Identifiers consist of any of the following charac- ters :

A-Z 0-9 : @ $ _

Identifiers may begin with any of these characters except 0-9. The first character may have a special meaning, as described in the following sections.

9.6.1. Identifiers Starting with ‘:’ Symbols starting with a colon ( ‘:’ ) are local symbols. This method appends this local label to the last non-local label (i.e. label beginning with other than a colon). This allows simple labels within a global block not to pollute valuable name space. The labels can be referenced within this local block using the abbreviated local name. To reference this label outside the block, the full form needs to be used (i.e. non local:local).

9.6.2. Identifiers Starting with ‘$’ Symbols starting with the dollar sign ( ‘$’ ) are reserved for future debugging use. Currently, only one symbol starting with the dollar sign is reserved by the as- sembler, which is the dollar sign itself. It is used to get the value of the load pointer for the current segment.

9.6.3. Identifiers Starting with ‘_’

Symbols starting with the underscore ( ‘_’ ) are reserved for use by compilers.

9.6.4. Identifiers Starting with ‘@’ Symbols starting with the at symbol ( ‘@’ ) are treated as temporary labels. Temporary symbols are treated just like other labels, except they are not included in the symbol table. The LOCAL pseudo-op generates symbols in the form of @@NNNN, where NNNN is a four digit decimal number starting with 0000.

9.7. System Variables

In order to make programming easier, PM defines some system variables. You cannot redefine these variables, although they can be used as you would other vari- able.

9.7.1. $ The dollars sign ( $ ) is used to get the value of the load pointer for the current segment. Each of the four segments (CODE, DATA, EEPROM and ABS) has its own load pointer. Therefore, the value of $ depends on the segment in which it ap- pears. Expressions C-22 ©1996 microEngineering Labs 9.7.2. DEVICE DEVICE returns the core specifier. For details on these flags, see the description of the DEVICE pseudo-op.

10. File Formats

10.1. Source File

; Test File for PIC Macro Assembler

include ‘T13.INC’ ; Show Include File

SIZE equ 10h ; Show Assignment Statement mac “uChip” ; Show Macro Expansion

nmtlist ; Suppress Multi Line Listing db “uChip” ; Generate Constants mac “uChip” ; Expand & Generate Constants PM uses a common collimated format for the input (or source) file. This is the same format as used by the original Parallax PIC assembler. Items starting in column 1 are either labels, variables, or macro names. Items beginning in column 2 or later are assumed to be opcodes or pseudo ops. Depending on the opcode or pseudo-op, zero or more comma separated parameters may follow the opcode/pseudo-op. Com- ments (which begin with a semicolon) may begin in any column.

10.2. Map File

The MAP file is used to link the executable file to the source file. The MAP file contains one 16-bit number (2 bytes) for each word in the code space of the target processor. This 16-bit number (stored LSB first) is the number of the line in the source file which generated the corresponding instruction in the executable image. No provisions are made for mapping instructions on to lines in generated in IN- CLUDE or MACLIB files.

10.3. Binary Output File

The simplest output format of PM is the 16-bit binary format. The binary file contains one 16-bit word (2 bytes) for each word in the code space of the target processor. This word (stored LSB first) contains the actual PIC opcode for the corre- sponding address (i.e. the first word of the file corresponds to address 000h in the target processor). The most significant bits of the word which are unused by the processor (4 in the 12-bit core, 2 in the 14-bit core) are zeroed. Addresses not as- signed values by the assembler are stored with all 1’s (0FFFh in the 12-bit core, 3FFFh in the 14-bit core).

10.4. Merged Intel HEX File

The default output format of PM is the Merged Intel HEX format. This section will not describe the standard Intel HEX format (which is well documented else- where), but details the deviations from the standard for the Merged format. Appendix C ©1996 microEngineering Labs C-23 PIC Macro Assembler Reference Each word of the executable image is stored in consecutive bytes in the Intel format (LSB first). To adjust for the 2-byte word size of the PIC, the Intel HEX addresses are doubled (since the format is strictly byte oriented). With these two adjustments made, the Merged Intel HEX format is identical to the standard Intel HEX format.

Unlike the binary format, only bytes which are actually generated have any value specified in the Merged Intel HEX format. If some fill value is required, this must be handled by your PIC programmer.

Unlike the binary file format, the Merged Intel HEX format also contains infor- mation on the processor type, ID/checksuming flag and the fuses.

10.4.1. PIC16C5x Device Descriptor :061FFA00 0001 FFFF 03 02 DD Intel Checksum Fuses Processor Number ID Checksum Flag Intel Header

The device descriptor for the PIC16C5x family is shown above. The checksum flag (2 bytes) is 0000 if no checksum is to be calculated and 0001 is the checksum is to be calculated. The ID field contains the 16-bit ID (LSB first) as specified by the ID pseudo-op. The ID is FFFF if the checksum for the PIC is to be calculated (i.e. Checksum = 0001). The processor numbers for the PIC16C5x family are as follows:

00 PIC16C54 01 PIC16C55 02 PIC16C56 03 PIC16C57 04 PIC16C58

For details on the fuses field, see the description of the DEVICE pseudo op.

10.4.2. PIC16Cxx Device Descriptor :084000007F007F007F007F00BC Intel Checksum ID Intel Header

:04400E00FF3F000070 Intel Cheksum 00 PIC16C71 Processor Code 01 PIC16C84 Fuses 02 PIC16C64 Intel Header 03 PIC16C74

File Formats C-24 ©1996 microEngineering Labs 10.5. Symbol Table File

a_abs 0000000A a_code CODE 0000000A a_data DATA 0000000A a_eeprom EEPROM 0000000A x_abs 00000000 x_code CODE 00000000 x_data DATA 00000000 x_eeprom EEPROM 00000000 The symbol table contains all labels (except labels starting with the ‘@’ charac- ter) defined in the program. This file contains three unlabeled columns. The first column contains the actual name of the symbol. The case of the defining instance is preserved and only the first 32 significant characters are displayed. The second col- umn may contain the label’s type (CODE, DATA or EEPROM). This is determined by the segment in which the label was defined. No type is generated for the ABS segment, which is the default. Finally, the last column contains the full 32-bit repre- sentation of the number in hexadecimal. Note that base-16 is understood and no ‘H’ suffixes or ‘0x’ prefix has been included. Symbols are listed in alphabetical order.

This format is intended for use by debuggers and is not really made human readable. While the items currently begin in fixed column, this may change in the future. Those parsing these items should rely on the use of whitespace as separators, rather than column numbers. Additional fields (columns) may be added to the end of each line in the future, so those processing this format should ignore items occurring after the value.

10.6. Listing File

1 ; Test File for PIC Macro Assembler 2 3 include ‘T13.INC’ * 1 mac macro p * 2 db ‘p’ * 3 endm * 4 mac “uChip” + 000- 822 875 843 868 db ‘“uChip”’ 004- 869 870 822 4 5 =0010 SIZE equ 10h 6 mac “uChip” + 007- 822 875 843 868 db ‘“uChip”’ 00B- 869 870 822 7 8 nmtlist # 9 00E- 875 843 868 869 db “uChip” 10 mac “uChip” # + 013- 822 875 843 868 db ‘“uChip”’ The listing file gives the programmer the most information about the actual as- sembly of the source file, and is therefore the most complex. This file contains three columns of assembly information followed by the source code.

The first column of the listing is a single character which gives additional infor- mation about the line being listed. The following table shows these tag characters. While multiple tags might apply to a single line, only one is listed. Thus, they are listed below in order of preference : Appendix C ©1996 microEngineering Labs C-25 PIC Macro Assembler Reference # More than 4 Words Generated, but Suppressed * Line is from Include File Normal Source Line

The second column displays the line number. If the current line is from an in- cluded file, the number of that line within the include file is listed. If the current line is generated by a macro expansion, the line number is replaced with a ‘+’.

The last column displays the results of the line. If the line computes a value for a label or as the parameter for a pseudo-op, then the value is display either as a 4 or 8 hexadecimal digit number following an ‘=’. If the line generates code, the current load pointer is displayed, followed by ‘-’ and one or more lines of up to 4 words per line. For comments and many pseudo-ops, this column is left blank.

11. Assembling Existing Parallax Code

For the most part, PM will assemble existing Parallax code (previously assem- bled w/ PASM, PASM71 or PASMX) with little or no change. The following steps may be needed :

* Depending on the type of PIC, place the following line in the source prior to any lines of code :

PIC16C5x MACLIB ‘P5X.INC’ PIC16C61 MACLIB ‘P61.INC’ PIC16C62 MACLIB ‘P62.INC’ PIC16C62x MACLIB ‘P62x.INC’ PIC16C63 MACLIB ‘P63.INC’ PIC16C64 MACLIB ‘P64.INC’ PIC16C65 MACLIB ‘P65.INC’ PIC16C70 MACLIB ‘P70.INC’ PIC16C71 MACLIB ‘P71.INC’ PIC16C72 MACLIB ‘P72.INC’ PIC16C73 MACLIB ‘P73.INC’ PIC16C74 MACLIB ‘P74.INC’ PIC16C84 MACLIB ‘P84.INC’

* If you receive the error [225] Undefined Symbol ‘W’, the source may con- tain the Parallax opcode MOV W,fr-W. This opcode is not supported by PM. This opcode can, however, be replaced with the Microchip equivalent SUBWF fr,0.

MOV W,fr-W Becomes SUBWF fr,0

* The SUBB instruction of PASM was specialized for use with the PIC carry flag (C), which is inverted from carry flags in most conventional processors (0 if a borrow occurs). Thus, SUBB modified its destination if the specified bit is 0, which is nonsense for general bit usage (although it makes sense for 16-bit subtraction). If you used these instructions in your program, you must invert the sense of the bit. File Formats C-26 ©1996 microEngineering Labs SUBB fr,bit Becomes SUBB fr,/bit SUBB fr,/bit Becomes SUBB fr,bit

* The original Parallax assembler evaluates equations strictly left to right (i.e. 3+4*5 = 35). PM also evaluates equations left to right, but uses operator precedence (i.e. 3+4*5 = 23). This typically creates no problems since PIC programs tend to be relatively simple. You should, however, check for complex calculations to assure that their evaluation will be correct.

12. Warnings

100 Attempt to Skip MultiByte OpCode @ Address Indicates the current instruction is a multibyte Parallax instructions and that the previous instruction is attempting to skip it. Obviously, if this were done unintention- ally, a successful skip would enter the current opcode mid-instruction.

101 Use of Local Label Prior to Use of Non-Local Label Indicates that a local label (i.e. starting with a colon) has been defined prior to the definition of a non-local label (i.e. a legal label name starting with other than a colon). Because local names depend on the named of last non-local label defined, this usage is obviously suspicious. The label generating the warning is not expanded as are other local labels (see Local Labels).

102 Code Crosses Boundary @ Address Both the 12-bit and 14-bit PIC cores have paged architectures in which the normal incrementing of the PC doesn’t extended into page select registers (PA0 & PA1 in the PIC16C5x, PCLATH in the PIC16Cxx). If a continuous block of code is generated across a page boundary and a forward jump is coded, the actual jump location will be to the previous page.

104 Called Addresses must Reside in Lower Half of Page In the PIC16C5x family, the 9th bit of address is zeroed on calls. Thus, call desti- nations must reside in the lower 256 words of any 512 word page. This mistake is only a warning since calls made to the upper 256 words will alias to an address in the lower 256 words of the page.

105 Bit Addresses are the Same This warning indicates that you have attempted to copy a bit to itself. The Parallax MOVB bit,bit instruction will correctly copy a bit to itself, although the operation has no useful applications.

106 Register Addresses are the Same This warning indicates that you have attempted to copy a register to itself. While this is legal, it generates a MOVF and MOVWF instruction, placing the moved value in W and setting the Z flag. If your intentions are to set the Z flag according to contents of the specified register, the TEST instruction will do this in one word and without de- stroying the contents of W. Appendix C ©1996 microEngineering Labs C-27 PIC Macro Assembler Reference 13. Errors

Unless specified otherwise, each of the following errors will terminate the as- sembly of the current line. If possible, the assembler will generate correct code (or at least the correct number of words) before the line is aborted. Assembly continues with the next line of source.

Unless otherwise specified, the error report has no side effects other than to bump the error count.

200 Instruction Restricted to 14-Bit Core The opcode of the specified line cannot be used for the PIC16C5x family: ADDLW #literal SUBLW #literal RETFIE RETURN

201 ‘Character’ Expected The assembler expected, but didn’t find, the specified character.

202 Illegal Character ‘Character’ The assembler doesn’t recognize the legal use of the specified character.

203 ‘—’ or ‘++’ Expected The Parallax instruction MOVSZ (MOVe and Skip in Zero) must take one of two forms : MOVSZ W,++fr MOVSZ W,—fr

204 ‘W’ Expected as First Parameter The Parallax instruction MOVSZ (MOVe and Skip in Zero) must take one of two forms : MOVSZ W,++fr MOVSZ W,—fr

205 Illegal Use of Keyword ‘Keyword’ Indicates that the specified identifier is a reserved word of the assembler and has been improperly used.

206 CHECKSUM Not Supported in 14-Bit Core The CHECKSUM option may be used as the ID of a processor in the PIC16C5x family. This option is not legal on the 14-bit core.

208 Illegal Use of SUB Instruction This error indicates an attempt was made to use the illegal instruction : SUB W,fr

Errors C-28 ©1996 microEngineering Labs 209 Indirect Jump Expected in Form of ‘PC+W’ This error indicates an attempt was made to use the illegal instruction : JMP PC+Expr

210 Bit Addresses Must Differ The Parallax MOVB bit1,/bit2 instruction requires that the source and destina- tion bits be different. An attempt to copy the complement of a bit to itself will result in the unconditional setting of the bit.

211 Poorly Formed Numeric Constant ‘Token’ Indicates that the symbol is not a legally formed numeric token. If any initial portion of this token is a valid constant, that portion is converted and its value is used as the result of the token.

212 Extra Tokens on End of Line Some initial portion of the current line assembled correctly, but additional as- sembly tokens remain unprocessed. This is often the result of a syntax error (extra parameters, misplaced or missing punctuation, etc.). Code is generated for the cor- rect initial portion of the line.

213 IRPC Expected Id or String Constant The second parameter of the IRPC macro definition is the item (scanned charac- ter by character) which drives the macro expansion. This item must be either an identifier or a quote-enclosed string constant.

214 IRPC Missing Replacement Parameter The first parameter of the IRPC macro definition is the variable which accepts the characters scanned from the second parameter. The first parameter must be an identifier unique within the definition of the macro.

215 Attempt to Redefine Macro ‘Identifier’ An attempt was made to redefine the named macro.

216 Attempt to Redefine Macro Parameter ‘Identifier’ Each parameter and local variable of a macro must be unique. This error indi- cates that a parameter or local name has been duplicated.

217 Attempt to Generate Code in Non-Code Segment Due to the Harvard Architecture (split code and data spaces) of the PICs, in- structions may only be executed from CODE space (ROM). This error indicates that an attempt was made to generate opcodes in the data or EEPROM segments. In general, only the DS pseudo-op is legal in the data segment and DS, DB and DW are the only legal pseudo-ops in the EEPROM segment.

Appendix C ©1996 microEngineering Labs C-29 PIC Macro Assembler Reference 218 Address Limit of Address Exceeded This error indicates that current segment has overflowed.

219 Collision in HEX File @ Address This error indicates that more than one word has been generated for the specified ROM address.

220 Illegal Bit Number In the PIC (and most processors), the bits of a byte are numbered from 0 (the least significant bit - LSB) to 7 (the most significant bit - MSB). This error indicates that the specified bit number is not in the range of 0 to 7.

221 Illegal Bit Address The four basic bit operators of the PIC take either an 8-bit field (12-bit core) or a 10-bit field (14-bit core). This is composed of a register address and a bit number. If this combination exceeds the 8 or 10 bit range for the selected processor, this error is generated. Note that only the composite value is checked - this check in no way guarantees the validity of the bit number or the register address. These value are, however, checked whenever they can be checked as separate parameters.

222 Illegal Destination Specifier Many Microchip instructions expect the second parameter to specify the destina- tion of the operation result : 0 if the result is also the source register, 1 if the result is to be placed in W. This error indicates that a numeric expression was used for this parameter which neither evaluated to 0 nor 1. For clarity, the second parameter can be omitted to use the source register as the destination and W can be used to specify W as the destination.

223 Illegal TriState File Register Address Register The TRIS instruction may only operate upon registers 5, 6, or 7. This error indicates that the specified register value was other than 5, 6, or 7. The equivalent Parallax instruction may also generate this error :

MOV !Register,Source

224 Keyword Directive Only for Use in Macros Some keywords (such as LOCAL and ENDM) only have meaning in the defini- tion of a macro body. This error indicates that an attempt was made to use such a keyword in some other context.

225 Undefined Symbol ‘Identifier’ A reference was made to the specified symbol although no such symbol was detected in the first pass of the assembler.

Errors C-30 ©1996 microEngineering Labs 226 Numeric Constant or Symbol Name Expected A legal expression is a well formed sentence containing operators and terminals from which values for the operators are derived. This error indicates that an expres- sion terminal was encountered which didn’t evaluate to a numeric value.

227 Divide by Zero An attempt was made (in the source) to divide by zero at assembly time.

228 Modulus by Zero An attempt was made (in the source) to take the modulus of a number by zero at assembly time.

229 Device Doesn’t Support EEPROM An attempt was made to generate values in the EEPROM segment for a device which doesn’t support EEPROM.

230 Collision in EEPROM @ Address An attempt was made to generate more that one value for the specified EEPROM location.

231 Attempt to Redefine ‘Identifier’ An attempt was made to assign a new value to a symbol defined either as a program label or using the EQU pseudo-op. A common (but confusing) source of this error can result from different flows through conditional assembly blocks be- tween the first and second passes. While this type of variant programming can be done, it is very tricky and poor programming practice - it should be avoided.

232 File Name Expected Indicates that the parameter specified for the current INCLUDE or MACLIB pseudo-op is not a quoted string.

233 String Expression Expected for Title The TITLE pseudo-op is used to replace the normal copyright notice of the listing with a customized header. This new header must be specified as a quoted string and is the only parameter of the TITLE pseudo-op.

234 Identifier Expected The IFDEF and IFNDEF conditional assembly pseudo-ops require one identifier as it parameter. This error is generated whenever this parameter is other than a legal identifier.

235 Opcode Expected Instead of ‘Token’ Any text starting in column 2 or later which is not a commented is assumed to either be an opcode, a pseudo-op or the name of a defined macro. All other tokens will generate this error.

Appendix C ©1996 microEngineering Labs C-31 PIC Macro Assembler Reference 236 Label ‘Identifier’ Undefined in Pass 0 This error indicates that an attempt was made to define the specified symbol in pass 1, although no definition was made for the symbol during pass 0. This is almost always the result of different flows through conditional assembly blocks between pass 0 and pass 1.

237 IRP Missing Replacement Parameter The IRP macro takes two parameters. The first parameter is an identifier which is substituted on each expansion with the next item from the comma separated list (the second parameter). This error indicates that the identifier expected for the first parameter of the IRP statement was not found.

14. Fatal Errors

300 Too Many Errors The assembler can generated an unlimited number of warnings, but the number of errors is limited. While this value defaults to 15, it can be changed using the -G option. This fatal error is generated when this allowance is exceeded.

301 Out of Memory Indicates that the symbol table, macro table and other memory requirements for internal bookkeeping have exceeded the memory capacity of your PC. While this error message is unlikely, it can occur on limited or heavily burdened systems. If not already at the 640K limit for conventional memory, add memory. Unloading or load- ing high of TSRs and network drivers can increase usable memory. Memory may also be gained by reducing the number of BUFFERS and FILES allocated in CONFIG.SYS.

302 Unable to Open File ‘Filename’ Indicates that DOS was unable to open the specified file. This is either because the file could not be found or not enough file handles were available (this usually only occurs with deep nesting of INCLUDE and MACLIB statements). If the file exists, make sure it resides in the current directory. If the file is an INCLUDE or MACLIB file, also check in the default include directory. While this defaults to the INC subdirectory of the directory where PM.EXE is kept, it can be modified using the -I option. If the file is found as described above, try increasing the number of FILES in CONFIG.SYS.

303 Unable to Create File ‘Filename’ Indicates that DOS was unable to create the specified file. This is either because there are not enough file handles available or there is not enough space on the desti- nation disk. If there is adequate disk space available, try increasing the number of FILES in CONFIG.SYS.

Errors C-32 ©1996 microEngineering Labs 304 No Source File Specified This error is generated if PM is invoked with options, but without the name of a source file. If PM is invoked with no options and no source name, a brief help screen is displayed.

305 Unable to Write to File ‘Filename’ Indicates that DOS was unable to write to the specified file. This usually results when there is not enough space on the destination disk or the specified file has some special write protection (such as DOS SHARE.EXE).

306 Page Width must be 80 to 255 Columns The PAGE pseudo-op is used to specify the size of the listing page. The first parameter is used to specify the width of the page. This value must be between 80 and 255, inclusive.

307 Illegal Device Type An attempt was made to use an illegal specifier with the DEVICE statement. Such values would have 10 or 11 as the two most significant bits.

308 Macro Buffer Overflow An attempt was made to define a macro which was larger than 4K. This usually indicates a missing ENDM pseudo-op.

15. Internal Errors

These errors are not documented, because they should not occur. If they occur, technical support should be contacted and a copy of the code producing the error should be made available.

400 Attempt to Free Non-Allocated Memory [Pointer] 401 Attempt to Reference Non-Allocated Memory [Pointer] 402 Attempt to Pop Empty Symbol Table Stack 403 Attempt to Exit on Empty File Stack 404 Attempt to Pop Empty Macro Stack 405 Macro Stack Error 406 Attempt to Pop Empty Conditional Assembly Stack 407 No Function Handler for ‘Keyword’

Appendix C ©1996 microEngineering Labs C-33 PIC Macro Assembler Reference Notes C-34 ©1996 microEngineering Labs Parallax Instruction Set D Reference

Larry found that he learned a lot of instructions during his walk home ... as long as it didn’t rain.

Appendix D ©1998 Sirius microSystems D-1 Parallax Instruction Set Reference D-2 ©1998 Sirius microSystems Table of Contents

Microchip Instructions ...... D-7

Parallax Instructions ...... D-7 Introduction ...... D-7

Summary of Parallax Instructions ...... D-8 Byte-oriented Operations...... D-8 Bit-oriented operations ...... D-9 Inc/dec-conditional branches ...... D-9 Compare-conditional branches...... D-9 Bit-conditional branches ...... D-9 Unconditional branches ...... D-10 I/O and control operations ...... D-10

ADD...... D-11 ADD destination, source ...... D-11

ADDB ...... D-11 ADDB destination, bit ...... D-11

AND...... D-12 AND destination, source ...... D-12

Call...... D-13 Call addr...... D-13

Compare and Jump ...... D-13 Compare and jump if above ...... D-13 Compare and jump if above or equal ...... D-13 Compare and jump if Below ...... D-14 Compare and Jump if below or equal ...... D-14 Compare and jump if equal ...... D-15 Compare and jump if not equal ...... D-15

Clear Carry ...... D-16

Clear ...... D-16 CLR register/flag ...... D-16 Clear bit ...... D-16

Compare and Skip ...... D-17 Compare and skip if above ...... D-17 Compare and skip if above or equal ...... D-17 Appendix D ©1998 Sirius microSystems D-3 Parallax Instruction Set Reference Compare and skip if below ...... D-18 Compare and skip if below or equal ...... D-18 Compare and skip if equal ...... D-18 Compare and skip if not equal...... D-19

Decrement ...... D-19 Dec file register ...... D-19 Dec file register and skip if zero ...... D-19 Dec file register and jump if not zero ...... D-20

Increment ...... D-20 Increment file register and jump if not zero ...... D-20 Increment file register ...... D-20 Increment file register and skip if zero...... D-20

Jump ...... D-20 Jump if carry ...... D-20 Jump to addr ...... D-21 Jump PC + W ...... D-21 Jump W ...... D-21 Jump if not bit ...... D-21 Jump if not carry ...... D-21 Jump if not zero ...... D-21 Jump if zero ...... D-22

Long Instructions ...... D-22 Long Call ...... D-22 Long Jump ...... D-22 Long Set ...... D-22

Move ...... D-22 MOV destination, Source ...... D-22

Bit Move ...... D-25 MOVB Destination bit, Source bit ...... D-25

Move and Skip ...... D-26 Move and skip if zero ...... D-26

Negate ...... D-26

No Operation ...... D-26

Not ...... D-26 Not fr/W...... D-26

OR ...... D-27 Or Destination, Source ...... D-27 Table of Contents D-4 ©1998 Sirius microSystems Return ...... D-28 Return from subroutine ...... D-28 Return from interrupt...... D-28 Return with value in W...... D-28

Rotate ...... D-28

Skip ...... D-29

Set...... D-30 Set bit ...... D-30 Set Carry ...... D-30 Set Zero ...... D-30

Sleep ...... D-30

Subtract ...... D-30 Sub minuend,subtrahend ...... D-30

Subtract Bit ...... D-31

Swap Nibbles ...... D-31

Test ...... D-31

XOR ...... D-32 XOR Destination,Source ...... D-32

Appendix D ©1998 Sirius microSystems D-5 Parallax Instruction Set Reference Notes D-6 ©1998 Sirius microSystems Microchip Instructions

Microchip instructions are described in detail in the PIC16C8X data sheets be- ginning on pages 53.

Parallax Instructions

Introduction Early adopters of the PIC microcontroller were less than pleased with the PIC’s instruction set. While appropriate for a RISC architecture, it is somewhat cryptic and makes code unreadable. Parallax realized this when they decided to build PIC development tools. To overcome the problem, Parallax decided to build an 8051-like instruction set.

The Parallax intruction set has some advantages. Most notably, the instructions are more intuitive and generally allow programmers to write more readable code. It also has some disadvantages. First, each Parallax instruction expands to between 1 and 4 PIC instructions. This variable instruction length makes “cycle counting”difficult. Second, it is not always obvious from the Parallax instruction what it actually happening. Consider the intruction . While the in- struction does the obvious (setting the file register to themov literal fr,#lit value), it also has the less obvious side effect (setting the W register to the literal value). Such hidden side effects can make debugging difficult.

Recognizing that each instruction set has advantages and disadvantages, PM supports both. While the PIC instruction set is widely documented, the Parallax instruction set is not. That is the purpose of this supplement.

—From microEngineering Labs “PIC Macro Assembler Instruction Set Supplement © 1996 microEngineering Labs

The following example demostrates the syntax difference between Parallax in- structions and Microchip instructions. Parallax instructions follow the Intel conven- tion of listing the operands in sequentially reverse order:

Instruction Destination,Source whereas Microchip instructions take the form:

OpCode Operand,n Microchip instructions encode the Source in the Operand and specify the desti- nation as a bit (n) that can represent either the Operand if n=1 (the default), or the Working Register (W) if n=0.

We recommend that you examine both instruction sets. Work with the one you find the most comfortable to use, or the most intuitive.

All PIC-MDS example programs are provided in Micochip and Parallax code formats. Parallax code chapters have been printed on blue paper to distinguish them from the Microchip code chapters. Appendix D ©1998 Sirius microSystems D-7 Parallax Instruction Set Reference Summary of Parallax Instructions

Byte-oriented Operations

Words Flags W used mov w,#literal* 1 - - Move literal into w mov w,fr 1 Z - Move fr into w mov fr,w 1 - - Move w into fr mov fr,#literal 2 - W Move literal into fr mov fr1,fr2 2 Z W Move fr2 into fr1 mov w,#literal-w 1 C,DC,Z - Move literal-w into w mov w,fr-w‡ 1 C,DC,Z - Move fr-w into w

add w,#literal* 1 C,DC,Z - Add literal into w add w,fr 1 C,DC,Z - Add fr into w add fr,w 1 C,DC,Z - Add w into fr add fr,#literal 2 C,DC,Z W Add literal into fr add fr1,fr2 2 C,DC,Z W Add fr2 into fr1

sub fr,w 1 C,DC,Z - Subtract w from fr sub fr,#literal 2 C,DC,Z W Subtract literal from fr sub fr1,fr2 2 C,DC,Z W Subtract fr2 from fr1

and w,#literal 1 Z - AND literal into w and w,fr 1 Z - AND fr into w and fr,w 1 Z - AND w into fr and fr,#literal 2 Z W AND literal into fr and fr1,fr2 2 Z W AND fr2 into fr1

or w,#literal 1 Z - OR literal into w or w,fr 1 Z - OR fr into w or fr,w 1 Z - OR w into fr or fr,#literal 2 Z W OR literal into fr or fr1,fr2 2 Z W OR fr2 into fr1

xor w,#literal 1 Z - XOR literal into w xor w,fr 1 Z - XOR fr into w xor fr,w 1 Z - XOR w into fr xor fr,#literal 2 Z W XOR literal into fr xor fr1,fr2 2 Z W XOR fr2 into fr1

clr w 1 Z - Clear w clr fr 1 Z - Clear fr

mov w,++fr 1 Z - Move fr+1 into w inc fr 1 Z - Increment fr

mov w,—fr 1 Z - Move fr-1 into w

dec fr 1 Z - Decrement fr

mov w,>>fr 1 C - Move right-rotated fr into w rr fr 1 C - Rotate right fr

mov w,<

mov w,<>fr 1 - - Move nibble-swapped fr into w swap fr 1 - - Swap nibbles in fr

not w 1 Z - Perform 1’s-complement on w mov w,/fr 1 Z - Move 1’s-complemented fr into w not fr 1 Z - Perform 1’s-complement on fr

test w 1 Z - Test w for zero test fr 1 Z - Test fr for zero

Summary of Parallax Instructions D-8 ©1998 Sirius microSystems Bit-oriented operations

Words Flags W used addb fr,bit 2 Z - Add bit into fr subb fr,bit† 2 Z - Subtract bit from fr

clrb bit 1 - - Clear bit clc - - Clear carry clz 1 - - Clear zero

setb bit 1 - - Set bit stc 1 - - Set carry stz 1 - - Set zero

movb bit1,bit2 4 - - Move bit2 into bit1 movb bit1,/bit2 4 - - Move not bit2 into bit1

Inc/dec-conditional branches

movsz w,++fr 1 - - Move fr+1 into w and skip if zero incsz fr 1 - - Increment fr and skip if zero ijnz fr,addr 2 - - Increment fr and jump if not zero movsz w,—fr 1 - - Move fr-1 into w and skip if zero decsz fr 1 - - Decrement fr and skip if zero djnz fr,addr 2 - - Decrement fr and jump if not zero

Compare-conditional branches

csa fr,#literal 3 C,DC,Z W Compare and skip if above csa fr1,fr2 3 C,DC,Z W Compare and skip if above csae fr,#literal 3 C,DC,Z W Compare and skip if above or equal csae fr1,fr2 3 C,DC,Z W Compare and skip if above or equal csb fr,#literal 3 C,DC,Z W Compare and skip if below csb fr1,fr2 3 C,DC,Z W Compare and skip if below csbe fr,#literal 3 C,DC,Z W Compare and skip if below or equal csbe fr1,fr2 3 C,DC,Z W Compare and skip if below or equal cse fr,#literal 3 C,DC,Z W Compare and skip if equal cse fr1,fr2 3 C,DC,Z W Compare and skip if equal csne fr,#literal 3 C,DC,Z W Compare and skip if not equal csne fr1,fr2 3 C,DC,Z W Compare and skip if not equal

cja fr,#lit,addr 4 C,DC,Z W Compare and jump if above cja fr1,fr2,addr 4 C,DC,Z W Compare and jump if above cjae fr,#lit,addr 4 C,DC,Z W Compare and jump if above or equal cjae fr1,fr2,addr 4 C,DC,Z W Compare and jump if above or equal cjb fr,#lit,addr 4 C,DC,Z W Compare and jump if below cjb fr1,fr2,addr 4 C,DC,Z W Compare and jump if below cjbe fr,#lit,addr 4 C,DC,Z W Compare and jump if below or equal cjbe fr1,fr2,addr 4 C,DC,Z W Compare and jump if below or equal cje fr,#lit,addr 4 C,DC,Z W Compare and jump if equal cje fr1,fr2,addr 4 C,DC,Z W Compare and jump if equal cjne fr,#lit,addr 4 C,DC,Z W Compare and jump if not equal cjne fr1,fr2,addr 4 C,DC,Z W Compare and jump if not equal

Bit-conditional branches

sb bit 1 - - Skip if bit sc 1 - - Skip if carry sz 1 - - Skip if zero

snb bit 1 - - Skip if not bit snc 1 - - Skip if not carry snz 1 - - Skip if not zero Words Flags W used

Appendix D ©1998 Sirius microSystems D-9 Parallax Instruction Set Reference jb bit,addr 2 - - Jump to address if bit jc addr 2 - - Jump to address if carry jz addr 2 - - Jump to address if zero

jnb bit_addr,addr 2 - - Jump to address if not bit jnc addr 2 - - Jump to address if not carry jnz addr 2 - - Jump to address if not zero

Unconditional branches

skip 1 - - Skip following instruction word (Skip should be followed by a single word instruction)

jmp addr 1 - - Jump to address jmp pc+w 1 C,DC,Z - Add w into pcl jmp w 1 - - Move w into pcl

call add 1 - - Call to address ret 1 - - Return from call retw lit,lit... 1 - - Return from call with literal in w

reti 1 - - Return from interrupt

I/O and control operations

mov !port,w* 1 - - Move w into port’s tris mov !port,#lit* 2 - W Move literal into port’s tris mov !port,fr* 2 Z W Move fr into port_fr’s tris

mov !option,w* 1 - - Move w into option mov !option,#lit* 2 - W Move literal into option mov !option,fr* 2 Z W Move fr into option

clr wdt 1 TO,PD - Clear wdt and prescaler sleep 1 TO,PD - Clear wdt and enter sleep mode

1 - - No operation

* Applies to PIC16C71 and PIC16C84 only † PM implementation differs from Parallax ‡ Not implemented by PM

Source & Destination Descriptions: fr & frn represent one of the PIC File Registers (see Chaper 3) w represents the Working Register #literal is an 8-bit numeric constant bit corresponds to a bit in a file register and can also be represented as fr,n where n (from 0-7) represents the nth bit of file register fr addr can be a memory address or address label

Summary of Parallax Instructions D-10 ©1998 Sirius microSystems ADD

ADD destination, source Destination = Destination + Source. Destination may be W or a file register. Source may be W, a file register or a literal (all literals must have a # sign as their first char).

ADD fr,#literal Reg./Flags affected: W,C,DC,Z Words: 2 Add literal into fr. Translates to: Cycles: 2

movlw literal ;W=literal addwf fr1 ;fr=fr+W Note: Although not explicitly referenced, modifies W. ADD fr,#literal

ADD fr1,fr2 Reg./Flags affected: W,C,DC,Z Add fr2 into fr1. Translates to: Words: 2 Cycles: 2

movf fr2,0 ;W=fr2 addwf fr1 ;fr1=fr1+W Note: Although not explicitly referenced, modifies W. ADD fr1,fr2

ADD fr,W Reg./Flags affected: C,DC,Z Add W into fr. Translates to: Words: 1 Cycles: 1

addwf fr ;W=W+fr

ADD W,#literal Reg./Flags affected: W,C,DC,Z Add literal into W. Translates to: Words: 1 Cycles: 1

addlw literal ;W=W+literal

ADD W,fr Reg./Flags affected: W,C,DC,Z Add fr into W. Translates to: Words: 1 Cycles: 1

addwf fr,0 ;W=W+fr

ADDB

ADDB destination, bit If bit = 1, destination = destination + 1. If bit = 0, destination = destination + 0. Destination must be a file register.

Reg./Flags affected: Z ADDB fr,bit Words: 2 Translates to: Cycles: 2

btfsc bit ;if bit=0,PC=PC+2 incf fr ;fr=fr+1 Appendix D ©1998 Sirius microSystems D-11 Parallax Instruction Set Reference AND

AND destination, source

Destination=logical and with source. Destination may be fr or W. Source may fr, W or literal (precede literal with a # sign).

Reg./Flags affected: W,Z AND fr,#literal Words: 2 AND literal into file register. Cycles: 2 Translates to:

movlw literal ;W=literal andwf fr ;fr=fr&W Usefull for masking out or including desired bits. For example, to isolate the bottom three bits in a file register AND the file register with #07h. Eg.

fr = 55h 01010101 and fr, #07h and 00000111 results in fr = 5h 00000101 Note: Although not explicitly referenced, modifies W. and fr,#literal

AND fr1,fr2 Reg./Flags affected: W,Z Words: 2 And fr2 into fr1. Translates to: Cycles: 2

movf fr2,0 ;W = fr2 andwf fr1 ;fr1 = W and fr2 Note: Although not explicitly referenced, modifies W. and fr,fr2 Reg./Flags affected: Z AND fr,W Words: 1 And W into fr. Translates to: Cycles: 1

andwf fr ;fr=fr&W

Reg./Flags affected: W,Z AND W,#literal Words: 1 And literal into W. Translates to: Cycles: 1

andlw literal ;W=W&literal Reg./Flags affected: W,Z AND W,fr Words: 1 And fr into W. Translates to: Cycles: 1

andwf fr,0 ;W=W&fr

D-12 ©1998 Sirius microSystems Call

Call addr Calls the subroutine located at address location specified by label addr. Execu- tion will continue at subroutine location until a return instruction executes. After return execution continues at the intstruction after the CALL.

Reg./Flags affected: none CALL addr Words: 1 Call Subroutine. Translates to: Cycles: 2

call addr ;push PC:PC=addr Compare and Jump

Compare and jump if above

CJA fr,#literal,addr Reg./Flags affected: W,C,DC,Z Compare fr to literal and jump if above. Words: 4 Translates to: Cycles: 4(5 if jump)

movf fr1,0 ;W=fr1 subwf, fr2,0 ;W=fr2-W btfsc C ;if fr<=literal, PC=PC+2 goto addr ;pc=addr Note: Although not explicitly referenced, modifies W. CJA fr,#literal,addr

CJA fr1,fr2,addr Reg./Flags affected: W,C,DC,Z Compare fr1 to fr2 and jump if above Words: 4 to addr. Translates to: Cycles: 4(5 if jump)

movf fr1,0 ;W=fr1 subwf, fr2,0 ;W=fr2-W btfss C ;if fr1<=fr2, PC=PC+2 goto addr ;pc=addr Note: Although not explicitly referenced, modifies W. CJA fr1,fr2,addr

Compare and jump if above or equal

Reg./Flags affected: W,C,DC,Z CJAE fr,#literal,addr Words: 4 Compare fr to literal and jumps if above Cycles: 4(5 if jump) or equal to addr. Translates to:

movlw literal ;W=literal subwf, fr,0 ;W=fr-W btfsc C ;if fr

Appendix D ©1998 Sirius microSystems D-13 Parallax Instruction Set Reference Reg./Flags affected: W,C,DC,Z CJAE fr1,fr2,addr Words: 4 Compare fr1 to fr2 and jumps if above Cycles: 4(5 if jump) or equal to addr. Translates to:

movf fr2,0 ;W=fr2 subwf, fr1,0 ;W=fr1-W btfsc C ;if fr1

Compare and jump if Below

Reg./Flags affected: W,C,DC,Z CJB fr1,#literal,addr Words: 4 Compare fr1 to literal and jump if below Cycles: 4(5 if jump) to addr. Translates to:

movlw literal ;W=literal subwf, fr,0 ;W=fr-W btfss C ;if fr>=literal, PC=PC+2 goto addr ;pc=addr Note: Although not explicitly referenced, modifies W. CJB fr1,#literal,addr Reg./Flags affected: W,C,DC,Z CJB fr1,fr2,addr Words: 4 Compare fr1 to fr2 and jump if below Cycles: 4(5 if jump) to addr. Translates to:

movf fr2,0 ;W=literal subwf, fr1,0 ;W=fr1-W btfss C ;if fr>=fr2, PC=PC+2 goto addr ;pc=addr Note: Although not explicitly referenced, modifies W. CJB fr1,fr2,addr

Compare and Jump if below or equal

Reg./Flags affected: W,C,DC,Z CJBE fr,#literal,addr Words: 4 Compare fr1 to literal and jump if below Cycles: 4(5 if jump) or equal to addr. Translates to:

movlw ~literal;W=~literal addwf fr,0 ;W=fr+W btfss C ;if fr> literal, PC=PC+2 goto addr ;pc=addr Note: Although not explicitly referenced, modifies W. CJBE fr,#literal,addr

D-14 ©1998 Sirius microSystems Reg./Flags affected: W,C,DC,Z CJBE fr1,fr2,addr Words: 4 Compare fr1 to fr2 and jump if below Cycles: 4(5 if jump) or equal to addr. Translates to:

movf fr1,0 ;W=fr1 subwf, fr2,0 ;W=fr2-W btfsc C ;if fr>=fr2, PC=PC+2 goto addr ;pc=addr Note: Although not explicitly referenced, modifies W. CJBE fr1,fr2,addr

Compare and jump if equal

CJE fr,#literal,addr Reg./Flags affected: W,C,DC,Z Compare fr to literal and jump if equal Words: 4 to addr. Translates to: Cycles: 4(5 if jump)

movlw literal ;W=literal subwf, fr,0 ;W=fr-W btfsc Z ;if fr<>literal, PC=PC+2 goto addr ;pc=addr Note: Although not explicitly referenced, modifies W. CJE fr1,#literal,addr

CJE fr1,fr2,addr Reg./Flags affected: W,C,DC,Z Compare fr1 to fr2 and jump if equal Words: 4 to addr. Translates to: Cycles: 4(5 if jump)

movf fr2,0 ;W=literal subwf, fr1,0 ;W=fr1-W btfsc Z ;if fr<>fr2, PC=PC+2 goto addr ;pc=addr Note: Although not explicitly referenced, modifies W. CJE fr1,fr2,addr

Compare and jump if not equal

Reg./Flags affected: W,C,DC,Z CJNE fr,#literal Words: 4 Compare fr to literal and jump if not equal Cycles: 4(5 if jump) to addr. Translates to:

movlw literal ;W=literal subwf, fr,0 ;W=fr-W btfss Z ;if fr=literal, PC=PC+2 goto addr ;pc=addr Note: Although not explicitly referenced, modifies W. CJNE fr,#literal,addr

Appendix D ©1998 Sirius microSystems D-15 Parallax Instruction Set Reference CJNE fr1,fr2,addr Reg./Flags affected: W,C,DC,Z Compare fr1 to fr2 and jump if equal Words: 4 to addr. Translates to: Cycles: 4(5 if jump)

movf fr2,0 ;W=literal subwf, fr1,0 ;W=fr1-W btfsc Z ;if fr1=fr2, PC=PC+2 goto addr ;pc=addr Note: Although not explicitly referenced, modifies W. CJNE fr1,fr2,addr

Clear Carry

CLC Reg./Flags affected: C Clears the carry flag. Translates to: Words: 1 Cycles: 1

bcf C ;C=0

Clear

CLR register/flag Register/flag = 0. Clears the specified register or flag.

CLR fr Reg./Flags affected: Z Clears fr. Translates to: Words: 1 Cycles: 1

clrf fr ;fr=0

Reg./Flags affected: Z CLR W Words: 1 Clears the working register. Cycles: 1 Translates to:

clrw ;W=0

CLR WDT Reg./Flags affected: T0,PD Clears the watchdog timer Words: 1 Translates to: Cycles: 1

clrwdt ;reset WDT

Clear bit

Reg./Flags affected: none CLRB bit Words: 1 Clears the specified bit. Cycles: 1 Translates to:

bcf bit ;bit=0

D-16 ©1998 Sirius microSystems CLZ Reg./Flags affected: none Clears the zero flag. Words: 1 Translates to: Cycles: 1

bcf Z

Compare and Skip

Compare and skip if above

CSA fr,#literal Reg./Flags affected: W,C,DC,Z Compare fr to literal and skip next Words: 3 instruction if above.Translates to: Cycles: 3 (4 if skip)

movlw ~lit ;W=~literal addwf fr,W ;W=W+fr btfss C ;If fr>literal, PC=PC+2 Note: Although not explicitly referenced, modifies W. CSA fr,#literal,addr

CSA fr1,fr2 Reg./Flags affected: W,C,DC,Z Compare fr1 to fr2 and skip next Words: 3 instruction if above.Translates to: Cycles: 3 (4 if skip)

movf fr,0 ;W=~fr1 subwf fr2,0 ;W=fr2-W btfsc C ;If fr1>fr2, PC=PC+2 Note: Although not explicitly referenced, modifies W. CSA fr1,fr2,addr

Compare and skip if above or equal Reg./Flags affected: W,C,DC,Z CSAE fr,#literal Words: 3 Compare fr to literal and skip next Cycles: 3 (4 if skip) instruction if above or equal .Translates to:

movlw lit ;W=literal subwf fr,0 ;W=W-fr btfss C ;If fr>=literal, PC=PC+2 Note: Although not explicitly referenced, modifies W. CSAE fr,#literal,addr Reg./Flags affected: W,C,DC,Z CSAE fr1,fr2 Words: 3 Compare fr1 to fr2 and skip next Cycles: 3 (4 if skip) instruction if above or equal.Translates to:

movf fr1,0 ;W=fr2 subwf fr1,0 ;W=fr1-W btfsc C ;If fr1>=fr2, PC=PC+2 Note: Although not explicitly referenced, modifies W. CSAE fr1,fr2,addr

Appendix D ©1998 Sirius microSystems D-17 Parallax Instruction Set Reference Compare and skip if below Reg./Flags affected: W,C,DC,Z CSB fr,#literal Compare fr to literal and skip next Words: 3 instruction if below. Translates to: Cycles: 3 (4 if skip)

movlw lit ;W=literal subwf fr,0 ;W=fr-W btfsc C ;If fr

movf fr2,0 ;W=~fr2 subwf fr1,0 ;W=fr1-W btfsc C ;If fr1

CSBE fr,#literal Reg./Flags affected: W,C,DC,Z Compare fr to literal and skip next Words: 3 instruction if below or equal. Translates to: Cycles: 3 (4 if skip)

movlw ~lit ;W=~literal addwf fr,0 ;W=W+fr btfsc C ;If fr<=literal, PC=PC+2 Note: Although not explicitly referenced, modifies W. CSBE fr,#literal,addr

CSBE fr1,fr2 Reg./Flags affected: W,C,DC,Z Compare fr1 to fr2 and skip next Words: 3 instruction if below or equal. Translates to: Cycles: 3 (4 if skip)

movf fr1,0 ;W=~fr1 subwf fr2,0 ;W=fr2-W btfss C ;If fr1<=fr2, PC=PC+2 Note: Although not explicitly referenced, modifies W. CSBE fr1,fr2,addr Compare and skip if equal Reg./Flags affected: W,C,DC,Z CSE fr,#literal Words: 3 Compare fr to literal and skip next Cycles: 3 (4 if skip) instruction if equal. Translates to:

movlw lit ;W=literal subwf fr,0 ;W=W-fr btfss C ;If fr=literal, PC=PC+2 Note: Although not explicitly referenced, modifies W. CSBE fr,#literal,addr

D-18 ©1998 Sirius microSystems CSE fr1,fr2 Reg./Flags affected: W,C,DC,Z Compare fr1 to fr2 and skip next Words: 3 instruction if equal. Translates to: Cycles: 3 (4 if skip)

movf fr2,0 ;W=fr2 subwf fr1,0 ;W=fr1-W btfss C ;If fr1=fr2, PC=PC+2 Note: Although not explicitly referenced, modifies W. CSE fr1,fr2,addr Compare and skip if not equal

CSNE fr,#literal Reg./Flags affected: W,C,DC,Z Compare fr to literal and skip next Words: 3 instruction if equal. Translates to: Cycles: 3 (4 if skip)

movlw lit ;W=literal subwf fr,0 ;W=fr-W btfsc C ;If fr<>literal, PC=PC+2 Note: Although not explicitly referenced, modifies W. CSBE fr,#literal,addr Reg./Flags affected: W,C,DC,Z CSNE fr1,fr2 Compare fr1 to fr2 and skip next Words: 3 instruction if equal. Translates to: Cycles: 3 (4 if skip)

movf fr2,0 ;W=fr2 subwf fr1,0 ;W=fr1-W btfss C ;If fr1<>fr2, PC=PC+2 Note: Although not explicitly referenced, modifies W. CSNE fr1,fr2,addr

Decrement

Dec file register

DEC fr Reg./Flags affected: Z Fr=fr-1. Decrements the specified Words: 1 file register. Translates to: Cycles: 1

decf fr ;fr=fr-1 Dec file register and skip if zero Reg./Flags affected: none DECSZ fr Words: 1 Decrement the specified file register and Cycles: 1 (2 if skip) skip next instruction if zero results. Translates to:

decfsz fr ;fr=fr-1:if 0,PC=PC+2

Appendix D ©1998 Sirius microSystems D-19 Parallax Instruction Set Reference Dec file register and jump if not zero Reg./Flags affected: none DJNZ fr,addr Decrement the specified file register and Words: 2 jump to addr if result is not zero. Cycles: 2(3 if jump) Translates to:

decfsz fr ;fr=fr-1:If 0,PC=PC+2 goto addr ;PC=addr Increment

Increment file register and jump if not zero Reg./Flags affected: none IJNZ fr,addr fr=fr+1. Increments the specified Words: 2 file register and jump to addr if result Cycles: 2(3 if jump) is not zero. Translates to:

incfsz fr ;fr==fr+1: If 0,PC=PC+2 goto addr ;PC=addr

Increment file register

INC fr Reg./Flags affected: Z Increment the specified file register. Words: 1 Translates to: Cycles: 1

incf fr ;fr=fr+1 Increment file register and skip if zero

INCSZ fr Reg./Flags affected: none fr=fr+1. Increments the specified Words: 1 file register and skips next instruction if Cycles: 1 (2 if skip) result is zero. Translates to:

incfsz fr ;fr=fr+1: If 0,PC=PC+2

Jump

Jump if carry

JC addr Reg./Flags affected: none Jump if carry bit set to addr. Words: 1 Translates to: Cycles: 1 (2 if skip)

btfsc C ;IF C=0,PC=PC+2 goto addr ;PC=addr

D-20 ©1998 Sirius microSystems Jump to addr Reg./Flags affected: none JMP addr Words: 1 Jump to address. Cycles: 2 Translates to:

goto addr ;PC=addr Jump PC + W Reg./Flags affected: C,DC,Z JMP PC+W Words: 1 Skips W+1 instructions. Cycles: 2 Translates to:

addwf PCL ;PC=PC+W+1 Jump W Reg./Flags affected: none JMP W Words: 1 Jump to W. Cycles: 2 Translates to:

movwf PCL ;PC=(PCLATH<<8)+W Jump if not bit

JNB bit,addr Reg./Flags affected: none Jump if bit equals 0 to addr. Words: 2 Translates to: Cycles: 2(3 if jump)

btfss bit ;If bit=1,PC=PC+2 goto addr ;PC=addr

Jump if not carry

JNC addr Reg./Flags affected: none Jump if carry equals 0 to addr. Words: 2 Translates to: Cycles: 2(3 if jump)

btfss C ;If C=1,PC=PC+2 goto addr ;PC=addr

Jump if not zero Reg./Flags affected: none JNZ addr Words: 2 Jump if Z flag equals 0 to addr. Cycles: 2(3 if jump) Translates to:

btfss Z ;If Z=1, PC=PC+1 goto addr ;PC=addr

Appendix D ©1998 Sirius microSystems D-21 Parallax Instruction Set Reference Jump if zero Reg./Flags affected: none JZ addr Words: 2 Jump if Z flag equals 1 to addr. Cycles: 2(3 if jump) Translates to:

btfsc Z ;If Z=0.PC=PC+2 goto addr ;PC=addr Long Instructions

Long Call

Reg./Flags affected: none LCALL addr Words: 1-3 Perfroms a long call. Cycles: 2-4

[bcf/bsf PCLTH.4] ;set if 8k code [bcf/bsf PCLTH.3] ;set if 4k or 8k code call addr Long Jump

LJMP addr Reg./Flags affected: none Performs a long jump. Words: 1-3 Cycles: 2-4

[bcf/bsf PCLTH.4] ;set if 8k code [bcf/bsf PCLTH.3] ;set if 4k or 8k code goto addr ;Push PC: PC=addr Long Set

LSET addr Reg./Flags affected: none Perfroms a long set. Words: 1-3 Cycles: 2-4

[bcf/bsf PCLTH.4] ;set if 8k code [bcf/bsf PCLTH.3] ;set if 4k or 8k code Move

MOV destination, Source Moves the source into the destination. Source may be a file register or register. Destination is a file register.

MOV fr,#literal Reg./Flags affected: W Move literal into file register. Words: 2 Translates to: Cycles: 2

movlw literal ;W=literal movwf fr ;fr=W Note: Although not explicitly referenced, modifies W. MOV fr,#literal

D-22 ©1998 Sirius microSystems Reg./Flags affected: W,Z MOV fr1,fr2 Words: 2 Move fr2 into fr1. Cycles: 2 Translates to:

movf fr2,0 ;W=fr2 movwf fr1 ;fr1=W Note: Although not explicitly referenced, modifies W. MOV fr1,fr2 Reg./Flags affected: none MOV fr,W Move W into fr. Words: 1 Translates to: Cycles: 1

movwf fr ;fr=W

Reg./Flags affected: W MOV OPTION,#literal Words: 2 Move literal into OPTION register. Cycles: 2 Translates to:

movlw literal ;W=literal option ;OPTION=W Note: Although not explicitly referenced, modifies W. Microchip recommends that the OPTION instructionMOV notOPTION,#literal be used if upwards compatabilty with future PIC16CXX products is desired.

Reg./Flags affected: W,Z MOV OPTION,fr Words: 2 Move fr into OPTION register. Cycles: 2 Translates to:

movf fr,0 ;W=fr option ;OPTION=W Note: Although not explicitly referenced, modifies W. Microchip recommends that the OPTION instruction notMOV be OPTION,frused if upwards compatabilty with future PIC16CXX products is desired.

Reg./Flags affected: none MOV OPTION,W Words: 1 Move W into OPTION register. Cycles: 1 Translates to:

option Note: Microchip recommends that the OPTION instruction not be used if upwards compatabilty with future PIC16CXX products is desired.

Appendix D ©1998 Sirius microSystems D-23 Parallax Instruction Set Reference MOV !fr,#literal Reg./Flags affected: W Move literal into fr’s TRIS register. Words: 2 Translates to: Cycles: 2

movlw literal ;W=literal tris fr ;TRIS(fr)=W Note: Although not explicitly referenced, modifies W. Micro- chip recommends that the TRIS instruction notMOV be !fr,#literal used if upwards compatabilty with future PIC16CXX products is desired.

Reg./Flags affected: W,Z MOV !fr1,fr2 Words: 2 Move fr2 into fr’s TRIS register. Cycles: 2 Translates to:

movf fr2,0 ;W=fr2 tris fr1 ;TRIS(fr1)=W Note: Although not explicitly referenced, modifies W. Microchip recommends that the TRIS instruction not be usedMOV if!fr1,fr2 upwards compatabilty with future PIC16CXX products is desired.

MOV !fr,W Reg./Flags affected: W Move W into fr’s TRIS register. Words: 1 Translates to: Cycles: 1

tris fr ;TRIS(fr)=W Note: Microchip recommends that the TRIS instruction not be used if upwards compatabilty with future PIC16CXX products is desired.

Reg./Flags affected: W MOV W,#literal Words: 1 Move literal into W register. Cycles: 1 Translates to:

movlw literal ;W=literal

MOV W,fr Reg./Flags affected: W,Z Move fr into W register. Words: 1 Translates to: Cycles: 1

movf fr,0 ;W=fr

Reg./Flags affected: W,Z MOV W,/fr Words: 1 Move complement of fr into W register. Cycles: 1 Translates to:

comf fr,0 ;W=~fr

D-24 ©1998 Sirius microSystems MOV W,fr-W Reg./Flags affected: W,C,DC,Z Move fr-W into W register. Words: 1 Translates to: Cycles: 1

subwf fr,0 ;W=fr-W

Note: Not supported by PM.

MOV W,++fr Reg./Flags affected: W,Z Move fr+1 into W register. Words: 1 Translates to: Cycles: 1

incf fr,0 ;W=fr+1 Reg./Flags affected: W,Z MOV W,--fr Words: 1 Move fr-1 into W register. Cycles: 1 Translates to:

decf fr,0 ;W=fr-1 Reg./Flags affected: W,C MOV W,<

rlf fr,0 ;C=fr.7:W=(fr<<1)|C

Reg./Flags affected: W,C MOV W,>>fr Move value of fr rotated right through Words: 1 carry into W register. Translates to: Cycles: 1

rrf fr,0 ;C=fr.7:W=(fr>>1)|C

MOV W,<>fr Reg./Flags affected: W Move swapped nibbles of fr into W. Words: 1 Translates to: Cycles: 1

swapf fr,0 ;W=fr[3..0]|fr[7..4] Bit Move

MOVB Destination bit, Source bit

MOVB Bit1,Bit2 Reg./Flags affected: none Move bit2 into bit1. Translates to: Words: 4 Cycles: 4

btfss bit2 ;if bit2=1, pc=pc+2 bcf bit1 ;bit1=0 btfsc bit2 ;if bit2=0, pc=pc+2 bsf bit1 ;bit1=1

Appendix D ©1998 Sirius microSystems D-25 Parallax Instruction Set Reference MOVB Bit1,/Bit2 Reg./Flags affected: none Move complement of bit2 into bit1. Words: 4 Translates to: Cycles: 4

btfsc bit2 ;if bit2=0, pc=pc+2 bcf bit1 ;bit1=0 btfss bit2 ;if bit2=1, pc=pc+2 bsf bit1 ;bit1=1 Move and Skip

Move and skip if zero

MOVSZ W,++fr Reg./Flags affected: W Move fr+1 into W and skip if zero. Words: 1 Translates to: Cycles: 1

incfsz fr,0 ;W=fr+1:if 0,PC=PC+2

MOVSZ W,--fr Reg./Flags affected: W Move fr-1 into W and skip if zero. Words: 1 Translates to: Cycles: 1

decfsz fr,0 ;W=fr-1:if 0,PC=PC+2 Negate

NEG fr Reg./Flags affected: Z Negates fr. Translates to: Words: 2 Cycles: 2 comf fr ;fr=~fr incf fr ;fr=fr+1 No Operation

NOP Reg./Flags affected: none No operation. Translates to: Words: 1 Cycles: 1 nop ;do nothing for one machine cycle Not

Not fr/W Complement file or working register.

NOT fr Reg./Flags affected: Z Words: 1 Complements file register specified. Cycles: 1 Translates to:

comf fr ;fr=~fr

D-26 ©1998 Sirius microSystems NOT W Reg./Flags affected: Z Words: 1 Complements working register. Cycles: 1 Translates to:

xorlw 0ffh ;W=W XOR FFh = ~W OR

Or Destination, Source Source is ORed with Destination. Destination may be file or working register. Source may be file or working register or a literal.

Reg./Flags affected: W,Z OR fr,#literal Words: 2 OR literal into fr. Cycles: 2 Translates to:

movlw literal ;W=literal iorwfr fr

OR fr1,fr2 Reg./Flags affected: W,Z OR fr2 into fr1. Words: 2 Translates to: Cycles: 2

movf fr2,0 ;W=fr2 iorwf fr1 ;fr1=fr1 OR W

OR fr,W Reg./Flags affected: Z OR W into fr. Words: 1 Translates to: Cycles: 1

iorwf fr ;fr=fr OR W

OR W,#literal Reg./Flags affected: W,Z OR literal into W Words: 1 Translates to: Cycles: 1

iorlw literal ;W=W OR literal

OR W,fr Reg./Flags affected: W,Z OR fr into W. Words: 1 Translates to: Cycles: 1

iorwf fr,0 W=W OR fr

Appendix D ©1998 Sirius microSystems D-27 Parallax Instruction Set Reference Return

Return from subroutine

RET Reg./Flags affected: none Return from subroutine. Pops the value Words: 1 off the stack and places the value into Cycles: 2 the program counter. Translates to: (12 bit core)

retlw 0 ;W=0: Pop PC Translates to: (14 bit core)

return ;Pop PC

Return from interrupt

RETI Reg./Flags affected: none Return from interrupt subroutine. Pops the Words: 1 value off the stack and places the value Cycles: 2 into the program counter. GIE bit is set enabling interrupts. Translates to: (14 bit core only)

retfie ;Pop PC: Set GIE Return with value in W

RETW #literal,#literal,... Reg./Flags affected: W Return from subroutine with value(s) in Words: 1 - many W. Pops the value off the stack and Cycles: 2 per literal places the value into the program counter. Translates to:

retlw literal1 ;Pop PC: W=literal1 retlw literal2 ;Pop PC: W=literal2 ... Rotate

Reg./Flags affected: C RL fr Rotate fr left through carry. Words: 1 Translates to: Cycles: 1

rlf fr ;C=fr.7:fr=(fr<<1)|C

RR fr Reg./Flags affected: C Rotate fr right through carry. Words: 1 Translates to: Cycles: 1

rrf fr ;C=fr.7:fr=(fr>>1)|C

D-28 ©1998 Sirius microSystems Skip

SB Bit Reg./Flags affected: none Skip next instruction if bit set. Words: 1 Translates to: Cycles: 1 (2 if skip)

btfss bit ;if bit=0,PC=PC+2

SC Reg./Flags affected: none Skip next instruction if Carry flag set. Words: 1 Translates to: Cycles: 1 (2 if skip)

btfss C ;if C=0,PC=PC+2

SKIP Reg./Flags affected: none Skip next instruction. Words: 1 Translates to: Cycles: 2

btfss 4,7

SNB bit Reg./Flags affected: none Skip next instruction if not bit. Words: 1 Translates to: Cycles: 1 (2 if skip)

btfsc bit ;if bit=0,PC=PC+2

Reg./Flags affected: none SNC C Skip next instruction if not Carry. Words: 1 Translates to: Cycles: 1(2 if skip)

btfsc C ;if C=0,PC=PC+2

SNZ bit Reg./Flags affected: none Skip next instruction if not Carry. Words: 1 Translates to: Cycles: 1(2 if skip)

btfsc Z ;if C=0,PC=PC+2

Reg./Flags affected: none SZ Words: 1 Skip next instruction if zero. Cycles: 1(2 if skip) Translates to:

btfss Z ;if Z=0,PC=PC+2

Appendix D ©1998 Sirius microSystems D-29 Parallax Instruction Set Reference Set

Set bit

SETB Bit Reg./Flags affected: none Bit = 1. Sets the specified bit. Words: 1 Translates to: Cycles: 1

bsf bit ;bit=1

Set Carry

Reg./Flags affected: C STC Words: 1 Set carry flag. Cycles: 1 Translates to:

Set Zerobsf C ;C=1

STZ Reg./Flags affected: Z Set zero flag. Words: 1 Translates to: Cycles: 1

bsf Z ;Z=1 Sleep

Reg./Flags affected: TO,PD SLEEP Words: 1 Enter sleep mode. Cycles: 1 Translates to:

sleep ;Enter low power mode Subtract

Sub minuend,subtrahend Subtracts the subtrahend from the minuend. Minuend must be a file register. Subtrahend may be a file or working register or a literal.

SUB fr,#literal Reg./Flags affected: W,C,DC,Z Subtracts literal from fr. Words: 2 Translates to: Cycles: 2

movlw literal ;W=literal subwf fr ;fr=fr-W Note: Although not explicitly referenced, modifies W SUB fr,#literal

D-30 ©1998 Sirius microSystems Reg./Flags affected: W,C,DC,Z SUB fr1,fr2 Words: 2 Subtracts fr2from fr1. Cycles: 2 Translates to:

movf fr2,0 ;W=fr2 subwf fr1 ;fr1=fr1-W Note: Although not explicitly referenced, modifies W. SUB fr1,fr2

Reg./Flags affected: C,DC,Z SUB fr,W Subtracts W from fr. Words: 2 Translates to: Cycles: 2

subwf fr ;fr=fr-W Subtract Bit

SUBB fr,bit Reg./Flags affected: Z (If bit 1) Subtracts bit from fr. Words: 2 Translates to: Cycles: 2

btfsc bit decf fr

Swap Nibbles

Reg./Flags affected: none SWAP fr Words: 1 Swaps nibbles in fr. Cycles: 1 Translates to:

swap fr ;fr[3..0]|fr7..4]

Test

TEST fr Reg./Flags affected: Z Tests fr for zero. Words: 1 Translates to: Cycles: 1

movf fr ;if fr=0,Z=1 Else Z=0

Appendix D ©1998 Sirius microSystems D-31 Parallax Instruction Set Reference XOR

XOR Destination,Source Exclusive ORs destination with source. Destination may be the working register or a file register. Source may be a literal, working or file register.

Reg./Flags affected: W,Z XOR fr,#literal Words: 2 Exclusive OR literal into fr. Cycles: 2 Translates to:

movlw literal ;W=literal xorwf fr ;fr=fr XOR W

Note: Although not explicitly referenced, modifies W. XOR fr,#literal

XOR fr1,fr2 Reg./Flags affected: W,Z Exclusive OR fr2 into fr1. Words: 2 Translates to: Cycles: 2

movf fr2,0 ;W=fr2 xorwf fr1 ;fr1=fr1 XOR W

Reg./Flags affected: Z XOR fr,W Words: 1 Exclusive OR W into fr. Cycles: 1 Translates to:

xorwf fr ;fr=fr XOR W

Reg./Flags affected: W,Z XOR W,#literal Words: 1 Exclusive OR literal into W. Cycles: 1 Translates to:

xorlw literal ;W=W XOR literal

Reg./Flags affected: W,Z XOR W,fr Words: 1 Exclusive OR fr into W. Cycles: 1 Translates to:

xorwf fr,0 ;W=W XOR fr

D-32 ©1998 Sirius microSystems Program Pull-Out References Microchip Code

While we can’t promise a solution to all your problems, we do give you a good start!

Program Pull-Out ©1998 Sirius microSystems Microchip Code 1 References Copyright © 1996, 1998 Sirius microSystems. All rights reserved.

Second Printing.

Parallax is a Trademark of Parallax, Inc. PICmicro™ is a Registered Trademark of Microchip Technology Inc. in the U.S.A. and other countries.

No part of this publication may be reproduced, stored in a retrieval system, or transmitted, in any form or by any means, mechanical, electronic, photocopying, or recording, or otherwise, without the prior written permission of Sirius microSystems.

Sirius microSystems has taken care to trace ownership of copyright material contained in this text. However, Sirius microSystems will gladly accept any information that enables them to rectify any reference or credit in subsequent editions.

For conditions, permissions and other rights under this copyright, contact Sirius microSystems:

Sirius microSystems 172 Harvard Road Waterloo, ON N2J 3V3 Canada tel.: 519.886.4462 fax: 519.886.4253 http://www.siriusmicro.com

ISBN 0-9681220-0-0 (Training Manual) ISBN 0-9681220-1-9 (Teacher’s Reference)

Disclaimer of Liability This manual and the program subroutines included herein are written for the Sirius microSystems PICmicro™ Development System and are provided on an “as is” basis, without any warranty, either expressed or implied. These materials are provided for educational use only, and Sirius microSystems does not assume any liability for damages, either incidental or consequential, arising out of the application, use, or misuse of any of its software or hardware products. Sirius microSystems reserves the right, without further notice, to make changes to any of its training materials, software or hardware referred to in this manual in order to improve its function, design or reliability.

Printed in Canada.

2 Microchip Code ©1998 Sirius microSystems Contents

PIC-MDS Subroutine Library Summary...... 5 ATOD.LIB ...... 5 BIN2BCD.LIB ...... 5 BIN2DEC.LIB ...... 6 DEC2BIN.LIB ...... 6 EEPROM.LIB ...... 6 KEYPAD.LIB ...... 7 LCD.LIB ...... 7 LCD4BIT.LIB...... 7 RS232RX.LIB ...... 8 RS232TX.LIB ...... 8 SEEPROM.LIB ...... 9

Subroutine Library Files ATOD.LIB - PIC16C711 A/D Subroutine Library ...... 11 BIN2BCD.LIB - Binary to BCD Conversion Library ...... 13 BIN2DEC.LIB - Binary to Decimal Conversion Library ...... 15 DEC2BIN.LIB - Decimal to Binary Conversion Library ...... 16 EEPROM.LIB - PIC16F84 EEPROM Subroutine Library ...... 17 KEYPAD.LIB - Keypad Subroutine Library ...... 19 LCD.LIB - LCD Subroutine Library ...... 21 LCD4BIT.LIB - 4-bit Interface LCD Subroutine Library...... 24 LCD71.LIB - PIC16C71/711 LCD Subroutine Library...... 28 RS232RX.LIB - RS-232 Receive Subroutine Library ...... 31 RS232TX.LIB - RS-232 Transmit Subroutine Library ...... 34 SEEPROM.LIB - Serial EEPROM Subroutine Library ...... 37

Chapter Example Program Files ALARM.ASM - Chapter 9 Example Program ...... 43 ASCII.ASM - Chapter 12 Example Program ...... 45 BLIP.ASM - Chapter 8 Example Program ...... 49 BOUNCE.ASM - Chapter 9 Example Program ...... 51 CLOCK.ASM - Chapter 11 Example Program...... 53 COUNT.ASM - Chapter 8 Example Program ...... 58 CUSTOM.ASM - Chapter 12 Example Program ...... 59 DBOUNCE.ASM - Chapter 9 Example Program ...... 63 DELAY.ASM - Chapter 8 Example Program...... 65 KEY.ASM - Chapter 10 Example Program ...... 66 KEYINT.ASM - Chapter 11 Example Program ...... 69 KEYSCAN.ASM - Chapter 9 Example Program...... 73 KEYSCLB.ASM - Chapter 10 Example Program ...... 76 NVMEM.ASM - Chapter 13 Example Program ...... 79 OUTPUT.ASM - Chapter 5 Example Program ...... 84 RECV232.ASM - Chapter 15 Example Program ...... 85 SEETEST.ASM - Chapter 17 Example Program...... 88 TIMEOUT.ASM - Chapter 18 Example Program ...... 97 VMETER.ASM - Chapter 16 Example Program ...... 101 Program Pull-Out ©1998 Sirius microSystems Microchip Code 3 References WDTIMER.ASM - Chapter 18 Example Program ...... 107 XMIT232.ASM - Chapter 15 Example Program ...... 111

4 Microchip Code ©1998 Sirius microSystems PIC-MDS Subroutine Library Summary

This section provides a quick reference to the function, requirements if any, and use of each subroutine library file included with the PIC-MDS. All variables shown as belonging to a subroutine library are not defined in the library code. These vari- ables must be defined (in the form of an EQUate statement) by the program that calls the library. For more details on library subroutines and operation, see the indi- vidual library pull-out programs and the chapters using the libraries.

ATOD.LIB Provides subroutine function calls for analog-to-digital (A/D) converter operation in the PIC16C71/711.

Variables: none

Requirements: ADRES (09h) is used as a temporary register. Read ADRES con- tents before changing the A/D port, A/D clock divisor, or initiating a new conversion.

Use: To convert a voltage on an A/D input pin into a binary number: 1. CALL AD_Port to initialize Port A and turn on A/D. (opt.) Steps marked with (opt.) 2. Load W with a clock divisor, below, and CALL AD_Clock. (opt.) are necessary when first ADCLK2 - oscillator/2 calling the library and are ADCLK8 - oscillator/8 unneccessary for subse- ADCLK32 - oscillator/32 quent calls provided that no ADCLKRC - internal RC oscillator other libraries are called in 3. Load W with a pin number, below, and call AD_Channel. (opt.) between. For example, calling LCD_Port after ADCH0 - channel 0, pin RA0/AN0 calling AD_Port will ADCH1 - channel 1, pin RA1/AN1 reconfigure Port A for ADCH2 - channel 2, pin RA2/AN2 digital I/O. Before calling ADCH3 - channel 3, pin RA3/AN3 AD_Poll, AD_Port must be 4. CALL AD_Poll to start the conversion. called. 5. Read the conversion result from ADRES.

BIN2BCD.LIB Converts a 16-bit binary number into five BCD nybbles.

Variables: HighByte - upper eight bits of the 16-bit number to convert LowByte - lower eight bits of the 16-bit number to convert TenThous - ten-thousands digit of result stored in lower nybble ThouHund - thousands digit and hundreds digit of result TensOnes - tens digit and ones digit of result ShiftCounter - a counter used to count shifts during a conversion

Requirements: none

Use: To convert a 16-bit number into five BCD digits: 1. Move a 16-bit binary number into HighByte and LowByte. 2. CALL BIN_BCD to initiate the conversion. 3. Read conversion results from TenThous, ThouHund, & TensOnes. Program Pull-Out ©1998 Sirius microSystems Microchip Code 5 References BIN2DEC.LIB Converts an 8-bit binary number into three binary digits.

Variables: Hundreds - hundreds digit of the result Tens - tens digit of the result Ones - ones digit of the result

Requirements: none

Use: To convert an 8-bit binary number into three binary digits: 1. Load W with the binary number to be converted. 2. CALL BIN_DEC to initiate the conversion. 3. Read the results from Hundreds, Tens & Ones.

DEC2BIN.LIB Converts three binary decimal (with values less than 10) digits into an 8-bit binary number.

Variables: Hundreds - hundreds digit of the initial number Tens - tens digit of the initial number Ones - ones digit of the initial number

Requirements: none

Use: To convert three binary digits into an 8-bit binary number: 1. Load Hundreds, Tens & Ones with the numbers to be converted. 2. CALL DEC_BIN to initiate the conversion. 3. Read the result from W.

EEPROM.LIB Provides function calls for the internal data EEPROM in the PIC16C/F84.

Variables: none

Requirements: none

Use: To write data into an EEPROM address: 1. Move an EEPROM address into EEADR. 2. Move a data byte into EEDATA. 3. CALL EE_Write.

To wait for EEPROM write completion: 1. CALL EE_Wait.

To read data from an EEPROM address: 1. Move an EEPROM address into EEADR. 2. CALL EE_Read. 3. Read the data from EEDATA.

6 Microchip Code ©1998 Sirius microSystems KEYPAD.LIB Provides function calls for keypad scanning on the PIC-MDS. Returns a key code corresponding to the key number of any one key being pressed. A return code of 0 indicates no keys are pressed. This library does not implement key debouncing.

Variables: Key - contains the key code following a key scan

Requirements: none

Use: To scan for a key press: 1. CALL KB_Port to configure Port B for keypad use. (opt.) 2. CALL KB_Scan to scan for a key press. 3. Read the key code from Key.

LCD.LIB Provides function calls for LCD operation in 8-bit mode (this is the default mode for PIC-MDS programs).

Variables: none

Requirements: 1. Two free levels of processor stack are required for nested calls. 2. The calling program must provide a 5 ms (minimum) time delay routine called Delay_5ms.

Use: To initialize the LCD display after power-up: 1. CALL LCD_Port to configure Port A and Port B for the LCD. 2. CALL LCD_Init to initialize the LCD controller.

To write a character to the current LCD cursor position: 1. CALL LCD_Port to configure Ports A and B for the LCD. (opt.) 2. Load W with the ASCII value of the character. 3. CALL LCD_Data to display the character.

To write a command or character address to the LCD controller: 1. CALL LCD_Port to configure Ports A and B for the LCD. (opt.) 2. Load W with the command or character address. 3. CALL LCD_Reg to write the data into the LCD controller.

Some important LCD commands (see the library file for others): LCDLine1 - character address for the start of line 1 LCDLine2 - character address for the start of line 2 LCDCLR - clears the LCD display memory LCDInc - sets automatic cursor increment mode CursOn - displays the LCD cursor CursOff - disables display of the LCD cursor

LCD4BIT.LIB Same as LCD.LIB but operates in 4-bit mode. Requirements and Use are as above.

Variables: LCDTemp - stores commands and data for transmission. Program Pull-Out ©1998 Sirius microSystems Microchip Code 7 References RS232RX.LIB Provides function calls to receive RS-232 serial data without handshaking. The de- fault RS-232 data rate is 9600 bps, although this can by changed by modifying the Bit_Time variable in RS232RX.LIB. Subroutines are provided to wait for a serial character, or to begin reception after the calling program detects a start bit. If a framing error occurs during reception, the Receive byte will be cleared (00h).

Variables: Counter - delay counter for bit time delay loop BitCounter - counts number of received bits Receive - holds received serial character

Requirements: Two free levels of processor stack are required for nested calls.

Use: To wait for and receive a serial character: 1. CALL Receive_Port to configure Port A.4 for input. 2. CALL Receive_Wait to wait for the next serial character. 3. Read the received character from Receive.

To receive a serial character after detecting a start bit: 1. CALL Receive_Port prior to waiting for a start bit. 2. CALL Receive_Data after detecting a start bit. 3. Read the received character from Receive.

RS232TX.LIB Provides function calls to transmit RS-232 serial data without handshaking. The default RS-232 data rate is 9600 bps, although this can be changed by modifying the Bit_Time variable in RS232TX.LIB.

Variables: Counter - delay counter for bit time delay loop BitCounter - counts number of transmitted bits Transmit - stores the serial character to be transmitted

Requirements: Two free levels of processor stack are required for nested calls.

Use: To transmit a serial character: 1. CALL Transmit_Port to configure Port A.4 for output. 2. Move the byte to be transmitted into Transmit. 3. CALL Transmit_Data to send the serial byte.

8 Microchip Code ©1998 Sirius microSystems SEEPROM.LIB Provides function calls for interfacing to 93LC56 (256-byte) and 93LC66 (512-byte) serial EEPROMs (SEEPROMs) in 8-bit mode only.

Variables: SEEClock - clock counter register for serial data frame SEEData - SEEPROM data byte storage register SEEAddrh - SEEPROM high address byte SEEAddrl - SEEPROM low address byte

Requirements: Two free levels of processor stack are required for nested calls.

Use: To enable or disable SEEPROM write access: 1. CALL SEE_Port to configure Ports A & B. (opt.) 2. Move SEEEWEN (enable) or SEEEWDS (disable) into W. 3. CALL SEE_Command to send the command to the SEEPROM.

To write a data byte into a SEEPROM address: 1. CALL SEE_Port to configure Ports A & B. (opt.) 2. Load SEEAddrh with the high byte of the SEEPROM address. 3. Load SEEAddrl with the low byte of the SEEPROM address. 4. Load SEEData with the data byte to be written. 5. Move the SEEWrite constant into W. 6. CALL SEE_Command to initiate the write operation. 7. CALL SEE_Wait to wait for the completion of the write. (opt.)

To read a data byte from a SEEPROM address: 1. CALL SEE_Port to configure Ports A & B. (opt.) 2. Load SEEAddrh with the high byte of the SEEPROM address. 3. Load SEEAddrl with the low byte of the SEEPROM address. 4. Move the SEERead constant into W. 5. CALL SEE_Command to initiate the write operation. 6. Read the data byte from SEEData.

See the library pull-out for information on the Erase, Erase All, and Write All commands.

Program Pull-Out ©1998 Sirius microSystems Microchip Code 9 References 10 Microchip Code ©1998 Sirius microSystems ATOD.LIB - PIC16C711 A/D Subroutine Library

;ATOD.LIB V1.2 Last Modified on August 31, 1998

;These program subroutines were written for the Sirius microSystems PICmicro ;development system. For more information contact Sirius microSystems by phone ;at 519-886-4462, or on the Internet at http://www.siriusmicro.com .

;Sirius microSystems provides this software on an “as is” basis, without any ;warranty, either expressed or implied. All Sirius microSystems software is ;provided for educational use only, and Sirius microSystems does not assume ;any liability for damages, either incidental or consequential, arising out of ;the application, use, or misuse of any of its software or hardware products. ;Sirius microSystems reserves the right, without further notice, to make ;changes to any of its software or hardware referred to in this program or ;library program in order to improve its function, design or reliability.

;Description

; This subroutine library provides calls for A/D converter operation, ; including: ; - Port configuration ; - A/D Channel selection ; - Conversion Clock selection ; - A/D conversion routine with polling

;Variables

; No file register variables are required by this subroutine library. ; ADRES (09h) is used for temporary storage.

;Requirements

; ADRES (09h) is used as a temporary register before conversion. Ensure ; that its data has been read before calling the library functions for ; the next conversion. ADRES normally holds the A/D conversion result.

; Calling programs may require shorting jumpers over RA0 and RA1 on the ; JU6 header. These jumpers physically connect potentiometers VR3 and ; VR4 to the RA0 and RA1 inputs on the PIC16C711. Normally these jumpers ; are not installed to minimize the effect of an analog voltage source ; (from the potentiometers) on the digital I/O lines.

;Use

; 1. Call AD_Port to initialize Port A for A/D operation and turn on A/D ; 2. Move a clock divisor constant into W and call AD_Clock ; 3. Move a channel selector constant into W and call AD_Channel ; 4. Call AD_Poll ; 5. Read the result from ADRES

;A/D Clock Divisor Software Constants

ADCLK2 EQU 00000000b ;A/D clock=oscillator/2 ADCLK8 EQU 01000000b ;A/D clock=oscillator/8 ADCLK32 EQU 10000000b ;A/D clock=oscillator/32 ADCLKRC EQU 11000000b ;A/D clock from internal RC osc.

;One A/D clock (TAD) must be greater than 2 microseconds. Choose a clock ;divider from above based on your oscillator frequency.

;eg. 16 MHz oscillator 1 oscillator clock = T = 62.5 ns ; ; TAD / T = Clock divider ; 2 us / 62.5 ns = 32 ; ; Therefore, a 16 MHz oscillator must be divided by 32 to ; produce the correct A/D clock. ; Program Pull-Out ©1998 Sirius microSystems Microchip Code 11 References ATOD.LIB - PIC16C711 A/D Subroutine Library

;An A/D conversion completes in 10 TAD. For the example above, the ;conversion will finish in 20 microseconds.

;Using the internal oscillator allows a conversion to be performed during ;SLEEP for greatest accuracy. Use interrupt to wake processor when the ;conversion finishes. Conversion time with the RC oscillator is nominally ;40 microseconds but varies between individual processors.

;A/D Channel Selector Software Constants

ADCH0 EQU 00000000b ;A/D conversion on RA0 ADCH1 EQU 00001000b ;A/D conversion on RA1 ADCH2 EQU 00010000b ;A/D conversion on RA2 ADCH3 EQU 00011000b ;A/D conversion on RA3

;A/D conversion channels 2 and 3 are not implemented on the PIC-MDS but ;can be accessed through the screw terminal strip or PICBUS.

AD_Port ;Initializes ADCON1 for analog input on RA0 and RA1 with ;VDD as the voltage reference and turns A/D converter on.

BSF RP0 ;Select memory page 1 MOVLW 00000011b ;OR this byte with TRISA to enable IORWF TRISA ;required analog pins as inputs MOVLW 02h ;Make RA0 and RA1 analog inputs by MOVWF ADCON1 ;writing this byte to ADCON1 (88h) BCF RP0 ;Back to page 0 BSF ADON ;Turn A/D converter on RETURN

AD_Clock ;Sets ACDS0 and ADCS1 bits in ADCON0 based on the number ;in W. Load W with a clock divider constant from the ;list, above. Read ADRES before calling AD_Clock.

MOVWF ADRES ;Use ADRES as temporary storage MOVLW 3Fh ;Load W with 0011 1111 ANDWF ADCON0,1 ;AND with ADCON0 to clear high bits MOVF ADRES,0 ;Get clock divider bits from ADRES IORWF ADCON0,1 ;OR with ADCON0 to set clock bits RETURN

AD_Channel ;Sets CHS0 and CHS1 bits in ADCON0 based on the number in ;W when AD_Channel was called. Load W from channel constants ;list, above. Read ADRES before calling AD_Channel.

MOVWF ADRES ;Use ADRES as temporary storage MOVLW 11100111b ;Load W with 1110 0111 and ANDWF ADCON0,1 ;AND with ADCON0 to clear CHS0/1 MOVF ADRES,0 ;Get channel select bits from ADRES IORWF ADCON0,1 ;OR with ADCON0 to set channel bits RETURN

AD_Poll ;Sets GO_DONE bit in ADCON0 to start the A/D conversion ;and keeps polling the bit until the conversion is ;complete. Get the result of the conversion from ADRES.

BSF GO_DONE ;Start A/D conversion :Loop BTFSC GO_DONE ;Check GO_DONE for end of conversion GOTO :Loop ;and keep checking until done RETURN

12 Microchip Code ©1998 Sirius microSystems BIN2BCD.LIB - Binary to BCD Conversion Library

;BIN2BCD.LIB V1.2 Last modified on August 31, 1998

;These program subroutines were written for the Sirius microSystems PICmicro ;development system. For more information contact Sirius microSystems by phone ;at 519-886-4462, or on the Internet at http://www.siriusmicro.com .

;Sirius microSystems provides this software on an “as is” basis, without any ;warranty, either expressed or implied. All Sirius microSystems software is ;provided for educational use only, and Sirius microSystems does not assume ;any liability for damages, either incidental or consequential, arising out of ;the application, use, or misuse of any of its software or hardware products. ;Sirius microSystems reserves the right, without further notice, to make ;changes to any of its software or hardware referred to in this program or ;library program in order to improve its function, design or reliability.

;Description

; This subroutine library converts 16-bit binary numbers to five BCD ; digits stored in three file register locations. The result registers ; are TenThous to hold the ten-thousands digit, ThouHund to hold the ; thousands and hundreds digits, and TensOnes to hold the tens and ones ; digits. This subroutine is useful for displaying a 16-bit variable as ; five decimal digits on the LCD display.

; This routine takes 458 clock cycles to complete. If you don’t need ; 16-bit accuracy—for example for a 12-bit A/D converter—you can ; redefine the BinBits (Binary Bits) variable for the number of bits of ; accuracy that are required. This results in shorter conversion times.

; Note also that the contents of HighByte and LowByte are corrupted during ; the conversion and therefore their contents will have changed upon ; returning to the calling program.

;Variables

; The following variables must be defined as file register locations in ; your calling program. Use the format:

; Variable name EQU File Register location (0Ch to 2Fh)

; HighByte - the high byte of the 16-bit number to convert ; LowByte - the low byte of the 16-bit number to convert ; TenThous - the ten-thousands digit of the result ; ThouHund - the thousands and hundreds digits of the result ; TensOnes - the tens and ones digits of the result ; ShiftCounter - a counter used to count shifts during the conversion

; The following variable is a Software variable that defines the number ; of bits to be converted. By default, this is 16 bits.

; BinBits - equated to 16. Change this in the program to ; convert fewer digits

;Use

; 1. Move the binary number into HighByte and LowByte ; 2. Call BIN_BCD ; 3. Retreive your results from TenThous, ThouHund, and TensOnes

;Software Equate

BinBits EQU 16 ;Number of binary bits to convert

BIN_BCD ;This conversion subroutine uses the add-3 algorithm to ;convert binary to BCD. The binary number is shifted into ;the BCD registers one bit at a time. After each shift, each Program Pull-Out ©1998 Sirius microSystems Microchip Code 13 References BIN2BCD.LIB - Binary to BCD Conversion Library

;BCD digit is checked to see if it is greater than or equal ;to five. If so, three is added to the BCD digit. The original ;number is the shifted again before each digit is checked to ;see if it equals or exceeds 5. After 16 shifts, the result ;is complete.

MOVLW BinBits ;Save the number binary digits in the MOVWF ShiftCounter ;number into the ShiftCounter register

CLRF TensOnes ;Clear all BCD digits before starting CLRF ThouHund CLRF TenThous

GOTO ShiftBits ;Start by shifting bits into BCD regs.

Adj_BCD MOVLW 03h ;Preload W with 03 and add to lower ADDWF TensOnes ;nybble in TensOnes register BTFSS TensOnes.3 ;Check for a result greater than 7 SUBWF TensOnes ;If not, subtract three from nybble MOVLW 30h ;Preload W to add 03 to upper nybble ADDWF TensOnes ;in TensOnes register BTFSS TensOnes.7 ;Check for a result greater than 7 SUBWF TensOnes ;If not, subtract three from nybble

MOVLW 03h ;Preload W with 03 and add to lower ADDWF ThouHund ;nybble in ThouHund register BTFSS ThouHund.3 ;Check for a result greater than 7 SUBWF ThouHund ;If not, subtract three from nybble MOVLW 30h ;Preload W to add 03 to upper nybble ADDWF ThouHund ;in ThouHund register BTFSS ThouHund.7 ;Check for a result greater than 7 SUBWF ThouHund ;If not, subtract three from nybble

MOVLW 03h ;Preload W with 03 and add to lower ADDWF TenThous ;nybble in TenThous register BTFSS TenThous.3 ;Check for a result greater than 7 SUBWF TenThous ;If not, subtract three from nybble

ShiftBits BCF C ;Clear Carry before first shift RLF LowByte ;Shift Low Byte left, C into HighByte RLF HighByte ;Shift High Byte left, C into TensOnes RLF TensOnes ;Shift TensOnes left, C into ThouHund RLF ThouHund ;Shift ThouHund left, C into TenThous RLF TenThous ;Shift TenThous left

DECFSZ ShiftCounter ;Check if all bits have been shifted GOTO Adj_BCD ;If not, adjust digits and shift again RETURN

14 Microchip Code ©1998 Sirius microSystems BIN2DEC.LIB - Binary to Decimal Conversion Library

;BIN2DEC.LIB v1.2 Last modified on August 31, 1998

;These program subroutines were written for the Sirius microSystems PICmicro ;development system. For more information contact Sirius microSystems by phone ;at 519-886-4462, or on the Internet at http://www.siriusmicro.com .

;Sirius microSystems provides this software on an “as is” basis, without any ;warranty, either expressed or implied. All Sirius microSystems software is ;provided for educational use only, and Sirius microSystems does not assume ;any liability for damages, either incidental or consequential, arising out of ;the application, use, or misuse of any of its software or hardware products. ;Sirius microSystems reserves the right, without further notice, to make ;changes to any of its software or hardware referred to in this program or ;library program in order to improve its function, design or reliability.

;Description

; This subroutine library converts 8-bit binary numbers to a three-digit ; decimal code (ie. 0-0-0 - 2-5-5) and stores the result in three file ; register locations. This subroutine is useful for displaying a binary ; number as three decimal digits on the LCD display.

;Variables

; The following variables must be defined as file register locations in ; your calling program. Use the format:

; Variable name EQU File Register location (0Ch to 2Fh)

; HUNDREDS - the hundreds digit counter ; TENS - the tens digit counter ; ONES - the ones remainder

;Use

; 1. Move the binary number into W ; 2. Call BIN_DEC ; 3. Retreive your results from Hundreds, Tens and Ones

BIN_DEC ;This conversion program attempts to subtract 100 from ;the binary number until the result is negative. Each ;subtraction increments the HUNDREDS digit. When it can’t ;subtract 100, the program subtracts 10 from the remainder ;until the result once again is negative, incrementing the ;TENS digit for each subtraction. The remainder of the ;subtraction becomes the ONES digit.

CLRF HUNDREDS ;Reset the hundreds counter CLRF TENS ;and the tens counter MOVWF ONES ;Ones digit holds results

:Hundred MOVLW 100 ;Load W with 100 and SUBWF ONES,W ;subtract it from the number BTFSS C ;If result is negative GOTO :Ten ;check for any tens INCF HUNDREDS ;otherwise count 1 hundred MOVWF ONES ;Remainder becomes result GOTO :Hundred ;Check for another hundred

:Ten MOVLW 10 ;Load W with 10 and SUBWF ONES,W ;subtract it from the number BTFSS C ;If result is negative RETURN ;we’re done, ONES holds remainder INCF TENS ;otherwise count 1 ten MOVWF ONES ;Remainder becomes result GOTO :Ten ;Check for another ten

Program Pull-Out ©1998 Sirius microSystems Microchip Code 15 References DEC2BIN.LIB - Decimal to Binary Conversion Library

;DEC2BIN.LIB v1.2 Last Modified on July 9, 1999

;These program subroutines were written for the Sirius microSystems PICmicro ;development system. For more information contact Sirius microSystems by phone ;at 519-886-4462, or on the Internet at http://www.siriusmicro.com .

;Sirius microSystems provides this software on an “as is” basis, without any ;warranty, either expressed or implied. All Sirius microSystems software is ;provided for educational use only, and Sirius microSystems does not assume ;any liability for damages, either incidental or consequential, arising out of ;the application, use, or misuse of any of its software or hardware products. ;Sirius microSystems reserves the right, without further notice, to make ;changes to any of its software or hardware referred to in this program or ;library program in order to improve its function, design or reliability.

;Description

; This subroutine library converts a three-digit decimal code to an ; 8-bit binary number and returns the number in W. The three digits are ; loaded from three file register locations and should not represent a ; number larger than 255 (no error checking is done). This routine is ; useful for storing user input as a byte of data.

;Variables

; The following variables must be defined as file register locations in ; your calling program. Use the format:

; Variable name EQU File Register location (0Ch to 2Fh)

; HUNDREDS - the hundreds digit counter ; TENS - the tens digit counter ; ONES - the ones remainder

;Use

; 1. Move three decimal numbers into Hundreds, Tens and Ones ; 2. Call Dec_Bin ; 3. Retrieve the binary number from W

Dec_Bin ;This conversion program starts by clearing W. 100 is added ;to W for each Hundreds digit. Hundreds digits are counted ;by decrementing the Hundreds digit until it reaches 0. Next, ;10 is added to W for each Tens digit. Finally, the Ones ;digit is added to W to get the result.

CLRW ;Clear W to store result MOVF Hundreds,1 ;Move Hundreds register to itself BTFSC Z ;to check for zero GOTO :Tens ;If no hundreds digit check tens digit :Add_Hundred ADDLW 100 ;Add 100 to W since there are hundreds DECFSZ Hundreds,1 ;Decrement hundreds digit, check for 0 GOTO :Add_Hundred ;If more hundreds, add another 100

:Tens MOVF Tens,1 ;Move Tens register to itself BTFSC Z ;to check for zero GOTO :Ones ;If no tens digit check ones digit :Add_Ten ADDLW 10 ;Add 10 to W since there are tens DECFSZ Tens,1 ;Decrement tens digit, check for 0 GOTO :Add_Ten ;If more tens, add another 10

:Ones ADDWF Ones,0 ;Add contents of Ones register to W RETURN ;All Done!

16 Microchip Code ©1998 Sirius microSystems EEPROM.LIB - PIC16F84 EEPROM Subroutine Library

;EEPROM.LIB v1.2 Last modified on August 31, 1998

;These program subroutines were written for the Sirius microSystems PICmicro ;development system. For more information contact Sirius microSystems by phone ;at 519-886-4462, or on the Internet at http://www.siriusmicro.com .

;Sirius microSystems provides this software on an “as is” basis, without any ;warranty, either expressed or implied. All Sirius microSystems software is ;provided for educational use only, and Sirius microSystems does not assume ;any liability for damages, either incidental or consequential, arising out of ;the application, use, or misuse of any of its software or hardware products. ;Sirius microSystems reserves the right, without further notice, to make ;changes to any of its software or hardware referred to in this program or ;library program in order to improve its function, design or reliability.

;Description

; This subroutine provides calls for PIC16F84 EEPROM operation including: ; - EEPROM data write ; - EEPROM data read ; - Wait for EEPROM write to finish

;Variables

; None

;Requirements

; None

;Use

; To write data to the EEPROM: ; 1. Move an EEPROM address into EEADR ; 2. Move the data to be written into EEDATA ; 3. CALL EE_Write

; To wait for EEPROM write completion: ; 1. CALL EE_Wait (on RETURN, EEPROM write is complete)

; To read data from the EEPROM: ; 1. Move an EEPROM address into EEADR ; 2. CALL EE_Read (the data will be available in EEDATA)

;Notes

; Instead of waiting for the EEPROM write to finish, EEIF can generate ; an interrupt. When using interrupts, some precautions must be taken:

; 1. Disable GIE (all interrupts) before calling EE_Write. ; 2. On exit from EE_Write, re-enable interrupts

; Microchip strongly recommends that interrupts be disabled during ; the EEPROM write sequence.

EE_Read ;Sets the RD bit in EECON1 to read the contents of EEADR ;into EEDATA.

BSF RP0 ;Select memory register page 1 BSF RD ;Set the EECON1.RD bit to read BCF RP0 ;Return to memory register page 0 RETURN

EE_Write ;Writes the contents of EEDATA to EEADR as specified in ;the PIC16F84 data sheets after enabling WREN. After ;writing the data, WREN is cleared, disabling accidental Program Pull-Out ©1998 Sirius microSystems Microchip Code 17 References EEPROM.LIB - PIC16F84 EEPROM Subroutine Library

;writes.

BSF RP0 ;Select memory register page 1 BSF WREN ;Enable EEPROM writes MOVLW 55h MOVWF EECON2 ;Write 55h to EECON2 MOVLW 0aah MOVWF EECON2 ;Write AAh to EECON2 BSF WR ;Set EECON1.WR bit BCF WREN ;Disable any further writes BCF RP0 ;Return to memory register page 0 RETURN

EE_Wait ;Wait for an EE_Write to finish by checking the EEIF ;flag bit in EECON1.

BSF RP0 ;Select memory register page 1 :Wait BTFSS EEIF ;Check EEIF for a high (1=finished) GOTO :Wait ;If low, wait for EEIF to go high BCF EEIF ;Clear EEIF after write is done BCF RP0 ;Return to memory register page 0 RETURN

18 Microchip Code ©1998 Sirius microSystems KEYPAD.LIB - Keypad Subroutine Library

;KEYPAD.LIB v1.2 Last Modified on August 31, 1998

;These program subroutines were written for the Sirius microSystems PICmicro ;development system. For more information contact Sirius microSystems by phone ;at 519-886-4462, or on the Internet at http://www.siriusmicro.com .

;Sirius microSystems provides this software on an “as is” basis, without any ;warranty, either expressed or implied. All Sirius microSystems software is ;provided for educational use only, and Sirius microSystems does not assume ;any liability for damages, either incidental or consequential, arising out of ;the application, use, or misuse of any of its software or hardware products. ;Sirius microSystems reserves the right, without further notice, to make ;changes to any of its software or hardware referred to in this program or ;library program in order to improve its function, design or reliability.

;Description

; This subroutine library provides calls for keyboard scanning, including: ; - Keypad port configuration ; - Key code retrieval

;Variables

; Key - key code return register (EQU to a file register)

;Requirements

; Ensure that your calling program defines KEY as a hardware register. ; After calling KB_Scan, the KEY register contains the number of the ; key pressed. If no key was pressed, KEY contains the number 0.

;Use

; 1. Call KB_Port to initialize Port B for the keyboard ; 2. Call KB_Scan to scan for a key press ; 3. Retrieve the Key code from the Key variable

;Notes: You should add a key debouncing routine to your calling program. ; Each time a key is pressed, the mechanical contacts ‘bounce’ for ; a short time, alternately making and breaking the key connection. ; Key bounce would be read by the microcontroller as a series of ; rapid key presses instead of one single key press. Keys and buttons ; can be debounced by reading the keys once, and then again after ; a short debouncing delay: ; ; 1. Call KB_Port to initialize Port B for keypad use ; 2. Call KB_Scan to scan for a key press ; 3. Save the Key code variable in a temporary register ; 4. Call a delay routine of 20 ms ; 5. Call KB_Scan again to scan for a key press ; 6. Compare the new Key code value to the Key code saved in the ; temporary register. If they’re the same the key press is valid, ; otherwise discard the key press.

KB_Port ;Initializes Port B for keyboard input by setting RB0-3 as ;output and RB4-7 as inputs with pull-up resistors enabled.

BSF RP0 ;Select memory page 1 MOVLW 0F0h ;Set high nibble to input and MOVWF TRISB ; low nibble to output BSF RBPU ;Enable pull-ups on inputs BCF RP0 ;Select memory page 0 RETURN ;Done, return to calling program

KB_Scan ;Scans the keyboard by: ; 1. Setting the Key variable to a 1 for the first key code ; 2. Setting all row outputs except row 1 to a high (row 1 Program Pull-Out ©1998 Sirius microSystems Microchip Code 19 References KEYPAD.LIB - Keypad Subroutine Library

; gets set to a low. ; 3. Checking each column input in turn for the low on row 1. ; If no key is pressed, the column will read high due to ; the pull-up resistors. If a key is pressed, the column ; will read low. ; 4. Repeatedly setting all row outputs except the next row ; high and repeating step 3 for each row.

;If a key press is detected, the routine exits with the key ;number in the Key variable. Key numbers are (in decimal):

; Col. 1 2 3 4 ; Row +----+----+----+----+ ; 1 | 1 | 2 | 3 | 4 | ; +----+----+----+----+ ; 2 | 5 | 6 | 7 | 8 | ; +----+----+----+----+ ; 3 | 9 | 10 | 11 | 12 | ; +----+----+----+----+ ; 4 | 13 | 14 | 15 | 16 | ; +----+----+----+----+ ;If no key press is detected, the routine exits with the ;number 0 in the Key variable. This makes it easy to check ;for no key presses by testing the Z flag.

;The KB_Scan routine checks for key presses in the sequence ;indicated by the key numbers, above. If two or more keys ;are pressed simultaneously, only the first key in the ;sequence will be returned.

CLRF Key ;Clear Key register and then INCF Key ;set Key to first return code MOVLW 0Eh ;Output 0 to first row only, MOVWF PORTB ;Output to Port B NOP ;and wait for signals to settle

:Col_Check BTFSS PORTB.4 ;Check first column for low RETURN ;and exit on key press INCF Key ;If no key press, increment key number BTFSS PORTB.5 ;Check second column for low RETURN ;and exit on key press INCF Key ;If no key press, increment key number BTFSS PORTB.6 ;Check third column for low RETURN ;and exit on key press INCF Key ;If no key press, increment key number BTFSS PORTB.7 ;Check fourth column for low RETURN ;and exit on key press INCF Key ;If no key press, increment key number

:Row_Set MOVLW 11h ;Load W with number of keys + 1 SUBWF Key,0 ;and compare with current key value BTFSC Z ;If keys + 1 = current key then GOTO :No_Keys ;no key was pressed BSF C ;Set carry bit to make first row high RLF PORTB ;and rotate row outputs GOTO :Col_Check

:No_Keys CLRF Key ;Set Key variable to 0 and RETURN ;return to calling program

20 Microchip Code ©1998 Sirius microSystems LCD.LIB - LCD Subroutine Library

;LCD.LIB v1.2 Last modified on August 31, 1998

;These program subroutines were written for the Sirius microSystems PICmicro ;development system. For more information contact Sirius microSystems by phone ;at 519-886-4462, or on the Internet at http://www.siriusmicro.com .

;Sirius microSystems provides this software on an “as is” basis, without any ;warranty, either expressed or implied. All Sirius microSystems software is ;provided for educational use only, and Sirius microSystems does not assume ;any liability for damages, either incidental or consequential, arising out of ;the application, use, or misuse of any of its software or hardware products. ;Sirius microSystems reserves the right, without further notice, to make ;changes to any of its software or hardware referred to in this program or ;library program in order to improve its function, design or reliability.

;Description

; This subroutine provides calls for LCD operation including: ; - Port Configuration ; - Register mode commands ; - LCD Busy check ; - LCD Enable toggle

;Variables

; None

;Requirements

; Two free levels of processor stack are required for nested calls.

; The LCD_Init subroutine requires a minimum 5ms delay to initialize ; the LCD. Delays longer than 5ms are acceptable. LCD_Init calls a ; subroutine by the name of Delay_5ms which must be included in your ; calling program. If your calling program contains a delay loop of ; longer than 5ms, you can use that delay by adding a Delay_5ms ; label before the routine.

;Use

; To initialize the LCD display after power-up: ; 1. Call LCD_Port to initialize Port A and Port B for the LCD display ; 2. Call LCD_Init to initialize the LCD controller

; To write a command or character to the LCD display: ; 1. Call LCD_Port to initialize Port A and Port B for the LCD display ; 2. Move an LCD command or ASCII character into W ; 3. Call LCD_Reg or LCD_Data to send the command or ; character to the LCD.

;LCD Hardware Equates

LCDRS EQU PORTA.0 ;LCD Register Select LCDRW EQU PORTA.1 ;LCD Read/~Write LCDE EQU PORTA.2 ;LCD Enable

;LCD Software Commands (Constants)

LCDLine1 EQU 80h ;Line 1 starting address LCDLine2 EQU 0C0h ;Line 2 starting address LCDCLR EQU 01h ;Clear Display, cursor home LCDHome EQU 02h ;Cursor home, DDRAM unchanged LCDInc EQU 06h ;Cursor increment mode LCDDec EQU 04h ;Cursor decrement mode LCDOn EQU 0Ch ;Display On LCDOff EQU 08h ;Display Off Program Pull-Out ©1998 Sirius microSystems Microchip Code 21 References LCD.LIB - LCD Subroutine Library

CursOn EQU 0Eh ;Display On and Cursor On CursOff EQU 0Ch ;Display On and Cursor Off CursBlink EQU 0Fh ;Display On and Cursor Blinking LCDLeft EQU 18h ;Shift Display Left LCDRight EQU 1Ch ;Shift Display Right CursLeft EQU 10h ;Move Cursor Left CursRight EQU 14h ;Move Cursor Right LCDFunction EQU 38h ;8-bit function register init. command LCDInit EQU 38h ;LCD initialization command LCDCGRAM EQU 40h ;CGRAM starting address

LCD_Port ;Initializes the Port B tristate buffers as outputs for ;LCD data lines. Sets Port A to digital (on PIC16C711) and ;sets the LCD Register Select, Read/~Write, and Enable ;lines to outputs.

BSF RP0 ;Select memory register page 1

;the next two lines are for the PIC16C711 only and should be ;removed for the PIC16F84 (PM produces an error when this ;is assembled for the ’84).

;MOVLW 03h ;1’s set Port A to digital ;MOVWF ADCON1 ;Write W to ADCON1 (88h)

MOVLW 11111000b ;Set lower 3 bits of RA to ANDWF TRISA ;digital output in TRISA CLRF TRISB ;Set Port B to output BCF RP0 ;Go back to register page 0 BCF LCDE ;Keep LCD Enable line off RETURN ;Ports are now set up for LCD

LCD_Init ;LCD initialization instructions from the Optrex data book. ;Sets LCD functions for DMC16207 display, performs soft- ;ware reset, clears memory and turns the display on.

MOVLW LCDInit ;Load W with initialize LCD code CALL LCD_Reg_Init ;and send it to LCD CALL Delay_5ms ;...and wait MOVLW LCDInit ;Load W with initialize LCD code CALL LCD_Reg_Init ;and send it to LCD again CALL Delay_5ms ;...and wait MOVLW LCDInit ;Load W with initialize LCD code CALL LCD_Reg_Init ;and send it to LCD again CALL Delay_5ms ;...and wait MOVLW LCDFunction ;Load W with initialize 8-bit code CALL LCD_Reg ;and send it to LCD CALL Delay_5ms ;...and wait

;Change the constant in the next line to set how the display ;is activated. eg. LCDOn, CursOn, CursBlink. The Constant is ;from the LCD software commands, above.

MOVLW LCDOn ;Command for display on & cursor off

CALL LCD_Reg ;Send it to LCD MOVLW LCDCLR ;Load W with clear LCD code CALL LCD_Reg ;and send it to LCD MOVLW LCDInc ;Load W with increment mode code CALL LCD_Reg ;and send it to LCD RETURN

LCD_Reg_Init ;Used only for initialization prior to setting function ;register. In this time, the LCD busy flag cannot be checked.

22 Microchip Code ©1998 Sirius microSystems LCD.LIB - LCD Subroutine Library

BCF LCDRS ;Enter register mode MOVWF PORTB ;and send W to LCD reg. on Port B GOTO LCD_Enable ;Send register command

LCD_Reg ;Load W with LCD software constant from table, above. ;LCD_Reg outputs the command to the LCD and blips the ;enable line with LCD_Enable to complete the command.

BCF LCDRS ;Enter register mode MOVWF PORTB ;and send W to LCD reg. on Port B CALL LCD_Check ;Check LCD busy flag GOTO LCD_Enable ;Send register command

LCD_Data ;Load W with the ASCII character code to send to LCD. ;LCD_Data outputs the character to the LCD and blips ;the enable line with LCD_Enable to complete the send.

BCF LCDRS ;Enter register mode MOVWF PORTB ;and send W to LCD on Port B CALL LCD_Check ;Check LCD busy flag BSF LCDRS ;Enter ASCII mode GOTO LCD_Enable ;Send ASCII character

LCD_Check ;Checks the state of the LCD Busy flag and waits for any ;previous command to finish before returning to the ;calling routine.

BSF LCDRW ;Set LCD read mode BSF RP0 ;Select memory page 1 MOVLW 0FFh ;Set Port B to input and MOVWF TRISB ;disable tristate buffers BCF RP0 ;Back to memory page 0 BSF LCDE ;Enable LCD NOP ;and wait for an extra cycle :Loop BTFSC PORTB.7 ;Check LCD busy bit and GOTO :Loop ;wait if high. (Busy=1) BCF LCDE ;Disable LCD BSF RP0 ;Select memory page 1 CLRF TRISB ;Set Port B to output BCF RP0 ;Back to memory page 0 BCF LCDRW ;Back to LCD write mode RETURN ;LCD is now free

LCD_Enable ;Sends a 500 ns enable pulse to the LCD to complete the ;register or character write operation. The NOP instruction ;is only required for processors faster than 8 MHz. For ;processors faster than 16 MHz, add a second NOP.

BSF LCDE ;Set enable line NOP ;and pause for an extra 250ns BCF LCDE ;Reset the enable line RETURN ;Done!

Program Pull-Out ©1998 Sirius microSystems Microchip Code 23 References LCD4BIT.LIB - 4-bit Interface LCD Subroutine Library

;LCD4BIT.LIB v1.2 Last modified on August 31, 1998

;These program subroutines were written for the Sirius microSystems PICmicro ;development system. For more information contact Sirius microSystems by phone ;at 519-886-4462, or on the Internet at http://www.siriusmicro.com .

;Sirius microSystems provides this software on an “as is” basis, without any ;warranty, either expressed or implied. All Sirius microSystems software is ;provided for educational use only, and Sirius microSystems does not assume ;any liability for damages, either incidental or consequential, arising out of ;the application, use, or misuse of any of its software or hardware products. ;Sirius microSystems reserves the right, without further notice, to make ;changes to any of its software or hardware referred to in this program or ;library program in order to improve its function, design or reliability.

;Description

; This subroutine provides calls for LCD operation in 4-bit mode ; including: ; - Port Configuration ; - Register mode commands ; - LCD Busy check ; - LCD Enable toggle

;Variables

; LCDTemp - Temporary command byte storage register

;Requirements

; Two free levels of processor stack are required for nested calls.

; The LCD_Init subroutine requires a minimum 5ms delay to initialize ; the LCD. Delays longer than 5ms are acceptable. LCD_Init calls a ; subroutine by the name of Delay_5ms which must be included in your ; calling program. If your calling program contains a delay loop of ; longer than 5ms, you can use that delay by adding a Delay_5ms ; label before the routine.

;Use

; To initialize the LCD display after power-up: ; 1. Call LCD_Port to initialize Port A and Port B for the LCD display ; 2. Call LCD_Init to initialize the LCD controller

; To write a command or character to the LCD display: ; 1. Call LCD_Port to initialize Port A and Port B for the LCD display ; 2. Move an LCD command or ASCII character into W ; 3. Call LCD_Reg or LCD_Data to send the command or ; character to the LCD.

;LCD Hardware Equates

LCDRS EQU PORTA.0 ;LCD Register Select LCDRW EQU PORTA.1 ;LCD Read/~Write LCDE EQU PORTA.2 ;LCD Enable

;LCD Software Commands (Constants)

LCDLine1 EQU 80h ;Line 1 starting address LCDLine2 EQU 0C0h ;Line 2 starting address LCDCLR EQU 01h ;Clear Display, cursor home LCDHome EQU 02h ;Cursor home, DDRAM unchanged LCDInc EQU 06h ;Cursor increment mode LCDDec EQU 04h ;Cursor decrement mode LCDOn EQU 0Ch ;Display On

24 Microchip Code ©1998 Sirius microSystems LCD4BIT.LIB - 4-bit Interface LCD Subroutine Library

LCDOff EQU 08h ;Display Off CursOn EQU 0Eh ;Display On and Cursor On CursOff EQU 0Ch ;Display On and Cursor Off CursBlink EQU 0Fh ;Display On and Cursor Blinking LCDLeft EQU 18h ;Shift Display Left LCDRight EQU 1Ch ;Shift Display Right CursLeft EQU 10h ;Move Cursor Left CursRight EQU 14h ;Move Cursor Right LCDFunction EQU 28h ;4-bit function register init. command LCDInit EQU 38h ;LCD Initialization LCDCGRAM EQU 40h ;CGRAM starting address

LCD_Port ;Initializes the top 4 Port B tristate buffers as outputs for ;LCD data lines. Sets Port A to digital (on PIC16C711) and ;sets the LCD Register Select, Read/~Write, and Enable ;lines to outputs.

BSF RP0 ;Select memory register page 1

;the next two lines are for the PIC16C711 only and should be ;removed for the PIC16F84 (PM produces an error when this ;is assembled for the ’84).

;MOVLW 03h ;1’s set Port A to digital ;MOVWF ADCON1 ;Write W to ADCON1 (88h)

MOVLW 11111000b ;Set lower 3 bits of RA to ANDWF TRISA ;digital output in TRISA MOVLW 00001111b ;Set upper 4 bits of TRISB to ANDWF TRISB ;digital output BCF RP0 ;Go back to register page 0 BCF LCDE ;Keep LCD Enable line off RETURN ;Ports are now set up for LCD

LCD_Init ;LCD initialization instructions from the Optrex data book. ;Sets LCD functions for DMC16207 display, performs soft- ;ware reset, sets 4-bit mode, clears memory and turns the ;display on.

MOVLW LCDInit ;Load W with initialize LCD code CALL LCD_Reg_Init ;and send it to LCD CALL Delay_5ms ;...and wait MOVLW LCDInit ;Load W with initialize LCD code CALL LCD_Reg_Init ;and send it to LCD again CALL Delay_5ms ;...and wait MOVLW LCDInit ;Load W with initialize LCD code CALL LCD_Reg_Init ;and send it to LCD again CALL Delay_5ms ;...and wait MOVLW LCDFunction ;Load W with initialize 4-bit mode CALL LCD_Reg_Init ;and send it to LCD CALL Delay_5ms ;...and wait MOVLW LCDFunction ;Load W with initialize 4-bit mode CALL LCD_Reg ;and send it to LCD CALL Delay_5ms ;...and wait

;Change the constant in the next line to set how the display ;is activated. eg. LCDOn, CursOn, CursBlink. The Constant is ;from the LCD software commands, above.

MOVLW LCDOn ;Command for display on & cursor off CALL LCD_Reg ;Send it to LCD MOVLW LCDCLR ;Load W with clear LCD code CALL LCD_Reg ;and send it to LCD MOVLW LCDInc ;Load W with increment mode code CALL LCD_Reg ;and send it to LCD RETURN Program Pull-Out ©1998 Sirius microSystems Microchip Code 25 References LCD4BIT.LIB - 4-bit Interface LCD Subroutine Library

LCD_Reg_Init ;Used only for initialization prior to setting 4-bit mode. ;W is loaded with the 8-bit initialization string (38h) of ;which only the top 4 bits (3h) are sent to the LCD.

MOVWF LCDTemp ;Store command in temporary register MOVLW 0Fh ;Load W with value to clear ANDWF PORTB ;upper 4 bits of Port B BCF LCDRS ;Enter register mode MOVF LCDTemp,0 ;Load W with command byte ANDLW 11110000b ;Keep upper 4 bits of W and IORWF PORTB ;OR with PORT B GOTO LCD_Enable ;and send first nybble of command

LCD_Reg ;Load W with LCD software constant from table, above. ;LCD_Reg outputs the command to the LCD as two separate ;nybbles (first the upper 4 bits, then the lower 4 bits) and ;blips the enable line with LCD_Enable to finish the command.

MOVWF LCDTemp ;Store command byte in temp register MOVLW 0Fh ;Load W with value to clear ANDWF PORTB ;upper 4 bits of Port B BCF LCDRS ;Enter register mode MOVF LCDTemp,0 ;Load W with command byte ANDLW 11110000b ;Keep upper 4 bits of W and IORWF PORTB ;OR with PORT B CALL LCD_Check ;Check LCD busy flag CALL LCD_Enable ;and send first part of command MOVLW 0Fh ;Load W with value to clear ANDWF PORTB ;upper 4 bits of Port B SWAPF LCDTemp,0 ;Load W with lower nybble of command ANDLW 11110000b ;Keep upper 4 bits of W and IORWF PORTB ;OR with PORT B GOTO LCD_Enable ;Send second part of command & return

LCD_Data ;Load W with the ASCII character code to send to LCD. ;LCD_Data outputs the character to the LCD and blips ;the enable line with LCD_Enable to complete the send.

MOVWF LCDTemp ;Store data byte in temporary register MOVLW 0Fh ;Load W with value to clear ANDWF PORTB ;upper 4 bits of Port B BCF LCDRS ;Enter register mode MOVF LCDTemp,0 ;Load W with command byte ANDLW 11110000b ;Keep upper 4 bits of W and IORWF PORTB ;OR with PORT B CALL LCD_Check ;Check LCD busy flag BSF LCDRS ;Set RS to ASCII mode CALL LCD_Enable ;and send upper nybble of character MOVLW 0Fh ;Load W with value to clear ANDWF PORTB ;upper 4 bits of Port B BCF LCDRS ;Set RS to register mode SWAPF LCDTemp,0 ;Load W with lower nybble of command ANDLW 11110000b ;Keep upper 4 bits of W and IORWF PORTB ;OR with PORT B BSF LCDRS ;Set RS to ASCII mode GOTO LCD_Enable ;Send second part of command & return

LCD_Check ;Checks the state of the LCD Busy flag and waits for any ;previous command to finish before returning to the ;calling routine.

BSF LCDRW ;Set LCD read mode BSF RP0 ;Select memory page 1

26 Microchip Code ©1998 Sirius microSystems LCD4BIT.LIB - 4-bit Interface LCD Subroutine Library

MOVLW 0F0h ;Set upper 4 bits of Port B to input IORWF TRISB ;in tristate buffers by ORing BCF RP0 ;Back to memory page 0 BSF LCDE ;Enable LCD NOP ;and wait for an extra cycle :Loop BTFSC PORTB.7 ;Check LCD busy bit and GOTO :Loop ;wait if high. (Busy=1) BCF LCDE ;Disable LCD BSF RP0 ;Select memory page 1 MOVLW 0Fh ;Set upper 4 bits of Port B back to ANDWF TRISB ;output by ANDing BCF RP0 ;Back to memory page 0 BCF LCDRW ;Back to LCD write mode RETURN ;LCD is now free

LCD_Enable ;Sends a 500 ns enable pulse to the LCD to complete the ;register or character write operation. The NOP instruction ;is only required for processors faster than 8 MHz. For ;processors faster than 16 MHz, add a second NOP.

BSF LCDE ;Set enable line NOP ;and pause for an extra 250ns BCF LCDE ;Reset the enable line RETURN ;Done!

Program Pull-Out ©1998 Sirius microSystems Microchip Code 27 References LCD71.LIB - PIC16C71/711 LCD Subroutine Library

;LCD71.LIB v1.2 Last modified on August 31, 1998

;These program subroutines were written for the Sirius microSystems PICmicro ;development system. For more information contact Sirius microSystems by phone ;at 519-886-4462, or on the Internet at http://www.siriusmicro.com .

;Sirius microSystems provides this software on an “as is” basis, without any ;warranty, either expressed or implied. All Sirius microSystems software is ;provided for educational use only, and Sirius microSystems does not assume ;any liability for damages, either incidental or consequential, arising out of ;the application, use, or misuse of any of its software or hardware products. ;Sirius microSystems reserves the right, without further notice, to make ;changes to any of its software or hardware referred to in this program or ;library program in order to improve its function, design or reliability.

;Description

; This subroutine provides calls for PIC16C711 LCD operation including: ; - Port Configuration ; - Register mode commands ; - LCD Busy check ; - LCD Enable toggle

;Variables

; None

;Requirements

; Two free levels of processor stack are required for nested calls.

; The LCD_Init subroutine requires a minimum 5ms delay to initialize ; the LCD. Delays longer than 5ms are acceptable. LCD_Init calls a ; subroutine by the name of Delay_5ms which must be included in your ; calling program. If your calling program contains a delay loop of ; longer than 5ms, you can use that delay by adding a Delay_5ms ; label before the routine.

;Use

; To initialize the LCD display after power-up: ; 1. Call LCD_Port to initialize Port A and Port B for the LCD display ; 2. Call LCD_Init to initialize the LCD controller

; To write a command or character to the LCD display: ; 1. Call LCD_Port to initialize Port A and Port B for the LCD display ; 2. Move an LCD command or ASCII character into W ; 3. Call LCD_Reg or LCD_Data to send the command or ; character to the LCD.

;LCD Hardware Equates

LCDRS EQU PORTA.0 ;LCD Register Select LCDRW EQU PORTA.1 ;LCD Read/~Write LCDE EQU PORTA.2 ;LCD Enable

;LCD Software Commands (Constants)

LCDLine1 EQU 80h ;Line 1 starting address LCDLine2 EQU 0C0h ;Line 2 starting address LCDCLR EQU 01h ;Clear Display, cursor home LCDHome EQU 02h ;Cursor home, DDRAM unchanged LCDInc EQU 06h ;Cursor increment mode LCDDec EQU 04h ;Cursor decrement mode LCDOn EQU 0Ch ;Display On LCDOff EQU 08h ;Display Off

28 Microchip Code ©1998 Sirius microSystems LCD71.LIB - PIC16C71/711 LCD Subroutine Library

CursOn EQU 0Eh ;Display On and Cursor On CursOff EQU 0Ch ;Display On and Cursor Off CursBlink EQU 0Fh ;Display On and Cursor Blinking LCDLeft EQU 18h ;Shift Display Left LCDRight EQU 1Ch ;Shift Display Right CursLeft EQU 10h ;Move Cursor Left CursRight EQU 14h ;Move Cursor Right LCDFunction EQU 38h ;8-bit function register init. command LCDInit EQU 38h ;LCD initialization command LCDCGRAM EQU 40h ;CGRAM starting address

LCD_Port ;Initializes the Port B tristate buffers as outputs for ;LCD data lines. Sets Port A to digital (on PIC16C711) and ;sets the LCD Register Select, Read/~Write, and Enable ;lines to outputs.

BSF RP0 ;Select memory register page 1

;the next two lines are for the PIC16C711 only and should be ;removed for the PIC16F84 (PM produces an error when this ;is assembled for the ’84).

MOVLW 03h ;1’s set Port A to digital MOVWF ADCON1 ;Write W to ADCON1 (88h)

MOVLW 11111000b ;Set lower 3 bits of RA to ANDWF TRISA ;digital output in TRISA CLRF TRISB ;Set Port B to output BCF RP0 ;Go back to register page 0 BCF LCDE ;Keep LCD Enable line off RETURN ;Ports are now set up for LCD

LCD_Init ;LCD initialization instructions from the Optrex data book. ;Sets LCD functions for DMC16207 display, performs soft- ;ware reset, clears memory and turns the display on.

MOVLW LCDInit ;Load W with initialize LCD code CALL LCD_Reg_Init ;and send it to LCD CALL Delay_5ms ;...and wait MOVLW LCDInit ;Load W with initialize LCD code CALL LCD_Reg_Init ;and send it to LCD again CALL Delay_5ms ;...and wait MOVLW LCDInit ;Load W with initialize LCD code CALL LCD_Reg_Init ;and send it to LCD again CALL Delay_5ms ;...and wait MOVLW LCDFunction ;Load W with initialize 8-bit code CALL LCD_Reg ;and send it to LCD CALL Delay_5ms ;...and wait

;Change the constant in the next line to set how the display ;is activated. eg. LCDOn, CursOn, CursBlink. The Constant is ;from the LCD software commands, above.

MOVLW LCDOn ;Command for display on & cursor off

CALL LCD_Reg ;Send it to LCD MOVLW LCDCLR ;Load W with clear LCD code CALL LCD_Reg ;and send it to LCD MOVLW LCDInc ;Load W with increment mode code CALL LCD_Reg ;and send it to LCD RETURN

LCD_Reg_Init ;Used only for initialization prior to setting function ;register. In this time, the LCD busy flag cannot be checked. Program Pull-Out ©1998 Sirius microSystems Microchip Code 29 References LCD71.LIB - PIC16C71/711 LCD Subroutine Library

BCF LCDRS ;Enter register mode MOVWF PORTB ;and send W to LCD reg. on Port B GOTO LCD_Enable ;Send register command

LCD_Reg ;Load W with LCD software constant from table, above. ;LCD_Reg outputs the command to the LCD and blips the ;enable line with LCD_Enable to complete the command.

BCF LCDRS ;Enter register mode MOVWF PORTB ;and send W to LCD reg. on Port B CALL LCD_Check ;Check LCD busy flag GOTO LCD_Enable ;Send register command

LCD_Data ;Load W with the ASCII character code to send to LCD. ;LCD_Data outputs the character to the LCD and blips ;the enable line with LCD_Enable to complete the send.

BCF LCDRS ;Enter register mode MOVWF PORTB ;and send W to LCD on Port B CALL LCD_Check ;Check LCD busy flag BSF LCDRS ;Enter ASCII mode GOTO LCD_Enable ;Send ASCII character

LCD_Check ;Checks the state of the LCD Busy flag and waits for any ;previous command to finish before returning to the ;calling routine.

BSF LCDRW ;Set LCD read mode BSF RP0 ;Select memory page 1 MOVLW 0FFh ;Set Port B to input and MOVWF TRISB ;disable tristate buffers BCF RP0 ;Back to memory page 0 BSF LCDE ;Enable LCD NOP ;and wait for an extra cycle :Loop BTFSC PORTB.7 ;Check LCD busy bit and GOTO :Loop ;wait if high. (Busy=1) BCF LCDE ;Disable LCD BSF RP0 ;Select memory page 1 CLRF TRISB ;Set Port B to output BCF RP0 ;Back to memory page 0 BCF LCDRW ;Back to LCD write mode RETURN ;LCD is now free

LCD_Enable ;Sends a 500 ns enable pulse to the LCD to complete the ;register or character write operation. The NOP instruction ;is only required for processors faster than 8 MHz. For ;processors faster than 16 MHz, add a second NOP.

BSF LCDE ;Set enable line NOP ;and pause for an extra 250ns BCF LCDE ;Reset the enable line RETURN ;Done!

30 Microchip Code ©1998 Sirius microSystems RS232RX.LIB - RS-232 Receive Subroutine Library

;RS232RX.LIB v1.2 Last modified on August 31, 1998

;These program subroutines were written for the Sirius microSystems PICmicro ;development system. For more information contact Sirius microSystems by phone ;at 519-886-4462, or on the Internet at http://www.siriusmicro.com .

;Sirius microSystems provides this software on an “as is” basis, without any ;warranty, either expressed or implied. All Sirius microSystems software is ;provided for educational use only, and Sirius microSystems does not assume ;any liability for damages, either incidental or consequential, arising out of ;the application, use, or misuse of any of its software or hardware products. ;Sirius microSystems reserves the right, without further notice, to make ;changes to any of its software or hardware referred to in this program or ;library program in order to improve its function, design or reliability.

;Description

; This subroutine provides calls for the PIC-MDS to receive RS-232 ; characters through the serial header (H3), including: ; - variable Baud rates and data bits ; - receive bit setup ; - wait for a serial start bit ; - receive a serial character

;Variables

; Each of the variables below must be equated to a file register by ; the calling program: ; ; Counter - Used by bit time delay loop ; BitCounter - Counts number of received bits ; Receive - Stores the received serial byte

;Requirements

; Two free levels of processor stack for nested subroutine calls ; ; An external RS-232 serial terminal or a computer with an appropriate ; connection to the PIC-MDS serial input header (H3). For testing we ; used a cable wired as follows and communicated with the MS Windows ; Terminal program in Windows for Work Groups 3.11: ; ; Computer DB-25 PIC-MDS ; Transmit pin 2 —> H3.3 - Rx ; Receive pin 3 —> H3.1 - Tx ; Ground pin 7 —> H3.2 - Gnd

;Use

; To receive serial characters: ; 1. Call Receive_Port to initialize PortA.4 as an input ; 2. Call Receive_Wait to wait for and receive one serial byte ; 3. (Optional) Check the Receive register for 00h indicating a ; serial framing error has occurred.

; Since PortA.4 is the serial input and the input for TMR0, this ; serial library can be interrupt enabled. To receive via TMR0 ; interrupts, do the following: ; 1. Enable TMR0 interrupt (see Chapter 11), with external input, ; no prescaler, and falling-edge trigger ; 2. Pre-load TMR0 with FFh. The next falling edge on PortA.4 ; increments TMR0 to 00h generating an interrupt. ; 3. Enable GIE (Global Interrupt Enable) ; 4. When a TMR0 interrupt is generated, have your ISR Call ; Receive_Data to receive the character. Depending on the Baud Program Pull-Out ©1998 Sirius microSystems Microchip Code 31 References RS232RX.LIB - RS-232 Receive Subroutine Library

; rate and the number of cycles of your ISR, you may have to ; adjust the value of Half_Bit. Reduce Half_Bit by one for every ; four cycles of code taken by your ISR.

;RS232RX.LIB Hardware Equates for PIC-MDS

Serial_Input EQU PORTA.4 ;Serial input pin on PIC-MDS

;Software Equates

; DataBits and Bit_Time may be commented out to allow the calling ; program to select equates governing the number of data bits as ; well as the received baud rate. Or, change DataBits and Bit_Time ; below to your defaults.

DataBits EQU 08h ;8 data bits

;Set Bit_Time, below, with a value from the table corresponding to your ;PIC’s clock speed and the serial Baud rate required. To ensure accurate ;serial bit timing, use a crystal oscillator and not a ceramic resonator ;or RC combination to generate the processor clock.

;+------+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+ ;|Clk\ Bd| 300 | 600 | 1200| 2400| 4800| 9600|14400|19200|28800|38400|57600| ;+------+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+ ;| 1 MHz | 0CEh| 65h | 31h | 17h | 0Ah | 04h*| --- | --- | --- | --- | --- | ;| 2 MHz | --- | 0CEh| 65h | 31h | 17h | 0Ah | 06h | 04h*| --- | --- | --- | ;| 4 MHz | --- | --- | 0CEh| 65h | 31h | 17h | 0Fh | 0Ah | 06h | 04h*| --- | ;| 8 MHz | --- | --- | --- | 0CEh| 65h | 31h | 20h | 17h | 0Fh | 0Ah | 06h | ;| 10 MHz| --- | --- | --- | FFh*| 7Fh | 3Eh | 29h | 1Eh | 13h | 0Eh | 08h | ;| 16 MHz| --- | --- | --- | --- | 0CEh| 65h | 43h | 31h | 20h | 17h | 0Fh | ;| 20 MHz| --- | --- | --- | --- | FFh*| 7Fh | 54h | 3Eh | 29h | 1Eh | 13h | ;+------+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+ ;*Timing inaccuracies using these delay constants may cause serial errors.

Bit_Time EQU 3Eh ;Serial Bit delay from table above Half_Bit EQU Bit_Time/2 ;Half of the Bit delay

Receive_Port ;Sets PORTA.4 to input. Make sure PIC-MDS JU5 is set to Rx!

BSF RP0 ;Select memory register page 1 MOVLW 00010000b ;Load W with bit to make RA.4 input IORWF TRISA ;and OR with Port A tristate reg. BCF RP0 ;Return to memory register page 0 RETURN

Receive_Wait ;Waits for an RS-232 start bit indicated by RA.4 going low.

BTFSC Serial_Input ;Check serial input pin GOTO Receive_Wait ;If high, wait for low

Receive_Data ;Delay for half the Bit_Time and confirm the presence of the ;start bit. Then wait for Bit_Time and read each bit into ;Carry. Rotate Carry into the Receive byte and repeat the ;delay, Carry and rotate until number of DataBits have been ;received. The Receive register stores the received byte. If ;framing error occurs (only a simple check for a stop bit is ;done) the contents of the Receive register will be 00h.

MOVLW DataBits ;Load W with number of data bits MOVWF BitCounter ;and save in BitCounter register MOVLW Half_Bit ;Load W with half of bit delay time CALL BitDelay ;and wait for 1/2 bit BTFSC Serial_Input ;Check for low start bit again

32 Microchip Code ©1998 Sirius microSystems RS232RX.LIB - RS-232 Receive Subroutine Library

GOTO Receive_Data ;If high, error occurred-keep waiting

:Next_Bit MOVLW Bit_Time ;Load W with bit delay time CALL BitDelay ;and wait until middle of next bit BTFSS Serial_Input ;Check serial input pin for 1 BCF C ;If serial input is 0, clear Carry BTFSC Serial_Input ;Check serial input pin for 0 BSF C ;If serial input is 1, set Carry RRF Receive ;Rotate Carry into received data byte DECFSZ BitCounter ;Decrement bit counter & check for 0 GOTO :Next_Bit ;If not 0, get the next bit

MOVLW Bit_Time ;Load W with bit delay time CALL BitDelay ;and wait until middle of stop bit BTFSS Serial_Input ;Check for high stop bit GOTO Receive_Error ;If low, we have a framing error RETURN ;Otherwise, return

Receive_Error ;Simply clears Receive buffer if no stop bit is found.

CLRF Receive ;If a framing error occurs, clear RETURN ;Receive register before returning

BitDelay ;RS-232 Bit time period delay

MOVWF Counter ;Move delay time in W to Counter :Loop NOP ;Pad loop to 4 cycles DECFSZ Counter,1 ;Decrement bit counter GOTO :Loop ;and do it until zero RETURN

Program Pull-Out ©1998 Sirius microSystems Microchip Code 33 References RS232TX.LIB - RS-232 Transmit Subroutine Library

;RS232TX.LIB v1.2 Last modified on August 31, 1998

;These program subroutines were written for the Sirius microSystems PICmicro ;development system. For more information contact Sirius microSystems by phone ;at 519-886-4462, or on the Internet at http://www.siriusmicro.com .

;Sirius microSystems provides this software on an “as is” basis, without any ;warranty, either expressed or implied. All Sirius microSystems software is ;provided for educational use only, and Sirius microSystems does not assume ;any liability for damages, either incidental or consequential, arising out of ;the application, use, or misuse of any of its software or hardware products. ;Sirius microSystems reserves the right, without further notice, to make ;changes to any of its software or hardware referred to in this program or ;library program in order to improve its function, design or reliability.

;Description

; This subroutine provides calls for the PIC-MDS to transmit RS-232 ; characters through the serial header (H3), including: ; - variable Baud rates and data bits ; - selectable transmit pin ; - transmit a serial character

;Variables

; Each of the variables below must be equated to a file register by ; the calling program: ; ; Counter - Used by bit time delay loop ; BitCounter - Counts number of transmitted bits ; Transmit - Stores the serial byte to be transmitted

;Requirements

; Two free levels of processor stack for nested subroutine calls ; ; An external RS-232 serial terminal or a computer with an appropriate ; connection to the PIC-MDS serial input header (H3). For testing we ; used a cable wired as follows and communicated with the MS Windows ; Terminal program in Windows for Work Groups 3.11: ; ; Computer DB-25 PIC-MDS ; Transmit pin 2 —> H3.3 - Rx ; Receive pin 3 —> H3.1 - Tx ; Ground pin 7 —> H3.2 - Gnd

;Use

; To transmit serial characters: ; 1. Call Transmit_Port to initialize PortA.4 as an output ; 2. Move the data byte to be sent to the Transmit register ; 3. Call Transmit_Data to send the serial byte

;RS232RX.LIB Hardware Equates for PIC-MDS

Serial_Output EQU PORTA.4 ;Serial input pin on PIC-MDS

;Software Equates

; DataBits and Bit_Time may be commented out to allow the calling ; program to select equates governing the number of data bits as ; well as the transmit baud rate. Or, change DataBits and Bit_Time

34 Microchip Code ©1998 Sirius microSystems RS232TX.LIB - RS-232 Transmit Subroutine Library

; below to your defaults.

DataBits EQU 08h ;8 data bits

;Set Bit_Time, below, with a value from the table corresponding to your ;PIC’s clock speed and the serial Baud rate required. To ensure accurate ;serial bit timing, use a crystal oscillator and not a ceramic resonator ;or RC combination to generate the processor clock.

;+------+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+ ;|Clk\ Bd| 300 | 600 | 1200| 2400| 4800| 9600|14400|19200|28800|38400|57600| ;+------+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+ ;| 1 MHz | 0CEh| 65h | 31h | 17h | 0Ah | 04h*| --- | --- | --- | --- | --- | ;| 2 MHz | --- | 0CEh| 65h | 31h | 17h | 0Ah | 06h | 04h*| --- | --- | --- | ;| 4 MHz | --- | --- | 0CEh| 65h | 31h | 17h | 0Fh | 0Ah | 06h | 04h*| --- | ;| 8 MHz | --- | --- | --- | 0CEh| 65h | 31h | 20h | 17h | 0Fh | 0Ah | 06h | ;| 10 MHz| --- | --- | --- | FFh*| 7Fh | 3Eh | 29h | 1Eh | 13h | 0Eh | 08h | ;| 16 MHz| --- | --- | --- | --- | 0CEh| 65h | 43h | 31h | 20h | 17h | 0Fh | ;| 20 MHz| --- | --- | --- | --- | FFh*| 7Fh | 54h | 3Eh | 29h | 1Eh | 13h | ;+------+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+ ;*Timing inaccuracies using these delay constants may cause serial errors.

Bit_Time EQU 03Eh ;Serial Bit delay from table above Half_Bit EQU Bit_Time/2 ;Half of the Bit delay

Transmit_Port ;Sets PORTA.4 to output. Make sure PIC-MDS JU5 is set to Tx!

BSF RP0 ;Select memory register page 1 MOVLW 00001111b ;Load W with bit to make RA.4 output ANDWF TRISA ;and OR with Port A tristate reg. BCF RP0 ;Return to memory register page 0 BSF Serial_Output ;Set serial line high RETURN

Transmit_Data ;Drop PortA.4 from high to low to indicate the Start Bit and ;delay for one Bit_Time. Rotate the Transmit buffer right ;into Carry and set or clear the serial output pin based on ;Carry. Wait for another bit time and continue rotating and ;transmitting until all eight bits have been sent. Finally, ;send a stop bit.

MOVWF Transmit ;Save character in W to buffer MOVLW DataBits ;Load W with number of data bits MOVWF BitCounter ;and save in BitCounter register BCF Serial_Output ;Send Start bit NOP ;and pad routine to be same length NOP ;as :Next_Bit code so Bit_Time is NOP ;accurate NOP NOP NOP NOP

:Next_Bit MOVLW Bit_Time ;Load W with bit delay time CALL BitDelay ;and wait one bit duration RRF Transmit ;Rotate Transmit byte into C BTFSS C ;Check Carry for a 1 BCF Serial_Output ;If C=0, clear serial output BTFSC C ;Check Carry for a 0 BSF Serial_Output ;If C=1, set serial output DECFSZ BitCounter ;Decrement bit counter & check for 0 GOTO :Next_Bit ;If not 0, get the next bit

MOVLW Bit_Time ;Load W with bit delay time CALL BitDelay ;and wait until end of last bit BSF Serial_Output ;Set serial line high for Stop bit Program Pull-Out ©1998 Sirius microSystems Microchip Code 35 References RS232TX.LIB - RS-232 Transmit Subroutine Library

MOVLW Bit_Time ;Load W with bit delay time CALL BitDelay ;and wait a bit RETURN

BitDelay ;RS-232 Bit time period delay

MOVWF Counter ;Move delay time in W to Counter :Loop NOP ;Pad loop to 4 cycles DECFSZ Counter,1 ;Decrement bit counter GOTO :Loop ;and do it until zero RETURN

36 Microchip Code ©1998 Sirius microSystems SEEPROM.LIB - Serial EEPROM Subroutine Library

;SEEPROM.LIB v1.2 Last modified on August 31, 1998

;These program subroutines were written for the Sirius microSystems PICmicro ;development system. For more information contact Sirius microSystems by phone ;at 519-886-4462, or on the Internet at http://www.siriusmicro.com .

;Sirius microSystems provides this software on an “as is” basis, without any ;warranty, either expressed or implied. All Sirius microSystems software is ;provided for educational use only, and Sirius microSystems does not assume ;any liability for damages, either incidental or consequential, arising out of ;the application, use, or misuse of any of its software or hardware products. ;Sirius microSystems reserves the right, without further notice, to make ;changes to any of its software or hardware referred to in this program or ;library program in order to improve its function, design or reliability.

;Description

; This subroutine provides calls to access the 93LC56 or 93LC66 Serial ; EEPROM (SEEPROM) for long-term data or variable storage. Serial EEPROMs ; are non-volatile and maintain their data even while power is off. The ; SEEPROM connects to the PIC microcontroller using three wires: Chip ; Select (SEECS), Clock (SEECLK) and Data In/Data Out (SEEDIDO).

; To write a byte to the SEEPROM, the PIC must serially transmit a start ; bit, a command op-code, a storage address, and data on SEEDIDO while ; toggling SEECLK. To read data back from the SEEPROM, the PIC clocks out ; the start bit, the command op-code, the storage address, and then keeps ; toggling SEECLK while reading the data on SEEDIDO.

; A full frame of serial data is shown below. Full frames are used by the ; Read, Write and Write All commands. The other four commands, Erase, ; Erase All, Erase-Write Enable, and Erase-Write Disable use a partial ; data frame and omit the data bits.

; +--+---+---+----+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ ; |SB|OP1|OP0|X/A8|A7|A6|A5|A4|A3|A2|A1|A0|D7|D6|D5|D4|D3|D2|D1|D0| ; +--+---+---+----+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ ; |<- partial frame for non-data instr. ->| ; |<- full frame for data instruction ->|

; SB=Start bit, OPn=Op-code bit, An=Address bit, Dn=Data bit, X=don’t care

; The presence of the A8 bit allows addressing of up to 512 bytes. Because ; the size of the data frame is constant, addressing a 256 byte SEEPROM ; requires a don’t care bit (X) to be transmitted in place of A8.

; +------+------+----+------+ ; |SEEPROM| Size X Org. | A8 | A7-A0 | ; +------+------+----+------+ ; |93LC56 | 256 X 8-bit | X | Valid Address | ; +------+------+----+------+ ; |93LC66 | 512 X 8-bit | Valid Address | ; +------+------+----+------+

; These subroutines support the 93LC56 (256 byte) and 93LC66 (512 byte) ; SEEPROMs, in 8-bit data mode (X8 organization) only, and include ; subroutines for: ; - Port configuration ; - SEEPROM erase or write enable and disable ; - SEEPROM data write to a specific SEEPROM address ; - SEEPROM data read from a specific SEEPROM address ; - SEEPROM global write and erase ; - Wait for SEEPROM Erase/Write completion

; 16-bit data mode (X16 organization) is not supported. For 16-bit ; mode, modify the SEE_Clk subroutine according to the Microchip Data ; book for the 93LC46/56/66 series of serial SEEPROMs. Program Pull-Out ©1998 Sirius microSystems Microchip Code 37 References SEEPROM.LIB - Serial EEPROM Subroutine Library

;Variables

; The following variables must be defined by the calling program:

; SEEClock - SEEPROM serial clock counter register ; SEEData - Data byte storage register ; SEEAddrh - SEEPROM high address register ; SEEAddrl - SEEPROM low address register

;Requirements

; These routines require two levels of processor stack as well as the ; variables defined above.

;Use

; To set up Port A for Serial EEPROM use: ; 1. Call SEE_Port

; To read data from or to write data or a command to the Serial EEPROM: ; 1. Load low address byte into SEEAddrl or clear SEEAddrl ; 2. Load high address byte into SEEAddrh or clear SEEAddrh ; 3. For a data write operation, load data byte into SEEData ; 4. Move the SEEPROM Command Op-code into W using a MOVLW instruction ; 5. CALL SEE_Command ; 6. For a data read operation, retrieve the data byte from SEEData

; To wait for the completion of a write operation: ; 1. CALL SEE_Wait. A RETURN is issued when the SEEPROM operations are ; complete. Typical ERASE and WRITE operations take 4 ms to complete, ; ERAL takes 8 ms, and WRAL takes 16 ms.

;SEEPROM Commands

; Below is a list of the SEEPROM Command Op-codes indicating which ones ; require a valid address and the direction of data transfer:

; Op XOP Address Bits ; Code Code Instruction Description X/A8 A7 A6-A0 Data Bits ; ------; 00 00 EWDS -Erase/Write Disable XOP XOP X - ; 00 01 WRAL -Write All XOP XOP X to SEEPROM ; 00 10 ERAL -Erase All XOP XOP X - ; 00 11 EWEN -Erase/Write Enable XOP XOP X - ; 01 WRITE -byte to address X/A8 A7 A6-A0 to SEEPROM ; 10 READ -byte from address X/A8 A7 A6-A0 from SEEPROM ; 11 ERASE -contents of address X/A8 A7 A6-A0 -

; Note that for all 00 Op-Codes, a two bit extended op-code (XOP) takes ; the place of the A8 and A7 bits. The remaining address bits are don’t ; care bits, but must be transmitted to complete the instruction.

;SEEPROM Hardware Equates

SEECLK EQU PORTA.0 ;SEEPROM Serial Clock pin SEEDIDO EQU PORTA.1 ;SEEPROM Data In and Data Out pins SEECS EQU PORTA.3 ;SEEPROM Chip Select pin

;SEEPROM Software Commands (Constants)

SEERead EQU 0C0h ;Read data op-code SEEEWEN EQU 9Ch ;Erase/Write Enable op-code SEEErase EQU 0E0h ;Erase data op-code SEEERAL EQU 94h ;Erase All op-code

38 Microchip Code ©1998 Sirius microSystems SEEPROM.LIB - Serial EEPROM Subroutine Library

SEEWrite EQU 0A0h ;Write data op-code SEEWRAL EQU 8Ch ;Write All op-code SEEEWDS EQU 84h ;Erase/Write Disable op-code

SEE_Port ;Configures Port A to digital (on PIC16C71), sets the SEEPROM ;Chip Select and Serial Clock lines to output, and sets the ;Data line to input. Chip Select is left de-activated.

MOVLW 14h ;Make sure SEECS, SEECLK and SEEDIDO ANDWF PORTA ;pins are 0 before making them outputs BSF RP0 ;Select memory page 1

;Remove comments from the following two lines if your program ;uses the PIC16C71 with the A/D converter enabled. ;MOVLW 03h ;1’s set Port A to digital, ;MOVWF ADCON1 ;write to ADCON1 (88h)

MOVLW 14h ;Set SEECS, SEECLK & SEEDIDO pins of ANDWF TRISA ;Port A to digital output BCF RP0 ;Select memory page 0 RETURN

SEE_Command ;This subroutine parses the SEEPROM command op-code, completes ;op-code formatting and calls the appropriate routine to clock ;the op-code, address, and data (if necessary) to the SEEPROM.

;The op-code command is stored in the upper 4-6 bits of SEEAddrh ;according to the diagram shown below. For non-extended op- ;codes, SEEAddrh stores the Start-Bit, two Op-code bits and A8. ;The top four bits of SEEAddrh and the contents of SEEAddrl are ;later shifted out to the SEEPROM by the SEE_Clk subroutine, ;which transmits these as a partial serial data frame.

; SEEAddrh SEEAddrl ;+--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ ;|SB|OP|OP|A8| | | | | |A7|A6|A5|A4|A3|A2|A1|A0| ;+--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+

;For extended op-codes, SEEAddrh stores the Start-Bit, four Op- ;code bits (two op-code bits, plus two extended op-code bits) ;and a flag bit (7B) indicating that only 7 dummy address bits ;need to be sent. In this case, SEE_Clk transmits the upper five ;bits of SEEAddrh and the lower seven bits of SEEAddrl.

; SEEAddrh SEEAddrl ;+--+--+--+---+---+--+--+--+ +--+--+--+--+--+--+--+--+ ;|SB|OP|OP|XOP|XOP|7B| | | |A7|A6|A5|A4|A3|A2|A1|A0| ;+--+--+--+---+---+--+--+--+ +--+--+--+--+--+--+--+--+

IORWF SEEAddrh ;Store command to top bits of SEEAddrh BTFSS SEEAddrh.6 ;Check bit 6 for a 1 GOTO :Check_5 ;If 0, find command by checking bit 5 CALL SEE_SetA8 ;Set A8 and counter for SEEAddrh BTFSS SEEAddrh.5 ;Check bit 5 for a 1 GOTO SEE_Read ;If 0, goto SEEPROM Read routine CALL SEE_Clk ;Do clocking for ERASE instruction GOTO SEE_Done ;and clean up before Returning

:Check_5 MOVLW 05h ;Load W with 5 to shift 5 top bits of MOVWF SEEClock ;SEEAddrh during clocking BTFSS SEEAddrh.5 ;Check bit 5 for 1 GOTO :Check_4 ;If bit 5=0, check bit 4 CALL SEE_SetA8 ;Otherwise, set counter and A8 for GOTO SEE_Write ;SEEPROM WRITE instruction Program Pull-Out ©1998 Sirius microSystems Microchip Code 39 References SEEPROM.LIB - Serial EEPROM Subroutine Library

:Check_4 BTFSS SEEAddrh.4 ;If 0, check bit 4 for a 1 GOTO :Check_3 ;If bit4=0, check bit 3 CALL SEE_Clk ;If bit4=1, send EWEN or ERAL commands GOTO SEE_Done ;and clean up before Returning

:Check_3 BTFSC SEEAddrh.3 ;Check bit3 for a 0 GOTO SEE_Write ;If bit3=1, WRAL using SEEPROM Write CALL SEE_Clk ;otherwise, send EWDS command and GOTO SEE_Done ;clean up before Returning

SEE_SetA8 ;Moves A8 bit from bit position 0 of SEEAddrh to bit 4 and ;sets SEEClock to 4 to clock out top 4 bits of SEEAddrh only:

; SEEAddrh ; +--+--+--+--+--+--+--+--+ ; |SB|OP|OP|A8| | | |A8| <-original A8 gets moved to bit 4 ; +--+--+--+--+--+--+--+--+

MOVLW 04h ;Load W with 4 to shift only top 4 MOVWF SEEClock ;bits of SEEAddrh during clocking BTFSS SEEAddrh.0 ;Check A8 bit for a 1 RETURN ;If A8=0, Return BSF SEEAddrh.4 ;otherwise, move A8 bit from 0 to 4 RETURN

SEE_Read ;Reads the byte from the specified address location of the ;SEEPROM into the SEEData register.

CALL SEE_Clk ;Clock op-code and address to SEEPROM

BSF RP0 ;Select memory register page 1 MOVLW 00000010b ;and load W with 00000010b to IORWF TRISA ;set SEEDIDO line to input BCF RP0 ;Return to register page 0 MOVLW 08h ;Load the clock counter with 8 MOVWF SEEClock ;to clock data out of SEEPROM CLRF SEEData ;Clear Data receive byte before read

:ClkData BSF SEECLK ;Set serial clock to read bits NOP ;and wait for data output to settle BTFSS SEEDIDO ;Check SEEPROM Data Out for a 1 BCF C ;If DO=0, clear Carry BTFSC SEEDIDO ;Check SEEPROM Data Out for a 0 BSF C ;If DO=1, set Carry BCF SEECLK ;Clear SEECLK line RLF SEEData ;Shift Carry into SEEData register DECFSZ SEEClock ;Decrement clock counter to clock in GOTO :ClkData ;all 8 bits of SEEData

BCF SEECS ;Disable SEEPROM Chip Select

GOTO SEE_Port ;Return after re-enabling outputs

SEE_Write ;Stores the byte in SEEData to the address in the SEEPROM ;specified by SEEAddrh and SEEAddrl.

CALL SEE_Clk ;Clock Op-code and address to SEEPROM

MOVLW 08h ;Load the clock counter with 8 to MOVWF SEEClock ;clock out 8 data bits from SEEData

:ClkData BCF SEECLK ;Clear serial clock between bits RLF SEEData ;Rotate high bit of SEEData into C BTFSS C ;Check Carry for a 1 BCF SEEDIDO ;If C=0, clear SEEPROM Data line

40 Microchip Code ©1998 Sirius microSystems SEEPROM.LIB - Serial EEPROM Subroutine Library

BTFSC C ;Check Carry for a 0 BSF SEEDIDO ;If C=1, set SEEPROM Data line NOP ;and wait for it to settle BSF SEECLK ;Clock bit in by setting SEECLK DECFSZ SEEClock ;Decrement clock counter to clock out GOTO :ClkData ;all 8 bits of SEEData

BCF SEECLK ;Clear SEEPROM Serial Clock and GOTO SEE_Done ;clean up before Returning

SEE_Clk ;This subroutine writes the Start bit, Op-code and Address to ;the SEEPROM by serially shifting SEEAddrh and SEEAddrl into ;the SEEPROM. The calling routine determines how many bits ;of SEEAddrh are transmitted.

BCF SEECLK ;Ensure SEEPROM serial clock is clear BSF SEECS ;before enabling SEEPROM Chip Select

:ClkAddrh BCF SEECLK ;Clear serial clock between bits RLF SEEAddrh ;Rotate high bit of SEEAddrh into C BTFSS C ;Check Carry for a 1 BCF SEEDIDO ;If C=0, clear SEEPROM Data line BTFSC C ;Check Carry for a 0 BSF SEEDIDO ;If C=1, set SEEPROM Data line NOP ;and wait for it to settle BSF SEECLK ;Clock bit in by setting SEECLK DECFSZ SEEClock ;Decrement clock counter to clock out GOTO :ClkAddrh ;the top 4 bits of the instruction

MOVLW 08h ;If SEEClock was 0, reload the clock MOVWF SEEClock ;counter with 8 for SEEAddrl RLF SEEAddrh ;Rotate SEEAddrh once more to check BTFSC C ;C for the 7-bit dummy address flag DECF SEEClock ;If 7B flag set, decrement bit counter

:ClkAddrl BCF SEECLK ;Clear serial clock between bits RLF SEEAddrl ;Rotate high bit of SEEAddrl into C BTFSS C ;Check Carry for a 1 BCF SEEDIDO ;If C=0, clear SEEPROM Data line BTFSC C ;Check Carry for a 0 BSF SEEDIDO ;If C=1, set SEEPROM Data line NOP ;and wait for it to settle BSF SEECLK ;Clock bit in by setting SEECLK DECFSZ SEEClock ;Decrement clock counter to clock out GOTO :ClkAddrl ;all 8 bits of SEEAddrl

BCF SEECLK ;Clear SEEPROM serial clock to finish RETURN

SEE_Done ;It is important that the upper bits of SEEAddrh are cleared ;before initiating a new SEEPROM command. To save a calling ;program from clearing SEEAddrh between successive commands, ;SEEAddrh and SEEAddrl are automatically cleared after de- ;selecting the SEEPROM.

BCF SEECS ;Clear Chip Select to end command

CLRF SEEAddrh ;Clear contents of SEEAddrh and CLRF SEEAddrl ;SEEAddrl after use and RETURN ;Return to the calling program

SEE_Wait ;Waits until the SEEPROM RDY/BSY flag is set, indicating ;the SEEPROM Erase or Write operation has finished.

BSF SEECS ;Set SEEPROM Chip Select and Program Pull-Out ©1998 Sirius microSystems Microchip Code 41 References SEEPROM.LIB - Serial EEPROM Subroutine Library

NOP ;Wait for set-up time :Wait BTFSS SEEDIDO ;Check for 1 on DI/DO pin GOTO :Wait ;If 0, SEEPROM is still busy RETURN

42 Microchip Code ©1998 Sirius microSystems ALARM.ASM - Chapter 9 Example Program

;ALARM.ASM v1.2 Last modified on August 31, 1998

;These program subroutines were written for the Sirius microSystems PICmicro ;development system. For more information contact Sirius microSystems by phone ;at 519-886-4462, or on the Internet at http://www.siriusmicro.com .

;Sirius microSystems provides this software on an “as is” basis, without any ;warranty, either expressed or implied. All Sirius microSystems software is ;provided for educational use only, and Sirius microSystems does not assume ;any liability for damages, either incidental or consequential, arising out of ;the application, use, or misuse of any of its software or hardware products. ;Sirius microSystems reserves the right, without further notice, to make ;changes to any of its software or hardware referred to in this program or ;library program in order to improve its function, design or reliability.

;Description

; This program demonstrates port input. It initializes port B bit 0 ; as an input and port B bit 1 as an output. When the user ; disconnects bit 0 from ground, the LED connected to bit 1 ; illuminates. Note that port B has built-in pull-up resistors ; and therefore requires no external pull-ups.

;Jumper Settings

; JU2 5VDC internal/external select REG ; JU1 Variable DC internal/external select REG ; JU3 Processor power select jumper RUN ; JU4 EEPROM X8/X16 organization select N/A ; JU6 Port A LED output and analog input RA0 OFF ; RA1 OFF ; RA2 ON ; RA3 OFF ; RA4 OFF ; JU5 RS-232 receive/transmit select N/A

;Requirements

; Attach a small piece of wire to the third screw terminal (CON1-3). ; Connect this wire to the ninth screw terminal (CON1-9). ; When this wire is disconnected the LED on Port B bit 1 (RB1) ; will light. The LED on RB0 displays the state of the input.

Maclib ‘PF8x.INC’ ;Library file for PIC16F84 and PM assembler ;Comment this line out for other assemblers

Device PIC16F84,HS_OSC,WDT_OFF,PROTECT_OFF,PWRT_ON ID ‘ALRM’

ORG 00h ;Reset Vector location GOTO Initialize ;Start program after Interrupt vector

ORG 05h ;One location past Interrupt vector

Initialize BSF RP0 ;Select register page 1 MOVLW 00000001b ;Load W with desired I/O pattern MOVWF TRISB ;Move W to TRISB to make bit 0 input ;(1=input, 0=output) BCF RBPU ;Enable Port B pull-up resistors ;(OPTION.7 on register page 1) BCF RP0 ;Back to register page 0 CLRF PORTB ;Turn off all LEDs

Main BTFSC PORTB.0 ;Check Port B bit 0 for a low GOTO LED_On ;If we’re here, bit 0 is high BCF PORTB.1 ;If bit 0 is low, turn off LED GOTO Main ;Check bit 0 again Program Pull-Out ©1998 Sirius microSystems Microchip Code 43 References ALARM.ASM - Chapter 9 Example Program

LED_On BSF PORTB.1 ;Turn on LED on bit 1 GOTO Main ;Check bit 0 again

44 Microchip Code ©1998 Sirius microSystems ASCII.ASM - Chapter 12 Example Program

;ASCII.ASM v1.2 Last modified on August 31, 1998

;These program subroutines were written for the Sirius microSystems PICmicro ;development system. For more information contact Sirius microSystems by phone ;at 519-886-4462, or on the Internet at http://www.siriusmicro.com .

;Sirius microSystems provides this software on an “as is” basis, without any ;warranty, either expressed or implied. All Sirius microSystems software is ;provided for educational use only, and Sirius microSystems does not assume ;any liability for damages, either incidental or consequential, arising out of ;the application, use, or misuse of any of its software or hardware products. ;Sirius microSystems reserves the right, without further notice, to make ;changes to any of its software or hardware referred to in this program or ;library program in order to improve its function, design or reliability.

;Description

; ; This program illustrates how to use the LCD.LIB, KEYPAD.LIB and ; DEC2BIN.LIB subroutine libraries. A user enters three key strokes ; representing a binary number (from 000 to 255, but no error checking ; is done). The key strokes are displayed as well as the equivalent ; ASCII character generated by the LCD. ; ; Use this program to determine LCD character codes for programs. ; ; The keypad is remapped after being called by KB_Scan to return ; the following numbers. Key remapping as well as displaying a ; message on the LCD demonstrate ROM data table reads. ; ; Old key from KB_Scan gets remapped to new key values: ; +----+----+----+----+ +----+----+----+----+ ; | 1 | 2 | 3 | 4 | | 1 | 2 | 3 | 0 | ; +----+----+----+----+ +----+----+----+----+ ; | 5 | 6 | 7 | 8 | | 4 | 5 | 6 | 0 | ; +----+----+----+----+ +----+----+----+----+ ; | 9 | 10 | 11 | 12 | | 7 | 8 | 9 | 0 | ; +----+----+----+----+ +----+----+----+----+ ; | 13 | 14 | 15 | 16 | | 0 | 0 | 0 | 0 | ; +----+----+----+----+ +----+----+----+----+ ;

;Jumper Settings

; JU2 5VDC internal/external select REG ; JU1 Variable DC internal/external select REG ; JU3 Processor power select jumper RUN ; JU4 EEPROM X8/X16 organization select N/A ; JU6 Port A LED output and analog input RA0 OFF ; RA1 OFF ; RA2 ON ; RA3 OFF ; RA4 OFF ; JU5 RS-232 receive/transmit select N/A

;Requirements

; If you are using the EPIC programmer and the In-Circuit programming ; cable, you must remove this cable from the PIC-MDS to ensure proper ; program execution. Otherwise, keys in column 4 will not be read.

Maclib ‘PF8x.INC’ ;Library file for PIC16F84 and PM assembler ;Comment this line out for other assemblers

Device PIC16F84,HS_OSC,WDT_OFF,PROTECT_OFF,PWRT_ON ID ‘ASCI’ Program Pull-Out ©1998 Sirius microSystems Microchip Code 45 References ASCII.ASM - Chapter 12 Example Program

;Hardware Equates

ORG 0Ch ;Start of File register area

;Equates required by BIN2DEC.LIB and DEC2BIN.LIB: Hundreds DS 1 ;Hundreds digit Tens DS 1 ;Tens digit Ones DS 1 ;Ones digit

;Other equates Counter DS 1 ;LCD character counter

Counter1 DS 1 ;LCD delay counter Counter2 DS 1 ;LCD delay counter

Key DS 1 ;Key return code variable

Digit DS 1 ;ASCII digit counter variable

ORG 00h ;Start program at Reset Vector

CLRF Key ;Clear Key return variable CLRF Counter1 ;and delay counters CLRF Counter2 GOTO Initialize ;Continue with initialize routine

ORG 05h ;One location past Interrupt Vector

Include ‘DEC2BIN.LIB’ ;Decimal to Binary conversion routine Include ‘KEYPAD.LIB’ ;Keypad scanning subroutine library Include ‘LCD.LIB’ ;LCD subroutine library

Initialize ;This subroutine initializes the LCD display and writes ;a message on to line 1 and ‘=’ on to line 2. The cursor ;is turned on to indicate where input will be shown.

CLRF Digit ;Clear digit counter CALL LCD_Port ;Set up ports for LCD use CALL LCD_Init ;Initialize LCD and clear screen CALL Disp_Init ;Send first line

Send_Equals MOVLW LCDLine2 ;Load W with address of line 2 (C0h) ADDLW 0Ah ;and offset cursor to position 11 CALL LCD_REG ;Send cursor position to LCD MOVLW ‘=’ ;Load W with ASCII ‘=’ CALL LCD_Data ;and send to LCD for display

Set_Cursor MOVLW LCDLine2 ;Load W with address of line 2 (C0h) ADDLW 06h ;and offset cursor to position 7 CALL LCD_REG ;Send cursor position to LCD

Cursor_On MOVLW CursOn ;Load W with cursor on command (0Eh) CALL LCD_REG ;and send to LCD

CALL KB_Port ;Configures Port B for keypad

Main ;Main waits for a valid key press. When a valid key returns, ;the keypad is scanned again after a debounce delay. The Key ;value is remapped to the keypad numbers shown in the ;description, above. Key values are successively stored in ;the Hundreds, Tens and Ones registers and displayed on line ;two of the LCD. When three keys have been entered, the key ;codes are converted to binary and displayed on the LCD as ;the character code for that key combination.

Get_Key CALL KB_Scan ;Get Key return code

46 Microchip Code ©1998 Sirius microSystems ASCII.ASM - Chapter 12 Example Program

MOVF Key,0 ;Check Key return code BTFSC Z ;for no key press (0=no key) GOTO Get_Key ;If no key pressed, try again

CALL Delay_5ms ;Wait for key to settle CALL Delay_5ms CALL Delay_5ms CALL Delay_5ms

CALL KB_Scan ;Read Key code after settling MOVF Key,0 ;Read Key code into W CALL Key_Remap ;and Remap key codes MOVWF Key ;Save new Key code to key

MOVF Digit,0 ;Get digit count in W ADDWF PCL ;and offset PC with digit GOTO Digit1 ;First time through, write Hundreds GOTO Digit2 ;next, to Tens GOTO Digit3 ;then, Ones

Digit1 CALL LCD_Port ;Configure Ports for LCD MOVF Key,0 ;Get Key return code MOVWF Hundreds ;and store in Hundreds variable ADDLW 30h ;Convert Key to ASCII CALL LCD_Data ;and display on LCD INCF Digit ;Add one to digit counter GOTO Release ;Wait for user to release key

Digit2 CALL LCD_Port ;Configure Ports for LCD MOVF Key,0 ;Get Key return code MOVWF Tens ;and store in Tens variable ADDLW 30h ;Convert Key to ASCII CALL LCD_Data ;and display on LCD INCF Digit ;Add one to digit counter GOTO Release ;Wait for user to release key

Digit3 CALL LCD_Port ;Configure Ports for LCD MOVF Key,0 ;Get Key return code MOVWF Ones ;and store in Ones variable ADDLW 30h ;Convert Key to ASCII CALL LCD_Data ;and display on LCD

Move_Cursor MOVLW LCDLine2 ;Load W with address of line 2 (C0h) ADDLW 0Ch ;and offset cursor to position 13 CALL LCD_REG ;Send cursor position to LCD

CALL Dec_Bin ;Converts Hundreds, Tens Ones to binary CALL LCD_Data ;and display on LCD

CLRF Digit ;Reset digit counter

Reset_Cursor MOVLW LCDLine2 ;Load W with address of line 2 (C0h) ADDLW 06h ;and offset cursor to position 7 CALL LCD_REG ;Send cursor position to LCD

Release ;This is the opposite of the first key check. It waits for ;the Key code to be zero and pauses for the debounce delay.

CALL KB_Port ;Set Port B for keypad use Wait CALL KB_Scan ;Scan keypad MOVF Key,0 ;Check key for 0 BTFSS Z ;And if Z=1 key has been released GOTO Wait ;Otherwise, wait for release CALL Delay_5ms ;Wait for key to settle CALL Delay_5ms CALL Delay_5ms CALL Delay_5ms GOTO Main ;Get next digit Program Pull-Out ©1998 Sirius microSystems Microchip Code 47 References ASCII.ASM - Chapter 12 Example Program

Disp_Init ;Writes ‘ASCII Code Char.’ to the first line of the LCD ;display using LCD display library (LCD.LIB).

CLRF Counter ;Reset character counter Get_Char MOVF Counter,0 ;Get character offset into W CALL Message ;use it to get character IORLW 00h ;RETLW won’t affect flags so use OR to BTFSC Z ;check for end of message RETURN ;and finish if done CALL LCD_Data ;If not done, send character to LCD INCF Counter,1 ;Add 1 to Counter GOTO Get_Char ;Do it again for the next character

Message ADDWF PCL ;Offset program counter by adding W RETLW ‘A’ ;Message RETLW ‘S’ RETLW ‘C’ RETLW ‘I’ RETLW ‘I’ RETLW ‘ ‘ RETLW ‘C’ RETLW ‘o’ RETLW ‘d’ RETLW ‘e’ RETLW ‘=’ RETLW ‘C’ RETLW ‘h’ RETLW ‘a’ RETLW ‘r’ RETLW ‘.’ RETLW 0 ;End of message

Key_Remap ADDWF PCL ;Use old Key to offset PC NOP ;No Key=0 code RETLW 1 ;old key code 1 remapped to new key 1 RETLW 2 ;old key code 2 remapped to new key 2 RETLW 3 ;old key code 3 remapped to new key 3 RETLW 0 ;old key code 4 remapped to new key 0 RETLW 4 ;old key code 5 remapped to new key 4 RETLW 5 ;old key code 6 remapped to new key 5 RETLW 6 ;old key code 7 remapped to new key 6 RETLW 0 ;old key code 8 remapped to new key 0 RETLW 7 ;old key code 9 remapped to new key 7 RETLW 8 ;old key code 10 remapped to new key 8 RETLW 9 ;old key code 11 remapped to new key 9 RETLW 0 ;old key code 12 remapped to new key 0 RETLW 0 ;old key code 13 remapped to new key 0 RETLW 0 ;old key code 14 remapped to new key 0 RETLW 0 ;old key code 15 remapped to new key 0 RETLW 0 ;old key code 16 remapped to new key 0

Delay_5ms ;Delay loop used to initialize LCD

CLRF Counter1 ;Wipe first counter MOVLW 1Ah ;Load W with timer Constant MOVWF Counter2 ;for Counter2

:Loop DECFSZ Counter1,1 ;Decrement first counter GOTO :Loop ;256 times DECFSZ Counter2,1 ;Decrement, second counter GOTO :Loop ;from constant, above RETURN

48 Microchip Code ©1998 Sirius microSystems BLIP.ASM - Chapter 8 Example Program

;BLIP.ASM v1.2 Last modified on August 31, 1998

;These program subroutines were written for the Sirius microSystems PICmicro ;development system. For more information contact Sirius microSystems by phone ;at 519-886-4462, or on the Internet at http://www.siriusmicro.com .

;Sirius microSystems provides this software on an “as is” basis, without any ;warranty, either expressed or implied. All Sirius microSystems software is ;provided for educational use only, and Sirius microSystems does not assume ;any liability for damages, either incidental or consequential, arising out of ;the application, use, or misuse of any of its software or hardware products. ;Sirius microSystems reserves the right, without further notice, to make ;changes to any of its software or hardware referred to in this program or ;library program in order to improve its function, design or reliability.

;Description

; This program demonstrates looping for Chapter 8. It initializes all ; port B pins to be outputs, keeps all LEDs lit for a short time, delays ; for a longer time and then repeats.

;Jumper Settings

; JU2 5VDC internal/external select REG ; JU1 Variable DC internal/external select REG ; JU3 Processor power select jumper RUN ; JU4 EEPROM X8/X16 organization select N/A ; JU6 Port A LED output and analog input RA0 OFF ; RA1 OFF ; RA2 ON ; RA3 OFF ; RA4 OFF ; JU5 RS-232 receive/transmit select N/A

;Requirements

; This is a simple program that requires no prior setup.

Maclib ‘PF8x.INC’ ;Library file for PIC16F84 and PM assembler ;Comment this line out for other assemblers

Device PIC16F84,HS_OSC,WDT_OFF,PROTECT_OFF,PWRT_ON ID ‘BLIP’

;Hardware Equates

Counter1 EQU 0Ch ;First delay counter register Counter2 EQU 0Dh ;Second delay counter register Counter3 EQU 0Eh ;Third delay counter register

ORG 00h ;Reset Vector location GOTO Initialize ;Start program after Interrupt vector ORG 05h ;One location past Interrupt vector

Initialize BSF RP0 ;Select memory register page 1 CLRF TRISB ;Make Port B output by clearing TRISB BCF RP0 ;Go back to register page 0 CLRF PORTB ;Clear Port B register CLRF Counter1 ;Clear Counter1 register (0Ch) CLRF Counter2 ;and Counter2 register (0Dh)

Main MOVLW 0FFh ;Load W with ones to turn on LEDs MOVWF PORTB ;and write to Port B register MOVLW 03h ;Load W with 3 MOVWF Counter2 ;and preset Counter2 before Loop_On

Loop_On DECFSZ Counter1 ;Decrement Counter1 and check for 0 Program Pull-Out ©1998 Sirius microSystems Microchip Code 49 References BLIP.ASM - Chapter 8 Example Program

GOTO Loop_On ;If not 0, decrement Counter1 again DECFSZ Counter2 ;If 0, decrement Counter2 GOTO Loop_On ;If not 0, do Counter1 loop

CLRF PORTB ;Turn off LEDs by clearing Port B MOVLW 0Dh ;Load W with 13 MOVWF Counter3 ;and preset Counter3 before Loop_Off

Loop_Off DECFSZ Counter1 ;Decrement Counter1 and check for 0 GOTO Loop_Off ;If not 0, decrement Counter 1 again DECFSZ Counter2 ;If Counter1=0, decrement Counter2 GOTO Loop_Off ;If not 0, do Counter1 loop DECFSZ Counter3 ;If Counter2=0, decrement Counter3 GOTO Loop_Off ;If not 0, do Counter1 & 2 loops GOTO Main ;If 0, go to Main

50 Microchip Code ©1998 Sirius microSystems BOUNCE.ASM - Chapter 9 Example Program

;BOUNCE.ASM v1.2 Last modified on August 31, 1998

;These program subroutines were written for the Sirius microSystems PICmicro ;development system. For more information contact Sirius microSystems by phone ;at 519-886-4462, or on the Internet at http://www.siriusmicro.com .

;Sirius microSystems provides this software on an “as is” basis, without any ;warranty, either expressed or implied. All Sirius microSystems software is ;provided for educational use only, and Sirius microSystems does not assume ;any liability for damages, either incidental or consequential, arising out of ;the application, use, or misuse of any of its software or hardware products. ;Sirius microSystems reserves the right, without further notice, to make ;changes to any of its software or hardware referred to in this program or ;library program in order to improve its function, design or reliability.

;Description

; This program demonstrates switch contact bounce. It initializes port A ; bit 4 as an input and port B as output. When the user connects port A ; bit 4 to ground, the LEDs display the number of contact bounces that ; occur. The count accumulates until the RESET button is pressed. ; Note that port A has no internal pull-up capability. However the ; PIC-MDS has an external pull-up pre-wired to Port A bit 4 (RA4).

;Jumper Settings

; JU2 5VDC internal/external select REG ; JU1 Variable DC internal/external select REG ; JU3 Processor power select jumper RUN ; JU4 EEPROM X8/X16 organization select N/A ; JU6 Port A LED output and analog input RA0 OFF ; RA1 OFF ; RA2 ON ; RA3 OFF ; RA4 OFF ; JU5 RS-232 receive/transmit select N/A

;Requirements

; Attach a small piece of wire to the third screw terminal (CON1-3). ; When this grounded wire is connected to the 8th screw terminal ; (CON1-8) the LEDs on port B reflect the number of bounces.

Maclib ‘PF8x.INC’ ;Library file for PIC16F84 and PM assembler ;Comment this line out for other assemblers

Device PIC16F84,HS_OSC,WDT_OFF,PROTECT_OFF,PWRT_ON ID ‘BOUN’

ORG 00h ;Reset Vector location GOTO Initialize ;Start program after Interrupt vector

ORG 05h ;One location past Interrupt vector

Initialize BSF RP0 ;Select register page 1 MOVLW 00010000b ;Load W with the desired I/O pattern MOVWF TRISA ;Make Port A bit 4 input ;(1=input, 0=output) CLRF TRISB ;Make Port B output BCF RP0 ;Back to register page 0 CLRF PORTB ;Turn off all LEDs

Main BTFSC PORTA.4 ;Check Port A bit 4 for a low GOTO Main ;If we’re here, bit 4 is high INCF PORTB ;If bit 4 is low, increment Port B

Wait_for_High BTFSS PORTA.4 ;Check Port A bit 4 for a high Program Pull-Out ©1998 Sirius microSystems Microchip Code 51 References BOUNCE.ASM - Chapter 9 Example Program

GOTO Wait_for_High ;If we’re here, bit 4 is still low GOTO Main ;Bit 4 went high, wait for next bounce

52 Microchip Code ©1998 Sirius microSystems CLOCK.ASM - Chapter 11 Example Program

;CLOCK.ASM v1.2 Last modified on August 31, 1998

;These program subroutines were written for the Sirius microSystems PICmicro ;development system. For more information contact Sirius microSystems by phone ;at 519-886-4462, or on the Internet at http://www.siriusmicro.com .

;Sirius microSystems provides this software on an “as is” basis, without any ;warranty, either expressed or implied. All Sirius microSystems software is ;provided for educational use only, and Sirius microSystems does not assume ;any liability for damages, either incidental or consequential, arising out of ;the application, use, or misuse of any of its software or hardware products. ;Sirius microSystems reserves the right, without further notice, to make ;changes to any of its software or hardware referred to in this program or ;library program in order to improve its function, design or reliability.

;Description

; ; This program demonstrates interrupt driven timing while running a ; separate task. A TMR0 interrupt is generated 60 times per second ; and is used to update the elapsed time on the LCD display. When not ; updating the display, a single LED is scanned across Port B.

; Since PortB is used by both the ISR and the Main routine, the ISR ; saves and restores all port registers.

;Jumper Settings

; JU2 5VDC internal/external select REG ; JU1 Variable DC internal/external select REG ; JU3 Processor power select jumper RUN ; JU4 EEPROM X8/X16 organization select N/A ; JU6 Port A LED output and analog input RA0 OFF ; RA1 OFF ; RA2 ON ; RA3 OFF ; RA4 OFF ; JU5 RS-232 receive/transmit select N/A

;Requirements

; None

Maclib ‘PF8x.INC’ ;Library file for PIC16F84 and PM assembler ;Comment this line out for other assemblers

Device PIC16F84,HS_OSC,WDT_OFF,PROTECT_OFF,PWRT_ON ID ‘CLK ‘

;Hardware Equates

ORG 0Ch ;Start of File register area

;Equates required by BIN2DEC.LIB and DEC2BIN.LIB: Hundreds DS 1 ;Hundreds digit Tens DS 1 ;Tens digit Ones DS 1 ;Ones digit

;Equates required to keep time: Hours DS 1 ;Holds elapsed hours Minutes DS 1 ;Holds elapsed minutes Seconds DS 1 ;Holds elapsed seconds Sixtieth DS 1 ;Holds sixtieths of a second

;Other equates Counter DS 1 ;LCD character counter Program Pull-Out ©1998 Sirius microSystems Microchip Code 53 References CLOCK.ASM - Chapter 11 Example Program

Counter1 DS 1 ;LCD delay counter Counter2 DS 1 ;LCD delay counter

Counter3 DS 1 ;general purpose delay counter Counter4 DS 1 ;general purpose delay counter

Temp_W DS 1 ;Temporary registers Temp_Status DS 1 ;used to save values during interrupt Temp_TRISB DS 1 ;service routine (ISR) The ISR Temp_TRISA DS 1 ;will save their values on entry Temp_PortB DS 1 ;and restore them on exit. Temp_PortA DS 1

Key DS 1 ;Key return code variable

ORG 00h ;Start program at Reset Vector

CLRF Hours ;Set hours to 00 CLRF Minutes ;Set minutes to 00 CLRF Seconds ;Set seconds to 00 GOTO Initialize ;Continue with initialize routine

ORG 04h ;Interrupt Service Routine (ISR) ;starts at Interrupt Vector

Check_T0IF ;When an interrupt occurs, Check_T0IF confirms it was ;generated by a TMR0 overflow. If not, and other interrupts ;are enabled, they must get serviced in the Other_Int ;routine. When TMR0 overflows Sixtieth is decremented and ;checked for equaling zero. If Zero then Seconds, Minutes ;and Hours are updated and displayed. Otherwise, interrupts ;are re-enabled and execution continues.

Save MOVWF Temp_W ;Save W in Temp_W SWAPF Status,0 ;Swap Status halves into W MOVWF Temp_Status ;and save Status in Temp_Status

MOVF PORTA,0 ;Load W with Port and TRIS contents MOVWF Temp_PortA ;and save to temporary registers MOVF PORTB,0 MOVWF Temp_PortB BSF RP0 MOVF TRISA,0 MOVWF Temp_TRISA MOVF TRISB,0 MOVWF Temp_TRISB BCF RP0

ISR BTFSS T0IF ;Check for TMR0 interrupt GOTO Other_Int ;If cleared, check other interrupts

DECFSZ Sixtieth ;Has 1 second elapsed? GOTO Exit ;If not, use Exit to leave ISR MOVLW 60 ;If zero, reset sixtieth counter MOVWF Sixtieth ;to 60 INCF Seconds ;Update seconds and SUBWF Seconds,0 ;check for overflow (Seconds=60) BTFSS Z ;by testing Z GOTO Update_Clock ;If Z=0, update clock with new time

CLRF Seconds ;If Z=1, Seconds is 60, reset to 0 MOVLW 60 ;reload W with 60 INCF Minutes ;Update Minutes and SUBWF Minutes,0 ;check for overflow (Minutes=60) BTFSS Z ;by testing Z GOTO Update_Clock ;If Z=0, update clock with new time

54 Microchip Code ©1998 Sirius microSystems CLOCK.ASM - Chapter 11 Example Program

CLRF Minutes ;If Z=1, Minutes is 60, reset to 0 MOVLW 24 ;Load W with 24 INCF Hours ;Update Hours and SUBWF Hours,0 ;check for overflow (Hours=24) BTFSS Z ;by testing Z GOTO Update_Clock ;If Z=0, update clock with new time

CLRF Hours ;If Z=1, reset hours to 00

Update_Clock CALL LCD_Port ;Reconfigure Ports for LCD and CALL Disp_Time ;display the new time

Exit ;Reloads TMR0 so the next 60th second time-out can generate ;an interrupt and restores all registers.

MOVLW 93 ;Preload W for 60 Hz delay MOVWF TMR0 ;and save to TMR0 BCF T0IF ;Clear TMR0 interrupt flag and BSF T0IE ;enable TMR0 interrupt

Restore MOVF Temp_PortA,0 ;Restore registers from temporary MOVWF PORTA ;registers MOVF Temp_PortB,0 MOVWF PORTB BSF RP0 MOVF Temp_TRISA,0 MOVWF TRISA MOVF Temp_TRISB,0 MOVWF TRISB BCF RP0

SWAPF Temp_Status,0 ;Swap Status halves to W MOVWF Status ;and return Status to pre-interrupt ;value SWAPF Temp_W,1 ;Swap halves of Temp_W SWAPF Temp_W,0 ;Swap Temp_W back to W

RETFIE ;Return and enable interrupts

Other_Int MOVLW 20h ;Set only TMR0 interrupt MOVWF INTCON ;and write to interrupt register RETFIE ;Return and enable global interrupts

Initialize CLRF Counter ;Clear counters CLRF Counter1 CLRF Counter2 CLRF Counter3 CLRF Counter4 MOVLW 60 ;Preload sixtieths MOVWF Sixtieth ;with 60

CALL LCD_Port ;Set up ports for LCD use CALL LCD_Init ;Initialize LCD and clear screen CALL Disp_Init ;Display “Elapsed time:” on line 1 CALL Disp_Time ;Display time on line 2

CALL TMR0_Init ;Initialize Real Time Clock Counter ;Timer 0 (TMR0) and enable interrupts.

BSF RP0 ;Select Register Page 1 CLRF TRISB ;Make Port B output BCF RP0 ;Back to Register Page 0

MOVLW 01h ;Light up the first LED MOVWF PORTB ;on Port B BCF C ;Clear the Carry Program Pull-Out ©1998 Sirius microSystems Microchip Code 55 References CLOCK.ASM - Chapter 11 Example Program

Main ;This code runs when the Interrupt service routine isn’t ;running and cycles a single LED across the display.

:Loop DECFSZ Counter3,1 ;Decrement first counter GOTO :Loop ;256 times DECFSZ Counter4,1 ;Decrement, second counter GOTO :Loop ;from constant, above

RLF PORTB ;Rotate PORTB to the left GOTO Main ;Do it again and again and ...

Disp_Init ;Writes ‘Elapsed time:’ to first line of LCD display using ;LCD display library (LCD.LIB).

MOVLW LCDCLR ;Send LCD clear display code CALL LCD_REG ;to LCD as a command MOVLW LCDLine1 ;Send LCD line one address to CALL LCD_REG ;LCD as a command CLRF Counter ;Reset character counter Get_Char MOVF Counter,0 ;Get character offset into W CALL Message ;use it to get character IORLW 00h ;RETLW won’t affect flags so use OR to BTFSC Z ;check for end of message RETURN ;and finish if done CALL LCD_Data ;If not done, send character to LCD INCF Counter,1 ;Add 1 to Counter GOTO Get_Char ;Do it again for the next character

Message ADDWF PCL ;Offset program counter by adding W RETLW ‘E’ ;Message RETLW ‘l’ RETLW ‘a’ RETLW ‘p’ RETLW ‘s’ RETLW ‘e’ RETLW ‘d’ RETLW ‘ ‘ RETLW ‘t’ RETLW ‘i’ RETLW ‘m’ RETLW ‘e’ RETLW ‘:’ RETLW 0 ;End of message

Disp_Time ;Converts binary Hours, Minutes and Seconds digits to BCD ;and then to ASCII and displays them on LCD separated by ;colons.

MOVLW LCDLine2 ;Send LCD line two address to CALL LCD_REG ;LCD as a command MOVF Hours,0 ;Load W with Hours value CALL Disp_Digits ;and output to LCD MOVLW ‘:’ ;Load W with ASCII value of ‘:’ CALL LCD_Data ;and display on LCD MOVF Minutes,0 ;Load W with Minutes value CALL Disp_Digits ;and output to LCD MOVLW ‘:’ ;Load W with ASCII value of ‘:’ CALL LCD_Data ;and display on LCD MOVF Seconds,0 ;Load W with Seconds value CALL Disp_Digits ;and output to LCD RETURN

Disp_Digits ;Converts and displays value in W as two digits on LCD.

56 Microchip Code ©1998 Sirius microSystems CLOCK.ASM - Chapter 11 Example Program

CALL BIN_DEC ;and convert to tens and ones MOVLW 30h ;Load W with ASCII offset ADDWF Tens,1 ;and add to Tens digit ADDWF Ones,1 ;and Ones to change to ASCII MOVF Tens,0 ;Load W with Tens value CALL LCD_Data ;and display on LCD MOVF Ones,0 ;Load W with Ones value CALL LCD_Data ;and display on LCD RETURN

TMR0_Init ;Assign prescaler to TMR0 and preload TMR0 for 60 Hz ;interrupts.

CLRWDT ;Clear WDT and prescaler BSF RP0 ;Select register page 1 MOVF OPTION,0 ;Load W with current OPTION reg. ANDLW 11000111b ;Clear T0CS, T0SE and PSA bits ;T0CS=OPTION.5, Counter select ;0=Timer mode, 1=Counter mode ;T0SE=OPTION.4, Source Edge select ;0=Rising edge, 1=Falling edge ;PSA=OPTION.3, Prescaler Assignment ;0=TMR0, 1=WDT IORLW 00000111b ;Set PS2, PS1 and PS0 ;000=/2, 001=/4, ...111=/256 MOVWF OPTION ;Set OPTION register with new value BCF RP0 ;Return to register page 0

MOVLW 93 ;Load W with 93 because incrementing MOVWF TMR0 ;TMR0 from 93-256 takes 1/60s

MOVLW 20h ;Enable only the TMR0 interrupt MOVWF INTCON ;and write to INTCON

RETFIE ;Return and enable global interrupts

Delay_5ms ;Delay loop used to initialize LCD

CLRF Counter1 ;Wipe first counter MOVLW 1Ah ;Load W with timer Constant MOVWF Counter2 ;for Counter2

:Loop DECFSZ Counter1,1 ;Decrement first counter GOTO :Loop ;256 times DECFSZ Counter2,1 ;Decrement, second counter GOTO :Loop ;from constant, above RETURN

Include ‘BIN2DEC.LIB’ ;Binary to Decimal conversion routine Include ‘LCD.LIB’ ;LCD subroutine library

Program Pull-Out ©1998 Sirius microSystems Microchip Code 57 References COUNT.ASM - Chapter 8 Example Program

;COUNT.ASM v1.2 Last modified on August 31, 1998

;These program subroutines were written for the Sirius microSystems PICmicro ;development system. For more information contact Sirius microSystems by phone ;at 519-886-4462, or on the Internet at http://www.siriusmicro.com .

;Sirius microSystems provides this software on an “as is” basis, without any ;warranty, either expressed or implied. All Sirius microSystems software is ;provided for educational use only, and Sirius microSystems does not assume ;any liability for damages, either incidental or consequential, arising out of ;the application, use, or misuse of any of its software or hardware products. ;Sirius microSystems reserves the right, without further notice, to make ;changes to any of its software or hardware referred to in this program or ;library program in order to improve its function, design or reliability.

;Description

; This program demonstrates port output. It initializes all port B pins ; to be outputs and then counts from 0 to 255 (FFh) repeatedly.

;Jumper Settings

; JU2 5VDC internal/external select REG ; JU1 Variable DC internal/external select REG ; JU3 Processor power select jumper RUN ; JU4 EEPROM X8/X16 organization select N/A ; JU6 Port A LED output and analog input RA0 OFF ; RA1 OFF ; RA2 ON ; RA3 OFF ; RA4 OFF ; JU5 RS-232 receive/transmit select N/A

;Requirements

; This is a simple program that requires no prior setup.

Maclib ‘PF8x.INC’ ;Library file for PIC16F84 and PM assembler ;Comment this line out for other assemblers

Device PIC16F84,HS_OSC,WDT_OFF,PROTECT_OFF,PWRT_ON ID ‘CNT ‘

ORG 00h ;Reset Vector location GOTO Initialize ;Start program after Interrupt vector

ORG 05h ;One location past Interrupt vector

Initialize BSF RP0 ;Select memory register page 1 CLRF TRISB ;Make Port B output by clearing TRISB BCF RP0 ;Go back to register page 0 CLRF PORTB ;Turn off LEDs by clearing Port B

Loop INCF PORTB ;Add 1 to Port B register GOTO Loop ;and do it again, and again...

Done SLEEP ;Stop executing the program

58 Microchip Code ©1998 Sirius microSystems CUSTOM.ASM - Chapter 12 Example Program

;CUSTOM.ASM v1.2 Last modified on August 31, 1998

;These program subroutines were written for the Sirius microSystems PICmicro ;development system. For more information contact Sirius microSystems by phone ;at 519-886-4462, or on the Internet at http://www.siriusmicro.com .

;Sirius microSystems provides this software on an “as is” basis, without any ;warranty, either expressed or implied. All Sirius microSystems software is ;provided for educational use only, and Sirius microSystems does not assume ;any liability for damages, either incidental or consequential, arising out of ;the application, use, or misuse of any of its software or hardware products. ;Sirius microSystems reserves the right, without further notice, to make ;changes to any of its software or hardware referred to in this program or ;library program in order to improve its function, design or reliability.

;Description

; ; This program demonstrates how to create & use custom LCD characters. ; Four Truck and four Man characters are created from bitmaps. The ; Man character is used to show cursor cell animation and the Truck ; demonstrates line scrolling. ;

;Jumper Settings

; JU2 5VDC internal/external select REG ; JU1 Variable DC internal/external select REG ; JU3 Processor power select jumper RUN ; JU4 EEPROM X8/X16 organization select N/A ; JU6 Port A LED output and analog input RA0 OFF ; RA1 OFF ; RA2 ON ; RA3 OFF ; RA4 OFF ; JU5 RS-232 receive/transmit select N/A

;Requirements

; None

Maclib ‘PF8x.INC’ ;Library file for PIC16F84 and PM assembler ;Comment this line out for other assemblers

Device PIC16F84,HS_OSC,WDT_OFF,PROTECT_OFF,PWRT_ON ID ‘CUST’

;Hardware Equates

ORG 0Ch ;Start of File register area

Counter DS 1 ;LCD character counter Position DS 1 ;LCD position counter

Counter1 DS 1 ;LCD delay counter Counter2 DS 1 ;LCD delay counter

ORG 00h ;Start program at Reset Vector

CLRF Counter ;Clear LCD character counter CLRF Counter1 ;and delay counters CLRF Counter2 GOTO Initialize ;Continue with initialize routine

ORG 05h ;One location past Interrupt Vector

Include ‘LCD.LIB’ ;LCD subroutine library Program Pull-Out ©1998 Sirius microSystems Microchip Code 59 References CUSTOM.ASM - Chapter 12 Example Program

Initialize ;This subroutine initializes the LCD display and programs ;the custom characters by calling Prog_Character.

CALL LCD_Port ;Set up ports for LCD use CALL LCD_Init ;Initialize LCD and clear screen CALL Prog_Character ;Load LCD with custom characters MOVLW LCDLine1 ;Load W with Line 1 address MOVWF Position ;Save W in Position register CALL LCD_REG ;and send to LCD as command MOVLW 04h ;Load W with Man1 Character code MOVWF Counter ;and save in LCD character counter

Walk ;Makes a little man walk across the screen by successively ;writing each of the 4 Man characters into the same cursor ;position and then moving the cursor 1 position to the ;right before repeating.

MOVF Counter,0 ;Get current Man Character CALL LCD_Data ;and send to LCD MOVLW CursLeft ;Load W with Cursor Left shift CALL LCD_Reg ;command and send to LCD CALL Delay ;Wait a bit INCF Counter ;Increment to next Man Character MOVLW 08h ;Load W with number of last Man SUBWF Counter,0 ;and check for last count BTFSS Z ;by checking Z GOTO Walk ;If not at last Man, display next man

MOVLW ‘ ‘ ;If at last Man, Load W with ‘ ‘ CALL LCD_Data ;to clear character MOVLW 04h ;Load W with Man1 Character MOVWF Counter ;and save to character counter INCF Position ;Increment cursor position variable MOVLW 90h ;Load W with last visible position SUBWF Position,0 ;and compare with Position BTFSS Z ;by checking Z GOTO Walk ;If not at last position, do it again

CALL Delay ;If done, wait before rolling Truck

Roll ;Scrolls a Truck back across the screen continuously by ;writing the 4 Truck characters off the screen (cursor was ;left at position 90h by Walk) and then scrolling the ;screen to the left. Since the display was cleared earlier ;you will see only the Truck. The line length is 40 chars. ;Every 40 display shifts, the Truck comes around again.

CLRF Counter ;Clear character counter variable :Next MOVF Counter,0 ;Load W with counter CALL LCD_Data ;and send character to LCD INCF Counter ;Increment Counter register MOVLW 04h ;Load W with number of Truck chars. SUBWF Counter,0 ;and compare with counter BTFSS Z ;by checking Z GOTO :Next ;If not done, send next Truck char.

:Loop MOVLW LCDLeft ;If done, load W with LCD shift left CALL LCD_Reg ;command and send to LCD CALL Delay ;Wait a bit GOTO :Loop ;Keep scrolling the display

Prog_Character ;Loads the custom character data into the LCD Character ;Generator RAM. CGRAM is ASCII characters 0-7. Each character ;is loaded as a bit-map, one line at a time. The cursor ;auto-increments to the next CGRAM location after each ;write.

60 Microchip Code ©1998 Sirius microSystems CUSTOM.ASM - Chapter 12 Example Program

MOVLW LCDCGRAM ;Send LCD CGRAM address (40h) to CALL LCD_REG ;LCD as a command CLRF Counter ;Reset character counter Get_Char MOVF Counter,0 ;Get character offset into W CALL Characters ;use it to get character data CALL LCD_Data ;If not done, send character to LCD INCF Counter,1 ;Add 1 to Counter MOVLW 64 ;Load W with number of char. bytes SUBWF Counter,0 ;and compare with Counter BTFSC Z ;by checking Z flag RETURN ;If Counter=64, we’re done GOTO Get_Char ;Do it again for the next character

Characters ADDWF PCL ;Offset PC with Counter in W

Truck1 RETLW 00000000b ;Row 1, ASCII character 00 RETLW 00000011b ;Row 2, ASCII character 00 RETLW 00000011b ;Row 3, ASCII character 00 RETLW 00001111b ;etc. RETLW 00001111b RETLW 00011010b RETLW 00000111b RETLW 00000010b

Truck2 RETLW 00001111b ;Row 1, ASCII character 01 RETLW 00001111b ;Row 2, ASCII character 01 RETLW 00001111b ;etc. RETLW 00001111b RETLW 00011111b RETLW 00001010b RETLW 00011111b RETLW 00001010b

Truck3 RETLW 00011111b RETLW 00011111b RETLW 00011111b RETLW 00011111b RETLW 00011111b RETLW 00000000b RETLW 00000000b RETLW 00000000b

Truck4 RETLW 00011111b RETLW 00011111b RETLW 00011111b RETLW 00011111b RETLW 00011111b RETLW 00001010b RETLW 00011111b RETLW 00001010b

Man1 RETLW 00000000b RETLW 00000000b RETLW 00010000b RETLW 00011000b RETLW 00010000b RETLW 00001000b RETLW 00001000b RETLW 00000000b

Man2 RETLW 00000000b RETLW 00000000b RETLW 00000000b RETLW 00001000b RETLW 00011100b RETLW 00001000b RETLW 00011000b Program Pull-Out ©1998 Sirius microSystems Microchip Code 61 References CUSTOM.ASM - Chapter 12 Example Program

RETLW 00001000b

Man3 RETLW 00000000b RETLW 00000000b RETLW 00000000b RETLW 00000100b RETLW 00000110b RETLW 00000100b RETLW 00001010b RETLW 00001010b

Man4 RETLW 00000000b ;Row 1, ASCII character 07 RETLW 00000000b ;Row 2, ASCII character 07 RETLW 00000001b RETLW 00000011b RETLW 00000001b RETLW 00000011b RETLW 00000001b RETLW 00000000b ;Row 8, ASCII character 07

Delay ;Delay between Man & Truck movements

:Loop DECFSZ Counter1,1 ;Decrement first counter GOTO :Loop ;256 times DECFSZ Counter2,1 ;Decrement, second counter GOTO :Loop ;256 more times RETURN

Delay_5ms ;Delay loop used to initialize LCD

CLRF Counter1 ;Wipe first counter MOVLW 1Ah ;Load W with timer Constant MOVWF Counter2 ;for Counter2

:Loop DECFSZ Counter1,1 ;Decrement first counter GOTO :Loop ;256 times DECFSZ Counter2,1 ;Decrement, second counter GOTO :Loop ;from constant, above RETURN

62 Microchip Code ©1998 Sirius microSystems DBOUNCE.ASM - Chapter 9 Example Program

;DBOUNCE.ASM v1.2 Last modified on August 31, 1998

;These program subroutines were written for the Sirius microSystems PICmicro ;development system. For more information contact Sirius microSystems by phone ;at 519-886-4462, or on the Internet at http://www.siriusmicro.com .

;Sirius microSystems provides this software on an “as is” basis, without any ;warranty, either expressed or implied. All Sirius microSystems software is ;provided for educational use only, and Sirius microSystems does not assume ;any liability for damages, either incidental or consequential, arising out of ;the application, use, or misuse of any of its software or hardware products. ;Sirius microSystems reserves the right, without further notice, to make ;changes to any of its software or hardware referred to in this program or ;library program in order to improve its function, design or reliability.

;Description

; This program demonstrates switch contact debouncing. It initializes ; port A bit 4 as an input and port B as output. Each time the user ; connects port A bit 4 to ground, the LEDs increment, displaying the ; number of contact closures. The count accumulates until the RESET ; button is pressed. Note that port A has no internal pull-up ; capability. However the PIC-MDS has an external pull-up pre-wired to ; Port A bit 4.

;Jumper Settings

; JU2 5VDC internal/external select REG ; JU1 Variable DC internal/external select REG ; JU3 Processor power select jumper RUN ; JU4 EEPROM X8/X16 organization select N/A ; JU6 Port A LED output and analog input RA0 OFF ; RA1 OFF ; RA2 ON ; RA3 OFF ; RA4 OFF ; JU5 RS-232 receive/transmit select N/A

;Requirements

; Attach a small piece of wire to the third screw terminal (CON1-3). ; When this grounded wire is connected to the 8th screw terminal ; (CON1-8) the LEDs on port B increment, reflecting the number of switch ; closures.

Maclib ‘PF8x.INC’ ;Library file for PIC16F84 and PM assembler ;Comment this line out for other assemblers

Device PIC16F84,HS_OSC,WDT_OFF,PROTECT_OFF,PWRT_ON ID ‘DBNC’

;Hardware Equates

Counter1 EQU 0Ch ;First delay counter variable Counter2 EQU 0Dh ;Second delay counter variable

ORG 00h ;Reset Vector location GOTO Initialize ;Start program after Interrupt vector

ORG 05h ;One location past Interrupt vector

Initialize BSF RP0 ;Select register page 1 MOVLW 00010000b ;Load W with the desired I/O pattern MOVWF TRISA ;Make Port A bit 4 input ;(1=input, 0=output) CLRF TRISB ;Make Port B output Program Pull-Out ©1998 Sirius microSystems Microchip Code 63 References DBOUNCE.ASM - Chapter 9 Example Program

BCF RP0 ;Back to register page 0 CLRF PORTB ;Turn off all LEDs CLRF Counter1 ;Clear location Counter1 (0Ch) MOVLW 40h ;Load W with preset for counter 2 MOVWF Counter2 ;Store W to Counter2 (0Dh)

Main BTFSC PORTA.4 ;Check Port A bit 4 for a low GOTO Main ;If we’re here, bit 4 is high

Delay DECFSZ Counter1 ;If we’re here, bit 4 is low GOTO Delay ;Let’s wait at least 20 ms for the DECFSZ Counter2 ;contacts to settle GOTO Delay

MOVLW 40h ;Once delay is done, reset counter 2 MOVWF Counter2 ;Store W to Counter2 (0Dh)

BTFSS PORTA.4 ;Is Port A bit 4 still low? INCF PORTB ;If so, increment Port B

Wait_for_High BTFSS PORTA.4 ;Wait for Port A bit 4 to go high GOTO Wait_for_High ;If low, keep checking GOTO Main ;If high, go back to Main

64 Microchip Code ©1998 Sirius microSystems DELAY.ASM - Chapter 8 Example Program

;DELAY.ASM v1.2 Last modified on August 31, 1998

;These program subroutines were written for the Sirius microSystems PICmicro ;development system. For more information contact Sirius microSystems by phone ;at 519-886-4462, or on the Internet at http://www.siriusmicro.com .

;Sirius microSystems provides this software on an “as is” basis, without any ;warranty, either expressed or implied. All Sirius microSystems software is ;provided for educational use only, and Sirius microSystems does not assume ;any liability for damages, either incidental or consequential, arising out of ;the application, use, or misuse of any of its software or hardware products. ;Sirius microSystems reserves the right, without further notice, to make ;changes to any of its software or hardware referred to in this program or ;library program in order to improve its function, design or reliability.

;Description

; This program demonstrates port output. It initializes all port B pins ; to be outputs and then counts from 0 to 255 (FFh) repeatedly with a ; delay of 65536 decrements between each count.

;Jumper Settings

; JU2 5VDC internal/external select REG ; JU1 Variable DC internal/external select REG ; JU3 Processor power select jumper RUN ; JU4 EEPROM X8/X16 organization select N/A ; JU6 Port A LED output and analog input RA0 OFF ; RA1 OFF ; RA2 ON ; RA3 OFF ; RA4 OFF ; JU5 RS-232 receive/transmit select N/A

;Requirements

; This is a simple program that requires no prior setup.

Maclib ‘PF8x.INC’ ;Library file for PIC16F84 and PM assembler ;Comment this line out for other assemblers

Device PIC16F84,HS_OSC,WDT_OFF,PROTECT_OFF,PWRT_ON ID ‘DELA’

;Hardware Equates

Counter1 EQU 0Ch ;First delay counter register Counter2 EQU 0Dh ;Second delay counter register

ORG 00h ;Reset Vector location GOTO Initialize ;Start program after Interrupt vector

ORG 05h ;One location past Interrupt vector

Initialize BSF RP0 ;Select memory register page 1 CLRF TRISB ;Make Port B output by clearing TRISB BCF RP0 ;Go back to register page 0 CLRF PORTB ;Clear Port B register CLRF Counter1 ;Clear Counter1 register (0Ch) CLRF Counter2 ;and Counter2 register(0Dh)

Main INCF PORTB ;Add 1 to Port B register Loop DECFSZ Counter1 ;Decrement Counter1 and check for 0 GOTO Loop ;If not 0, decrement Counter 1 again DECFSZ Counter2 ;If 0, decrement Counter2 GOTO Loop ;If Counter2 is not 0, decrement ;Counter1 another 256 times GOTO Main ;Update the LEDs after 65536 counts Program Pull-Out ©1998 Sirius microSystems Microchip Code 65 References KEY.ASM - Chapter 10 Example Program

;KEY.ASM v1.2 Last modified on August 31, 1998

;These program subroutines were written for the Sirius microSystems PICmicro ;development system. For more information contact Sirius microSystems by phone ;at 519-886-4462, or on the Internet at http://www.siriusmicro.com .

;Sirius microSystems provides this software on an “as is” basis, without any ;warranty, either expressed or implied. All Sirius microSystems software is ;provided for educational use only, and Sirius microSystems does not assume ;any liability for damages, either incidental or consequential, arising out of ;the application, use, or misuse of any of its software or hardware products. ;Sirius microSystems reserves the right, without further notice, to make ;changes to any of its software or hardware referred to in this program or ;library program in order to improve its function, design or reliability.

;Description

; Col. 1 2 3 4 ; Row +----+----+----+----+ ; Port B.0----1---| 1 | 2 | 3 | 4 | ; +----+----+----+----+ ; Port B.1----2---| 5 | 6 | 7 | 8 | ; +----+----+----+----+ ; Port B.2----3---| 9 | 10 | 11 | 12 | ; +----+----+----+----+ ; Port B.3----4---| 13 | 14 | 15 | 16 | ; +----+----+----+----+ ; Port B.4------+ | | | ; | | | ; Port B.5------+ | | ; | | ; Port B.6------+ | ; | ; Port B.7------+ ; ; This program demonstrates matrix keypad scanning along with LCD ; output using included subroutine libraries. The keypad is scanned ; continuously. Key return codes are converted to ASCII and displayed ; by their key digit (from the above diagram) on the LCD display. ; The key code will display for as long as it is valid. ; ; This program uses the DS (Define Space) directive instead of EQU ; (Equate) to define RAM registers. The advantage of this approach ; is that hardware registers can be created and removed from this ; program without manually re-locating their addresses. The drawback ; is that the physical location of the register is defined by the ; assembler, not the user. ; ; Also, notice that this program utilizes the space from memory ; location 0000h to the interrupt vector at 0004h. It’s not much ; space, but you can cram an extra 3 words into your program by ; doing this (the 4th word is the GOTO which jumps the interrupt ; vector, and is not really useful as storage).

;Jumper Settings

; JU2 5VDC internal/external select REG ; JU1 Variable DC internal/external select REG ; JU3 Processor power select jumper RUN ; JU4 EEPROM X8/X16 organization select N/A ; JU6 Port A LED output and analog input RA0 OFF ; RA1 OFF ; RA2 ON ; RA3 OFF ; RA4 OFF ; JU5 RS-232 receive/transmit select N/A

;Requirements

66 Microchip Code ©1998 Sirius microSystems KEY.ASM - Chapter 10 Example Program

; If you are using the EPIC programmer and the In-Circuit programming ; cable, you must remove this cable from the PIC-MDS to ensure proper ; program execution. Otherwise, keys in column 4 will not be read.

Maclib ‘PF8x.INC’ ;Library file for PIC16F84 and PM assembler ;Comment this line out for other assemblers

Device PIC16F84,HS_OSC,WDT_OFF,PROTECT_OFF,PWRT_ON ID ‘KEY ‘

;Hardware Equates

ORG 0Ch ;Start of File register area

;Equates required by KEYPAD.LIB: Key DS 1 ;Key code return register

;Equates required by BIN2DEC.LIB and DEC2BIN.LIB: Hundreds DS 1 ;Hundreds digit Tens DS 1 ;Tens digit Ones DS 1 ;Ones digit

;Other equates Counter DS 1 ;character counter for LCD Counter1 DS 1 ;general purpose counter Counter2 DS 1 ;general purpose counter Counter3 DS 1 ;general purpose counter

ORG 00h ;Start program at Reset Vector

CLRF Key ;Clear Key storage register CALL LCD_Port ;Set up ports for LCD output CALL LCD_Init ;Initialize LCD and clear screen GOTO Initialize ;Continue with initialize routine

ORG 05h ;Continue after interrupt vector

Include ‘LCD.LIB’ ;LCD subroutines go here Include ‘KEYPAD.LIB’ ;followed by Keypad subroutines Include ‘BIN2DEC.LIB’ ;and Binary to Decimal conversion

Initialize CALL DisplayInit ;Display “Key Pressed:” on LCD

Main ;This program loop scans the keypad using KEYPAD.LIB and ;gets the key value from Key register. BIN2DEC.LIB is used ;to convert the binary key number to three decimal digits. ;Each decimal digit is converted to ASCII by adding 30h and ;is sent to the LCD display.

MOVF Key,0 ;Get key code in W CALL BIN_DEC ;and convert to decimal CALL LCD_Port ;Set up ports for LCD output MOVLW 8Dh ;Send address of hundreds digit CALL LCD_REG ;to LCD display data RAM MOVLW 30h ;Load constant to convert to ASCII ADDWF Hundreds,1 ;and add to hundreds digit ADDWF Tens,1 ;add to tens digit ADDWF Ones,1 ;and add to ones digit MOVF Hundreds,0 ;Get hundreds digit into W CALL LCD_Data ;and send it to LCD MOVF Tens,0 ;Get tens digit into W CALL LCD_Data ;and send it to LCD MOVF Ones,0 ;Get ones digit into W CALL LCD_Data ;and send it to LCD CALL KB_Port ;Set up Port B for keypad input Program Pull-Out ©1998 Sirius microSystems Microchip Code 67 References KEY.ASM - Chapter 10 Example Program

CALL KB_Scan ;Read Port B for key press GOTO Main ;Do it again!

DisplayInit ;Writes ‘Key Pressed:’ to first line of LCD using ;LCD display library (LCD.LIB).

MOVLW LCDCLR ;Send LCD clear display code CALL LCD_REG ;to LCD as a command MOVLW LCDLine1 ;Send LCD line one address to CALL LCD_REG ;LCD as a command CLRF Counter ;Reset character counter Get_Char MOVF Counter,0 ;Get character offset into W CALL Message ;use it to get character IORLW 00h ;RETLW won’t affect flags so use OR to BTFSC Z ;check for end of message RETURN ;and finish if done CALL LCD_Data ;If not done, send character to LCD INCF Counter,1 ;Add 1 to Counter GOTO Get_Char ;Do it again for next character

Message ADDWF PCL ;Offset program counter by adding W RETLW ‘K’ ;Message RETLW ‘e’ RETLW ‘y’ RETLW ‘ ‘ RETLW ‘P’ RETLW ‘r’ RETLW ‘e’ RETLW ‘s’ RETLW ‘s’ RETLW ‘e’ RETLW ‘d’ RETLW ‘:’ RETLW 0 ;End of message marker

Delay_5ms ;Delay loop used to initialize LCD

CLRF Counter1 ;Wipe first counter MOVLW 1Ah ;Load W with Timer Constant MOVWF Counter2 ;for Counter2

:Loop DECFSZ Counter1,1 ;Decrement first counter GOTO :Loop ;256 times DECFSZ Counter2,1 ;Decrement, second counter GOTO :Loop ;from constant, above RETURN

68 Microchip Code ©1998 Sirius microSystems KEYINT.ASM - Chapter 11 Example Program

;KEYINT.ASM v1.2 Last modified on August 31, 1998

;These program subroutines were written for the Sirius microSystems PICmicro ;development system. For more information contact Sirius microSystems by phone ;at 519-886-4462, or on the Internet at http://www.siriusmicro.com .

;Sirius microSystems provides this software on an “as is” basis, without any ;warranty, either expressed or implied. All Sirius microSystems software is ;provided for educational use only, and Sirius microSystems does not assume ;any liability for damages, either incidental or consequential, arising out of ;the application, use, or misuse of any of its software or hardware products. ;Sirius microSystems reserves the right, without further notice, to make ;changes to any of its software or hardware referred to in this program or ;library program in order to improve its function, design or reliability.

;Description

; Col. 1 2 3 4 ; Row +----+----+----+----+ ; Port B.0----1---| 1 | 2 | 3 | 4 | ; +----+----+----+----+ ; Port B.1----2---| 5 | 6 | 7 | 8 | ; +----+----+----+----+ ; Port B.2----3---| 9 | 10 | 11 | 12 | ; +----+----+----+----+ ; Port B.3----4---| 13 | 14 | 15 | 16 | ; +----+----+----+----+ ; Port B.4------+ | | | ; | | | ; Port B.5------+ | | ; | | ; Port B.6------+ | ; | ; Port B.7------+ ; ; This program demonstrates interrupt driven matrix keypad scanning ; along with LCD output using included subroutine libraries. This ; program is functionally equivalent to KEY.ASM in its operation, but ; puts the microcontroller to sleep in between operations. Sleep mode ; allows for ultra-low power consumption and is useful for extending ; the battery life or portable applications. ; ; The program first initializes the LCD and displays “Key Pressed:”. ; Next, assuming the microcontroller will shortly be sleeping, the ; letters “ZZZ” replace the key code number. Then, port B is ; reconfigured for keypad input with the pull-up resistors enabled. ; Finally, the RB Port Change interrupt is enabled after clearing ; the interrupt flag (just in case). After setting the Global ; Interrupt Enable flag, the microcontroller goes to sleep. ; ; When a key on the keypad is pressed, it pulls one of the RB4-7 ; input pins low, generating an interrupt. The microcontroller begins ; to execute the code at 0004h—the interrupt vector. Here, the RB ; port change interrupt is disabled, Port B is used to scan the keys ; for a key press, and the result is converted to ASCII and displayed ; on the LCD. By this point, the user is likely still holding the key ; on, and the microcontroller is once more put to sleep with the RB ; port change interrupt enabled. When the key is released, the code ; at 0004h again executes, updating the display. ; ; This program uses the DS (Define Space) directive instead of EQU ; (Equate) to define RAM registers. The advantage of this approach ; is that hardware registers can be created and removed from this ; program without manually re-locating their addresses. The drawback ; is that the physical location of the register is defined by the ; assembler, not the user. ; ; Also, notice that this program utilizes the space from memory Program Pull-Out ©1998 Sirius microSystems Microchip Code 69 References KEYINT.ASM - Chapter 11 Example Program

; location 0000h to the interrupt vector at 0004h. It’s not much ; space, but you can cram an extra 3 words into your program by ; doing this (the 4th word is the GOTO which jumps the interrupt ; vector, and is not really useful as storage).

;Jumper Settings

; JU2 5VDC internal/external select REG ; JU1 Variable DC internal/external select REG ; JU3 Processor power select jumper RUN ; JU4 EEPROM X8/X16 organization select N/A ; JU6 Port A LED output and analog input RA0 OFF ; RA1 OFF ; RA2 ON ; RA3 OFF ; RA4 OFF ; JU5 RS-232 receive/transmit select N/A

;Requirements

; If you are using the EPIC programmer and the In-Circuit programming ; cable, you must remove this cable from the PIC-MDS to ensure proper ; program execution. Otherwise, keys in column 4 will not be read.

Maclib ‘PF8x.INC’ ;Library file for PIC16F84 and PM assembler ;Comment this line out for other assemblers

Device PIC16F84,HS_OSC,WDT_OFF,PROTECT_OFF,PWRT_ON ID ‘KEYI’

;Hardware Equates

ORG 0Ch ;Start of File register area

;Equates required by KEYPAD.LIB: Key DS 1 ;Key code return register

;Equates required by BIN2DEC.LIB and DEC2BIN.LIB: Hundreds DS 1 ;Hundreds digit Tens DS 1 ;Tens digit Ones DS 1 ;Ones digit

;Other equates Counter DS 1 ;character counter for LCD Counter1 DS 1 ;general purpose counter Counter2 DS 1 ;general purpose counter Counter3 DS 1 ;general purpose counter

ORG 00h ;Start program at Reset Vector

CLRF Key ;Clear key storage register CALL LCD_Port ;Set up ports for LCD use CALL LCD_Init ;Initialize LCD and clear screen GOTO Initialize ;Continue with initialize routine

ORG 04h ;Interrupt service routine starts here

Check_RBIF ;When an interrupt occurs, Check_RBIF confirms it was ;generated by RB Port Change. If not, and other interrupts ;are enabled, they must get serviced in the Other_Int ;routine. When a valid key arrives, it gets displayed, ;then the port is re-configured for keypad input. Exiting ;this interrupt service routine, re-enables interrupts.

BTFSS RBIF ;Check for RB port change interrupt

70 Microchip Code ©1998 Sirius microSystems KEYINT.ASM - Chapter 11 Example Program

GOTO Other_Int ;If cleared, check other interrupts CALL Delay_5ms ;Wait for key to settle CALL Delay_5ms ;10 ms should be enough time CALL KB_Port ;Set up Port B for keypad scanning CALL KB_Scan ;Scan keys for key press MOVF Key,0 ;Check Key register for 0 - no key BTFSC Z ;by testing the Z flag GOTO Nap_Time ;If no key was returned, user let go ;so we display ZZZ to indicate sleep

CALL BIN_DEC ;If key returned, convert to decimal CALL LCD_Port ;Set up ports for LCD output MOVLW 8Dh ;Send address of hundreds digit CALL LCD_REG ;to display data RAM MOVLW 30h ;Load constant to convert to ASCII ADDWF Hundreds,1 ;and add to hundreds digit, ADDWF Tens,1 ;add to tens digit ADDWF Ones,1 ;and add to ones digit MOVF Hundreds,0 ;Gets hundreds digit into W and CALL LCD_Data ;send it to LCD MOVF Tens,0 ;Get tens digit into W and CALL LCD_Data ;send it to LCD MOVF Ones,0 ;Get ones digit into W and CALL LCD_Data ;send it to LCD

CALL KB_Port ;Set up Port B for keypad scanning CLRF PORTB ;and get ready for Port B Change MOVF PORTB,0 ;Update Port B input latches BCF RBIF ;Clear the interrupt flag RETFIE ;and return

Other_Int RETFIE ;Return and enable global interrupts

Initialize CALL DisplayInit ;Display “Key Pressed:” on LCD

Nap_Time MOVLW 8Dh ;Send address of hundreds digit CALL LCD_REG ;to display data RAM MOVLW ‘Z’ ;Load ASCII character Z CALL LCD_Data ;and send it to LCD MOVLW ‘Z’ ;Re-load ASCII character Z CALL LCD_Data ;and send it to LCD MOVLW ‘Z’ ;One more time! CALL LCD_Data ;and send it to LCD

CALL Init_Port_B ;Get Port B ready for interrupts

Main SLEEP ;Shut down and wait for key press NOP GOTO Main

DisplayInit ;Writes ‘Key Pressed:’ to first line of LCD display using ;LCD display library (LCD.LIB).

MOVLW LCDCLR ;Send LCD clear display code CALL LCD_REG ;to LCD as a command MOVLW LCDLine1 ;Send LCD line one address to CALL LCD_REG ;LCD as a command CLRF Counter ;Reset character counter Get_Char MOVF Counter,0 ;Get character offset into W CALL Message ;use it to get character IORLW 00h ;RETLW won’t affect flags so use OR to BTFSC Z ;check for end of message RETURN ;and finish if done CALL LCD_Data ;If not done, send character to LCD INCF Counter,1 ;Add 1 to Counter GOTO Get_Char ;Do it again for the next character Program Pull-Out ©1998 Sirius microSystems Microchip Code 71 References KEYINT.ASM - Chapter 11 Example Program

Message ADDWF PCL ;Offset program conter by adding W RETLW ‘K’ ;Message RETLW ‘e’ RETLW ‘y’ RETLW ‘ ‘ RETLW ‘P’ RETLW ‘r’ RETLW ‘e’ RETLW ‘s’ RETLW ‘s’ RETLW ‘e’ RETLW ‘d’ RETLW ‘:’ RETLW 0 ;End of message

Init_Port_B ;Sets Port B up for keypad scanning. RB0-3 are low outputs ;and RB4-7 are inputs with pull-ups enabled. When a key ;press occurs, one of the RB4-7 inputs goes low, generating ;and interrupt.

CALL KB_Port ;Set Port B for keypad scanning CLRF PORTB ;Make outputs low MOVLW 08h ;Set only RB port change interrupt MOVWF INTCON ;and write to interrupt register RETFIE ;Return and enable interrupts

Delay_5ms ;Delay loop used to initialize LCD

CLRF Counter1 ;Wipe first counter MOVLW 1Ah ;Load W with timer Constant MOVWF Counter2 ;for Counter2

:Loop DECFSZ Counter1,1 ;Decrement first counter GOTO :Loop ;256 times DECFSZ Counter2,1 ;Decrement, second counter GOTO :Loop ;from constant, above RETURN

Include ‘BIN2DEC.LIB’ ;Binary to Decimal conversion routine Include ‘KEYPAD.LIB’ ;Key pad scanning routines Include ‘LCD.LIB’ ;LCD subroutine library

72 Microchip Code ©1998 Sirius microSystems KEYSCAN.ASM - Chapter 9 Example Program

;KEYSCAN.ASM v1.2 Last modified on August 31, 1998

;These program subroutines were written for the Sirius microSystems PICmicro ;development system. For more information contact Sirius microSystems by phone ;at 519-886-4462, or on the Internet at http://www.siriusmicro.com .

;Sirius microSystems provides this software on an “as is” basis, without any ;warranty, either expressed or implied. All Sirius microSystems software is ;provided for educational use only, and Sirius microSystems does not assume ;any liability for damages, either incidental or consequential, arising out of ;the application, use, or misuse of any of its software or hardware products. ;Sirius microSystems reserves the right, without further notice, to make ;changes to any of its software or hardware referred to in this program or ;library program in order to improve its function, design or reliability.

;Description

; Col. 1 2 3 4 ; Row +----+----+----+----+ ; Port B.0----1---| 1 | 2 | 3 | 4 | ; +----+----+----+----+ ; Port B.1----2---| 5 | 6 | 7 | 8 | ; +----+----+----+----+ ; Port B.2----3---| 9 | 10 | 11 | 12 | ; +----+----+----+----+ ; Port B.3----4---| 13 | 14 | 15 | 16 | ; +----+----+----+----+ ; Port B.4------+ | | | ; | | | ; Port B.5------+ | | ; | | ; Port B.6------+ | ; | ; Port B.7------+ ; ; This program demonstrates matrix keypad scanning. Port B.0-3 connect ; to the keypad rows and are set as outputs. Port B.4-7 connect to the ; keypad columns and are set as inputs with the internal pull-up ; resistors enabled. To read the keypad, a row is set low. While the ; row is low, each column input is examined. Columns normally are high ; because of the pull-up resistors. If a column is low, the key at that ; row-column intersection is pressed. If no column is found low, the ; program advances to the next row. ; ; When a key press is detected, that row-column combination assigns a ; number from 1-16 (according to the above diagram) to the Key variable. ; The binary value in the Key variable is displayed on the LEDs. Note ; that the same Port B pins have two functions: most of the time they ; are scanning the keypad, with Port B.4-7 as inputs and Port B.0-3 as ; outputs. When a key is pressed Port B is temporarily set to output to ; display the key value. The key will display for a short period of ; time. When a key is not pressed, you will notice the key scanning ; taking place.

;Jumper Settings

; JU2 5VDC internal/external select REG ; JU1 Variable DC internal/external select REG ; JU3 Processor power select jumper RUN ; JU4 EEPROM X8/X16 organization select N/A ; JU6 Port A LED output and analog input RA0 OFF ; RA1 OFF ; RA2 ON ; RA3 OFF ; RA4 OFF ; JU5 RS-232 receive/transmit select N/A

;Requirements Program Pull-Out ©1998 Sirius microSystems Microchip Code 73 References KEYSCAN.ASM - Chapter 9 Example Program

; If you are using the EPIC programmer and the In-Circuit programming ; cable, you must remove this cable from the PIC-MDS to ensure proper ; program execution. Otherwise, keys in column 4 will not be read.

Maclib ‘PF8x.INC’ ;Library file for PIC16F84 and PM assembler ;Comment this line out for other assemblers

Device PIC16F84,HS_OSC,WDT_OFF,PROTECT_OFF,PWRT_ON ID ‘KSCN’

;Hardware Equates

Counter1 EQU 0Ch ;Delay counter register Counter2 EQU 0Dh ;Delay counter register Counter3 EQU 0Eh ;Delay counter register Key EQU 0Fh ;This register will hold a number from ;0-15 representing the last key pressed

ORG 00h ;Reset Vector location GOTO Initialize ;Start program after Interrupt vector

ORG 05h ;One location past Interrupt vector

Initialize BSF RP0 ;Select register page 1 MOVLW 0F0h ;Set keypad column connections to input ;(Port B.4-7) and row connections to ;output (Port B.0-3) MOVWF TRISB ;Write to Port B tristate register BSF RBPU ;Enable pull-ups on inputs BCF RP0 ;Go back to register page 0 CLRF Counter1 ;Clear delay loop counters CLRF Counter2 MOVLW 08h ;Preload Counter3 delay loop counter MOVWF Counter3 ;for 1/2 second delay

Main CLRF Key ;Clear Key register and INCF Key ;Increment Key MOVLW 0Eh ;Output 0 to first row only, MOVWF PORTB ;Output to Port B NOP ;Wait for signals to settle

Col_Check BTFSS PORTB.4 ;Check first column for low GOTO Dispkey ;and if low, display key INCF Key ;If no key press, increment key number BTFSS PORTB.5 ;Check second column for low GOTO Dispkey ;and if low, display key INCF Key ;If no key press, increment key number BTFSS PORTB.6 ;Check third column for low GOTO Dispkey ;and if low, display key INCF Key ;If no key press, increment key number BTFSS PORTB.7 ;Check fourth column for low GOTO Dispkey ;and if low, display key INCF Key ;If no key press, increment key number

Row_Set MOVLW 11h ;Load W with number of keys + 1 SUBWF Key,0 ;and compare with current key value BTFSC Z ;If keys + 1 = current key then GOTO Main ;no key was pressed

BSF C ;Set carry bit RLF PORTB ;so that row 1 is high during rotate GOTO Col_Check ;and check next column

Dispkey BSF RP0 ;Select register page 1 CLRF TRISB ;Set Port B to output BCF RP0 ;Go back to register page 0

74 Microchip Code ©1998 Sirius microSystems KEYSCAN.ASM - Chapter 9 Example Program

MOVF Key,0 ;Put value of Key into W MOVWF PORTB ;and display on LEDs

Delay DECFSZ Counter1 ;3-level nested loop GOTO Delay ;gives approx. 1/2 second delay DECFSZ Counter2 GOTO Delay DECFSZ Counter3 GOTO Delay

GOTO Initialize ;We’re done. Reset Port B and delay ;counters

Program Pull-Out ©1998 Sirius microSystems Microchip Code 75 References KEYSCLB.ASM - Chapter 10 Example Program

;KEYSCLB.ASM v1.2 Last modified on August 31, 1998

;These program subroutines were written for the Sirius microSystems PICmicro ;development system. For more information contact Sirius microSystems by phone ;at 519-886-4462, or on the Internet at http://www.siriusmicro.com .

;Sirius microSystems provides this software on an “as is” basis, without any ;warranty, either expressed or implied. All Sirius microSystems software is ;provided for educational use only, and Sirius microSystems does not assume ;any liability for damages, either incidental or consequential, arising out of ;the application, use, or misuse of any of its software or hardware products. ;Sirius microSystems reserves the right, without further notice, to make ;changes to any of its software or hardware referred to in this program or ;library program in order to improve its function, design or reliability.

;Description

; Col. 1 2 3 4 ; Row +----+----+----+----+ ; Port B.0----1---| 1 | 2 | 3 | 4 | ; +----+----+----+----+ ; Port B.1----2---| 5 | 6 | 7 | 8 | ; +----+----+----+----+ ; Port B.2----3---| 9 | 10 | 11 | 12 | ; +----+----+----+----+ ; Port B.3----4---| 13 | 14 | 15 | 16 | ; +----+----+----+----+ ; Port B.4------+ | | | ; | | | ; Port B.5------+ | | ; | | ; Port B.6------+ | ; | ; Port B.7------+ ; ; This program demonstrates matrix keypad scanning using calls to an ; included subroutine library. It is functionally equivalent to the ; KEYSCAN.ASM program. ; ; The following description is from KEYSCAN.ASM. Port B.0-3 connect ; to the keypad rows and are set as outputs. Port B.4-7 connect to the ; keypad columns and are set as inputs with the internal pull-up ; resistors enabled. To read the keypad, a row is set low. While the ; row is low, each column input is examined. Columns normally are high ; because of the pull-up resistors. If a column is low, the key at that ; row-column intersection is pressed. If no column is found low, the ; program advances to the next row. ; ; When a key press is detected, that row-column combination assigns a ; number from 1-16 (according to the above diagram) to the Key variable. ; The binary value in the Key variable is displayed on the LEDs. Note ; that the same Port B pins have two functions: most of the time they ; are scanning the keypad, with Port B.4-7 as inputs and Port B.0-3 as ; outputs. When a key is pressed Port B is temporarily set to output to ; display the key value. The key will display for a short period of ; time. When a key is not pressed, you will notice the key scanning ; taking place. ; ; KEYSCLB.ASM differs from KEYSCAN.ASM in that the keypad port control ; and scanning routines are called from KEYPAD.LIB. Since all of the ; actual keypad logic is contained in the KEYPAD.LIB file, KEYSCLB.ASM ; is a much shorter source file than KEYSCAN.ASM. This makes program ; creation simpler, since a programmer needs only to concentrate on ; the ‘real’ logic of the program, and not the nitty-gritty details. ; ; Subroutine libraries often require variables to be defined. Variables ; described in the subroutine library need to be defined in the calling ; program. This way, all variable definitions reside in the calling

76 Microchip Code ©1998 Sirius microSystems KEYSCLB.ASM - Chapter 10 Example Program

; program.

;Jumper Settings

; JU2 5VDC internal/external select REG ; JU1 Variable DC internal/external select REG ; JU3 Processor power select jumper RUN ; JU4 EEPROM X8/X16 organization select N/A ; JU6 Port A LED output and analog input RA0 OFF ; RA1 OFF ; RA2 ON ; RA3 OFF ; RA4 OFF ; JU5 RS-232 receive/transmit select N/A

;Requirements

; If you are using the EPIC programmer and the In-Circuit programming ; cable, you must remove this cable from the PIC-MDS to ensure proper ; program execution. Otherwise, keys in column 4 will not be read.

Maclib ‘PF8x.INC’ ;Library file for PIC16F84 and PM assembler ;Comment this line out for other assemblers

Device PIC16F84,HS_OSC,WDT_OFF,PROTECT_OFF,PWRT_ON ID ‘KSLB’

;Hardware Equates

Counter1 EQU 0Ch ;Delay counter register Counter2 EQU 0Dh ;Delay counter register Counter3 EQU 0Eh ;Delay counter register

;Equates required by KEYPAD.LIB Key EQU 0Fh ;This register will hold a number from ;0-15 representing the last key pressed

ORG 00h ;Reset Vector location GOTO Initialize ;Start program after Interrupt vector

ORG 05h ;One location past Interrupt vector

Include ‘KEYPAD.LIB’ ;KEYPAD.LIB subroutines go here

Initialize CALL KB_Port ;Library call to initialize Port B for ;keypad input CLRF Counter1 ;Clear delay loop counters CLRF Counter2 MOVLW 08h ;Preload Counter3 delay loop counter MOVWF Counter3 ;for 1/2 second delay

Main CALL KB_Scan ;Library call to scan keypad MOVF Key,0 ;Load value of Key into W BTFSC Z ;Check for no key GOTO Main ;If Z set, no key so scan again

Dispkey BSF RP0 ;Select register page 1 CLRF TRISB ;Set Port B to output BCF RP0 ;Go back to register page 0

MOVF Key,0 ;Put value of Key into W MOVWF PORTB ;and display on LEDs

Delay DECFSZ Counter1 ;3-level nested loop GOTO Delay ;gives approx. 1/2 second delay DECFSZ Counter2 GOTO Delay Program Pull-Out ©1998 Sirius microSystems Microchip Code 77 References KEYSCLB.ASM - Chapter 10 Example Program

DECFSZ Counter3 GOTO Delay

GOTO Initialize ;We’re done. Reset Port B and delay ;counters

78 Microchip Code ©1998 Sirius microSystems NVMEM.ASM - Chapter 13 Example Program

;NVMEM.ASM v1.2 Last modified on August 31, 1998

;These program subroutines were written for the Sirius microSystems PICmicro ;development system. For more information contact Sirius microSystems by phone ;at 519-886-4462, or on the Internet at http://www.siriusmicro.com .

;Sirius microSystems provides this software on an “as is” basis, without any ;warranty, either expressed or implied. All Sirius microSystems software is ;provided for educational use only, and Sirius microSystems does not assume ;any liability for damages, either incidental or consequential, arising out of ;the application, use, or misuse of any of its software or hardware products. ;Sirius microSystems reserves the right, without further notice, to make ;changes to any of its software or hardware referred to in this program or ;library program in order to improve its function, design or reliability.

;Description

; This program demonstrates how to use EEPROM.LIB to store important ; data in the PIC16F84’s non-volatile EEPROM memory. NVMEM simply ; displays the contents of the first four EEPROM memory locations on ; the LCD display and expects you to enter a 4-digit number from the ; keypad. This 4-digit number (which could represent a pass-code) is ; stored into EEPROM and a message indicating that you should remove ; power from the PIC-MDS is displayed. Remove power from the PIC-MDS, ; and upon powering up, the number you entered will be displayed.

;Jumper Settings

; JU2 5VDC internal/external select REG ; JU1 Variable DC internal/external select REG ; JU3 Processor power select jumper RUN ; JU4 EEPROM X8/X16 organization select N/A ; JU6 Port A LED output and analog input RA0 OFF ; RA1 OFF ; RA2 ON ; RA3 OFF ; RA4 OFF ; JU5 RS-232 receive/transmit select N/A

;Requirements

; If you are using the EPIC programmer and the In-Circuit programming ; cable, you must remove this cable from the PIC-MDS to ensure proper ; program execution. Otherwise, keys in column 4 will not be read.

Maclib ‘PF8x.INC’ ;Library file for PIC16F84 and PM assembler ;Comment this line out for other assemblers

Device PIC16F84,HS_OSC,WDT_OFF,PROTECT_OFF,PWRT_ON ID ‘NVME’

;Hardware Equates

ORG 0Ch ;Start of File register area

Counter DS 1 ;LCD character counter

Counter1 DS 1 ;LCD delay counter Counter2 DS 1 ;LCD delay counter

Key DS 1 ;Key return code variable

Digit DS 1 ;ASCII digit counter variable

ORG 00h ;Start program at Reset Vector Program Pull-Out ©1998 Sirius microSystems Microchip Code 79 References NVMEM.ASM - Chapter 13 Example Program

CLRF Key ;Clear Key return variable CLRF Counter1 ;and delay counters CLRF Counter2 GOTO Initialize ;Continue with initialize routine

ORG 05h ;One location past Interrupt Vector

Include ‘EEPROM.LIB’ ;EEPROM subroutine library Include ‘KEYPAD.LIB’ ;Keypad scanning subroutine library Include ‘LCD.LIB’ ;LCD subroutine library

Initialize ;This subroutine initializes the LCD display and writes ;a message on to line 1 and ‘=’ on to line 2. The cursor ;is turned on to indicate where input will be shown.

CLRF Digit ;Clear digit counter CALL LCD_Port ;Set up ports for LCD use CALL LCD_Init ;Initialize LCD and clear screen CALL Disp_Line1 ;Send first line message to LCD

Send_Old ;Reads EEPROM addresses 0-3 and writes the contents to the ;LCD display.

CLRF EEADR ;Select EEPROM address 00 :Loop CALL EE_Read ;Call EE_Read to place data into MOVF EEDATA,0 ;EEDATA, and read EEDATA into W CALL LCD_Data ;Copy W to LCD DDRAM INCF EEADR ;Increment to next EEPROM address MOVLW 04h ;Load W with number of data bytes SUBWF EEADR,0 ;and compare with EEADR BTFSS Z ;by checking Z GOTO :Loop ;If not at EEADR 04, get next data

Line2 MOVLW LCDLine2 ;Load W with line 2 DDRAM address CALL LCD_Reg ;and write to LCD CALL Disp_Line2 ;Send second line message to LCD

MOVLW CursOn ;Load W with Cursor On command CALL LCD_Reg ;and write to LCD

Get_New ;Wait for key presses and after a debounce delay stores the ;ASCII value of the current key codes in EEPROM memory from ;address 0-3.

CLRF EEADR ;Reset EEADR to the beginning CALL KB_Port ;Configure Port B for keypad

Get_Key CALL KB_Scan ;Get Key return code MOVF Key,0 ;Check Key return code BTFSC Z ;for no key press (0=no key) GOTO Get_Key ;If no key pressed, try again CALL Delay_5ms ;Wait for key to settle CALL Delay_5ms CALL Delay_5ms CALL Delay_5ms

CALL KB_Scan ;Read Key code after settling MOVF Key,0 ;Read Key code into W CALL Key_Remap ;and Remap key codes

MOVWF EEDATA ;Save new Key code in EEDATA CALL EE_Write ;Write key data to current EEADR CALL EE_Wait ;and wait for write to finish

CALL EE_Read ;Read current EEADR to check ;that EEDATA was written properly

CALL LCD_Port ;Configure Ports for LCD

80 Microchip Code ©1998 Sirius microSystems NVMEM.ASM - Chapter 13 Example Program

MOVF EEDATA,0 ;Get saved Key code from EEPROM CALL LCD_Data ;and display on LCD

CALL KB_Port ;Set Port B for keypad use Wait CALL KB_Scan ;Scan keypad MOVF Key,0 ;Check key for 0 BTFSS Z ;And if Z=1 key has been released GOTO Wait ;Otherwise, wait for release CALL Delay_5ms ;Wait for key to settle CALL Delay_5ms CALL Delay_5ms CALL Delay_5ms

INCF EEADR ;Increment to next EEPROM address MOVLW 04h ;Load W with number of data bytes SUBWF EEADR,0 ;and compare with EEADR BTFSS Z ;by checking Z GOTO Get_Key ;If not at EEADR 04, get next data CALL LCD_Port ;Reconfigure ports for LCD MOVLW LCDLine1 ;Load W with line 1 DDRAM address CALL LCD_Reg ;and write to LCD CALL Disp_Done ;Display done message SLEEP

Key_Remap ;Changes key codes into ASCII values.

ADDWF PCL ;Use old Key to offset PC NOP ;No Key=0 code RETLW 30h ;key 1 remapped to ASCII 30h ‘0’ RETLW 31h ;key 2 remapped to ASCII 31h ‘1’ RETLW 32h ;key 3 remapped to ASCII 32h ‘2’ RETLW 33h ;key 4 remapped to ASCII 33h ‘3’ RETLW 34h ;key 5 remapped to ASCII 34h ‘4’ RETLW 35h ;key 6 remapped to ASCII 35h ‘5’ RETLW 36h ;key 7 remapped to ASCII 36h ‘6’ RETLW 37h ;key 8 remapped to ASCII 37h ‘7’ RETLW 38h ;key 9 remapped to ASCII 38h ‘8’ RETLW 39h ;key 10 remapped to ASCII 39h ‘9’ RETLW 41h ;key 11 remapped to ASCII 41h ‘A’ RETLW 42h ;key 12 remapped to ASCII 42h ‘B’ RETLW 43h ;key 13 remapped to ASCII 43h ‘C’ RETLW 44h ;key 14 remapped to ASCII 44h ‘D’ RETLW 45h ;key 15 remapped to ASCII 45h ‘E’ RETLW 46h ;key 16 remapped to ASCII 46h ‘F’

Disp_Line1 ;Writes ‘Old Data: ‘ to the first line of the LCD ;display using LCD display library (LCD.LIB).

CLRF Counter ;Reset character counter :Get_Char MOVF Counter,0 ;Get character offset into W CALL Message1 ;use it to get character IORLW 00h ;RETLW won’t affect flags so use OR to BTFSC Z ;check for end of message RETURN ;and finish if done CALL LCD_Data ;If not done, send character to LCD INCF Counter,1 ;Add 1 to Counter GOTO :Get_Char ;Do it again for the next character

Message1 ADDWF PCL ;Offset program counter by adding W RETLW ‘O’ ;Message1 RETLW ‘l’ RETLW ‘d’ RETLW ‘ ‘ RETLW ‘D’ RETLW ‘a’ Program Pull-Out ©1998 Sirius microSystems Microchip Code 81 References NVMEM.ASM - Chapter 13 Example Program

RETLW ‘t’ RETLW ‘a’ RETLW ‘:’ RETLW ‘ ‘ RETLW 0 ;End of message

Disp_Line2 ;Writes ‘New Data: ‘ to the second line of the LCD ;display using LCD display library (LCD.LIB).

CLRF Counter ;Reset character counter :Get_Char MOVF Counter,0 ;Get character offset into W CALL Message2 ;use it to get character IORLW 00h ;RETLW won’t affect flags so use OR to BTFSC Z ;check for end of message RETURN ;and finish if done CALL LCD_Data ;If not done, send character to LCD INCF Counter,1 ;Add 1 to Counter GOTO :Get_Char ;Do it again for the next character

Message2 ADDWF PCL ;Offset program counter by adding W RETLW ‘N’ ;Message2 RETLW ‘e’ RETLW ‘w’ RETLW ‘ ‘ RETLW ‘D’ RETLW ‘a’ RETLW ‘t’ RETLW ‘a’ RETLW ‘:’ RETLW ‘ ‘ RETLW 0 ;End of message

Disp_Done ;Writes ‘Power down now.’ to the first line of the LCD ;display using LCD display library (LCD.LIB).

CLRF Counter ;Reset character counter :Get_Char MOVF Counter,0 ;Get character offset into W MOVLW HI Message3 ;Move the High Byte of Message3 ;location into W MOVWF PCLATH ;and Move it into PCLATH MOVLW Message3+1 ;Move message address + 1 into W ADDWF Counter,0 ;Calculate offset address and BTFSC C ;see if it overflows INCF PCLATH ;If so, increment PCLATH CALL Message3 ;Jump to the data table

IORLW 00h ;RETLW won’t affect flags so use OR to BTFSC Z ;check for end of message RETURN ;and finish if done CALL LCD_Data ;If not done, send character to LCD INCF Counter,1 ;Add 1 to Counter GOTO :Get_Char ;Do it again for the next character

Message3 MOVWF PCL ;W contains low program counter ;byte and points to next location ;plus Counter offset RETLW ‘P’ RETLW ‘o’ RETLW ‘w’ RETLW ‘e’ RETLW ‘r’ RETLW ‘ ‘ RETLW ‘d’ RETLW ‘o’ RETLW ‘w’ RETLW ‘n’

82 Microchip Code ©1998 Sirius microSystems NVMEM.ASM - Chapter 13 Example Program

RETLW ‘ ‘ RETLW ‘n’ RETLW ‘o’ RETLW ‘w’ RETLW ‘.’ RETLW ‘ ‘ RETLW 0 ;End of message

Delay_5ms ;Delay loop used to initialize LCD

CLRF Counter1 ;Wipe first counter MOVLW 1Ah ;Load W with timer Constant MOVWF Counter2 ;for Counter2

:Loop DECFSZ Counter1,1 ;Decrement first counter GOTO :Loop ;256 times DECFSZ Counter2,1 ;Decrement, second counter GOTO :Loop ;from constant, above RETURN

Program Pull-Out ©1998 Sirius microSystems Microchip Code 83 References OUTPUT.ASM - Chapter 5 Example Program

;OUTPUT.ASM v1.2 Last modified on August 31, 1998

;These program subroutines were written for the Sirius microSystems PICmicro ;development system. For more information contact Sirius microSystems by phone ;at 519-886-4462, or on the Internet at http://www.siriusmicro.com .

;Sirius microSystems provides this software on an “as is” basis, without any ;warranty, either expressed or implied. All Sirius microSystems software is ;provided for educational use only, and Sirius microSystems does not assume ;any liability for damages, either incidental or consequential, arising out of ;the application, use, or misuse of any of its software or hardware products. ;Sirius microSystems reserves the right, without further notice, to make ;changes to any of its software or hardware referred to in this program or ;library program in order to improve its function, design or reliability.

;Description

; This program demonstrates port output. It initializes all port B pins ; to be outputs and then places a pattern on port B to illuminate LEDs.

;Jumper Settings

; JU2 5VDC internal/external select REG ; JU1 Variable DC internal/external select REG ; JU3 Processor power select jumper RUN ; JU4 EEPROM X8/X16 organization select N/A ; JU6 Port A LED output and analog input RA0 OFF ; RA1 OFF ; RA2 ON ; RA3 OFF ; RA4 OFF ; JU5 RS-232 receive/transmit select N/A

;Requirements

; This is a simple program that requires no prior setup.

Maclib ‘PF8x.INC’ ;Library file for PIC16F84 and PM assembler ;Comment this line out for other assemblers

Device PIC16F84,HS_OSC,WDT_OFF,PROTECT_OFF,PWRT_ON ID ‘OUTP’

ORG 00h ;Reset Vector location GOTO Initialize ;Start program after Interrupt vector

ORG 05h ;One location past Interrupt vector

Initialize BSF RP0 ;Select memory register page 1 CLRF TRISB ;Make Port B output by clearing TRISB BCF RP0 ;Go back to register page 0

Main MOVLW 01010101b ;Move 01010101b into W and MOVWF PORTB ;output pattern to LEDs on Port

Done SLEEP ;Stop executing the program

84 Microchip Code ©1998 Sirius microSystems RECV232.ASM - Chapter 15 Example Program

;RECV232.ASM v1.2 Last modified on August 31, 1998

;These program subroutines were written for the Sirius microSystems PICmicro ;development system. For more information contact Sirius microSystems by phone ;at 519-886-4462, or on the Internet at http://www.siriusmicro.com .

;Sirius microSystems provides this software on an “as is” basis, without any ;warranty, either expressed or implied. All Sirius microSystems software is ;provided for educational use only, and Sirius microSystems does not assume ;any liability for damages, either incidental or consequential, arising out of ;the application, use, or misuse of any of its software or hardware products. ;Sirius microSystems reserves the right, without further notice, to make ;changes to any of its software or hardware referred to in this program or ;library program in order to improve its function, design or reliability.

;Description

; This program demonstrates serial port polling and software timed ; RS-232 signal reception. Serial characters are received at the serial ; header (H3), translated from RS-232 to TTL levels by the MAX232, ; and routed through the serial Transmit/Receive select jumper (JU5) ; to RA.4 on the PIC. Once characters are received, they are scrolled ; across the LCD display. RA.4 was chosen to receive serial characters ; because it can generate a TMR0 interrupt in response to a change in ; the signal level applied to it. ; ; To ensure accurate serial bit timing, use a crystal oscillator and ; not a ceramic resonator to generate the processor clock.

;Jumper Settings

; JU2 5VDC internal/external select REG ; JU1 Variable DC internal/external select REG ; JU3 Processor power select jumper RUN ; JU4 EEPROM X8/X16 organization select N/A ; JU6 Port A LED output and analog input RA0 OFF ; RA1 OFF ; RA2 ON ; RA3 OFF ; RA4 OFF ; JU5 RS-232 receive/transmit select RX

;Requirements

; An external RS-232 serial terminal or a computer with an appropriate ; connection to the PIC-MDS serial input header (H3). For testing we ; used a cable wired as follows: ; ; Computer DB-25 PIC-MDS ; Transmit pin 2 —> H3.3 - Rx ; Receive pin 3 —> H3.1 - Tx ; Ground pin 7 —> H3.2 - Gnd

Maclib ‘PF8x.INC’ ;Library file for PIC16F84 and PM assembler ;Comment this line out for other assemblers

Device PIC16F84,HS_OSC,WDT_OFF,PROTECT_OFF,PWRT_ON ID ‘232R’

;Hardware Equates

ORG 0Ch ;Start of File register area

;Counter equates CharAddress DS 1 ;Holds current LCD DDRAM address CharCounter DS 1 ;Counts characters before scrolling Counter1 DS 1 ;Delay counter for Delay_5ms Program Pull-Out ©1998 Sirius microSystems Microchip Code 85 References RECV232.ASM - Chapter 15 Example Program

Counter2 DS 1 ;Delay counter for Delay_5ms

;Equates required by RS232RX.LIB Counter DS 1 ;Bit delay counter BitCounter DS 1 ;RS232 bit counter register Receive DS 1 ;Received byte storage register

;Other equates LCD_Length EQU 16 ;Number of characters per LCD line

ORG 00h ;Start program at Reset Vector

CALL LCD_Port ;Set up ports for LCD use CALL LCD_Init ;Initialize LCD and clear screen CALL Receive_Port ;Set RA.4 for serial input GOTO Initialize ;Jump over interrupt vector

ORG 05h ;Program starts after interrupt vector

Include ‘LCD.LIB’ ;LCD subroutine library Include ‘RS232RX.LIB’ ;RS-232 receive library

Initialize ;Prepare character counters and LCD for data

MOVLW LCD_Length ;Load W with number of LCD characters MOVWF CharCounter ;and save in CharCounter DECF CharCounter ;-1 from CharCounter to account for 0 MOVLW CursBlink ;Load W with constant to blink cursor CALL LCD_Reg ;and write to LCD as a command

MOVLW LCDLine1 ;Load W with DDRAM address of line 1 MOVWF CharAddress ;and save in CharAddress variable CALL LCD_Reg ;before writing it to the LCD

Main ;Receive serial characters in Receive buffer

CALL Receive_Wait ;Wait for and receive one serial byte

MOVF Receive,0 ;After receiving, check character for BTFSC Z ;and error (Receive=00h) GOTO Main ;If no character, wait again

LCD_Write ;Write the character in Receive buffer to LCD display

MOVF Receive,0 ;Move received character into W & CALL LCD_Data ;write to current DDRAM address INCF CharAddress ;Add 1 to DDRAM address counter MOVLW 0A8h ;Load W with last DDRAM address +1 SUBWF CharAddress,0 ;and subtract from CharAddress BTFSC Z ;to see if 40 characters are full GOTO Line_Reset ;If so, reset LCD to start of line

MOVF CharCounter,1 ;Check Character counter for end BTFSC Z ;of visible screen by checking Z GOTO Scroll ;If at end, scroll display left DECF CharCounter ;If not, decrement CharCounter GOTO Main ;and wait for next character

Scroll ;Scroll display left to keep new characters in LCD window

MOVLW LCDLeft ;Load W with LCD shift left command CALL LCD_Reg ;and send to LCD GOTO Main ;Wait for next character

Line_Reset ;If 40 characters have been written to DDRAM, scroll the ;display contents left and reset DDRAM to line 1.

86 Microchip Code ©1998 Sirius microSystems RECV232.ASM - Chapter 15 Example Program

MOVLW LCDLeft ;Load W with LCD shift left command CALL LCD_Reg ;and write to LCD MOVLW LCDLine1 ;Load W with first DDRAM address MOVWF CharAddress ;and save in CharAddress register CALL LCD_Reg ;before writing it to LCD GOTO Main ;Wait for more serial data

Delay_5ms ;Delay loop used to initialize LCD

CLRF Counter1 ;Clear Counter1 MOVLW 1Ah ;Load W with timer Constant MOVWF Counter2 ;for Counter2

:Loop DECFSZ Counter1,1 ;Decrement first counter GOTO :Loop ;256 times DECFSZ Counter2,1 ;Decrement, second counter GOTO :Loop ;from constant, above RETURN

Program Pull-Out ©1998 Sirius microSystems Microchip Code 87 References SEETEST.ASM - Chapter 17 Example Program

;SEETEST.ASM v1.2 Last modified on August 31, 1998

;These program subroutines were written for the Sirius microSystems PICmicro ;development system. For more information contact Sirius microSystems by phone :at 519-886-4462, or on the Internet at http://www.siriusmicro.com .

;Sirius microSystems provides this software on an “as is” basis, without any ;warranty, either expressed or implied. All Sirius microSystems software is ;provided for educational use only, and Sirius microSystems does not assume ;any liability for damages, either incidental or consequential, arising out of ;the application, use, or misuse of any of its software or hardware products. ;Sirius microSystems reserves the right, without further notice, to make ;changes to any of its software or hardware referred to in this program or ;library program in order to improve its function, design or reliability.

;Description

; SEETEST is a utility to test and program 93LC56 (256 byte) and 93LC66 ; (512 byte) serial EEPROMs (SEEPROMs) in the Sirius PICmicro Devemopment ; System. SEEPROM address and data are displayed in Hex on the top line of ; the LCD display. The lower line displays the prompts ‘Dwn Up Sel Chg’. ; The top row of buttons on the keypad acts as soft keys for the prompts ; on the LCD. Selecting the ‘Dwn’ or ‘Up’ buttons decrements or increments ; the SEEPROM address. For each address, the data stored at that address ; is displayed. Pressing ‘Sel’ allows you to enter a 3-digit address (000- ; 1FF) to view or change. Pressing ‘Chg’ allows you to enter a 2-digit hex ; byte into the current address.

;Jumper Settings

; JU2 5VDC internal/external select REG ; JU1 Variable DC internal/external select REG ; JU3 Processor power select jumper RUN ; JU4 EEPROM X8/X16 organization select X8 ; JU6 Port A LED output and analog input RA0 OFF ; RA1 OFF ; RA2 ON ; RA3 OFF ; RA4 OFF ; JU5 RS-232 receive/transmit select N/A

;Requirements

; If you are using the EPIC programmer and the In-Circuit programming ; cable, you must remove this cable from the PIC-MDS to ensure proper ; program execution. Otherwise, keys in column 4 will not be read.

Maclib ‘PF8x.INC’ ;Library file for PIC16F84 and PM assembler ;Comment this line out for other assemblers

Device PIC16F84, HS_OSC, WDT_OFF, PROTECT_OFF, PWRT_ON ID ‘SEET’

;Hardware Equates

ORG 0Ch ;Start of File register area

Digit DS 1 ;Hex digit register Character DS 1 ;LCD message character offset Counter1 DS 1 ;LCD delay/keystroke delay counter Counter2 DS 1 ;LCD delay/keystroke delay counter Delay DS 1 ;Keystroke delay duration KeyTemp DS 1 ;Temporary Key register

Addrh DS 1 ;Temporary SEEPROM high address byte Addrl DS 1 ;Temporary SEEPROM low address byte

88 Microchip Code ©1998 Sirius microSystems SEETEST.ASM - Chapter 17 Example Program

;Equates required by KEYPAD.LIB

Key DS 1 ;Key return code variable

;Equates required by SEEPROM.LIB

SEEAddrh DS 1 ;SEEPROM high address byte SEEAddrl DS 1 ;SEEPROM low address byte SEEClock DS 1 ;SEEPROM clock counter register SEEData DS 1 ;SEEPROM data storage byte

;Software Equates

Menu_Msg EQU 0 ;Menu message offset Status_Msg EQU 16 ;Status display message offset Addr_Msg EQU 31 ;”Enter Address” message offset Data_Msg EQU 47 ;”Enter Data” message offset

Address EQU 5 ;Cursor offset for address display Data EQU 14 ;Cursor offset for data display

ORG 00h ;Start program at Reset Vector

CLRF Key ;Clear Key return variable CLRF Counter1 ;and delay counters CLRF Counter2 GOTO Initialize ;Continue with initialize routine

ORG 05h ;One location past Interrupt Vector

Include ‘SEEPROM.LIB’ ;EEPROM subroutine library Include ‘LCD.LIB’ ;LCD subroutine library Include ‘KEYPAD.LIB’ ;Keypad scanning subroutine library

Initialize ;Continue setting variables and initialize the LCD display.

CLRF Digit ;Clear hex digit register CLRF Addrl ;Clear program low and high address CLRF Addrh ;bytes to set initial address to 000h

Update_Status ;Displays the current SEEPROM address and data on the top line ;of the LCD and the Menu options on the bottom line.

CALL LCD_Port ;Set up ports for LCD use CALL LCD_Init ;Initialize LCD and clear screen MOVLW LCDLine1 ;Send line 1 starting character CALL LCD_Reg ;address to LCD MOVLW Status_Msg ;Load W with Status message offset CALL Disp_Message ;and call display message routine MOVLW LCDLine1+Address ;Set LCD character position to CALL LCD_Reg ;start of address display area MOVF Addrh,W ;Load W with high address byte ANDLW 0Fh ;Clear upper nybble CALL Hex_Remap ;and convert to ASCII for LCD CALL LCD_Data ;and display on LCD MOVF Addrl,W ;Load W with low address byte MOVWF Digit ;and save a copy in Digit register SWAPF Digit,W ;Switch nybbles and copy to W ANDLW 0Fh ;Clear upper nybble before CALL Hex_Remap ;converting to ASCII for CALL LCD_Data ;display on LCD

MOVF Addrl,W ;Load W with low address byte again ANDLW 0Fh ;Clear upper nybble before Program Pull-Out ©1998 Sirius microSystems Microchip Code 89 References SEETEST.ASM - Chapter 17 Example Program

CALL Hex_Remap ;converting to ASCII for CALL LCD_Data ;display on LCD

CALL SEE_Port ;Set up Port A for SEEPROM use MOVF Addrl,W ;Copy low address byte to MOVWF SEEAddrl ;SEEPROM low address byte MOVF Addrh,W ;Copy high address byte to MOVWF SEEAddrh ;SEEPROM high address byte MOVLW SEERead ;Send SEEPROM Read byte command CALL SEE_Command ;to SEEPROM

CALL LCD_Port ;Set up Ports for LCD use MOVLW LCDLine1+Data ;Set LCD character position to CALL LCD_Reg ;start of data display area SWAPF SEEData,W ;Switch nybbles of SEEPROM data to W ANDLW 0Fh ;Clear upper nybble before CALL Hex_Remap ;converting to ASCII for CALL LCD_Data ;display on LCD

MOVF SEEData,W ;Load W with SEEPROM data byte ANDLW 0Fh ;Clear upper nybble before CALL Hex_Remap ;converting to ASCII for CALL LCD_Data ;display on LCD

MOVLW LCDLine2 ;Send LCD line 2 character address CALL LCD_Reg ;to LCD as a command MOVLW Menu_Msg ;Load W with Menu message offset CALL Disp_Message ;and call display message routine

CALL KB_Port ;Set Port B for keypad use CALL KB_Scan ;and scan keys for key press MOVF Key,W ;Load Key return code into W MOVWF KeyTemp ;and save in temporary register

MOVLW 01h ;Copy short key repeat delay into MOVWF Delay ;Delay register

Wait_for_Key ;Waits for a top-row key press and determines the action that ;follows the key press.

CALL KB_Scan ;Get Key return code MOVF Key,W ;Load Key code into W to set flags BTFSC Z ;and check for 0 (0=no key) GOTO Wait_for_Key ;If no key pressed, try again

:Key1 DECFSZ Key ;Check for Key=1 by subtracting GOTO :Key2 ;If not 0, check for Key=2 MOVF KeyTemp,W ;Load W with previous key code SUBLW 01h ;and check for equality with 1 BTFSC Z ;If not equal, key not held so skip GOTO :Delay1 ;If equal, key held. Use short delay. MOVLW 20h ;Copy long delay into MOVWF Delay ;Delay register :Delay1 CALL Repeat_Delay ;and wait for delay CALL Addr_Down ;If 0, decrment SEEPROM address GOTO Update_Status ;and redisplay Status screen

:Key2 DECFSZ Key ;Check for Key=2 by subtracting GOTO :Key3 ;If not 0, check for Key=3 MOVF KeyTemp,W ;Load W with previous key code SUBLW 02h ;and check for equality with 1 BTFSC Z ;If not equal, key not held so skip GOTO :Delay2 ;If equal, key held. Use short delay. MOVLW 20h ;Copy long delay into MOVWF Delay ;Delay register :Delay2 CALL Repeat_Delay ;and wait for delay CALL Addr_Up ;If 0, increment SEEPROM address

90 Microchip Code ©1998 Sirius microSystems SEETEST.ASM - Chapter 17 Example Program

GOTO Update_Status ;and redisplay Status screen

:Key3 DECFSZ Key ;Check for Key=3 by subtracting GOTO :Key4 ;If not 0, check for Key=4 CALL Addr_Set ;If 0, allow user to set address CALL KB_Port ;Set Port B for keypad use CALL Key_Release ;and wait for all keys to be released GOTO Update_Status ;Redisplay Status screen

:Key4 DECFSZ Key ;Check for Key=4 by subtracting GOTO Wait_for_Key ;If not 0, ignore other keys CALL Data_Set ;If 0, allow user to set data CALL KB_Port ;Set Port B for keypad use CALL Key_Release ;and wait for all keys to be released GOTO Update_Status ;Redisplay Status screen

Addr_Down ;Decrements the current 9-bit SEEPROM address.

MOVF Addrl,1 ;Check Addrl for 0 by moving it onto BTFSC Z ;itself and checking the Z flag GOTO :Check_Addrh ;If Addrl is 0, check Addrh DECF Addrl ;Otherwise, decrement Addrl and RETURN ;return to calling program

:Check_Addrh MOVF Addrh,1 ;Check Addrh for 0 by moving it onto BTFSC Z ;itself and checking the Z flag RETURN ;If Addrh=0 & Addrl=0, don’t decrement DECF Addrh ;Otherwise, decrement Addrh and DECF Addrl ;Addrl before returning RETURN

Addr_Up ;Increments the current 9-bit SEEPROM address.

INCF Addrl ;Increment Addrl and check for a BTFSS Z ;roll-over to 0 RETURN ;If no roll-over, return MOVF Addrh,1 ;Check Addrh for 0 by moving it onto BTFSS Z ;itself and chekcing the Z flag GOTO :Fix_Addrl ;If Addrl=0 & Addrh=1, decrement Addrl INCF Addrh ;Otherwise, increment Addrh RETURN ;and return

:Fix_Addrl DECF Addrl ;Decrement Addrl to highest possible RETURN ;address of 1FF and return

Addr_Set ;Allows the user to enter the 9-bit SEEPROM Address.

CALL LCD_Port ;Set Port A and Port B for LCD use MOVLW LCDLine2 ;Set LCD charcter position to line CALL LCD_Reg ;two and send command to LCD MOVLW Addr_Msg ;Load W with Address message offset CALL Disp_Message ;and call display message routine

MOVLW LCDLine1+Address ;Set LCD character position to CALL LCD_Reg ;start of address display area MOVLW ‘?’ ;Load W with “?” character CALL LCD_Data ;and send to LCD three times to MOVLW ‘?’ ;indicate address entry field CALL LCD_Data MOVLW ‘?’ CALL LCD_Data MOVLW LCDLine1+Address ;Set LCD character position to CALL LCD_Reg ;start of address display area MOVLW CursBlink ;and set blinking cursor CALL LCD_Reg ;Send command to LCD Program Pull-Out ©1998 Sirius microSystems Microchip Code 91 References SEETEST.ASM - Chapter 17 Example Program

CLRF Addrh ;Clear high and low CLRF Addrl ;SEEPROM address bytes CALL KB_Port ;Set Port B for keypad use and CALL Key_Release ;make sure that no keys are pressed :Digit1 CALL KB_Scan ;Scan keys for a keystroke MOVF Key,W ;Load Key into W to check for keypress BTFSC Z ;and check Z flag GOTO :Digit1 ;If Z=0, no key pressed. Scan again CALL Key_Remap ;Convert key stroke to binary nybble MOVWF Digit ;and save in Digit register MOVF Digit,1 ;Reread Digit to set flags BTFSC Z ;Check for Digit=0 by testing Z GOTO :Store1 ;If Digit was 0, store & display it DECF Digit,W ;Otherwise, check for Digit=1 by BTFSS Z ;decrementing and checking Z GOTO :Digit1 ;If not 0 or 1 wait for valid Digit

:Store1 CALL LCD_Port ;Set Port A and Port B for LCD use MOVF Digit,W ;Copy saved Digit to MOVWF Addrh ;Addrh register CALL Hex_Remap ;and convert to ASCII value CALL LCD_Data ;Display Digit code on LCD

CALL KB_Port ;Set Port B for keypad use and CALL Key_Release ;make sure that no keys are pressed :Digit2 CALL KB_Scan ;Scan keys for a keystroke MOVF Key,W ;Load Key into W to check for keypress BTFSC Z ;and check Z flag GOTO :Digit2 ;If Z=0, no key pressed. Scan again CALL Key_Remap ;Convert key stroke to binary nybble MOVWF Digit ;Save result to Digit register and MOVWF Addrl ;save in top of Addrl register SWAPF Addrl,1 ;by swapping nybbles of Addrl CALL LCD_Port ;Set Port A and Port B for LCD use MOVF Digit,W ;Load W with Digit value CALL Hex_Remap ;and convert to ASCII CALL LCD_Data ;Display Digit code on LCD

CALL KB_Port ;Set Port B for keypad use and CALL Key_Release ;make sure that no keys are pressed :Digit3 CALL KB_Scan ;Scan keys for a keystroke MOVF Key,W ;Load Key into W to check for keypress BTFSC Z ;and check Z flag GOTO :Digit3 ;If Z=0, no key pressed. Scan again CALL Key_Remap ;Convert key stroke to binary nybble MOVWF Digit ;Save result to Digit register and IORWF Addrl ;save in bottom of Addrl CALL LCD_Port ;Set Port A and Port B for LCD use MOVLW CursOff ;Send LCD command to turn off CALL LCD_Reg ;blinking cursor MOVF Digit,W ;Load W with Digit value CALL Hex_Remap ;and convert to ASCII CALL LCD_Data ;Display Digit code on LCD

RETURN

Data_Set ;Allows the user to enter the 8-bit SEEPROM data.

CALL LCD_Port ;Set Port A and Port B for LCD use MOVLW LCDLine2 ;Set LCD charcter position to line CALL LCD_Reg ;two and send command to LCD MOVLW Data_Msg ;Load W with Data message offset CALL Disp_Message ;and call display message routine

MOVLW LCDLine1+Data ;Set LCD character position to CALL LCD_Reg ;start of data display area

92 Microchip Code ©1998 Sirius microSystems SEETEST.ASM - Chapter 17 Example Program

MOVLW ‘?’ ;Load W with “?” character CALL LCD_Data ;and send to LCD two times to MOVLW ‘?’ ;indicate data entry field CALL LCD_Data MOVLW LCDLine1+Data ;Reset LCD character position to CALL LCD_Reg ;start of address display area MOVLW CursBlink ;and set blinking cursor CALL LCD_Reg ;Send command to LCD

CLRF SEEData ;Clear SEEPROM data byte CALL KB_Port ;Set Port B for keypad use and CALL Key_Release ;make sure that no keys are pressed :Digit1 CALL KB_Scan ;Scan keys for a keystroke MOVF Key,W ;Load Key into W to check for keypress BTFSC Z ;and check Z flag GOTO :Digit1 ;If Z=0, no key pressed. Scan again CALL Key_Remap ;Convert key stroke to binary nybble MOVWF Digit ;Save Key code in Digit register MOVWF SEEData ;and also in top of SEEData register SWAPF SEEData,1 ;by swapping nybbles of SEEData CALL LCD_Port ;Set Port A and Port B for LCD use MOVF DIgit,W ;Load W with Digit value CALL Hex_Remap ;and convert to ASCII CALL LCD_Data ;Display key code on LCD

CALL KB_Port ;Set Port B for keypad use and CALL Key_Release ;make sure that no keys are pressed :Digit2 CALL KB_Scan ;Scan keys for a keystroke MOVF Key,W ;Load Key into W to check for keypress BTFSC Z ;and check Z flag GOTO :Digit2 ;If Z=0, no key pressed. Scan again CALL Key_Remap ;Convert key stroke to binary nybble MOVWF Digit ;Save Key code in Digit register IORWF SEEData ;and save in bottom of SEEData CALL LCD_Port ;Set Port A and Port B for LCD use MOVLW CursOff ;Send LCD command to turn off CALL LCD_Reg ;blinking cursor MOVF Digit,W ;Load W with Digit value CALL Hex_Remap ;and convert to ASCII CALL LCD_Data ;Display key code on LCD

CALL SEE_Port ;Configure Port A for SEEPROM MOVLW SEEEWEN ;Send Erase/Write Enable command CALL SEE_Command ;to SEEPROM MOVF Addrl,W ;Copy Addrl byte to MOVWF SEEAddrl ;SEEAddrl MOVF Addrh,W ;Copy Addrh byte to MOVWF SEEAddrh ;SEEAddrh MOVLW SEEWrite ;Send data write command CALL SEE_Command ;to SEEPROM MOVLW SEEEWDS ;Send Erase/Write Disable command CALL SEE_Command ;to SEEPROM

RETURN

Key_Release ;Waits for the key to be released

CALL KB_Scan ;Scan keys for key press MOVF Key,W ;Check Key return code for no key BTFSS Z ;by checking for 0 (0=no key) GOTO Key_Release ;If key pressed, try again CALL Delay_5ms ;If key released, wait for debouncing RETURN ;and return

Hex_Remap ;Changes binary nybble into ASCII Hex value. Program Pull-Out ©1998 Sirius microSystems Microchip Code 93 References SEETEST.ASM - Chapter 17 Example Program

MOVWF Character ;Store character offset

MOVLW HI Hex_Code ;Move the High Byte of Hex_Code ;address location into W MOVWF PCLATH ;and into PCLATH MOVLW Hex_Code+1 ;Move address + 1 into W ADDWF Character,W ;Calculate offset address and BTFSC C ;see if it overflows INCF PCLATH ;If so, increment PCLATH CALL Hex_Code ;Jump to the data table

RETURN ;and finish if done

Hex_Code MOVWF PCL ;Use Hex digit to offset PC RETLW ‘0’ ;0000 remapped to ‘0’ RETLW ‘1’ ;0001 remapped to ‘1’ RETLW ‘2’ ;0010 remapped to ‘2’ RETLW ‘3’ ;0011 remapped to ‘3’ RETLW ‘4’ ;0100 remapped to ‘4’ RETLW ‘5’ ;0101 remapped to ‘5’ RETLW ‘6’ ;0110 remapped to ‘6’ RETLW ‘7’ ;0111 remapped to ‘7’ RETLW ‘8’ ;1000 remapped to ‘8’ RETLW ‘9’ ;1001 remapped to ‘9’ RETLW ‘A’ ;1010 remapped to ‘A’ RETLW ‘B’ ;1011 remapped to ‘B’ RETLW ‘C’ ;1100 remapped to ‘C’ RETLW ‘D’ ;1101 remapped to ‘D’ RETLW ‘E’ ;1110 remapped to ‘E’ RETLW ‘F’ ;1111 remapped to ‘F’

Key_Remap ;Changes key code into binary nybble.

MOVWF Character ;Store character offset

MOVLW HI Key_Code ;Move the High Byte of Hex_Code ;address location into W MOVWF PCLATH ;and into PCLATH MOVLW Key_Code+1 ;Move address + 1 into W ADDWF Character,W ;Calculate offset address and BTFSC C ;see if it overflows INCF PCLATH ;If so, increment PCLATH CALL Key_Code ;Jump to the data table

RETURN ;and finish if done

Key_Code MOVWF PCL ;Use Key code to offset PC NOP ;No key 0 RETLW 01h ;Key 1 remapped to 0001 RETLW 02h ;Key 2 remapped to 0010 RETLW 03h ;Key 3 remapped to 0011 RETLW 0Ah ;Key 4 remapped to 1010 RETLW 04h ;Key 5 remapped to 0100 RETLW 05h ;Key 6 remapped to 0101 RETLW 06h ;Key 7 remapped to 0110 RETLW 0Bh ;Key 8 remapped to 1011 RETLW 07h ;Key 9 remapped to 0111 RETLW 08h ;Key 10 remapped to 1000 RETLW 09h ;Key 11 remapped to 1001 RETLW 0Ch ;Key 12 remapped to 1100 RETLW 0Eh ;Key 13 remapped to 1110 RETLW 00h ;Key 14 remapped to 0000 RETLW 0Fh ;Key 15 remapped to 1111 RETLW 0Dh ;Key 16 remapped to 1101

Disp_Message ;Copies ASCII data from a look-up table to the current cursor

94 Microchip Code ©1998 Sirius microSystems SEETEST.ASM - Chapter 17 Example Program

;position of the LCD. Character is loaded with the starting ;offset of the message before calling this routine.

MOVWF Character ;Save offset in Character counter

:Get_Char MOVLW HI Message ;Move the High Byte of Message3 ;location into W MOVWF PCLATH ;and Move it into PCLATH MOVLW Message+1 ;Move message address + 1 into W ADDWF Character,W ;Calculate offset address and BTFSC C ;see if it overflows INCF PCLATH ;If so, increment PCLATH CALL Message ;Jump to the data table

IORLW 00h ;RETLW won’t affect flags so use OR to BTFSC Z ;check for end of message RETURN ;and finish if done CALL LCD_Data ;If not done, send character to LCD INCF Character,1 ;Add 1 to Character GOTO :Get_Char ;Do it again for the next character

Message MOVWF PCL ;W contains low program counter ;byte and points to next location ;plus Character offset

RETLW ‘ ‘ ;Menu_Msg Start RETLW ‘D’ RETLW ‘w’ RETLW ‘n’ RETLW ‘ ‘ RETLW ‘U’ RETLW ‘p’ RETLW ‘ ‘ RETLW ‘S’ RETLW ‘e’ RETLW ‘l’ RETLW ‘ ‘ RETLW ‘C’ RETLW ‘h’ RETLW ‘g’ RETLW 0 ;End of message 1

RETLW ‘A’ ;Status_Msg Start RETLW ‘d’ RETLW ‘d’ RETLW ‘r’ RETLW ‘:’ RETLW ‘ ‘ RETLW ‘ ‘ RETLW ‘ ‘ RETLW ‘ ‘ RETLW ‘D’ RETLW ‘a’ RETLW ‘t’ RETLW ‘a’ RETLW ‘:’ RETLW 0 ;End of message 2

RETLW ‘E’ ;Addr_Msg Start RETLW ‘n’ RETLW ‘t’ RETLW ‘e’ RETLW ‘r’ RETLW ‘ ‘ RETLW ‘A’ RETLW ‘d’ RETLW ‘d’ RETLW ‘r’ Program Pull-Out ©1998 Sirius microSystems Microchip Code 95 References SEETEST.ASM - Chapter 17 Example Program

RETLW ‘e’ RETLW ‘s’ RETLW ‘s’ RETLW ‘ ‘ RETLW ‘ ‘ RETLW 0 ;End of message 3

RETLW ‘E’ ;Data_Msg Start RETLW ‘n’ RETLW ‘t’ RETLW ‘e’ RETLW ‘r’ RETLW ‘ ‘ RETLW ‘D’ RETLW ‘a’ RETLW ‘t’ RETLW ‘a’ RETLW ‘ ‘ RETLW ‘ ‘ RETLW ‘ ‘ RETLW ‘ ‘ RETLW ‘ ‘ RETLW 0 ;End of message 4

Delay_5ms ;Delay loop used to initialize LCD

CLRF Counter1 ;Wipe first counter MOVLW 1Ah ;Load W with timer Constant MOVWF Counter2 ;for Counter2

:Loop DECFSZ Counter1,1 ;Decrement first counter GOTO :Loop ;256 times DECFSZ Counter2,1 ;Decrement, second counter GOTO :Loop ;from constant, above RETURN

Repeat_Delay ;Long delay loop to for key repeat

CLRF Counter1 ;Wipe Counter1 and :Set MOVLW 40h ;load W with preset MOVWF Counter2 ;for Counter2

:Loop DECFSZ Counter1,1 ;Decrement first counter GOTO :Loop ;256 times DECFSZ Counter2,1 ;Decrement second counter GOTO :Loop ;256 more times CALL KB_Scan ;Scan Key codes for release MOVF Key,W ;Load Key code into W and check BTFSC Z ;for 0 (0=released) RETURN ;If released, return early DECFSZ Delay ;Decrement delay duration counter GOTO :Set ;based on loaded Delay value RETURN

96 Microchip Code ©1998 Sirius microSystems TIMEOUT.ASM - Chapter 18 Example Program

;TIMEOUT.ASM v1.2 Last modified on August 31, 1998

;These program subroutines were written for the Sirius microSystems PICmicro ;development system. For more information contact Sirius microSystems by phone ;at 519-886-4462, or on the Internet at http://www.siriusmicro.com .

;Sirius microSystems provides this software on an “as is” basis, without any ;warranty, either expressed or implied. All Sirius microSystems software is ;provided for educational use only, and Sirius microSystems does not assume ;any liability for damages, either incidental or consequential, arising out of ;the application, use, or misuse of any of its software or hardware products. ;Sirius microSystems reserves the right, without further notice, to make ;changes to any of its software or hardware referred to in this program or ;library program in order to improve its function, design or reliability.

;Description

; This program demonstrates how to determine whether a MCLR or Watch Dog ; Timer (WDT) reset was responsible for re-starting program executing in ; the PICmicro. The LCD displays a message indicating the source of the ; reset, either MCLR or WDT. During normal processing the WDT is always ; being reset. By pressing and holding a key for 2-3 seconds, the WDT will ; time out, resetting the PICmicro. Use the reset button to restart the ; program.

; Note that this program also demonstrates a problem that may occur during ; the execution of WDT-enabled programs. Although a user typically presses ; and releases a key, pressing and holding a key in this program will ; cause an unintended reset. Make sure to verify the operation of programs ; that receive an unintended WDT reset!

;Jumper Settings

; JU2 5VDC internal/external select REG ; JU1 Variable DC internal/external select REG ; JU3 Processor power select jumper RUN ; JU4 EEPROM X8/X16 organization select N/A ; JU6 Port A LED output and analog input RA0 OFF ; RA1 OFF ; RA2 ON ; RA3 OFF ; RA4 OFF ; JU5 RS-232 receive/transmit select N/A

;Requirements

; This program has no special requirements.

Maclib ‘PF8x.INC’ ;Library file for PIC16F84 and PM assembler ;Comment this line out for other assemblers

Device PIC16F84,HS_OSC,WDT_ON,PROTECT_OFF,PWRT_ON ID ‘TOUT’

;Hardware Equates

ORG 0Ch ;Start of File register area

Character DS 1 ;LCD message character offset Counter1 DS 1 ;LCD delay/keystroke delay counter Counter2 DS 1 ;LCD delay/keystroke delay counter

;Equates required by KEYPAD.LIB

Key DS 1 ;Key return code variable Program Pull-Out ©1998 Sirius microSystems Microchip Code 97 References TIMEOUT.ASM - Chapter 18 Example Program

;Software Equates

Reset_Msg EQU 0 ;Reset source message offset Pwr_Msg EQU 12 ;Power up message offset WDT_Msg EQU 29 ;Watchdog timer message offset

ORG 00h ;Start program at Reset Vector

CLRF Key ;Clear Key return variable CLRF Counter1 ;and delay counters CLRF Counter2 GOTO Initialize ;Continue with initialize routine

ORG 05h ;One location past Interrupt Vector

Include ‘LCD.LIB’ ;LCD subroutine library Include ‘KEYPAD.LIB’ ;Keypad scanning subroutine library

Initialize ;Continue by initializing the LCD display.

CALL LCD_Port ;Set up Ports for LCD use

BTFSS TO ;Check WDT Time Out flag and GOTO WDT_Message ;skip WDT and LCD init if reset by WDT

Init_WDT CLRWDT ;Clear Watchdog Timer BSF RP0 ;Select register page 1 MOVLW 0FFh ;Set Option register for WDT with MOVWF Option ;1:128 prescaler (maximum prescaler) BCF RP0 ;Return to register page 0

Init_LCD CALL LCD_Init ;Initialize LCD and clear screen MOVLW LCDLine1 ;Send line 1 starting address CALL LCD_Reg ;to LCD MOVLW Reset_Msg ;Load W with Reset message offset CALL Disp_Message ;and call display message routine MOVLW LCDLine2 ;Send line 2 starting address CALL LCD_Reg ;to LCD MOVLW Pwr_Msg ;Load W with power up message offset CALL Disp_Message ;and display it on line 2 of LCD GOTO Wait_for_Key ;Continue with main program

WDT_Message MOVLW LCDLine2 ;Send line 2 starting address CALL LCD_Reg ;to LCD MOVLW WDT_Msg ;Load W with WDT message offset CALL Disp_Message ;and display it on line 2 of LCD

Wait_for_Key ;Checks for a key press. If no keys are pressed, WDT is reset.

CALL KB_Port ;Set up Ports for keypad scanning CALL KB_Scan ;Get Key return code MOVF Key,W ;Load Key code into W to set flags BTFSC Z ;and check for 0 (0=no key) GOTO Reset_WDT ;If no key pressed, reset WDT

Key_Release ;Waits for the key to be released. If a key is held for 2-3 ;seconds, the WDT will time out since there is not CLRWDT ;instruction inside this wait loop.

CALL KB_Scan ;Scan keys for key press MOVF Key,W ;Check Key return code for no key BTFSS Z ;by checking for 0 (0=no key) GOTO Key_Release ;If key is held, check again

98 Microchip Code ©1998 Sirius microSystems TIMEOUT.ASM - Chapter 18 Example Program

Reset_WDT ;Resets the WDT, setting the TO flag.

CLRWDT ;If no key pressed, clear Watchdog GOTO Wait_for_Key ;and check for another key press

Disp_Message ;Copies ASCII data from a look-up table to the current cursor ;position of the LCD. Character is loaded with the starting ;offset of the message before calling this routine.

MOVWF Character ;Save offset in Character counter

:Get_Char MOVLW HI Message ;Move the High Byte of Message3 ;location into W MOVWF PCLATH ;and Move it into PCLATH MOVLW Message+1 ;Move message address + 1 into W ADDWF Character,0 ;Calculate offset address and BTFSC C ;see if it overflows INCF PCLATH ;If so, increment PCLATH CALL Message ;Jump to the data table

IORLW 00h ;RETLW won’t affect flags so use OR to BTFSC Z ;check for end of message RETURN ;and finish if done CALL LCD_Data ;If not done, send character to LCD INCF Character,1 ;Add 1 to Character GOTO :Get_Char ;Do it again for the next character

Message MOVWF PCL ;W contains low program counter ;byte and points to next location ;plus Character offset

RETLW ‘R’ ;Reset_Msg Start RETLW ‘e’ RETLW ‘s’ RETLW ‘e’ RETLW ‘t’ RETLW ‘ ‘ RETLW ‘f’ RETLW ‘r’ RETLW ‘o’ RETLW ‘m’ RETLW ‘:’ RETLW 0 ;End of message 1

RETLW ‘P’ ;Pwr_Msg Start RETLW ‘o’ RETLW ‘w’ RETLW ‘e’ RETLW ‘r’ RETLW ‘-’ RETLW ‘u’ RETLW ‘p’ RETLW ‘ ‘ RETLW ‘o’ RETLW ‘r’ RETLW ‘ ‘ RETLW ‘M’ RETLW ‘C’ RETLW ‘L’ RETLW ‘R’ RETLW 0 ;End of message 2

RETLW ‘W’ ;WDT_Msg Start RETLW ‘a’ RETLW ‘t’ RETLW ‘c’ Program Pull-Out ©1998 Sirius microSystems Microchip Code 99 References TIMEOUT.ASM - Chapter 18 Example Program

RETLW ‘h’ RETLW ‘d’ RETLW ‘o’ RETLW ‘g’ RETLW ‘ ‘ RETLW ‘t’ RETLW ‘i’ RETLW ‘m’ RETLW ‘e’ RETLW ‘r’ RETLW ‘!’ RETLW ‘!’ RETLW 0 ;End of message 3

Delay_5ms ;Delay loop used to initialize LCD

CLRF Counter1 ;Wipe first counter MOVLW 1Ah ;Load W with timer Constant MOVWF Counter2 ;for Counter2

:Loop DECFSZ Counter1,1 ;Decrement first counter GOTO :Loop ;256 times DECFSZ Counter2,1 ;Decrement, second counter GOTO :Loop ;from constant, above RETURN

100 Microchip Code ©1998 Sirius microSystems VMETER.ASM - Chapter 16 Example Program

;VMETER.ASM v1.2 Last modified on August 31, 1998

;These program subroutines were written for the Sirius microSystems PICmicro ;development system. For more information contact Sirius microSystems by phone :at 519-886-4462, or on the Internet at http://www.siriusmicro.com .

;Sirius microSystems provides this software on an “as is” basis, without any ;warranty, either expressed or implied. All Sirius microSystems software is ;provided for educational use only, and Sirius microSystems does not assume ;any liability for damages, either incidental or consequential, arising out of ;the application, use, or misuse of any of its software or hardware products. ;Sirius microSystems reserves the right, without further notice, to make ;changes to any of its software or hardware referred to in this program or ;library program in order to improve its function, design or reliability.

;Description

; This program demonstrates the use of the PIC16C711 A/D converter in a ; voltmeter type application. It samples the voltage on potentiometers ; RA0 and RA1 and displays the binary result as a decimal number on the ; LCD. The RA0 value is then scaled to 5V and displayed as a voltage on ; line 2 of the LCD while the RA1 value is converted into a bar-graph ; display on the LED Bar. ; ; Note: If you use a voltmeter to measure the voltage on RA0 and RA1 ; while this program is running, you will not get the same results as ; on the display. The reason for this is that both RA0 and RA1 are ; multiplexed between being digital control lines for the LCD and analog ; inputs for the PIC. An oscilloscope will show the correct analog ; voltage between LCD writes.

;Jumper Settings

; JU2 5VDC internal/external select REG ; JU1 Variable DC internal/external select REG ; JU3 Processor power select jumper RUN ; JU4 EEPROM X8/X16 organization select N/A ; JU6 Port A LED output and analog input RA0 ON ; RA1 ON ; RA2 ON ; RA3 OFF ; RA4 OFF ; JU5 RS-232 receive/transmit select N/A

;Requirements

; None

Maclib ‘P71x.INC’ ;Library file for PIC16C711 and PM assembler ;Comment this line out for other assemblers

Device PIC16C711, HS_OSC, WDT_OFF, PROTECT_OFF, PWRT_ON ID ‘VMET’

;Hardware Equates

ORG 0Ch ;Start of register file memory

Counter1 DS 1 ;LCD/A-D update delay counter Counter2 DS 1 ;LCD/A-D update delay counter Counter3 DS 1 ;A-D update delay counter Character DS 1 ;LCD message character offset Analog0 DS 1 ;Temporary Analog storage for chan. 0 Analog1 DS 1 ;Temporary Analog storage for chan. 1 Bargraph DS 1 ;Temporary storage for LED bar output Program Pull-Out ©1998 Sirius microSystems Microchip Code 101 References VMETER.ASM - Chapter 16 Example Program

;Equates used by BIN2BCD.LIB

HighByte DS 1 ;High byte of number LowByte DS 1 ;Low byte of number

TenThous DS 1 ;Ten thousands BCD digit ThouHund DS 1 ;Thousands & Hundreds BCD digit TensOnes DS 1 ;Tens and Ones BCD digit

ShiftCounter DS 1 ;Counter for BCD conversion shifts

;Software Equates

Channel0_Msg EQU 0 ;’Ch.0:’ message offset Channel1_Msg EQU 5 ;’Ch.1:’ message offset Voltage_Msg EQU 10 ;’Ch.0 Voltage:’ message offset Ch0_Data EQU 4 ;Channel 0 data cursor address Ch1_Data EQU 12 ;Channel 1 data cursor address Ch0_Volts EQU 10 ;Channel 0 voltage cursor address

ORG 00h ;Reset Vector

CLRF Counter1 ;Clear delay counters CLRF Counter2 CLRF Counter3 GOTO Initialize ;Continue with initialization

ORG 05h ;One location past interrupt vector

Include ‘ATOD.LIB’ ;A-D conversion library Include ‘LCD71.LIB’ ;LCD subroutine library Include ‘BIN2BCD.LIB’ ;Binary to BCD conversion library

Initialize ;Sets up the LCD and writes messages to line 1 and line 2.

CALL LCD_Port ;Set up ports for LCD use CALL LCD_Init ;Initialize LCD & clear screen MOVLW LCDLine1 ;Send line 1 starting address to CALL LCD_Reg ;to LCD as a command MOVLW Channel0_Msg ;Load W with channel 0 message offset CALL Disp_Message ;and call display message routine

MOVLW LCDLine1+8 ;Set LCD address to middle of line 1 CALL LCD_Reg ;and pass to LCD as a command MOVLW Channel1_Msg ;Load W with channel 1 message offset CALL Disp_Message ;and call display message routine

MOVLW LCDLine2 ;Send line 2 starting address to CALL LCD_Reg ;to LCD as a command MOVLW Voltage_Msg ;Load W with ch 0 voltage_msg offset CALL Disp_Message ;and call display message routine

Main ;Configures A-D converter by initializing Port A to be ;analogue intsead of digital, setting the clock divider, ;and selecting the A-D channel.

CALL AD_Port ;Initialize A-D converter & Port A MOVLW ADCLK32 ;Get clock divider for high speed CALL AD_Clock ;from ATOD.lib and set A-D MOVLW ADCH0 ;Get channel 0 constant and CALL AD_Channel ;set A-D channel MOVF Bargraph,W ;Display Bargraph value on LEDs while

102 Microchip Code ©1998 Sirius microSystems VMETER.ASM - Chapter 16 Example Program

MOVWF PORTB ;waiting for next conversion

Call Delay_5ms ;Wait for track & hold to settle CALL AD_Poll ;Start conversion, & wait until done MOVF ADRES,W ;Load conversion result into W and MOVWF Analog0 ;save in Analog0 for voltage display

MOVLW ADCH1 ;Get channel 1 constant and CALL AD_Channel ;set A-D channel MOVF Bargraph,W ;Display Bargraph value on LEDs while MOVWF PORTB ;waiting for next conversion

CALL Delay_5ms ;Wait for track & hold to settle CALL AD_Poll ;Start conversion, & wait until done MOVF ADRES,W ;Load conversion result into W and MOVWF Analog1 ;save in Analog1

CALL LCD_Port ;Reconfigure Ports for LCD use MOVLW LCDLine1+Ch0_Data ;Send channel 0 data starting CALL LCD_Reg ;address to LCD as a command MOVF Bargraph,W ;Display Bargraph value on LEDs while MOVWF PORTB ;waiting for BCD conversion MOVF Analog0,W ;Load channel 0 result into W and MOVWF LowByte ;save into LowByte register CALL Display_Num ;Let Display_Num display BCD digits

MOVLW LCDLine1+Ch1_Data ;Send channel 1 data starting CALL LCD_Reg ;address to LCD as a command MOVF Bargraph,W ;Display Bargraph value on LEDs while MOVWF PORTB ;waiting for bcd conversion MOVF Analog1,W ;Load channel 1 result into W and MOVWF LowByte ;save into LowByte register CALL Display_Num ;Let Display_Num display BCD digits

MOVLW LCDLine2+Ch0_Volts ;Send channel 0 voltage starting CALL LCD_Reg ;address to LCD as a command MOVF Bargraph,W ;Display Bargraph value on LEDs while MOVWF PORTB ;waiting for scaling CALL Scale_Voltage ;Convert Ch.0 result to voltage and CALL Display_Volts ;display the result on the LCD

MOVF Bargraph,W ;Display Bargraph value on LEDs while MOVWF PORTB ;waiting for lookup RRF Analog1 ;Divide channel 1 result by 2 RRF Analog1 ;again = divide by 4 RRF Analog1 ;again = divide by 8 RRF Analog1 ;again = divide by 16 RRF Analog1 ;again = divide by 32 MOVLW 07h ;Clear upper 5 bits of result by ANDWF Analog1,W ;ANDing with zero, leave 3 bit result CALL Bar_Table ;in W to look up 1 of 8 patterns MOVWF PORTB ;Output LED pattern to LED bar MOVWF Bargraph ;and to Bargraph register for update

CALL AD_Delay ;Wait to minimize display flicker GOTO Main ;and do it again

Bar_Table ;Look-up table for bar graph display. Takes a number from ;0 to 7 and determins which LEDs should be on.

CLRF PCLATH ;Clear PCLATH before doing lookup ADDWF PCL ;PCL=PCL+W to generate offset RETLW 10000000b ;Bottom LED on RETLW 11000000b ;Bottom 2 LEDs RETLW 11100000b ;Bottom 3 LEDs RETLW 11110000b ;Bottom 4 LEDs RETLW 11111000b ;Bottom 5 LEDs Program Pull-Out ©1998 Sirius microSystems Microchip Code 103 References VMETER.ASM - Chapter 16 Example Program

RETLW 11111100b ;Bottom 6 LEDs RETLW 11111110b ;Bottom 7 LEDs RETLW 11111111b ;All LEDs on

Scale_Voltage ;Scales the result of the A/D conversion such that there are ;only 250 states instead of 256. This way the result can be ;multiplied by two to give a result from 0 to 500 representing ;a voltage of between 0.00 and 5.00 volts. For display, a ;decimal point is just inserted after the first digit by the ;Display_Volts subroutine.

MOVF Analog0,W ;Load W with the A/D result and SUBLW 225 ;check if it’s greater than 225 by BTFSS C ;testing the Carry flag DECF Analog0 ;If so, subtract one from the result MOVF Analog0,W ;Repeat the above process, comparing SUBLW 175 ;the A/D result with successively BTFSS C ;smaller values DECF Analog0 MOVF Analog0,W SUBLW 125 BTFSS C DECF Analog0 MOVF Analog0,W SUBLW 75 BTFSS C DECF Analog0 MOVF Analog0,W SUBLW 25 BTFSS C DECF Analog0

CLRF HighByte ;Clear HighByte register for multiply MOVF Analog0,W ;Reload W with scaled result and MOVWF LowByte ;save result in LowByte register BCF C ;Clear Carry before multiplying by 2 RLF LowByte ;Shift LowByte left to multiply RLF HighByte ;Shift Carry into HighByte CALL BIN_BCD ;and convert to BCD RETURN ;Return when done

Display_Volts ;Displays the result of the BCD scaled voltage as a decimal ;number at the current LCD cursor address.

MOVF ThouHund,W ;Load thousands & hundreds digits in ANDLW 0Fh ;W and clear thousands nybble ADDLW 30h ;Add ASCII offset to generate number CALL LCD_Data ;and display on LCD MOVLW ‘.’ ;Load W with ASCII code for “.” CALL LCD_Data ;and display on LCD SWAPF TensOnes,W ;Load tens & ones digit in reverse ANDLW 0Fh ;and clear ones nybble ADDLW 30h ;Add ASCII offset to generate number CALL LCD_Data ;and display on LCD MOVF TensOnes,W ;Load tens and ones digits in ANDLW 0Fh ;W and clear tens nybble ADDLW 30h ;Add ASCII offset to generate number CALL LCD_Data ;and display on LCD MOVLW ‘V’ ;Load W with ASCII code for “V” CALL LCD_Data ;and display on LCD RETURN ;Return when done

Display_Num ;Converts the 8-bit A/D result to BCD and displays the ;hundreds, tens and ones digits on the LCD at the current ;LCD cursor address.

104 Microchip Code ©1998 Sirius microSystems VMETER.ASM - Chapter 16 Example Program

CLRF HighByte ;Clear HighByte before converting CALL BIN_BCD ;result to BCD MOVF ThouHund,W ;Load thousands & hundreds digits in ANDLW 0Fh ;W and clear thousands nybble ADDLW 30h ;Add ASCII offset to generate number CALL LCD_Data ;and display on LCD SWAPF TensOnes,W ;Load tens & ones digit in reverse ANDLW 0Fh ;and clear ones nybble ADDLW 30h ;Add ASCII offset to generate number CALL LCD_Data ;and display on LCD MOVF TensOnes,W ;Load tens and ones digits in ANDLW 0Fh ;W and clear tens nybble ADDLW 30h ;Add ASCII offset to generate number CALL LCD_Data ;and display on LCD RETURN ;Return when done

Disp_Message ;Copies ASCII data from a look-up table to the current cursor ;position of the LCD. Character is loaded with the starting ;offset of the message before calling this routine.

MOVWF Character ;Save offset in Character counter

:Get_Char MOVLW HI Message ;Move the High Byte of Message3 ;location into W MOVWF PCLATH ;and Move it into PCLATH MOVLW Message+1 ;Move message address + 1 into W ADDWF Character,W ;Calculate offset address and BTFSC C ;see if it overflows INCF PCLATH ;If so, increment PCLATH CALL Message ;Jump to the data table

IORLW 00h ;RETLW won’t affect flags so use OR to BTFSC Z ;check for end of message RETURN ;and finish if done CALL LCD_Data ;If not done, send character to LCD INCF Character,1 ;Add 1 to Character GOTO :Get_Char ;Do it again for the next character

Message MOVWF PCL ;W contains low program counter ;byte and points to next location ;plus Character offset

RETLW ‘C’ ;Channel0_Msg Start RETLW ‘h’ RETLW ‘0’ RETLW ‘:’ RETLW 0 ;End of message 1

RETLW ‘C’ ;Channel1_Msg Start RETLW ‘h’ RETLW ‘1’ RETLW ‘:’ RETLW 0 ;End of message 2

RETLW ‘C’ ;Voltage_Msg Start RETLW ‘h’ RETLW ‘0’ RETLW ‘ ‘ RETLW ‘V’ RETLW ‘o’ RETLW ‘l’ RETLW ‘t’ RETLW ‘s’ RETLW ‘:’ RETLW 0 ;End of message 2 Program Pull-Out ©1998 Sirius microSystems Microchip Code 105 References VMETER.ASM - Chapter 16 Example Program

AD_Delay ;25ms delay between A-D conversions.

MOVLW 5 ;Load Counter3 with number of times MOVWF Counter3 ;to execute 5ms LCD delay loop

:Loop CALL Delay_5ms ;Wait 5 ms DECFSZ Counter3 ;Decrement counter 3 and check for 0 GOTO :Loop ;If not 0, wait again RETURN ;otherwise, return

Delay_5ms ;Delay loop used to initialize LCD.

CLRF Counter1 ;Wipe first counter MOVLW 1Ah ;Load W with timer Constant MOVWF Counter2 ;for Counter2

:Loop DECFSZ Counter1,1 ;Decrement first counter GOTO :Loop ;256 times DECFSZ Counter2,1 ;Decrement second counter GOTO :Loop ;from constant, above RETURN

106 Microchip Code ©1998 Sirius microSystems WDTIMER.ASM - Chapter 18 Example Program

;WDTIMER.ASM v1.2 Last modified on August 31, 1998

;These program subroutines were written for the Sirius microSystems PICmicro ;development system. For more information contact Sirius microSystems by phone ;at 519-886-4462, or on the Internet at http://www.siriusmicro.com .

;Sirius microSystems provides this software on an “as is” basis, without any ;warranty, either expressed or implied. All Sirius microSystems software is ;provided for educational use only, and Sirius microSystems does not assume ;any liability for damages, either incidental or consequential, arising out of ;the application, use, or misuse of any of its software or hardware products. ;Sirius microSystems reserves the right, without further notice, to make ;changes to any of its software or hardware referred to in this program or ;library program in order to improve its function, design or reliability.

;Description

; This program demonstrates the use of the Watch Dog Timer (WDT) to wake ; the PICmicro from Sleep in order to continue processing. This is useful ; in reducing power consumption while periodically resuming processing ; without using interrupts. By putting the PICmicro to Sleep, the WDT does ; not reset the microcontroller. This is demonstrated by clearing the ; Wake_Upx counters during a reset, but not during the WDT wake up (See ; the data sheets for more information). ; ; The program displays a 16-bit count indicating the number of times that ; the PICmicro has been awakened since the last reset. The display also ; indicates whether the PICmicro is Sleeping or Processing.

;Jumper Settings

; JU2 5VDC internal/external select REG ; JU1 Variable DC internal/external select REG ; JU3 Processor power select jumper RUN ; JU4 EEPROM X8/X16 organization select N/A ; JU6 Port A LED output and analog input RA0 OFF ; RA1 OFF ; RA2 ON ; RA3 OFF ; RA4 OFF ; JU5 RS-232 receive/transmit select N/A

;Requirements

; This program has no special requirements.

Maclib ‘PF8x.INC’ ;Library file for PIC16F84 and PM assembler ;Comment this line out for other assemblers

Device PIC16F84,HS_OSC,WDT_ON,PROTECT_OFF,PWRT_ON ID ‘WDTM’

;Hardware Equates

ORG 0Ch ;Start of File register area

Character DS 1 ;LCD message character offset Counter1 DS 1 ;LCD delay/keystroke delay counter Counter2 DS 1 ;LCD delay/keystroke delay counter Wake_UpH DS 1 ;Wake-up event counter high byte Wake_UpL DS 1 ;Wake-up event counter low byte

;Equates required by BIN2BCD.LIB

TenThous DS 1 ;Ten thousands register Program Pull-Out ©1998 Sirius microSystems Microchip Code 107 References WDTIMER.ASM - Chapter 18 Example Program

ThouHund DS 1 ;Thousands and hundreds register TensOnes DS 1 ;Tens and ones register HighByte DS 1 ;High byte of binary number LowByte DS 1 ;Low byte of binary number ShiftCounter DS 1 ;BCD shift counter

;Software Equates

Wake_Up_Msg EQU 0 ;Wake-up message offset Sleep_Msg EQU 11 ;Sleeping message offset Proc_Msg EQU 22 ;Processing message offset

Wake_Ups EQU 8Bh ;Wake-up counter position on LCD

ORG 00h ;Start program at Reset Vector

CLRF ShiftCounter ;Clear BCD shift counter CLRF Counter1 ;and delay counters CLRF Counter2 GOTO Initialize ;Continue with initialize routine

ORG 05h ;One location past Interrupt Vector

Include ‘LCD.LIB’ ;LCD subroutine library Include ‘BIN2BCD.LIB’ ;Binary to BCD conversion library

Initialize ;Continue by initializing the LCD display.

CLRF Wake_UpH ;Continue clearing registers CLRF Wake_UpL CALL LCD_Port ;Set up Ports for LCD use

Init_WDT CLRWDT ;Clear Watchdog Timer BSF RP0 ;Select register page 1 MOVLW 0FEh ;Set Option register for WDT with MOVWF Option ;1:64 prescaler BCF RP0 ;Return to register page 0

Init_LCD CALL LCD_Init ;Initialize LCD and clear screen MOVLW LCDLine1 ;Send line 1 starting address CALL LCD_Reg ;to LCD MOVLW Wake_Up_Msg ;Load W with Wake-up message offset CALL Disp_Message ;and call display message routine

Main MOVLW LCDLine2 ;Send line 2 starting address CALL LCD_Reg ;to LCD MOVLW Proc_Msg ;Load W with Processing message offset CALL Disp_Message ;and display it on line 2 of LCD

MOVLW 1 ;Increment Wake-Up counter low byte ADDWF Wake_UpL ;using Add instruction BTFSC C ;Check Carry for roll-over INCF Wake_UpH ;and increment high byte if set

MOVF Wake_UpL,W ;Copy Wake-Up counters to LowByte and MOVWF LowByte ;HighByte for BCD conversion MOVF Wake_UpH,W MOVWF HighByte

CALL Bin_BCD ;Convert to BCD

MOVLW Wake_Ups ;Send starting address of wake-up CALL LCD_Reg ;counter to LCD MOVF TenThous,W ;Load W with lower nybble of ANDLW 0Fh ;Ten thousands digit

108 Microchip Code ©1998 Sirius microSystems WDTIMER.ASM - Chapter 18 Example Program

ADDLW 30h ;Convert it to ASCII and CALL LCD_Data ;display it on the LCD

SWAPF ThouHund,W ;Load W with upper nybble of ANDLW 0Fh ;thousands and hundreds digits ADDLW 30h ;Convert it to ASCII and CALL LCD_Data ;display it on the LCD

MOVF ThouHund,W ;Load W with lower nybble of ANDLW 0Fh ;thousands and hundreds digit ADDLW 30h ;Convert it to ASCII and CALL LCD_Data ;display it on the LCD

SWAPF TensOnes,W ;Load W with upper nybble of ANDLW 0Fh ;tens and ones digit ADDLW 30h ;Convert it to ASCII and CALL LCD_Data ;display it on the LCD

MOVF TensOnes,W ;Load W with lower nybble of ANDLW 0Fh ;tends and ones digit ADDLW 30h ;Convert it to ASCII and CALL LCD_Data ;display it on the LCD

MOVLW LCDLine2 ;Send line 2 starting address CALL LCD_Reg ;to LCD CALL Delay_5ms ;Add a 20ms pause to see Processing mesg CALL Delay_5ms CALL Delay_5ms CALL Delay_5ms

MOVLW Sleep_Msg ;Load W with Sleeping message offset CALL Disp_Message ;and display it on line 2 of LCD

SLEEP ;Sleep until WDT expires NOP ; GOTO Main ;On WDT wake-up, display next count

Disp_Message ;Copies ASCII data from a look-up table to the current cursor ;position of the LCD. Character is loaded with the starting ;offset of the message before calling this routine.

MOVWF Character ;Save offset in Character counter

:Get_Char MOVLW HI Message ;Move the High Byte of Message3 ;location into W MOVWF PCLATH ;and Move it into PCLATH MOVLW Message+1 ;Move message address + 1 into W ADDWF Character,0 ;Calculate offset address and BTFSC C ;see if it overflows INCF PCLATH ;If so, increment PCLATH CALL Message ;Jump to the data table

IORLW 00h ;RETLW won’t affect flags so use OR to BTFSC Z ;check for end of message RETURN ;and finish if done CALL LCD_Data ;If not done, send character to LCD INCF Character,1 ;Add 1 to Character GOTO :Get_Char ;Do it again for the next character

Message MOVWF PCL ;W contains low program counter ;byte and points to next location ;plus Character offset

RETLW ‘W’ ;Wake-up_Msg Start RETLW ‘a’ RETLW ‘k’ RETLW ‘e’ Program Pull-Out ©1998 Sirius microSystems Microchip Code 109 References WDTIMER.ASM - Chapter 18 Example Program

RETLW ‘-’ RETLW ‘u’ RETLW ‘p’ RETLW ‘ ‘ RETLW ‘#’ RETLW ‘:’ RETLW 0 ;End of message 1

RETLW ‘S’ ;Sleep_Msg Start RETLW ‘l’ RETLW ‘e’ RETLW ‘e’ RETLW ‘p’ RETLW ‘i’ RETLW ‘n’ RETLW ‘g’ RETLW ‘ ‘ RETLW ‘ ‘ RETLW 0 ;End of message 2

RETLW ‘P’ ;WDT_Msg Start RETLW ‘r’ RETLW ‘o’ RETLW ‘c’ RETLW ‘e’ RETLW ‘s’ RETLW ‘s’ RETLW ‘i’ RETLW ‘n’ RETLW ‘g’ RETLW 0 ;End of message 3

Delay_5ms ;Delay loop used to initialize LCD

CLRF Counter1 ;Wipe first counter MOVLW 1Ah ;Load W with timer Constant MOVWF Counter2 ;for Counter2

:Loop DECFSZ Counter1,1 ;Decrement first counter GOTO :Loop ;256 times DECFSZ Counter2,1 ;Decrement, second counter GOTO :Loop ;from constant, above RETURN

110 Microchip Code ©1998 Sirius microSystems XMIT232.ASM - Chapter 15 Example Program

;XMIT232.ASM v1.2 Last modified on August 31, 1998

;These program subroutines were written for the Sirius microSystems PICmicro ;development system. For more information contact Sirius microSystems by phone ;at 519-886-4462, or on the Internet at http://www.siriusmicro.com .

;Sirius microSystems provides this software on an “as is” basis, without any ;warranty, either expressed or implied. All Sirius microSystems software is ;provided for educational use only, and Sirius microSystems does not assume ;any liability for damages, either incidental or consequential, arising out of ;the application, use, or misuse of any of its software or hardware products. ;Sirius microSystems reserves the right, without further notice, to make ;changes to any of its software or hardware referred to in this program or ;library program in order to improve its function, design or reliability.

;Description

; This program demonstrates software timed RS-232 signal transmission. ; The keypad is scanned and whenever a key is pressed, the key return ; code along with some text is transmitted through H3, the serial ; header. The MAX232 translates the signal on RA.4 to RS-232 levels ; after it passes through the serial Transmit/Receive select jumper ; (JU5). ; ; To ensure accurate serial bit timing, use a crystal oscillator and ; not a ceramic resonator to generate the processor clock.

;Jumper Settings

; JU2 5VDC internal/external select REG ; JU1 Variable DC internal/external select REG ; JU3 Processor power select jumper RUN ; JU4 EEPROM X8/X16 organization select N/A ; JU6 Port A LED output and analog input RA0 OFF ; RA1 OFF ; RA2 ON ; RA3 OFF ; RA4 OFF ; JU5 RS-232 receive/transmit select TX

;Requirements

; An external RS-232 serial terminal or a computer with an appropriate ; connection to the PIC-MDS serial input header (H3). For testing we ; used a cable wired as follows: ; ; Computer DB-25 PIC-MDS ; Transmit pin 2 —> H3.3 - Rx ; Receive pin 3 —> H3.1 - Tx ; Ground pin 7 —> H3.2 - Gnd

Maclib ‘PF8x.INC’ ;Library file for PIC16F84 and PM assembler ;Comment this line out for other assemblers

Device PIC16F84,HS_OSC,WDT_OFF,PROTECT_OFF,PWRT_ON ID ‘232T’

;Hardware Equates

ORG 0Ch ;Start of File register area

;Equates required by BIN2DEC.LIB: Hundreds DS 1 ;Hundreds digit Tens DS 1 ;Tens digit Ones DS 1 ;Ones digit

;Equates required by KEYPAD.LIB: Program Pull-Out ©1998 Sirius microSystems Microchip Code 111 References XMIT232.ASM - Chapter 15 Example Program

Key DS 1 ;Key return code register

;Equates required by RS232TX.LIB: Counter DS 1 ;Serial bit delay counter BitCounter DS 1 ;RS232 bit counter register Transmit DS 1 ;Transmit byte storage register

;Other equates: CharCounter DS 1 ;Message character counter Counter1 DS 1 ;Delay counter variable Counter2 DS 1 ;Delay counter variable

ORG 00h ;Start program at Reset Vector

CALL Transmit_Port ;Configure PortA.4 as serial output CALL KB_Port ;Configure Port B for keypad scanning GOTO Get_Key ;Jump over interrupt vector

ORG 05h ;Program starts after interrupt vector

Include ‘BIN2DEC.LIB’ ;Binary to decimal conversion library Include ‘KEYPAD.LIB’ ;Keypad scanning subroutine library Include ‘RS232TX.LIB’ ;RS232 serial transmission library

Get_Key ;Wait for a key stroke, debounce it and convert it to three ;decimal digits.

CALL KB_Scan ;Get Key return code MOVF Key,0 ;Check Key return code BTFSC Z ;for no key press (0=no key) GOTO Get_Key ;If no key pressed, try again

CALL Delay ;Wait for key to settle CALL KB_Scan ;Read Key code after settling MOVF Key,0 ;Read Key code into W CALL Bin_Dec ;and convert to decimal

Convert_ASCII ;Add 30h to offset the BCD numbers into ASCII.

MOVLW 30h ;Load ASCII offset into W and ADDWF Tens ;add to Tens and ADDWF Ones ;Ones registers to make ASCII numbers

Transmit_Key ;Transmit the word ‘Key ‘

MOVLW ‘K’ ;Load W with ASCII code for ‘K’ and CALL Transmit_Data ;send out of serial port MOVLW ‘e’ ;Load W with ASCII code for ‘K’ and CALL Transmit_Data ;send out of serial port MOVLW ‘y’ ;Load W with ASCII code for ‘K’ and CALL Transmit_Data ;send out of serial port MOVLW ‘ ‘ ;Load W with ASCII code for ‘K’ and CALL Transmit_Data ;send out of serial port

Transmit_Num ;Transmit the two key return code ASCII digits.

MOVF Tens,0 ;Load W with ASCII Tens digit and CALL Transmit_Data ;send out of serial port MOVF Ones,0 ;Load W with ASCII Ones digit and CALL Transmit_Data ;send out of serial port

Transmit_Mesg ;Transmit the word ‘ Pressed’, followed by the character ;codes for carriage return (13) and line feed (10).

CLRF CharCounter ;Clear message character counter Get_Char MOVF CharCounter,0 ;Get current character count in W CALL Message ;and retrieve message character

112 Microchip Code ©1998 Sirius microSystems XMIT232.ASM - Chapter 15 Example Program

MOVWF Transmit ;Store returned character in Transmit MOVF Transmit,1 ;and check transmit for end of BTFSC Z ;message marker by checking Z GOTO Wait ;If message done, wait for key release CALL Transmit_Data ;If not, send current character INCF CharCounter ;Increment the character counter GOTO Get_Char ;and get the next character

Wait ;Wait until the user releases the pressed key.

CALL KB_Scan ;Scan keypad MOVF Key,0 ;Check key for 0 BTFSS Z ;And if Z=1 key has been released GOTO Wait ;Otherwise, wait for release CALL Delay ;Wait for key to settle GOTO Get_Key ;Wait for next key

Message ADDWF PCL ;Offset program counter by W RETLW ‘ ‘ ;to Return Message characters RETLW ‘P’ RETLW ‘r’ RETLW ‘e’ RETLW ‘s’ RETLW ‘s’ RETLW ‘e’ RETLW ‘d’ RETLW 13 ;Carriage Return character RETLW 10 ;Line Feed character RETLW 0 ;End of Message marker

Delay ;Provides a debounce delay for the keypad.

CLRF Counter1 ;Wipe first counter MOVLW 80h ;Load W with timer Constant MOVWF Counter2 ;for Counter2

:Loop DECFSZ Counter1,1 ;Decrement first counter GOTO :Loop ;256 times DECFSZ Counter2,1 ;Decrement, second counter GOTO :Loop ;from constant, above RETURN

Program Pull-Out ©1998 Sirius microSystems Microchip Code 113 References 114 Microchip Code ©1998 Sirius microSystems