C What Happens USING PIC® MICROCONTROLLERS AND THE CCS C COMPILER
DAVID BENSON VERSION 1.0
NOTICE The material presented in this book is for the education and amusement of students, hobbyists, technicians and engineers. Every effort has been made to assure the accuracy of this infor mation and its suitability for this purpose. Square 1 Electronics and the author assume no responsibility for the suitability of this information for any application nor do we assume any liability resulting from use of this information. No patent liability is assumed for use of the information contained herein. All rights reserved. No part of this manual shall be reproduced or transmitted by any means (including photo copying) without written permission from Square 1 Electronics and the author. Copyright © 2008 David Benson
TRADEMARKS Registered trademarks of Microchip Technology, Inc: PICmicro PIC PICSTART Plus PICkit 2 MPLAB ICD 2 ICSP In-Circuit Serial Programming Registered trademarks of Microsoft Corporation: Microsoft Windows Hyper Terminal Registered trademarks of Hilgraeve, Inc.: HyperTerminal Private Edition
PUBLISHER
Square 1 Electronics P.O. Box 1414 Hayden, ID 83835 U.S.A. Voice (208)664-4115 FAX (208)772-8236 EMAIL
[email protected] http://www.sq-1.com
C What Happens INTRODUCTION
1
PIC MICROCONTROLLER PRODUCT OVERVIEW
4
SELECTING A DEVICE FOR EXPERIMENTS
6
PIC16F818
Pins and functions Package Clock oscillator Reset Ports Special Features PIC microcontroller architecture Code and data protection Configuration bits CIRCUIT FOR PIC16F818 EXPERIMENTS CHOOSING DEVELOPMENT TOOLS
CCS compiler Device programming methods Device programmers and ease of running code examples Device programmer In-circuit serial programmer Choosing a device programmer Microchip PICSTART Plus Choosing an in-circuit programmer/debugger CCS ICD-U40 (or -S40) Microchip PICkit 2 Microchip ICD 2
8
8 8 9 9 10 10 11 13 13 14 18
18 18 18 18 19 19 20 20 20 20
PROGRAMMING A DEVICE USING THE ICD-U40 (or -S40)
22
PROGRAMMING A DEVICE USING THE PICkit 2
26
PROGRAMMING A DEVICE USING THE ICD 2
28
PROGRAMMING A DEVICE USING THE PICSTART Plus
31
CCS COMPILER
32
C SOURCE CODE
What it looks like Typing accuracy Comments Text And Formatting BITS, BYTES, ETC.
Bit Nibble Byte Binary Hexadecimal
34
34 34 34 34 36
36 36 36 36 38
CONSTANTS
40
VARIABLES
41
DATA
42
Data types ASCII characters NAMING CONSTANTS AND VARIABLES
Reserved words in C
43 44 45
45
OPERATORS - SHORT LIST
47
TRUE vs. FALSE
48
DEVICE FILES
48
PRE-PROCESSOR DIRECTIVES - SHORT LIST
49
INs AND OUTS OF DIGITAL I/O
51
CONFIGURATION REGISTER(S) FUSES
53
FUNCTIONS
main() function Functions Built-in functions - short list STATEMENTS
Executable statements Blocks Conditional statements Semicolon use rules
54
55 56 57 58
58 58 58 59
PROGRAM DESIGN
Program design - control flow if if/else while loop do/while loop for loop switch/case break continue return goto Rule Modular programming WRITING PROGRAMS (With Experiments)
60
61 61 62 64 65 66 67 67 68 68 68 68 69 70
Programming concepts 70 Programming examples 72 Simple data transfers 75 Loop - endless 76 While loop 77 Do/while loop 78 Port registers accessed as variables 79 Port addresses defined using 79 #byte directives Port addresses defined using 80 user-created include file Port addresses defined using 81 get environment built-in function Loop with a counter 82 For loop 82 Loop until 84 While loop 84 Comparisons 86 Relational operators 86 If/else 86 Switch/case 87 Function calls and time delays 89 Bit-level I/O using built-in functions 92 Bit toggle 93 If statement - read switch position 94 ! logical operator 96 && logical operator (two switches) 97 logical operator (two switches) 97 if/else, else, else 98 Read input bit, write output bit 100 Event counting 102
Bit manipulation using bit manipulation functions Bit set/clear Bit testing Flags #bit pre-processor directive example typedef example Bit manipulation using bitwise operators Shift bits right or left Change specific bit to "1" Change specific bit to "0" Change specific bit to its compliment Goto Function library Cut and paste TALKING TO A PIC MICROCONTROLLER WITH A PC VIA A WINDOWS TERMINAL PROGRAM
"U"-turn experiment PC-to-PC "2-lane highway" experiment PC/PIC microcontroller PC baud rates RS-232 interface for a PIC microcontroller PIC microcontroller-to-PC serial communication Formatting PIC microcontroller data on a PC screen STRINGS ARRAYS
Index to an array Step through array elements Extract n**1 element from array Add offset to index Lookup tables 7-segment LED display STRUCTURES
Structures and ports - bit fields MATH AND MANIPULATING NUMBERS
104 104 104 105 106 106 107 107 108 108 108 110 112 112 113
114 117 118 118 119 121 122 125 127
127 128 129 130 131 131 133
137 140
Mathematical operators 140 Operator precedence 140 Data type selection considerations 142 Formatting variables such as math results for printing 143 PASSING VARIABLES
Passing variables Returning variables Prototyping functions
146
146 147 147
OPERATORS
Assignment operator Relational operators Logical operators Increment and decrement Mathematical operators Bitwise operators Pointer operators Structure operators Operators that don't fit the categories INTERRUPTS
149
149 149 149 149 150 150 150 150 150 151
External interrupt sources 152 Internal interrupt sources 152 Timer 0 interrupt 152 Port B interrupt on change - bits 7, 6,5,4 152 Interrupts generated by other peripherals 153 Global interrupt enable flag (GIE) 153 Return from interrupt 153 Where to put the interrupt service routine in program 153 memory Interrupt latency 153 Multiple external interrupt sources 153 Interrupts in C 154 Functions - Built-in 154 Pre-processor directives used to identify 154 interrupt service routines Example - external interrupt 155 TIMING AND COUNTING USING TIMER 0
Digital output waveforms Using timer 0 Prescaler Putting timer 0 to work Setting up timer 0 Starting timer 0 Counter How do we know timer 0 is doing something? Timer 0 will keep on counting as long as: Timer 0 must be reloaded after each overflow for repeating time intervals Stopping timer 0 Timer 0 experiments Digital output waveform using timer 0 - internal clock Single time interval - internal clock Free running mode - internal clock - 0.1 second period Single time interval - external clock Free running mode - internal clock Counting events (pulses) Going further
158
158 159 160 161
162 162 163 166 169 170 174 175
ANALOG TO DIGITAL CONVERSION
176
INSERTING ASSEMBLY CODE IN C CODE
179
APPENDIX A - PULSER
180
APPENDIX B - SOURCES
181
APPENDIX C - HEXADECIMAL NUMBERS
182
APPENDIX D - PROGRAM LISTINGS vs. PAGE NUMBERS
183
INTRODUCTION The internal operation of a microcontroller is all about reading and writing to registers, or some times a bit in a register. This is done to: • • • • •
Control the operation of the microcontroller itself. To communicate with the outside world via input or output pins (lines). To move data from one register to another. To perform mathematical calculations. And more.
Assembly language programmers select and use instructions from the microcontroller's instruc tion set and put them in the proper order to make the desired (hopefully) things happen. C does a lot of this byte and bit level stuff for you. C is a high level language. You, the pro grammer, create the overall plan in the form of C source code. The C compiler generates an assembly level program and the file containing the l's and 0's that get programmed into the microcontroller (device) itself. C does not have an instruction set. Functions and executable statements get the job done. Some functions are built-in to the compiler, and some you write yourself. The C compiler that we will be using has a lot of built-in functions specific to PIC ® microcontrollers which will make your job much easier. You will write the executable statements. You will find that there are lots of ways to do the same thing in C (that work). I have two goals which conflict. The most important one is to give you the basics in the simplest, cleanest, most consistent wray possible to minimize confusion and move you toward writing your own pro grams (that work) as soon as possible. The secondary goal is to show' you enough about other ways to do things that you will be able to understand other people's code, especially the exam ples and drivers that come with the compiler which have been created by various authors over time. Reading this book will not give you an encyclopedic knowledge of C. It is not meant to be erudite. It is meant to be informal and user friendly. My goal is to help you be successful. No matter what programming language or specific device you use, you will need to know some thing about the internal workings/layout of the device you choose to work w'ith and the electrical connections to the outside world. In this book, we will use the PIC 16F818 for running the examples. The information that you need to understand the examples is provided so you won't have to look elsew'here for it (w ith the exception of some specific details listed in the CCS C Compiler Reference Manual). When you move on to projects of your ow n using other devices, you will need a copy of the Microchip data sheet for each device. It will be book-length and available for download at microchip.com in PDF format.
1
The PIC16F818, like the majority of PIC microcontrollers, has program memory made using flash technology, which means it can be erased electrically. It can be programmed, tested in-cir cuit and reprogrammed if necessary in a matter of a few minutes and without the need for an ultraviolet (UV) EPROM eraser. It is a small device (18-pins), readily available to all including hobbyists and students at a cost of $4.00 (at this writing) in single quantity. Think of the PIC16F818 as a custom I/O handler. It looks at its inputs and, based on what it sees, it sends signals out its outputs. You can customize it to do what you w'ant via program ming. It is not a heavy duty number cruncher or data manipulator. A variety of device programmers arc available for the PIC16F818 from independent program mer manufacturers for as little as $40. Learning how PIC microcontrollers work and how to apply them involves study in three areas: • Use of a computer running Microsoft Window's (tm) (as needed). • C programming language and C compiler. • PIC microcontroller itself. The use of "pow'er tools" for programming PIC microcontrollers is essential. This means learn ing to use an IBM compatible computer if you haven't already done so. It also means learning to use a C compiler which converts English-like readable instructions into machine language understood by the PIC microcontroller itself. Finally, learning about the PIC microcontroller's inner workings is possible once use of the power tools is understood. The usual approach used by others to teach the use of PIC microcontrollers has been to get into all of the theory and details of the programming language and then show advanced examples using one of the more complicated parts. As usual, only 5 percent of this information is needed to get started, but which 5 percent. The approach taken here will be to give you the 5 percent you need to get going using the P1C16F818 masquerading as a relatively simple part. The object is to make this process as easy and enjoyable as possible. Once you get through this and you have programmed a PIC16F818 for the first time, a wrhole newr world awaits. You will be able to create more interesting projects and have more fun!
2
The assumption is made that you know how' to do the following on a computer running Microsoft Window's: • Create a new folder. • Copy part of the contents of a CD to the folder. • Use a simple text editor to create a text file, save it, make a copy of it, print it, and copy it to the folder. As a beginner, you need to type the code examples in this book yourself, make the typing mis takes we all make, and learn what the error messages generated by C compiler mean. That is why the code in this book is not on our web site. The code for our intermediate and advanced level books is on our web site.
GENERAL INFORMATION See our web site at http://www.sq-l.com for updates and for errata.
Let's C what happens!
PIC MICROCONTROLLER PRODUCT OVERVIEW This book is not about one device. It is about the whole Microchip microcontroller product line. We need a place to start, a simple (relatively speaking) device which will be available for an extended period. I feel that the best device for initial learning purposes is the PIC16F818. What you learn in the process of using it is applicable, in varying degrees, to the entire Microchip product line. In a simplistic way, Microchip's 8-bit microcontroller line may be classified or categorized in three groups as follows: • 12-bit core base-line - 10, 12 and 16 series part numbers • 14-bit core mid-range - 12 and 16 series part numbers • 16-bit core - 18 series part numbers A different set of rules applies to each group. The number of bits in the instruction words corre spond to the core width (in bits). We don't really care how' many bits are in an instruction word or how' wide the core is. We merely need to know what category a given device belongs in so we know' which set of rules apply to it. All of these microcontrollers arc classified as 8-bit devices because the data and data bus are 8 bits wide. The most popular segment of the 8-bit product line is the 14-bit core mid-range parts. Our atten tion will be focused there. The 12-bit core base-line parts are less sophisticated than the 14-bit core parts and are a step backwards (dumbed down). They still have plenty of capability for many low-end applications and are widely used where production volume is high and unit cost must be very low. They are not used much by experimenters. The 18 series parts have many similarities with the mid-range devices, but require a separate dis cussion. This group is growing. Microchip has introduced a new' 16-bit microcontroller family. The data and data bus are 16 bits w ide. The core is 24 bits wide. These devices have a lot of computation capability and on board peripherals. Once you learn the fundamentals of using PIC microcontrollers, there is plen ty of room to grow. So, the information in this book applies directly to the 14-bit core parts.
4
Chances are that when you choose a part for a project or product, it won't be the one you begin your learning experience with. Learn with the PIC16F818 and branch out later to learn about other devices that interest you. You will need an PIC16F818 data sheet (really a book) as a ref erence as well as a data sheet for each device you become interested in later on. This informa tion is available on Microchip's web site. Microchip has product family information available on their web site. As I am writing this, you can select 8-bit PIC Microcontrollers, then PIC16MCU to arrive at a matrix of information con sisting of devices going down and features going across the matrix. Their web site is constantly changing, so you may have to poke around a little to get there. Compare the features and layout of devices of interest with the soon to be familiar PIC16F818 as a reference point.
5
SELECTING A DEVICE FOR EXPERIMENTS This book is not about one or two specific PIC microcontrollers. The information presented will serve as a foundation for working with all Microchip microcontrollers. In order to do experi ments and to create code that works, we must select a specific device to work with. By making minor changes, the code examples in this book will run on many other PIC microcontrollers in the 14-bit core product line. One of the great things about C is that code can be ported from one device to another easily. I have chosen the PIC16F818 is the example because: • It has 18 pins (small). • It has an internal clock oscillator with 8 speeds selectable via software. The 8 speed clock oscillator is a relatively new design used in many new devices currently being introduced by Microchip. • It has the best mix of on-board peripherals (timer/counters, A/D converter) for beginner and intermediate level experimentation. • It has in-circuit debugging capability built into the device which you will find is a big advantage as you move forward to more complex projects. There are lots of features and their associated registers inside the PIC16F818 which I will keep hidden from you so you don't have to worry about them until some time down the road (next book). The PIC 16F818 will appear to you as a simple device with a few pins which will go unused for now. When choosing a dcvice for an application, one would look at factors such as program memory size, on-board peripherals such as A/D, timer/counters, etc.
6
When firing up a device you have not used before for the first time, you must do the following: • Determine whether or not there are analog peripherals (A/D and/or comparators) which must be turned off if not used. The CCS C compiler will do this for you as a default. • If there is a multi-speed internal clock oscillator (software selectable speed), you must determine what speed it will run at when the device is powered-up and whether or not the speed must be changed during initialization of the device to suit your application. • Determine what features are controlled by the configuration word(s) as the device is programmed by the device programmer and what selections should be made. Using C will greatly simplify this process for you. • Determine how many configuration registers there are and how to write to them. Using C will greatly simplify this process for you. Explanations of these things follow as appropriate. I have made the choices for you when using the PIC16F818 as your example for the experiments. However, I will show you how to do this on your own.
PIC16F818 PINS AND FUNCTIONS
The PIC 16F818 is fabricated using CMOS technology. It consumes very little power and is fully static meaning that the clock can be stopped and all register contents will be retained. The maximum sink or source current for a port at any given time is as follows:
Any I/O Pin Port A Port B Sink current Source current
2 5 mA 2 5 mA
100 raA 100 mA 100 mA 100 mA
Supply current is primarily a function of operating voltage, frequency and I/O pin loading and is typically 2 mA or so for a 4MHz clock oscillator and 5 volts. This drops to less than 100 microamps (even a few microamps) in the power-managed modes (see data sheet). Because the device is CMOS, all inputs must go somewhere. All unused inputs should be pulled up to the supply voltage (usually I 5 VDC) via a 10 K resistor.
PACKAGE The PIC16F818 is available in an 18-pin DIP package suitable for the experimenter. The current part number is PIC 16F818-I/P.
8
CLOCK OSCILLATOR The internal clock oscillator may be used (most common), as is done in this book, or an external clock oscillator may be used. The details of various external oscillator circuits and components as well as internal clock oscillator use options are given in the Microchip data sheet. At pro gramming time, the part must be told via configuration bits which clock oscillator option will be used. This will be explained as we go along. For experimentation, we will use the internal clock oscillator as follows: • Default frequency (31.25 KFIz) for most applications. • 4 MHz for applications using a time delay (built-in function or timer 0).
RESET The PIC16F818 has built-in power-on reset which works as long as the power supply voltage comes up quickly. Commonly the MCLR pin is merely tied to the power supply using a pull-up resistor. A switch may be used to regain control if things run away.
For our experiments, we will use pin 4 as MCLR which stands for Master Clear (reset). It will be pulled up to +5volts via a 47 K resistor to keep the device out of reset unless the MCLR pin is pulled low by some external device.
If you choose to use one of the ICD-type in-circuit serial programmers, the programmer will use pin 4 for the programming threshold voltage, Vpp, which puts the device in programming mode. After programming is completed, you may bring the device out of reset to test your program using the ICD control interface running on the PC. This makes programming and testing your codc fast and easy.
9
PORTS Port A, as we will be using it, has 7 bits/lines. Port B is 8 bits/lines wide or byte-wide. Each port line may be individually programmed as an input line or output line. This is done using a special function which matches a bit pattern with the port lines in registers callcd "tristate" or "tris" registers. A "0" associated with a port line makes it an output, a "1" makes it an input. Examples follow. Pins which may have analog functions in use are analog functions when the microcontroller comes out of reset. For the PIC16F818, the CCS compiler will generate an instruction which changes those pins to digital I/O as part of the initialization process unless the compiler encoun ters a call to setup_adc_ports ( ) ; . This is a default and it is very important to keep in mind. The Port B lines have weak pullup resistors on them which may be enabled or disabled under software control. All 8 resistors are enabled/disabled as a group via a built-in function in the compiler (not used in this book). The pullup resistor on an individual port line is automatically turned off when that line is configured as an output. The pullups are disabled on power-on reset. Port A, bit 4 is shared with the external timer/counter input called TOCKI. As a digital input line, the input is Schmitt trigger. As a digital output line, it is open drain, so a pullup resistor is required. The output cannot source current, it can only sink current. For experimenting, all unused port lines should be tied to the power supply via 10 K pullup resistors (CMOS rule - all inputs must go somewhere). On reset, all port lines are inputs.
SPECIAL FEATURES Watchdog Timer The watchdog timer is useful in some control applications where a runaway program could cause a safety problem. We will not deal with it exccpt to say that it is important to select "watchdog timer off' when programming the configuration bits.
Power-up Timer (PWRT) The power7up timer holds the device in reset for a time which allows the power to come up to a level wjiich will provide reliable operation of the device at which time it is allowed to come out of resetV The power-up timer should be selected "enabled" when programming the configuration bits.
Brown-out Reset (BOR) If Vdd falls below approximately 4 volts for about 100 microseconds, the device will be reset. The brown-out reset feature should be selected "enabled" when programming the configuration bits.
Sleep Mode The feature of the "sleep mode" is drastically reduced power consumption achieved by turning off the main clock oscillator.
10
In-Circuit Debugging The PIC16F818 is designed so that an in-circuit debugger may be connected to it (advanced topic).
Low-Voltage ICSP Programming Low voltage ICSP will not be used.
Peripherals Peripherals such as timer/counters and A/D converters will be discussed in chapters devoted to the subjects.
Special Feature Selection Details follow.
PIC MICROCONTROLLER ARCHITECTURE PIC microcontrollers have two separate blocks of memory, program memory and data memory.
Program Memory The PIC16F818 program memory is 14 bits wide and 1K words long. Program memory is flash which means it can be erased electrically. Program memory is read-only at run time for the purposes of this book. PIC microcontrollers can only execute code contained in program memory.
Pointed To By ■ Reset Vector
Pointed To By Interrupt Vector
0 x 3 F F _______________________
A limited amount of data may be stored in program memory (see Writing Programs chapter).
11
Weird Hex Notation The "Ox" means hexadecimal. The Ox notation comes from the C programming language. The main thing is, when you see OxOF, it means hexadecimal OF. 0x004 means hexadecimal 004. Some of the newer Microchip literature uses "h" to denote hexadecimal numbers. 3FFh means 3FF hexadecimal. h'3FF' has the same meaning.
Data Memory Data memory consists of register files containing registers of two types: • General purpose registers which hold your data. • Special Function Registers (SFRs). The register files are 8 bits wide (with the exception of the PCLATH register which is 5 bits wide). The P1C16F818 has a 512 register file address space (0x000 - Ox IFF) divided into four banks, but not all addresses are used. Register File 0x00 01 02
03 04 05 06 07 08 09 0A 0B 0C
Indirect Address TMR0 PCL Status File Select Port A Data Port B Data
Indirect Address Pointer * Timer/Counter Program Counter Low Order 8 Bits Status Register - Flags Indirect Pointer Port A Port B
PCLATH INTCON
Program Counter Latch High Order 5 Bits Interrupt Control
IF 20
General Purpose Registers Think. Of This Area As RAM (Data Memory) 0x7F Bank 0 Not Physically Implemented Note: Bank Switching And Banks 2 And 3 Ignored
64 file registers have specific dedicated purposes and are called Special Function Registers (SFRs). For the most part, the C compiler knows what to do with the SFRs and the address of each. Wc will discuss the very few situations in which the compiler needs help finding address es as the need arises. 128 registers arc there for the C compiler to use and may be thought of as RAM or data memory for storing data during program execution.
12
Data EEPROM Memory Data EEPROM memory is not directly mapped into the data memory register file address space described earlier. Instead, it is addressed using six special function registers and some built-in C functions. This topic is beyond the scope of this book. Oh yes, I neglected to spell out what the acronym means. It stands for memory that can be read, written to, or even erased electronically. It is usually used to store data acquired during program execution (think data logger).
CODE AND DATA PROTECTION The code protection bits in the configuration register may be set so as to protect the code in pro gram memory, the data in data memory, and the data in EEPROM memory from examination by the outside world (so your code can't be ripped off). Your program can still access and change the contents of data EEPROM memory with the code protection bits set.
CONFIGURATION BITS The configuration bits are loeated in flash memory outside the main part of flash memory used for program storage. They are used to determine things like clock oscillator type, functions of some of the pins, etc. There is a chapter devoted to this subject. The device programmer accesses these bits during the device programming procedure. By doing this, the device will be in the correct configuration when it comes out of reset.
13
CIRCUIT FOR EXPERIMENTS One simple circuit may be used for all but one of the experiments in this book. The exception utilizes a 7-segment LED digital display.
TOCKI ANO INT RA4 RA1 RAO RBO
14
Looking at what is included may give you some ideas about how you would like to construct it. My suggestions on how to proceed follow. A simple circuit board may be assembled which includes a socket for a PIC16F818, power supply terminal block, power supply decoupling capacitors, three 3-pin headers and shorting blocks for use in selecting functions for pins RAO, RA1 and RA4, screw terminal blocks as a means of connecting RAO/ANO, RA I, RA4/T0CKI, and RBO/INT to the off-board components used in the experiments, and DIP switches for pins RAO, 1, 2, 3. A modular jack is included for easy connection to any of the three ICD/programmers described in the book.
If you decide to use a device programmer rather than use an ICD as a programmer, I would defi nitely use a ZIF socket for the PIC microcontroller to avoid bending or damaging the pins. 18-pin ZIF sockets are becoming expensive and difficult to find. The once common part made by the TEXTOOL division of 3M is still available from Digi-Key. It is the gold plated (literally) version (3M part number 218-3341-00-0602J) and the cost is around $18. A 24-pin Aries socket is available from JAMECO, Digi-Key and others. The Aries part number is 24-6554-10 (tin plated contacts) and the price will be in the $8 range. Simply ignore the extra 6 pins. Pullup resistors are used in the experiments primarily for the purpose of preventing unused inputs from floating. There are pullups on port B built into the PIC16F818. I decided not to use them because they just add confusion to the program examples and detract from explanation of the applications themselves. So........... as a beginner, when you use the circuit module, remember there are 10 K pullup resistors on all unused port lines. You can save refinements for later.
15
A modular phone jack is used to connect to the ICD via cable. A printed circuit board style jack is shown. One manufacturer is tyco Electronics AMP. The part number is 5204703. The Digi-Key part number is A9049-ND.
The modular phone jack is connected as shown:
Modular Jack 6-Conductor
□ tyco Electronics / AMP
□ Mfgr. P/N 520470-3 Digi-Key P/N A9049-ND
16
If you arc not able to find the small modular phone jack and you want one NOW, you may pur chase a wall-mount phone jack and whack it down to size using a saw. It will have screw termi nals on the back. Short wires may be used to connect it to your board or a solderless bread board.
The example in the photos has one end cut off to show the concept. The one that I have used for some time has all four sides of the mounting plate portion cut off.
CCS has a nice PIC16F818 board available which includes what I have described above plus a little more. See Appendix B - Sources.
CHOOSING DEVELOPMENT TOOLS CCS C COMPILER One of the great things about the CCS C compiler is that it includes tots of built-in functions (think subroutines if you are not familiar with C) which control the PIC microcontroller on board peripherals. You will not have to learn about or concern yourself with many of the inter nal workings (think control registers) of the microcontroller. If you want to read the A/D con verter, simply use the READ ADC() function. Precision time delay built-in functions are avail able for your use. CCS also supplies drivers to control popular external devices so you don't have to work so hard figuring out how to do it on your own. The CCS C compiler is a power tool for creating the code for your applications.
DEVICE PROGRAMMING METHODS Device Programmers And Ease Of Running Code Examples There are two choices. • lise a device programmer, program the device, remove it from the socket on the programmer, place it in the socket on the test circuit, power-up the test circuit, and run the program. This is easier than it sounds. • Use an in-circuit debugger (ICD) as a programmer This is done using a method called in-circuit serial programming (tm) (ICSP) (tm) and the device is programmed in the experiment board. Immediately after programming, the circuit may be exercised by clicking on a "run" (or similarly named) button on-screen. Moving the device is not necessary. This is the easiest method. ICDs are the least expensive way to go these days unless you already own a device programmer.
Device Programmer A device programmer is used to load code into a device and that's it. The device is usually clamped in the programmer's zero insertion force (ZIF) socket during programming. After pro gramming is completed, the device is removed from the ZIF socket and inserted in the socket on the experiment board. The board is powered-up and the code is tested.
In-Circuit Serial Programmer An in-circuit debugger (ICD) may be used to download code into a device, run the code, and debug the code. Debugging is not covered in this book, however, a debugger may be used to load the example programs in this book into a device followed by bringing the device out of reset so the code will run. The device is part of the example circuit when the programming takes place, a process called in-circuit serial programming (ICSP).
18
In-circuit serial programming requires the use of two port lines, generally port B, pins 7 and 6. To keep things simple, the examples in this book do not use these two pins for the test circuit. This allows in-circuit programming followed immediately by running the program using the ICD on-screen controls to bring the microcontroller out of reset which allows the program to run. In an industrial/commercial product development environment, port B, pins 7 and 6 would be used in the application and special means (a special substitute device or a header containing one) would be used to gain access to the part for debugging purposes while leaving port B, pins 7 and 6 free. This is an advanced topic and wc won't concern ourselves with the details here. The PIC16F818 may be programmed using an ICD as an in-circuit serial programmer followed, immediately, by running the code. Available ICD's include the CCS ICD-U40 (or ICD-S40), the PICkit 2 (tm), and the Microchip ICD 2 (tm). Three advantages of using this method over using a device programmer (only) are: • The convenience of running the code immediately following programming. • The low cost of the tool. • The ICD will be available for debugging when you move up to more advanced projects.
CHOOSING A DEVICE PROGRAMMER Selecting a programmer (only, not an ICD) for PIC microcontroller development is a personal choicc based on the following criteria: • Range of parts which can be programmed. • Support (level, long-term). • Price. Simple, inexpensive device programmers are available which run under Microsoft Windows. As product offerings are continually changing in this fast-paced market, I suggest you contact the programmer manufacturers directly for the latest information. Note that some programmers are connected to the PC's parallel (printer) port, some arc connected to a serial port (usually COM2), and some are USB devices.
Microchip PICSTART Plus (tm) Microchip's PICSTART Plus will program their 5 volt dual in-line (DIP) packagc devices. The latest version of the PICSTART Plus contains a PIC 18 scries microcontroller which converts information received from the PC's serial port to the appropriate signals to program each device. Since these devices have differing requirements, the code in the PIC 18 microcontroller must be updated to cover the requirements of new devices as they become available. The latest code (firmware) may be downloaded from Microchip's web site at no charge. The PICSTART Plus operates under Windows and is connectcd to one of the PC's serial ports (usually COM2).
19
The control software for the PICSTART Plus is incorporated in MPLAB (tm) which is Microchip's development software. MPLAB is also updated frequently to incorporate support for new devices as they are introduced. The PICSTART Plus currently sells for about $200.
CHOOSING AN IN-CIRCUIT PROGRAMMER/DEBUGGER CCS ICD-U40 (or -S40) The 1CD-U40 uses a USB interface and the ICD-U40 uses an RS-232 serial interface. They each use different control software. The CCS ICD will program the devices used as examples used in this book using ICSP and will allowr the program to run after the device is programmed. The ICD Control Software is separate from the compiler software. The ICD-U40 or -S40 currently costs approximately $75.
Microchip PICkit 2 (tm) The PICkit 2 uses a USB interface. The PICkit 2 will program the devices used as examples used in this book using ICSP and will allow the program to run after the device is programmed. Control software comes with the PICkit 2 and will handle the tasks we need to perform with the examples in this book. The PICkit 2 may be used under the control of MPLAB for many devices. We will use the PICkit 2 control software in our examples. The PICkit 2 MCU programmer (PG164120) currently costs about $35. I suggest purchasing a RJ-11 to ICSP adapter (AC 164110) ($ 10) to go with it. It has a header at one end to interface with the PICkit 2 and a short 6-conductor cable with a modular plug on the other to interface w ith the modular jack on your board.
Microchip ICD 2 (tm) The ICD 2 will also program the device used as an example in this book using ICSP and will allow the program to run after the device is programmed. MPLAB is used to control the ICD 2. An ICD 2 with a USB cable and powrer supply sells for approximately SI90.
20
Programming (only) Connections
Programming Software
CCS ICD Control Software
PICkit 2 Application Software (MPLAB for some devices)
MPLAB
PICSTART Plus
MPLAB
21
PROGRAMMING A DEVICE USING THE ICD-U40 (or -S40)
INSTALLING THE ICD CONTROL SOFTWARE Follow the CCS directions on CD.
USING THE ICD AS A PROGRAMMER To program a C object file (.cot) into a PIC microcontroller: Connect the 1CD-U40 to your PC using the USB cable included with the ICD module. Connect the ICD to your target board using the short modular phone cable (6-conductor) supplied with the ICD. The target board should be powered by your +5 volt logic power supply. Power-up the PC which will supply power to the ICD via the USB interface. Power-up the Target board. Open the ICD control software. Note that this program is separate from the compiler software.
22
The ICD Control Program window appears.
Targets Supported: All
To program and exercisc an example program, click on the Advanced button. The ICD Advanced window appears.
Our objectives are: • Halt the device (hold the MCLR line low). _____ • Run example programs (put the target device in run mode by allowing the MCLR line to be pulled high). • Program (write) example programs into a device. We will not concern ourselves with debugging as that is an advanced topic. Halt vs. Run can be selected by clicking on the appropriate button in the Target State area in the ICD Advanced window. To program a dcvicc, a .cof file must have been created previously using the compiler.
24
With the ICD Advanced window open: Halt the target device. In the Write Device area, click on From Hex/Cof file. The Download To Target window will appear. Navigate to the object file you wish to write to the target device and select it (will be highlighted when you have selected it). Click Open. This will initiate programming. In the message area in the lowrer left comer of the ICD Advanced window, a message should appear indicating that your source file has been written to the target device. Click on the Run button. There will be a slight delay. Observe your program running (look at LEDs or whatever depending on what the code is supposed to do). When you have finished your celebration (you did do everything correctly didn't you!), click Halt. You may repeat the programming process to test another program. When you are finished: Power-off the target board first (always!). Power-off the PC last. Disconnect the USB cablc. When using the CCS ICD to program a PIC microcontroller, the software also supports .hex files (not just .cof files). Since .hex files are much smaller and do not contain the C source, .hex files are more often used in a production setting.
PROGRAMMING A DEVICE USING THE PICkit 2 To program a .cof file into a PIC microcontroller: The PICkit 2 comes with its own programming software which we will use here. Some devices may be programmed using MPLAB and accessing the PICkit 2 as one of the programmer options under MPLAB. The PICkit 2 has a 6-pin header socket as the interface to a user board. Products are often designed with a 6-pin header on them to allow in-circuit serial programming (ICSP) after the product is assembled and just before it is shipped allowing the latest firmware version to be pro grammed into the product. Firmware may also be changed by the customer in the field after the product is in use. for experimenting and development, Microchip offers an adapter consisting of a very small board with a header to mate with the socket on the PICkit 2 plus a modular phone jack. A short 6-conductor phone cable is included to conncct the adapter to a modular phone jack on your board. The Microchip part number is AC 164110 (ICD 2 to ICSP adapter).
Connect the PICkit 2 , adapter, modular phone cable, and your board together. Conncct your board to your +5 volt logic power supply (power supply off). Connect the PICkit 2 to your PC using the USB cable supplied with it. Power-up the PC. Power-up your board. Open the PICkit 2 programming software.
26
The PICkit 2 software will come up recognizing the device on your board (assuming the devicc family you are using was selected the last time the software was used). If not, on the Menu Bar, select Devicc Family>Midrange. Check /MCLR in the small Vdd PICkit 2 box. Load your .cof file into MPLAB’s Program Memory (zone). File>Import Hex Navigate to your .cof file. Select the file. Click Open. A message will appear indicating that the file has been imported. Click on the Write button to program the device. A message should appear reporting success. Uncheck /MCLR in the small Vdd PICkit 2 box. Your program should run. To halt program execution check /MCLR. This will hold the device in reset. To program and run another program, load another .cof file and repeat the programming procedure. When you have finished experimenting, power-down using the reverse sequence: Power-down the target board. Power-down the PC.
27
PROGRAMMING A DEVICE USING THE ICD 2 DESCRIPTION The Microchip in-circuit debugger (ICD 2) consists of software which runs on a PC (included in MPLAB) and hardware which looks like a colorful hockey puck (two of the colors are shown here).
For the purposes of this book, the ICD 2 will be used as an In-Circuit Serial Programmer (tm). The unit has a USB connector for serial communication with a host PC and a 6-conductor modu lar phone jack for communication with a flash PIC microcontroller. The PIC microcontroller resides on a so-called "target" board which is the user's (your) board. Microchip strongly recommends using USB and NOT the RS-232 connection which is built into the ICD 2 for communications between the host PC and the ICD 2. Following the current version of the Microchip USB Port Setup instructions is a MUST. Refer to the "Readme for MPLAB ICD 2" contained in the Readmes folder in the MPLAB folder. I recommend purchasing the ICD 2 full kit with power supply (DV164007) and storing the RS-232 serial cable somewhere.
28
The ICD 2 can operate in two operating modes: • Debugger mode (not discussed here). • Programmer mode. In the programmer mode, your code is programmed into the device for stand alone (without the ICD 2 connected) operation. The code can, however, be run with the ICD 2 connected. Selecting the best option for powering the ICD 2 and the target is critical. Based on my experi ence and that of others, I recommend powering the ICD 2 using Microchip's wall transformer power supply and NOT via the USB port. I also recommend powering the target (your circuit) with your own power supply.
USER BOARD = TARGET BOARD For the purposes of this book, the PIC16F818 experiment board described earlier is set up to be used with the ICD 2. You can easily set up another board of your own in a similar way by pro viding the modular phone jack and using the 47 K pull-up resistor on MCLR (reset).
SETTING UP THE ICD 2 Connect the ICD 2 to your PIC16F818 board using a short 6-conductor modular phone cable. Connect your PIC 16F818 board to a suitable +5 volt DC power supply. When powering-up the ICD 2 and PIC16F818 board the first time or for use with a new project, use the following procedure: 1. At start-up, NO power should be applied to the PIC 16F818 board. 2. Power-up the host PC. 3. Power the ICD 2 . The green "Power" LED in the ICD 2 should be on. 4. Start MPLAB. At this point, it is assumed that you have a .cof file suitable to be programmed into the PIC16F818 on your board. 5. Configure>Select Devicc. Select PIC16F818. 6. Select ICD 2 as the programmer to be used. Programmer>Select Programmer>MPLAB ICD 2.
29
7. A Setup wizard will appear the first time the ICD 2 is connected. Select USB as the communications method. Select target has owrn power supply. Select auto connect to ICD 2. Select ICD 2 automatically downloads the required operating system. 8. Select Programmer>Settings. 9. The MPLAB ICD 2 Settings dialog box will open. Click the Power tab and ensure that the check box for "Power target circuit from ICD 2" is NOT checked. Click OK. This is important! 10. Power-up your PIC 16F818 board. 11. Open the output window. View>Output. 12. Select Programmer>Connect. 13. Observe the activity in the output window. On completion, the next to the last two text lines should read "Running ICD Self Test... Passed" and the last text line should read "MPLAB ICD 2 Ready". 14. You should now be able to debug and erase the PIC16F818 on your board. Reverse the procedure to power-down (PIC16F818 board off, ICD 2 off, PC off).
PROGRAMMING PROCEDURE Soooooo........ once the setup has been done, use the following procedure to program a .cof file into a PIC microcontroller: 1. 2. 3. 4. 5. 6. 7. 8.
Connect the ICD 2 to your board (target board). Connect the ICD 2 to your PC. Power-up the PC. Power-up the ICD 2 using the ICD 2 power supply. Power-up the target board using your own power supply. Open MPLAB. Configure>Select Device. Programmer>Select Programmer. Select MPLAB ICD 2. 9. Programmer>Connect (if you don't have auto-connect selected). 10. Import your .cof file into MPLAB's Program Memory (zone). File>Import. Navigate to your .cof file. Select the file. Click Open. A message will appear indicating that the file has been imported. 11. Programmer>Program. A message in the Output window should report success. 12. Programmer>Release from Reset to run your program. 13. Import another .cof file and repeat the procedure. 14. Programmer>Disable Programmer (assuming you are finished programming devices for a while). 15. Power-down using the reverse sequence: Power-down the target board. Power-down the IC’D 2 by disconnecting the power cable. Power-down the PC.
30
PROGRAMMING A DEVICE USING THE PICSTART Plus
To program a .cof file into a PIC microcontroller: Connect the PICSTART Plus to your PC (as usual). Power-up the PICSTART Plus. Open MPLAB. Configure>Select Device. Programmcr>Se 1 ect Programmer. Select PICSTART Plus. Programmer>Enable Programmer. A message in the Output window will indicate your PICSTART Plus firmware version. Load your .cof file into MPLAB's Program Memory (zone). File>Import. Navigate to your .cof file. Select the file. Click Open. A message will appear indicating that the file has been imported. Insert the device in the ZIF socket. Be careful about pin orientation. Programmer>Program. A message in the Output window should report success. Remove the programmed device from the ZIF socket. Programmer>Disable Programmer (assuming you are finished programming devices for a while). Power-down the PICSTART Plus. NEVER power-up the PICSTART Plus with a device in it as the device may be damaged!
31
CCS COMPILER
INSTALLING CCS COMPILER - PCWH Follow the CCS directions on the CD.
USING THE COMPILER Create a new' folder for your C stuff. Create a source file. File>New>Source Csl The compiler will add .c file name extension. Type your first source code. Call it Csl as an example. Create a new project. Project>Create. The Select main source file window appears. Select device. Select your file (Csl or whatever). Click Open. The Project options window appears. Your file name has been selected automatically (if you had one open). Click Apply. Compile your code. Click on the Compile tab on the menu bar at the top of the screen. The Compile menu ribbon will appear. Click on the Compile icon on the Compile menu ribbon. Your source code will be compiled successfully, we hope. The Output window will appear indicating how the compile process turned out. For the examples in this book, a warning message will appear: »>Warning 208 Csl.c Line 6 (i,5): Function not void and does not return a value main Ignore the warning. This is what we wanted, so celebrate!! A C object file (.cof file) was created as part of the process of compiling your source code (done in the background). It is located in the same folder as your source code (Csl .cof). This is the file that will be programmed into the PIC microcontroller.
32
If you have PIC microcontroller assembly language programming expcricnce, you may want to take a look at the assembly language listing of the code generated by the compiler. To do this, click on the Output files icon on the right end of the Compile menu ribbon. Click on the C/ASM List icon. : in proper places critical!! One missing semicolon can result in a lot of compiler error messages of various kinds. I am cer tain that you will never experience this.
C SOURCE CODE This is what C source code looks like: ////first C program ala pictl.asm Csla #include #fuses INTRC_IO,NOWDT,PUT,NOPROTECT,BROWNOUT,MCLR,NOLVP,NOCPD,NOWRT,NODEBUG #fuses CCPB2 //internal clock osc with I/O on RA7, RA6 //watchdog timer disabled power-up timer enabled //code protection off brown-out reset enabled //mclr enabled low-voltage programming disabled //no EE data protection write protection off //no debug CCPl function pin RB2 (arbitrary) main()
{ setuposcillator(0SC4MHZ); outputb (OxOf); while (TRUE);
//4 MHz clock oscillator //bit pattern to port B //circle, always
} This is a very simple program which runs on a PIC16F818. We will assume that there are 8 LEDs connected to port B. Executing this program causes 4 LEDs to be off and 4 LEDs to be on. I am sure this program looks very cryptic to you now. When you have finished reading this book and doing the experiments, this program and much more complex ones will no longer seem cryptic. As you read the next few chapters, you can refer to this program to see how the topics relate to this program. For now, let's make some observations about the overall look of the program.
TYPING ACCURACY Typing accuracy is very important when creating C source code. A punctuation mark, either typed by mistake or omitted, can cause a lot of head scratching (or worse) because your "per fect" program won't compile. The compiler sees exactly what you type.
COMMENTS Comments help anyone (including you) who reads your code understand what it does. There arc two styles. /* //
The compiler ignores all comments.
34
*/
Comments between /* and */ Comments between // and end of line
TEXT AND FORMATTING Formatting such as spaces, tabs, carriage returns, etc. are ignored by the compiler. Formatting makes code readable to us. White space resulting from laying out a program so it appears better organized is a good thing. This comes from using spaces, tabs, and blank lines. The compiler will ignore white space. Use tabs for indentation instead of several spaces. The number of spaces per tab is usually adjustable. Three spaces per tab works well. ANSI (or standard) C is case sensitive, but CCS C is not.
35
BITS, BYTES, ETC. BIT One bit in memory or a register can represent 1 of 2 possible states, "0" or "1". In the world of digital electronics, it is convenient to build circuit elements which have two states, off or on. These states can be represented by "0" or "1". POSITIVE LOGIC Binary Number 0 1
Voltage 0 volts (approximately) 5 volts (approximately) in a 5 volt system
The exact voltage ranges which represent 0 and 1 vary depending on the logic supply voltage and the integrated circuit logic chip family used (TTL, CMOS, etc.). The choice of using binary 0 to represent 0 volts is arbitrary. Positive logic is shown above. It can be done the opposite way which is called negative logic.
NIBBLE A nibble consists of 4 bits and can represent 16 possible states. A nibble is typically the upper or lower half of a byte (most significant or least signi (leant nibble).
BYTE A byte consists of 8 bits and is said to be 8 bits wide. 8-bit microcontrollers move bytes around on an 8-bit data buss (8 conductors wide).
BINARY A binary' number with more than one bit can represent numbers larger than " I". How much larg er depends on the number of bits. An 8-bit binary number (byte) can represent 256 possible numbers (0 to 255). A 16-bit binary number can represent numbers from 0 to 65,535. If we use a byte to transmit information, we can transmit 256 possible combinations, enough to represent the 10 decimal digits, upper and lower case letters, and more. A commonly used code used to represent these characters is called ASCII (American Standard For Information Interchange).
36
Binary numbers arc based on powers of 2. The value of bit 0 is 2° = 1 if it contains a 1, or 0 if it contains 0. The value of bit 1 is 21 = 2 if it contains a 1, or 0 if it contains 0. The value of bit 3 is 23 = 8 if it contains a 1, or 0 if it contains 0, and so on. For a 16-bit binary number, bit 0 is the least significant bit, and bit 15 is the most significant bit. The following table shows the value of each bit position if it contains a " I
Bit 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 Most Significant
Least Significant
Bit
Value
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
1 2 4 8 16 32 64 128 256 512 1024 2048 4096 8192 16384 32768
The value of a binary number contained in a 16-bit timer/counter would be determined by multiplying the contents of each bit by the value of each bit.
1 Bit
0
0
1
1
0
15 14 13 12 11 10
0
1
0
0
1
0
0
9
8
7
6
5
4
3
01 1
1
21
0
L
L
37
Counting up in binary goes like this: 0000 0001 0010 0011 0100 0101 etc.
You can use this information when you observe what happens to some LEDs used to display the count in a binary count up example program. PIC on-board timer/counters count in binary. A binary number may be used to represent byte-wide bit patterns sent to output ports.
HEXADECIMAL Binary numbers which are two bytes long are difficult to recognize, remember and write without errors, so the hexadecimal numbering system is sometimes used instead. Think of hex as a kind of shorthand notation to make life easier rather than some kind of terrible math.
Hexadecimal Binary Decimal 0 1 2 3 4 5 6 7 8 9 A B C D E F
0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Hex is sometimes used in this book to represent addresses in memory and is sometimes used to represent bytes of data. Using hex is not difficult. All you need is a little practice. One byte requires two hex digits. Note that the bits representing a byte are sometimes shown in groups of four. Note that the most significant hex digit is on the left. Hex numbers are denoted by "Ox" in this book. Some of the more recent Microchip literature uses the "h" to designate a number as hexadecimal.
38
To summarize: Binary 1
Hex
Decimal
1 1
11 1t
0000 0001 0101 1111
0 1 5 F
0 1 5 15
0000 0000 0000 0001 1111
0000 0001 1111 0000 1111
00 01 OF 10 FF
0 1 15 16 255
0000 0000 0000 1111
0000 0001 0000 1111
0000 0001 0100 FFFF
0 1 256 65535
ii
t1
Nibbles
Bytes
Two Bytes 0000 0000 0000 1111
0000 0000 0001 1111
Hexadecimal OxFFFF (the very top of the program memory address space in some microcon trollers) is much easier to write or remember than either 1111 1111 1111 1111 or 65535.
39
CONSTANTS A literal constant may be defined as part of a built-in function such as: output_b (OxOf);
//defines hex byte OxOf and sends bit pattern // to port B
A symbolic constant may be defined using the key word const which is a modifier that can be applied to any numeric declaration. const int LEVEL = 1 0 ; // defines integer type constant named // level with a value of 10
After the symbolic constant is defined, it is referred to by name in the program. The #define pre-processor directive may be used for defining constants. #define MAX_SAMPLES 32
This method for defining constants is probably used more often than the key word const method. A convention in C is to use upper case letters in all constant names. Constants are stored in program memory and cannot be changed during program execution.
40
VARIABLES Variables are memory locations used to store data. A variable must be defined prior to use in a program by using the assignment operator. variable = data '---assignment operator
Variables are named according to the data type that will be stored in them, ie. an integer variable holds integer data, etc. (see next chapter, Data). The variable definition process tells the compiler how much memory space should be allocated for the variable being defined. A variable, as the name implies, may be changed during program execution and will be stored in a general purpose file register (RAM location) in the PIC microcontroller. Variables are either global or local. • Global variables are defined outside a function and can be used by any function. • Local variables are defined inside a function (after an opening brace) and used within that function (before the corresponding closing brace). It is considered good practice to use local variables wherever possible so you can control access to them. If a function needs to use another function's local variable, that variable can be passed to the function that needs it. Access to local variables is controlled, a good thing. Passing variables (arguments) will be discussed in a later chapter on the subject. Declaration of a variable will be demonstrated in the following chapter after data types have been explained. Naming of variables is explained in the chapter after that.
DATA Basic data types used in this book are (see note below): Character (ASCII) A character is a single ASCII character which may be represented by 8 bits. There are 256 ASCII characters. The characters most commonly used in microcontroller applications are contained in a table later in this chapter. Apostrophes indicate a character 'A' 'a' ' 1 '6' More than one character is called a string and is designated by quotation marks " " (see Strings chapter) Bit One bit Called inti, sometimes called short or boolean, can be called bit with use of typedef declarator (details follow) Can represent one of two numbers, "0" or "1" Byte 8 bits Called int8, byte Can represent 0 - 255 Hex OxOf Binary ObOOOOllll int 16 16-bit number Can represent 0 - 65535 Integer Whole numbers No decimal point Called int - same as int8 by default Can represent 0 - 255 Float Real numbers May have a decimal point Not used in this book Void Indicates no specific type
These are called data "types" and are used in type declarations to allocate the space required in memory for data storage.
42
Type qualifiers may be added to further delineate these basic number types, but we won't use them. Variables with negative values will not be discussed. Note: The definitions of C data types depends heavily on the source of the information. The degree of inconsistency is huge! My goal is to present what is needed to get going in a simpli fied way while still giving you a representative look at the wrorid of C. Using the CCS names (inti, int8, inti6) exclusively would simplify things, but you would not be able to read code found elsewhere. You will have some difficulty anyway, but I hope to keep it to a minimum. The following table lists the data types used in this book plus inti 6.
DATA TYPES How I Think
CCS Name
Bits
character bit byte 16-bit binary integer
char inti int8 intl6 int
8 1 8 16 8
Range N/A 0, 1 0 - 255 0 - 65535 0 - 255
The integer data type may be assigned as follows int a; //declares variable a as in integer type a = 2; //assigns initial value 2 to variable a int a = 2; //combined declaration, declares variable a and assigns // and initial value 2
The = sign is the assignment operator. Assignment examples arc sprinkled through the code examples that follow'. typedef is a declarator which can be used to create a new type name that can be used in declarations. [type-qualifier] [type-specifier] [declarator] typedef inti bit; //use bit instead of inti
An example appears in the Writing Programs chapter in the Flags section.
ASCII CHARACTERS The transmission of text requires that the text characters be encoded using a combination of binary bits. The most widely accepted text code is ASCII, the American Standard Code for Information Interchange, supported by the American National Standards Institute (ANSI). ASCII includes 26 upper case letters, 26 lower ease letters, the numerals 0 through 9, plus some punctuation characters and special characters. The following table includes the most commonly used characters. The table shows how each character may be represented by a hex byte as is sometimes necessary in microcontroller applications (driving an alphanumeric LCD for example).
JIBBLE 0x2 0x0 1 2 3 4 5 6 7 8 9 A B C D E F
Example: 0x41 = A Note: 0x20 = Blank
44
i " # $ % Sc ' ( ) * +
,
/
UPPER NIBBLE 3 4 5 6 0 1 2 3 4 5 6 7 8 9 / < = >
A B C D E F G
H I J K L M N O
P Q R S T U V W X Y Z
/\
7 P
a b c d e f g h i j k 1 m n o
q r s t u V w x y z
NAMING CONSTANTS AND VARIABLES Names for constants and variables are also referred to as identifiers (id). Rules: 1) All names used in a program must be unique. 2) Names must begin with a letter of the alphabet or an underscore. 3) After the first letter, names can be made up of letters, numbers, and underscores in any combination. An occasional capital letter may be used for clarity. 4) Names may be of any length up to a maximum of 32 characters. 5) ANSI (standard) C is ease sensitive, but CCS C is not. 6) The following key words are reserved for special uses in C. Do not use them for names. auto break case char const continue default do doubl else entry
enum extern float for goto if int long register return short
signed sizeof static struct switch typedef union unsigned void volatile while
7) In addition, the CCS compiler has the following non-standard reserved key words: addressmod _fixed float32 float48 float64
inti int8 intl6
int32 int48 int64
45
A nice thing about C is that port pins may be named for their functions while writing programs which makes referring to them easy. The #define pre-processor directive may be used for defining constants. #define GREEN LED PIN_B0
When it is time to write a line of code to toggle the green LED, the "green one" is easier to remember than the fact that the green LED is wired to port B, pin 0. output toggle(GREEN_LED);
Another example is: #define TD PIN_A1
RS-232 data is transmitted via pin I’D rather than port A, pin 1.
46
OPERATORS - SHORT LIST An operator is a symbol that instructs the C compiler to perform a specific operation on one or more operands. An operand is an expression that the operand acts on. This will become clear through usage. We will need only a few operators to get started writing C programs. They are: Assignment operator equal sign variable = expression; Assign the value of expression to variable = not normally used in math, but it is legal to do so
Relational operators == < Valid Fuses The kinds of things determined when making configuration selections arc: Clock oscillator type selection Watchdog timer enabled/disabled Powcr-up timer enabled/disabled RA5/MCLR/Vpp pin function selection Brown-out reset enabled/disabled Lowr voltage programming cnabledMisabled Data code protection enabied/disabled Flash program memory write protection on/off In-circuit debugging enabled/disabled CCP module pin selection Flash program memory codc protection on;off
RC Disabled Enabled MCLR Enabled Disabled Disabled Off Disabled CCP 2 Off
RC NOWDT PUT MCLR BROWNOUT NOLVP NOCPD NOWRT NODEBUG CCP2 NOPROTECT
Pre-proccssor directives are discussed in a chapter on the subject.
53
The CCS C compiler has default fuse selections. The defaults for the PIC16F818 are listed in the second and third columns in the list above. As it turns out, the default selections are what I would use, with the exception of the clock oscil lator. Using the internal clock oscillator is most convenient. We will use the default 31.25 KHz internal clock oscillator frequency for all examples except those involving a time delay or the use of timer 0. In those instances, we will use 4MHz as the internal clock oscillator frequency. The clock oscillator frequency is divided by 4 inside the microcontroller resulting in an instruction clock frequency of 1 MHz when the clock oscillator frequency is 4 MHz. This makes the math easy for calculating timer 0 intervals. In this book, clock oscillator type and frequency will be selected in one of three ways: 1) For programs with no time delay or use of timer 0: #fuses intrc io
The pre-processor directive selects the internal clock oscillator option. By default, the frequency will be 31.25 KHz. 2) For programs using a time delay, we will use the internal clock oscillator operating at 4 MHz. #use_delay(internal=4mhz)
The pre-processor directive selects the internal clock oscillator operating at 4 MHz. In addition to the delay, the compiler gives you: #fuses intr_io setuposcillator(0SC4MHZ);
These two lines do not need to appear in your code. The pre-processor directive syntax is: #use delay(type=speed) See the CCS compiler manual for details. type is the clock oscillator type. speed is a constant.
The compiler takes care of the clock oscillator fuses for us. 3) For programs using timer 0, we will use: #fuses intrc_io
and setup_osciliator(0SC_4MHz);
This will be illustrated by the programming examples that follow.
54
FUNCTIONS main() FUNCTION A function is a routine that performs a task. A function may come with the C compiler you are using or you may write one yourself. All C programs contain a "main" function which embodies the program that you create,
main() {
program
The parentheses that follow a function name indicate that it is a function. Parameters are some times passed to functions as arguments contained within the parenthesis. In this example, there are none. Braces { } indicate what is included in the function, which is the whole program in this case. void main (void) is commonly used in place of main() to begin C programs.
function
void main (void)
V
N------- main has no arguments
main does not return data
I choose not to use this method because in microcontroller applications, arguments are not required for the main program and no data is returned. The CCS compiler generates a warning when I do this. I choose to ignore it because using main() makes the code simpler and more readable. Simple is my goal.
55
FUNCTIONS Functions are the basis of programming microcontrollers in C. The CCS C compiler comes with lots of functions designed to do specific tasks such as writing to a port, creating a time delay, set ting up an A/D converter, etc. The fact that these built-in functions are provided will save a lot of work and your projects will be completed sooner. Parameters may be passed to functions as arguments. function ( ________ , ________ , ________ )
Calling a function may or may not return a variable. You may write a function to perform a specific task, test it, and store it away so it can be retrieved and used the next time you are writing code which includes that task.
56
BUILT-IN FUNCTIONS - SHORT LIST The CCS C Compiler Reference Manual contains descriptions of the built-in functions contained in their compilers. Following is an abbreviated list of some functions we will need to get started writing programs. Some built-in functions require a special/specific include file(s) to work. Refer to the descrip tion of the built-in functions you are interested in using in your program. If a pre-processor directive file is needed, its name will appear under the "Requires:" heading in the built-in func tion description in the manual.
FUNCTION
BIT_CLEAR() BIT_SET() BIT_TEST DELAY_CYCLES() DELAY_MS() DELAY US()
SYNTAX
bit_clear(var,bit) bitset(var,bit) value=bit test(var,bit) delay cycles(count) delay_ms(time) delay_us(time)
PRE_PROCESSOR DIRECTIVE (if required)
#use delay #use delay
//clock frequency //clock frequency
For ports where x is port identification letter (ie. "a", "b", etc.): SET_TRIS x() INPUT_x() OUTPUT x(), etc.
set_tris_x(value) value = input_x() output_x(value)
For individual port pins: INPUT() OUTPUT_LOW() OUTPUT_HIGH() OUTPUTBIT() OUTPUT TOGGLE(
value = input(pin) outputlow(pin) output high(pin) output_bit(pin, value) output_toggle(pin)
For interrupts: CLEAR_INTERRUPT() clearinterrupt(level) DISABLE_INTERRUPTS() disable_interrupts(level) ENABLE_INTERRUPTS() enable_interrupts(level) EXT_INT EDGE() ext_int_edge(source, edge)
#int xxxx #int_xxxx
edge H_TO_L high to low transition at INT pin edge L_TO H low to high transition at INT pin For RS-232: PUTC() PRINTF()
putc(cdata) printf(string)
#use_rs232 and #use delay #use_rs232 and #use_delay
57
For controlling timer 0: SETUP TIMER 0() SETTIMERO() GET_TIMER0()
setuptimer_0(mode) set_timerO(value) value=get_timer0()
For controlling the A/D conversion process: SETUP_ADC(mode) SETUP_ADC_PORTS() SET_ADC_CHANNEL() READADC()
setup adc(mode) setup_adc_ports (value) setup adc channel(chan) value=read_adc([mode])
STATEMENTS EXECUTABLE STATEMENTS An executable statement is a line of code that does something. Executable statements always end with a semicolon which indicates that the statement is executable. means "execute".
Blocks A block is a group of one or more executable statements enclosed by braces. { statementl; statement2;
//block of statements
statementn;
}
CONDITIONAL STATEMENTS Conditional statements control program flow (see next chapter), if while do for switch
58
SEMICOLON USE RULES Again, executable statements always end with a semicolon wrhich indicates that the statement is executable. means "execute". Conditional statements are not followed by a semicolon. if do for switch while has exceptions and has its own rules - see below, while do/while loop Semicolon required after w'hile (condition), while loop No semicolon after while (condition). Exception: a semicolon is required after while(TRUE) used in a while loop acting as a halt at the end of a program (executed).
Remember that there is no semicolon after a function name such as main() or del(). The programming examples in the chapter on Writing Programs will serve to illustrate.
59
PROGRAM DESIGN This chapter will serve as an outline or overview of program design possibilities. Chunks of this information will be reprinted as appropriate in the following chapter on Writing Programs with accompanying programming examples. Showing the possibilities in one place will serve now as an overview and later as a reference. You may want to skim through this chapter the first time and then reread it a time or two as you go through the next chapter (Writing Programs).
60
PROGRAM DESIGN - CONTROL FLOW if
if (condition) statement;
//single statement
or if (condition)
{ statementl; statement2;
//block of statements
statementn;
If the condition is true, statement(s) is executed. If the condition is false, statement(s) is not executed. In either case, execution continues with the line of code following statement(s). Note that if(condition) and statement(s) are all part of the if statement.
The relational operators may be used as the basis of conditions in if and if/else conditional state ments to direct program flow.
Relational Operators Comparisons == Equal to > Greater than < Less than >= Greater than or equal to Font. Font: Courier or Courier New. The courier font is a monospace font. Font Style: Regular Size: 10 File>Properties The "filename" Properties dialog box appears. Click on the Settings tab. Emulation: ANSI The remaining settings should be the default settings. Click OK. File>Save.
115
Strike a letter key. Nothing happens. The screen displays characters received, NOT characters sent. Turn off your computer. Install the "U-turn" connector at the serial port you are going to use. Generally this will be COM 2 as most systems have the mouse connected to COM 1. Turn on your computer. Open the settings file you just created in HyperTerminal. The HyperTerminal window should now be open, blank, and a cursor should be blinking in the upper left hand cor ner. Now type any character. The character will appear on-screen w^here the cursor was. The character displayed is actually the character received by the terminal program. If you type the letter "a", it will be transmitted out the COM 2 serial port on the TD line, make a U-turn, come back in the same serial port on the RD line and will be displayed on the screen. Note that the character sent is not displayed, the character received is. They happen to be the same in this case because of the U-turn. Three ASCII control characters are useful for controlling the placement of ASCII alphanumeric characters on the screen of the PC as they are received. This is important because we want the information to be readable and also because we will want data to be formatted to be saved as a useful text file. The three ASCII control characters are:
As an example, a carriage return is sent when the control and "m" keys are pressed simultane ously (control m). As you probably already know, carriage return causes placement of characters on the screen to move to the extreme left side. Line feed causes characters to be placed on the next line down the screen. Horizontal tab means tab over to the right. Theses terms come from the teletype days. Try experimenting with the first three control characters to get a feel for how they control place ment of the characters on-screen (formatting). To clear the screen, Edit>Clear Screen. For our PIC microcontroller-based experiments, the microcontroller will send data to the PC where it will appear on the HyperTerminal screen. Examples appear in the Strings and Math And Manipulating Numbers chapters.
116
PC-TO-PC "2-LANE HIGHWAY" EXPERIMENT If you have two PCs available, you might like to do the following experiment to learn more about serial communication between twro PCs, both running HyperTerminal. A cable wrill be required to conncct the two serial ports. The simplest possible cable which will work consists of two data lines (one for each direction) and a ground line.
Cable Assembly
Notice that the transmit data (TD) line on computer 1 is connected to the receive data (RD) line on computer 2 and visa versa. You can easily make your own cable assembly using twro 9-pin female D-subminiature connectors and three lengths of wire. Keep the cable as short as possible (8 feet works for me). Both computers must communicate using the same settings for baud rate, etc. You can start by using the settings used previously in the setup examples. Baud rate Data bits Parity Stop bits Flow control
4800 8 None 1 None
The objective is to establish bi-directional communication between two computers. We will assume both computers are running HyperTerminal. To establish bi-directional communication, connect the computers via the serial cable, turn both of them on and bring up HyperTerminal with your settings file in each. When you have the HyperTerminal window open in each computer, type a character in one of the computers. It will appear on the screen of the other computer. Now do the reverse. After you have played a little, clean off the screen in each computer by using Edit>Clear Screen.
117
PC/PIC MICROCONTROLLER The hardware side of 2-way communications between a PIC microcontroller and a PC will be described next.
PC Baud Rates Baud rate is defined as the number of bits transmitted per second. The baud rates available for serial communication via a PC using a terminal program are:
Baud Rates
118
RS-232 INTERFACE FOR A PIC MICROCONTROLLER My objective here is to give you just enough information about RS-232 to make it possible to build a simple hardware interface between a PC1 serial port and a PIC microcontroller. A MAX233 RS-232 converter IC from MAXIM Dallas will be used to develop the 9 volts or so required to transfer data per the RS-232 standard. Among other things, an RS-232 converter chip is an inverter. There is an RS-232 converter chip inside the PC which inverts data going both ways. It is desirable to use one at the PIC microcontroller end too so that everything comes out right (see diagram on following page).
RS-232 CONVERTER
119
The connections between the PC, cable, RS-232 converter and PIC microcontroller are:
RS-232 CONVERTER
Note that only the wrircs used between the PC and RS-232 converter board in a particular experi ment are shown in the drawings that follow in this book. The third wire in the cable described in the "2-lane highwray" experiment will not interfere. The pin-functions for PC RS-232 serial connectors of interest here are:
Function
9-pin*
Transmitted data (TD) Received data (RD) Common
3 2 5
25-pin 2 3 7
* Shown in this book
The cable is the same one used for the PC-to-PC experiments. Note that transmit on one end goes to receive on the other end. To test your RS-232 converter, use a wire to connect the PIC microcontroller transmit and receive terminals (Rlout and Tlin) on the converter board. With the converter board connected to the PC via cable, a character sent using the PC terminal program will (should) appear on screen as was the case with the "U-turn'1 experiment. Up to this point, we have discussed 2-way communication between a PC and a PIC microcon troller. The RS-232 converter is designed for 2-way communication. The experiments which follow are 1-way with the microcontroller transmitting information to the PC.
120
PIC MICROCONTROLLER-TO-PC SERIAL COMMUNICATION Next, we will get a PIC microcontroller to talk to a PC. We'll sec if the listener (PC) understood w'hat the talker (PIC microcontroller) said. The circuit for the experiments is:
SEND
RS-232 CONVERTER
RECEIVE
The PIC16F818 uses port A, bit 1 to transmit. For the purposes of this discussion, it is assumed that you will be using two PC's, one to develop code and program it into the PIC microcontroller using the ICD programmer/lCSP method and the other to display the results transmitted to it via RS-232. The procedure for firing-up the hardware and running the first example program is: 1) Powrer-up the PC running the CCS compiler and the device programmer. 2) Power-up the ICD programmer, the PIC microcontroller board and the RS-232 converter board. 3) Program the PIC 16F818. 4) Send switch open. 5) Bring the PIC 16F818 out of reset. 6) Power-up the PC that will receive the RS-232 communications from the PIC16F818. 7) Set up the HyperTerminal program as in previous examples (4800 baud). 8) Close send switch. 9) The character or string in the coming experiments should appear on the screen of the PC. To run the second and subsequent examples, life gets simpler. 1) 2) 3) 4) 5) 6) 7) 8)
Clear screen on the display PC. Send switch open. Hold the PIC16F818 in reset. Import the next .cof file. Program the device. Release the PIC 16F818 from reset. Close send switch. Look at the result on the display PC screen.
121
FORMATTING PIC MICROCONTROLLER DATA ON A PC SCREEN In the next chapter, you will learn about the printfQ built-in function which may be used to send ASCII alphanumeric characters to a PC for display on-screen. Three printf() escape sequences are useful for controlling the placement of ASCII alphanumeric characters on the screen of the PC as they are received. This is important because we want the information to be readable and also because we will want data to be formatted to be saved as a useful text file. The three printfQ escape sequences are:
New line Carriage return Horizontal tab
/n /r /t
(line feed)
As you probably already know, carriage return causes placement of characters on the screen to move to the extreme left side. Line feed causes characters to be placed on the next line down the screcn. Horizontal tab means tab over to the right. Theses terms come from the teletype days. The binary codes for these functions must be built into PIC microcontroller code and sent to the PC so that the data displayed will make sense to humans. Sample programs will illustrate how the printf() escape sequences work. ////escape sequence demo 1 /include #use delay (internal = 4mhz) #use rs232 (baud = 4800, xmit = PINAl) main()
Csl9a
{ while (input(PIN A2)==l); putc ('s'); printf ("C what happens!");
//go low? wait for ready switch to close //start here on-screen //send ASCII character string out a // serial port
while (TRUE);
} Result: sC wrhat happens! Notice that the "s" and "C" are run together. In the next example, we will use the \n escape sequence to put "C what happens" on a new line. Notice, also, that the #use delay() and #use rs232() built-in functions are needed. As used here, putcQ outputs a single ASCII character and printf() outputs a string of ASCII characters. They are built-in functions. Single quotes are used to indicate a single character which is defined in the putc() function. Quotation marks arc used to indicate a string of charac ters w'hich is defined in the printf() function.
122
////escape sequence demo 2 /include #use delay {internal = 4mhz) #use rs232 (baud = 4800, xmit = PIN A1) main()
Cs 19b
{ while (input(PINA2)==1); putc ('s'); printf ("\n"); printf ("C what happens!");
//go low? wait for ready switch to close //start here on-screen //new line //send ASCII character string out a // serial port
while (TRUE);
Result:
C what happens! "C what happens!" is on a new line with a blank space one character wide. Adding a carriage return escape sequence will cure that problem. ////escape sequence demo 3 /include /use delay (internal = 4mhz) /use rs232 (baud = 4800, xmit main()
Csl9c
PIN_A1)
{ while (input(PIN_A2)==1); putc ('s'); printf ("\n\r"); printf ("C what happens!");
//go low? wait for ready switch to close //start here on-screen //new line, carriage return //send ASCII character string out a // serial port
while (TRUE);
Result: s C what happens! That's better! Notice that the \n and \r are together (no comma).
123
Now let's try out the horizontal tab escape sequence. ////escape sequence demo 4 /include #use delay (internal = 4mhz) #use rs232 (baud = 4800, xmit = PIN A1) main()
Csl9d
{ while (input(PIN_A2)==1); putc (’s'); printf ("\n\r\t"); printf ("C what happens!"); while (TRUE);
Result: s C wrhat happens!
124
//go low? wait for ready switch to close //start here on-screen //new line, carriage return, horiz tab //send ASCII character string out a // serial port
STRINGS A "string" is a group of characters. C does not have a string data type (string of characters). String data is stored as one character per element in an array called a "string array". A string literal is enclosed in quotation marks. A string terminator tells the C compiler where the endvof the string is. It is called the null char acter or null zero and is added automatically by the compiler. You can't see it, but it is there. String length is the number of characters in the string including spaces and the null character. The null character must be included in the count even though it is not visible. Examples are: char msg[6] = "error" error has 5 characters Adding room for the null character makes 6 char alarm[15] = "smoke detected"; smoke = 5 characters space = 1 character detected = 8 characters Add 1 to make room for the null character Total = 15
The next example program sends an ASCII character to a PC via the serial port. This example is nearly the same as what was done in the previous chapter, but now the emphasis is on explaining strings.
SEND
RS-232 CONVERTER
RECEIVE
125
////character demo - rs232 /include #use delay (internal = 4mhz) #use rs232 (baud = 4800, xmit = PIN Al) main()
Cs20a
{ while (input(PIN_A2)==1); putc ('a'); while (TRUE);
//go low? wait for ready switch to close //send 'a' out a serial port
} Power-up with the switch open. When you are ready to send, close the switch. Sending data some time after power-up allows time for the serial connection to become stable. Notice that the #use delay() and #use rs232() built-in functions are needed. The next example program sends an ASCII character string to a PC via the serial port. The hardware and procedure are the same.
////string demo - rs232 /include /use delay (internal = 4mhz) /use rs232 (baud = 4800, xmit = PIN_A1) main( )
Cs20b
{ while (input(PINA2)==1); printf ("C what happens!");
//go low? wait for ready switch to close //send ASCII character string out a // serial port
while (TRUE);
This is a short introduction to strings. Manipulation of strings can become quite involved. The CCS compiler has 22 built-in functions for working with strings. For now, it is sufficient to be aware that these possibilities exist.
126
ARRAYS Arrays have "elements" and all of the elements are the same data type. Define array: data type const array name [size]; number of elements in array modifier or qualifier (if needed)
"const" is the constant qualifier. Use of const here will cause the constants to be placed in pro gram memory (ROM). Again, the elements in an array are all of one data type. The data type is specified in the array definition. Data types have corresponding array types. As an example, we can define an integer array, which we will call i a, and the initial values: int const i_a[4] = {1, 2, 3, 4};
4 elements
Note that the order is int const, not the reverse as in the CCS manual, i a[3] is the third element of the array which has a value of 4. The array name is the index to the first clement in the array. We can also declare an index to the array which will be useful in pointing to all elements in the array: int pi_a; //declare index
The compiler will know that pi_a is an index because when it is used, it is associated with the name of the array.
127
With an array and an index, we can: • Step through the array using the index. • Point to the nth element in the array. • Add an offset to the index. Examples will serve to illustrate. The index may be incremented by: pi_a++
//increments index pi_a to next element of array
We can step through array elements using this technique.
////array demo Cs2 la //// uses time delay via function call /include #use delay(internal=4mhz) //clock oscillator internal, frequency del ( ) //delay function
{ delay jus(500); return;
//delay 500 milliseconds
} main()
{ int const vals[4] = {0,1,2,3}; int pvals = 0; int i; output b (0x00); for (i=0; i main()
{ //4 MHz clock oscillator setuposcillator(OSC_4MHZ); DIV_128); //internal clock osc, setup_timer_0(RTCC_INTERNAL|RTCC //prescaler divide clock osc by 128 //all port B pins low outputb (0x00); //clear timer 0 interrupts clear interrupt (INTTIMERO); enableinterrupts (GLOBAL); //enable interrupts enable_interrupts (INT_TIMER0); //clear and start timer 0 settimerO(0); //LED on outputhigh(PINBO); while (TRUE);
165
Free Running Mode - Internal Clock We will need an external clock with a period of 0.1 second = 100 milliseconds for the example following this one. It makes sense to use a PIC microcontroller, don't you think? The time interval between toggle operations (period divided by 2) is roughly 1 microsecond per internal clock cycle times 2 (prescaler divide by 2) times 256 rollovers times 98 = 50,176 microseconds = 50 milliseconds = period -s- 2. Use internal clock divided by 2 and file register counter. Timer 0 increments to OxFF and rolls over. Interrupt is generated and file register used as a counter is incremented. When count reaches 98, port B, bit 0 is toggled. This occurs at one-half period intervals. Result is a square wave output with period = 100 milliseconds.
166
Main Program
Start Count
Interrupt Service Routine
////timer/counter demo I I I I free running 1111 internal clock + 2 1111 file register counter /include /fuses INTRC 10 int t = 0; /INT_TIMERO i_serv()
Cs26c
//declare t for counter //enable timer 0 interrupt //interrupt service function
{ t++; if (t==98)
//increment counter //time interval completed?
{ output_toggle(PINBO); t = 0;
//toggle port b, pin 0 //clear counter
} } main()
{ //4 MHz clock oscillator setup_oscillator(OSC 4MHZ); setup_timer_0(RTCC INTERNAL|RTCC DIV_2); //internal clock osc, //prescaler divide clock osc by 2 output_b (0x00); //all port B pins low clear interrupt (INT_TIMER0); //clear timer 0 interrupts enable_interrupts (GLOBAL); //enable interrupts enable interrupts (INT_TIMER0); set_timer0(0); //clear and start timer 0 while (TRUE);
To observe the square wave output on port B, pin 0, you will need an oscilloscope.
168
Single Time Interval - External Clock Use external 0.1 second clock (another PIC microcontroller running the code in the previous example). Square wave input - increment counter on rising edge (low to high transition). Bypass prescaler. Blink an LED once. Note: It takes about 25.6 seconds for the LED to turn off, so wait patiently! 256 clock pulses are needed to overflow timer 0.
Main Program
L to H Rising Edge
Start Count
Interrupt Service Routine
169
////timer/counter demo ala pictl7.asm 1111 single time interval I I 1 1 external clock, bypass prescaler 1111 blink LED once /include /fuses INTRC 10 /INT_TIMERO //enable timer 0 interrupt i_serv() //interrupt service function
Cs26d
{ output_low(PIN_BO); //LED off disable_interrupts (INT_TIMERO); //disable timer 0 interrupt
} main( )
{ setup_oscillator(0SC4MHZ); //4 MHz clock oscillator setup_timer_0(RTCC_EXT L_T0_H|RTCC_DIV 1); //external clock osc, low to hi //prescaler bypassed output_b (0x00); //all port B pins low //clear timer 0 interrupts clear_interrupt (INT TIMERO); //enable interrupts enable_interrupts (GLOBAL); enable_interrupts (INTTIMERO); //clear and start timer 0 set_timerO(0); outputhigh(PINBO); //LED on while (TRUE);
Free Running Mode - Internal Clock Use internal clock divided by 128. Output to port B, bit 0. Interrupts are used. The microcontroller is free to do other things when not servicing interrupts (not done in this example).
170
Main Program
Interrupt Service Routine Start Count
171
////timer/counter demo I I I I free running 1111 internal clock -j- 128 1111 10 counts to overflow /include /fuses INTRC 10 /INT_TIMERO i_serv()
ala pict 20.asm
Cs26e
//enable timer 0 interrupt //interrupt service function
{ output toggle(PIN_B0); settimerO(Oxf6);
//toggle LED //load timer 10 coynts (decimal) to // rollover
> main()
{ setup_oscillator(0SC4MHZ); //4 MHz clock oscillator setup_timer_0(RTCC_INTERNAL|RTCC DIV_128); //internal clock osc, //prescaler divide clock osc by 128 output_b (0x00); //all port B pins low clear_interrupt (INT TIMER0); //clear timer 0 interrupts enable_interrupts (GLOBAL); //enable interrupts enable_interrupts (INTTIMERO); while (TRUE);
Run the program and look at port B, bit 0 with a scope. Examples: ■ Load 0xF6, prescaler + 128 (10 counts to overflow) l.usec x 128/count x 10 = 1.2 8 msec
This is the time between each HI/LO or LO/HI transition at the port line. The time to execute the interrupt service routine adds to this slightly.
172
Load 0x00, prescaler + 128 0x00 = 256 decimal Counts to overflow
128 ^.sec x 256 = 33 msec
Load 0x00, prescaler bypassed (-^1) 1 j.isec x 256 = 256+ (.isec (no allowance for program overhead)
Load 0x40, prescaler -4- 2 (192 counts to overflow) 1 (.isec x 192 x 2 = 384+ (.isec (no allowance for program overhead)
384+ usee
Counting Events (Pulses) Use the pulser described in Appendix A as a source of negative-going pulses. The negativegoing pulses will increment the counter on the falling edge (high to low transition).
174
////event counting demo /include /fuses INTRC_IO /byte portb = 0x06 /byte timerO = 0x01 main()
ala pict21.asm
Cs26f
// port B address
{ setup_timer 0(RTCCEXT_H_TO_L|RTCC_DIV_1); //external pulses, //prescaler 1 = bypass output_b (0x00); //all port B pins low set_timer0(0); //clear and start timer 0 while (input(PINA0)==0); //wait for switch to open portb = timerO; //port B = timer 0 while (TRUE);
1). Power-up with switch closed. • Open switch - all LEDs should he off. 2). Power-up with switch closed. • Pulse X (few) times. • Open switch. LEDs display pulse count X.
GOING FURTHER Wouldn't it be nice if our timer/counter could count beyond 255! A 16-bit timer counter known as Timer 1 (TMR1) is available in many of the PIC devices. It can count up to 65,535. TMR1 is usually accompanied by an 8-bit timer/counter called Timer 2 (TMR2) and a capture/compare/pulse width modulation module (CCP) which makes a lot of very useful appli cations relatively easy to implement. How-to information using assembly language is contained in our book entitled Time'n and Count'n.
175
ANALOG TO DIGITAL CONVERSION Analog to digital (A/D) conversion is essential to using PIC microcontrollers because they can only process digital information. Analog signals, usually voltages from sensors, must be con verted to binary numbers digestible by the PIC microcontroller. As usual, this may be done by one of several methods with the usual cost/accuracy/resolution/PCB in2/etc. tradeoffs to be made. V
The PIC16F818 has 5 pins which may (or may not) be used as A/D channels. These are port A, bits 4,3,2,1,0. The five analog inputs are multiplexed into one sample and hold circuit. The out put of the sample and hold is the input to a successive approximation converter The reference voltage may be the logic supply (5 volt for our example) to the PIC16F818 (range 0-5V) or an external reference via pins RA2 and RA3. If an external reference is used, only 4 A/D channels are available. The intricacies of using an external voltage reference are beyond the scope of this book. Important electrical specs are:
vain
0 to 5V if Vre£ = 5V logic supply Vref 5V logic supply for this example Maximum source impedance 2.5K
A pre-processor directive and four built-in functions are used to control the A/D conversion process: • #dcvice with the chip option ADC=x determines whether the A/D conversion result is 8 or 10 bits. 8-bit mode is the default. • setup adc {mode) where mode options are device dependent and include things like A/D off and conversion clock speed (conversion sample time). • setup adc ports (value) determines which pins having analog capability are actually used for A/D in the application. • set adc channel (chan) determines which A/D channel will be read next. • read_adc ([mode]) controls the conversion proccss. Details are in the CCS compiler manual. The options for each built-in function are in the device .h file (PIC16F818) for the example which follows.
176
A simple example follows which uses one A/D channel (ANO) to measure the voltage on the wiper of a potentiometer, gives an 8-bit result, and displays the least significant 6 bits of the result via 6 LEDs. The voltage is measured once every 200 milliseconds.
+5VDC
177
////A/D test /include /device ADC=8 /use delay (internal=4mhz) main()
Cs27 //A/D read returns 8 bits //clock oscillator internal, frequency
{ byte result; setup adc(ADC_CLOCK_DIV_32); setup_adc_ports (ANO); set_adc_channel (0); delay us(10 ) ; read do
//declare variable result (a byte) //A/D - clock divided by 32 //use analog channel 0 //prepare to read analog channel 0 //short delay between select channel &
{ result = read_adc(); output_b (result); delay_ms(2 00);
//start and read A/D //bits to port ^ //delay between reads
} while (TRUE);
} For this example, notice: • A pre-processor directive is used to specify that the result is to be 8 bits. 8-bit A/D is the default. It is specified here to make you aware of what is taking place. An 8-bit result provides 256 possibilities. • A pre-processor directive is used to: - Select the internal clock oscillator - Select the frequency for time delay purposes. • For A/D conversion, the clock oscillator frequency is divided by 32 as we are not in a hurry and doing so will avoid some timing issues. • A pin used as an analog channel must be an input pin (taken care of by the compiler). • A time delay is used between selecting the A/D channel to be read and the first reading of the A/D so as to conform to A/D use rules as spelled out in the PIC16F818 Data Sheet. • Comments in the code provide the rest. Allow the devicc to come out of reset and observe the LEDs as you turn the potentiometer shaft. The count read from the A/D converter is displayed in binary (least significant 6 bits).
178
INSERTING ASSEMBLY CODE IN C CODE For those of you who have experience with PIC assembly language, it may be useful to insert some assembly code in a C program that you are writing. The most common reason for doing this is to optimize a situation where timing is critical. If you have a really neat trick that you have created in assembly language and have not figured out a way to do it in C, or think it can't be done in C, there is a solution. Two pre-processor directives are used. • #asm • #endasm
The code between the directives is treated as assembly code by the compiler. A very simple example follows:
////assembler in C program /include /fuses INTRC_IO /byte portb = 0x06 main()
ala pictl.asm
Cs28
//port B address
{ set_tris_b (0x00); /asm movlw OxOf movwf portb /endasm while (TRUE);
//port B outputs
//bit pattern to port B //circle, always
} Note that the portb identifier/label works in both C and assembly.
179
APPENDIX A - PULSER It is easy to build a simple pulser circuit which provides both positive-going and negative-going pulse outputs. The circuit is built around a 74HC14 hex Schmitt trigger inverter IC and a single pole, single throw momentary contact toggle switch. The switch is spring-loaded to the normal ly closed position. Pushing the switch lever and releasing it results in one pulse being generated. Either the positive-going or negative-going output is connected to the PIC microcontroller cir cuit being tested as determined by the application. The debouncing circuit is followed by a resistor and capacitor which function as differentiator creating a narrow pulse of 10 or more microseconds duration. The circuit can be constructed on a solderless breadboard or constructed using a more permanent method of your choosing.
PULSER CIRCUIT
Contact Switch
180
74HC14
APPENDIX B - SOURCES CCS, Inc.
P.O. Box 2452 Brookfield, WI 53008 Sales 262 522 6500 ext. 35 Tech Support 262 522 6500 ext. 32 FAX 262 522 6504 Web www.ccsinfo.com/picc email
[email protected] Digi-Key
701 Brooks Avenue South Thief River Falls, MN 56701-0677 Tel 800 344 4539 Web http://www.digikey.com Jameco Electronics
1355 Shoreway Road Belmont CA 94002-4100 Tel 800 831 4242 Fax 800 237 6948 Web http://www.jameco.com email
[email protected] Marlin P. Jones & Assoc Inc
C Compilers Development Systems
Electronic Components PIC Microcontrollers
Electronic Components PIC Microcontrollers
Electronic Components
P.O. Box 12685 Lake Park FL 33403 Tel 800 652 6733 Fax 800 432 9937 Order Online http://www.mpja.com email
[email protected] Microchip Technology Inc.
2355 W. Chandler Blvd. Chandler AZ 85224 Tel 480 792 7200 Web http://www.microchip.com
PIC Microcontrollers PIC Programmer Development Systems In-Circuit Debuggers
181
APPENDIX C HEXADECIMAL NUMBERS Hexadecimal Binary Decimal
0 1 2 3 4 5 6 7 8 9 A B C D E F
0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
APPENDIX D PROGRAM LISTINGS vs. PAGE NUMBER
Program Number
Page Number
Program Number
Page Number
Csla Cslb Cs2a Cs2b Cs2c Cs2d Cs2e Cs2f Cs3 Cs4 Cs5 Cs6 Cs7a Cs7b Cs8a Cs8b Cs9a Cs9b CslOa CslOb Csl 1 Csl2 Cs 13 Cs 14 Csl5 Cs 16 Csl7a Csl7b Csl7c Csl7d Csl8 Csl9a Csl9b Csl9c Csl9d
34,73 74 75 77 78 79 80 81 83 85 87 88 90 91 92 93 95 96 97 97 99 101 101 103 105 106 108 109 109 110 112 122 123 123 124
Cs20a Cs20b Cs2 la Cs2 lb Cs2 lc Cs2 Id Cs22a Cs22b Cs22 c Cs23a Cs23b Cs23c Cs2 3d Cs2 4a Cs24b Cs2 4c Cs25 Cs26a Cs26b Cs26c Cs26d Cs26e Cs26f Cs2 7 Cs2 8
126 126 128 129 130 132 136 138 139 142 144 145 145 146 147 148 157 163 165 168 170 172 175 178 179
183
4