You are on page 1of 252

Microtronics Pakistan

Invent FutureProgramming / 1
Beginning PIC Microcontroller

Learn By Doing: Less Theory More Practical

Lets Begin
Microcontroller Programming
Using PIC Microcontrollers

Amer Iqbal Qureshi

Microtronics Pakistan
www.electronicspk.com
Beginning PIC Microcontroller Programming / 2

Preface

L
earning electronics has been my passion ever since I was i high school. It
was always a fun seeing my project coming to life. Only a passionate hob-
byist can appreciate the feeling, jubilation and sense of pride one feels
when the LEDs turn ON. A wonderful sight nothing is comparable with the
first glow of LEDs. Things kept on progressing, early experiments turned into more complex and more
complicated ones, but one thing remains the same Yes its working man !.
Professionally I am cardiac surgeon and an electronics hobbyist. Therefore I am fully aware of the needs of
a hobbyist. Most hobbyists are not technically sound people. They just love doing electronics. They have
expertise in their own fields, but a passion to see electronics work. This book has been written therefore
from this point of view. It will concentrate more on practical things than going into theoretical details.
However I feel one should know what's happening behind the scenes. So a reasonable time will also be
spent on understanding basic theory as well.
Although this book is about learning microcontroller programming , and not about electronics, yet I feel it
would be nice to have an overview of little electronics as related to microcontrollers projects as well. Pro-
gramming a microcontroller is not much difficult job. However getting a project work is somewhat labori-
ous. Therefore one needs to know and learn little bit of electronics as well.
My passion has always been to help others learn whatever Allah has blessed me with. A number of texts
exist for experienced and professional people, yet I Always think there is a need for absolute beginner. Its
the beginning that is most difficult. Thats why cars have maximum engine resources available in first gear
when it has to take a start. Once things start rolling pervious experiences tend to facilitate more learning.
As a hobbyist I would say, I have learnt maximum by doing wrongs. So do not worry if the project is not
working, its blessing indeed, that nature wants you to try 100 different things that you would normally ig-
nore. The key to learning is Persistence.
So I conclude here with the pray to Almighty Allah, that please help me transfer whatever I have to those
who have the desire to learn (Amin).

Dr. Amer Iqbal


ameriqbalqureshi@yahoo.com
www.electronicspk.com
Beginning PIC Microcontroller Programming / 3

Table of Contents
Introduction to Microcontrollers and Control Systems 4

8
Microchip PIC Microcontrollers
11
Setup Your Personal Workbench
16
A Brief Tour of MikroBasic
26
MikroBasic Programming Language
32
Hello World
Understanding I-O Ports and Special Function Registers 38
Control Structures Loops and Decisions 42
Connecting 50
Output and Input Devices
Using Push Switches 57
Character LCD Display 63
Seven Segment LED Display 77
USART 84
Universal Asynchronous
Receiver and Transmitter
Dealing With Analog Data 99
Graphic LCD and Touch Screen 112
Using Numeric Keypad 119
Producing Sound 129
Pulse Width Modulation 133
I2C Communication EEPROM 144
I2C Communication DS1307 Real Time Clock 152
Interrupts and Timers 158
Motor Control, DC Motor, Stepper and Servo 170
LED Matrix Displays 190
Infra Red Communication and Remote Controls 195
SPI - Serial Parallel Interface 211
RS485 Long Range Serial Communication 218
Dallas One Wire Protocol 230
USB - Universal Serial Bus 244
Beginning PIC Microcontroller Programming / 4

Introduction to
1 Microcontrollers

E ver since man has started interacting with his environment there has been one goal Control. Its
been the basic nature of man to control his environment, things around him and even nature. By
control he means getting something useful out of what was not useful to him. This very nature persists and
is the basis of development. All research may it be biological, physical or chemical is to know the vary na-
ture of things and then to find ways to control it.
By definition control means we should be able to command it.
The very particular thing should respond to our requirements.
When talking about microcontrollers the same philosophy
applies. We want to control the flow of electron, a very sim-
ple desire. Our scientists and engineers designed electronics
components like resistors, conductors, transistors and so on to
make this happen. It has been customary to make devices us-
ing these discreet components. However the demand to con-
trol went on increasing and when logic got involved designing
a control system just by discreet components became really
difficult. It was here that the need of a microcontroller felt.
In fact before the advent of microcontroller, computer in some
form was already invented. So there was already a system to solve the problems using a set of instructions,
a program. The control systems were separate entity used mainly in industry where mechanical jobs were to
be controlled, like automatically packing the products, monitoring the tension of a thread in textile etc. The
merger of computer and these control systems resulted in what we today know as micro-controller.
So microcontroller in fact is a complete computer along with various other devices necessary for a control
system integrated on the same chip. Microcontrollers are used in automatically controlled products and de-
vices, such as automobile engine control systems, implantable medical devices, remote controls, office ma-
chines, appliances, power tools, and toys. By reducing the size and cost compared to a design that uses a
separate microprocessor, memory, and input/output devices, microcontrollers make it economical to digi-
tally control even more devices and processes.
What is the difference between a microprocessor and a microcontroller?
Well this is an important question that needs to be answered in the beginning. Truly speaking both can be
considered almost same. However there are slight differences in philosophy. A microprocessor has a central
processing unit (CPU) and a system to connect this CPU to the outside world. In order for this CPU to work
it needs a program. This program must be stored somewhere. Usually it is loaded from an external storage
medium into an electronic memory. The microprocessor system must have an external memory where not
only program can be stored, but also intermediate results of processing be stored. The microprocessor also
needs to have a system of devices that are responsible for getting data from outside world and present data
from processor to outside world. This kind of arrangement makes the system highly flexible and adaptable.
Just consider your personal computer. You have the choice to configure it in a number of ways. You can
add more memory, change hard disk type, have a CD or DVD ROM, many different types of input devices
and so on. You also have the liberty to run a variety of programs at your will. At one time you are listening
to music and at other time working with your spreadsheet. So microprocessors are used where you want
flexibility and freedom.
Microcontrollers on the other-hand are designed to work in a very narrow spectrum of job. Once pro-
Beginning PIC Microcontroller Programming / 5

grammed for a particular job, it is not supposed to do another in a given scenario. Thus a microcontroller
needs to have a precisely defined job. Second objective of microcontroller usage was to reduce the external
circuitry. It was therefore decided that everything that is required to make a microcontroller work should be
integrated within the same integrated circuit. The microcontroller therefore has a CPU, program memory,
working memory, extra storage memory etc. In addition to that the other commonly required features or
modules like Analog to digital conversion, serial communication, timers etc are also built into the same
chip. Microcontroller therefore is a complete computer in itself. Although not as robust as your PC, but still
its complete. Many a times these microcontrollers are also called One-Chip-Computers. Although you can
say to some extent that we can program a microcontroller to do any job, like driving an LCD display, con-
trolling a motor, sensing a temperature sensor and so on, why cant we call it a general purpose small scaled
computer?
Yes you are right, you can make this tiny computer do a lot many functions and some times all together.
Like you can setup a system where temperature is sensed, displayed on an LCD display and turns a fan ON
or OFF based upon set temperature. Precisely speaking when we say microcontrollers are not general pur-
pose, we mean, when a particular hardware is designed, lets say the above example, and a microcontroller
has been appropriately programmed to handle the job. Now that particular controller is going to stay there
and function like that only. No body would love to program the same programmer to transmit the data on
serial port, as the particular hardware has no serial connection.
So hardware design and microcontroller program are made for each other. The hardware is designed ac-
cording to a particular microcontroller in mind, and microcontroller is programmed to control the particular
hardware.
Why are there so many different kinds of microcontrollers?
Yes this is most relevant question that can and should arise in your
mind. Truly speaking there is not much difference. I frequently
quote an example of cars. You may phrase the same question, as
"Why are there so many different kinds of cars, or automobiles?"
Try to answer this question yourself, or ask your friend. The an-
swer you get is 100% true and applicable to microcontrollers.
Just like there are many different manufacturers of cars, they have
different internal architectures, and core engine issues, but all have
same basic structure. After-all they are all run on gasoline. Still
they have something their own. But a few things are always same.
they all have similar gearing system, similar ignition system, simi-
lar steering wheel, accelerator and brakes paddle and they function
exactly the same way. From a users perspective there is not much difference. Thus if you ignore what's
inside and learn to drive a Mercedes there are bright chances you will be able to drive a Toyota with same
confidence. Except for small differences like position of radio, the look and feel of your dash-board every-
thing is same.
Same is the case with microcontrollers. There are a number of manufacturers, ATMEL and Microchip for
example. If you have the core idea of one you can easily switch to another, believe me its that easy. So its
decided that for our purposes we do not need to get our lives complicated by the issue where to start? They
are all same, with slight differences in flavor.
Why are there so many different microcontrollers even from the same manufacturer?
Humm, well again a very logical query. If the microntrollers differ among manufacturers do they also differ
if from same manufacturer? Again to solve this question lets frame it around our automobiles example.
Toyota for example manufactures automobiles from small 'student cars' to huge trucks. All having same
architectural plan, but designed from different usage perspective. Student car has smaller engine, low lux-
ury but cost effective. Family cars are more capacious slightly more powerful engine, have bigger trunk,
and lots of luxuries like air conditioning, music system etc. The truck needs engine power, hydraulic system
for unloading loads but no luxury at all.
Same is true about microcontrollers from the same manufacturer. Since a microcontroller is going to be
Beginning PIC Microcontroller Programming / 6

used for a specific job when the project is finalized. It may or may not need every possible facility. The
manufacturers therefore make these various devices to help you select the one that best suits your require-
ments. Conceptually and from the using point of view they are almost same. In a hierarchy the controllers
with low pin count and smaller number of resources are compatible with higher processors. Thus if you
experiment a prototype with a reasonably powerful processor, and your project is only using a few LED
indicators and a serial communication. The final device will use a controller with low pin counts and
smaller number of peripherals. The programming technique and commands will almost remain same.
I hope I made my point clear. If you learn one microcontroller, switching to another from same manufac-
turer involves only very small re-learning. You need to learn only the modules that are different. A USART
(serial module) in 14 pin microcontroller is same as in 40 pin bigger controller. Another major difference is
in the amount of memory available. so when your project is finalized on a prototype you can inspect your
final program and decide which particular microcontroller from this family will be best suited. There are
usually two criteria to affect this decision, 1: Price 2: Size both of these affect the final commercial product.
If this is not the issue you can continue with whatever is available.
Is it Possible to have more than one microcontrollers in a project?
Absolutely yes. Indeed complex projects have various modules, and each module having its own microcon-
troller. In order to create harmony among these modules the modules are connected with each other as well
so that microcontrollers communicate among themselves as well. An example is an automatic car. Modern
automatic cars have about 40 microcontrollers in it. Some for engine, some for breaks other for windows
etc.
Lets re-cap what we have learned for about microcontroller.
1. It is an integrated circuit (IC) that is available in various sizes and packages
2. It is programmable, without a program it has no function assigned to it
3. It has various modules integrated into it, the type and number varies with the microcontroller type
4. Most of the processes are either same or similar, so if you master one microcontroller its easy to switch
5. Microcontrollers are able to control other devices through logical signals, but do not have enough
power to drive them directly. They are controllers not drivers.
6. In a given application the microcontroller will continue to work on a pre-defined path and they are not
meant to be programmed to perform a large variety of tasks
7. Many circuits can still be made using specialized discreet ICs, however using microcontroller instead
would greatly reduce the component count, and made it extremely easy to change design.

A brief history, how microcontrollers were developed.


In the year 1969, a team of Japanese engineers from BUSICOM com-
pany came to the USA with a request that a few integrated circuits for
calculators were to be designed according to their projects. The request
was set to INTEL company , Marcian Hoff was in charge of the pro-
ject there. Since having been experienced in working with a computer
PDP8, he came to an idea to suggest fundamentally different solution
instead of the suggested design. That solution presumed that the opera-
tion of integrated circuit was to be determined by the program stored
in the circuit itself. It meant that configuration would be simpler, but it
would require far more memory than the project proposed by Japanese
engineers.
After a while, even though the Japanese engineers were trying to find
an easier solution, Marcians idea won and the first microprocessor
was born. A major help with turning an idea into a ready-to-use prod-
Beginning PIC Microcontroller Programming / 7

uct, Intel got from Federico Faggin. Nine months after his arrival
to Intel he succeeded in developing such a product from its origi-
nal concept. In 1971 Intel obtained the right to sell this integrated
circuit. Before that Intel bought the license from BUSICOM
company which had no idea what a treasure it had. During that
year, a microprocessor called the 4004 appeared on the market.
That was the first 4-bit microprocessor with the speed of 6000
operations per second. Not long after that, American company
CTC requested from Intel and Texas Instruments to manufacture
8-bit microprocessor to be applied in terminals. Even though
CTC gave up this project at last, Intel and Texas Instruments
kept working on the microprocessor and in April 1972 the first 8-
bit microprocessor called the 8008 appeared on the market. It
was able to address 16Kb of memory, had 45 instructions and the
speed of 300,000 operations per second. That microprocessor
was the predecessor of all todays microprocessors. Intel kept on developing it and in April 1974 it
launched 8-bit processor called the 8080. It was able to address 64Kb of memory, had 75 instructions and
initial price was $360.
In another American company called Motorola, they quickly realized what was going on, so they launched
8-bit microprocessor 6800. Chief constructor was Chuck Peddle. Apart from the processor itself, Motorola
was the first company that also manufactured other peripherals such as 6820 and 6850. At that time many
companies recognized greater importance of microprocessors and began their own development. Chuck
Peddle left Motorola to join MOS Technology and kept working intensively on developing microproces-
sors.
At the WESCON exhibition in the USA in 1975, a crucial event in the history of the microprocessors took
place. MOS Technology announced that it was selling processors 6501 and 6502 at $25 each, which inter-
ested customers could purchase immediately. That was such sensation that many thought it was a kind of
fraud, considering that competing companies were selling the 8080 and 6800 at $179 each. On the first day
of exhibit, in response to the competitor, both Motorola and Intel cut the prices of their microprocessors to
$69.95. Motorola accused MOS Technology and Chuck Peddle of plagiarizing the protected 6800. Because
of that, MOS Technology gave up further manufacture of the 6501, but kept manufacturing the 6502. It was
8-bit microprocessor with 56 instructions and ability to directly address 64Kb of memory. Due to low price,
6502 became very popular so it was installed into computers such as KIM-1, Apple I, Apple II, Atari, Com-
modore, Acorn, Oric, Galeb, Orao, Ultra and many others. Soon appeared several companies manufacturing
the 6502 (Rockwell, Sznertek, GTE, NCR, Ricoh, Commodore took over MOS Technology). In the year of
its prosperity 1982, this processor was being sold at a rate of 15 million processors per year!
Other companies did not want to give up either. Frederico Faggin left Intel and started his own company
Zilog Inc. In 1976 Zilog announced the Z80. When designing this microprocessor Faggin made the crucial
decision. Having been familiar with the fact that for 8080 had already been developed he realized that many
would remain loyal to that processor because of great expenditure which rewriting of all the programs
would result in. Accordingly he decided that a new processor had to be compatible with the 8080, i.e. it had
to be able to perform all the programs written for the 8080. Apart from that, many other features have been
added so that the Z80 was the most powerful microprocessor at that time. It was able to directly address
64Kb of memory, had 176 instructions, a large number of registers, built in option for refreshing dynamic
RAM memory, single power supply, greater operating speed etc. The Z80 was a great success and every-
body replaced the 8080 by the Z80. Certainly the Z80 was commercially the most successful 8-bit micro-
processor at that time. Besides Zilog, other new manufacturers such as Mostek, NEC, SHARP and SGS
appeared soon. The Z80 was the heart of many computers such as: Spectrum, Partner, TRS703, Z-3 and
Galaxy.
In 1976 Intel came up with an upgraded version of 8-bit microprocessor called the 8085. However, the Z80
was so much better that Intel lost the battle. Even though a few more microprocessors appeared later on the
market (6809, 2650, SC/MP etc.), everything was actually decided. There were no such great improvements
which could make manufacturers to change their mind, so the 6502 and Z80 along with the 6800 remained
chief representatives of the 8-bit microprocessors of that time.
Beginning PIC Microcontroller Programming / 8

Microchip PIC
2 Microcontrollers

A mong a large number of companies manufacturing microcon-


trollers Microchip is relatively young, yet proven its worth.
Although microcontrollers were being developed since early 1970s real
boom came in mid 1990s. A company named Microchip made its first
simple microcontroller, which they called PIC. Originally this was de-
veloped as a supporting device for PDP computers to control its periph-
eral devices, and therefore named as PIC, Peripheral Interface Controller. Thus all the chips developed by
Microchip have been named as a class by themselves and called PIC.
A large number of microcontroller designs are available from microchip. Depending upon the architecture,
memory layout and processing power. They have been classified as low, mid and high range microcontrol-
lers.
The beauty of these devices is their easy availability, low cost and easy programming and handling. This
has made PIC microcontrollers as the apple of hobbyists and students eyes. We shall be talking about mid-
range PIC microcontrollers, and use PIC18F452 as a prototype in this book to explore them. Knowledge
gained by learning and exploring one microcontroller is almost 90% applicable on other microcontrollers of
the same family. The only difference is in availability of resources on different chips. We shall shift to other
microcontrollers where a particular feature is required like USB devices.

General Layout of PIC Microcontrollers


When we talk about discreet components it is cus-
tomary to talk about the pin numbers. Most of you
who have experienced working with various inte-
grated circuits know that most schematics show
connection details in terms of pin number of an IC.
That is also true to some extent when we talk about
microcontrollers. However it is more customary to
talk about Pin-Names instead of numbers. Since the
names tend to remain the same in many different
microcontrollers from the same manufacturer it be-
comes extremely easy to adapt from one controller
to another.
Functional Compatibility
As you can see the pins shown here have various symbols assigned to them, separated by /. These abbre-
viations are pin names and correspond to the specific function of the module inside to which they are at-
tached. Note each pin has multiple associations, like pin 26 is RC7/RX/DT. It means the pin can assume
three different types of functions. However at any given time, or in any given project the pin is set to as-
sume any one of them. This is simply done during programming by setting various special function regis-
ters. Generally speaking when we talk about a pin in PIC we use its common name, and that is the one
which is written first for example RB0, RB1, RC6 etc. Another beautiful thing about this naming conven-
tion is that since most microcontrollers from PIC share similar modules, so they tend to have almost same
names. The exact pin number might be different, but functionally they tend to behave same. As an example
look at the pin-outs of an 18 pin PIC microcontroller. You can see this microntrollers has RB0 to RB7 pins,
which are similar to those in 18F452. however pin numbers are different.
Beginning PIC Microcontroller Programming / 9

Therefore when making a project the discussion says you have


to connect an LED to RB4. This should mean pin 10 in case of
16F84 and pin 37 in case of 18F452. Functionally both will be
same. Note simpler design of 16F84, as most of pins have sin-
gle function. This means this microcontroller does not have
many modules inside.
Since functions tend to repeat in all processors from Micro-
chip. Learning them facilitates working with higher processors.
In next higher processor you have to learn only whats new.
Pin Compatibility
As far as pin counts of microcontroller is concerned you will find many different models with same pin
counts. For example 16F84 is an 18 pin PIC mi-
crocontroller, so is 16F628A and 16F819 and
many others too. Being different processors they
definitely have differences in the available mem-
ory, additional storage and number and type of
peripheral device modules like Timers etc. a look
at their Pin arrangement will reveal that the pins
with same names are located in same position.
Such microcontroller are therefore called pin-
compatible. You can easily replace one for an-
other in the same hardware, without any connection changes and enjoy the powers of a better processor if
required. For example you started a project and designed the hardware, for 16F84 microcontroller with 1K
program memory. Initially the project went smoothly, but as it grew in complexity the 1K memory was not
sufficient. So you can replace it with 16F628A having 2K memory and same pin layout. Of-course you will
need to recompile the code for 16F628A but the beauty is you do not need to modify the hardware.
How PIC Microcontrollers are Numbered (Named).
This is interesting to note that all microcontrollers from Microchip have PIC as part of their name. the
next 2 digits indicate the family or series. We shall talk about this later. Then comes the letter F. This
stands for Flash. An F indicates that this microcontroller has flash memory and it can be erased and re-
programmed many thousand times. The other types have C in this location. These microcontrollers are
one-time programmable. Next two or three digits are the model number. Sometimes the have a post-fix of
letter A like 16F628A the models with A postfix are revised versions and are preferred over their non-A
versions.
Microcontroller Instruction Set
You will come across various computer and electronics geeks talking about instruction sets and speaking a
lot of unfamiliar words. Do not be confused and disappointed on hearing those. Truly speaking every mi-
croprocessor has a core language called Assembly Language. Microprocessor understands only numbers,
and various basic actins like transferring a byte from one memory location to another, adding two integer
numbers or comparing two memory locations. These commands are called the basic instruction set of a mi-
crocontroller. Having more possible commands means more liberty to play with, but this also increases the
complexity of processor itself. The instruction set of Microchip PIC microcontrollers varies from 35 in-
structions for low end controllers to over 80 instructions for high end controllers.
Do we really Need to Know These Commands?
I would say No and yes. As a beginner and hobbyist you will almost never need to talk to the microcontrol-
ler in these commands. It will be your compiler that will do this job. So you will need to know the com-
mands your compiler gives, and do not need to worry about these low level, controller commands. However
when you progress and become a professional a knowledge of these underlying commands is helpful. Occa-
sionally you may need to bypass the compiler generated instructions and write a part of your application in
assembly to give more speed.
Beginning PIC Microcontroller Programming / 10

What are RISC Computers.


RISC stands for Reduced Instruction Set Computers. Although having more instructions in the core instruc-
tion set gives more liberty and power, yet it also complicates the controller architecture. It was observed
that many of the instructions available in the instruction set are not very frequently used, and their function
can be achieved by a combination of other instructions. For example consider multiplication. Multiplying a
number by say 40 can be achieved by adding the same number to itself 40 times. Thus eliminating need for
multiplication instruction and reducing controller complexity.
More and more processors were then developed using this philosophy to reduce the instruction set and
therefore reduce the complexity of processor. This has resulted in rather more efficient, faster and economi-
cally cheaper processing power.
This became more relevant to microcontrollers where it was supposed to look-after simple tasks and did not
require very powerful instruction set.
PIC Microcontroller Families
Microchip manufactures microcontrollers for a wide spectrum of applications. There are controllers requir-
ing very little processing powers, then there are mid-range processors and finally digital signal processing
controllers for processor intensive applications. As already said all have similar plans, and know one family
facilitates a project with another family.
Although you have to see the microchip site and study appropriate data sheets, a rule of thumb is that PIC
12FXXX series are low end controllers, 16FXXX are Mid range with 14 bit program memory, and
18FXXX High end with 16 bit memory. 24FXXX and 32FXXX are 24 bit and 32 bit processors for proces-
sor intensive functions.
For beginners I would suggest start with 16F628A and progress to 18F452. The figure below shows the
hierarchy of various PIC families.
Beginning PIC Microcontroller Programming / 11

Setup Your Personal Electronics


3 Workbench

N
ow that you have a basic understanding, although a lot remains to
be said about PIC microcontroller, I think it would be wise to
discuss all those things where they are addressed or used. I per-
sonally believe there is only way of perfect learning and that is
Learn By Doing. There is not alternate to this statement, rather I shall ex-
tend it by Do It Yourself . Therefore if you are really interested in learning
these beasts, roll your sleeves and setup your own workbench. Most hobby-
ists and students have already a place in home, where they can spend hours
and hours with their gadgets. In this section we shall talk about the basic
setup that you must have. Its not hard and fast rule to have everything as I
mention, you can modify your working environment as well as gadgets to
suit your needs. I would recommend you to go through a very nice text,
Electronics for Dummies .
I shall not talk about the bench itself, and the qualities it should have. All you would need is a table, a per-
sonal desktop type computer and a few tools. Desktop computer, because they are rather cheap, easily
available, and even an older Pentium 4 will work fine. More so because they have Hardware serial ports
which are more suitable for cheaper student type programmers and for establishing serial communication
with microcontrollers.
You should have a minimum of following hardware to get started:
Project / Bread Board.
This is also called solder-less board. You can find a
number of them in different sizes available in local
market and electronics hobbyists shops. The beauty
of this board is that it can be used again and again
for various projects. Components can be easily
plugged into the holes and various connections
made using jumper wires. You can have multiple
such boards and pre-made common circuits on them
so that you do not have to made them again and
again. The jumper wires you use should be little stiff
and single wire, instead of twisted wires. It is easier
to insert the rather stiff single wire into the holes.
The top and bottom rails are connected horizontally
and are used for power supply. The rest if holes are connected together vertically making columns of inter
connected holes. See http://en.wikipedia.org/wiki/Breadboard for details about using a breadboard.
Digital Multi-Meter
A digital multi-meter is mandatory for any electronics lab. This meter has three measuring systems in it. A
voltmeter to measure the AC and DC Volts, an Ampere meter to measure the flowing current and an Ohm
meter to measure the resistance. See http://en.wikipedia.org/wiki/Multimeter for details about using a multi
-meter. You will find a number of simple and advanced multi-meters in market. To begin with get the sim-
ple one, There is no need of other functions like pulse generator or frequency measurements for our pur-
pose.
Beginning PIC Microcontroller Programming / 12

DC Power Supply
This is an important part of your lab. We shall need a
5V regulated power supply for our projects, but some
parts of the project may require more than that. A num-
ber DC power supply adapters are available in market
having selectable output volts. Indeed battery packs are
also available however they give a fixed output supply.
A few packs have rechargeable batteries. I shall not
suggest a very sophisticated power supply at this mo-
ment. Get a multi volt 3-12V DC adapter preferably 300
-500mA rating. These adapters usually have a polarity
selection switch as well, make sure your adapter has
this as it is useful to change the positive and negative terminals. Notice the adapter shown in figure has
multiple outlet pins. Also there is a clip like 9V battery. This is specially good, as we can have 9V Battery
holder in our project and can power the board through 9V battery or this DC adapter.
I shall not go into details of building a 5V supply. If you are going to use Breadboard for your experiments,
make sure you have a 7805 voltage regulator IC and make appropriate 5V supply either on the breadboard
or separately.
Programmer
Programmer is a piece of hardware that will
transfer the program from your computer to the
program memory of your microcontroller. Once
the program has been transferred you insert the
chip into the development board or your bread-
board and let the program execute. This picture
shows a very simple programmer for students and
hobbyists. This programmer can accept program
through a serial port cable connected to your
computer. The target microcontroller is inserted into the ZIF socket. After the program is transferred the
controller can be removed and inserted into your project board. A number of other designs, some cheaper
and some expansive also exist. This particular programmer is called JDM design. You can visit JDM home
page at: http://www.jdm.homepage.dk/newpic.htm, or the Feng deign, http://feng3.cool.ne.jp/en/
pg5v2.html as of the one shown above. Many microcontroller hobby shops sell these and many other de-
signs at reasonable prices. It is better for a beginner to get a pre-made and tested programmer so that he
may concentrate on his primary objective, i.e programming. Once he has made through the things, and his
confidence level is high he can attempt to make things himself. Many shops also sell these programmers as
kits, that include PCB, and components so that you can build yourself.
In Circuit Programming
It is traditional to have a ZIF socket programmers. You insert the controller at appropriate place in pro-
grammer socket, burn the program into controller and then remove the controller from its socket. Re-insert
it back into the project board and test. This removal and insertion again and again has its hazards. You can
break the legs, insert it wrong way and damage the controller. Moreover its tedious job. The current stan-
dard is to program the controller in its target board. This does require a programmer, but you do not need to
remove the controller from its target board. The target board however needs to have a way the programmer
can be connected. This is called In-Circuit programming header (ICSP). You can see the header in above
figure. If your board has such a header, just connect a connecting cable between programmer and board and
your controller can be programmed right there.
Bootloader
There is another advancement in microcontrollers, called self-programming. Not all controllers have this
capability. Only newer and advanced controllers can be programmed in this way. 16F628A can not be pro-
grammed through bootloader. Howerver 16F877A or 18F452 etc can all be programmed. Although we shall
Beginning PIC Microcontroller Programming / 13

use the standard programmer, it is useful to know about this technique as well. In order to use this tech-
nique you have to install a small software, called bootloader into the program memory of microcontroller
using a standard programmer. Once the bootloader is in place now each time you reset or start the controller
bootloader executes first. It will check the serial port, or USB if controller has one, to see if a new program
is coming. In case a new program is available, it is accepted, and written into free memory of controller.
After the program is transferred the control is transferred to new program and starts executing.
Development Boards
Well PIC microcontrollers basically need a very simple hardware setup to execute a program in them. But
the program will execute inside the controller. In order to communicate with external world or actually con-
trol something we need to have some
external devices connected to the con-
troller. This is fairly easy to the level of
a few LEDs or buzzer but becomes
quite complicated when a number of
devices need to be interfaced. If you are
making a specific project, its worth
making a proper PCB, or do it on vero-
board, with soldering.
Many commercial companies and or-
ganizations have made complete
boards, that have many devices pre-
built over them. You can use them to
test your programs, or extend them to
connect to your particular project.
These boards can be as simple as con-
taining just microcontroller , crystal
and power supply to huge containing
dozens of devices.
I would suggest getting a simple board
first. Once you have mastered the basic
structure you can invest on something
like Easy PIC-6 from microelectronica.
Just ask your geeky friends and I am
sure they will guide you the appropriate
place where you can get these boards.
Smart boards
Every development board does not has
every possible interfacing device. And
there are certain devices that are com-
monly required in many projects, again
and again. So these devices are usually
available as standalone boards, called
smart boards. These boards alone can
not do any function, but can be easily
plugged into any microcontroller pro-
ject, and extend its functionality. An
example can be Real time clock chip. This chip has all the necessary circuitry and program to maintain the
time. Project where time and date keeping functionality is required this chip can be useful. In case your
board does not have this chip, you can have it as a smart board. Not only you can use the smart board with
your particular development board, but can incorporate it into other standalone projects.
Beginning PIC Microcontroller Programming / 14

Understand your board


You can connect the various devices to microcontroller in many different ways. Specially when it comes to
general purpose devices like LED, LCD and switches etc are concerned. It is important to know how de-
vices are connected to the microcontroller. Usually the manufacturer of board provides a manual or sche-
matic to show the connections. In case our discussion differs in terms of connections, you can make appro-
priate changes in your program to take the difference in account.
Software required
You need to install two basic software on your computer. A compiler and a programmer supporting soft-
ware. As I mentioned earlier microcontrollers understand numbers, their commands are also numbers. Hu-
mans on the other hand understand words. So software were made that accept English like commands and
convert them into appropriate controller understandable commands. These software are called compilers.
The syntax and structure of English like commands depends upon the programming language being used.
There are a number of programming languages I common use. By far C is the most popular and most
commonly used. For a beginner I would suggest using BASIC as a programming language. A number of
compilers exist for BASIC language to compile the commands into controller understandable code. There
are two popular compilers, PROTON BASIC, developed by Crownhill Associates and MikroBasic devel-
oped by Mikroelectronica. Both of them have their fans, and fan-clubs. PROTON BASIC has very simple
programming style, and has very few restrictions on style, it however lacks a structured programming ap-
proach which pays in the long run.
My previous texts have used PROTON BASIC as a programming language. In this book I shall give Mikro-
Basic a try. The advantage of MikroBasic is that a demo version can be easily downloaded from their site.
This demo version is not limited to the number of supported controllers. Its only limit is 2K code size. 2K
Beginning PIC Microcontroller Programming / 15

code is quite big for a microcontroller, and most of the basic learning projects remain well under 2K. Sec-
ondly Mikroelectrica also makes C and Pascal compilers. The device related library remains almost same.
So whatever you learn on MikroBasic, is also applicable to a large extent to MikroC as well. MikroBasic
compiler and associated documentation can be downloaded from http://www.mikroe.com/eng/products/
view/9/mikrobasic-pro-for-pic/ .
Mikrobasic is an integrated development environment. This means the same software has an editor, a com-
piler and many other supporting tools. MikroBasic supports their own programmer as an integrated devel-
opment tool. Since we are using a different programmer, we shall not use that part of their software.
Programmer Software
As we are using JDM programmer, we need to download and install a supporting software. JDM is an open
source design, so many free to download supporting programs are available. WinPIc800, ICPROG and
PICPGM are some of the commonly used. We shall use PICPGM for our purpose. Nevertheless all have
same functionality. If you have a different programmer or want to use a different software it does not mat-
ter, as long as it supports your controller and accepts the compiled (.hex) file and transfers it to the control-
ler.
PICPGM
You can download this free software from, http://members.aon.at/electronics/pic/picpgm/ . Although the
number of supporting devices is some-
what less, but it does support all com-
monly used PIC microcontrollers. The
beauty of this software is that it auto-
matically detects the type of program-
mer, the port where it is attached and
the microcontroller that is connected.
If everything is detected automatically
it is for sure that the system has been
properly connected and configured.
Most of the times you do not have to
do anything, except to file it. It will
automatically detect the programmer
and microcontroller. Browse the .hex
file and click over program button.
Yellow button on toolbar with light-
ning icon.
Beginning PIC Microcontroller Programming / 16

4 A Brief Tour of MikroBasic

N
ow that we are ready to take-off, its better to have a brief tour of our working environment, so
that we know where to find various tools, and how to make a basic project. Although Mikroba-
sic is loaded with features and tools, we shall not discuss each and everything in this section.
You can find very good documentation in the Mikrobasic manuals. We are using Mikrobasic
Pro 2009 version. The exact look and experience may differ depending upon your particular release. Never-
theless they all have same basic features, like a new model of a car, basically its a car and if you under-
stand previous one surely you will understand this one as well.
Traditionally programming consisted of many separate steps. You need an editor to write your program as a
text file, then you need a compiler that will accept the source file and generate the appropriate target file.
Then you need a system to transfer the generated file into the microcontroller. In case you need to revise the
software he entire procedure is repeated again. On top of that there are certain other features that are di-
rectly or indirectly related. An ordinary editor, like Notepad has no idea what you are writing. The intelli-
gent editor of Mikrobasic however knows you are writing an application software for a particular microcon-
troller, so it helps you by highlighting the keywords, variables and objects etc. Similarly there are other
tools to help you write the code, so that you do not need to remember the exact syntax of a particular com-
Beginning PIC Microcontroller Programming / 17

mand.
Mikrobasic is a user-friendly and intuitive environment. Indeed such a programming system is called
Integrated Development Environment. Most of the commands and actions are common in windows envi-
ronment therefore they do not need to be talked about. For example we all know what is Cut-Paste, how to
open a file, locate a folder and save a file etc.
The Mikrobasic screen looks haunting at the first glance. Having so many sections and modules. Hang-on
they are all there to help you, you can customize the look according to your needs by dragging and drop-
ping various dock able windows. All I need to introduce you is the fundamentally important parts.
The main window in center is your text editor. It is here you will write your program. The panels on right

and left are supporting panels that you will open when required. The panel below is message area where
you will find various system messages, we shall talk about these messages as and when they appear.
Most of the times our code can become quite big,
and it makes sense to store it in different files.
Instead of writing in the same one big file, it is
better to store the parts of project in various files.
In this way it is easier to find the code, and also to
use the same code in other projects if required.
Thus Mikrobasic and many other newer IDEs
encourage the Project approach. A project con-
sists of one or more than one files.
So lets begin with a simple project, where we
want a small program to blink the LEDs con-
nected to PORTB. For now do not take the code
seriously, what I want is to familiarize you with
the basic procedure.
Beginning PIC Microcontroller Programming / 18

When you first fire Mikrobasic a default project already opens. Click over the Project menu and then over
Close Project Group. The entire window will clear and there will be just blank IDE with no editor.
Now click over Project menu and then on New Project. A new project wizard will appear. This will ask
you a few questions about your project and set the necessary environment for you. Although you can set all
those things yourself, or if you want to modify them later, this wizard approach is good to start.

The first is a welcome screen. It has given you an idea what its going to do. That it will create a new project
and setup your environment. I would suggest you create a new folder before that somewhere in your hard
drive, lets call it PicProjects . Then for every project make a sub folder, lets say Blink for this project.
The project wizard only makes files and might name those blink but if you create multiple projects files
with similar names might be confused. So here I assume you have created a folder like:
D:\PicProjects\Blink.
Now click Next. This step is
asking you to chose the micro-
controller for which you are
going to write the program.
You will do this according to
your particular controller. We
are going to use an 18 Pin PIC
microcontroller 16F819.
In other projects we might
chose 16F6128A, and in still
others 18F452 depending upon
the particular situation.
It is important to tell the Mik-
robasic about the microcontrol-
ler that we shall be actually
using. This is because it will
select the appropriate registers
for that particular controller, as
Beginning PIC Microcontroller Programming / 19

well as load the memory map fro various registers. For example two controllers can have PORTB, and this
register will be called same when writing code, but the internal memory address within the microcontroller
might be different. Thus when a compiled file (.hex) file is created the addresses of registers are sent, not
names. That is why the .hex file created for one microcontroller may not work on other having similar
source code.
Click next, now it is asking for
te Device clock speed. This is
the speed of oscillator we are
going to use. The default is
8MHz. Again you will need to
consult your board. If it has a
crystal oscillator, you got to
know what speed crystal it is.
Usually its written over it but
many a times its so faint that
you can not properly read it. The
best guide is manual from the
manufacturer.
In case you have assembled the
board yourself, then of-course
you know what crystal you are
using. I personally use a 20MHz
oscillator to push the microcon-
troller to its limits. As I had pre-
viously discussed it not always best to use highest speed. It depends upon your application. Any way right
now our board has a 20MHz crystal oscillator, so we change this value to 20.0 MHz.

Next step is to chose the location


where project files will reside,
and the name of your project file.
Notice I have selected my folder
and named the project file as
Blink. It has automatically given
it the extension of .mbppi. This is
a reserved extension of Mikroba-
sic for its project file. The project
file is actually a binder. That will
contain links to many other files
that are part of the project. S your
project is not in this file, your
actual code will be in separate
files and even may be scattered
in many different folders. This
File will keep a link to those
files.
We shall not experiment with
distributed files for now, and all our files related to a project will reside in the same folder. May it be a sin-
gle file or more we are going to use this approach.
The next step is asking you to Add a file to the project. It is here we add previously written files. For now
since we do not have a file yet, just click next. In fact we are creating an empty project folder.
Next step is asking you to chose the libraries. The concept of libraries is very beautiful and at the same time
very powerful. Most advanced compilers may it be microcontroller related or PC programming related have
Beginning PIC Microcontroller Programming / 20

libraries. I shall talk more about li-


braries later. For here I would just
say that various programming appli-
cations need to take into considera-
tion a number of commonly used
technologies. For example LCD, thi-
sis commonly used in many applio-
cations. In order to use an LCD prop-
erly we need to write quite lengthy
code. Need to know its commands,
and their format and then send the
data accordingly. All this complexity
has been hidden from us by the Mik-
robasic LCD library. So we are con-
cerned only upto the level of how our
LCD is connected and what we want
it to show. The rest of code is gener-
ated during .hex file creation by Mik-
robasic. Thus presence of the LCD library has made our coding easier. The more libraries you have, natu-
rally more facilities you have to work with. Another beauty of these libraries is that if you change the con-
troller, use of library remains same. Even if you later opt to chose MikroC for example, it will also have
almost same library. Since Microelectronics people make compilers for other controllers as well, for exam-
ple 8051, Although the MikroBasic compiler for 8051 will be different, but will have the same environment
and same libraries. Ok for now we want to include every library in our project. The code will not increase
by this action, because only the code that is included in source file will get compiled. Including them here is
only for reference. Click next, and final step is finish. Just finish it and your project is created with a new
file in editor. Notice the file name in editor window is Blink.mbas this is our source file. Mbas is an exten-
sion for Mikrobasic source code. It has automatically inserted a few lines of code. By default the first line
has to have a directive called program and its name. In this case Blink. Then there has to be a label named
Beginning PIC Microcontroller Programming / 21

main:
Notice a : after the word main. This word must be there and this indicates the starting point of your appli-
cation. Whenever the program starts executing it will first locate the main: label and start program execu-
tion from there, later it can be made to jump to other modules.
So our code will start after the main: module. The last command end. Should be there to indicate where
main code body is finished. You can write other callable procedures and functions below the end Statement.

Now enter a program like this. Dont worry about the commands and what they say. They will be clear in a
few moments. While writing a command if you press Ctrl+(Space key) a help will automatically appear you
can go on typing the command and it will go on filtering finally you can find the one you are intending to
write. This becomes helpful if you forget the exact command or its parameters. This window is called code
assistant.
Note Basic language is not case sensitive, whereas C is case sensitive. So in Mikrobasic PORTB and portb
are same. It is however conventional and more user friendly to write the names of registers in capital case,
and your local variables in small case.
Now that we have written the source code, its time to save it. After saving we can generate the .hex file
click over project and then Build. This will invoke the compiler and you will see a number of messages
appearing in the messages window below the editor window. Look for the last line, saying Finished Suc-
cessfully. That is it. You have successfully created a .hex file that can be transferred into 16F819 micro-
controller.
Now lets have a look at the folder where we created the project file. As you can see there a re a number of
Beginning PIC Microcontroller Programming / 22

files there including our project file, then the source file. Notice one important file, pointed by arrow, the
Blink.hex file. This is the file that contains all the code necessary for executing our LED blinking program
to 16F819 microcontroller.
If you have reached so far, that is good, and this is the barely minimum that is required. Now if you want to
modify the code, just change it in the editor and build again. Remember we are dealing with our source file
through project, so if you close the Mikrobasic, you will open the project not file. Click over Project, and
then open project chose your project file and there you are. Your code along with all settings is back.
Burning the .Hex File into Microcontroller
Lets move one step forward and transfer the .hex file into your microcontroller. I assume that you have
already installed PICPGM software on your computer, connected the PIC programmer, I am using PIC PG-
2 a JDM type programmer. The programmer in
turn is connected to the development board with
16F819 in place. I am using In circuit program-
ming technique, so I do not need to remove the
controller from its motherboard.
You can see in this picture that the programmer
is connected through serial cable to the PC. Most
PCs have one serial port and its named as
COM1.
On the other hand the Programmer is connected
to a cable to the development board. The ar-
rangement of pins on this header is fairly stan-
dard as per Microchip guidelines. Make sure if
you are using such an arrangement the pins la-
Beginning PIC Microcontroller Programming / 23

beled properly and have arrangement as per microchip guidelines.

Easy PIC III Trainer Board for 18 pin PIC Microcontrollers

This picture shows our development board. Notice the cable from programmer, is connected to the In Cir-
cuit Programmer Header. You can also see the crystal oscillator very clearly labeled as 20.000 MHz. After
connecting these, you will find that power LED turns ON, even though we have not plugged in supply yet.
This little 5V supply is coming from programmer. This is enough in most cases to program the microcon-
troller, but if there are other ICs on board, the
supply may not be enough. Therefore connect
your power supply to the board and turn it ON
while programming. Now we fire the PIC
PGM. Notice it has detected the programmer as
well as the controller in place. Click the yellow
Program button and it will transfer the program
into microcontroller program memory. In the
end it will show a green message box indicat-
ing a successful transfer. If the red box indicat-
ing an error appears check your whole system.
After the program is transferred, you have to un
-plug the programmer from development board.
This is because the programmer has still kept
the MCLR pin in programming mode and due
to this the program can not execute. Instead of
removing the cable from board, I usually un-
pug the serial cable from programmer. That
effectively turns the programmer OFF and re-
Beginning PIC Microcontroller Programming / 24

leases the MCLR pin. Turn The Power of your board OFF, remove the Serial Cable from programmer and
turn the power of your board again.
You should see the LEds Blinking at a rate of 1 second. This will be exact 1 second ON, and 1 Second

OFF.

Notice the LEDs B6 and B7 are somewhat dim than B4 and B5. This is because we have placed 220 Ohms
resistors with LEDs on B4 and B5 (actually connected to RB4 and RB5) to limit the current drain from PIC
microcontroller. However with LEDs on RB6 and RB7 we have placed 1.5K resistors. This had to be done
to take advantage of In circuit programming. The In circuit programming also uses RB6 and RB7 to trans-
fer data, see data sheet, these pins are also labeled as PGD and PGC. When a current draining device like
LEDs is connected to these pins they tend to drain the programming signals and therefore microcontroller
can not be programmed.
Microchip recommends to keep this pins free if possible, otherwise use a 1.5 to 4.7K resistor. This will only
limit current but still any other device requiring logical value like a transistor etc will not be affected.
Well so far so good. What if your project is not producing optimum results? This definitely indicates some
problem. Problem can be in your hardware or in your software. This is time to debug your application.
Truly speaking best debugger is one which reads in the program status and microcontroller status from the
actual board while program is working in real environment. This type of debugging requires a special hard-
ware device called In circuit debuggers. Mikroelectronica and other companies have their own proprietary
debuggers that can be used with their compilers. Microchip makes ICD-2, ICD-3 and PICKit-2, PICkit-3
for this job. Still if you just want to see how your program will execute, and want to see its logic flow, Mik-
Beginning PIC Microcontroller Programming / 25

roBasic has built in debugger. We shall talk about this in some later section.

.
Beginning PIC Microcontroller Programming / 26

MikroBasic
5 Programming Language

B
ASIC is an old programming language. It was developed in 1964 at Dartmouth college, New
Hampshire USA by John George kemeny and Thomas Eugene Kurtz. At that time programming
a computer required lots of technical knowledge about the hardware and electronics. The idea of
developing this language was to facilitate non-science students able to program computers and
use them. A number of other programming languages developed like Fortran, Cobol, PL1 and so on they all
did great job but vanished with time. BASIC stood the tests of time and still persists in quite advanced form
for a number of platforms. Today BASIC is considered a family of High-Level programming languages.
The science of computer programming has taken many changes, BASIC language has adapted these
changes and therefore stands with many other competing languages, like C.
Therefore truly speaking a programming language itself is a set of principles or rules to write a program.
BASIC language therefore defines certain rules, and these rules remain same, weather we are programming
a personal computer or a microcontroller.
Lets come straight to microcontroller. A number of companies make BASIC language compilers for micro-
controllers. They all have to follow the same basic principles as defined by the BASIC language. However
they differ in two ways:
1. Each compiler provides its own set of libraries, which contain useful functions and procedures
to carry on everyday tasks. Some of these functions may be similar but differ in implementa-
tion. For example every compiler would provide a facility to write data on an LCD display, but
exactly how to implement it in user program will differ.
2. BASIC language defines many standards, which have been evolved over a period of decades.
These standards dictate the standards of programming technique. Not every compiler follows
the latest standards. There are compilers with excellent library but they lack what is called
Structured Programming
MikroBasic is fairly advanced and it tries to adopt many advanced standards. It has an excellent library to
support many commonly used procedures, as well as it follows structured programming technique. This
chapter can not be a detailed tutorial on programming, but I would just mention that a structured program is
more easy to maintain and extend.
Microcontrollers have limited memory, indeed a few Kilobytes, therefore it is hard to implement every
standard of programming as these standards require more memory. To some extent these standards are then
applicable in microcontrollers with more memory, but in these smaller controllers like 16F819 with just 4K
memory it is not expected that an object oriented model be implemented.
Many procedural calls, from one procedure to another and from there to another result in storing the local
variables and registers on a common memory place called Stack. The more stack space a controller has
more deeply it can address the nested procedures. With limited stack space we have to keep in mind that we
can not call too many procedures in a nested fashion.
So programming Microcontrollers is a two way challenge, on one hand you have to achieve the results you
want with limited computing capabilities. On the other hand you have to manage the available resources,
limited program memory, limited variables storage and so on.
Considering limited stack space, Recursive calls to the same procedure are not allowed in MikroBasic.
It may not be possible to discuss each and every MikroBasic command in detail, here however a general
outline will be given so that we can take a simple start. We shall talk about specific commands and issues
Beginning PIC Microcontroller Programming / 27

as they will be encountered in the following chapters.


I would however recommend you to go through the manual of MikroBasic compiler that will give more
details on specific topics.
MikroBasic organizes your program in the form of a project. A project is nothing but a collection of re-
sources required to solve an issue. Ideally speaking this does not only include the code you are writing but
also the help material, research articles and support libraries. Everything even your rough work is part of
the project and must be kept and moved together. We usually assign a separate folder for each project and
then keep the various files in that folder. MikroBasic Project includes all relevant files including your
source code. When asked to compile only the files referenced in code will be used to produce single target
file called .hex file.
Many students ask, why we should have multiple code files, when we can write the code in one file. That is
true, and indeed many beginners do the same way. However to be a professional you must be organized.
The code is better organized in individual files, containing one specific part of the code. Similarly there are
many projects where almost same code is required in various locations. Thus if you have already written,
tested and debugged a code why to repeat it again.
In order to keep it modular we tend to keep the code organized in different files. For example I have devel-
oped a routine to accept numeric data and floating point data from the keypad, and pass it on to the program
as integer or floating point variables. It took me pretty long to develop the algorithm, error testing etc. Now
if I save this code as a separate file, like keypad.bas then I will just include this file in my every project,
and I would not have to worry about this code again.
So if a project is going to include so many code files, how will the compiler know where to start? This is
done by the Main: keyword. There should be only one file that should contain this keyword. Usually this is
also the specific file for your project as well.
MikroBasic is very strict in following its program structure. A program consists of :
A Header section
A Declarations Section
Procedures and Functions
Main Program Body

The Header section is the first part of program and contains keyword: Program this is followed by the
name you have given to the program. Following this is the Keyword Include this describes external mod-
ule files to be included in your code. If your program does not require external referenced files, this may be
excluded. In files that do not contain the main section the Program keyword is replaced by Module. We
shall see about these things where need arises. For now just remember your program will begin with Pro-
gram keyword, and will contain the main keyword.
Variables
Variables are the main stay of any program. These are the structures which contain run-time data. Variables
are defined and used in a program, but they get actual existence when the program starts execution within
the target machine. Variables are created in RAM. In microcontrollers RAM is different from Program
memory. Usually Program memory is reasonably large, but RAM is quite small. We have to be careful
while using variables, as we can easily end up in consuming the precious RAM. Different microcontrollers
differ in size of RAM they have. This is also an important factor in choosing the microcontroller for your
application. For example Microcontroller A might have enough powers to handle a particular job, but when
you compile the program, its usage of memory out-runs the RAM on this chip, so you have to choose an-
other with more RAM, or re-design your program to accommodate smaller memory size.
Any way , we were talking about variables. There are certain rules for using variables:
Beginning PIC Microcontroller Programming / 28

A variable must be declared before it is assigned a value or used. In MikroBasic there is a keyword Dim
that is used to declare a variable.
A Variable must have a unique name. It can be a single letter, a combination of letters and numbers and
some special characters. The variable name however must always begin with a letter. It should not have
space, or special characters like , &, * etc. Also a variable name should not conflict with similarly named
MikroBasic command or Microcontroller special function register names.
A variable must be defined as specific type at the time of declaration. The type means kind of data it will be
supposed to contain. Although internally everything is as bits and bytes yet there are different ways of han-
dling them. The compiler therefore requires you to inform it the data type the variable will hold. We shall
talk more about data types as they are required, but for now just remember the commonly used data types:
dim i, j, k As byte

Type Size Range


bit 1bit 0 or 1
sbit 1bit 0 or 1
byte, char 8bit 0 .. 255
short 8bit -127 .. 128
word 16bit 0 .. 65535
integer 16bit -32768 .. 32767
longword 32bit 0 .. 4294967295
longint 32bit -2147483648 .. 2147483647

float 32bit 1.17549435082 * 10-38 .. 6.80564774407 *

dim counter, temp As word

Notice the keyword As after the list of variable names. Following this is the type of these variables.
Life and Scope of Variables
When a variable is declared within a module, procedure or a function, the variable is said to be private to
that module. It is created when the program enters the module, and when the program leaves the module it
is removed from RAM. The location is free for use by other variables to be created. The contents are
cleared and variable name is released.
Therefore if you declare a variable named count in a procedure, when the procedure exits you can not ac-
cess the variable count because it is out of scope now. Moreover if you have another procedure and it also
uses same variable name, there is no conflict, both will be handled separately.
A Variable that is declared before the main statement is called Global variable. This variable is going to
persist for the entire life of program. The variable is accessible to every module. However now modules can
not declare their own private variable with this name, as it already exists.
Arrays and Strings
Arrays are special data types with same variable name for many variables. However each variable has a
subscript number, which can be used to access an array variable. In this way many similar variables do not
need to be declared separately and named separately. The key point is there should be a logical reason to
group them.
Dim Months as Byte[12]
This statement will declare an Array of 12 variables. Each having name Months. Each variable will be
able to hold one byte of data. However to refer a particular variable we need to provide it an index number.
Beginning PIC Microcontroller Programming / 29

Since we have created 12 variables, they will have index numbers 0 .. 11. In our program we shall access
them as Months[0], Months[5] etc.
Strings are nothing but an array of characters. Although every character is internally stored as a number, but
the compiler will not perform mathematical functions on these numbers. They are called characters. To de-
clare a string we use string as type followed by its length in square brackets.
Dim msg1 As String[16]
Msg1=Hello World

The string is internally stored as array of characters, plus one additional character called null. This contains
number 0. to indicate end of string.
Special Function Registers of PIC
There are a number of registers located inside the microcontroller that modify the function and behavior of
various modules. These are called special function registers. Although internally represented by specific
memory locations, they have been given names in the datasheets. It is easier to talk about them using their
names instead of locations. Most of the registers are common among many PIC microcontrollers so they
have same name, some are specific or different and they tend to have different names.
There is no need to declare the special function registers in MikroBasic. MikroBasic compiler already de-
clares them for us when we chose appropriate microcontroller as part of project definition. MikroBasic de-
clares them as Word type. Moreover they are declared as Global so they are accessible from every part of
the program.
Constants
Constants are data whose value remain same throughout the program life. They are simply difficult to re-
member therefore we give them a user friendly Name, like a variable. Unlike variables their value can not
be changed. Once declared we can use them. Constants do not consume RAM. They are part of the program
memory.
Same rules apply for declaring constants as for variables. It is however traditional among programmers to
name the constants in upper case. The data type is automatically calculated by the compiler at time of dec-
laration, smallest size is chosen.
const MAX as longint = 10000

const MIN = 1000 ' compiler will assume word type

const SWITCH = "n" ' compiler will assume char type

const MSG = "Hello" ' compiler will assume string type

const MONTHS as byte[12] = (31,28,31,30,31,30,31,31,30,31,30,31)

Thus in a program with some maximum and minimum values, instead of using 10000 and 1000 again and
again, we will use MAX and MIN in program. This will also facilitate if we decide to change the maximum
and minimum values, instead of locating many places where we had written 1000 and 10000 we just change
the constant definition, and thats it. Another danger in using raw values is wrong entry at certain position,
or while changing the value to new one, missing it in some location. All this is avoided if we make a good
programming habit of using constants, and also writing comments to elaborate whats in your mind.
Comments
Comments are special type of text that is meant for programmer only. This text acts as small on the spot
Beginning PIC Microcontroller Programming / 30

notes to help programmer remember and recall, what is happening in this part of code. Comments can be
placed on entire line, and series of commented lines act as a block of notes. Comments can also be placed
along side the code. To begin a comment just enter the character (apostrophe) and start writing the com-
ment. A comment will continue on the same line. To continue it on the next line, you have to begin the next
line with a new comment. Comments are stripped off during compilation and do not affect the object code
generation.
Literals
Literals are special indicators used to inform the compiler about nature of some values being used in pro-
gram. For example integer numbers can be represented in decimal, hexadecimal or binary form. Internally
the value might be same, but physically they are written in different formats. Although it is not very diffi-
cult to guess the nature of a number by looking at it, but it might become confusing at times. Consider the
binary number 10, now in binary notation it is two, but some one might interpret and read it as ten, which is
entirely different value. Therefore in order to remove this ambiguity, MikroBasic allows you to prefix the
value with certain characters, to indicate the intended nature of value.
A % sign is used before binary numbers, like %1011 is four bit binary number
A $ sign is used to indicate a hexadecimal value, like $A0 is eight bit number in hexadecimal format. Peo-
ple with C language background are used to using 0x as a prefix for hexadecimals. MikroBasic accepts this
as well, so $A0 and 0xA0 are same thing.
No prefix indicates a decimal number, thus a value 67 is simply sixty seven.
Labels
Labels are tags of text used to refer some specified location of code in the program. A program con contain
as many labels as you want, but they must be unique. To define a label, all the rules used to define variables
are implemented. The label however does not need to be declared first. Just write label name, followed by a
colon : for example, AA: is a valid label. Now this section of code can be referred to by Goto AA . Notice
when using the label name with Goto there is no : sign.
Use of labels is not encouraged. In todays programming standards, what we call structured programming,
people will frown if they see use of labels in the program. They are supported for two reasons, firstly for
backward compatibility, and secondly since assembly language code can be mixed in MikroBasic, and as-
sembly is non-structured language. It will certainly need use of labels. So we will use labels only very occa-
sionally.
Symbols
Sometimes in a program using special function register names, or even their bits, might be repeated a lot.
This might increase confusion as to remember what this register is doing. So we use symbols to represent
those commands, or even registers. When the program is compiled, the compiler will actually replace those
symbols with the equivalent defined code.
Functions and Procedures
It is customary to write the code in a linear top to down format. Since a program actually contains many
logically different processes, like a portion might be calculating something, another getting user input and
still another responsible for displaying the result on LCD. No doubt all these processes can be written in a
single process, writing appropriate code where required. This approach however is criticized by many pro-
gramming gurus.
The reason is that you might be repeating same code again and again, thus if changes are required you have
to apply at a number of places. Still more objectionable is that the compiler will generate more machine
language code and therefore will consume more controller memory.
Functions and procedures are parts of the program that are complete in themselves and have been designed
to do a specific task.
They can be given specific, meaningful names. All variables required by these sub-programs are private
Beginning PIC Microcontroller Programming / 31

and therefore will not interfere with each other. Once a function and procedure has been tested to work
properly, you will not need to remember its internal workings. Now it will be dealt as a block of statements,
referred only by the name. You may call them any number of times, even pass on parameters. Functions on
the other hand also return a value back to the calling program.
Using functions and procedures is considered a good programming practice. Therefore to ensure we stick to
the best standards, we shall try to use this programming methodology wherever possible.
There are still many more areas of MikroBasic that need to be addressed, these will need a complete book
in itself. MikroBasic has its own very good programming reference available in PDF format. You must go
through it to read more.
Beginning PIC Microcontroller Programming / 32

6 Hello World !

M
any students and hobbyists love to make their own development boards. No doubt this is es-
sential practice to make at-least one basic board yourself so that you know exactly how to
hook-up the microcontroller in a circuit. After-all any project is not merely programming but
has an equally important electronics hardware part as well. In this section we shall dissect the
barely necessary microcontroller board on a breadboard, and write a simple program as we did earlier to
blink the LED.
Breadboard Basics
I am sure most of you are already familiar with a breadboard, however just for completion of the topic and
for our friends who are new to electronics let
me give a brief tutorial. Also we shall define
some best practices to make the breadboard
project easier to handle, and share. If we are
following standard practices, it is easier to
share things.
Breadboard is also called a solder-less
board. Components can be easily inserted
into the board. Underneath these holes are
connected together. Thus there is no need to
solder the components together. The Top
and bottom Rows are connected together as
two rails. These are used to power supply
the different parts of project. It is customary
to use lower rail (show n as blue line) as
ground and upper rail shown with red as +
supply. The columns shown in between are
connected together as vertical columns. There is a groove in the middle that disconnects the columns above
and below. Thus an integrated circuit can be inserted with half pins above and half below the groove.
It is also customary to keep the notch of in-
tegrated circuits towards left. This simulates
most of the time with schematic to reduce
the complexity. The upper and lower power
rails are not connected together. You must
connect them together using jumper wires.
Some breadboards even have disconnected
power rails in both upper and lower parts, to
allow you four different types of power sup-
plies in case your project needs. Since we
will be working most of the times with sin-
gle supply of 5V it will be more convenient
to connect them together as one supply.
I would like to mention here about jumper
wires. I used to have lot of difficulty in in-
serting the jumper wires and also to keep
them in good contact, when I was a beginner. Use single core little hard, preferably No. 20-22 gauge wires.
Beginning PIC Microcontroller Programming / 33

Do not use soft multi-core wires, as they are difficult to insert. As shown in this figure cut them into differ-
ent legths and keep them in a container. You can find suitable container from stationary shops, where vari-
ety of pencil boxes will suit this. Similarly make boxes for components like resistors, capacitors, transistors
and ICs etc.
Five Volts regulated Power Supply
Most microcontrollers work at 5V power supply,
although some require 3.3V, we shall be using 5V
compliant microcontrollers in this book. Unfortu-
nately power supply units are available in 1.5V in-
crements. Using three 1.5V batteries in series will
give 4.5V and is accepted as a source of supply.
However as batteries will get consumed this voltage
will drop and microcontroller project will misbe-
have. A better solution is to have a 6 or 9V power
supply, either in the form of a battery pack, or as a
DC adapter, and then convert that supply to 5V
regulated one using voltage regulator ICs. In case
you are working with a development board, they
usually have this thing built right on the board. In
case you are working on breadboard, or make your
own customized board on veroboard then you have to make your own.
I would prefer to make the 5V supply on your breadboard and then not to dismantle it every time. Your
breadboard should therefore always be ready for 5V circuits. A still better idea is to make your own stand-
alone 5V supply unit, that can be used in many projects.
PIC Microcontroller Basic Setup
The basic setup of PIC Microcontroller can be as simple as just hooking up the 5V supply. I would however
go for the more traditional setup that is standard. PIC microcontrollers have an MCLR pin. You will have to
see the datasheet of your particular controller to find this pin. This pin when connected to ground
(momentarily) will reset the microcontroller execution, and the program will restart again. Note this action
does not erase the program from memory. In order to allow the program to run, this pin must be at logical
Beginning PIC Microcontroller Programming / 34

high or near 5V. You can simply connect it directly to +5V, also called VDD (+ 5V is also called VDD, and
Ground VSS). Since many applications also use in circuit programming, and also use this pin to reset the
controller, it is better to use a 10K resistor to connect it to VDD supply.
Some Microcontrollers, like the 16F877 as shown has two pins for +5V supply and two for GND. Both of
these sets must be connected to power supply.
Oscillator
All microcontrollers need a source of pulses to synchronize internal tasks. The processor will take one step
forward in program execution every time a pulse is received. Therefore we have to provide a reliable source
of these pulses. If pulses increase or decrease due to instability in oscillator circuit the program execution
will be affected and many timing applications will not be accurate. We use Crystal oscillator for this pur-
pose. A crystal oscillator is very stable over a wide range of physical conditions like temperature and pres-
sure. The oscillators are available in various frequencies, like 4, 8, 10, 12, 20 and 40 MHZ or even more.
You can choose any, but you have to know its frequency. We shall be using 20MHz Crystal oscillator in
our projects.
PIC microcontrollers have two pins named OSC1 and OSC2, consult your datasheet to locate them. The
crystal oscillator can be connected to these two pins. There is no orientation of legs, it can be connected
anyway you like.
The faster the crystal is faster is program execution and response, this however also consumes more power.
As per lab is concerned this is usually not a big issue. In your final projects, if the project is battery based,
and very high speed is not requirement of your project use, a lower frequency crystals to conserver battery.
In order to stabilize the oscillator two 22pf capacitors are used as shown in the circuit diagram shown
above.
Connecting LEDs
Microcontrollers are designed to give out control signals. They are not meant to provide necessary power
for the output device. You will therefore need an external driver circuit for that. We shall talk about driver
circuits later in this book. Driving an LED is however simple and does not require much power. Usually
Beginning PIC Microcontroller Programming / 35

LEDs can be connected directly to the microcontroller pins. If you go through the PIC microcontroller data-
sheet it says, each pin is capable of supplying 25mA of current. Since LEDs come in different forms, some
consume more current where as others are more economical. It is therefore standard practice to place a cur-
rent limiting resistor in series with the LED to protect the microcontroller I-O line from being damaged.
The true value of this current limiting resistor depends upon the specifications of your particular LED.
However the best bet is to use a 220 to 330 ohms resistor. I use 3mm small LEDs and a 220 Ohms resistor
in series. Since resistor is in series it does not matter if it is placed before or after the LED.
Current Sourcing and Sinking
These are the two terms commonly used in microcontroller applications specially where LEDs are con-
cerned. By current sourcing we mean that to be active microcontroller pin will be at logical high value, and
the consuming device will get + supply from microcontroller pin. In Current sinking, the device gets + sup-
ply directly from the power line, and microcontroller pin acts as GND. Thus when microcontroller pin gets
logical low, the current flows from VDD, through the LED into PIC pin. The led will then glow when the
pin is low. In current sourcing LED will glow when microcontroller pin is high.
Breadboard Friendly Modules
I would strongly recommend you to make the
breadboard LED project yourself, as this is the
most native form and you will gain a lot of con-
fidence. In order to practice on breadboard time
and again, you have to build this basic circuit.
Many students and some commercial vendors
make small modules that are breadboard
friendly. These modules are made keeping in
view their use on breadboard. These modules
make your life a lot easier. They are truly a
plug-n-play sort of thing. You Plug-in the mod-
ules on breadboard, and treat them as one com-
ponent. Then using jumper wires connect them
together in the way you want them.
You can see in this picture an Arduino based

module with all necessary circuitry built. The module can be easily plugged into the breadboard and used to
interface other parts. Other parts may be modules by themselves or built right on the breadboard.
In our first few project we shall use this kind of modules on breadboard to make our life little easier. Later
Beginning PIC Microcontroller Programming / 36

we shall switch over to development board to make it further easier. The module shown here is from Micro-
tronics Pakistan. This is based upon an 18 Pin PIC micro-
controller, has 20 MHz Crystal Oscillator, an In circuit pro-
gramming Header and I-O lines as well as supply lines as
Breadboard plug-in header pins. The board requires 5V
regulated supply. It has however a reversed polarity protec-
tion diode on +5V supply line.
We shall also use this breadboard friendly LED board that
contains 8 LEDs along with current limiting resistors. The
Inputs and common ground are provided as breadboard plug
-in header. We shall also use the 5V regulator breadboard
friendly module to supply necessary power to the power
rails of the breadboard.
PIC16F819 with 8 LEDs connected.
Now I expect you to have your board ready with PIC16F819 and 8 LEDs connected to PORTB. If you have
another controller like 16F877 or 18F452 it is OK. You just make the standard board with power, crystal
etc. and connect 8 LEDs to PORTB. Except for definition of the controller to the MikroBasic rest of the
project will be the same. The Breadboard friendly module I am using as an example has 16F819 microcon-

troller at 20 MHz Oscillator. This figure shows the basic setup, There is a 5V regulator module taking
power from a 9V battery. An 18 pin PIC16F819 microcontroller module. All I-O lines are snapped-in the
breadboard. The +5V and GND lines are connected to power rails, underneath. This module has 20 MHz
crystal oscillator. Notice the In Circuit programming header connected to the JDM programmer. The pro-
grammer is serial based. The serial cable will be connected to programmer only when programming. When
program is to be executed the serial cable, or programmer has to be disconnected, otherwise it will not free
the MCLR (VPP) pin and program will not execute. We have connected the entire PORTB, 8 pins to the
Beginning PIC Microcontroller Programming / 37

respective LEDs on the LED module. The pin RB6 and RB7 are also named as PDC and PGD. These two
pins are also used to transfer the new program into microcontroller. When a low resistance device like, an
LED is connected to these pins, they may steal the data signals and programming fails. Therefore if you
want to enable in circuit programming as well as want to use these pins for output, make sure that the de-
vice connected does not steal the signals. Alternately you can use 1.5 to 4.7K resistors with the controlling
device to limit this effect. Since our LED module has all 220 ohms resistors, we will unplug the RB7 wire
while programming.
Writing Your First Program
Now we are all ready to write our first program and test it. Our First program will turn all the LEDs ON.
You have already seen this program before in chapter 4. There is no harm in repeating something, and we
shall take this as a beginning to more advanced programming. So Fire MikroBasic IDE, close anything that
already opens and start a new project. It will be good idea to make your own folder like PICprojects, and
then make individual folders for each project. We shall Name this project as FIRST.

program First

' Declarations section

main:
' Main program
TRISB=0
PORTB=%11111111
end.

Now build the project. It should produce a First.hex file. Connect the serial cable to programmer, and pro-
grammer to the board. In case you are using some other programmer just take necessary steps to transfer the
First.hex file into the controller and test the program. Before doing In circuit programming make sure you
had disconnected the RB7 pin wire. The result should be all LEDs ON.
The %11111111 is binary equivalent of decimal 255.
You could replace this with 255 as well, but without
% sign. The 1 means this bit of PORTB will be high.
So we have made all bits high, therefore all LEDs
connected are ON.
Now try different values:
%10101010
%11110000
%11001100
0x0A
0xFA
255
100
These will produce different combinations. Proceed to the next chapter only if you have achieved this re-
sult.
Beginning PIC Microcontroller Programming / 38

Understanding The I-O Ports


7 and Special Function Registers

B
y definition a port is a location through which one system communicates with another system. In
our case the microcontroller communicates with the external world through its I-O ports. These
are called I-O because these
ports can send information
from controller to the external
devices or get data from the external de-
vices. Thus each port is labeled as Bi-
Directional.
PIC Microcontroller ports are named as
PORTA, PORTB, PORTC and so on. The
number of ports and bits in each port de-
pends upon the microcontroller you are
using. The PIC16 and PIC18 families are 8
bit controllers, therefore most ports are
8bit wide. However due to limited number
of pins in the controller, the port bits might
be reduced.
PIC16F819 has two ports, PORTA and PORTB. PORTB is complete 8 bit register, where as PORTA has
only 5 bits. Individual bits of ports are named as RB0, RB1, RB2 RB7 in case of PORTB, and similarly
RA0, RA1 RA4 in case of PORTA.
Other PIC microcontrollers like 16F877 or 18F452 have 40 pins, some of the pins are for power, oscillator
and MCLR, and rest are divided into various ports. For details of these ports refer to the relevant datasheet
to check the port names, and associated pins.
So each pin of microcontroller is directly connected to the associated PORT register within the microcon-
troller. When the program sets a bit of a PORT as high, the corresponding pin goes high, and has about 5V
on it. When the bit goes low, the same thing happens to the pin. Therefore to control the individual pin, and
program PortBits

' Declarations section

main:
' Main program
TRISB=0
PORTB=0
PORTB.B0 = 1
end.

not the entire PORT, we need to manipulate the bits of PORT.


MikroBasic treats each PORT as an 8 bit variable. To address a single bit of a port, you can specify it as
Beginning PIC Microcontroller Programming / 39

part of the PORT like this:


PORTB.B0
This means bit 0 of PORTB which will correspond to RB0 pin of the microcontroller. Similarly PORTB.7
means RB7 and so on. If multiple bits need to be set, you can assign values to the entire PORT, or if indi-
vidual bits need to be addressed, you can use the bit number to assign it a value.
In this program first we have set all bits of PORTB to 0. then using PORTB.B0 = 1 will cause only RB0
high. Thus only one led will turn ON.
The TRISB register
As previously stated, each pin, and therefore bit of a port register can act as output or as input. To define
this functionality of each bit, there is a TRIS register for every PORT. So TRISA for PORTA, TRISB for
PORTB and TRISC for PORTC etc. each bit of TRIS register will control the corresponding bit of PORT
register. A value of 0 in this bit will make that PORT bit as output, and a value of 1 will make that pin and
PORT bit as input.
You must have noticed the TRISB=0 statement in previous programs. This statement will turn all the bits in
TRISB register as 0, and therefore all PORTB bits will be Output type. That is why we are able to set their
values from within the program. Now suppose we have a switch on RB0, and an LED on RB1. So we want
PORTB.B0 to act as Input and PORTB.B1 to act as output, so that we can read in the status of switch and
affect the status of LED. To set this behavior we need to set TRISB register accordingly.

TRISB.B0 = 1 RB0 is INPUT


Beginning PIC Microcontroller Programming / 40

TRISB.B1 = 0 RB1 is output.


Special Function Registers
Registers are memory locations within the microcontroller that can be read and written by the program.
Truly speaking every memory location is called a register in terms of microcontrollers. Some parts of this
memory are for general purpose usage to store our variable data, whereas some parts are reserved for inter-
nal usage of the microcontroller. These specific locations, that have special meanings for the microcontrol-
ler are called special function registers or SFRs.
Each SFR has a specific function and affects the operation of the microcontroller. Some of these registers
control the overall function of controller whereas others are associated with specific devices inside the con-
troller and affect their function. General purpose registers can be Options register, or even PORTS. Specific
registers like ADCON registers are meant to affect the functionality of analog to digital conversion module.
A sound knowledge of these registers and their specific bit functions is mandatory for an effective applica-
tion development and get most out of the microcontroller. High level programming languages, and compil-
ers like MikroBasic manage many of these registers in background, allowing us to give commands in easy

to use commands. Sometimes however you need to manipulate these registers yourself. The functions and
detailed descriptions of these registers are best described in the datasheet of your particular controller.
How to use SFRs
Microcontroller has lot to offer, it has a number of special function registers, and each register has a number
of bits. A 0 or 1 in a particular bit location is going to modify the behavior of microcontroller. If these bits
are not properly set, microcontroller may not behave as you want it. One fortunate thing is that these regis-
ters have been given names, which to some extent give us a clue as to its functions. Then each applicable
bit in a SFR is also given a name, this further facilitates its usage.
MikroBasic has gone a step ahead to further facilitate us, by defining these registers as variables. You can
treat them just like variables, even individual bits have been given names, according to the datasheets. Thus
Beginning PIC Microcontroller Programming / 41

if datasheet says there is a register named, OPTION_REG and it has bit 7 named RBPU. This bit affects
internal pull-up resistors on PORTB pins. A value of 1 at this bit will turn this feature off, and a value of 0
will turn it ON. MikroBasic has named this bit as NOT_RBPU . You can access this bit by writing OP-
TION_REG.NOT_RBPU = 1
This will disable Pull-Up resistors on PORTB. If you want to see the declarations for your microcontroller
that MikroBasic has defined, just right click in editor window and select Declarations. Or just press Ctrl +
D. We shall talk about various special function registers and their bits where required.
It is however not possible to discuss and use each and every SFR in this book. You must therefore go
through the appropriate modules relevant to your project in the datasheets. Some of these register names are
same through the series of PIC microcontrollers, others however have been named differently in different

microcontrollers.
So the take-home message is, you must go through the datasheet of your particular controller at-least once.
Beginning PIC Microcontroller Programming / 42

Control Structures
8 Loops and Decisions

W
ell so far we have been through enough theory, by now you understand how to write a sim-
ple program, what are PORT registers, how to configure them as Input or Output and what
are special function registers. Now lets have little more fun with our LED setup. We are
now going to Blink the LEDs in different combinations and different ways to explore vari-
ous programming techniques.
First thing that we must learn is how to repeat a single, or a group of commands again and again. This fea-
ture essentially is the most powerful feature of computers. They can repeat a group of instructions again and
again. We do not have to write the instructions multiple times. This process is called a loop.
There are essentially two basic types of loops:
1. Endless loops
2. Controlled Loops
Endless loops invariably go on repeating something continuously. No condition has been described to end
this loop. Although they are commonly used with main program, to keep the program running it is better to
have a mechanism to exit the loops.
Using Label and Goto Statement
A label to indicate location of a program instruction and Goto are the most primitive methods used to

main:
' Main program
TRISB=0
AA:
PORTB=255
delay_ms(1000)
PORTB=0
delay_ms(1000)
goto AA

end.

make a simple loop.


Notice the Line Label AA: immediately before PORTB=255. and goto AA statement at end of loop. This
will essentially keep on repeating these instruction continuously.
Delay_ms()
In this code you come across a new command delay_ms(1000). This is a MikroBasic command to introduce
a delay. _ms stands for milliseconds. Since 1000 milliseconds are equal to 1 second, this delay will remain
effective for 1 second. So when PORTB=255 is executed, all LEDs turn ON, and then a 1s delay routine
goes on. During this period PORTB status will remain unchanged, so we will see LEDs on for 1s. After 1s
Beginning PIC Microcontroller Programming / 43

the next instruction PORTB=0 executes and it turns all LEDs OFF. Again there is a 1s delay after this to
keep the LEDs OFF. And then goto statement transfers control back to AA and then PORTB=255 executed
again. In one loop cycle, the LEDs turn ON for 1s and turn OFF for 1s. This whole sequence is repeated
again and again endlessly due to Goto statement. So we have an endless loop.
Notice in this program we are using a deley_ms(1000) twice. This is not a good programming practice, as
compiler will generate the same code twice. As we previously talked todays programming practice encour-
ages to eliminate this. We can therefore define a Procedure that will have this delay function. In our main
loop we will call this procedure twice.

program Blink

' Declarations section


Sub procedure Delay
delay_ms(1000)
return
end sub

main:
' Main program
TRISB=0
AA:
PORTB=255
Delay
PORTB=0
Delay
goto AA
end.

A procedure and function, is a full self contained code that must be placed in declarations section before the
main: label.
This is now in good programming practices format. Although functionally same, I just wanted to show you
that there are number of ways to achieve the same result. However in order to be recognized as a good pro-
grammer you must learn and tune yourself to adhere to the best practices. We will further improve this
thing as we get along.
Controlled loop
A controlled loop has some mechanism to exit from the loop. This mechanism is based upon certain condi-
tions that are changing during the loop cycle. The loop is supposed to continue as long as the condition is

main:
' Main program
dim x as byte
TRISB=0

CC:
x=0
Beginning PIC Microcontroller Programming / 44

AA:
if x=5 then goto BB
PORTB=255
Delay
PORTB=0
Delay
x=x+1
goto AA
end if
BB:
Delay_ms(5000)
goto CC
end.

evaluated as true. When the condition is evaluated as


false, the loop will terminate. Let us modify the above
program, to Blink the LEDs 5 times with a delay of 1s.
After that there is a delay of 5s and the cycle repeats.
We have to use x as a counter, to count the number of
times the blink routine has been repeated. Every time
the cycle is completed we increment its value by 1. Fi-
nally when the value reaches 5 we exit from the loop,
make a 5 second pause and reset the counter back to 0
and then repeat the entire thing. This program has two
loops. One is controlled loop, and the other is endless
loop.
We can construct this loop in a variety of ways, either
testing for the condition to be true or false, checking
condition at beginning or end of loop. In an case the
flow of program is managed by labels, and goto state-
ments. Such a program very quickly becomes so much
complicated that it becomes hard to follow where the
program is leading too. This kind of program with so
many goto statements is called a spaghetti code.
Structured programming is the only way to reduce this
mess. In structured programming the loops are con-
trolled by specific statements that define the structure
and conditions for the loop.
There are two basic types of structured loops.
1. Those in which a group of code is to be repeated a
finite number of times. The control loop as in our
example.
2. Those loops in which the number of times a loop
will repeat is not known at the time of program-
ming, but a condition has been defined to be moni-
tored to terminate the loop. For example to repeat a
cycle, till a key is pressed. Now when the key will
be pressed, we dont know. The cycle might repeat
Beginning PIC Microcontroller Programming / 45

1 time, or 100 times, or may be could not repeat even once, because the key was already pressed.
MikroBasic therefore provides two most commonly used structured looping mechanisms.
WhileWend Loop
While loop is a very commonly used construct to repeat a group of statements. The Basic structure is:
While <test condition>
Statements
Statements
Wend
The Test condition is anything that evaluates to True or False. The loop tests this condition every time, and
if condition is true the entire cycle is repeated, when the condition is false, the statements of loop body are
ignored and program execution continues below the wend statement. The Wend statement marks the end of
while body.
An endless loop can be very easily constructed by using a condition that is always evaluated to be true.
MikroBasic has a reserved word TRUE that can be used in place of this condition. Before demonstrating
the use of While Loop, I would like to introduce the For Next Loop, so that both are demonstrated together.
FOR NEXT Loop
For Next loop, is similar to While loop, but there is no test condition to be evaluated. Instead it has a
counter, and the loop statement test internally if the counter has reached its end point. Since the Looping
mechanism automatically manages the counter, the counter variable should not be modified by your code
within the loop body. You can use the counter variable to read its value, but not modify it.
The structure of this loop is:
For Variable = start TO End
Statements
Statements
Next Variable
Since the control of loop is through the counter the variable must be numeric and must be declared before
program Blink

' Declarations section


Sub procedure Delay
delay_ms(1000)
return
end sub

main:
' Main program
dim x as byte
TRISB=0

While True
For X = 1 to 5
Beginning PIC Microcontroller Programming / 46

PORTB=255
Delay
PORTB=0
Delay
Next x
Delay_ms(5000)
wend
end

use.
Now lets Re-Write the above program, using structured Loops.
As you can see the code has become more easy to read and follow, its more logical now. MikroBasic IDE
further facilitates you by drawing lines, to show the body of loop, and if you click over lets say While, it
will highlight its corresponding Wend, wow thats wonderful.
There are number of other things about these loops to talk about, but I hope we shall talk about things as
and when need arises. Only then those things get highlighted.
One final thing, before we conclude this section, is the repetition of delay_ms(5000). Although the first
delay was of 1 second and this delay of 5 seconds, but the code of delay mechanism is being repeated. We
can eliminate this by making our Delay routine more flexible. Instead of fixed 1s delay, lets pass it on a
parameter, that we want this much delay, and the procedure should adjust itself accordingly.

program Blink

' Declarations section


Sub procedure Delay(dim t as byte)
vdelay_ms(t*1000)
return
end sub

main:
' Main program
dim x as byte
TRISB=0

While True
For X = 1 to 5
PORTB=255
Delay(1)
PORTB=0
Delay(1)
Next x
Delay(5)
wend
end.
Beginning PIC Microcontroller Programming / 47

The delay_ms() is not a library function, instead it is a macro, and it expands itself where it is used. More-
over the delay time, is a constant and you can not replace it with a variable. The second delay mechanism is
vdelay_ms() function. This is a library function and you can pass it on a variable value. Notice the Proce-
dure definition, Now after procedure name there is a Parameter, t, which is supposed to be byte sized. We a
assume that a number will be passed to this routine that will be seconds, the routine passes on milliseconds
by multiplying this parameter with 1000 to vdelay_ms() function.
Now our final version of this program, is fully compliant with standard programming, it has structured
loops, and procedure calls with parameters.

There is yet another looping statement, called do Loop Until. The construct is like:
Do
Statements
Statements
Loop Until <Condition>

The loop will continue until the condition is true. The difference from While loop, is that the condition is
tested after the statements are executed, so the statements are executed at-least once.
Decisions
Just like loops which allow us to repeat selected statements, another important area of program control is
selective section of certain statement. This implies that we can have two different scenarios at a given time,
and the program has to decide which path to choose,
and therefore execute one set of statements and ignore
other set. Almost all programming languages allow this
functionality. MikroBasic implements this with an IF
Then Else construct. This construct has many formats,
but here we shall talk only about simple constructs.
IF Then End If
This is the simplest construct, where a test condition is
tested. If the test condition evaluates to TRUE then a
group of statements are executed, and after that the pro-
gram continues, otherwise these statements are by-
passed, and the program continues after these state-
ments.
Now there should be a way to inform the compiler the
boundary of statements to be executed in case the con-
dition is true. This is called IF Then Block.
IF x > 100 Then
Turn LED1 ON
End If
Statements
Statements
So in this construct specific action is taken only if condition is true. No action is taken if the condition is
false.
Beginning PIC Microcontroller Programming / 48

Second type of construct is, If Then Else End


If.
IF Then Else End If
In this type of construct two types of code are
provided. Only one of them will be executed,
depending upon the condition. If the condition
is evaluated to be true, Then the code following
Then is executed, till the Else statement is en-
countered. The code execution stops here and
jumps to below the End if to continue rest of
the program.
In case the condition evaluates to false the other group of code is executed. This part of code block begins
after the Else keyword, and continues down to End if.
If X > 100 Then
Turn Led1 ON
Turn Led2 Off
Else
Turn Led1 Off
Turn Led2 ON
End If

Statements
Statements
In any case the program will then take the path below End if to continue.
You can use the same construct to do nested Ifs. If located within another If.
Beginning PIC Microcontroller Programming / 49

There is yet another construct to facilitate multiple Ifs. When a number of different tasks have to be per-
formed based upon many different options, either you can place multiple Ifs, or use Select Case End Case
construct.
Select case operator

case "*"

res = n1 * n2

case "/"

res = n1 / n2

case "+"

res = n1 + n2

case "-"

res = n1 - n2

case else

res = 0

cnt = cnt + 1

End Select
Those of you familiar with programming like VB or C++, these things may not sound strange. Indeed it is
plus point that whatever you have learnt in other programming languages can be applied to Microcontroller
programming as well.
We shall enhance on these language features as and where required.
Now let us experiment a little with Our LED setup.
Making a Binary Counter.
This should be a simple project for you people. All we want is to implement a variable whose value should
vary from 0 to 255, then show the value on LEDs on PORTB, with 0.5 seconds delay. After the value
reaches 255, the whole thing should repeat endlessly.
Beginning PIC Microcontroller Programming / 50

Connecting
9 Output and Input Devices

S
o far whatever we have learnt was happening inside the microcontroller. We have been driving
LEDs ON and OFF, and learnt how to take decisions. The primary objective of a microcontroller
is however to control external devices. In our setup an LED is basically a symbolic representation
of an Output device. This Output device in a real world could be a motor, a relay, a solenoid a
heater or something else. So this chapter will concentrate on electronics part, as to how to connect a micro-
controller with these devices.
Assuming a decision has been made to turn these devices ON or OFF, how the microcontroller will actually
do that. Truly speaking this is not part of programming, and those of you with a background of some elec-
tronics may not find anything much unusual here. Since this book is for a hobbyist, he might have some
patchy knowledge about these things, therefore I think it is better to give him a little guidelines, so that he
can easily hook-up his projects with real-world control systems.
There can be a number of output devices each having their own requirements. Broadly speaking we can say
there are devices that have their own built in driver circuits, and they only need an interfacing signals, like 0
or 1. Such devices can be directly connected to your controller I-O lines, with a Ground common. I hope
everybody understands that when two different power supplied devices are connected, the ground must be
connected together. There is no need to connect positive supplies.
Driving Heavy DC Load
DC load without an electromagnetic influx are simplest and
easiest to drive. Such load can consist of a Bulb, A group of
LEDs to be driven together as one piece, a speaker or a
buzzer etc. As previously said microcontroller Pins can give
a maximum 25mA current. This current is sufficient to drive
a transistor. The transistor here will act as a switch, Either
the base will be High or Low, there is no in-between state, so
transistor will be either fully saturated and conduct with
maximum current possible for its design, from Collector to
Emitter or vice versa.
This is the simplest driver circuit. Using an NPN transistor a
logic 1 on base through a resistor, will turn the transistor ON,
and current will flow from LED or some other device. The
choice of transistor will then depend how much current will need to flow to drive the device. Commonly
used transistor is 2N3904, this can handle a current up to 150mA. For higher current loads you may find
Darlington pair power transistor more useful. TIP120 is most
commonly used for this purpose. Even better would be
MOSFET transistors. They are purely silicon switch, they do
not have in-between states and very low internal resistance
once they are ON. Make sure the MOSFET you use is logic
level compatible. That means it can be driven from 0-5V
some require more volts to turn them ON. Secondly if you
are driving them directly through your microcontroller out-
put pin, as in Bipolar transistors, check the MOSFET data-
sheet if it can be driven safely by microcontroller supplied
25mA current. The switching speed depends upon gate cur-
rent. It therefore more safe to drive the MOSFET through a
Beginning PIC Microcontroller Programming / 51

small transistor. Using this circuit you can even use MOSFETs
requiring high gate volts.
Driving Inductive Load
Inductive loads are devices that have a coil and an electromag-
net for its function. This can be a relay, a DC Motor, A sole-
noid or things like that. What makes this situation a little bit
different is that when current flows through the coil, a mag-
netic flux is produced that is present in the core of coil. When
the power is disconnected, the coil gets re-energized through
the magnet flux in core, and produces a high voltage spike.
This high voltage spike can damage the transistor, or MOS-
FET. Therefore a protection Diode is required for these de-
vices.
Darlington Pair Transistor
This is two transistors connected together so that the current amplified by the
first is amplified further by the second transistor. The overall current gain is
equal to the two individual gains multiplied together.
This gives the Darlington pair a very high current gain, such as 10000, so that
only a tiny base current is required to make the pair switch on.
A Darlington pair behaves like a single transistor with a very high current
gain. It has three leads (B, C and E) which are equivalent to the leads of a
standard individual transistor. To turn on there must be 0.7V across both the
base-emitter junctions which are connected in series inside the Darlington pair, therefore it requires 1.4V to
turn on.
As such there is no need to use a Darlington pair with microcontrollers where the output volts and current
are sufficiently high. The Darlington Pair can be made yourself, using a low power and a high power tran-
sistor or available in a package, like TIP-120.
ULN2803 Darlington Array
Driving DC loads is so common with microcontrollers
that it really becomes very difficult to make transistor, or
MOSFET circuits for every load to drive it. For really
high loads, like Motors, or Solenoids requiring more
than 2Amps there is no choice but to use Power transis-
tors or MOSFETS with good heat sinking.
For ordinary loads, up to 500mA, we have an integrated
circuit that contains 8 units of Darlington pairs. These
are easily interfaced with Microcontroller I-O Lines.
The outputs have protection diodes as well, so you can
use them with inductive as well as non-inductive loads.
The load must be connected to positive supply, it can be
anything upto 50 Volts. The ground is connected through ULN2803 output. The common of diodes, (pin
10) Must be connected to positive of supply used to drive the load. The
GND must be thick wire, or strong enough to handle the current flow.
We shall be using ULN2803 where a load more than the capacity of an
ordinary transistor needs to be driven.
Each channel of ULN2803 can handle up to 500mA of current. If more
current needs to be handled, two channels can be connected together to
share the current load. The IC is available as standard DIP package and
does not need heat sinking.
Beginning PIC Microcontroller Programming / 52

Handling AC Load
AC Loads are usually handled through Relays, they do a good job, in isolating the microcontroller circuit
from the AC Circuit. This is usually OK for smaller loads, but for higher loads the contacts making spark
can find high frequency interference to the microcontroller. Most people tend to isolate the relay from mi-
crocontroller circuit using Opto-isolators.
Opto-isolators or opt-couplers are small Integrated cir-
cuit like chips that contain an LED and a photo diode
inside. Thus when a microcontroller pulse turns the in-
ternal LED ON, the photo-diode starts conducting and
gives a pulse at output. This pulse can then be used to
drive the transistor, or ULN2803 etc to drive the Relay.
The power supply and even ground of the driving cir-
cuit is kept separate.
Similarly optocopulers can be used to get input data
from sources where volts are not compatible with TTL
levels (0-5V)
This will isolate the high voltage, and high noise input
system from the main microcontroller system.
Remember Microcontrollers do not tolerate electrical
noise very well. Such noise is a common issue in indus-
trial applications. Opt-Isolators are therefore frequently
used at both input and output levels in industrial applica-
tions.
TRIACs
Triacs are sort of solid state devices, that can be used to control AC devices. They are however not safe to
use by a beginner, therefore I shall not go into details, or encourage you to use them. Even when using re-
lays for AC load, make sure you have taken all the necessary precautions to avoid an electro shock. For
more information see this video:
http://www.youtube.com/watch?v=n2f9u2xI624
They are being used in AC Dimmers, and other AC motor speed
control circuits.

INPUT Devices
There are number of Input devices, but basically they all have similar Basic plan. Broadly speaking there
are two types of Inputs:
1. Analog
2. Digital
We shall talk about specific issues of these various types in appropriate sections, here I would like to give
you a Basic understanding as how to setup your hardware to interface with these types of data.
Input has to generate an electrical signal for the microcontroller to appreciate it. For Digital Inputs, these
signal must be within 0-5V range. More than this voltage is going to damage the microcontroller. In case
the input device is not TTL compliant, you must take appropriate steps to make it 0-5V range. How to do it,
we shall discuss it in a separate section.
Beginning PIC Microcontroller Programming / 53

Active High and Active Low


These two terms are commonly used to describe the Input characteristics of some devices. By Active high,
we mean that the signal for an activity is provided as a logic high, and by active low the opposite is meant.
Input pins should not be left to dangle open. For example
when a switch is connected to a pin, when the switch is not
being pressed the pin is left as open. Microcontroller will not
be able to assess its state when the line is neither high nor low.
A Pull-Up or Pull-Down Resistor is usually connected with
the pin to keep it high or low in case Input is not there. This
should be opposite to the active state of the Input. For exam-
ple if our switch is connected to ground, it means it will be
giving logic zero signal to the pin when pushed, this line must
then be pulled-up with a 10K resistor to keep the pin high
when switch is open. The value of resistor can be anything, for
a push switch, but for some other devices, as the active signal
is not very powerful, the resistor if very low will steal the sig-
nal and PIC may not see it. I therefore prefer using a 10K re-
sistor instead of 1K.
We shall be using an Active-Low configuration for push
switches in our examples. You can use either configuration in
your projects.
Using 38KHz IR Sensor
Although Infra-Red light is just like ordinary light, with a lower frequency, It needs special sensors to de-
tect. I-R signals are very commonly found in our environment as part of ordinary light. Even heat emitted
from our body has IR component. This makes use of IR signals very difficult, as stray signals from sur-
roundings may produce the signal.
Remote controls for, TV, DVD, Air conditioners and many other devices also
use IR signals. They however transmit the signal coded as 38KHz frequency.
Using ordinary sensors, then it becomes difficult to decode the signals. This
sensor has been specially made only to give you the signals sent at 38KHz
modulation.
We shall talk more about this in section on using IR remote controls, however
here I just want to mention how to connect this sensor to your PIC. The sensor
is also Active-Low. It has three pins, two for power and one for output. The
exact configuration of these pins differ among models. However the one I use
has Left most pin, pin-1 as output the middle is +5V and third is Ground. I do not use th3 330 Ohms resistor
with power supply,
rather tend to connect
directly to +5V, and
use 10K pull-Up resis-
tor. The decoupling
capacitor is not neces-
sary, but a good habit
to use.
Dealing with Non
-TTL Inputs
As previously men-
tioned your Microcon-
troller would expect
the Input to be TTL
compliant. This means
Beginning PIC Microcontroller Programming / 54

the signal will be either 0V or 5V. Anything more than 5V can be damaging. In case you have industrial
grade input, which is usually around 24V, you have to scale it down.
Using the formula given you can calculate the values of R1 and R2 to scale down the input volts down to
5V. To calculate R1 and R2, you can fix one of them to say 10K, and then calculate the value of other.
Truly speaking, the specific values of resistors are not that important as is
their ratio. So if you have both R1 and R2= 10K this will be half divider cir-
cuit. It will scale down any input volts by half. Thus if Input voltage is 12 V
the output will be 6V.
There will be same effect if you use both R1 and R2 as 100K. The difference
will be in the input impedance and limit of current. Since our Microcontroller
Inputs do not require much current, and they only need volts, we can use
High value resistors to suit our needs. Also If the Input source has high cur-
rent capacity, the resistors should be high valued, so that impedance is high
and current flow is limited.
A 5.1V zener diode may also be introduced in parallel with R2, so that in
case Input volts exceed our calculated ones, the Microcontroller always gets
5V and no more than that.
Opt-isolators are another method of using High voltage inputs to be interfaced with Microcontrollers. This
has already been discussed earlier in this chapter.
Analog Input
This is truly said that we live in Analog world, but process in digital world. Most of the Inputs in real world
are not yes or no. Indeed they have a constantly varying factor. For example Light. There can be literally
millions of possible levels of light intensity. Its not just presence or absence of light. Similarly temperature,
there are several levels of temperature even in a given range. Some times these variations are important,
and we need to differentiate among them. Then we need to know the exact level of an input signal. This is
done by gathering analog signal and converting it to digital, Analog to digital conversion. We shall talk
more about this in Analog section, but here I would like to write a few lines as how to get this Analog data
into the Analog Input of Microcontroller.
All Microcontrollers are not equipped with built-In Analog to digital conversion. Since it is such an impor-
tant module, many PIC microcontrollers have this built-in capability. However only specific pins can be
selected for this job.
The analog Input can have varying voltage levels, as opposed to digital Input. These volts must be within 0-
5V however maximum, or we will damage the microcontroller. Before using an analog source with micro-
controller make sure its output will remain within the 5V limits.
If there is a chance of getting high spike, protect the input with a 5.1V zener diode. This is usually not the
case with sensors, that are getting power supply from the microcontroller board, or 5V. Thus they can not
give more than that. This protection however becomes important if you are using an external Analog de-
vice, with its own power supply. Note using zener diode might distort your original Input signal data to
some extent, so do take a note of it as well.
You can use other isolating circuitry like Op-Amps, or even voltage di-
viders to do that.
LM35 Temperature Sensor
LM35 and LM34 are linear scale, precision temperature sensors. They
vary their output linearly according to the sensed temperature. Since they
get power supply from your board, and the output volts are calibrated
according to the temperature, the output volts never exceed 5V. You can
therefore directly use these sensor s with Analog pin of PIC microcon-
trollers directly. We shall talk more about this in appropriate sections.
Beginning PIC Microcontroller Programming / 55

Resistive Sensors
There are many sensors that vary their resistance in response to some change in physical parameter. This
can be a light sensor, an IR sensor, Flex sensor and so on. Microcontrollers can not measure resistance di-
rectly. The sensor is dealt like an ordinary resistance, and connected to the circuit as part of a voltage di-
vider. The output voltage will then vary with varying resistance and therefore physical quantity. The value
of the resistor R will determine the range of the output voltage Vo. For best results you need a large
'swing' (range) for Vo and this is achieved if the resistor is much larger than the sensor's minimum resis-
tance Rmin, but much smaller than the sensor's maximum resistance Rmax.
You can use a multimeter to help you find the minimum and maximum
values of the sensor's resistance (Rmin and Rmax). There is no need to be
precise, approximate values will do.
Then choose resistor value: R = square root of (Rmin Rmax)
Choose a standard value which is close to this calculated value.
For example:
An LDR: Rmin = 100 Ohms , Rmax = 1M,
so R = square root of (100 1M) = 10k.
Note the response of these sensors is not linear. Therefore the output volt-
age will not change linearly with change in physical quantity. In case you
need to take precision measurements you will have to devise a calibration
mechanism.
You can also swap the positions of Sensor and R, to swap the effect of change in resistance on output volt-
age.
Current Sensing
The Analog data is not only about voltage levels, but also current levels. Unfortunately there is no direct
method available to sense the current flowing in a circuit. Hall-Effect sensors do this job, but they are not
easily available.
A suitable method is to convert the current into volts using Ohms law and then measure the volts. The mi-
crocontroller can then recalculate the current. This is done using a very small resistor, called Shunt resistor.
The shunt resistor is placed in series with the ground of source. Since Ground of PIC and source are com-
mon, we can easily measure the volts across shunt resistor. Using Ohms Law:
I=V/R (V is measured voltage
and R= 0.1) A protection diode
5.1 Z is optional, and may help
protect the microcontroller in
case current exceeds. Usually a
0.5 Ohms resistor is available in
Market, from 2W to 10W. The
wattage will depend how much
current you are expecting to flow
at maximum.
We shall make a voltage and cur-
rent meter in our projects section
and put this theory into practice.
Current sensing has many uses. It
is used to protect the circuit in
case of short circuit. Can be used
in switch mode power supplies to provide variable current source power supply.
When a DC or stepper motor is running it is drawing certain amount of current. If the motor is forced to
Beginning PIC Microcontroller Programming / 56

stop, by some obstruction or problem, the current will


rise tremendously and if sensed properly can be used to
strop the motor.
Well so far I hope enough has been said about common
interfacing issues, and the relevant hardware approach to
use. Rest of the matter then lies with the software in microcontroller.
Beginning PIC Microcontroller Programming / 57

10 Using Push Switches

I
n previous chapter you have seen how we can connect a push switch to our microcontroller. You
might recall that it can be either active high or active low, with a Pull-down or Pull-Up resistor. The
Push switch is used to inform the microcontroller a user response. In early days of electronics a switch
was hard wired in a circuit and
would therefore complete or disconnect
a circuit and affect its performance.
The duty of switch was therefore very
much clearly defined. For example a
switch to turn the filters ON or OFF
could do only this job and no other.
The function of a switch in microcon-
troller is not directly tied to a function.
This is just an Input to the microcon-
troller and the modification in function is responsibility of software.
I remember I had a digital clock, that had four push switches in it to set the hours, minutes and seconds etc.
Now I have another with just one switch, and I can set everything just using this single switch. So the
power of managing Input is in software. As you can imagine this thing can become really complicated, as
you keep on thinking the various functionalities in your project to be managed by switches. We shall how-
ever keep ourselves little simple and stick to basic functionality.
In our setup the switches are in Active-Low format, with a 10K Pull-Up resistor. The Switches are con-
nected to RA3 and RA4 lines of PIC16F819 Microcontroller. In the same board we have four LEDs con-
nected to RB4, RB5, RB6 and RB7. RB4 and RB5 LEDs have current limiting resistors of 220 Ohms,
whereas RB6 and RB7 LEDs have 1.5K resistors. This was to be done, because RB6 and RB7 are also used
for In Circuit Program-
ming, and a lower resis-
tance would steal too much
of a programming signal.
Although this will cause
these LEDs to appear little
dim, but its OK to have the
feeling, all we need to see
is the presence of logic 1.
You can easily drive any
other device, through these
1.5K resistors, indeed we
use almost 4.7K resistors to drive a transistor.
Since our board has two switches we shall be mainly playing with RB4 and RB5 LEDs. Since our switch is
connected in Active Low configuration, with a Pull-Up resistor, our microcontroller will see this pin at logi-
cal high level when switch is not being pressed and at logic low level when switch is being pressed.
program Blink

' Declarations section


Symbol LED1 = PORTB.4
Beginning PIC Microcontroller Programming / 58

Symbol SW1 = PORTA.3


main:
' Main program
TRISB.4 = 0 'PORTB.4 is Output
TRISA.3=1 'PORTA.3 is Input
ADCON1=7 'Turn Entire PORTA as Digital
LED1=0 'Turn LED Off Initially
while true
if SW1=0 then
LED1=1
delay_ms(200)
end if
wend

end.

Push switches are available as, having two or 4 legs. Truly speaking there should be only two legs. 4 legs
however makes it more stable mount. The four legs are actually two sets of 2-legs. Secondly switches are
available as normally open and push to close, as well as normally closed and push to open.
Debounce Issue
The switches are mechanical devices, when the contacts meet the produce a sort of connect-disconnect se-
quence many times, due to irregularities, dust and impurities in the contacts. These small spikes of signals
can be misinterpreted by microcontroller as many repeated pushes on the switch and therefore the program
might misbehave.
Several hardware and software level solutions have been proposed for this problem The simplest is to have
a 0.01uF capacitor with switch output line. This will tend to buffer the noise a little bit. We shall tackle this
issue with software however. So what we do is on first detect that switch has been pressed, we put the con-
troller in a small wait state, something like 200mS. This also serves as the opportunity for user to release
the switch. If this time period is very small, the user has pressed the button, and has not yet released it, and
controller after completing the job, again sensed it that switch is still down.
There are literally hundreds of techniques to handle these issues. For Now lets get practical, and write a
simple program that should read the switch at RA3 and Turn The LED ON.
The code is simple, but has few strange things, and I think this is the best place to clarify these. First we
have used symbol LED1 and SW1 to define the PORTB.4 and PORTA.3 (RB4 and RA3). This will help
later in code to write the meaningful words instead of writing register names and pin names etc. Then we
have set TRISB.4 = 0 . This time we have specifically set only RB4 as output. Although we are not using
rest of the PORTB, but its a good practice only to set what is required.
Next we have set TRISA.3 = 1, you might remember we talked about TRIS registers. A 0 in bit makes that
pin Output and a 1 in the bit makes corresponding Pin Input.
ADCON1=7 This is something new. Its good to talk about it, rather than skipping. 16F819 has 5 Analog
channels, also called AN0, AN1 AN4. If you look at the pin diagram of 16F819 you might notice that
these Analog channels are sharing the RA0..RA4 pins. Since we want to configure all these pins as digital,
as we are not going to use the analog features for now, we have to tell the microcontroller to turn analog
features on these pins off, and connect the pins as digital to PORTA register. By default these pins are set as
analog. If you look at the datasheet of PIC16F819, and browse to Analog section, it has two special func-
tion registers (ADCON0 and ADCON1) that affect the functionality of Analog Module.
Here is part of the table showing various settings for these pins. D indicates the pin to behave as digital, and
Beginning PIC Microcontroller Programming / 59

A indicates it will behave as Analog. There are 8 bits in ADCON1 register, the lower 4 in various combina-
tions describe how the pins will be set. The left most column says this setting. If lowest 4 bits are set as
0101 (decimal 5) then RA0 and RA1 will be Analog, RA2 Digital, RA3 again part of analog system, RA4
will be digital. Similarly if these bits are set as 011x (x indicates this bit is ignored in this case so it can be
1, or 0 does not matter). So if we set it as 0111 (decimal 7) or (0110 decimal 6) both will cause all Ra0 ..
RA4 as digital and non-of these pins will act as Analog.
We shall talk more about it in Analog section, but it was important to clarify it here why we used AD-
CON1=7 This will set the higher 4 bits as 0 as well, but since we are not using analog module, they become
un-important.
So in all our programs that will require turning Analog system Off in case of 16F819 we shall use this set-
ting. Keep the concept in mind, that we have to set the appropriate register bits to declare which pins we
want as analog and which as digital. In case of 16F877, or 18F452 or other controllers having more Analog
channels these settings and register names will be different. So always confirm this from the datasheet of
your controller.
Well next we turn LED OFF and have an endless
loop, and test the status of SW1 (PORTA.3). If it
is not pressed we continue the loop. When the
SW1 is found pressed, we immediately turn the
LED1 ON and give a 200ms delay, to deal with
Debounce and allow the user to lift finger from
switch. Once LED is On we do not have a
mechanism to turn it OFF, except to reset the
controller.
Now lets improve this, and add a feature to turn it OFF. This time we shall be using SW2 to Turn it OFF. I
hope you can think of this yourself, and I would appreciate that, however just for sake of completeness, I
give the code here.
Now you can well imagine, that pressing SW1 will turn LED ON, and pressing SW2 will turn it OFF. So
far so good. Now you can think of replacing the LED with some other device, like a FAN driving it through
a transistor, or a Relay to turn it ON or OFF to control a heavy load, just by pushing two small switches.

Remember we are not here interested only in making an LED glow, I know there are hundred other meth-
ods to glow an LED, the objective here is if we can control an output line we can control an external device.
Practically speaking we are dealing with individual bits right now. Reading state of two bits as witches, and
changing stet of a single output bit. Now lets say we want to use only one switch for the above task. So if
we press SW1 the LED turn ON, and when pressed again, it turns OFF. I would like you to think and make
this yourself. The solution is simple, on press of button you have to check status of LED, if it is already
ON, you turn it OFF and vice versa.
IF SW1=0 then
IF LED1=1 then
LED1=0
Else
LED1 =1
End if
Delay_ms(200)
Beginning PIC Microcontroller Programming / 60

End if

So you can see you can use two Ifs, one inside the other. First we have tested the switch, and then tested
the current state of LED, if its ON, we turn it OFF, and if OFF we turn it ON.
There is yet another thing to learn, the bit-wise operations. Many a times we have to perform operations on
individual bits, other than just turning it high or low.
These can be summarized as:
AND, OR, NOT, XOR, Shift Left, and Shift Right.
We shall talk about NOT this time. A NOT means reverse of logic. So if state is 1 NOT will make it 0 and
program Blink

' Declarations section


Symbol LED1 = PORTB.4
Symbol SW1 = PORTA.3
symbol SW2 = PORTA.4
main:
' Main program
TRISB.4 = 0 'PORTB.4 is Output
TRISA.3 = 1 'PORTA.3 is Input
TRISA.4 = 1 'PORTA.4 is Input
ADCON1=7 'Turn Entire PORTA as Digital
LED1=0 'Turn LED Off Initially
while true
if SW1=0 then 'Switch 1 Pressed
LED1=1 'Turn LED ON
delay_ms(200)
end if

if SW2=0 then 'Switch 2 Pressed


LED1=0 'Turn LED OFF
delay_ms(200)
end if
wend

end.

if its 0 Not will make it 1. Thus we can simply use this operation to turn LED ON and OFF on press of a
switch. Notice LED1= NOT LED1 The NOT operator will return reverse of LED1 status, and set this
value as new value of LED.
Just like mathematical operators, + , - , * and / for real numbers, these are operators for bits. I do not want
to overburden and confuse you here, and we shall talk about these operators more where there need arises.
Other Types of Switches
Push switches are a great way to get user interaction. They are also called momentary switches, because
they are ON for a small amount of time. Sometimes you need to make your application more dynamic, by
Beginning PIC Microcontroller Programming / 61

placing some control switches, that tend to modify the behavior of application. For example you have made
a serial device, and want to place a few switches to set the BAUD rate of communication. In simplest sce-
nario we can assume that if a particular switch is ON, the device will set its baud rate to 9600 otherwise
2400. This effect can be achieved by making a jumper switch. You can connect a jumper just like a switch
to an I-O line along with Pull-Up resistor. Now placing a jumper on this will keep the so called switch or
jumper ON and the I-O line will be Low. Now in your program you can read the status of your I-O line and
set the registers for Baud-Rate accordingly.
When many such settings need to be done, to configure your device, you can use DIP Switches.
DIP switches are available as packages containing, 2,3,4 8 or more switches. You can use individual
switch to control one function, or use their combination as a binary value to select one of the many func-
tions or behaviors in you program.
If You have a DIP-4 switch, this can represent a 4 bit number, and this can encode 16 possible combina-
tions, ranging from 0 to 15 (0000 to 1111)
Rotary BCD Switches
Rotary BCD switches are another way to get the same effect. This switch has 4 output lines and a GND.
The four output lines will code the BCD number for the selected position of switch. You will need Pull-Up
resistors with the output lines however.
The switch shown here has 10 positions, from 0 to 9. The four bits will therefore give binary number corre-
sponding to the switch position.
Lever Switches
Lever switches are yet another type that can be used to detect mechanical events, like passing some bags on
a conveyer belt.
Literally hundreds of modifications of these basic switches exist, you have to select the one that suits your

program Blink

' Declarations section


Symbol LED1 = PORTB.4
Symbol SW1 = PORTA.3
symbol SW2 = PORTA.4
main:
' Main program
TRISB.4 = 0 'PORTB.4 is Output
TRISA.3 = 1 'PORTA.3 is Input
TRISA.4 = 1 'PORTA.4 is Input
ADCON1=7 'Turn Entire PORTA as Digital
LED1=0 'Turn LED Off Initially
while true
if SW1=0 then 'Switch 1 Pressed
LED1= not LED1 'Toggle state of LED1
delay_ms(200)
end if
wend
end.
Beginning PIC Microcontroller Programming / 62

application. All however work in the same way.


Beginning PIC Microcontroller Programming / 63

11 Character LCD Display

S
o far we have been using LEDs to communicate with the user. Although they are good in some
basic projects, but projects requiring little more elaborate communication with user will require
some sort of textual display. Seven segment LED
displays are good to show numbers and to some
extend characters, but character LCDs are best for this
situation. You may or may not need the luxury of character
LCD in your final product or project, yet this is useful to
have it at-least in the prototype phase to debug, and moni-
tor the application.
In this chapter we shall be talking about character LCD
displays. They are the most popular, easy to use and find
extensive library of supporting commands in most of the
compilers. Although using them does not require a deeper
understanding of the technology and communication com-
mands, yet we shall briefly talk about this for completion
of the topic.
LCD displays are made by a number of manufacturers. Each LCD has its own controller to display the
characters and manipulate the related electronics. This controller however needs to communicate with your
controller to know what you want to display and how you want the display to behave. Naturally you will be
limited by what the host controller of LCD is going to offer and how it is expecting you to send data.
It is therefore mandatory to go through the technical datasheet of your particular LCD, in order to properly
connect and use it. Hitachi introduced long ago an LCD with a controller called HD44780. Since then this
has become a very popular controller for the LCD displays, and a number of other companies although
making their own controllers, but they are technically and functionally compatible with HD44780 LCD
controllers. Most of the commonly available LCD modules are based upon this controller. Still it is impor-
tant to confirm that the LCD you have is based upon this controller.
Using this standard display will eliminate a lot of fuss, to go through the datasheets and understand the tim-
ing diagrams etc. HD44780 itself is very easy to connect and communicate, indeed you will not find it very
difficult even if using assembly language. Most of the commonly used compilers, like MikroBasic, CCSC
and Proton BASIC etc have pre-built libraries of commands to use these displays.
Character displays are available as single line, two or four line displays.
Each line can have 8, 16 or 20 characters. Based upon this they are named as 16 x 2 or 16 x 4 etc. 16 x 2
means the display will have two lines of display and each line will have 16 characters.
16 x 2 is the most common display used by students and hobbyists as it has sufficient display area to show
most commonly required display information. We shall be using this 16 x 2 display in our examples, never-
theless you are free to use 16 x 4 or even 20 x 4 display if its available with you. Larger display although
good for use, and does not require different software or hardware yet due to its bulk, sometimes gets diffi-
cult to stabilize on boards. Other than that is OK with them.
HD44780 Character Display Pin Diagrams
Displays will be available in two basic styles. Most commonly used have connections available in single
line, as shown in the diagram, in others the connections are available as two rows of eight each on side of
Beginning PIC Microcontroller Programming / 64

the display. This is only difference in orientation. Once you know the connection numbers correctly, there
is no difference in connections.
HD44780 displays usually have 16 pins. Some may have 14. Actually display requires only 14 pins, two
others are for a back light. This makes the display more readable, even in dim lights. The standard practice
now is to use the ones with back light. The pins are clearly numbered as pin 1 and pin 16 as shown in this
image. Your particular display might vary a little bit, but there has to be some way to indicate the pin 1.
This LCD display can work at 5V supply. Since we are using 5V supply microcontrollers it will be simple
to connect it with these controllers.
Now lets talk a little bit about the pin numbers and functions. Although they are easy to understand, still its
better to know about them.
Pin 1: is GND and Pin 2: is +5V
Pin 3: is to provide a contrast adjustment volts. As we shall see in schematics usually a variable resistor, or
a pot is used to adjust the contrast. I have personally found that instead of using a POT, just use a 1.5K re-
sistor to connect this pin to GND and this provides sufficiently good contrast. A fixed resistor however does
not allow you to adjust the contrast. So its up to you to use the 5K POT or a 1.5K resistor.
Pin 4: is also called register select or R/S pin. This pin informs the LCD controller as to select the internal
register. The internal registers are command and data. Selecting command register will accept input from
data lines and treat them as special commands to control display. Selecting data register will treat the data
on data lines as text to be displayed. When dealing through MikroBasic we will not need to remember this
and compiler will do the switching between registers automatically for us.
Pin 5: is Read / Write or sometimes labeled as RW. When we send some data to display, this is stored in
internal memory of LCD. After the data has been displayed, even if the microcontroller starts doing some-
thing else, the LCD controller will keep on displaying the data from its internal memory. Sometimes our
program needs to read the LCD memory back, to know what is being displayed. The RW pin works in this
Beginning PIC Microcontroller Programming / 65

context. When the pin is Low we can write to the display, and when pin is high we can read from the dis-
play. Since most of the times there is no need to read from the display, so this pin is usually permanently
tied to GND.
The MikroBasic compiler however allows you to connect to an I-O line, so that if you wish you can read
from the display. This however consumes an I-O line. We shall therefore not use this feature and keep this
pin permanently tied to GND so that display is always in write mode.
Pin 6: is enable pin. A logic 1 on this pin will activate the display to accept new data. A 0 will deactivate it.
The display will however continue to display the previously displayed data. This pin must be connected to
the I-O line of microcontroller.
The compiler will automatically
generate enabling or disabling
code to display text.
Pin 7 to Pin 14: these are data
pins, named as D0 .. D7 thus it
will require exactly one byte or an
entire microcontroller port to com-
municate. If the project has
enough free I-O lines it is better to
connect the LCD in 8 bit mode.
Since most projects are short in I-
O lines HD44780 allows you to
connect either as 4bit or 8 bit
mode. In 4-bit mode you can use
only upper 4 data lines, that is,
D4 .. D7 these four bits of data
lines can then be connected to 4
bits of microcontroller, either up-
per 4 bits or lower 4. But not in
between. So a minimum us 6 I-O lines are required to connect LCD. We shall connect our display as:
You can connect them with any port line, but you got to know the connections, as we have to inform the
compiler our connections. Only then it can produce appropriate signals to display data. Data pins, have to
be on single port, but you can connect Enable and RS pins or even RW pin if you want, to any other I-O
lines.
The back light LED can be connected directly to 5V, or preferably through a current limiting 330 Ohms
resistor. Some applications even want this LED to be under the program control, So these applications can
connect the LED through a transistor, so that an I-O line can turn the LED ON or OFF.
Beginning PIC Microcontroller Programming / 66

So far you have basic information to setup the LCD hardware. The image above shows an LCD connected
on Breadboard and using PIC16F819 breakout smart board to connect.
Since our applications are getting little more hardware intensive, I shall switch over to a development board
to demonstrate things. This facilitates, that most of the hardware is already connected, and we can concen-
trate on our particular part of code. Our board is based upon PIC18F452 Microcontroller running at 20MHz
clock speed. The good news about our board is that the on-board devices like LCD, LED etc are not hard
wired to microcontroller lines. Using jumper wires we can connect and configure the hardware exactly as
we want. You can see the jumper wires connecting LCD lines with microcontroller Lines, close to them.

We have connected the LCD to PIC18F452 as below:


LCD Connection PIC18F452 Microcontroller Pin
D7 PORTD.7

D6 PORTD.6

D5 PORTD.5

D4 PORTD.4

R/W GND

Enable PORTD.3

RS PORTD.2

Make a new project in MikroBasic, by the name of LCD and enter following code.
program Lcd

' Lcd module connections


dim LCD_RS as sbit at PORTD.B2
LCD_EN as sbit at PORTD.B3
LCD_D4 as sbit at PORTD.B4
LCD_D5 as sbit at PORTD.B5
LCD_D6 as sbit at PORTD.B6
Beginning PIC Microcontroller Programming / 67

LCD_D7 as sbit at PORTD.B7

LCD_RS_Direction as sbit at TRISD.B2


LCD_EN_Direction as sbit at TRISD.B3
LCD_D4_Direction as sbit at TRISD.B4
LCD_D5_Direction as sbit at TRISD.B5
LCD_D6_Direction as sbit at TRISD.B6
LCD_D7_Direction as sbit at TRISD.B7
' End Lcd module connections
main:
Lcd_Init()
Lcd_Cmd(_LCD_CLEAR)
while true

Lcd_Out(1,1,"Hello")
delay_ms(2000)
wend

end.

Well the code looks little weird at first, with so many new keywords. Just relax, soon they will be making
sense. MikroBasic and many other languages for embedded systems give you the liberty to define your
hardware connections. This makes the program look little longer and complicated, but it gives you the lib-
erty do design the hardware as you want.
The program begins with declarations of LCD connections. MikroBasic has a built-in library to use
HD44780 LCDs. This library must be enabled in your project to use it. While making the project it asks
you to include all libraries, if you answered Yes to this the library is already selected, otherwise there is a
Library Manager tab on right side, open it and select LCD library.
dim LCD_RS as sbit at PORTD.B2
LCD_EN as sbit at PORTD.B3
LCD_D4 as sbit at PORTD.B4
LCD_D5 as sbit at PORTD.B5
LCD_D6 as sbit at PORTD.B6
LCD_D7 as sbit at PORTD.B7
LCD_RS, LCD_EN, LCD_D4 etc are global variables already declared in LCD library. You have to match
them as bits to bits of PORT register. LCD_RS as sbit at PORTD.2 maps the LCD_RS global variable to
RD2 bit of microcontroller. The sbit instead of bit is used to map a variable to SFR register. So we have
mapped all LCD connections to the PORTD bits as we mentioned in the table above.
Next we have to map the corresponding TRIS register pins to global LCD variables for direction.
LCD_RS_Direction, LCD_EN_Direction etc. are mapped to TRISD register pins. You might be wondering
why we need to tell this, as we are only going to write to these bits, so they will be output. Since MikroBa-
sic is more than what we normally do. Sometimes we have to read the internal registers of LCD in that case
these lines will be used as Inputs. That is why MikroBasic Library requires you to provide the complete
details.
You have to provide this mapping only once in the declarations section of program. After this declaration
our main program begins. The first command given here is a call to Library function, Lcd_Init() , this is
mandatory to call this function once. This will initialize all its internal connections and send startup instruc-
tions to the LCD to clear up its registers and get ready to work.
Remember I have used the word Library Function. This means that Lcd_Init() function is not as such part
of BASIC language. Just like For-Next etc. This is a call to a function, which has already been compiled.
So you can also make your own libraries of common procedures for use later in other projects. Another im-
portant point is, that if you switch from MikroBasic to MikroC for example, these library commands will
Beginning PIC Microcontroller Programming / 68

remain similar. So only compiler language will change, calling Lcd_Init() function and other functions will
remain almost same.
Lcd_Cmd(_LCD_CLEAR)
Just like LCD-Init() function the LCD_Cmd() function is used to send various LCD Specific command
codes to the LCD. These codes modify the behavior of LCD, as well as turns On or Off various features.
These codes have been defined as constants in the LCD library.

Lcd Command Purpose


_LCD_FIRST_ROW Move cursor to the 1st row
_LCD_SECOND_ROW Move cursor to the 2nd row
_LCD_THIRD_ROW Move cursor to the 3rd row
_LCD_FOURTH_ROW Move cursor to the 4th row
_LCD_CLEAR Clear display
_LCD_RETURN_HOME Return cursor to home position, returns a shifted display to
its original position. Display data RAM is unaffected.
_LCD_CURSOR_OFF Turn off cursor
_LCD_UNDERLINE_ON Underline cursor on
_LCD_BLINK_CURSOR_ON Blink cursor on
_LCD_MOVE_CURSOR_LEFT Move cursor left without changing display data RAM
_LCD_MOVE_CURSOR_RIGHT Move cursor right without changing display data RAM
_LCD_TURN_ON Turn Lcd display on
_LCD_TURN_OFF Turn Lcd display off
_LCD_SHIFT_LEFT Shift display left without changing display data RAM
_LCD_SHIFT_RIGHT Shift display right without changing display data RAM

_LCD_CLEAR will clear anything already displayed on screen.


Lcd_Out(1,1,"Hello")
LCD_Out() is also library function used to send text data to LCD display. The first two numbers are the line
number and column numbers on LCD where data should start displaying. The String Hello can be a con-
stant as here, or it can be a data formatted as string in a string variable. We shall use these variables later.
Rest of the program is as usual, we have given a delay, and Put the LCD_OUT function within the loop.
There is no need to place Lcd_Init() in Loop, but you can issue Lcd_cmd() as many times as you want.
To display data on LCD you have to provide the text as a string. In our example we have provide a fixed
text Hello to be displayed. However programs usually need to display the results of variables. The values
of variables can not be directly supplied to Lcd_Out() function. They have to be formatted as text in a string
type variable, and then using that string variable to display the result.
In our next program we shall make use of Conversions Library. This Library contains useful functions to
convert one type of data into another. We shall use this library to convert our Byte data into string and then
display the value on LCD.
The Lcd_Out() requires the data to be displayed completely formatted in a text string. As we had previously
discussed a string is basically an array of bytes. The end of string is marked by a special character called
Null. Practically this is binary 0 in the last byte. Lets say your LCD display has 16 characters in one line. So
we can have an string type variable having maximum length of 16 bytes. We can put smaller strings in it, in
that case the Null character will be placed at the end of smaller text data, and Lcd_Out() will display only
that part. Once data has been sent to LCD, the string variable can be used for another data.
No doubt strings can be directly stored in a string variable, but what about the variables containing numbers
in binary format? These numbers are not in text form. To convert them into text, we need to use the conver-
sion library functions. These functions accept the binary number, or variable, and convert them into textual
Beginning PIC Microcontroller Programming / 69

format including the minus sign if required. This text data can be saved into a string and displayed on LCD.
A summary of these conversion functions can be found in the help file of MikroBasic. Here I would show
only a few types and how to use them.
This program has two new things to demonstrate.
program LCD

sub procedure Display(dim Byref txt as string[16])


Lcd_Cmd(_LCD_CLEAR)
Lcd_Out(1,1,txt)
delay_ms(2000)
return
end sub

' Declarations section


dim LCD_RS as sbit at RD2_bit
LCD_EN as sbit at RD3_bit
LCD_D4 as sbit at RD4_bit
LCD_D5 as sbit at RD5_bit
LCD_D6 as sbit at RD6_bit
LCD_D7 as sbit at RD7_bit

LCD_RS_Direction as sbit at TRISD2_bit


LCD_EN_Direction as sbit at TRISD3_bit
LCD_D4_Direction as sbit at TRISD4_bit
LCD_D5_Direction as sbit at TRISD5_bit
LCD_D6_Direction as sbit at TRISD6_bit
LCD_D7_Direction as sbit at TRISD7_bit
' End Lcd module connections

dim Msg as string[16]


dim x as byte
dim a1 as integer
dim b as float
main:
' Main program
Lcd_Init()
x=100
a1 = -16000
b= 13.567
while True
ByteToStr(x,msg)
Display(msg)
Beginning PIC Microcontroller Programming / 70

shortToStr(x,msg)
Display(msg)

FloatToStr(b,msg)
Display(msg)
wend

end.

1: Use of conversion library


2: Passing Array type data to a procedure.

In this program we have declared a text string variable named, msg. This variable has been assigned a
length of 16 bytes. Since we have to call the display routine again and again, along with a pause and clear
the screen, instead of repeating these commands we have declared a procedure, named Display. This proce-
dure would accept a text data as a parameter and then use Lcd_Out() to show it. Since string data is com-
plex variable, it can not be passed as such to the procedure. This requires that instead of sending a copy of
data, send a pointer to data. This type of parameter is called ByRef (By reference). Now Txt in our proce-
dure is actually referring to the original msg variable. So be careful when dealing with parameters passed
by reference. They are referring to the original data, and not private copy of the procedure.
Next we have declared three different types of numeric variables, and assigned them some values. There is
a different conversion function for each numeric type, so used them separately to convert into text, and then
display the message.
String Concatenation
Sometimes two strings need to be merged as one, this is called string concatenation. In mikroBasic this is
simple, just place + operator between the strings, and they are concatenated together as a new string.

Dim string1 as string[6]


Dim string2 as string[10]
Dim string3 as string[20]
String1=Hello
String2= world
String3= string1 + string2

String3 will now contain hello world


You will come across a few other library functions to display text. They are self explanatory, like in
Lcd_Out() you have to provide the cursor location. In Lcd_Out_Cp() the data is displayed at current cursor
position. Similarly Lcd_Chr() will display a character. Remember character is only one byte, and it is not
terminated by a Null. Thus it is not a string.
Number of string manipulation functions are available under strings library.
LCD Memory
The discussion so far is more than enough to use the LCD display in your projects. However an LCD dis-
Beginning PIC Microcontroller Programming / 71

play has more to offer. A knowledge of its internal working, can be helpful in writing more powerful appli-
cations.
LCD display contains three memory blocks:
DDRAM Display Data RAM;
CGRAM Character Generator RAM; and
CGROM Character Generator ROM.
DDRAM Memory
DDRAM memory is used for storing characters to be displayed. The size of this memory is capable of
storing 80 characters.

As you can see in the above figure the internal display memory is 80 characters, however 16 charac-
ters in each line are connected to the display. Thus a message longer than 16 characters can be
stored in the internal memory. To display the other parts of memory there is a command for LCD,
called shift right and shift left, they will scroll the display memory. Refer to LCD_Shift_Left command in
the commands table.

CGROM Memory

CGROM memory contains a standard character map with all characters that can be displayed on the
screen. Each character is as-
signed to one memory loca-
tion:
The addresses of CGROM
memory locations match the
characters of ASCII. If the pro-
gram being currently executed
encounters a command send
character P to port then the
binary value 0101 0000 ap-
pears on the port. This value is
the ASCII equivalent to the
character P. It is then written to
an LCD, which results in dis-
playing the symbol from the
0101 0000 location of
CGROM. In other words, the
character P is displayed. This
applies to all letters of alphabet
(capitals and small), but not to
numbers. As seen on the previ-
ous map, addresses of all digits
are pushed forward by 48 rela-
tive to their values (digit 0 ad-
Beginning PIC Microcontroller Programming / 72

dress is 48, digit 1 address is 49, digit 2 address is 50 etc.). Accordingly, in order to display digits correctly
it is necessary to add the decimal number 48 to each of them prior to being sent to an LCD.

What is ASCII? From their inception till today, computers can recognize only numbers, but not letters. It
means that all data a computer swaps with a peripheral device has a binary format even though the same is
recognized by the man as letters (the keyboard is an excellent example). In other words, every character
matches a unique combination of zeroes and ones. ASCII is character encoding based on the English al-
phabet. ASCII code specifies a correspondence between standard character symbols and their numerical
equivalents.

So all characters that makeup the ASCII dataset includes normal text characters, along with commonly used
special characters like, comma, period and percent sign etc. The Font and therefore style is all defined in
the internal map of these characters as 5x8 matrix of a display.

CGRAM Memory
Apart from standard characters, the LCD display can also display symbols defined by the user itself. It can
be any symbol in the size of 5x8 pixels. RAM memory called CGRAM in the size of 64 bytes enables it.
Memory registers are 8 bits wide, but only 5 lower bits are used. Logic one (1) in every register represents a
dimmed dot, while 8 locations grouped together represent one character. It is best illustrated in figure be-
Beginning PIC Microcontroller Programming / 73

low:
The characters are not stored permanently in LCD memory, therefore they have to be created every time the
program starts. There is a special command for LCD that will define the CGRAM Address to store the
character.
First we have to generate the character map. And convert each character image into set of numbers. Fortu-
nately MikroBasic has a tool to do this
for us.
Just click over the menu item tools and
then select LCD Custom Character.
This window will popup. Showing a
matrix of 5 x 8 squares. This entire set
represents an LCD character. Now
click on the desired boxes to make a
character of your choice. In the
CGRAM address select the Character
Number in CGRAM row. And press
Generate. It will generate a small code
that you can use to stuff the character
map into CGRAM.
Once the character or characters have
been placed in CGRAM, you can use
the LCD_Chr() command to display the
character.
To stuff the CGRAM with character
map, you have to send the command (0x40) + the address of first row of character map memory. And then
send a series of LCD_Chr_Cp() command to write one byte at a time.

program CustomCharacter

' Declarations section


const character as byte[8] = (4,4,4,10,17,10,4,4)

sub procedure CustomChar()


dim i as byte
LCD_Cmd(64)
for i = 0 to 7
LCD_Chr_Cp(character[i])
next i
end sub

main:
' Main program
Lcd_Init()
CustomChar()
Lcd_Out(1,1,"Hello")
LCD_Chr(2,1,0)
end.
Beginning PIC Microcontroller Programming / 74

I have generated most of this code through the Custom Character Tool, but modified a little to make it little
more practical. First an array of 8 bytes is generated to represent the character map. Then a procedure was
defined to stuff the CGRAM with custom character. The Lcd_Cmd(64) is equivalent to 0x40 as I already
said. Since this character is going to be 0th character its starting address would be 0. so 0x40+0 = 0x40
command is sent. After that using a loop all the 8 bytes are
stuffed.
The main program, first call Init_Lcd() function and then calls a
regular print out of hello. The line:
LCD_Chr(2,1,0)
Displays the custom character at line 2, position 1. Since character map is at address 0, we use this number.
Similarly you can generate 8 custom characters and then use them to display special characters.

Extended ASCII Character Set.


The ASCII Character set is one byte long. This means it can code for 256 characters, numbered from 0 to
255. All text characters like A,B,C etc and some special characters like comm., period, and brackets etc
have been given special codes. These codes are universally accepted and all manufacturers of computers
follow these codes. The standard characters are much less than 256, and therefore lots of codes have not
been specified by ASCII. Manufacturers of computer and LCD displays are free to assign these codes to
special graphical characters of their choice. To display a character by its code, use this command:
Lcd_Chr(1,1, n)
Where 1,1 are the line number and column on LCD and n is the code of character. A 65 for example will
display A and 66 will display B. Special characters will be defined in your LCD from 128 upward to
255. The exact characters will depend upon the manufacturer.

program CustomCharacter

' Declarations section

main:
' Main program
dim i as byte
dim msg as string[5]
Lcd_Init()
LCD_Cmd(_LCD_CURSOR_OFF)
While true
LCD_cmd(_LCD_CLEAR)
for i=160 to 255
BytetoStr(i,msg)
LCD_Out(1,1,msg)
Lcd_Chr(1,7,i)
Delay_ms(500)
next i
Wend
end.
Beginning PIC Microcontroller Programming / 75

The above program will loop through codes 160 to 255, and show you the character display for each code.
The table above shows this as well, but as I said exact characters displayed will depend upon manufacturer.

Where the LCD Declaration Code Gone?


As we had previously discussed the LCD declarations have to be defined in terms of the connections with
your board. Indeed we specifically defined those definitions in earlier examples. In these later examples
Beginning PIC Microcontroller Programming / 76

there is no such code, where has it gone?


You definitely need that code, however writing this code every time in your programs will be time consum-
ing an boring. As our hardware connections are not going to change, we have defined the code in a separate
file as a module and include this module in every project, so the same code is available to every program.

Similarly other commonly used code can be placed within modules and they are then included in the pro-
ject.
Beginning PIC Microcontroller Programming / 77

12 Seven Segment LED Display

Y
ou have seen LCD is a great tool to display data. It can display text as well as numbers and
other characters. Some projects require only to display numbers, and
to reduce the cost of project or commercial device you need to use
seven segment LED displays. This chapter will focus on how to use
these displays with microcontrollers.
Seven segment LED display has been named so, because it has 7 bars, arranged
in the form of number 8. Each of these bars is just an ordinary LED. A combina-
tion of them being ON or OFF will make a number to be displayed.
Although there are seven segments to display the number, there is another one in
fact 8th one, the dot. Dot is used to display the decimal point in case it is required.
You will find 7-segment LED modules in various sizes and number. The larger sized have more current
demanding LED or some other lighting system, thus using them directly with microcontroller is not encour-
aged. They can however be used with a suitable driver circuit, like a transistor etc.

Anatomy of a Single Digit


Let us look at the single 7-segment digit. The
seven segments are named as a,b,c,d,e,f and g.
The position of these various segments is univer-
sally defined. Thus segment a is always top hori-
zontal and d is always bottom horizontal etc.
Since each LED is a diode, so it has an anode
and cathode. One terminal of each LED is tied
together internally and brought out as Common
connection. All other terminals are brought out
as separate pins.
In case all cathodes are tied together this display
will be called 7-segment display with common
cathode. In case Anodes are tied together they
will be called Common Anode display.
It is important to know which one you have. In
case of common cathode the common terminal
will be connected to ground and all others will
be connected to the microcontroller pins, through a current limiting resistor, just as we connected LEDs in
our earlier project. Thus when the microcontroller pin will go high it will make the corresponding LED
glow. A combination of selected pins to go high and keep others low will make a certain number appear on
display.
Remember this is just an LED module, unlike
LCD it does not have its controller or memory,
so every damn thing has to be managed in your
program. Since using seven segment displays are
little more program intensive, that is why I have
included them after the LCD module. Although
Beginning PIC Microcontroller Programming / 78

simpler than LCD, but more code Hungary they are. So tighten your belts you are going to have some tough
time ahead.
So practically speaking a single digit will require 7 I-O lines of microcontroller for digit, and in case you
also want to use dot then 8 lines will be required. Although there is no since of using a dot with single digit,
but we will connect it. You will realize the wisdom later.
The pins of seven segment dis-
play are not standard, so you
have to figure out first the pins
on your module. The easiest
way is to first locate the com-
mon. And then connect all
other pins one by one to map
the a,b,c .. g and dp connec-
tions.
In all our schematics we will
only mention the segment
name, you must map them to
your particular module.
In this figure you can see that
an entire port, lets say PORTD
has been connected to the seg-
ments. So that segment a is
connected to RD0, b to RD1 and so on. Now to make number 5 we have to turn segments a,c,d,f and g ON
so our PORTD should be like: 01101101 (binary) This will turn appropriate LEDs ON and display number
5. Now this 01101101 itself is a number (Decimal 109 and hex 6D) this number is called Number Mask.
We have to map it some how with the binary number 5, so that whenever number 5 is to be displayed this
mask is sent to microcontroller port.
We have to prepare similar masks for other numbers, like 0,1,2,3,4...9. You ca well imagine even we can
make other symbols to display like A, or C etc. Our primary task here is to make you understand basics so
we are not going to complicate the issue at present.
So I assume that you have the common cathode seven segment display and connected as shown. Working
with common anode is similar, except the common pin is connected to positive supply. The microcontroller
pins will however behave reverse. A High on pin will turn segment OFF and a 0 will turn it OFF rest of
every thing will remain the same. So only your Mask will be changed, all 0s are changed to 1 and all 1s to
0. So here is a simple program to demonstrate. PortD has been declared as Output (TRISD=0) and has been

program OneDigit

' Declarations section


main:
' Main program
TRISD=0
while true
PORTD=63 ' Mask for Number 0
Delay_ms(1000)
PORTD= 125 ' Mask for Number 6
Delay_ms(1000)
wend
end.
Beginning PIC Microcontroller Programming / 79

assigned values 63 and 125 alternately with a delay of 1 sec-


ond in between. Number 63 is a mask for 0 to display, and
number 125 is a mask for number 6 to display. So this pro-
gram will alternately display 0 and 6 endlessly.
Making the Mask is not difficult, although it would be a
good practice to do it yourself, yet MikroBasic has simpli-
fied the task by providing a tool, to create masks for us.
You can use this tool to generate any mask you want.
So far the idea was to show you how we can make numbers
display on seven segment display. Now lets make things lit-
tle more professional. Practically what we want to display is
in a byte sized variable in binary format. Now we want to make a table of masks for all the digits, from 0 to
9.
program AllDigits

' Declarations section


Const Digit_Mask as byte[10]= ( 63, 6, 91, 79, 102, 109,
125, 7, 127, 111)
main:
' Main program
Dim x as byte
TRISD=0
while true
For x= 0 to 9
PORTD= Digit_Mask[x]
Delay_ms(1000)
next x
wend
end.
In this program we have declared an array of constants, named Digit_Mask. This 10 byte array contains
masks for displaying digits from 0 to 9 on a common cathode seven segment display. Thus Digit_Mask[0]
will contain mask for digit 0, and Digit_Mask[7] will contain mask for number 7. Now in our program,
whatever digit is to be displayed its mask is loaded as an index in array to PORTD. It is assumed that
PORTD is connected to seven segment display as before. Now our digit can display any number from 0-9
on a single digit 7-segment display.
Adding More Digits
Well so far its been pretty easy and simple, as it was just like turning LEDs ON and OFF. What if we want
to add another digit, so that we have a range fro 0-99. The easiest way would be to connect the second digit
to another I-O Port, say for example to PORTB and then use the same technique as before to display units
and tens. Well this method is I-O line Hungary, it will consume so many I-O lines. You will need 8 I-O
Lines for every digit added. So this method is not recommended.
Multiplexing
The solution is to use multiplexing. Multiplexing is a technique to use the same I-O lines for many different
uses. In our case we will use the same I-O Lines to send data to all the displays. In other words all our digits
will be connected in parallel to the same set of I-O lines. Thus if we have 3 digits, the segment a of all dig-
its will be connected together to one I-O line, similarly segment b will be connected to second I-O line and
Beginning PIC Microcontroller Programming / 80

so On. Naturally you must be wondering if we send number 7 mask to the I-O lines this number will be dis-
played on All digits, so how we can then display different numbers on different digits Like display 123 ?
Now consider this arrangement. Here we have four digits the segment a of all digits tied together and
brought out as one segment, similarly, b, c and so on. The tricky part is in common connection. If we are
using common cathode display, as we did in previous examples, we connected the common pin to ground
connection permanently. This time instead of connecting the common pin to ground directly it is connected
through an NPN transistor. The four inputs of transistors are connected to the microcontroller. This will
certainly need another 4 I-O lines. When Transistor T1 is activated and all others are off whatever mask is
present on data port, will be displayed on SEG1 display. Although same data will also go to SEG3, SEG2

and SEG4 but since their transistors are OFF they will not show the data. They will show nothing. ThenT2
is activated and new Mask is set on data port, the second digit will be shown, and this time on SEG2, all
others will be OFF.
The Key point in this technique is to enable each digit one by one, and changing the display mask every
time. This will show the digits one at a time. Thus if we send 0123 as 3 then 2 then 1 and then 0 activating
T1 when 3 is sent, activating T2 when 2 is sent and so we shall be able to see the number 0123 on display,
but only one digit at a time. To display the number as one piece, we make use of an issue with our eyes.
The Persistence of Vision. Persistence of Vision or POV implies that our eyes keep an image for about 0.1
second even though the actual image is gone. Thus if second image is created within 0.1 second the two
images merge together and eye sees them as one.
To make use of POV in multiplexed displays, we simply change the display digit rapidly, before the image
of previous digit is erased from eye. So actually only one digit is displayed at a time, but our eye will see it
as one image, and read the display as 0123.
Persistence of vision has many applications in electronics, the Marquee like display messages, TV displays
etc all rely on POV.
So now lets write a code to see how we can play with four digits multiplexed. Instead of connecting 4 sepa-
rate digits together, you can get multiplexed seven segment displays as one piece. They contain 2, 3, or 4
digits, all segments internally connected together. The output connections therefore will be 7 segments, a
dot and 4 common cathode or anode whatever the case may be. We are going to use 4 digit common cath-
Beginning PIC Microcontroller Programming / 81

ode multiplexed seven segment display. You will have to find


out the pin connections for segment a,b,c,d..g and dot. Then
find out the common connections for each of the four digits.
Connect the four NPN transistors, a general purpose 2N3904 is
OK for this job.
Connect the display to PORTD for data segments. And the
transistors may be connected to PORTC. So that T1 is con-
nected to PORTC.0, T2 to PORTC.1 and so on.
Now when we turn PORTC.0 high and all other PORTC pins
low the units digit is selected. Loading PORTC with a number
mask will make that number appear on units display. Then
bringing PORTC.0 Low will deselect the units display. Turn
PORTC.1 high and tens digit will be selected changing the
PORTD number mask will display the tens digit. The same
process is repeated with all four digits and then the entire proc-
ess is repeated again and again. To keep the number displayed you have to keep this process repeated. In
case after displaying the number your program gets busy in something else, the display will go blank. We
shall talk about handling this issue when we discuss interrupts. So don't get afraid.

program Sevensegments

' Declarations section


Const Digit_Mask as Byte[10]=
(63,6,91,79,102,109,125,7,127,111)

main:
' Main program
dim Number as Word
dim i as byte
TRISD=0
TRISC=0
portc=0
Number = 5867

while true
i=Number mod 10 ' Extracts 7
PORTC.0=1
PORTD=Digit_Mask[i]
Delay_ms(100)
Portc.0=0

i=(Number/10) mod 10 ' Extracts 6


PORTC.1=1
PORTD=Digit_Mask[i]
Delay_ms(100)
Portc.1=0

i=(Number/100) mod 10 ' Extracts 8


Beginning PIC Microcontroller Programming / 82

PORTC.2=1
PORTD=Digit_Mask[i]
Delay_ms(100)
Portc.2=0

i=(Number/1000) mod 10 ' Extracts 5


PORTC.3=1
PORTD=Digit_Mask[i]
Delay_ms(100)
Portc.3=0

wend
end.

Here is a simplified code, this is not optimized, as you can see it is repeating many statements. I have delib-
erately done so to make you understand how things are going to work. The Number to be displayed has
been placed in a word sized variable, lets say it is 5867. Although it appears as four byte thing here in text,
but in a variable its in binary format, and the variable itself is two bytes long. As we have previously dis-
cussed we are going to display the numbers one at a time. So we have to devise a method to extract individ-
ual digits from this numeric variable. This is done mathematically.
5867 / 1000 = 5.867 since we are performing integer calculation, this will yield 5. This extracts Thousands
digit.
5867 / 100 = 58.67 = 58 (integer) Mod 10 = 8
Now this MOD thing is new to you. In our routine mathematics we do not use it, but it is there just like any
other mathematical operation. Mod is just like division, but instead of dividend it return the remainder.
Thus if you divide 58 with 10 the answer is 5 and remainder 8. The normal division will return 5 and MOD
will return 8.
Similarly, 5867 /10 = 586.7 = 586 (integer) MOD 10 = 6
And 5867 MOD 10 = 7
In this way we have separated all individual digits. Now we divide our code into 4 parts, one for each digit.
We first extract the unit part, put the mask value for this digit on PORTD and then set the unit digit enable
pin PORTC.0 as high. This will display the digit 7 on units display. We keep this display for 100 ms and
then turn the PORTC.0 OFF. Next we extract tens digit and do the same process, with PORTC.1. This will
display the Number 6 on tens display. We do the same process for hundreds and thousands digits. After one
complete cycle the whole thing is repeated.
If You want to see the multiplexing in somewhat slow motion, increase the delay period lets say to 1000ms
and you will see each individual digit separately for 1 second. Then decrease the delay gradually, finally
below 100ms you will get flicker free display showing entire 5867 as one number.
It is important to clarify this concept of multiplexing first. We can then improve the code by eliminating the
redundant code and using standard procedure calls.
program Sevensegments

' Declarations section


Const Digit_Mask as Byte[10]=
(63,6,91,79,102,109,125,7,127,111)
Sub Procedure ShowNumber(dim n as Word)
Beginning PIC Microcontroller Programming / 83

dim z1 as word
dim x, i as byte
z1=1000
PORTC=%00001000
for x=0 to 3
i = (n/z1) mod 10
PORTD=digit_mask[i]
Delay_ms(100)
z1=z1/10
PORTC=PORTC >> 1
next x

End Sub
main:
' Main program
dim Number as Word
TRISD=0
TRISC=0
Number = 5867

while true
ShowNumber(Number)
wend
end.
This time code has been little optimized, a little math's will reveal that the process is same. The heart of
code is procedure ShowNumber(). We have passed this procedure the number that we want to display. The
four steps to isolate digits have been broken to a single step and repeated four times using a for-Next loop.
The new thing in this code is :
PORTC= PORTC >> 1
This >> is shift right operator. It can be used with any byte, word etc. PORTC was initially assigned a value
of %00001000 so PORTC.3 is 1 and all others are 0. So this has effect of selecting thousands digit after
extracting and displaying the mask, we have shifted this by one bit to right. PORTC >> 1 will cause the
entire PORTC shifted 1 bit to right. New value will be 00000100 this will select hundreds digit and so on.
Beginning PIC Microcontroller Programming / 84

USART

13 Universal Asynchronous
Receiver and Transmitter

A
lthough a microcontroller is a world in itself, having complete set of input and output systems,
yet there are many applications that need to communicate among each other. Communication
among devices has been a difficult
task historically. It had issues of
speed and codes for special instructions etc. It is
therefore not surprising to find a large number of
communication protocols like SPI, I2C, USART
and USB etc. Each has its own merits and uses.
The one most commonly used system is called
USART. Most commonly it is called Serial Com-
munication.
The communication among computers and electronic devices is not different from human communication.
As we have to make sure the both humans understand the same language, and have significant understand-
ing as to speak and listen to each other. This mutual agreement is based upon some set of rules. In electron-
ics and computers such rules are called Protocols.
Since USART is serial Protocol, it means it will use one line to transmit data. The data on the other hand is
composed of at least a byte, which contains 8 bits. Now when one device sends these bits as a series of
highs and lows, the other device must capture them accurately. A slightest error in capturing will alter the
bit pattern and change the message. The Protocol therefore must have a mechanism to ensure this.
USART protocol forces certain rules to minimize this error. First Both machines, no matter how Fast or
slow they are running, must mutually agree the speed of communication. This is called Baud Rate or bits
per second. The standard Baud Rates have been defined in Protocol, and you are bound to choose from
them. So Baud Rate on both machines must be the same.
Second things is to define the Byte Length. Although a standard byte is always 8 bits long, yet some sys-
tems believe that the text data they are going to send can fit into 7 bits, so they will be using 7 bits to define
a byte. Again this must be set the same on both machines. Generally an 8 bit byte is used.
Third is the Parity bit. This is an additional bit sent after the byte to ensure that a logic 0, or logic 1 was not
changed while transfer over wire due to some interference. The Parity is said to be Even, Odd or none.
Even Parity means if the number
of 1s in byte is an even number
the parity bit (9th bit) will be sent
as 1. The receiving program will
then count the number of 1s re-
ceived and compare it with parity
bit received. Although not 100%
fool proof yet this has some pro-
tection. Again both systems must
agree as to what parity system
they will be using.
Each system will use one Line for
transmission and other line for
receiving data. The transmission
of one will be connected to receiving of other and vice versa. The transmission and receiving are conven-
Beginning PIC Microcontroller Programming / 85

tionally written as Tx and Rx.


Next important thing is the logic level. Some devices work on 5V supply and they assume a 4.5V as logic
1, while other devices might be working at 3.3V and would take 3V as Logic 1. Moreover the devices with
3.3V processors, may not tolerate 5V signal on their in-
put lines. So before connecting it is best to make sure
both systems have compatible supplies, and if they are
different hardware can tolerate it. For example there are
many 3.3V devices that have 5V tolerant inputs.
So if your devices have compatible supplies, that is usu-
ally the case, you can connect the pins of processors di-
rectly. In addition to Tx and Rx connections, you will
certainly have to connect the grounds of two devices to-
gether. There is no need to connect the VDD (or +5V supply) together unless you are powering from a sin-
gle source.
Remember USART is a communication Protocol, it is not a means of connection. You can connect the de-
vices directly through a cable, or establish the link
through Infra-red LEDs, Fiber optic cables, Radiofre-
quency or what not. The needs only a mechanism
through which a logic high and logic Low can be reliably
transmitted and received.
Thus you may find a number of connecting devices that
will be labeled as USART compatible. For example you
may find radiofrequency modules, that when correctly
set can be connected to Tx and Rx lines of one device
and similar module to Tx and Rx of other device. Now Our program will remain the same, as if communi-
cating through wired connections.
These days GSM and GPRS modules are available to send SMS and get global positioning data from satel-
lite. These modules, are a world in themselves. They just have Tx and Rx communication lines for interfac-
ing with your microcontroller, once connected you have to send commands to the modules and receive data
from modules.
You must be wondering how important it would be to learn the USART system, as a large number of elec-
tronic devices are using this system. So if you want your device to take advantage of these other devices
you must learn the USART protocol
A major limitation of USART protocol is that only two devices can be connected together. This system can
not be used to make one device master and two or more slaves.
This chapter is all about this communication. So lets get started.

MAX-232 Level Shift Chip


Many of you must have heard about
this chip, required to establish serial
communication. In above discussion
I have not mentioned about this
thing, indeed told you that the de-
vices can be connected directly. So
what is this chip all about and why
to use it?
USART is one protocol to manage
communication, as said previously
many different media can be used to
establish the connection. Simplest
being a wire, others include wire-
Beginning PIC Microcontroller Programming / 86

less, infra-red and so on. Earlier engineers established a connectivity protocol called RS-232. This was done
to increase the difference between logic zero
and logic 1 so that the environmental noise
may not make it difficult to differentiate.
According to this protocol a logic 1 is 12V
and a logic 0 is +12V. Whereas the micro-
controllers use TTL levels, a logic 1 is +5V
and logic 0 is 0V. If you come across a de-
vice that has label of RS-232 on serial port,
then you must place this MAX-232 chip in
between the controller and the other device.
One such device is your PC. Although
newer PCs are lacking this serial port in fa-
vor of USB, yet those with serial port have
RS-232 standards. So you can not connect
your microcontroller directly with the Serial
Port of your PC.
The MAX-232 chip does something great, using capacitors and charge pumps it can generate +12 to 12
Volts. So it is actually a two way level converter. From PC side it receives data as 12 to +12V signals and
converts them to +5V and 0V for the microcontroller. Similarly it gets 5V and 0V signals from microcon-
troller and converts them to 12 and +12V signals for PC or any other RS-232 compliant device.
Therefore if you want to establish a data communication between your PC and microcontroller device, you
have to use this MAX-232 level converter chip. In other applications where two controllers are directly
communicating there is no need to use it.
Most development boards have this chip on board to facilitate communication with PC. If your development board
allows you access to the I-O lines of microcontrollers directly, you can take connections directly and disable the MAX
-232 chip to establish direct connections. When using those lines directly it is important to isolate the MAX connec-
tions otherwise they are going to interfere.

MAX-232 does not allow very long distance of wire to communicate. Indeed the specifications mention the
capacitance of wire. Truly speaking a maximum
of 50 ft is allowed and commonly used wire is
1.5 meters long.
The MAX-232 chip has two sets of level con-
verters, 2 for Rx and two for Tx. As previously
said that serial communication only requires two
wires, one Tx and one Rx. This is the standard
and usually what is required. However in some-
what better systems another system operates in
addition to data. This system allows two systems to communicate as to the receiving system has processed
previous data and ready to accept more, or it has not yet processed previous data and can not take more.
Similarly the sending program or system will see first if the other system is ready to take data. The com-
plete serial communication will therefore need 4 wires, two for data Tx and Rx and two for control commu-
nication. This situation is called Full-Duplex mode. MAX 232 is capable of being used as full-duplex.
However since most of the times we use only communication, that is half-duplex we can also use DS275
which is very efficient and does not require exter-
nal capacitors as well.
We shall not go into details of the control system,
and concentrate basically on the communication
part. We assume that our receiver is sufficiently
fast to process all data it is presented before next
data arrives.

Hardware and Software USART


Beginning PIC Microcontroller Programming / 87

This looks strange as to have serial communication at two levels. What does it mean? It is important to un-
derstand this concept here, as it will be used in many other objects later. As you know USART is only a set
of rules, to send or receive data. It is assumed that data sent is in particular format with a start bit, data, par-
ity and stop bits. We can easily monitor any I-O line to receive data or transmit data. This should not be
difficult for a good programmer and you have the liberty to use any digital line for this purpose. The down
side of this approach is the code to implement this thing will occupy our precious program memory, and
then we might run out of memory for a longer application. Moreover this will need to be written every time
You want to use the serial communication, and a small error or mistake can take several hours to resolve.
Microchip and other manufacturers have helped the programmer by providing a hardware module inside the
controller. This module has dedicated circuitry necessary to establish serial communication. All you need is
to set its few registers and then enable this module. The code will be dramatically reduced, as all headache
of monitoring, and formatting is done by the module now. The down side however is that the module is

hard wired to certain pins on microcontroller, and now you are bound to use these specified pins for Tx and
Rx only. Secondly since these pins have other functions as well, you will have to sacrifice those functions
in favor of hardware USART.
I will show you both methods of software USART a well as Hardware USART. Generally I would prefer to
use the hardware USART if its available in your controller and if you can spare the two dedicated Tx and
Rx pins. Do not take it for granted since serial communication is so common so every microcontroller
would have hardware USART module. For example consider PIC16F819 a very good microcontroller hav-
ing 5 analog channels as well, but no hardware USART module. Thus if we want to use ADC and serial
communication, we will have to implement serial through software. Similarly PIC16F628A it has hardware
USART but no analog channels. Others like PIC16F88 have both. So the choice of controller is also dic-
tated by your requirements. The controllers with more built in modules will naturally be more expansive.
Another advantage of software USART is that you can use it along with the hardware USART. For exam-
ple our device needs to communicate serially with two different devices. We can connect one device to the
hardware USART and other to any other spare digital pins and use Software USART to communicate with
Beginning PIC Microcontroller Programming / 88

it.
Although code becomes larger when implementing software USART, it is the .hex file.
So far enough theory. Lets be practical. I hope your development board has the MAX-232 chip and a DB-9
connector to connect it to PC using a straight serial cable. It is important to have straight serial cable, some
cables have crossed Tx and Rx connections. The output of MAX should be connected to Tx and Rx pins of
your microcontroller. In case of 18 pin PIC microcontrollers like 16F628A these are Pin 7 and Pin 8 for Rx
and Tx respectively. The same pins are also RB1 and RB2. In case of 40 pin PIC microcontrollers like
18F452 these are RC7 and RC6 (26 and 25) for Rx and Tx.
So we are connecting to the hardware module connections. These pins when configured to act as Rx and Tx
will be connected to the internal USART module.
Remember Rx means this pin will receive data, so it must be connected to Tx of MAX or other device, and

Tx will transmit data and must be connected to Rx of MAX or other device. So your connections might
look like this. The pin numbers of MAX may differ in your hardware, because you know there are two sets
of communications in MAX. It depends which set is chosen by your hardware manufacturer. In any case it
does not matter as long as connections are made properly.

Initializing Hardware USART Module


The first step in using the communication system is to initialize the hardware module. Certainly you do not
need to tell the pins for Tx and Rx, but need to tell it the communication speed or BAUD rate. The module
will be initialized as:
Receiver enabled
Transmitter enabled
Beginning PIC Microcontroller Programming / 89

Frame size 8 bits


1 STOP bit
Parity mode disabled
Asynchronous operation

UART1_Init(9600)

This is the command given to initialize the communication module. This command must be issued before
using any communication commands. The command needs to be executed only once in the early part of
your program. The BAUD rate like 9600 must be given as a number and not as a variable. Since calculation
of timings according to the oscillator speed are quite complex, if such calculation is made within the pro-
gram the code becomes too big. Since most devices do not allow multiple BAUD rates, a fixed BAUD rate
like this is calculated by the compiler at compile time, and final calculated values are placed in registers.
In case you want to implement multiple speeds, you must manually calculate the values and store the final
values in your program, and load the necessary registers with those values. Using a high level language
commands like UART1_Init() saves you messing up with registers directly. Nevertheless it does not limit
you, and if you have gone through datasheet you can do so directly.
Why UART1 and not just UART? Whereas some microcontrollers may not have a hardware UART module,
others can have one and still others two modules. Thus Mikrobasic supports use of second module simply
by changing 1 to 2.

UART Read and Transmit Buffers


The USART module has two internal memory locations where all data received and all data to be transmit-
ted is stored. This is done automatically, thus when we issue the UART1_Read() command it actually reads
data from the buffer into our memory variable. Similarly when we write data to transmit it is stored in the
write buffer and USART module automatically transmits it one byte at a time.
This fact highlights two important issues. First before reading in the buffer we have to determine if the
buffer has a byte data available or not, and after reading in the byte must clear the buffer to allow it receive
more data. Similarly before writing we must check if the transmit buffer is empty and we can load it with
new byte. When USART module successfully transfers the data it automatically clears the transmit buffer.
To determine these two states MikroBasic provides us two commands.
UART1_DataReady()
This function will return a 0 if there is no data available, means buffer is empty, and 1 if it has a byte avail-
able for reading.
UART1_Tx_Idle()
This function checks the outgoing transmit buffer to see if a slot for byte is available.
Although you are not bound to determine these statuses in your program but I think it is good practice to
implement this to avoid confusion in case there is no data you are reading in garbage.
UART1_Write_Text(Text)
The UART1_Write_Text function sends a string of characters. Instead of sending one character at a time,
you can format the data as string and send as a bulk transmit. The text must be a string, and should not be
more than 255 characters long.
So lets write a simple program that should continuously transmit a text Welcome. It does not matter if
somebody is receiving it or not, it will keep on sending. This is asynchronous mode. Just like a broadcast no
matter if there is someone listening or not the relay station is transmitting music.
Beginning PIC Microcontroller Programming / 90

program UART1

' Declarations section

main:
' Main program
UART1_init(9600)
Delay_ms(200)
while True
UART1_Write_Text("Welcome")
UART1_Write(10)
UART1_Write(13)
Delay_ms(1000)
wend

end.

There are few things to notice in this program. First after initializing the module for 9600 BAUD rate, we
have placed a small delay, before beginning transmit. This was done so to allow enough time for the mod-
ule to get its things ready.
Next in a loop, we have sent a Text string Welcome. This is the text we want to transmit. The next two
lines transmit character 10 and 13. just as single bytes. Character 10 and 13 are ASCII codes for Newline
Beginning PIC Microcontroller Programming / 91

and carriage return. Thus Welcome will appear on every new line. Had we omitted these characters, the
Welcome would appear continuously, one after the other.
So far we have made a system to transmit, who is going to receive the data? Naturally your PC. So we must
have a software on PC that should monitor the serial port and receive data arriving and then display it for us
to see. Such a program is called terminal. There are many available, windows has its own called Hyper-
Terminal. Similarly MikroBasic has a tool available for this job, named UART terminal.
In the terminal window first thing that you must set is the COM port to which you have attached the cable.
Most PCs have one COM port called COM1 other may have more. If you are using USB to serial converter
that might appear as COM4 or something like that.
Next you have to make sure that the BAUD rate is set to the same as you set in microcontroller. Rest of set-
tings are usually standard as we assumed defaults in MikroBasic.
Now press Connect Button, and turn microcontroller ON. You should see the Welcome message repeatedly
appearing after one second. If You have reached this successfully congratulations, we can proceed further,
otherwise check the entire system first.
Well so far so good. You have successfully established a one way connection from microcontroller to PC.
To make this communication little bit more useful, we also need to send data from PC to Microcontroller.
UART1_Read()
This function reads the input buffer and extracts one byte from the pipeline. Truly speaking serial commu-
nication sends one byte at a time, therefore it is quite natural to read one byte at a time.

program UART1

' Declarations section


dim Receive as Byte
main:
' Main program
UART1_init(9600)
Delay_ms(200)
while True
if (UART1_DATA_Ready()=1) then
Receive=UART1_Read()
UART1_write(Receive)
end if
wend
end.

In this program the code tests the input buffer if a character is available, as soon as a character is received it
is extracted into a byte sized variable. Once the character has been received in variable you are free to test it
and use it as you like. In this program however the same character is sent back to the terminal. So whatever
is typed gets echoed back on the terminal.
UART1_Read_Text(string, delimiter, attempts)
This function is used to read in an entire string into a string type variable. The delimiter is a character or a
string that is looked for in the input stream, when this is found the input is terminated.
Getting Numbers:
Many a times it is necessary to get the numeric data from serial port. Usually the numbers typed on terminal
Beginning PIC Microcontroller Programming / 92

are sent as characters of text. So if you send 135, this will not be received a number 135, but as a string
135. So you will receive it in a text string, and then convert string to integer using StrToInt() function.
Similarly if a number is to be sent, it must be converted to string first and then sent.
So lets write a complete program to exercise all these features. We are going to write a program in which
we shall enter a number from 1 to 255, a byte sized thing, and then microcontroller will make a times table
from 1 to 10 and send it back to the terminal.

program UART1

' Declarations section


dim Message as string[30]
dim t as string[6]
dim x as byte
dim b as byte
dim a1 as byte
Sub procedure NewLine
UART1_Write(10)
UART1_Write(13)
end sub

main:
' Main program
UART1_init(9600)
Delay_ms(200)
UART1_write_text("Microtronics Table")
NewLine()
while True
UART1_write_text("Enter Number:")
UART1_Read_Text(Message,",",10)
UART1_Write_Text(Message)
NewLine()
x=strToInt(Message)
IntToStr(x,t)
Beginning PIC Microcontroller Programming / 93

for a1= 1 to 10
Message=""
strcat(Message,t)
strCat(message," X ")
IntTostr(a1,t)
StrCat(Message,t)
StrCat(Message," = ")
b= a1 * x
IntToStr(b,t)
StrCat(Message,t)
UART1_Write_text(Message)
NewLine()
next a1
wend

end.

StrCat() function is used to concatenate two strings into one. The code is not fully optimized as per stan-
dards, however it has been loosely optimized for easier understanding. You can improve upon this.
Well by now most common scenario, of establishing a two way communication have been demonstrated.
We have used the internal USART module of the microcontroller, and therefore our communication has to
be through the two dedicated I-O lines, namely Tx and Rx on your microcontroller.
Sometimes we have to make a communication system on another set of lines. This is usually because we
have two devices one connected to hardware USART and another to other I-O lines. A second possibility is
that we are using a microcontroller, like 16F84 or 16F819 that do not have the hardware USART. In this
case we implement the entire protocol in our software, and implement what is called software USART.
Truly speaking this is a big headache, to manage every aspect of communication. Fortunately most modern
day compilers free us from this mess, and provide software libraries for this communication.

program SoftUART

' Declarations section


dim x as byte
main:
' Main program
Soft_UART_Init(PORTC,7,6,9600,0)

while true
for x="z" to "A" step -1
Soft_UART_Write(x)
delay_ms(100)
next x
wend
end.
Beginning PIC Microcontroller Programming / 94

The source code, usually is almost same, with little difference, but the object code generated by compiler is
quite lengthy, and tends to eat up lots of memory. It is therefore advisable to use hardware USART where
possible, however you can use software USART if there is an indication.
Soft_UART_Init(PORTC,7,6,9600,0)
This is the most important command, it will initialize the software UART communication system. The
command requires the port name to be used, 7 and 6 are bits used for Rx and Tx , 9600 is the baud rate and
last parameter is if data is to be inverted, a 0 means non-inverted.
Notice I have used RC6 and RC7 the same bits used by Hardware UART. However this time the internal
hardware module has not been used. I could have used any two pins of a single port. Since my board had
Max232 connected to these two pins, and communicating with computer would require an intervening
Max232, so I had to use these two pins.
Communicating with devices that are TTL compliant does not require Max232. here you can directly con-
nected Tx of one board with Rx of other. There are many devices out there which use this protocol. They
can be connected to your microcontroller directly. Examples are Radio Frequency communication link,
GPS and GSM modules etc. Even you can make your own devices that are standalone devices and can
communicate with any other device that uses USART communication protocol.
Serial LCD Project
Well So far we have covered the serial communication, both hardware USART and Software USART. We
have already read about LCD and we know that interfacing with an LCD would require at least 6 I-O lines,
4 for data and 2 for control. This will be a great idea to have a serial based LCD, so that interfacing requires
only one I-O line as well as sending data should be simple and does not require programmer to understand
the communication protocol. This type of device would be even more useful to be used with compilers that
do not have the necessary LCD library to interface.
Many such LCDs are available in market, and they are pretty expansive as well. They do not have special
rocket science built-in, but have an extra controller that reads-in serial data based upon certain fixed baud
Beginning PIC Microcontroller Programming / 95

rate and it has standard LCD on the other end. The mi-
crocontroller accepts serial data and transfers it to LCD
using LCD protocol.
This is a conceptual diagram. You may omit the Max232
converter if you want your LCD to interface directly
with other microcontroller projects, or if you keep the
level converter the device can also be used with your
PC. In that case using HyperTerminal or some other
software can send data to serial port, and data will ap-
pear on LCD.
So here we would like to make the device for use with
other microcontrollers. Therefore there is no need to use
Max232 converter.
I will be using my two development boards, one to act as
serial LCD and the other to send serial data for display.

Serial LCD Board Hardware


The serial LCD board will have following hardware configuration:
PIC 18F452 @ 20MHz oscillator
16x2 character LCD with following connections:
Data : PORTD RD4, RD5, RD6, RD7
Enable: PORTD.2
RS : PORTD.3
Serial data in Rx : RC7

The RC7 is also the RX pin for Hardware USART, thus we can use the hardware library to receive data.
We will configure the USART at 9600 baud rate, 8 bit data no parity.

program Serial_LCD_Rx

' Declarations section


dim
LCD_RS as sbit at RD3_bit
LCD_EN as sbit at RD2_bit
LCD_D7 as sbit at RD7_bit
LCD_D6 as sbit at RD6_bit
LCD_D5 as sbit at RD5_bit
LCD_D4 as sbit at RD4_bit

dim
LCD_RS_Direction as sbit at TRISD3_bit
LCD_EN_Direction as sbit at TRISD2_bit
LCD_D7_Direction as sbit at TRISD7_bit
LCD_D6_Direction as sbit at TRISD6_bit
LCD_D5_Direction as sbit at TRISD5_bit
Beginning PIC Microcontroller Programming / 96

LCD_D4_Direction as sbit at TRISD4_bit


' End Lcd module connections
dim x as byte

main:
' Main program
Lcd_Init()
UART1_Init(4800)

while true
if (UART1_Data_Ready() = 1) then
x = UART1_Read()
Lcd_chr_cp(x) ' write one byte to the LCD
end if
wend
end.

OK, in this program we have simply set the LCD configuration, you have done before in LCD section. Next
we have initialized the LCD and Hardware USART. We have initialized the UART module to act as 9600
baud receiver and transmitter. There is no need to tell the pins, because hardware module will always use
the RX and TX pins on your microcontroller. In our case we are using 18F452, so its RC7 is Rx pin. Then
we have setup an infinite loop, to read the USART module, when a character byte is reached, it is read into
a variable x. this data is then passed on to LCD module as a single character byte. Hopefully data will ap-
pear on LCD.
We can use this device with any microcontroller, may it be PIC, AVR or 8051 or any other as long as that is
transmitting USART compliant data. All We need is to connect the RC7 pin of this board to the data trans-
mitting pin of the transmitting board. That pin might be hardware USART TX pin, or any other pin config-
ured to send serial data using software USART.
This simple program is set only to receive and display text data, LCD commands like Clear Screen, and
cursor movement are not taken care of. As it is said all great journeys begin with first step, once you have
established this you can expand on.

Serial Data Transmitter


Our transmitter board consists of PIC 18F4520 at 20MHz oscillator. We have connected the RC7 of LCD
board with RC6 of this board. The RC6 is Tx of Hardware USART. So we can use the hardware USART
on 18F4520 to transmit our data.

program Serial_LCD_Tx

' Declarations section

main:
' Main program
UART1_Init(4800)
delay_ms(100)
Beginning PIC Microcontroller Programming / 97

while TRUE
UART1_Write_Text("Hello World ")
delay_ms 3000

wend

end.

Notice both transmitter and receiver UART modules are configured to work at 4800 baud rate. This pro-
gram is simply transmitting the text data Hello world on the Tx pin. Which is connected to the Rx pin of
receiver board. The receiver would capture serial data and display on LCD.
Well so far its good. We have established a serial link and now our serial LCD board can be used in any
project, requiring only 1 I-O line. The receiver does not care if data being sent is from a PC, PIC microcon-

Receiver Con-
nections (RC6,
RC7)

Transmitter
Connections

Power Supply to Trans-


mitter allows common
ground as well
Beginning PIC Microcontroller Programming / 98

troller or any other. As long as data is formatted to comply with UART specifications its OK. Secondly it
does not bother if the transmitter microcontroller pin is USART Rx pin. Your transmitter board can trans-
mit data using software UART to any pin of its choice.
Why not increase the BAUD rate? Well that is a good question. No doubt we can simply configure or re-
ceiver and transmitter to 9600 or even more. I tried it on 9600 and it works fine. We must keep in mind a
few things before deciding higher speeds. As our transmitter is Asynchronous which means it is going to
send data weather the receiver has received or not. Thus at higher speeds, if after receiving one byte you
have a long process to manage the data sent by transmitter will be missed during this period. Although
USART has a small buffer to receive data while processor is busy this buffer is very small and gets over-
flow very soon. Thats why even at lower speeds, if you have a long process on receiver the data might be
lost.
In this simple example there is not much overhead, except after receiving a byte it is to be sent to LCD. The
LCD_Chr_CP() might take some time before the program can proceed to get a new byte from buffer. So at
higher speed this can be a problem. Fortunately there are solutions, but it is important to understand the
problem. If we understand the problem only then we can appreciate a solution.
In our later chapters we will make many other exciting devices that will be using serial communication.
Like we would setup an infra-red based Tx-Rx communication system between two boards. So the wires
will be replaced by IR modules, thats it. Similarly you can use sound, radio frequency visible light and
what not.
So I close this chapter with the remarks that although entire books have been written on serial communica-
tion, establishing a simple serial connection is not at-all difficult. If you go through the details of USART
module in data sheet you will notice you do even more than that.
Beginning PIC Microcontroller Programming / 99

14 Dealing With Analog Data

I
t is rightly said that we live in Analog World and process in Digital World. Conceptually analog
and digital are two entirely different fields. In analog electronics the voltage and sometimes current is
changing. There are no limits, the change can be from negative volts and fluctuate to positive side by
several hundred volts. It is the changing pattern in volts that can contain data. Indeed many sensors
are analog in nature. They sense the real world physical quantities and transform them into an analog sig-
nal, proportionate to what has been sensed.
The simplest and commonest sensor you can say is a microphone. This sensor senses the vibrations in audi-
ble range and transforms the sound intensity to a proportional analog signal. The voltage produced by mi-
crophone is very small in milli-volts or even lesser range, even in this small range it can capture and encode
the entire details of a musical concert. You can imagine hundreds and thousands of different type of sounds
being produced, along with different
notes etc. everything is reliably cap-
tured and presented to processing sec-
tion as different data by the micro-
phone.
Similarly other sensors like tempera-
ture, humidity, wind speed, angular
motion of car, height, pressure, light
and chemical (specific sensor for spe-
cific chemicals) sense their respective
physical quantities and convert them
into an analog signal.
Since microcontrollers and such de-
vices are to a large extent concerned
with managing and controlling these
physical values, it is mandatory to have
a mechanism that will accept this ana-
log data. Microcontrollers are digital devices that can process a data converted into binary number. So all
we need is a mechanism that somehow converts this analog data of varying voltage into a binary number.
Then rest of the job is easy for microcontroller to handle.
There are two basic characteristics that must be addressed in this conversion. 1: The conversion must be
reliable, that is it must give the same digital number every time a given stable signal is converted. 2: Even
very small change in voltage should be sensed as a different number. These two characteristics are techni-
cally called Accuracy and Precision.

Analog to Digital Converter


Analog to Digital Converter or ADC is a device through which a given input voltage is sampled and con-
verted into some arbitrary digital number. The digital number does not need to be equal to voltage. Say for
example if input volts are 2V the digital number produced might be 128. But it will always be 128 on an
input volt of 2V. Secondly the behavior has to be linear, so that lets say the converter increments number by
one on every 0.5V then a 2.5V would produce 129 and 3V would produce 130 and so on. Thus if we know
the rage of volts being sensed, and the resolution in terms of volts per digital number then we can calculate
the incoming volts.
Here I would not go into the very details of how it is done, but how to use what has been done for us.
Beginning PIC Microcontroller Programming / 100

This picture shows how an ADC is supposed to work. In a varying volts (Blue Line) samples are takes at

small intervals and they are presented to microcontroller as numbers. Notice if the distance between two
samples is long we are likely to miss what happened in between. The closer are sampling points better rep-
resentation of the data is obtained. Similarly on vertical scale the ability to distinguish between two small
volts, say for example a voltage of 2.5231 and 2.5232 are different and must be sensed as different number.
This is precision.
Since dealing with analog data is so frequent, microchip has incorporated an analog to digital converter
right inside the microcontrollers.
Not all microcontrollers have this
module, and some differ in the
number of channels that can be
sensed. By channel we mean dif-
ferent sensors. So if we have a
temperature as well as light sen-
sor, and we want to record their
outputs separately then obviously
we need two different channels to
read individual sensor.
PIC16F628A does not have ADC
in it, so you can not use it in situa-
tions where analog data is to be
dealt with. PIC16F819, again an
18 pin PIC has about 4 channels of
analog input. Therefore you need
to have a look at your data sheet to
see which pins are your ADC
channels. They are usually named
as AN0, AN1 and AN2 etc.
Have a look at the pin configuration of PIC18F452. Notice pin RA0 is also labeled as AN0 and so on. You
can see there are 8 analog channels in this controller, AN0 to AN7.
Now as you know RA0 pin can be used as digital as well analog, so we must configure this behavior before
using them. By default all pins with analog system are configured as analog, in order to use them as digital
we have to specifically instruct the controller that we do not want this particual pin to be used as analog and
we want to use it as digital. To do that we have to study the internal registers of analog module a little bit.
Beginning PIC Microcontroller Programming / 101

This looks little cumbersome at beginning, but once you understand it you will enjoy the liberty it gives.

So the Microchip ADC system consists of:


1: Input Pins that will get the analog voltage to be converted.
2: Analog to Digital Converter
3: Output Result in a register
As previously said that your microcontroller will have many pins that can be used as analog. The same pins
can also be used as digital. In any given project you do not need all analog pins, and indeed you want to use
some of these as digital as to read a switch or use with an LCD etc. You must see data sheet of your par-
ticular controller, but for now I am assuming PIC18F452. It has a register named ADCON1. The ADCON1
register has eight bits, out of those eight 4 bits named as CHS0 CHS3 a combination of 0 and 1 in these
bits will determine which pins will be used as analog and which are to be used as digital a detail of this
combination will be given in data sheet, we will however use only two pins AN0 as analog and keep the
rest as digital. This turns out to be 1110 in these bits.
Next important is ADFM bit again this is bit no 7 of ADCON1 register. This bit determines if the result will
be right justified or left. We will talk in detail about it later.
Once these settings have been given, you have to fire the ADC go bit this will acquire the sample from re-
quired pin, and place result in a set of results registers named as ADRESH and ADRESL.
Well the above discussion was only to give you an in sight that what happens under the hood. Fortunately
most of these headaches are taken by our compiler and we have a set of powerful commands to manage all
that.

How Much Volts


This is very important to keep your input volts within limits tolerated by your microcontroller. The PIC mi-
crocontroller can tolerate a maximum of 5V as input on the ADC pins. And minimum of 0V We shall talk
later about how to deal with higher volts and negative volts, do not worry they are all possible.
Beginning PIC Microcontroller Programming / 102

So we will take a variable resistor, or potentiometer and connect its two external connections to VDD and
GND and slider pin to AN0 pin of our microcontroller. Additionally we
will have an LCD Module so that we can see the results.
This is essentially a voltage divider. We shall confirm the Vout at POT
center pin with multimeter to confirm that.
This program will simply read in the channel 0, AN0, and display the
ray data on LCD. Adc_Read(0) is the main command that will do the
entire job, it will initialize the ADC module, and configure registers for
most common usage. The only parameter it requires is the channel num-
ber to acquire data from. There are other complex settings that we will
talk later to override the defaults set by this function.
program ADC
' Declarations section
'Lcd module connections
dim LCD_RS as sbit at RD2_bit
LCD_EN as sbit at RD3_bit
LCD_D4 as sbit at RD4_bit
LCD_D5 as sbit at RD5_bit
LCD_D6 as sbit at RD6_bit
LCD_D7 as sbit at RD7_bit

LCD_RS_Direction as sbit at TRISD2_bit


LCD_EN_Direction as sbit at TRISD3_bit
LCD_D4_Direction as sbit at TRISD4_bit
LCD_D5_Direction as sbit at TRISD5_bit
LCD_D6_Direction as sbit at TRISD6_bit
LCD_D7_Direction as sbit at TRISD7_bit
' End Lcd module connections

dim adc_rd as word


dim txt as string[16]
main:
' Main program
Lcd_Init()
LCD_Cmd(_LCD_CLEAR)
LCD_Out( 1,1,"ADC")

' Set ADCON1 register to Enable AN0 as analog and All


others as Digital
ADCON1 = ADCON1 or 0xE
while TRUE
adc_rd=ADC_Read(0)
WordToStr(adc_rd,txt)
LCD_Out(2,1,txt)
Wend
End.
Beginning PIC Microcontroller Programming / 103

Before using this function we have to set ADCON1 register to configure the desired pins as digital or ana-
log.
Here is a table from PIC18F452 data sheet analog section showing the settings of bits 0..3. various combi-
nations will select various pins as analog and digital. Like making all the bits 0000 will make all channels
Analog, and 011x (x means don't care about this bit) will make all channels digital. Since we want AN0 as
analog and all others as digital, our choice would be, 1110. Thus we have to set bit0 of ADCON1 register

as 0 and bits 1,2 and 3 as logical 1. This can be done in one step, or in individual steps, the choice is yours.
To set the bits individually:
ADCON1.0 = 0
ADCON1.1 = 1
ADCON1.2 = 1
ADCON1.3 = 1

The other method will be to OR the ADCON1 register with a number that has these bits set. 1110 binary
number is equal to 0xE hexadecimal number.
ADCON1 = ADCON1 OR 0xE
Will do the same job.
Now we can issue the Adc_Read(0) function, the function will acquire data from AN0 and return a num-
ber, we will store this number in a memory variable and then use it to calculate the analog voltage.
Before that we must understand the nature of the number returned. Well again a little bit of theory but its
important to understand this. The ADC module will estimate the amount of voltage and compare it to a
voltage called Reference Volts. For now just forget it, by default the reference volts are the VDD supply.
So we assume that the Microcontroller is getting exactly 5V. The output of ADC module will be stored in a
set of registers called ADRESH and ADRESL. These are both 8 bit registers and combined together make a
16 bit register. Whenever you are dealing with ADC, weather with PIC or some other it is important to
know the resolution. By resolution we mean the result of estimate will be stored in how many bits. In an
ADC that stores results as 8 bit data, means it can store 256 individual results. Thus a number 0 would
mean No voltage or 0V and number 255 would mean volts equal to reference volts, or 5V in most cases.
Beginning PIC Microcontroller Programming / 104

Thus it has a range of 256 steps for a range of 0-5V a simple math's would show that:
255 is 5V
1 is 5/255 = 0.01960
Therefore if ADC is recording number 2, it means the applied volts are 2 * 0.01961 = 0.03921
Thats fine. If you look closely although practically speaking the difference between 0.01 and 0.03 is quite
low but it is there and what if the value of voltage applied is 0.02V It can not be recorded as 1, nor 2. ADC
would record it as 1, until the applied volts are 0.03V. So there are number of points in between the two
steps that are likely to be missed. An increasing resolution would mean more steps and therefore better
resolution.
Microchip ADC can be configured as 8 bit, or as 10 bit. The number of possible combinations for a 10 bit
number are 210 = 1024. Thus same voltage range would be divided in 1024 steps. So 5/1023 = 0.00488.
This is a better resolution and acceptable for most applications.
Now ADC will store the 10 bit number in a 16 bit register. ANRESH will contain higher two bits and AN-
RESL will contain the lower 8 bits. We will not need to worry about it as ADC_Read(0) will return us a
number between 0 and 1023. a 0 would mean 0V and 1023 would mean volts equal to VDD or 5V.
Now if we want to convert this number into volts, just multiply it with 0.00488 and you get the precise volts
that are being applied. Now update the previous program according to this example. Here we have declared
another variable v as a floating point variable, and calculated the actual volts by multiplying adc_res by
0.00488 then displaying the result on second line of display. Now move the slider of POT and see how
volts are displayed on LCD. To confirm you can use Multi-meter to simultaneously measure the volts. Note
when you apply multi-meter it seals some power and actual volts may drop a bit.

dim adc_res as word


dim txt as string[16]
dim txt2 as string[16]
dim v as float
main:
' Main program
LCD_Init()
LCD_CMD(_LCD_CLEAR)
ADCON1=ADCON1 OR 0xE
while true
adc_res= Adc_Read(0)
v=adc_res * 0.00488
WordToStr(adc_res,txt)
FloatToStr(v,txt2)
LCD_Out(1,1,txt)
LCD_Out(2,1,txt2)
delay_ms(1000)
wend

So we have a working system to sample an analog channel and convert the number returned into represen-
tative volts.
I will just make a passing reference to various aspects of analog system, but not actually demonstrate these,
as its upto you how you explore. For most purposes only this much is necessary, that you should be able to
Beginning PIC Microcontroller Programming / 105

select which channel to use for Analog and declare others as digital, or a combination of analogs and digi-
tal, acquire analog data from a channel and convert it into representative volts.
When dealing with very small volts, a number of things have to be kept in mind, specially the stray capaci-
tance that might appear in long wires, and radio frequency interference as well as surrounding electrical
noise. These will affect the final signal reaching ADC pin.
For better accuracy it is important to provide a reference voltage on VREF pin and configure it as VREF
other than digital or analog, and also configure ADCON register to use Reference volts.
Using Analog Sensor
There are a number of sensors available that can sense environmental parameters. Some of these are just
variable resistors, that change their resistance proportional to the change in sensing parameter. An example
is thermistors, that can change its resistance according to the temperature. Similarly LDR, Light dependent
resistor will change according to light.

Note this is an extremely useful formula that you must remember.


Since our ADC can measure volts and not resistance, we need to convert resistance into volts. This is con-
veniently done by making a voltage divider. Here one of the resistors is fixed lets say 10K and other is un-
known, or your sensor. When there is change in sensor resistance there will be change in produced volts,
that are easily sensed by microcontroller. After that its just simple math to calculate the unknown resistance
and then to calculate the measured quantity.
So lets replace the Rtop with an LDR and RBottom as fixed 10K resistor. The central line Vout will be
given to AN0, and now see the effects of changing light. This kind of arrangement is used in Light follow-
ing robots. Where you make two such modules and connect them to two Analog lines like AN0 and AN1
and then quantify which sensor is reading more light, you control the speed of motors according to that and
your robot follows the light.

Linear Voltage Analog Sensors


There are a special variety of sensors, that have somewhat complex cir-
cuitry made inside them, and they process the sensed information a little
bit before handing over to microcontroller. As an example lets consider
LM35 a precision centigrade temperature sensor.
This sensor takes its power supply, senses the temperature and produces
an output voltage that is proportional to the sensed temperature in centi-
grade. The output is linear and changes regularly with temperature
change. A quick review of its data sheet shows that it produces a 10mV
per degree centigrade. Thus for a 37 degree centigrade it will produce a
370mV since 1000mV are 1V, 370MV are 370/1000= 0.370V
So if we connect LM35 to AN0 and measure the volts multiplying the
volts by 100 would give temperature in centigrade.
Beginning PIC Microcontroller Programming / 106

LM34 is its brother, with temperature calibration Fahrenheit. Rest of the process is same.
In this program I am using LM34 thats why I appended F to indicate Fahrenheit temperature. If You are
using LM35 Just change F to C. This program has been deliberately kept simply to show you how simple it
is acquire analog data from a sensor and convert it to something useful. Now once you have the temperature
you can setup another part by having a fan connected to it, and continuously monitor the temperature if it
exceeds a fixed point turn Fan ON otherwise turn it OFF. Thats all, and you have a temperature regulator

program LM35

' Declarations section

dim
LCD_RS as sbit at RD3_bit
LCD_EN as sbit at RD2_bit
LCD_D7 as sbit at RD7_bit
LCD_D6 as sbit at RD6_bit
LCD_D5 as sbit at RD5_bit
LCD_D4 as sbit at RD4_bit

dim
LCD_RS_Direction as sbit at TRISD3_bit
LCD_EN_Direction as sbit at TRISD2_bit
LCD_D7_Direction as sbit at TRISD7_bit
LCD_D6_Direction as sbit at TRISD6_bit
LCD_D5_Direction as sbit at TRISD5_bit
LCD_D4_Direction as sbit at TRISD4_bit
dim adc_res as word
dim txt as string[16]
dim txt2 as string[16]
dim v as float
dim t as float
main:
' Main program
LCD_Init()
LCD_CMD(_LCD_CLEAR)
ADCON1=ADCON1 OR 0xE 'Use AN0 as analog only
while true
adc_res= Adc_Read(0)
v=adc_res * 0.00488
t= v * 100
WordToStr(t,txt)
strcat(txt," F" )
Lcd_Out(1,1,txt)
delay_ms(1000)
wend
end.
Beginning PIC Microcontroller Programming / 107

device.
LM35 is very sensitive even small air currents will tend to change its output. Therefore you will see very
broad fluctuations when you handle it while its showing temperature. To avoid this it is recommended that
you take 10 samples in a loop, and then take their average then use this value as output of LM35.
Reading Voltage More than 5V
So far we have been experimenting with voltage source generated from the development board, and input
voltage was not more than 5V. What if we are expecting a more than 5V on input? The answer is simple,
use a voltage divider to scale down the volts.
Voltage divider is the answer. The ration of Z1 and Z2 resistors will determine the factor by which your
voltage will be dropped before reaching microcontroller. The formula although already given above, is be-

ing given again here:


Since input impedance of microcontroller is very high, very negligible amount of current is drawn, so the
individual values of resistors is not important, only ratio of the values is important. Lets say Z1 and Z2 both
are 10K, then it is 1/2 divider. If Vin is 10V the Vout will be 5V. The microcontroller will see the volts as
maximum 5V in this case, to get actual volts multiply the answer with 2.
Similarly if Z1=10K and Z2 = 20K then its 1/3 if applied volts are 15V the output voltage will be 5V, in
that case you will multiply the answer with 3 to get actual volts.
There is always a danger of getting in-
put higher than the safe limits of PIC.
A simple protection is to put a 5.1v
Zener diode across the line.
Other idea is to use opto isolator, that
will in any case not allow more than 5V
to reach the Microcontroller pin.
Most people however combine the volt-
age divider and zener diode protection. You can also place a variable resistor at Z1, and the fine tune it to
get the desired reduction factor.
How to Read Negative Volts
Sometimes we have to read in the negative
volts, to read in negative volts use an op-
amp in inverting sequence, this will convert
the negative volts to positive and your con-
troller can easily measure this, since you
know input is inverted multiply the answer
with 1.
Beginning PIC Microcontroller Programming / 108

How to sense Current Flowing


So far we have been dealing with volts, how about current? Since ADC can measure only volts, we have to
find a mechanism whereby current can be con-
verted into volts.
There are many methods including some sensors
made specifically for this purpose, Since this
manual is meant to understand the underlying
mechanisms its better to dissect the issue deeper.
The most common method used is Shunt Resis-
tor.
A wide variety of applications benefit from the
ability to measure current flow. Traditionally,
current sensing was primarily for circuit protec-
tion and reporting. However, as technology ad-
vances, current sensing is becoming more and
more important as a way to monitor performance
(and ultimately enhance it).
Some applications that benefit from current sensing:
Over current-protection and supervising circuits
Programmable current sources
Linear and switch-mode power supplies
Battery chargers
Battery-operated circuits for which you need to know the ratio of current
flow into and out of a rechargeable battery.
Proportional solenoid control, linear or PWM
A resistor with very low resistance is placed in the current path. The resistor
is usually placed on Ground path instead of supply path. This allows our mi-
crocontroller to have a common ground with sense resistor, and we can eas-
ily measure the voltage at sense point.
The value of sensing resistor is usually 0.05 Ohms. So according to Ohms
Law I= V/R the current is calculated by dividing the measured voltage by
0.05.
A more elegant and better method would be to use an OP amplifier to measure the voltage.
Beginning PIC Microcontroller Programming / 109

The output of OP amplifier is then sent to Microcontroller. This is applicable where the sensed current is
going to be very small. This can be pretty useful to measure the current of motor driving lets say, the win-
dow mirror of car, when it will encounter a resistance the current will increase and you may use the micro-
controller to stop the motor.
So using an ADC you can measure an unknown resistor, get useful data from an analog sensor and measure
current flowing into a system. These are the basis of most commonly encountered scenarios.
Making Your Own Sensors
Yes thats true, you can make your own sensors, out of lots of material that is sensitive to physical factors.
Here we are going to show you how you can make a Pressure Sensor. A pressure sensor is required in
many applications like to measure the weight of something, measuring atmospheric pressure or pressure
within a container. It can also be used to detect bumping etc. Although com-
mercial sensors are far more precise and accurate, nevertheless this activity
will show you how things are made and then improved.
The key to this experiment is the packing foam. You might have seen this if
you have ordered ICs, or other delicate substances. This is a conductive
foam. If you place the Multimeter across it you will see it conducting, and
the resistance depending upon thickness. If you squeeze it a little the wires
come closer, and resistance drops. Release the pressure and foam expands
back, and resistance increases again.
So we have a variable resistance, that is sensitive to pressure. All You need
is to cut a small, lets say 1 square cm piece, about 1/4 inch or less thick. Insert two Wires into it and secure
them in place, so that they do not touch each other and do not get pulled away accidently.
Thats all, we have our sensor ready. However since foam can absorb humid-
ity and therefore change its resistance it is better to coat it with some plastic
covering. Just dip the Foam along with wires into the plastic coating for a
few times and allow it to dry for about 20 mins.

Now you can make your sensor a part of voltage divider and the analog output
proportional to the pressure placed.
This experiment was given intentionally to facilitate you think of many more
devices that can be made to sense real world things.

Speed of ADC Conversion


Yes that matters a lot in certain circumstances, where you want to take samples very closely. The time
taken by the conversion process itself is important, as before one conversion is complete you can not take
Beginning PIC Microcontroller Programming / 110

another sample. PIC ADC can be set to different speeds, depending upon which oscillator it is going to use
for its module. It has its own internal Oscillator, which is good for most purposes. The ADCON0 register
has bits to select this.

Typically using ADC internal Clock, this time is 2-6us.


If you need more speed for a particular application, like you want to make a PIC based oscilloscope then
are dedicated serial or parallel ADCs available that can be interfaced with PIC.
Digital to Analog Conversion
We have seen previously that analog data need to be converted to digital in order to work with it through
microprocessors. Similarly sometimes Digital
data needs to be converted into analog. This is
not very frequently required and most micro-
controllers do not have any module to do so. A
simple and most commonly used method is
called PWM, Pulse width modulation. This is
an empirical method and not very accurate in
producing desired volts. We shall talk about it
in a later chapter.
There are specialized chips like DAC0808 and
others that can accept digital input in the for of
a byte, and produce an analog volts represent-
ing this on the output pin. The output needs to
be buffered by an OP AMP if you have to
drive certain device, also it requires a refer-
ence volts and negative volts.
Using dedicated DAC chips is the industry standard of getting analog signal out of digital signals. A few
other methods however exist.

R2R Ladder Network


This is beautiful arrangement of two types of resistors, one called R and other 2R. The absolute values are
not important, but the ration is important. So 2R resistor must be double the R resistor. So we are going to
use 10K and 20K resistors. The accuracy of this design depends to a large extent on the accuracy of resistor
values, thus where very precise DAC is required use 1% resistor tolerance.
Beginning PIC Microcontroller Programming / 111

This is the general arrangement of two types of resistors, you make it as much long as you can, increasing
the number bits, gives you more steps, and smaller increments in voltage. The output directly from R2R
network has volts, but very small current to actually drive something. It is therefore mandatory to put a
voltage Follower on output to give something really useful.
So if we give 00000000 on data bits, output will be 0V, and if we
give 11111111 output should be close to 5V. Truly speaking exact
5V are not achieved, due to saturation of OP Amp. Maximum
volts will be about 4.5V. If you want to get truly 5V then OP Amp
should be powered by slightly higher volts, like 9V. Also note that
voltage is summed up from Microcontroller output pins, the logi-
cal 1 of microcontroller pin is also not exactly 5V, so there is
small difference, but usually its acceptable.
So we have this 8bit DAC. 0-5V is divided in 256 steps. So each
step would be 5/256 = 0.019V thus if we set the data pins of lets
say PORTB to, 128, we expect to get 0.019 * 128= 2.43V. You can increase or decrease the number of bits
as you like. Truly speaking most DAC chips internally use this basic arrangement to produce analog output.
Sine Wave Output
The output from Microcontrollers is digital either high or low, the pulses produced therefore will have
square wave output. Some devices like high quality UPS require to be driven by a sine wave. The sine wave
does not increase or decrease in output abruptly, rather it gradually increases and gradually decreases fol-
lowing what is called a sine wave curve. The
alternating current we have in our lines has Sin
wave form. Using DAC and some mathematical
model in microcontroller numbers are generated
I such a sequence that output from DAC is a
sine wave.
Since one cycle is 360 degrees, sine values are
calculated and stored in a lookup wavetable.
Then using a loop to go through the entire
phase, the values from lookup table are read and
loaded into DAC input. This will effectively
produce a sine-wave output.
Beginning PIC Microcontroller Programming / 112

Graphic LCD and


15 Touch Screen

W
ell we have previously used character LCDs to display data. Also we have used serial termi-
nal to interact with user. Graphic LCDs are now being commonly used as they allow various
graphics and animations be displayed. Working with them is however little difficult. This is
so because the commonly used graphic
LCDs are Not Intelligent. Whereas the
character LCDs we have used are intelligent.
Graphic LCDs only allows you to turn a pixel On or Off.
Rest of everything is programmers responsibility. Even
they do not have a single font built-in to display plain text,
you have to make a Font definition table to help the graphic
LCD display characters.
The Font table has to be stored within the EEPROM of mi-
crocontroller, or if required in external EEPROM. Fortu-
nately modern day compilers have been quite helpful in
providing a bunch of commands and utilities to use these
displays.
A number of third party tools and libraries exist that can help manipulate these displays, we shall however
remain confined to what a standard compiler offers.
There are many types of graphic LCDs, some being used in mobile phones, and personal pocket PCs. These
are color displays or TFTs. We shall not talk about these in this section. The standard GLCDs are single
color usually black or white and a blue, green or white background. They are measured in number of pixels
they have. Smaller ones with fewer pixels and larger ones with more pixels are all available. Most com-
monly hobbyists and students use 128 x 64 GLCD. This means it has 128 pixels per row and a total of 64
rows are present.
The Controller on LCD will accept commands from your controller and control the corresponding pixel on
display. There are many different manufacturers and therefore many different controllers. Each controller
can have its own set of commands and therefore difficult to interface. The most commonly used displays
use Samsung KS0108 controller, or its true compatible. We shall therefore talk about this display.

Contrast Volts
This is a special issue about using GLCDs. They need a negative voltage to create contrast. Since our power
supply is usually 0, and +5V generating negative volts is a bit of task. This thing has been addressed by
LCD manufacturers and they have incorporated a negative voltage generator on the LCD module. While
purchasing GLCD make sure your display has this facility. I have a couple of GLCDs purchased earlier
when I did not know about this issue, and they are lying in my surplus bag.
Connections
As you can see this display has 20 lines, line 19
and 20 are for backlight LED. No 18 is the nega-
tive volts for contrast adjustment.
Pin 1 is VSS or GND and pin 2 is VDD or +5V.
V0 is Contrast D/I, R/W, E, CS1 and CS2 are
control pins. D0 to D7 are data pins. Unlike Character LCD that can be run using 4 data bits, GLCD re-
Beginning PIC Microcontroller Programming / 113

quires entire 8 bits of data. So one full port will be occupied by data for GLCD and some other pins for
control. Although control is managed by compiler, just for your knowledge, the GLCD has two control
chips on it, one controlling left half and other the right half of display. They are selected by CS1 and CS2
pins by our microcontroller to decide which controller will receive the command.
Connecting to Your Microcontroller
Well you can connect the display to your microcontroller any way you like. Please note in this picture the
CS1 and CS2 connections are shown at pin 1 and 2 of LCD. You will have to consult the data sheet of your

display to see how your display is configured. I will not talk about individual connection pins, but I will
talk about names of pins and their connections.
I have configured it like this:

CS1 RB0
CS2 RB1
Data D0..D7 RD0..RD7
RS RC0
RW RC1
E RC3

program GLCD

' Declarations section


' Glcd module connections
dim GLCD_DataPort as byte at PORTD

dim GLCD_CS1 as sbit at RB0_bit


GLCD_CS2 as sbit at RB1_bit
GLCD_RS as sbit at RC0_bit
GLCD_RW as sbit at RC1_bit
Beginning PIC Microcontroller Programming / 114

GLCD_EN as sbit at RC2_bit


GLCD_RST as sbit at RB5_bit

dim GLCD_CS1_Direction as sbit at TRISB0_bit


GLCD_CS2_Direction as sbit at TRISB1_bit
GLCD_RS_Direction as sbit at TRISC0_bit
GLCD_RW_Direction as sbit at TRISC1_bit
GLCD_EN_Direction as sbit at TRISC2_bit
GLCD_RST_Direction as sbit at TRISB5_bit
' End Glcd module connections

main:
' Main program
GLCD_Init()
delay_ms(100)
GLCD_Fill(0)
Glcd_Rectangle(0,0,127,63,1)
Glcd_Rectangle(10,10,117,53,1)
Glcd_Rectangle(20,20,107,43,1)

end.

In the declarations segment you have to define the connections of your LCD and their corresponding TRIS
register bits.
The constants like GLCD_CS1 and others are defined in GLCD constants library and the GLCD library
will use these names, so be careful in not changing these names.
In main section before using any
GLCD related command you have to
use GLCD_Init() call. This will initial-
ize the internal communication with
GLCD. It is always a good idea to give
some time for the initialization process
to complete before issuing a command.
The GLCD_Fill(0) will clear all the
pixels, just like clear screen. And
Glcd_Fill(255) will turn all pixels ON.
We have next placed three
GLCD_Rectangle() commands. This
command accepts 5 parameters, like
X,Y upper left corner of rectangle, and then X,Y of lower right. Last parameter 1 is the color of line, 1 is
black, 0 is white
We have issued three commands to draw three rectangles. If you are able to get this result then everything
is OK. Is the image is broken into two halves, it is likely your CS1 and CS2 are reversed, just try to invert
them either in hardware connections, or in your software definitions. In case these lines are connected to
analog lines, like RE0, RE1 make sure you set appropriate registers to declare them as digital lines.
Beginning PIC Microcontroller Programming / 115

Displaying Text
Naturally displaying text along with graphics is a requirement in all applications. Unlike character LCDs,
graphic LCDs do not have built-in capability to display text. Fortunately MikroBasic has lot to offer. In or-
der to display text we need a fonts file, where each character to be displayed has been defined in terms of
pixels that will be turned on to display it. This is a difficult job though, but it allows you to define your own
fonts. Fortunately MikroBasic has a few pre-built fonts so that for routine purpose its not a problem.
In the listing above I have omitted the GLCD connection definitions, I hope you know they are there. No-
tice the statement:

main:
' Main program
GLCD_Init()
delay_ms(100)
GLCD_Fill(0)
Glcd_Rectangle(0,0,127,63,1)
GLCD_Set_Font(@Font_Glcd_Character8x7,8,7,32)
GLCD_Write_text("Microtronics",10,1,1)
GLCD_Write_text("Pakistan",10,2,1)

GLCD_Set_Font(@Font_Glcd_Character8x7,8,7,32)
This statement selects the fonts table already defined by MikroBasic. The Font Name is:
Font_GLCD_Character8x7. Notice you have to include an @ sign before font name to indicate a pointer to
the map. Next two parameter 8, 7 define the grid on which characters have been mapped. And 32 is the off-
set position from where the map starts. All MikroBasic Fonts have offset 32, it means they start with defini-
tion of Space.
GLCD_Write_text("Microtronics",10,1,1)
GLCD_Write_text("Pakistan",10,2,1)

This statement actually displays text on LCD. First parameter after text, 10 is the x pixel from where to
start, Next parameter 1 and 2 are so called page numbers, you can call them actually line Numbers. The
exact y position of text will depend upon the font size, so instead of focusing on y pixel, they have given a
page number, that will automatically calculate the y position, so that text does not overlap.
Mikrobasic has four pre-built fonts for you:
List of supported fonts:

1. Font_Glcd_System3x5
2. Font_Glcd_System5x7
3. Font_Glcd_5x7
4. Font_Glcd_Character8x7

Displaying Bitmap Images


Naturally every graphic can not be drawn using the graphic commands like circle, dot, line etc. Many
graphics like icons etc are available as bitmaps or images. To display these images, we have to load the im-
Beginning PIC Microcontroller Programming / 116

age first in memory, it means the image will be part of your program, and consume the program memory.
The image however has first to be converted into a series of numbers, that are representative of the bits to
be turned On or Off. MikroBasic has a tool available in Tools menu, to convert bitmap into necessary num-
bers, the numbers are arranged in an array, that can then be copied into your program. You can also store
the image generated into a file, and then include that file in your program, in this way the code becomes
little more manageable.
Here is the GLCD bitmap editor. This bitmap editor supports three kinds of GLCD displays, since our is
KS0108 based we chose this tab. It has only 128x64 pixels option. Now first Load the bitmap, be sure that
the image should not be greater than the GLCD pixel dimensions. Choose MikroBasic as programming lan-
guage and the code is generated. Copy the image to clipboard and paste it in declarations section of your
program before the main statement.
Notice the command :
const SYMS3_BMP as byte[1024]
This is declaring a 1024 bytes array of constants, so it will consume program memory (1K). SYMS3_BMP
is the array name, you can give it your own name, anything like MyPic or so.
GLCD_Image(@SYMS3_BMP)
This command will display the image. Again notice the @ sign before array name, this will pass the mem-
ory address of the array to the code, instead of sending all the data. These are called pointers, and I think
they are beyond a beginners scope at this moment, so just remember that some functions require pointer to
the location of data in memory, this is done by prefixing the variable name by @ sign.
There are few other commands to manipulate the GLCD, like manipulating a single pixel, drawing a line, a
circle etc. I am not going to discuss each and every command here they have been discussed in the Mikro-
Basic help completely. You should experiment with them to know how they function.
Beginning PIC Microcontroller Programming / 117

Touch Panel
Touch panels are becoming quite popular these days as a method to get user input. Using them is not very
difficult but for a beginner it is little daunting task. In this section I will give you some useful information
about touch panels, but will not go into details of programming them.
Touch panel is a clear, transparent sheet, that fits on top of your graphic LCD. So that whatever is being
displayed on GLCD can be seen through the touch screen. Pressing over the touch screen with finger or
pointer produces a signal, that can be detected by your mi-
crocontroller. The microcontroller can then decode the sig-
nal to judge the x and y coordinate of area pressed.
Every software using touch panel will need to calibrate its
internal variables, so that it knows when pressed over pixel
0,0 what signal is produced, and when pressed over 127,
63 what signal is produced.
There are two types of touch screens, one called Resistive
Touch Screens, and others Capacitative Touch Screens.
Resistive touch screens are the most common ones, and
easily available, from mobile spare shops. As most new
mobiles have touch panels on them. The only issue for us-
ing is the connector, mobile phones have exceptionally
small connections, and therefore the screens have very delicate flexible cable, you will have to work really
hard to find either a touch screen with larger connectors, or work with smaller connectors.
Any way the resistive touch screens usually have 4 wires coming out, they are labeled as X+, X-, Y+ and Y
-. This labeling is not there on screen, you have to find out by multimeter. X+ and X will show conductiv-
ity with some resistance, and Y+ and Y will show contact with some resistance.
There are dedicated controllers and chips available to interface with them, this will spare the microcontrol-
ler and programmer from managing the screen. Nevertheless its not difficult to write your own program to
interface.

How Resistive Touch Screen Works ?


The resistive touch screen is made up of two clear plastic sheets, placed on a glass or plastic sheet. The
glass sheet only acts as surface to support. The first plastic sheet, is coated with a chemical that is transpar-
ent and has some resistance, two ends of this sheet lets say X axis have the connectors. Thus this plastic is
acting like a big resistor, the two ends are called X+ and X-, there is really now + and minus actually, just
to label them.
Then small plastic beads are placed to act as spacers, and
on top of these spacers another sheet of plastic is placed.
This is also coated with resistive chemical. The wire
connectors however are placed along Y axis and labeled
as Y+ and Y-
Thats all. This is touch screen. Two resistive surfaces
are separated from each other by small plastic beads. So
when something presses over the top sheet, it comes in
contact with the lower sheet. This effectively becomes a
potentiometer..
The microcontroller applies +5V to X+ and GND to X-
Current starts flowing across the resistor. Now when top
layer is pressed it touches this resistor somewhere along
this path, it can be close to +5V or away from 5V. The
Y+ or Y line is then read by analog system of micro-
controller and determines the voltage. This gives the
Beginning PIC Microcontroller Programming / 118

idea how much point of touch is close to +5V on X axis. Similarly +5V and Gnd are applied to Y plate and
X+ or X are read by analog to give an idea of other axis.
Thus you get the point of touch as X and Y points.
Dedicated touch panel controllers do this job for you, and give
you just SPI data to your controller. However it is not difficult
to implement using microcontroller directly.
Beginning PIC Microcontroller Programming / 119

16 Using Numeric Keypad

P
reviously we have seen how push switches can be used to get user input. The dilemma with push
switches is that they will need one I-O line per button. Keypad is yet another method of connect-
ing push switches. This however increases the number of buttons in a given I-O Lines. Although
keypads are usually available for numeric data, it is in fact the job of programmer how to interpret
the pressed key.
Keypads consist of push switches, arranged in the form of a matrix. They
are arranged in rows and columns, so that the switches in a column all
have one connection common, and that common connection is taken out as
common column. Similarly switches in a row, have other connection con-
nected together and taken out as common row. Thus each switch is part of
a row, and a column. So if we have a keypad with 4 rows and 4 columns,
this will be called a 4x4 keypad. This key pad will therefore have four
wires for rows and 4 wires for columns, a total of 8 wires. The 4x4 keypad
will have 16 push switches in it.
So the keypad can be connected to an entire port. When reading the key-
pad, the microcontroller scans it for a key press. When a key is pressed it
actually shorts a row and a column. So what microcontroller does is, it pulls one of the rows high or low
depending upon the choice of programmer, and then reads the status of column pins. The column which is
found high or low (corresponding to what was done at row pin), is the junction of row and column of the
key pressed. In this way it scans the entire rows and columns to see which key is pressed.
Since keypads are frequently used devices to get user data, most compilers provide pre-built libraries to
handle them. One drawback of keypad is that a combination of keys can not be detected.
If you are making your own scanning algorithm, you can connect the keypad anyway you like, since we are
going to use MikroBasic, it connects the columns via 10K resistors to ground. The columns are connected
to lower 4 bits of the port, and rows to higher 4 bits of the port.
Then there are commands to read the status of keypad. These commands will return a 0 if now key is
pressed, and a number from 0 to 16 if a key is pressed. The number will correspond only to the key pressed,
and in no way associated with the label written on the keypad.
Global variable KeypadPort as a byte must be defined and mapped to the port where you will be connect-
ing your keypad.
' Keypad module connections
dim KeypadPort as byte at PORTC
' End Keypad module connections
This variable must be declared in declarations section.
KeyPad_Init() must be issued once in the program before reading keypad. This command will initialize the
port for reading keypad status.
Keypad_key_Press()
This function scans the keypad and returns a number from 1 to 16 corresponding to the key pressed, it will
return 0 if no key is being pressed. You must declare a byte sized variable first to hold the data returned.
This function does not wait for a key to be pressed, and there is no way to buffer if a key was previously
Beginning PIC Microcontroller Programming / 120

pressed, while your program was busy somewhere else. Thus it scans the keypad in real time.
Keypad_key_click()
This function also scans the keypad and if a key press is detected it waits for it being released, when the key
is released it returns the number 1..16 depending upon the key pressed. Remember this is waiting com-
mand, not for initial key press, but when a key is pressed, it keeps on waiting till its released, this will effec-
tively block the program execution till key is released.

program keypad

' Declarations section


dim
LCD_RS as sbit at RD3_bit
LCD_EN as sbit at RD2_bit
LCD_D7 as sbit at RD7_bit
LCD_D6 as sbit at RD6_bit
LCD_D5 as sbit at RD5_bit
LCD_D4 as sbit at RD4_bit
Beginning PIC Microcontroller Programming / 121

dim
LCD_RS_Direction as sbit at TRISD3_bit
LCD_EN_Direction as sbit at TRISD2_bit
LCD_D7_Direction as sbit at TRISD7_bit
LCD_D6_Direction as sbit at TRISD6_bit
LCD_D5_Direction as sbit at TRISD5_bit
LCD_D4_Direction as sbit at TRISD4_bit

dim keypadPort as byte at PORTB


dim x as byte
dim txt as string[7]
main:
' Main program
Lcd_Init()
delay_ms(200)
LCD_CMD(_LCD_CLEAR)
INTCON2.7=0
KeyPad_init()
LCD_Out(1,1,"Key:")
while true
x=0
while x=0
x=KeyPad_Key_Press()
wend
ByteToStr(x,txt)
LCD_Out(1,6,txt)

wend

end.

This program will scan the keypad and return the code of key pressed. Note the column lines must have pull
-down resistors to provide logic 0 when no key is being pressed. I tried this program without those pull-
down resistors and it did not work. Since MikroBasic Keypad library assumes these Pull-Down resistors it
is mandatory to have them.
Since my system does not have the pull-down resistors, I will be using Proteus ISIS simulator to show you
the results. The system will work on your boards if you have properly build the hardware.

Getting Meaningful Input From Keypad


So far we have been able to connect to the keypad and get the data returned by MikroBasic routines. You
also know these routines will return a number ranging from 0 to 16. Zero if there is no key press, and 1..16
depending upon the key press. The number assigned to key will also depend which of the four lines are
used as rows and which as columns. So the best thing would be to connect the keypad the way you like and
then get scan codes for each key pressed.
Now the keypads can be available without any labels, just switches, or they can be available with already
Beginning PIC Microcontroller Programming / 122

labels on them. The labels will not correspond to the returned code, they are just labels, It becomes more
easy if we have a mechanism to get the label pressed, instead of the dummy code. So we have to map the
labels with scan codes, and then make a function that will return the equivalent label ASCII value.

Here is the schematic and simulation software that I will use for this demonstration. The LCD connections
are same, Keypad however is connected to PORB. Notice the three resistors to GND on columns 1,2,3, and
4. The labels are as if the keypad will be used as a calculator.
When I got the scan codes for this hardware, they started from top left button, label 7, next scan code was
given for label 4 and next for label 1 and so on. So label 7 was given scan code 1, and label + was given 16.

7 8 9 /
[1] [5] [9] [13]
4 5 6 *
[2] [6] [10] [14]
1 2 3
[3] [7] [11] [15]
C 0 = +
[4] [8] [12] [16]
Beginning PIC Microcontroller Programming / 123

The map above shows the labels on keypad and scan codes returned in brackets, below. So lets first write a
function that will accept the scan code as a parameter and return the ASCII code of the character. Note AS-
CII codes numbers are not same as numbers, for example ASCII code of 0 is 48, and for 1 it is 49. We
have used ASCII codes to be returned, because we also have to return the codes for keys like +, - and = etc.
We shall return code 13 for C to indicate an enter.

Sub Function GetkeyPad as Byte


dim kp as Byte
kp=0
while kp=0
kp=KeyPad_key_Click()
wend
select case kp
case 1
kp=55 ' 7
case 2
kp=52 ' 4
case 3
kp=49 ' 1
Case 4
kp=13 ' Enter
Case 5
kp = 56 ' 8
Case 6
kp = 53 ' 5
case 7
kp = 50 ' 2
case 8
kp = 48 ' 0
case 9
kp = 57 ' 9
case 10
kp = 54 ' 6
case 11
kp = 51 ' 3
case 12
kp = 61 ' =
case 13
kp = 47 ' /

case 14
kp = 42 ' *
case 15
kp= 45 ' -
case 16
kp = 43 ' +
Beginning PIC Microcontroller Programming / 124

end Select
Result=kp
end sub

This function when called from the main program will scan the keypad, using Keypad_Key_Click() func-
tion. This function is kept in a loop to monitor keypad, till a key is pressed and released. After that the func-
tion compares the scan code and return the ASCII value of the display label.

Getting A numeric Value


Getting a numeric value from keypad is not as simple as we experience in our computers. Keypad will ac-
knowledge only one digit at a time, and has no mechanism to record multiple key presses as a single num-
ber. Like pressing 7, 8, 9, 0 should give us an integer value of 7890. How to do that? Well not difficult,
First we will call our GetkeyPad Function and read the value. We are interested only in Digits 0..9. The AS-
CII value of 0=48 and ASCII value of 9 is 57. First we convert these values to binary number 0..9. Then we
accumulate the number in a word sized variable, and multiply the number with 10 this shifts the previous
figures to left by 1 position, and then in units position we add the new digit. Finally when C (ASCII 13) is
returned, the value in word variable is ready for use by our program.

program keypad

' Declarations section


dim
LCD_RS as sbit at RD3_bit
LCD_EN as sbit at RD2_bit
LCD_D7 as sbit at RD7_bit
LCD_D6 as sbit at RD6_bit
Beginning PIC Microcontroller Programming / 125

LCD_D5 as sbit at RD5_bit


LCD_D4 as sbit at RD4_bit

dim
LCD_RS_Direction as sbit at TRISD3_bit
LCD_EN_Direction as sbit at TRISD2_bit
LCD_D7_Direction as sbit at TRISD7_bit
LCD_D6_Direction as sbit at TRISD6_bit
LCD_D5_Direction as sbit at TRISD5_bit
LCD_D4_Direction as sbit at TRISD4_bit

dim keypadPort as byte at PORTB


dim txt as string[7]
dim u as word
Sub Function GetkeyPad as Byte
dim kp as Byte
kp=0
while kp=0
kp=KeyPad_key_Click()
wend
select case kp
case 1
kp=55 ' 7
case 2
kp=52 ' 4
case 3
kp=49 ' 1
Case 4
kp=13 ' Enter
Case 5
kp = 56 ' 8
Case 6
kp = 53 ' 5
case 7
kp = 50 ' 2
case 8
kp = 48 ' 0
case 9
kp = 57 ' 9
case 10
kp = 54 ' 6
case 11
kp = 51 ' 3
case 12
kp = 61 ' =
Beginning PIC Microcontroller Programming / 126

case 13
kp = 47 ' /

case 14
kp = 42 ' *
case 15
kp= 45 ' -
case 16
kp = 43 ' +
end Select
Result=kp
end sub
Sub Function GetNumber as Word
dim a as byte
dim b as word
b=0
while a <> 13
a=GetkeyPad()
if (a>=48) and (a<=57) then
b=(b*10) + (a-48)
end if
wend
Result=b
end sub
main:
' Main program
Lcd_Init()
delay_ms(200)
LCD_CMD(_LCD_CLEAR)
KeyPad_init()

While True
u=GetNumber()
WordtoStr(u,txt)
LCD_cmd(_LCD_CLEAR)
LCD_Out(2,1,txt)
wend
end.
Beginning PIC Microcontroller Programming / 127

Here is the complete program. Now it has two functions, one to read the keypad value and return the Ascii
code, and the other to get the numeric value of word size from the keypad.
Since our main program is only interested in getting numeric value, it declares a global variable u which is
word sized,
U=GetNumber()
This function call will call get number, that will further call get keypad. If the returned key is a number, it is
added to a local variable b, after multiplying the existing umber with 10. This process is repeated till C is
pressed. When C is pressed the GetNumber function exits and returns the value stored in b. This value is
then stored in u, now u has a word sized integer number in it that can be used in any calculations in the pro-
gram.
Note this simple program does not display numbers as they are clicked, you can just add a line to display
the numbers as clicked to show the currently typed number. We shall show it in next program.
Making a Simple Calculator
Well making a completely customized calculator
is not at all difficult. I have omitted many optimi-
zations from this code, only to demonstrate the
basic idea.
So our main program will call the getNumber
function, you press the desired number (less than
65535) and press C to complete, the number will
appear on screen, then main function will call
getKeyPad to read the operation, and store it in a
variable j.
Then again uses GetNumber function to read sec-
ond number, when you press the C the operation
is completed and we have two numbers in u and
z1. The mathematical operation is performed and result shown. You can improve upon this basic skeleton
to make a robust calculator. Note MikroBasic math library has lot to offer.
To keep the things simple I have not considered floating point inputs.
main:
' Main program
Lcd_Init()
delay_ms(200)
LCD_CMD(_LCD_CLEAR)
KeyPad_init()

While True

u=GetNumber() 'get First Operand


WordToStr(u,txt)
Lcd_Out(1,1,txt)
j=GetkeyPad()
Lcd_Chr_cp(j)
z1=getNumber()
wordTostr(z1,txt)
LCD_out(1,1,txt)
Beginning PIC Microcontroller Programming / 128

Select case j
case 43
a1 = u+z1
case 45
a1 = u-z1
case 42
a1 = u*z1
case 47
a1 = u/z1
end select
WordToStr(a1,txt)
Lcd_Out(2,1,txt)

wend

Note only main program is changed, rest of the things remain same, except for declaration of few variables.
So we have learnt how to use the numeric, or even alphanumeric keypad, get its scan codes, and map them
to the labels they are showing and then read them in our program. Once these routines have been written its
easy to call them anywhere I your program.
Even such modules can be saved separately and called in each program that needs them. So code once, code
it well and forget it, just use in all your programs.
Beginning PIC Microcontroller Programming / 129

17 Producing Sound

S
ound is an important physical aspect of our everyday life. Lots of interactions take place due to
sound. This includes both producing a sound and listening to it. Microcontrollers and other smart
devices will not let this important modality leave alone, and use it to any extent they can.
To be honest simplest sound interaction will be the ability of microcontroller to produce an audible
alert. This will inform the user about happening of an event, like an error state, a completion of task, or ac-
knowledgement of a key press. This alert is usually in the form of a small beep.
Making it little more advanced, the sound can take different tones. Now the same modality can indicate dif-
ferent states using different tones, thus a user will be aware of the status of device, just by listening to the
kind of tone.
Going even further the device might have to produce a Hi-Fi music. This might be a part of professional
musical instrument, like a keyboard or simply a mechanism to store and play music.
So far we have talked about sound production, what about sound as an input? Yes thats true, a microphone
is in fact a sound transducer or sensor. That is sensitive to environmental vibration in certain frequency
range. The sound is converted into electrical signals. These analog signals can be read by microcontroller
and processed according to the needs. A simple usage can be to respond on presence of sound, like turning
a fan On or Off. Others can be a robot that can follow the sound. Still more advanced packages can include
complex analysis of sound and separate the words into commands.
All these tasks are possible, and are being done in one or the other form. It is however important to decide
what tasks are within the limits of our microcontroller. Most of the high end tasks are usually packaged into
specialized controllers, or we can say ICs. The main application microcontroller would then only instruct
the specialized IC to do a particular task.
For example there are dedicated ICs, that can produce various melody sounds, to make it produce sound,
and select the melody, there are control pins, and these pins can be manipulated by your microcontroller.
Thus your microcontroller is relived of this burden. Similarly there are specialized chips that can decode the
MP3 data and produce audio output.
Here in this chapter we will mainly remain confined to the capabilities of PIC microcontroller. Certainly
this device is not specialized sound producing one therefore the capabilities are limited for a general pur-
pose usage.
Physics of Sound
Before playing with sound it is important to understand the basic physics. I hope most of you are aware of
that, but just for sake of completion of task it is mentioned here. Sound is basically a sort of pressure waves
produced in air. These pressure waves are produced by a mechanical movement of something. The larger is
the area of this something, called diaphragm, the produced waves will be stronger. Moreover also the am-
plitude of movement also strengthens the waves. So for a given sized diaphragm the amplitude of sound
produced will be proportional to the to and fro movement. Second important aspect of pressure waves is
their frequency. This feature imparts the number of to and fro movements per second. Human ear is sensi-
tive to frequencies in the range of 20Hz to 20KHz. Not every one can appreciate this large range, only very
young kids can appreciate this. Most of us can barely appreciate beyond 16Khz, and below 50hz.
Overtones are produced, due to vibration of air. The surrounding things, like plastic cage, etc also tend to
vibrate, and therefore modify the final vibrations reaching the ears of a listener.
Beginning PIC Microcontroller Programming / 130

So we shall be dealing mainly with a system that will play with frequency of speaker, because this is most
easily done by a microcontroller by producing On and Off signals.

How to Produce Sound


Truly speaking sound is an analog quantity, whereas our microcontroller is digital. To produce good quality
sound we need a digital to analog converter as well. For simplicity we will not go into these details how-
ever. To produce a sound we need something that should accept electrical input and convert it to mechani-
cal vibration. One such device everyone is aware of is magnetic speaker. When the coil of speaker is ener-
gized it produces a magnetic force, that interacts with permanent magnet in side the speaker. This force re-
pels or attracts the coil, and therefore the diaphragm attached to it. The more current flows through the coil,

more powerful magnetic flux is produced and amplitude of produced sound increases.

program Sound

' Declarations section


Symbol PIZO = PORTD.1
main:
' Main program
TRISD.1 = 0 'Declare as out
while True
PIZO = 0
delay_ms(500)
Beginning PIC Microcontroller Programming / 131

PIZO = 1
delay_ms(2000)
wend

end.

Since speakers contain a coil, which has some resistance, if speaker is directly connected to the microcon-
troller pin the current required will be too high. For example if we have a speaker with 16Ohms coil resis-
tance, when connected directly to the microcontroller pin, the pin will provide 5V logic level signal, then
according to Ohms law, I=V/R, I=5/16 , I=0.3Amperes or about 300mA. This is
sufficient to damage the I-O line which can source a maximum 25mA current.
Thus a speaker can not be driven directly with a microcontroller. You will need
an intervening transistor, to act as a switch for high current or at least a capacitor
to isolate the speaker directly from the microcontroller pin.
Second option is to use another technology, called Pizo Electric. Pizo electric
effect is the physical property of some ceramic crystals, when a potential differ-
ence across their ends is applied they expend and when applied in other direction
they shrink back. This will effectively produce a mechanical wave. The PIZO
does not require current flow, but only application of potential difference.
Fixed Frequency Buzzers, are most commonly used where a general purpose limited quality sound is to be
produced. These buzzers have a Pizo inside, along with necessary electronic circuit. They only need small
amount of current, well within range of PIC pin. Thus when voltage is applied, it
produces sound. Most of these buzzers produce a sound in the range of 1-2KHz.
Thus they are good to produce general alarms, alerts etc, but not good to produce
music, as they can not change the frequency.
The Pizo buzzer has two pins, one is positive supply and other is ground. You
can connect it in anyway to microcontroller pin. Like positive is connected to pin
and other pin of Pizo buzzer is connected to GND. When the corresponding pin
of microcontroller goes high, a beep is produced, and continues to be produced as
long as the pin stays high, when it is turned low, the sound stops. If connected
other way, that negative side of buzzer connected to pin and positive to VDD.
Then sound is produced when pin goes low, and stops when pin goes high.

program Sound

' Declarations section


main:
' Main program

Sound_Init(PORTD, 1)
while True
Sound_Play(1000,100)
Delay_ms(2000)
wend

end.
Beginning PIC Microcontroller Programming / 132

Tones can still be produced, by varying the duration of On and OFF signals on microcontroller pins. Even a
course quality frequency change be produced by sending impulses of varying frequency to the pin. Since
response of Pizo is very quick it can generate, a little bit of musical note, but not of professional quality.
In this program the Pizo buzzer is attached to PORTD.1 instead of writing PORTD.1 again and again, I
have defined a symbol PIZO
Symbol PIZO = PORTD.1
Now in rest of my program, wherever I use the word PIZO, it will be replaced with PORTD.1 during com-
piling. This method of defining symbols is a good practice to facilitate understanding.
Well just like a blinking LED, I have simply setup PORTD.1 to turn ON and OFF. When the line is off the
buzzer will sound, and when high it will not. This is as simple as turning an LED ON.
In this program we have used the MikroBasic sound library. This library again like other libraries needs to
be initialized, and given parameters the PORT name and pin to which either PIZO buzzer or Plain Pizo is
attached. The musical quality produced by plain Pizo will be much better as this can produce varying fre-
quencies.
The Sound_Play command takes frequency, 1000 in this case and duration, 100 mili seconds in the example
above to play a sound.
Beginning PIC Microcontroller Programming / 133

Pulse Width Modulation


18 CCP Module

M
any a times we need to produce analog output from microcontrollers. No doubt we can use
Digital to Analog converters as we discussed in the analog section, yet there is another
method, which is very popular. This is called Pulse Width Modulation or PWM.
PWM is a technique of getting analog signals from purely digital means without any inter-
vening digital to analog conversion. The idea is to produce a digital wave On and OFF. When the output is
ON it has 5V and when its OFF it has 0V. So the total amount of power provided by the pin over a given
period of time lets say 1 second is proportional to the duration for which pin has remained high. Thus if the
On and OFF times are equal, we can say 50% of the time the pin was high and 50% of time it was low.
Therefore the power given by the pin over time will be half of what it has.
The duration of ON time is called Pulse Width, and therefore this technique Pulse Width Modulation. An
increasing duration of ON time compared to OFF time effectively delivers more power, and voltage com-
pared to 5V. Since one cycle of pulse is On and Off. So a complete cycle is both ON and OFF. If the fre-
quency remains constant, an increase in On time will result in decrease in Off time. This is often referred to
as duty cycle.
So if we have a 50% duty cycle this would mean the On and Off times are equal and the power given by the
pin is reduced by one half.

Thus if the line remains at 0 all the time, we say its 0% duty cycle, the analog volts produced will also be 0.
If the duty cycle is 25%, which means the line remains on for 25% of time and remains Off for 75% of the
Beginning PIC Microcontroller Programming / 134

time. The output power will be around 5/4 volts.


When the pin is at high state, the load will draw current from it, this can result in decrease in volts specially
during the off period. The load is expecting volts even at this time, but when there is no volts, how will load
get it? The simple answer is using a capacitor. A small capacitor on line, will get charged during high and
when the line is low it discharges and supplies the load. If the capacitor is not charged in time again, it will
lose its charge and voltage will begin to fall. This is compensated by an increased frequency. High fre-
quency PWM allows very rapid and precise regulation of output volts.
This is in effect a switching power supply. The main advantage of PWM is that power loss in the switching
devices is very low. When a switch is off there is practically no current, and when it is on, there is almost
no voltage drop across the switch. Power loss, being the product of voltage and current, is thus in both cases
close to zero.
Just imagine our 220V AC is quite well regulated, but sometimes we needed to cut it down to give low
power to a device so that it runs slow. For example the sewing machine, with electric motor. The machine
operator does not want to run it all the times at full speed. To control its speed they had a paddle with a
rheostat (a variable resistor). Pressing the paddle half way would include some resistor and low power is
transferred to the motor. The rest of power is dissipated (loss) as heat. This is an inefficient system, as
power is being lost as heat to reduce energy.
There are other methods of reducing power like variable transformers, but they are bulky and difficult to
handle.
Certainly where more power is required to control a device like a motor, microcontroller will be used as a
source of PWM generation, and the actual device will be driven by another high speed switch like a transis-

tor.
Although you can connect the LED directly through a current limiting resistor,
here this show a general scheme. You can replace the LED and series resistor, with
a motor. Make sure the current required by motor is within limits
of your transistor. A still better approach is to use a darlington
pair (TIP122).
Well so far enough has been said about theory, now lets use the
concept and get into the business. One thing that you might ask
is that if we produce high frequency pulses using a loop, the
Beginning PIC Microcontroller Programming / 135

PWM would work, but what if our microcontroller has to do another job, like update an LCD, read analog
channels etc? during these other steps the PWM frequency would be lost. Fortunately there are methods to
tackle with this issue, and we shall talk about them when we discuss interrupts.
PWM is so commonly required that microchip has made a dedicated module into the controller. The num-
ber of these modules vary, some controls don't have it, some have, one, others might have up-to 6. The
benefit of module is that its output is attached to a specified I-O line. Therefore only that line can be used as
PWM output. The module once set, will continue to provide PWM pulses even though the main program is
doing something else. Thus if you set the speed of a fan to half, and continue to monitor temperature, PWM
module will keep on sending set PWM pulses to fan.
No doubt we can use loops, and interrupts to give PWM output at any line, but when PWM module is avail-
able it is better to use it.

A look at the PIC18F452 pin diagram does not reveal any PWM pin. The PWM is incorporated in a module
called Capture, Compare, PWM module. Thus it is labeled as CCP1 and CCP2

program PWM

' Declarations section


dim x as byte
main:
TRISC=0
PORTC=0
PWM1_Init(2000)
PWM1_Start()
while true
for x=0 to 255
PWM1_Set_duty(x)
delay_ms(5)
Beginning PIC Microcontroller Programming / 136

next x
wend
end.

MikroBasic allows only use of hardware modules present in your microcontroller. This compiler does not
have library to use software based PWM on any other pin. We shall have a look at that technique later,
when using interrupts.
The MikroBasic has just three commands for two supported modules. Some microcontrollers will give you
even more PWM modules, so you will need to address the registers directly.

PWM1_Init(2000)
This command will initialize the CCP1 module, and the generated frequency will be 2KHz. The choice of
frequency will depend upon nature of your application.

PMM1_Start()
This command will start the Module, to generate PWM pulses on the CCP1 Pin. (RC2 in case of 18F452)

PWM1_Set_Duty(127)
This command will set the duty cycle. 0 will mean off or 0% and 255 will mean 100% or full power. As
you can see this is a byte sized number. In most of the applications we generally talk duty cycle in percent-
age. Like 50% or 25%. Other specific values for duty ratio can be calculated as (Percent*255)/100.
Thus to get 25% duty cycle, put 25 x 255 / 100 = 63.75 (or approx 64).

PWM1_Stop()
This will stop the PWM module
Since CCP1 pin will have to produce output on it, its corresponding TRIS bit must be set to 0.
TRISC.2 = 0

In our program we have setup a loop containing variable x and vary its value from 0 to 255. setting this
value as duty cycle, every time, will change the PWM output and is an LED is connected to this line, you
will see it glow, gently from OFF to full ON.
The beauty of using PWM module, is that once the module has been set, you program can continue to do
other jobs, while the pulses
will be produced continu-
ously in background.
Now if you feed this output
to the base of a transistor,
that is going to drive some
heavy load like a fan, you
can vary the speed of fan by
changing the duty cycle.
So by now you understand
that PWM is a pulsed wave-
form delivered to drive an
analog circuit. Basically it is
fast switching that delivers
partial power during its On state. Since final output power then averages to somewhere between 0V and full
Beginning PIC Microcontroller Programming / 137

power, It can be used to gradually increase and decrease the power, thereby producing an output wave like
a sine wave.
Producing Analog Signal
We have seen how using PWM, we can deliver varying amount of energy to an LED, and produce a vary-
ing brightness. This however does not mean an actually varying voltage is being produced. A look on oscil-
loscope tracings will show a varying width pulse but still the output is digital, switching from 0-5V. This

image of an oscilloscopic screen shows how the duty cycle is varying, but the out volts are always 5V as
shown by the height of graph.
To get analog signal from PWM, we
need to place a filter circuit. The level
of the analog signal is equal
to RMS (root mean square) RMS for PWM signal (or any square wave) is equal to:

V power supply voltage, usually 5V


p pulse width
T period
For a typical DAC application PWM signal frequency is one of the most important parameters.
Generation of voltage level is rather an easy task, so any timer, any PWM mode and almost any frequency
can be used.
So lets assume our frequency is 31.25kHz.
Period T=1/31.250Hz= 0.000032s (=32s)
Beginning PIC Microcontroller Programming / 138

If we set 60% duty cycle, pulse width p=0.6*0.000032s=0.0000192s (19.2s).


For 60% duty cycle and 31.25kHz PWM frequency RMS = 5V*(0.0000192/0.000032)= 3V
Because duty cycle is equal to pulse width/period, RMS can be computed as RMS=5V*0.6=3V.

Low Pass Filter


Providing a filter can be simple to very complex, any many books have been written on just this subject.
We will be using a simple low pass filter that consists of just a resistor and a capacitor.
The low pass filter allows low frequencies to pass and holds the
high frequencies. The actual frequency called cut-off frequency
will depend upon the value of resistor and capacitor. For our pur-
pose frequency filtering is not a major concern, you can use
220K as R and 0.1uF as C. PWM Signal will be given at V-In.
Here is image from oscilloscope The blue wave form is PWM
signal, with 60% duty cycle, and red is output at RC filter, show-
ing 3V.

The second image is with incorrect Fil-


ter values, here we have used 1K resis-
tor, The output voltage is not constant
as you can see.

Sine Wave Generation


This is one of the topics hot debated by
my students. As many of them are in-
Beginning PIC Microcontroller Programming / 139

terested in making DC to AC inverters, and a Sine wave inverter has many advantages over square wave
inverter. In previous section you have seen how we can make a constant voltage from a given PWM duty
cycle. Changing the duty cycle over time will create varying voltage levels and therefore a wave output.
Indeed you can make any type of wave using this method, like sine wave, triangular wave saw tooth and so
on.
You can see from this image that each voltage level is being produced for a short period of time, thus a few

cycles of PWM at given duty cycle are given and then changed. It looks simple at first that we can increase
the duty cycle gradually and then come down at the same rate. Surely this will produce a wave, but not a
sine wave. By definition the sine wave is not linear increase and linear decrease, this will produce triangular
wave.

A look at these waveforms show that the slope of sine wave is not linear indeed its relation with time
changes.
So for a sine wave the voltage levels during an entire cycle have to be calculated. In the figure above, only
32 levels of voltages have been used, thats why the look of waveform is ragged. If more levels are used
during the entire cycle, the waveform become more smooth.
So instead of calculating voltage levels every time during cycle, a memory based table is generated that
contains the values of volts to be generated during entire cycle of one wave.

Sine Wave Table Generation


Before generating the sine wave table we got to know little math behind it. I know this is not intended for a
beginner, but availability of information is good.
Beginning PIC Microcontroller Programming / 140

A little Change in Low pass filter


We are going to use the same Low pass filter however we need to adjust the values of RC a little bit. This is
because the Low Pass filter has a natural cut-off frequency, thus to produce a smooth wave form we need a
filter that should have a cut-off frequency near the frequency of sine wave to be produced.
The cut-off frequency of a low pass filter is calculated by:
Thus if we use 10K resistor R and 0.1uF C, the cut-off frequency is : 159.2Hz. This filter will therefore pass
all frequencies from 0 to 159 Hz.

The PWM frequency can be chosen as desired, but it should be greater than the desired frequency of analog
signal to be produced. Higher frequency is better. So we shall be using a frequency of 10Khz as PWM Fre-
quency.
Next we have to decide how many steps we will have for one entire cycle of sine wave. A cycle of sine
wave is considered as a circle. Since circle consists of a continues line composed of infinite dots, the more
steps we have, more precise circle we get. Thus if we divide the circle in lets say 10 steps, there will be lots
of missing points, and our wave will be course, but it will be sine no doubt. Increasing the points increases
the resolution and therefore smoothness of the wave.
For simplicity and saving space of code for this book, we will use 32 points. Now we are going to divide
our cycle into 32 pieces or steps. We have to calculate the sine value for each of these steps. The value re-
turned by sine is always between +1 and 1. Eventually we want this value to be translated to our byte sized
duty cycle. So a value of 1 should be 0 and +1 should be 255. Since sine wave has positive and negative
points, whereas our system has only positive values of voltage. So we assume that the center of entire
range, 256/2 = 128 is considered 0. Anything above it is positive and anything below it is negative. So we
multiply the sine value of each point with 127 and then add 128 to it to bring negative numbers in the range.
Thus for any point we can calculate the sine value by this equation:
Where n is any point in the sample, Total samples are the number of samples decided. So we have decided
that we shall have 32 points or samples. This equation must be solved for each point numbered from 0 to
31. (Total Samples will be 32) since value of Pi is constant and number of Total samples is also constant:

This calculates to be: 0.19635


We use Microsoft Excel to calculate this table for us.
Just to show you the steps, I have broken down each step in one column, finally to get the rounded off value
in last column. Now we have mapped the entire 32 points to correspond with the duty cycle of our PWM
module.
These 32 points will represent one complete cycle of sine wave. This pattern will be repeated again and
again to produce continuous waves.
Now we have map for the sine wave, we have not yet decided what frequency will be produced. This is
again a little bit of math. The table and work done up to here will remain same whatever frequency we
choose. However since our Low Pass filter is for up to 159 Hz. We have to remain within these limits. In
case you want higher frequencies, just recalculate the RC values of low pass filter.
Lets say we want to produce a 50Hz Frequency. This means 50 cycles of sine wave in 1 second. 1 Cycle
will be completed in 1/50 seconds or 0.02 seconds. Thus our entire 32 steps should take 0.02 seconds to
complete. We divide this time into 32 steps. We will set one PWM duty cycle and wait for a period, then
next PWM value and again wait. In this way when entire 32 steps are completed 0.02 seconds would have
elapsed. MikroBasic allows delays in terms of milliseconds and microseconds, therefore we convert delay
Beginning PIC Microcontroller Programming / 141

n Sin(n * 0.19635) Multiply with 127 Add 128 Round Off


0 0 0 128 128
1 0.195090772 24.77653 152.7765 153
2 0.382684281 48.6009 176.6009 177
3 0.555571378 70.55757 198.5576 199
4 0.70710808 89.80273 217.8027 218
5 0.831470888 105.5968 233.5968 234
6 0.923880587 117.3328 245.3328 245
7 0.980785907 124.5598 252.5598 253
8 1 127 255 255
9 0.980784474 124.5596 252.5596 253
10 0.923877775 117.3325 245.3325 245
11 0.831466806 105.5963 233.5963 234
12 0.707102885 89.80207 217.8021 218
13 0.55556527 70.55679 198.5568 199
14 0.382677494 48.60004 176.6 177
15 0.195083567 24.77561 152.7756 153
16 -7.34641E-06 -0.00093 127.9991 128
17 -0.195097978 -24.7774 103.2226 103
18 -0.382691068 -48.6018 79.39823 79
19 -0.555577487 -70.5583 57.44166 57
20 -0.707113275 -89.8034 38.19661 38
21 -0.831474969 -105.597 22.40268 22
22 -0.923883398 -117.333 10.66681 11
23 -0.980787341 -124.56 3.440008 3
24 -1 -127 1 1
25 -0.980783041 -124.559 3.440554 3
26 -0.923874964 -117.332 10.66788 11
27 -0.831462725 -105.596 22.40423 22
28 -0.70709769 -89.8014 38.19859 38
29 -0.555559162 -70.556 57.44399 57
30 -0.382670706 -48.5992 79.40082 79
31 -0.195076362 -24.7747 103.2253 103
for each step into microseconds.
32 steps in 0.02 seconds
1 step in 0.02/32 = 0.000625 seconds
0.000625 * 1000 = 0.625 milliseconds
0.625 * 1000 = 625 microseconds.
So program will generate each PWM duty cycle for 625 microseconds before proceeding to next value.
Hopefully this should produce a sine wave with a 50Hz frequency.
Here is the output on a digital oscilloscope. The peak to peak time is about 20ms. Since frequency is 1/T
where T is in seconds. 20ms are 20/1000 = 0.02 seconds. And 1/0.02= 50 Thus the frequency being pro-
duced is 50Hz. You can easily change the frequency by recalculating the step delay.
Well this was an elementary Sine wave production. The actual frequency will slightly drift due to state-
ments managing loop are also taking some time, thus either precise correction can be made using a fre-
Beginning PIC Microcontroller Programming / 142

program PWM_Wave2

' Declarations section


const wave as byte[32] =
(128,153,177,199,218,234,245,253,255,253,245,234,218,

199,177,153,128,103,79,57,38,22,11,3,1,3,11,22,38,57,
79,103 )
dim x as byte
main:
' Main program
TRISC.2=0
PWM1_Init(10000)
PWM1_Start()
while true
for x=0 to 31
PWM1_Set_Duty(wave[x])
Delay_us(625)
next x
wend
end.

quency counter and calibrating the delay routine a little bit, or timing can be made more precise by using
timer interrupts to change the PWM duty cycles.
Nevertheless, this is still a good exercise to understand how various kinds of waves be made with micro-
Beginning PIC Microcontroller Programming / 143

controller using PWM and a simple filter. Thus if you know the equation of a wave you can calculate the
table of values and then use those values.
Beginning PIC Microcontroller Programming / 144

I2C Communication
19 I2C EEPROM

A
nother method of communication is I2C. I2C stands for Inter Integrated Circuit Communica-
tion. This protocol was first developed by Philips semiconductors. This protocol allows commu-
nication among many devices using only two lines. The two lines act as a bus, and all devices
are connected to the same bus. It sends data serially over one wire called SDA and uses the
other line SCL to send synchronize clocking signals. Both SCL and SDA lines are "open drain" drivers.
What this means is that the chip can drive its output low, but it cannot drive it high. For the line to be able
to go high you must provide pull-up resistors to the 5v supply . You need only one set of these pull-up re-

sistors for the entire bus.


Earlier we have studied how USART communication can be established between different devices. The
problem with USART is that only one device can be attached to a USART system. I2C systems allows
many devices to be connected just to the same two lines.
The I2C devices are classified as either Master or Slave. Master device has the control of bus. On it can
start a communication, and control the clocking signals. The slaves only listen when master has stated com-
munication, when master demands them to reply, they give their data on SDA line for consumption by mas-
ter. One communication system can have only one master device. Multi-master network is possible, but
quite complex. So we will confine ourselves to one master system only.
It looks odd that many different devices are connected to the same line yet they are identified separately.
This is due to the fact that each device has a unique address usually hard coded in it. Thus when master an-
nounces a connection it transmits an address, the device that matches this address responds. The address is
a 7 bit number usually. This means we can have 128 different devices connected to the same two lines.
A large number of devices are available that work
on I2C protocol. These include 24C08 and other
EEPROMS, DS1307 Real time clock, DS1620
Temperature sensor and many more. Even com-
plete modules like LCDs are available that can
communicate over I2C protocol. Even you can
make your own slave devices that can communi-
cate with the master.
Note : If you use I2C you can not put any other
(non I2C) devices on the bus as both lines are
used as clock at some point (generation of START
and STOP bits toggles the data line). So you can
not do something clever such as keeping the clock
line inactive and use the data line as a button
Beginning PIC Microcontroller Programming / 145

press detector (to save pins).


Since I2C is a proprietary protocol any commercially produced device has to pay the royalty. Some manu-
facturers in order to avoid this mention their devices as two wire instead of using the word I2C, whereas
reading their data sheet reveals that in fact this is an I2C device. DS1302, another Real time clock chip is an
example.
The module inside PIC to start I2C communication is called MSSP module or Master Synchronous Serial
Port (MSSP) module. A quick look at the pin diagram of PIC18F452 reveals that pin RC4 is also SDA, and
RC3 is SCL.
We shall begin with a simple circuit where our PIC18F452 will act as master and 24C08 EEPROM will be
connected as slave.
24C08 I2C EEPROM
Before using 24C08 EEPROM I would like to give a few words
about it. This is a series of EEPROMs available as 24Cxxx. The
number at xxx indicate amount of memory inside. Thus you can use
24C16, 24C256 and so on. All have same behavior. Pin 8 is VCC
and 4 is GND as the figure shows. Pin 7 Hold pin, is used to make
the chip read only. The hold pin also called Write control (WC) in
datasheet when pulled high makes the chip only readable. Connect-
ing it to GND directly or through an IO line, makes it writable.
Pin 5 and 6 are SDA and SCL, and should be connected to SDA and SCL of Microcontroller. Make sure the
Bus has two 10K pull-up resistors. These resistors are needed only once, no matter how many other devices
are connected.

The Device Code:


As it has been said before each device has 7 bit identification code. Pins A0, A1 and A2 are the lower three
bits of this address. The upper 4 bits are internally set to 1010. Thus in the configuration above where we
have connected A0, A1 and A2 to GND, the complete ID code of this device is %1010000. remember this
is binary number. This means you can have many EEPROM chips connected, by changing the settings on
A0..A2 pins.

The I2C Communication Protocol


Before we write any program, it is very important to understand the protocol. How this communication is
going to take place. This holds true not only for the EEPROM, but for any I2C device.
Notice the address is 7 bits long, an eighth bit (which is least significant bit) is used to indicate the desire of
Master to Read or Write. Read is 1 and write is 0.
The game begins with master initiating a start sequence. This includes a few signals on SDA and SCL lines,
but we are not going into this detail. This will be done for us by MikroBasic. So the first step is Start se-
quence. This sequence alerts all slaves and they start listening to the bus.
Next the 7 bit address and one bit of read or write desire are sent.
The master then waits for an Acknowledge response from one of the slaves. The slave whose address
matches with the address sent in previous step, responds.
Following this a byte of data is sent or received whatever is the case.
Then an Acknowledge
bit is transmitted to indi-
cate completion of proc-
ess
Finally a Stop sequence
is sent to close the con-
Beginning PIC Microcontroller Programming / 146

nection.
This pictures shows the
process of writing data
to a device.
The response from de-
vice to master requires this sequence. The master initiates the start, sends address then sends a Re-Start and
then receives data.
So lets assume we have an I2C EEPROM connected to SDA and SCL pins of microcontroller with 10K
pull-ip resistors on each line. The E0..E2 address pins are all connected to ground. So the device address is :
%1010 000. Note this is 7 bit number, the eight bit or truly speaking the least significant bit would be either
0 or 1 to indicate a write or read operation. Thus complete byte for write would be: %1010 000 0 (The
spaces are intentional just to separate parts). This binary number can be represented as hexadecimal: 0xA0
To read the data, the device address byte would be : %1010 000 1, the 1 in bit 0 position is indicating the
read operation. This is hexadecimal 0xA1. You can use any format to communicate. Since we are using
24C08 EEPROM, it has 1024 x 8 bits of EEPROM. In other words 1K Bytes of memory. The memory is
addressed from byte number 0 .. 1023. Thus while writing and reading we have to mention the location of
data within the EEPROM chip.
Now lets write a simple program, where we store a number, 170 or any other, in memory location 2 of our
EEPROM chip. Then read it back and display the contents on LCD. Of-course the same number as stored

main:
' Main program
LCD_Init()
LCD_CMD(_LCD_CLEAR)

I2C1_Init(100000) ' initialize I2C communication


I2C1_Start() ' issue I2C start signal
I2C1_Wr(0xA0) ' send byte via I2C(device address + W)
I2C1_Wr(2) ' send byte (address of EEPROM location)
I2C1_Wr(170) ' send data (data to be written)
I2C1_Stop() ' issue I2C stop signal

Delay_100ms()

I2C1_Start() ' issue I2C start signal


I2C1_Wr(0xA0) ' send byte via I2C (device address + W)
I2C1_Wr(2) ' send byte (data address)
I2C1_Repeated_Start() ' issue I2C signal repeated start
I2C1_Wr(0xA1) ' send byte (device address + R)
x = I2C1_Rd(0) ' Read the data (NO acknowledge)
I2C1_Stop() ' issue I2C stop signal

ByteToStr(x,txt)
LCD_Out(1,1,txt)
end.
Beginning PIC Microcontroller Programming / 147

should be read back.


Well lets dissect out this program, as it has everything about I2C communication.
First we know our hardware is connected, so that EEPROM is connected to SDA and SCL pins of Micro-
controller.
The listing has not shown the LCD configuration, I hope you understand how it is done.

I2C1_Init(100000)
This is the first statement required to initialize I2C module. The parameter 100000 is the I2C speed. Most
modern I2C devices communicate at
400K speed. Some slower devices work
at 100K. You got to check the device
specs as to what speed it supports. We
have initialized the module to commu-
nicate at 100K. Nevertheless it will
work at 400K as well.

I2C1_Start()
Next we have to start the I2C commu-
nication, by giving this statement, this
statement produces an I2C start condi-
tion of the line, this causes all attached
devices to become attentive and wait
for the address and command of the
device.

I2C1_Wr(0xA0)
Now we are going to transmit the device address and a write command. As said above 0xA0 is binary %
1010000 0. You know that the 24C08 device address that is hard coded is 1010, and we have set E0..E1
pins ground, so the complete address is 1010 000 the last 0 is write command.
Now when this byte is issued EEPROM chip will response, and expects a data to be coming. From here
onward what to send depends upon your device, since we are using 24C08, its data sheet states that it ex-
pects now a number that will be used as the address of memory location, followed by that the data to be
stored.
I2C1_Wr(2) we want to store the data at memory location 2
I2C1_Wr(170) We want to store data that is 170.

I2C1_Stop()
Now our write is complete and we can stop the I2C communication. This is done by this command.
Reading back the data from EEPROM is the second procedure. Essentially it first write the address of mem-
ory that we are interested in and then issue the read command.
Note once data in EEPROM has been saved, it remains there even when power is taken off. This type of
memory is used to store the captured data like temperature etc.

I2C1_Start()
Since our previous session was finished, we can start a new session by issuing the I2C_Start sequence
again.
I2C1_Wr(0xA0)
Beginning PIC Microcontroller Programming / 148

I2C1_Wr(2)
Again we send the device address along with write bit (0) and stuff the EEPROM with memory location
address, 2.

I2C1_Repeated_Start()
This time after stuffing the memory address, we have to issue a restart command. This prepares the bus for
read bit to be sent.

I2C1_Wr(0xA1)
Now we send the device address, %1010000, followed by 1. So 0xA1 is: %10100001. The last bit 1 (Least
significant bit) indicates that we want the read operation.

x = I2C1_Rd(0)
Now we issue the Read command, this command reads the contents transmitted by EEPROM. The parame-
ter 0 means we do not want to transmit an acknowledge bit. Acknowledge bit is used when we have to
read several bytes one after the other, so that we keep on telling the EEPROM that we have successfully
read the byte it has sent.

I2C1_Stop()
Now again we can stop the I2C operation as we have completed the job. The data that was stored, 170, has
been read back in variable x, that can now be used wherever required. We simply print it on LCD to be sure
that it has read the correct data.
Well you have successfully communicated with a device over I2C protocol. Remember as far as protocol is
concerned it only consists of an I2C Start condition followed by writing the device address. After that the
device is expecting data. Now nature of this data is different for different devices. Like in case of EEPROM
this includes sending the memory location and then data to be stored. For a real time clock this will be dif-
ferent. Therefore it is necessary to go through the datasheet of your device, that once the device address has
been transferred, what further data is required by the device.
As we are talking about the 24C08 and family EEPROMs, I shall expand the subject a little bit on using
these devices. This discussion may not be applicable to other type of I2C EEPROM or devices.

Memory Address of 24C08 EEPROM


The datasheet of 24C08 EEPROM says it has 8K memory. This actually means 8K bits, not bytes. So for
practical purpose it has 1K Bytes of memory or 1024. Similarly 24C16 has 16k bits, and therefore 2K Bytes
of memory.
There are important differences in ways to access the memory locations. The data sheet says the memory
location address can be a byte long. This means we can send an address of 255 maximum. So how will the
rest of memory bytes accessed?
This figure shows the write sequence for a byte to be written, after start sequence, the device select address
is sent followed by The Address of memory location. As you can see this is shown as 8 bits, this is followed
by the Byte to be written, your actual data and then Stop.
In our previous program we have written the memory address as 0. This means we want to store our num-
ber at 0 location. Since I2C can transmit only one byte at a time, the largest address we can send is 255. In a
device with 1K memory the largest address would be 1023. This number can not be expressed in byte, but
in a 2 byte word. Unfortunately in 24C08 up to 24C16 we can not send the address as a word.
This has been facilitated by the paging system in the memory. The memory has a number of pages, each
having 256 bytes capacity. Thus each page can be addressed from 0 to 255. The trick lies in selecting the
page. So before sending the address we have to select the page. 24C08 has 4 pages of 256 bytes each. These
pages can be selected by the device select code.
Beginning PIC Microcontroller Programming / 149

A look at the datasheet of 24C08 shows These devices have A0..A2 pins that are used to extend the device
address. We have discussed this previously. The pins have different connectivity in different chips. For ex-
ample in 24C02 these pins can be configured as 0 and 1 to make the address of chip. This will allow up to 7
such chips connected on the I2c BUS.
In case of 24C08 the datasheet says A0 and A1 are not connected internally, you can leave them open or

connect to ground, as you like. Only A2 will be used as part of device address. Therefore you can have only
two 24C08 chips on an I2C Bus. Lets suppose we have connected this A2 pin to high, then device address
would be: 10101xx and if connected to ground as in our case the address would be 10100xx. The last two
bits of address will actually Select Page of memory. Thus Address 1010000 will select page 0. similarly an
address 1010001 will select page 1. and so on.
That is how we will be able to select a 256 byte page, and within each page the memory locations will be
numbered from 0 to 255. To summarize, when our data is to be written within first 256 bytes of address we
will select page 0, and use address byte as 0..255. When data is to be stored in second page, we will select
Page 2 and again number the memory locations from 0..255.
In case of 24C16 which has 2K memory and therefore has 8 pages, numbered from 0..7. the data sheet
shows, even A2 is not connected, and all three bits will be used to select the page. This also implies only
one 24C16 EEPROM chip can be connected to I2C Bus.
So far we have solved the problem of addressing the high memory. Now we are
going to talk how to store data that is not byte sized. For example a short inte-
ger, or a double type data. The short integer is word sized data that is 16 bits in
length. So it will definitely need two bytes of storage. EEPROM only allows
storage of one byte at a time, and access back one byte at a time. Therefore we
need a mechanism to access the high and low Bytes of our data, and then store
them separately into two separately addressed bytes of EEPROM. When access-
ing data back, we will read the two bytes separately and then combine them into one word sized variable.
This looks little complicated, so lets write a program to store a large number, lets say 25000. This number
needs two bytes for storage, so we will store it at location 0 of page 0. It will occupy bytes 0 and 1 in the
page. We will store another number lets say 18000 in location 0 of page 1. Again this will occupy bytes 0
and 1 in that page. Then we will retrieve them back to show that even though address bytes are same, they
are stored separately due to different page numbers.

Multi-Byte Operation
S in this case each data storage will consist of writing two bytes. The standard operation is one byte se-
quence, as shown above. To store two bytes this sequence has to be repeated twice, with incremented loca-
tion address. Since write operation is little slow and might take about 5ms. While one write operation is in
progress the chip will not respond to master commands.
These chips allow Multi-Byte operation. 24C08 supports up to 16 bytes written as one operation. To do that
you just send bytes one after the other, the internal address is automatically incremented. After the stop in-
struction is given the chip starts the write procedure in actual EEPROM.
Since we are going to save 2 bytes of data we shall use this approach.
Beginning PIC Microcontroller Programming / 150

Device Address with Page Numbers


Previously we used address OxA0 and 0XA1 for write and read operations. Lets make the new addresses
for each page:
I have omitted the declarations for LCD, so that space can be saved. Also Two subroutines have been de-
fined in the declarations section. One to Write a Word sized data to a memory address. Second to read a
Word sized data from the memory location passed as parameter.
Device write operation address is also passed. Since its last bit is 0. Adding 1 to it will give the Read ad-
dress.
Lo(d) and Hi(d) these are two new functions for you. These functions will take an variable or a constant
return you the value of Low byte and high Byte respectively. For data types with more bytes like double
variables that have 4 bytes there are two more such functions to access the third and fourth bytes.
When writing data we have first written the low byte and then high byte. A reverse procedure was done
when reading, the first byte read is stored in Low byte of result and next byte in high byte of result.
When reading data first byte from I2C we have sent an acknowledgment bit I2C_RD(1) to indicate success-
ful reading and ready for next, when we have read the second byte we have not sent acknowledgment rather
sent 0 which does not send any thing. This is also sometimes called NACK response. We close the I2C ses-
sion thereafter.
While writing Low and High Bytes we have sent them one after the other this is Multi-Byte write operation.
Page 0 Write Operation %10100000 0xA0
Page 0 Read Operation %10100001 0xA1
Page 1 Write Operation %10100010 0xA2
Page 1 Read Operation %10100011 0XA3

Only we have to keep it in mind that multi-byte rite buffer is 16 bytes long in our chip.

This program will first store the values 25000 and 18000 in location 0 of page 0 and page 1. and then dis-
play them on the LCD. Notice the small 10ms delay between writings, to allow the first write process to
complete.
In real world you do not write to EEPROM very frequently, as this is not basically a mass storage medium.
Usually some kind of lookup tables and configuration settings are stored in it and mainly read in the pro-
gram.
Microcontrollers also have limited EEPROM in them, so for smaller storage, may be up to few bytes, you
can use the internal EEPROM. PIC18F452 has 256 bytes of EEPROM on Chip. We shall talk about using
this memory separately.
In this chapter our objective is mainly to introduce I2C communication and discussing the 24C08 EEPROM
in depth. I have discussed this paging system in depth because most examples found on internet and com-
pilers only demonstrate by writing and reading a byte of data.

sub Procedure EEPROM_Write_Word(dim d as Word, dim ad-


dress as byte, dim DeviceAddress as byte)
I2C1_Start()
I2C1_Wr(DeviceAddress)
I2C1_Wr(address)
I2C1_Wr(lo(d))
Beginning PIC Microcontroller Programming / 151

I2C1_Wr(hi(d))
I2C1_Stop
end sub

Sub Function EEPROM_Read_Word (dim address as Byte, dim


DeviceAddress as byte) as Word
I2C1_Start()
I2C1_Wr(DeviceAddress)
I2C1_Wr(address)
I2C1_Repeated_Start()
I2C1_Wr(DeviceAddress+1) ' make last bit 1 to indicate read
lo(Result)=I2C1_Rd(1)
hi(result)=I2C1_RD(0)
I2C1_Stop()
end sub

dim txt as string[16]


dim x as Word
dim i as byte

main:
' Main program
LCD_Init()
I2C1_Init(100000)

EEPROM_Write_Word(25000,0,0xA0)
delay_ms(10)
EEPROM_Write_Word(18000,0,0xA2)

delay_ms(100)
x= EEPROM_read_Word(0,0xA0)
WordToStr(x,txt)
LCD_Out(1,1,txt)

x=EEPROM_read_Word(0,0xA2)
WordToStr(x,txt)
LCD_Out(2,1,txt)

end.
Beginning PIC Microcontroller Programming / 152

I2C Communication
20 DS1307 Real Time Clock

I
n this chapter we are going to explore yet another very commonly used i2C device, the real time
clock, or simply RTC. There are many RTC chips available, some I2c compli-
ant and some using different protocols. Our objective of selecting an I2C com-
pliant RTC is to show you how EEPROM and Real time Clock, two different
kind of devices be attached to the same bus and used independently as well as si-
multaneously. For example we can make a data logger, to record the temperature
every 15 minutes. This will require a temperature sensor, an RTC and an EEPROM
to store data. All three components will work together. Although we have used
LM35 temperature sensor in analog section, there are I2C temperature sensors as
well, like DS1602. So if you have this chip, all three devices can be plugged on to
the same bus.
What is a Real Time Clock?
The time keeping is one of the important tasks sometimes required in your program. Basically time meas-
urement consists of hours, minutes and seconds and sometimes milli seconds as well. It also involves calen-
dar management that includes dates, months, years and day of week etc. No doubt you can do all this using
your microcontroller, and this should not be very difficult to program such a feature.
There are few issues in this approach:
1. You will need a lot of code, that will consume the program memory, leaving little behind for your ac-
tual application
2. In case your program is stuck in some longer loop, it will not be able to update the variables of clock
and time recorded might be inaccurate
3. In case of power failure or reset, the clock variables will be reset, and when restarted they will not
know the exact time now.
4. Keeping track of all the dates for months, and considering Leap Years, calculating day of week for a
given date requires a lot of programming.
So it is better to have a separate system that is specialized in this job. This will free us from all this head-
ache, and it becomes more modular. Although you will need a little extra hardware. The RTC chip has all
the necessary time keeping logic built into it. You only need to communicate it either to set new data and
time, or to query it the current time. The RTC chip has dual power supply, one is the main VCC that is re-
quired for Chip to function and communicate, and other is standby battery. This battery provides the power
for time keeping functions in the absence of VCC. Practically this is done through a small lithium 3V bat-
tery, but you can also place a supper capacitor (1F) in its place however with a diode to charge it. I prefer
using a battery. The power consumption is so small that the battery will be enough for years and years to
keep the time.

DS1307 Hardware
DS1307 is an 8 pin chip. It can be operated from 3 to 5V. In or-
der to keep its timing it will need its own crystal oscillator. That
can be connected directly between X1 and X2 pins. The crystal
must be 32.786 KHz. There is no need of external capacitors.
Since accuracy of timing is dependent upon this timing, long
lines can have stray capacitance and affect it. Thus it is recom-
Beginning PIC Microcontroller Programming / 153

mended that the crystal should be placed as close to the chip as possible. VCC and GND are self explana-
tory. VBat line can be connected to 3V Lithium ion battery.
There are three output lines, SDA, SCL and SQW. SDA and SCL are the same as we mentioned in
EEPROM, these are meant for I2C
communication. SQW is an additional
line, for square wave output. You can
leave it alone, or connect an LED to it
or connect to microcontroller if you
want to get a trigger every time the
clock is generated. Mostly people do
not use this line, but where you want
to get a trigger this is connected to
some line that can generate an inter-
rupt.
Next you have to make the hardware,
that we shall discuss here, and connect
it to the I2C Bus along with EEPROM.
Since our previous circuit for
EEPROM had pull-up resistors on
SDA and SCL lines, you do not need
to have those again. However if you
are not using the EEPROM circuit
then you got to have these resistors in
your hardware.
Breakout Boards are available from many companies that make development boards for students and hob-
byists. You can also make your own board on a small veroboard and use it anywhere in your projects.

Interfacing With DS1307


Now when the hardware is set, we assume that your hardware also has an LCD Connected to display the
time and date etc. First thing we got to know is the device address for I2c communication. The device ad-
dress is %1101000x. As previously discussed all I2c devices have 7 bit address, the last bit is either 0 or 1
to indicate Write or read operation.
Next we got to know the structural organization of the chip as it is exposed
for interfacing. The DS1307 has 8 internal registers or memory locations
addressed as 0x00 to 0x07. These registers contain all the communication
information. They have the date and time encoded as well as few other con-
figuration bits.
Our microcontroller will address these registers by their address, and then
either read values or write values into them to set new time.
Apart from these registers the chip also has 56 bytes of RAM, fro extra stor-
age if you want. Like if you want to store a time and date when there should be an Alarm etc. these are just
general purpose memory locations, powered by VBat. Thus the values stored here are preserved even after
VCC is gone.

Binary Coded Decimal Format


Unlike standard binary method of storage, where numbers are represented by a series of bits, the DS1307
stores data in another related format called BCD, or Binary Coded Decimal. It is therefore important to un-
derstand this format before using the chip.
Suppose we have a decimal number 57. This number can be represented as binary number: %00111001.
This is the standard method of representing numbers in computers and electronics. In BCD format the deci-
Beginning PIC Microcontroller Programming / 154

mal digits 5 and 7 will be treated separately and stored in their respective binary numbers. The 5 will be
represented by : 101 and 7 by 111. In decimal system each position can have a value from 0 to 9. and binary
for 9 is 1001. Thus highest number will require at least 4 bits. In BCD each number is therefore coded as 4

Decimal Value 5 7
BCD Value 0101 0111
bit binary number, and its decimal notation is directly translated. Number 57 will therefore be stored as:
The bits allocated are not always 4 as there can be situations where this number is going to be small. For
example in case of minutes, the tens digit is going to be fro 0 to 5 only, which can be represented in 3 bits
easily, sparing the highest bit for something else.

Lets now have look at the arrangement of various data in DS1307 registers.
For example look at address 00h. This address keeps record of current seconds. Since smallest number will
be 00 and largest 59. This needs to store a units number and a tens number. In case of 57 seconds 7 is unit
and 5 is tens. The lower 4 bits 0..3 will store the unit and higher 3 bits 4..6 will store the tens. The highest
7th bit is used for something else, it is not part of seconds.
Similarly address 01h will contain the minutes. Lower four bits 0..3 units and higher 3 bits tens. The highest
bit 7 will always be 0 and therefore will not interfere in our interpretation.
Now lets look at hours register, 02h. Hours can be represented as 12 hours or as 24 hours. In case of 12
hours mode the tens digit can be only 0 and 1 so requiring only one bit. However this mode will need an
indicator if its AM or PM. The 24 hours mode will require two bits for tens digit and there is no need to
store an AM/PM.
The lower 4 bits will contain the unit of hours. Bit 6 will determine the mode as either 12 or 24 hours. A 0
here will indicate 12 hours mode and 1 here will indicate 24 hours mode. Bit 4 and 5 will contain the tens
digit of hour if 24 hours mode is selected. If 12 hours mode is selected bit 4 will be enough to hold the tens
digit and bit 5 will contain an indicator to weather its AM or PM.
Address 03H will contain the day of week. Like Saturday Sunday, Monday etc. there will be one number
for each of the seven days.
Address 04h, 05h and 06h are clear they contain the date, as Date, month and Year.

Register 07h is the control register and needs little discussion.


Beginning PIC Microcontroller Programming / 155

This register mainly controls the behavior of SQW pin. If SQWE bit (bit-4) is set to 1 the square wave out-

put is enabled. The default for new chip is set to 0. The frequency of square wave produced at SQW pin is
controlled by the RS0 and RS1 bits.
The above table shows the output frequency on SQW pin and settings of RS0 and RS1 bits. Most of the
time if we need an LED to blink every second directly from the chip we set it to 1Hz. The same can be used
to generate an external interrupt to tell the microcontroller that a second has elapsed so that if necessary it
can update the time.
Bit CH of address 00H. This is called Clock Halt bit. This bit essentially halts the chip. By default this is set
to 1. and it must be cleared to 0 to enable the clock.
The DS1307 operates only at 100KHz I2C speed. Now that we have all the relevant information we can
proceed to communicate with this device. Before proceeding I would like to discuss briefly a method to
extract the values from BCD format and convert them into binary format so that we can treat them as single
number. Also a reverse process is required to convert the binary values into corresponding BCD values.
The simple answer is MikroBasic has two functions available, BCD2Decimal() and Decimal2BCD(). Both
of these functions assume 4 bit data for each digit. This is alright for most conversions, however it will be
little trick for Tens digit of hours, as here the bits have other meanings as well. This is not a problem if 24
hours mode is selected. Because in that mode bit 6 will be 0 and bit 4 and 5 will contain the tens digit of
hour. Bit 7 in any case is always 0. so this will not pose any difficulty for BCD2decimal conversion.
In case we want 12 hrs mode we have to mask out the bits 5,6 and 7. Then read out separately the value of
bit 5 to know if its Am or PM.
We shall handle these issues of masking later in this chapter, for now lets write a code to start our clock
chip. Gradually we will refine the program.

Device Address
As you know every I2C chip present on the bus must have a unique address. The 7 bit address of DS1307 is
1101000. The last bit 0, will either be 0 to write command and 1 for read command. Thus for writing it will
be 11010000 (0XD0) and for reading it will be 11010001 (0XD1).
I will omit the LCD declarations to save the space here. Instead of writing the entire code in main module,
this time I will make subroutines, that will be declared in the declarations part. Then these routines will be

Sub procedure Write_DS1307(Dim address as byte, dim


w_data as byte)
I2C1_Start()
I2C1_Wr(0xD0) ' // send byte via I2C (device address + W)
I2C1_Wr(address) ' // send byte (address of DS1307 register)
I2C1_Wr(w_data) ' // send data (data to be written)
I2C1_Stop() ' // issue I2C stop signal
End Sub

Sub Function Read_DS1307(dim address as byte) as Byte


I2C1_Start()
Beginning PIC Microcontroller Programming / 156

I2C1_Wr(0xd0)
I2C1_Wr(address)
I2C1_Repeated_Start()
I2C1_Wr(0xd1)
result=I2C1_Rd(0) 'Now read the response from DS1307
I2C1_Stop()
End Sub

called from main program again and again.


These two subroutines make the heart of this program. The first one is a procedure, as it does not return
anything. It accepts two parameters, The Address of DS1307 register where we want to store something,
and the byte sized data to be stored.
It starts the I2C session by sending a start condition, then it sends 0XD0 which the device address and a 0 to
indicate we want to write something. Following this it writes the Address of DS1307 register and then the
data to be stored. The Session is then closed, sending a Stop condition.
The second subroutine is a function. This subroutine will also accept a parameter, the address of DS1307
register we are interested in. The Function will first send the start condition followed by a write address.
Then it will stuff the DS1307 with Address of register, again a start condition is sent and a Read address is
sent. The response from DS1307 is read into result variable. Note in MikroBasic the function returns its
value through a globally defined result variable. The session is then closed.
Now when you get a new chip, or it is powered up, when there was no battery, all registers are blank. Also
the CH bit of register 0 is set to 1. So we have to first set some data into the registers, and then clear the CH
bit to enable the clock.

dim txt as string[16]


dim sec as byte
dim min as byte
dim hr as byte
main:
' Main program
LCD_Init()
I2C1_init(100000)

Write_DS1307(0,0x80)'%10000000 Set CH bit High to stop Oscilator

write_ds1307(1,0X27)'; //write min 27


write_ds1307(2,0x01)'; //write hour 1
write_ds1307(3,0x02)'; //write day of week 2:Monday
write_ds1307(4,0x17)'; // write date 17
write_ds1307(5,0x06)'; // write month 6 June
write_ds1307(6,0x08)'; // write year 8 --> 2008
write_ds1307(7,0x10)'; //SQWE output at 1 Hz
write_ds1307(0,0x00)'; //Reset second to 0 sec. and start Oscillator
Beginning PIC Microcontroller Programming / 157

While true
sec=BCD2Dec(Read_DS1307(0))
min=BCD2Dec(Read_DS1307(1))
Hr=BCD2Dec(Read_DS1307(2))
Bytetostr(Hr,txt)
LCD_Out(1,1,txt)

Bytetostr(min,txt)
LCD_Out(1,5,txt)

Bytetostr(sec,txt)
LCD_Out(1,9,txt)

delay_ms(500)
wend

For now we will only read the seconds register repeatedly to display on LCD. Moreover if you have placed
an LED on SQW pin it will blink at 1Hz, as control register will be set like that.

In first part of this program we have first disabled the oscillator of DS1307 by setting CH bit to 1. then all
registers are stuffed with some default data. The benefit of using hexadecimal numbers is that each part of
hexadecimal number is 4 bit long and therefore easily represents the BCD data. You can always calculate
these values yourself.
For example we want to set minutes to 27. a look at the register 1 of DS1307 shows that lower 4 bits
should contain 7, and higher 3 bits should contain 2. The highest bit is not used and will be 0. So in BCD
format 2 = 0010 and 7 is 0111. The complete byte should be %0010 0111 this turns out to be: 0X27 or deci-
mal 39. So you can either write 0X27 as we did or write decimal value 39.
Thus after setting all the registers, finally seconds register is set to 0. this will also clear the CH bit and os-
cillator starts.
Usually this type of setup is required only once, or when you want to set new date and time. Now when the
clock is running we can read various registers time to time and update the LCD.
Now to read the seconds in a variable named sec, we have to read the seconds register, that is addressed 0.
the returned data will be in BCD format. Since we want to use it as a decimal number so that we can per-
form any mathematical calculations if we want. MikroBasic has a useful conversions function, BCD2DEC
(). We pass the data returned by Read_DS137(0) function to BCD2DEC() and store its result in sec vari-
able. Now we can use the sec variable in any way we want. We can display it on LCD. This procedure is
kept in a loop, with 500ms delay. And it will continuously display the seconds. We have also read the min-
utes, and similarly can also read hours, date, month and year and display them all on LCD.
The Day of week register, gets automatically incremented when the date changes. When changing date
programmatically this does not get updated automatically. So when you change date always update this reg-
ister as well. The numbering system is all based upon your own preference, like 1 for Sunday, 2 for Mon-
day and so on.
Just like BCD2DEC we also have DEC2BCD() that takes a decimal value and converts it to equivalent
BCD value. You can use this function if you get input from user to set time in decimal numbers.
Now you have both EEPROM and Clock on the same bus, just by changing the device address you can
change the device. In a data logger application we will use this setup to measure temperature and log the
Beginning PIC Microcontroller Programming / 158

21 Interrupts and Timers

I
nterrupts are usually considered a hard topic. No doubt it is difficult to capture and implement with
full control. We shall try to understand the basics of interrupts and timers that are to some extent
linked with them. Hopefully by the end of this chapter
you would be able to read more exhaustive texts on this
topic.
Interrupts are so important to implement a useful real world
application that almost all microcontrollers offer some level of
this feature. The interrupt handling at the microprocessor level
then becomes very important feature while choosing a proces-
sor.
As the name implies, an interrupt can be compared to the gen-
eral process of interruption. Whenever you are interrupted
from a task, your attention is immediately diverted to the new
task and after finishing the new task you resume the previous
one where you left.
Let me explain with an example. Suppose you are working on
your desk, writing and article or examining a document, sud-
denly the telephone bell rings, this ringing of the bell invokes
an interrupt process. You stop the work, and leave everything
as is there, and pick-up the phone, attend the call and close the
conversation when its done. After the phone call is finished
you get back to your task and start the process again, where you left. The process of attending the call
should not disturb any thing other than a delay in your work. Your everything should be restored back, the
document and place you were working, the stream of ideas going on in your mind should all be back to the
same level as they were before you were interrupted. This is essentially the nutshell of an interrupt as it
happens in the microcontroller.
Why should there be an interrupt
mechanism and why it should be
important to us? This becomes
more important when microcon-
troller is in communication with
other devices while at the same
time it has to handle its own inter-
nal processes.
Suppose we have a model car that
can be controlled with a remote
control, as well as it has a sensor
to sense if it is about to bump into
the wall. In this simple scenario
we want the microcontroller to
respond to both signals, but we do
not know when these signals are about to be received. At the same time it has to drive the motors to move
the car.
Beginning PIC Microcontroller Programming / 159

So driving the motors is a process that will take most of the activity, but processor has to keep a watch on
remote sensor as well as collision sensor. It has to respond immediately when one or both are detected.
There are two methods to handle this.
Polling
Interrupts
Polling is the one most commonly used, by students and beginners. In this we check the devices one by one
there is a signal, if not we pass on to next step, check next device, and so on and then process the motors
and repeat the process again. This mechanism has two faults, first we are unnecessarily checking the de-
vices, and 99% of our checks would say the device does not need attention. Moreover what if we are man-
aging the motor and one of the devices needs attention, like you pressed the remote control button. When
the button was pressed the controller was not checking it, and was busy in some other process. When it
comes to check the device, you might have lifted finger from remote. Thus controller would miss the re-
mote button press.
The interrupt mechanism is more elegant, the processor remains busy in its primary job, and when there is
something on device only then the processor is interrupted to provide service to the device. Every device
can not be monitored. Like you can not monitor if the LED is ON or not. You can monitor the port, but you
don't know if LED is defective and not emitting light.
There are many sources of interrupt. These depend on your particular microcontroller. The more advanced
is your processor, more sources of interrupt it supports. You should see datasheet of your controller to see
which sources are available to fire an interrupt.
Some events are internal that when happen can be configured to fire an interrupt. These are the internal tim-
ers, named Timer0 and Timer1. There can be more depending upon the controller. These two are usually
there.
External interrupts are usually RB0 pin. It is also labeled as RB0/INT. when configured as INT whenever it
has logical 1 or 0 (configurable) it will fire an interrupt. RB4 to RB7 can also be configured to fire an inter-
rupt whenever their state changes.
Other than these I-O interrupts many internal modules can also generate an interrupt to indicate an event.
Usually completion of a job. These include ADC which can indicate when an ADC conversion is complete,
a USART that can fire when data has arrived, similarly CCP, I2C modules all can generate interrupts.
In any given application all sources are not required to be monitored, therefore only the ones required are
configured through selection of various register bits.
Interrupt Service Routine (ISR)
Interrupt service routine is a specialized subroutine that is fired automatically when an interrupt takes place.
It is now the responsibility of program to determine in this routine what has caused the interrupt to occur.
The ISR then does the necessary job to handle the situation and close the interrupt service so that main pro-
gram that was executing may continue.
It is recommended that the ISR should not take too much time in processing, and should not call too many
further subroutines. As calling a subroutine has to save all current pointers on a memory location called
stack. If too many nested calls are there the stack may get overflow.
Well for now you only need to know that ISR is a specialized subroutine to service the interrupt procedure.
Whenever an interrupt takes place its corresponding interrupt flag is set high. When the ISR is called this
flag must be cleared to indicate that interrupt has been serviced.

How to Set an Interrupt System ON?


By default the interrupts are set to off. In order to use the interrupts we have to enable them. Each service or
external pin that can generate an interrupt has an internal enable bit usually located in a specialized register
of interrupt handling system. These bits are named as T0IE you can also call it Timer0 Interrupt Enable. If
This bit is set to high the timer0 interrupt will be enabled. Similarly there are RBIE for PORTB Interrupts.
Beginning PIC Microcontroller Programming / 160

You will need to have a look at the datasheet to find the interrupt enabling bit of your choice.
On top of all these individual interrupt enabling bits there is a general interrupt bit which enables or dis-
ables the entire interrupt system.

The figure above shows this concept beautifully. The bell is interrupt handler routine or ISR. Lets say we
want to enable Timer0 interrupt. We shall set the switch TO1E on, as well as GIE on. GIE is general inter-
rupt enable switch. When timer0 will reach the interrupt level it will set its T0IF (timer0 interrupt flag) on
this will cause the bell to ring and we will say an interrupt has occurred.
Registers to control Interrupt system
There are many registers, the details of which are beyond this chapter. Some registers are common in all
PIC microcontrollers whereas others are different in different devices due to differences in types of inter-
rupt devices available in them. We are considering registers of PIC18F452 here.
INTCON Register
This register has the most commonly used interrupts enable disable bits. There are other registers as well
like INCON2 and INTCON3 for other less commonly used interrupts.

Bit 7 of INTCON register is GIE, that is General Interrupt Enable bit. When set to high the entire interrupt
system is enabled. Bit 6 PEIE is peripheral interrupt enable to enable interrupts of peripheral devices. Bit 5
is timer0 interrupt enable.
Bit 2 TMR0IF is the flag which will be set when timer0 interrupt takes place. Similarly INT0IF is flag for
INT0 and RBIF is flag for PORTB interrupts.
The meanings and usage of these flags and bits will be clear when we use them. When PORTB interrupts
are enabled including INT0 we can also set if transition from 0 to 1, called rising edge or 1 to 0 called fal-
ling edge will cause the interrupt. We shall see all this in detail when we will use these features. I have
Beginning PIC Microcontroller Programming / 161

program Interrupt1

' Declarations section


Sub Procedure Interrupt
Intcon.1=0
PORTD=PORTD+1
End sub

main:
' Main program
TRISD=0
Intcon.4 = 1
Intcon.1=0
Intcon.7=1
PORTD=0

while true
wend

end.

talked about them here only to give you a broader outline as to what's going to happen.
In this basic program, our hardware consists of a switch attached to RB0 (INT0) pin and is active low. The
LEDs are attached to PORTD. The key to this program is a procedure having name Interrupt this is re-
served word to indicate the interrupt service routine. Whenever an interrupt will be detected this procedure
will be called.
In the main program PORTD has been set as output, INTCON.4 is INT0IE that is INT0 Interrupt 0 Inter-
rupt enable. We have set it to 1 indicating we want this interrupt enabled. Next we turn INTCON.1 to 0.
This bit is INT0IF which is flag for INT0 interrupt. We have cleared it just for safety. Next we enable the
GPIE (INTCON.7) bit. This will enable the interrupt system. PORTD is set to 0 so all LEDs are OFF.
Now in main program we have setup a purposeless, endless loop. The microcontroller will be busy in exe-
cuting this loop all the time and there is no way it can update the status of PORTD.
As soon as the button is pressed the interrupt takes place and the endless loop is interrupted the control is
taken to ISR function, where we clear the interrupt flag and increment the PORTD value and terminate the
ISR. So whenever switch is pressed current microcontroller activity is interrupted and ISR gives service to
the interrupt.
This is complete interrupt system, where we have enabled the INT0 which is an external interrupt and en-
abled GPIE handled the interrupt when it occurs, clear the flag and get ready for next interrupt.
Notice we have used bit numbers in conjunction with INTCON register name to set various bits. You have
to consult the datasheet of your controller to see exactly which bits need to be set.
MikroBasic has declared the names of these bits as mentioned in datasheet as constants. So you do not need
to remember their number in register and you can also address them as:
INTCON.INT0IE = 1 ' Intcon.4 = 1
Beginning PIC Microcontroller Programming / 162

Rising or Falling Edge


As in our case we have a switch with pull-up resistor attached. When switch is pressed a falling edge occurs
and when switch is released a rising edge occurs. We can mention when to fire the interrupt. As soon as
switch is pressed, Falling edge or when switch is released, rising edge.
In some PIC microcontrollers there is an OPTION_REG register that contains this control bit. In 18F452
this register is not there and the INTCON2.6 is defined as INTEDG0. when set high the interrupt takes

place on rising edge and when set low it takes place on falling edge. Similarly there are edge control bits for
INT1, INT2 etc.

PORTB Pull-Up Resistors


Although this paragraph does not pertain to interrupts as such, but worth mentioning as RBPU is part of
INTCON2 register. PORTB in PIC has internal pull-up resistors, thus if you connect a switch to these pins
you do not need a 10K pull-up resistor. However to enable these pull-up resistors you will set INT-

CON2.RBPU bit high. Note this will enable pull-up resistors on all pins of PORTB.
INTCON2.INTEDG0 controls the rising or falling edge to trigger interrupt on INT0 (RB0) pin. Similarly
INTEDG1 and INTEDG2 are for INT1 and INT2. Note these values are for PIC18F452. If you are using
16F877 or other check your datasheet.
Beginning PIC Microcontroller Programming / 163

Handling multiple Interrupts


As you can see there are number of sources that can generate interrupts. However there can be only one
interrupt handling function or ISR. So lets say you have setup interrupt on INT0 as well as on INT1. Now
whichever interrupt takes place the processor will be taken to ISR. There you have to determine if it was
INT0 or INT1 or any else if that is activated. Then you have to take appropriate steps to handle them. This
decision is easily made by examining the Interrupt flag of respective interrupts. The Interrupt flag will be
set for only interrupt that caused the interruption. Once decided you can take appropriate action and clear
the flag.

Low Priority and High Priority Interrupts


PIC 18F family allows two types of interrupts that can happen simultaneously. One are called high priority
and other low priority. The priority of any interrupt can be set as high or low by setting its corresponding IP
(interrupt priority) bit. When a low priority interrupt is being serviced and a high priority interrupt takes
place during this period, the program will halt low priority interrupt handler and jump to high priority inter-
rupt handler, after finishing that it will return back to low priority interrupt service routine.
The procedure with name Interrupt is high priority and procedure with name Interrupt_Low is low priority
Beginning PIC Microcontroller Programming / 164

ISR. So you will declare two procedures if that is the case.

Interrupt while still in ISR


This can get a bit complicated for a beginner, but I want to mention it for completion of the topic. Normally
it is assumed that we are going to service one interrupt at a time. There are remote chances that while an
interrupt was being served another interrupt takes place. In that case the ISR will not be fired again, as ISR
is not re-entrant and recursion is not possible in PIC. The answer is check the other interrupt flags before
leaving and if another flag is high provide it service as well.
Timers and Counters
So far we have talked about external interrupts, there are interrupts that are generated internally from situa-
tions arising inside the microcontroller.

The most commonly used internal sources of interrupts are timers. Each PIC has a few internal timers. The
numbers and bits vary among different microcontrollers. PIC18F452 has four internal timers named
Timer0, Timer1, Timer2 and Timer3. We shall talk about Timer0 to show how this can be used. The same
applies to other timers as well, but you need to see the datasheet for small differences in behavior.
In PIC18F452 Timer0 consists of a control register and the actual register to hold the values of timer ticks.
The control register is called T0CON register, or you can call it Timer 0 configuration register. Calling it
this way makes little more sense.
The results are stored in two registers, TMR0H and TMR0L. Both of these are 8 bit registers. When com-
bined together they form a 16 bit register. Timer0 can be configured to work as 8 bit or 16 bit register.
Beginning PIC Microcontroller Programming / 165

When configured as 8 bit the data is stored only in TMR0L register and when configured as 16 bit, TMR0H
and TMR0L are combined together. TMR0L contains lower 8 bits and TMR0H contains higher 8 bits. To
understand and set the timer 0, you must understand the configuration or control register.

Timer or Counter?
Truly speaking every timer is basically a counter, that is counting pulses. If the pulses are coming with
regular intervals it is called timer, as by knowing the time period between pulses and multiplying the
counter value gives us the time elapsed. When the pulses are not regularly spaced we call it a counter as we
just want to know how many pulses have arrived.
Timer0 can be configured as timer or counter depending upon nature of pulses. Next important thing is the
source of these pulses. The timer can get its pulses from internal oscillator or from an external pin called
T0CKI (Timer 0 Clock Input) this is RA4 pin. The clock source of timer 0 is selected by T0CON.T0CS bit.
T0CS stands for Timer 0 Clock Source. If this bit is set to 0 then internal oscillator used for instructions is
used and if it is set to 1 then impulses on TOCKI (RA4) pin will be used to increment the timer 0 counter
registers.
So first thing to decide is the clock source internal oscillator or external pulses or TOCKI pin. Next we have
decide if we want to use it as 8 or 16 bit counter. Many smaller PICs like 16F877 etc have this implemented
as 8 bit only. In 18F452 TOCON.T08BIT sets this option. If this bit is set to 1 it is configured as 8 bit and if
set to 0 it is configured as 16 bit counter.
Apart from TMR0H and TMR0L registers there is an TMR0IF bit in INTCON register
(INTCON.TMROIF). This is Interrupt flag which will be set when the timer0 reaches its highest count and
rolls back to 0. When it is configured as 8 bit, this happens when 255 pulses have been received. In case of
16 bit it counts up to 65535. Although this is interrupt flag but it is set even when timer0 interrupt is not
enabled. In that case just polling the flag will tell if timer has reached its saturation point.
INTCON.TMR0IE enables or disables the interrupt. When this is enabled as soon as timer 0 reaches its
maximum value the TMR0IF is set high and an ISR is called.

Pre-Scalar
Pre-Scalar is often a confusing concept, but once understood it is fairly easy to understand. Suppose the
incoming pulses are very fast, if we increment the counter at every pulse the counter will reach saturation
very quickly and fire the interrupt. Too rapid interrupt firing is not good as this will slow down the main
process. However this gives the freedom of counting each and every pulse. To slow down the counter, we
implement a pre-scalar. A pre-scalar is essentially a divider. If we implement the pre-scalar as divide by 2
then the counter will actually recording one pulse for every two received on input. Thus if 1000 pulses are
received the counter will show 500. since we know we are dividing pulses by half, multiplying the counter
value by 2 would give the actual pulses.
A look at the figure above shows, T0CON register has three bits named TOPS0, TOPS1 and TOPS2. along
with that is PSA bit that first selects if we want to use pre-scalar or not. When set to 0 pre-scalar is disabled
and every pulse is counted. When set to 1 the bit settings of T0PS2..TOPS0 will select the pre-scalar ratio.
For example setting these bits to 111 will enable 1:256 pre-scalar. This means the counter will increment by
1 when 256 pulses have been received. To get the actual pulses you multiply the counter value by 256.

Calculating The Time From Timer0 Value


Lets say we are using the timer0 and its clock source is set to internal oscillator. By internal oscillator we
mean the clock pulses that are actually driving the internal processes. Remember the external oscillator is
divided by 4 when it reaches the processor in PIC microcontrollers. Thus if we have a 20MHz external os-
cillator the internal oscillator is 20/4= 5MHz. This means 5 x 106 pulses are being fired per second. One
pulse is being fired in 1/(5 x 106) = 0.0000002 seconds or 0.2 uS. If we do not use pre-scalar, and Timer0 in
8 bit mode then interrupt would fire in 0.2 us * 256 = 51.2 uS.
Similarly if we are using an 8MHz oscillator the internal frequency will be 8/4=2MHz. This means 2 x 106
pulses are being fired per second. One pulse is being fired in 1/(2 x 106) = 0.5 uS. The 8 bit timer will com-
plete one interrupt cycle in 0.5 * 256 = 128 uS. This eliminates the decimal point and eases out the calcula-
Beginning PIC Microcontroller Programming / 166

tion without using floating point math.


Now we are going to process two separate procedures using timer 0 interrupt. As we are using 20 MHz os-
cillator and timer 0 in 8 bit mode, the interrupt will take place every 51.2 uS. For simplicity lets assume its
50 uS.
We have two LEDs connected to PORTD.0 and PORTD.1 and we want to make them blink at different
rates. To do that we take two counter variables for each LED. We increment each counter on every interrupt
so these counters will increment every 50uS now we can decide to change the status of each LED on any
number which will be a multiple of 50uS. Lets say we do that when Counter1 for LED1 reaches 100, and
counter2 for LED2 reaches 500. Thus both LEDs will be blinking at their own rates.
program Interrupt2

' Declarations section


symbol LED1 = PORTD.0
Symbol LED2 = PORTD.1

dim Count1 as word 'Counter for LED1


dim count2 as word 'Counter for LED2
sub procedure Led1_proc
inc (Count1)
if Count1=50 then
LED1= not LED1
Count1=0
end if
end sub
sub procedure Led2_proc
inc (count2)
if count2= 10 then
LED2= not LED2
count2=0
end if
end sub
Sub Procedure Interrupt
INTCON.TMR0IF=0 'clear Interrupt flag
Led1_proc()
Led2_proc()
end sub
main:
' Main program
TRISD=0
T0CON.T08BIT = 1 ' set timer 0 in 8 bit mode
T0CON.T0CS=0 ' Use internal oscillator
T0CON.PSA=0 ' do not use pre-scalar

INTCON.TMR0IE=1 ' Enable Timer 0 interrupt


INTCON.TMR0IF=0 ' clear Timer 0 interrupt flag
Beginning PIC Microcontroller Programming / 167

INTCON.GIE =1 ' Enable General Interrupt


Count1=0
count2=0
LED1=0
LED2=0

while True ' An endless loop to do something else


Wend
end.

Now just like changing the status of LEDs you can also do other tasks that will operate in background. Re-
member the 7-segment LED display. In order to keep the numbers on display we had to keep them re-
freshed. During that process we can not do anything else, or the display will stop showing numbers.
You can do that easily using the interrupt. Every time interrupt takes place you can update the display. Thus
it will continuously keep on updating the display while your main program is free, even to wait for a user
input.
Using Timer 0 as a counter
Although using it as timer was also a counter, we can set the clock source to external. Just set
T0CON.T0CS to 1. this will set the clock source to T0CKI pin which is RA4 pin. Now here if we want we
can also set if the timer will increment on rising edge or falling edge of the incoming pulses. For most cases
it is rising edge that is considered as beginning of a pulse.
Making a Frequency Counter
Lets make a frequency counter. A device that will accept an incoming digital signals and count them for
one second and display the frequency. Then reset the timer and counter trips. Basically we will setup the

dim count as word


dim TotalCount as longword
dim txt as string[16]

Sub Procedure Interrupt


INTCON.TMR0IF=0
inc (count)
end sub
main:
' Main program
T0CON.T08Bit=1 ' set in 8 bit bode
T0CON.T0CS=1 ' Set Clock source to external TOCKI
T0CON.PSA=1 ' No Pre-scalar

INTCON.TMR0IE=1 ' Enable Interrupt


INTCON.T0IF=0 ' Clear T0 Interrupt flag
INTCON.GIE=1 ' Enagle Interrupts
LCD_Init()
T0CON.TMR0ON=0 'Stop Timer
while true
Beginning PIC Microcontroller Programming / 168

count=0
TMR0L=0
T0CON.TMR0ON=1 'Start Timer
delay_ms(1000) ' Count Pulses for 1 second
T0CON.TMR0ON=0 'Stop Timer
TotalCount=(Count * 256) + TMR0L

LongWordtostr(TotalCount,txt)
Lcd_Out(1,1,txt)
delay_ms(1000)
wend
end.

timer 0 in lets say 8 bit mode and set its clock source to external pulses. Since timer 0 is in 8 bit mode it
will be able to count only 255 pulses. If we also setup an interrupt on this timer. On every 256th pulse the
interrupt will fire. We will count this fire in a separate variable.
So first we stop the counter / timer by T0CON.TMR0ON bit set to 0. this will disable counting, we reset all
counters including TMR0L counter where its go-
ing to count. Then we turn it on, and wait for 1
second. The delay_ms() function uses only loops
to induce delay and it does not affect the timers.
After 1 second we multiply the count variable
with 256 to get the counts. To this we add any
more counts present in TMR0L register to get the
total count. Since we sampled data for good one
second, this count is actually the frequency.
The source of input signals is a digital frequency generator set to generate 10K Hz square waves. What will
be the maximum frequency that this counter be able to count. Theoretically speaking it depends upon the
size of counter variable. We have used a word sized counter variable, so it can record a maximum 65535
interrupts during one second. This will turn out to be 65535 x 256 = 16776960 pulses. The TMR0L can
hold further 255 pulses thus total possible are 16776960 + 255 = 16777215. converting this to mega hertz it
will be 16.777 Mega Hertz.
How we can increase the range? Well we can introduce a pre-scalar. A pre-scalar of 2 will double the
range. Or we can reduce the sampling time to 500 milli seconds. This will also double the range. So theo-
retically you can increase it any thing you want.

Limitation?
Practically it will not be possible to measure beyond 50MHz. This is not the issue of our algorithm, but a
limitation of PIC. When frequency increases the input pin has to respond in short time. The speed at which
this pin can respond limits this to 50Mhz. You can take some other fast counter that can that can response
up to 100MHz lets say, and it acts as a pre-scalar by 2. so it gets an input of 100MHz and outputs 50MHz.
This 50Mhz can be easily counted by PIC. Since our Fast counter chip is dividing the frequency by 2 we
multiply the obtained frequency by 2 and get actual
frequency. This time up to 100MHz. Similarly if the
chip divides frequency by 4, we can get up to 200
MHz.
If in the above program, you change the clock source
to internal, T0CON.T0CS=0 then the input is internal
oscillator. As our board is running at 20MHz the in-
ternal Frequency would be 20/4=5MHz. The image
Beginning PIC Microcontroller Programming / 169

shows this to be about 5.1MHz. So we are sure this particular frequency counter will be able to display fre-
quency up to 16MHz as such, or 50 MHz if you include pre-scalars etc.
What to do if my input signal is analog and not digital?
This is the next logical question you may ask. We want to measure
the frequency in analog signals like frequency etc. the solution is
simple. You will need a pre-amplifier to increase the signal strength
and then convert its peaks into digital output.
You can add this simple circuit as a pre amplifier. The output is not
truly digital, but peaks will reach 3V and considered by PIC as digi-
tal signal. The NPN transistor can be any having good gain and fre-
quency response.
This input circuit will work with digital signals as well. So it is a
good idea to build this circuit as part of your frequency meter.
Frequency meters are quite often required in hobby lab to trouble
shoot the circuits specially ones related to radio frequency, audio
and video.
There are many more uses of this basic frequency meter. For example capacitance and inductance can be
tuned into a frequency generator. If we can measure the frequency, and know the value of one other capaci-
tor or inductor, the value of other can be calculated. We shall make an LC meter later in this book.
Interrupts on Peripheral Devices
So far we have talked about the general mechanism of interrupt handling. We have used timer to cause an
interrupt. We have also seen how a press of a button, or a change in the state of RB0 pin can cause an inter-
rupt.
There are many modules like ADC, USART and I2C etc present within the controller. These modules when
they need an attention or they have something to tell, can generate an interrupt. The capability of a micro-
controller to have an interrupt on these modules varies. Therefore always check the capability of your mi-
crocontroller first.
The PIE register in 18F452 contains enable bits for various peripheral devices supporting this service.

This is being given here only to mention that these interrupts are also possible. In this beginner level man-
ual I will not go into details. I am sure if you have worked with previous examples, you will be able to un-
derstand this as well by looking at the datasheet.

Other associated registers are PIR1, PIR2 and so on.


So we conclude this chapter with comments that 18F devices have quite mature interrupt system, where not
only you can set interrupt but also prioritize them as well.
Beginning PIC Microcontroller Programming / 170

Motor Control
22 DC Motors | Steppers | Servos

S
o far we have been working with electronic devices. Microcon-
trollers are meant to be masters of control systems. The real
world working environment includes lot of stuff that contains
motors and solenoids to affect the mechanical activity. These
include industrial automation devices, robotic applications and
lot more.
This chapter is dedicated to understanding the basic architecture of these
devices and how the microcontroller is attached to control them.
Almost all of these electro-mechanical devices depend upon the phe-
nomenon of electromagnetism, and its interaction within a magnetic field.
This poses special challenges of inductance and EMF. It is beyond the
scope of this chapter to go into very details of all this but I think it would be nice to have a brief overview
of the basic solenoid.
What is a Solenoid
There is a general principal that when an electric current flows in a con-
ductor it produces a magnetic field around it. The magnetic field is circu-
lar and its rotational direction depends upon the direction of current flow-
ing.
The strength of this field depends upon the amount of current passing. The
magnetic effect is spread to all over the entire length of the wire. If the
wire wound in a helical form these magnetic fields will come close in a
compact form and tend to add to each others force. This will effectively
increase the density of magnetic field and therefore produce a stronger
effect.
When the wire covered with thin enamel paint is wound
together tightly to get this effect it is called a Solenoid.
Sometimes the wire is wound on a soft iron core that tends
to get magnetized when the current passes and losses mag-
netic effect when current stops.
The term solenoid refers specifically to a magnet designed to produce a uniform magnetic field in a volume
of space In engineering, the term solenoid may also refer to a variety of transducer devices that convert en-
ergy into linear motion.
Effect of Induced Magnetic Field
It looks simple that when we pass current through the solenoid it
induces a magnetic effect and when we stop it stops. The effect is
actually more than that. When the current starts flowing a mag-
netic field builds and this magnetic field actually opposes the
movement of electrons.
The second most important effect is that the soft iron core is a
magnet when current is flowing, when the current flow stops, the
magnet induces a secondary wave of current that is opposite in
Beginning PIC Microcontroller Programming / 171

direction to the original current. This back current can damage the driving
electronic circuitry. It is mandatory therefore to have a protective mecha-
nism against this effect. This usually comes in the form of a Fly-Back Di-
ode.
A diode that can tolerate the expected current is placed parallel to the in-
ductor in reverse biased form. Thus when current flows in reverse direc-
tion from the inductor it shunts it back and protects the underlying delicate
transistors.

Isolated Solenoids
Isolated solenoids are devices that contain a single coil to
produce a magnetic effect and then using that magnetic ef-
fect to achieve some mechanical advantage. Relay is the
most common such device. The coil or solenoid is powered
up by microcontroller and its magnet pulls down a lever ef-
fectively making or breaking a contact.
The microcontroller pin can not power the relay directly.
Although you might find a 5V relay, yet the current required
is quite high and this will damage the microcontroller.
Therefore a driving circuit is necessary. This circuit essen-
tially consists of a transistor that can tolerate the relay current. For small relays a simple transistor like
2N2222 with 200mA current is sufficient. For larger relays use a Darlington transistor like TIP122. relays
do not usually contain the protection diode in them, so be sure to
have this. For ordinary purposes 1N4007 is sufficient.
Another device that might be of interest to you is a solenoid linear
pull or push. When the current is applied the central rod is pulled
in and thus can pull in some other device. This type of device can
be used to unlock a door, connect or disconnect the model railway
tracks etc.
Similarly are solenoid valves, that can control the flow of water or gas based upon current passing through
the solenoid coils.
DC Motors
Now lets come to little more complicated electromechanical devices, called DC motors. These motors are
most commonly used in toys and small control systems. Although almost
all motors used in robotics and control systems use DC power source, yet
they have different names according to the structure.
DC motor, therefore is a reserved name for a class of motors that contain
brushes to alternate the field of electromagnets in them so that they can
keep on rotating. The speed of motion depends upon applied voltage or
power and direction upon applied polarity. If positive and negative termi-
nals are swapped then the direction of rotation is reversed.
DC motors consist of a core of solenoid, that can be two or more. Con-
nected to the battery terminals through brushes. The core is surrounded
by permanent magnets. Application of power to the coil energizes it and
makes an electromagnet that get repelled by the nearby magnetic field.
When half circle is completed the brushes change direction of current and the magnetic field of core
changes. This circle keeps on going and DC motor keeps on rotating.
The power of any motor, is measured as Torque. This is the force it can generate when adequately pow-
ered. The torque of DC motors depends upon the core. More turns of coil and more current it can draw
Beginning PIC Microcontroller Programming / 172

stronger torque is generated.


One problem with these motors is to control their speed. Although giving less
volts would reduce the speed but it will also reduce the torque. To overcome
this issue most of the times gears are used with these motors. This effectively
increases the torque as well as decreases the speed.
Gears can be fabricated right inside the motors. So that you do not need to
worry about their mechanics. Or they can be part of the DC motor assembly as
in toys.
Usually DC motor without gears do not have much torque and can not do a
purposeful practical job. You need to incorporate the gears in one or the other form. Motors with high
torque without gears are bigger in size and heavier in weight. They also require more power in terms of cur-
rent flow.

Characteristics of a DC Motor
Before using DC motors it is important to know few facts. This will help in understanding the driver cir-
cuits made for them.
1. They contain a strong solenoid and therefore need a fly back protection diode across them.
2. The speed can be controlled only by changing the applied voltage
3. Changing the polarity of motor will change the direction of rotation
4. When power is disconnected from the motor, the motor continues to rotate due to its momentum. Ex-
actly how long it will keep on rotating depends upon the momentum of load that is rotating with it as
well as the friction.
5. A free running DC motor actually becomes a generator and starts producing current if path to flow is
provided.
6. If the terminals of a free running DC motor are shortened together they tend to establish an electric cir-
cuit for the generator. This produces electrical current in coil and it becomes a magnet again. This time
however the magnetic field tends to stop the motor.
Therefore in a motor when power is stopped it keeps on running just as a neutral car. But when
both terminals are short, by connecting both to GND or to VDD. They act as a break.
DC motors usually drive at 12 to 24V depending upon the design. Therefore they usually need a separate
power supply from your microcontroller supply. Only GND connections are made common and microcon-
troller will only control the input of a transistor or Darlington to power the motor.
In its simplest form this c n be driven just like a relay. Just replace the relay solenoid, with DC motor.
Thats it. Now when your microcontroller applies logical 1 to the base of your NPN transistor the transistor
turns ON and motor starts rotating. A logical
0 at base will turn it off.
There are many choices for the transistor.
You can use a Darlington pair or power tran-
sistor if the current requirement of motor is
high or you can use MOSFETs that can han-
dle really big loads. Remember most com-
monly available MOSFETs require almost
12V to get ON. Therefore they can not be
used directly with a microcontroller. Nowa-
days some MOSFETs that can be driven at
5V levels are also available. They are called
Logic Level MOSFETs. They can be driven
directly from the controller.
Beginning PIC Microcontroller Programming / 173

TIP 122 has collector current of 5A


maximum. So optimum current is
about 2-3A. This is a good choice if
the current is in this range. As it can
also be driven directly by microcon-
troller.
For higher currents MOSFET is the
answer. Logic level MOSFETS are
hard to find. The IRF510 gate re-
quires about 7V to operate. Since
PIC can not give more than 5V we
need a driving circuit. A 10K resistor
will provide 12V to turn it on. When
NPN transistor turns on the gate of
IRF gets connected to GND and it
turns off. You can use any general
purpose NPN transistor like 2N3904.
The only trade-off is that when you
give logic 1 at PORTC.2 the transistor turns on and MOSFET turns off so motor stops. A logic 0 turns tran-
sistor off and turns motor off. This is to be compensated in software. Or the transistor can be placed on
positive side, with collector to +12V and emitter to gate and 10K resistor to GND. This will correct this
issue. Another factor is MOSFETs have built in protection diodes so you do not need an external one. IRF
510 can easily handle currents up to 5.6A. You can use IRF520 for currents Up to 10A.
Now whatever circuit you use, its up to you, the job of microcontroller will be same. I will however assume
that a logic 1 on microcontroller pin will turn the motor ON. You can search the internet and your local
market to find logic level MOSFET like IRLD110 that can be driven directly from the microcontroller.
It looks simple to turn the motor ON or OFF. What we need to talk about is how to increase or decrease the
speed. The answer is using PWM. We have already read about PWM in earlier chapter. So here we will

main:
' Main program
TRISC.2=0
while true
PORTC.2=1
delay_ms(5000)
PORTC.2=0
Delay_ms(5000)
wend

only demonstrate how the CCP module can be used to increase or decrease the speed of motor.
The above program resembling a blinking LED, is just for testing your hardware. Remember your motor
should get appropriate DC power supply and GND of motor driver supply and microcontroller board should
be connected. We assume you have connected the motor to RC2 of microcontroller.
Now we are going to use PWM to slowly start the motor and gradually bring it to full speed then gradually
bring it back down to off state.
This is fairly simple. By adjusting the duty cycle of PWM module we can increase or decrease the speed of
DC motor. Since this driver circuit can only run the motor in one direction, there are certain motors which
Beginning PIC Microcontroller Programming / 174

dim x as byte
main:
' Main program
PWM1_Init(5000)
PWM1_Start()
while true
for x=0 to 255
PWM1_Set_Duty(x)
delay_ms(500)
next x
delay_ms(5000)
for x=255 to 0 step -1
PWM1_Set_Duty(x)
delay_ms(500)
next x
delay_ms(500)
wend

are made only to run in one direction. This kind of driver circuit is useful
for these motors. Brushless DC fans are easily available these days. They
can run in only one direction and are quite efficient. Frequently used in
power supplies to cool down the heating components.
As an experimental project you can make a hardware with a temperature
sensor as we read in analog section and run the fan at a speed depending
upon temperature.
Lets say for temperature 20-25 centigrade the speed should be slow
For 25-30 it should be medium and above 30 it should be full high speed.
Darlington Array
As mentioned previously in some chapter, if your solenoid loads are
below 500mA, you can use ULN2803 or other simple ICs. These
ICs contain 8 Darlington pairs. There are also protection diodes in-
side. So you just connect the solenoid like relay or simple motor,
fan etc and connect the corresponding input pin to microcontroller.
As shown in figure here you can even connect two or more Darling-
ton in parallel to drive a higher load.
500mA load looks small, but remember it can withstand volts up to
50V. So give it a try first for your load, this simplifies the circuit a
lot. For higher loads you can make yourself using individual Dar-
lington or MOSFETs.
H-Bridge for DC Motors
So far we have talked about the DC motor that needs to run only in one direction. DC motors can run in
both directions if the supply polarity is reversed. This means the connector getting positive now gets nega-
tive and the one getting negative now gets positive. You must have experienced this many times using toy
motors and connecting them to the battery.
Beginning PIC Microcontroller Programming / 175

In order to change the polarity of motor electronically


we need a special arrangement of electronic switches.
These switches are turned on and off in a special se-
quence to change the polarity of motor. A schematic
drawing of this arrangement resembles the shape of
letter H therefore this circuit has been named as H-
Bridge.
The H-bridge consists of 4 switches and motor is con-
nected as a bridge between these two sets.
When S1 is closed and S2 open there is Positive sup-
ply on left terminal of motor. Similarly when S3 is
Open and S4 is closed there is negative supply to the right terminal of motor and motor starts spinning in
one direction. Now the if the situation is reversed, S1 open, S2 closed, S3 Closed and S4 Open. There is
negative on left terminal and positive on right terminal so motor again spins but in opposite direction.
This is the basic idea of an H-Bridge. We can replace the switches with transistors, MOSFETs or anything
else like relays.
Now in order to work be sure that S1 and S2 are not ON at the same time, as well as S3 and S4. because
this will create a short circuit.
Now lets make it little more practical. Se want that
S1 and S4 should work as one pair so that when S1
is ON S4 should also be ON, and S2 and S3 both
OFF. Similarly S3 and S4 should make the second
pair.
We have replaced the switches with TIP120/122
these are Darlington pairs with high current. Q1 and
Q3 inputs (base_ are connected together as Input A.
And Q2, Q4 are connected as input B.
Thus by selecting a logic 1 at A and Logic 0 at B
would turn the motor in one direction and reversing
this would reverse the motor. If both are 0 the mo-
tor is neutral. If both are made 1, this will short the
circuit as all transistors turn On. This situation is
avoided by little more additions to the H-Bridge
circuit. Therefore take your I-O lines low as a first step in your program because the initial state on startup
is not predictable.
Since direction of motor is going to be forward or
backward, you will need two diodes at each line to
protect against back EMF.
This is the basic idea of an H-Bridge you will find
various modifications in this idea. Mainly including
a combination of PNP and NPN transistors as well
as implementing some logic gates to avoid a short
circuit situation.
L293 and L293D
For smaller loads around 500mA motors there are
specialized integrated circuits that already contain
two H-bridges. L293 and L293D are one example.
L293D even has built-in protection diodes and
therefore very easy and simple to use. L293 on the
other hand does not have these protection diodes,
Beginning PIC Microcontroller Programming / 176

and you have to place 4 diodes per motor yourself, but it has current sensing system, that can be connected
to your analog input pin and you can monitor the current being driven by the motor. In case the motor is
forcibly stopped or the load is too heavy and motor can
not spin easily the current drawn increases.
These ICs have dual H-Bridge driver, therefore they can
drive two motors at a time. Each motor has three inputs.
Input A, Input B and E. The combination of 0 and 1 on
inputs A and B are used to make the motor move for-
wards or backwards. If both inputs are 00 or both are 11,
they act as fast break. The circuit is enabled when E pin
is high. When E pin is low the motor is in free moving
state, just like a neutral.
You can give PWM signals to E pin to control the speed
of motor. Note there are two power supplies. One is 5V
supply for the ,logical system and other is up to 36V for
motor. There are 4 GND pins, which actually act as heat
sink as well, so they should be connected to a broad ground plane if possible to act as heat sink.
The L293 is limited to 600mA, but in reality can only handle much small
currents unless you have done some serious heat sinking to keep the case
temperature down. Unsure about whether the L293 will work with your mo-
tor? Hook up the circuit and run your motor while keeping your finger on the
chip. If it gets too hot to touch, you can't use it with your motor.
L298 Dual H-Bridge Power Driver
L293 is usually OK for students and hobbyists however some serious work,
600mA is too small, as most motors can require load as high as 2-3A. L298 is
another variant for this job. The somewhat troubled thing to use this IC is its
pin style and spacing. This does not fit easily in most commonly used 0.1
spacing found in breadboard and veroboard. Otherwise this is good stuff,
with a heat-sink to which you attach a better heat-sink yourself.

Just like L293 it has two sets of H-bridge for two DC motors. Each set has two Inputs an Enable and a cur-
rent sensing output. In case you are not going to use current sensing just connect this to GND. This is im-
Beginning PIC Microcontroller Programming / 177

portant as this provides the GND path for the motor. If you want to use the current sensing then this pin
must be connected to GND through a 0.5 Ohms current sensing resistor, and pin connected to analog input
of your microcontroller.
The chip has dual power supply, one for motor driving this can be as high as 40V and the other is 5V sup-
ply for logical circuit. This chip can handle up to 3A per motor current easily. The input logic is same, a
combination of 1 and 0 on inputs for each motor will drive it in one direction or other. The Enable will en-
able or disable the driver. A PWM signal on Enable will control the speed of motor.

Note L298 does not have built-in protection diodes therefore you will need to place them yourself. A num-
ber of hobbyists stores sell pre-built ready to use L298 based module boards. They become useful because
it is difficult to make this circuit on breadboard or veroboard due to odd positioning of the IC pins.
Beginning PIC Microcontroller Programming / 178

program DCMotor2
Symbol ENA = PORTC.2
Symbol IN1 = PORTC.3
Symbol IN2 = PORTC.4
' Declarations section

Sub procedure M1_Forward


ENA=1
IN1=1
IN2=0
end sub

Sub procedure M1_Reverse


ENA=1
IN1=0
IN2=2
end sub

Sub procedure M1_Stop


ENA=0
end sub

Sub Procedure M1_Break


ENA=1
IN1=0
IN2=0
end sub

end

main:
' Main program
TRISC.2=0

This simple program will demonstrate the forward and reverse movement of a DC motor used through
L298 or L293D motor controller ICs. As we have tied the ENA pin to RC2 that is also PWM1 output you
can set the PWM on this pin to control the speed as well.
There are other variations in the DC motor construction that are helpful in getting a better control of the
motor. When we talk about the speed of a motor, we are changing the PWM frequency and that changes the
power delivered to motor. This however does not give us an exact indication as to how fast the motor is
rotating. The speed of motor is measured as rotations per minute or RPM. In order to get a feedback of the
exact RPMs at which motor is rotating we need a feedback mechanism of some sort. In its simplest form
this consists of an LED and a sensor. Arranged in such a way as to give a pulse on one complete rotation of
the motor.
Motors with Encoder
Commercial and professional motors have a full assembly attached to them that can give information about
Beginning PIC Microcontroller Programming / 179

TRISC.3=0
TRISC.4=0
while true
M1_Forward()
delay_ms(5000)

m1_Stop()
Delay_ms(5000)

m1_Reverse()
Delay_ms(5000)

M1_Stop()
delay_ms(5000)
wend

end.

the rotational position of the motor. The sensing technology can differ, like optical or mechanical, but all
types basically give a signal about the rotational position of the motor. In most cases there are four wires,
that can code a BCD number from 0 to 15 giving 16 possible positions in one rotation. The scheme may
vary from manufacturer to manufacturer.
There can be motors with built-in encoders or encoders are separately available to be mounted on any mo-
tor. We will not consider details of programming using these encoders in this text.
Stepper Motors
Third class of mechanical devices that can be used with microcontrollers are
stepper motors. Unlike the DC motors they do not start spinning straight
away, rather they move in steps. One step a time. This makes precision
movements very simple and controllable. Combined with gears to make the
movement even more precise makes these the motors of choice where pre-
cise mechanical work is needed.
These motors are characterized by two mechanical and one electrical pa-
rameters. When buying a motor you will need to know the number of steps
this motor has in one complete rotation. This turns out to be the stepping
angle. Most of the commonly used motors have 48 steps or 7.5 degrees of
angular ro-
tation per
step. This
precision
can be fur-
ther in-
creased by
combining
a gear as-
sembly with
it. Second
parameter is
the torque.
Beginning PIC Microcontroller Programming / 180

Just like in DC motors this indicates the force generated by the motor. Most of the times steppers are driv-
ing an assembly of gears to do a useful job therefore the torque always gets amplified.
Third parameter to consider is the electrical configuration. We shall talk more about it later when talking
about structure of steppers. Electrically there are two types one are called Unipolar steppers and others are

called Bipolar steppers. There is difference in driving them therefore you must know while purchasing what
type your stepper motor is.
Structure of Stepper Motors
Stepper motors have a core of permanent magnet and electromagnetic coils are surrounding it. There are
number of coils surrounding it. When a coil is energized it becomes a magnet with two opposite poles. The
permanent magnet connected to the axel is attracted to it and stops there. Then next set is energized and
first released, the magnet attracts to next one and stops there. This sequence is repeated again and again to
move the axel desired number of steps or degrees.
Bipolar Stepper Motors
These motors have two inductors named A and B.
The electromagnet A continues over to A and B continues to B. Thus
when A is energized there is North pole at A and South Pole at A same
is the case when B is energized. The motor will therefore have 4 wires
coming out. Two wires are for winding A and two wires are for winding
B. This type of motor is called Bipolar, because it has two sets of coils.
These are shown as four poles in the diagram, but actually each coil is
distributed to number of cores present around the motor. The cores for A
and B coils are alternately arranged. This gives precise movement. The
more such cores are there more precise is the motor movement.
From programmer perspective we will consider the motor as having two
Beginning PIC Microcontroller Programming / 181

inductors. These inductors need to be energized in a sequence to achieve a movement. Secondly the direc-
tion of current needs to be reversed as well to change the direction of north and south poles. Thus driving
this kind of motor will need some sort of H-Bridge.
The above figure show the effect on a permanent magnet present in the center, when various coils are ener-
gized. In a sequence. Note the sequence is important. An out of sequence process will result in halting of
the motor. And a reversed sequence will make it move in other direction. So you can step forward and step
backward depending upon which coils are energized in which sequence.

Conceptually they are drawn and considered like this, as having two coils the ends of coils named as A and
A, B and B. They can be named in any way you like its not a rule.
Before using your motor, and planning a driver circuit it is important to know the current rating of the coils.
Just like we did about using a solenoid.
There is another type of stepper motor called a Variable Reluctance Stepper. The hybrid stepper does not
contain a permanent magnet instead contains toothed stator. The number of coils are same, and the stator
moves one tooth at a time.
A third variety is called Hybrid Stepper. This is a combination of permanent magnet and toothed stator.
We shall not go into the details of these designs, as from functional point of view we do not have concerns
about the structural design.
Beginning PIC Microcontroller Programming / 182

Unipolar Stepper Motors


Problem with using bipolar steppers is that we need to reverse the polarity of supplied current to change the
direction of North and South poles. To counteract this a new type of winding was introduced where there
are four or more coils and one end of each coils is tapped together to make a common. The common end
always remains at GND and other coils are energized one after the other again in a particular sequence.

The lead-out can be different but basically they all represent the same architecture. The colors are usually
standard, but may vary, therefore you got to test with a multimeter to figure out the phase wires and com-
mon wires.
Stepping Modes
There are three modes or patterns of energizing the coils of a stepper motor.
1. Wave Drive (One Phase ON at a Time)
2. Full Drive (Two Phases are ON at a Time)
3. Half Drive (One Phase, alternating with Two
Phases ON at a Time)

Wave Drive
Full Drive
Half Drive
Making Hardware
Bipolar stepper motors can be driven by dual H-
Bridge like L298 or L293D. You can also make
power H-Bridges using MOSFETs as mentioned
previously.
Unipolar stepper motors can be driven by a custom
made simple driver for each phase, just like we did
for a single solenoid or they can be converted to
bipolar motors if you ignore the center tape com-
mon connection and consider the two coils as one.
Then four phases will be converted into two indi-
vidual solenoids and that can be connected to L298
driver directly.
Driving a Bipolar motor using dual H-bridge needs
to understand the sequences of 1 and 0s to be sent
Beginning PIC Microcontroller Programming / 183

on 4 input channels. ENA and ENB channels will


obviously be set high.
Driving Unipolar steppers through individual
phase control can be done through ULN2803 if
the current requirement of your motor is within
500mA.
When using L298 to drive the bipolar motor, or
using single phase drivers to drive a Unipolar mo-
tor requires programming logic to sequentially
control these motors. However many commercial
boards and equipment that works with these mo-
tors requires that your board should get a pulse for advancing a step, and another line to control the direc-
tion.
Most commercially developed boards therefore have all the logic built into them either with a microcontrol-

1 0 0 0

0 1 0 0

0 0 1 0

0 0 0 1

ler or dedicated stepper motor chips and expose only pulse in and direction pins for interfacing with other
projects.
We will here try to learn and experiment by building the logic ourselves through microcontroller. That will

program Stepper_unipolar

' Declarations section

main:
' Main program
TRISC=0
while True
PORTC.0=1
PORTC.1=0
PORTC.2=0
PORTC.3=0
delay_ms(200)

PORTC.0=0
PORTC.1=1
PORTC.2=0
PORTC.3=0
delay_ms(200)

PORTC.0=0
PORTC.1=0
PORTC.2=1
Beginning PIC Microcontroller Programming / 184

PORTC.3=0
delay_ms(200)

PORTC.0=0
PORTC.1=0
PORTC.2=0
PORTC.3=1
delay_ms(200)

end.

help understand how to control the motors, later you can opt to go for making your own driver or use a pre-
built chip.
We will begin with Unipolar stepper motor, that has five or six wires. Four wires are phases, 5th and 6xth
are common so will be connected to ground.

program Stepper_unipolar

' Declarations section


dim x as byte
main:
' Main program
TRISC=0
PORTC=0
while True
PORTC.0=1
for x=1 to 3
Portc = portc << 1
delay_ms(200)
next x
wend

end.

You will need 4 transistors that should match the power rating of your motor. I would prefer using
TIP120/122. That will be enough to handle
even moderately large motors. Fly-back di-
odes can 1N4007 or similar.
If you want to use ULN2803 then things are
really simple. To be on the safer side connect
each phase with two Darlingtons to allow
more current. You can also use single Dar-
lington per pair if the current ratings of your
motor allow.
Now whatever is the case we assume that the
Beginning PIC Microcontroller Programming / 185

hardware has been setup. Remember the motor will need about 12V and that has to be supplied as external
supply. Sharing only GND with microcontroller GND.
Connect the input connections 1a, 1b, 2a and 2b to any I-O lines of your choice. Let it be: RC0,RC1,RC2
and RC3. Now we have to figure out the sequence to energize the coils.
To start with all lines will be low. Starting with 1a and progressing to 2b, each line will be made high one
by one.
You can see this is wave like sequence. Reversing the sequence will reverse the direction. Advancement at
each step will move the motor by one step.
There is not much to discuss in this very basic program, we have set PORTC to output, and then in a loop
energizing each phase one by one, one at a time. The delay should be there as stepping is a mechanical ac-
tivity and will need some time. You can experiment with this value to increase or decrease the speed.
This is rather un-optimized code with lot of statement repeating again and again, but this was done inten-
tionally to show you what's happening. We can use shift left to set the bits left one by one.
Driving Bipolar Stepper with Dual H-Bridge
Bipolar stepper will require Two H-Bridges to control the two windings. The control is simple then.
The Connections are then activated in this sequence. This is simple wave drive. This whole sequence is 4
steps. If you want to have a control over individual step you will need to customize the software. One easy
way can be to store the sequences in an array, and then using an index number to select the next or previous
sequence.
There are hardware solutions to the entire process available. You can combine these hardware solutions to
make a consolidated driver that will accept a pulse for step and an indicator for direction. Optionally there
can be an enable or disable input. This will free your controller from implementing the logic and will need
to instruct the board when to take a step and in which direction.
Beginning PIC Microcontroller Programming / 186

program Stepper_Bipolar
Symbol Motor_1a = PORTD.0
symbol Motor_1b = PORTD.1
Symbol Motor_2a = PORTD.2
Symbol Motor_2b = PORTD.3

' Declarations section

main:
' Main program
TRISD=0
While true
Motor_1a = 1
Motor_2a = 0
Motor_1b = 0
Motor_2b = 0
delay_ms(200)

Motor_1a = 0
Motor_2a = 1
Motor_1b = 0
Motor_2b = 0
delay_ms(200)

Motor_1a = 0
Motor_2a = 0
Motor_1b = 1
Motor_2b = 0
delay_ms(200)

Motor_1a = 0
Motor_2a = 0
Motor_1b = 0
Motor_2b = 1
delay_ms(200)
wend

end.

L297 Stepper Motor Logic Chip


L297 is the co-partner of L298. it can be easily connected with it so that all the driving sequence for L298 is
already encoded within L297. this is a professional chip and has lots of input pins to allow you best control.
It can allow Normal wave full/half stepping as well as direction control and current sensing in case the mo-
tors get stuck.
L297 can also be used with ULN2803 or similar driver to drive unipolar motors. Most of the complex fea-
Beginning PIC Microcontroller Programming / 187

tures available in this chip are not required by a common user. Although we have seen driving unipolar
steppers through microcontroller directly is not difficult, yet when adding half stepping and other logics it
becomes little messy. So L297 can come to rescue you.
Combining L297 with L298N / L293E
In the above example we have seen how L297 can be combined with ULN2803 or other similar drive. In
order to drive Bipolar motors or even unipolar converted to bipolar setup, you will need an H-Bridge.
L298N is used for currents above 1A up to 4A. For currents less than 1A you can use L293E. Note L293E
is little different from L293D. It has current sensing and does not contain protection diodes.
L297 Has been specifically designed to work with these two chips. When you will explore internet to get
more information about L297 interfacing you will come across many new terminologies and confusing

facts.
Let me briefly explain those to you. L297 does not just drive the L298 and the motors but also monitors the
current and therefore variation in speed as well. This is called PWM chopper circuit. In order to get use of
this feedback the sense1 and sense2 of L298 must be connected to L297. Now L97 must be told about the
steady level current that must be maintained. This is given in the form of Vref. In simplest form as in above
circuit you can connect this pin directly to 5V, or place a POT to adjust the reference volts.
Next there are Home and Reset inputs. They are optional for you to use. At any given time you may not
know which phase being energized. When you give reset signal L297 resets the outputs to default position
that is first coil. This position is called Home. It means that after completing one cycle, usually 4 steps it
will come back to home again. Every time it comes to home sequence the Home pin gets High. This signal
is usually combined with Input signal from a mechanical system that indicates the Home position of your
device.
The OSC pin gets an oscillator circuit usually an RC oscillator. The sync pin is not used for one motor con-
trol, but if you have more motors, the Sync pin is connected to OSC pin of other. Sync pin actually outputs
the oscillator output for next chip. So next chip will not need an oscillator and will be synchronized with
first chip. The control pin is used to set if the chopper output is to ABCD outputs or to INH1 and INH2
Beginning PIC Microcontroller Programming / 188

lines. Mostly it is recommended that you can connect it to +5V.

Servo Motors
Servo motors are third type of motors used in electronics. They are frequently used where a precise position
of an object is to be maintained. These motors are therefore not meant for rotation. They tend to rotate for a

range usually through 180 degrees. Some having more range like 360 degrees are also available. The beauty
of these motors is when they have been commanded to a new position, they resist change in this position
and tend to maintain it. The torque here translates to the maximum opposing force
it can resist. Truly speaking servo is the name of a mechanism that has feedback
of its position and therefore it can be corrected.
Thats why these motors are frequently used in hobby RC projects, where despite
air pressure the position of rudder or take-off fins have to be maintained.
Interfacing servo motors is very simple, you do not need any specialized driving
circuit. These motors have three wires, two are for power supply and one is for
control signal. The control signal is in the form of PWM. You must consult the
datasheet of your particular motor as to the nature of pulses it expects.
Most of the motors require a pulse width of 1 to 2 ms. And the frequency of these
Beginning PIC Microcontroller Programming / 189

pulses from 50 to 100 Hz. The train of pulses should remain uninterrupted. Thus when a 1ms pulses are
there the motor will be in its extreme left position gradually increasing the pulse will bring it close to its
extreme right position.
You can achieve these pulses easily with PWM mod-
ule, or in your main loop, using a delay_ms function.
This simple program will demonstrate a fixed width
pulse that can be used to test your motor. To make it
flexible you have to use Vdelay_ms() or Delay_cyc()
functions. Delay_ms function only accepts a constant
value that is calculated at the time of compilation.
I would suggest using either PWM if that pin is avail-
able, or if you have to control a number of servos use
an interrupt routine to send corresponding pulses on
pins where servo is connected.

program Servo
symbol PIN = PORTC.0
' Declarations section

main:
' Main program
TRISC.0 = 0 ' Output PORTC.0
while true
PIN=1 'start Pulse
delay_us(1200) ' Keep in central position
Pin=0
delay_ms(10)
wend
end.
Beginning PIC Microcontroller Programming / 190

23 LED Matrix Displays

L
EDs are fascinating devices. They consume very small amount of current, do not produce heat
and can be rapidly switched on and off. Truly speak-
ing they are solid state light sources. They have been
used in electronics to indicate status of various proc-
esses like power status, or status of a motor etc. however they
can also be used in creating various animations, letters and
signs etc. We have already seen how arranging LEDs in a
seven segment display can be used to display numbers. Simi-
larly arranging LEDs in a row and column fashion can be used
to show up various characters, messages, animations and lot
more.
Arranging LEDs in a matrix form is not a big issue, but the
issue is if we are going to drive each LED with an I-O line we
will need a very large number of lines to control them. This
problem is solved by a natural phenomenon in our eyes, called persistence of vision. We make use of this
phenomenon in lots of electronic devices. Our eyes tend to retain an image for about 10ms. If the images
are produced rapidly our eyes tend to merge them up and see them as continuous image. This is what hap-
pens in television and projector etc.
LEDs arranged in a matrix, have a special combination of connections. That allows each LED individually
addressable, yet at the same time consuming very few I-O lines.
These come in various sizes and number of LEDs. The one
shown here in figure is called 5x7 LED matrix. This has 7
rows and each row contains 5 LEDS, totaling 35. there are
modules containing 5x8, or 8x8 matrix. Even the color can
be single, two or three colors per dot. We shall talk about
these multi-color modules later. At present we shall focus
on 5x7 module. The idea and programming technique re-
mains same, weather it is 5x7 or 8x8. to get a more wider
display multiple modules can be combined together to
make a larger matrix. Whatever length you achieve it still
remains a matrix and treated the same way as you treat one
module.
As you know each LED has two connections, an anode and
a cathode. In a matrix the LEDs are arranged in a matrix
form, so that all the anodes of a row are connected to-
gether, and all the cathodes of a column are connected to-
gether. This sequence can be carried out endlessly to make
the matrix as big as you want. There is no standard naming or numbering convention used to describe the
rows and columns. We should therefore define a rule, so that there is no confusion in later discussions. We
shall number the rows from above down. To the top most row is row 0, and then row 1 below it, finally row
6 is the bottom one.
Columns will be numbered from left to right , the left most column is column 0 and right most column 4.
So if we make the line of row 0 high or +5V then all the LEDs in row will get positive supply. And if we
Beginning PIC Microcontroller Programming / 191

apply negative to column 0 then only top left LED will turn on. If column 2 is given negative and column 1
is given positive then only second led in row 0 will turn on.
You can make your own modules by soldering the LEDs on a veroboard or you can get commercially made
modules as shown above. The pins under these modules are for rows and columns, however they are not
labeled. So you will need to figure out using a 3V battery. Just connect GND to one of the pins and touch
positive to all other pins one by one. Here we have fixed the column and seeking for row pins. The pins on
which an LED glow would indicate the row number, and the fixed pin GND will indicate the column num-
ber . Once these have been worked out, note them down on a page and label the pins as R0..R6 and C0..C4.
Making the Hardware.
We will connect the rows to an entire PORT of our controller. Let it be PORTB. So that RB0 is connected
to Row 0, RB1 to row 1 and so on.
The columns can be connected to another port, but since one column will be on at a time, this will drain all
the 7 LEDs. The current will be high for a PIC pin to handle. Therefore either you can use transistors to

drain it or use ULN2803 to drain them.


This figure shows how NPN Transistors are connected to the columns. A logic 1 at the base of transistor
will turn it on and connect the column to GND. The outputs from microcontroller will be connected to the
rows as shown. The current limiting resistor should be there, 220 ohms at least. This can be on columns as
shown here or in series with output pins, on rows. Now the base of these transistors can be connected to 5
other I-O lines of microcontroller. This is alright for this small project, but if you want to increase the num-
ber of modules this will become an issue. We will talk about this later. If your microcontroller has few I-O
lines then you will need lines for some switches, and other inputs. We can conserve the lines by using a
CD4017 decade counter. This counter has one clock input and 10 outputs. This counter increments the out-
Beginning PIC Microcontroller Programming / 192

put high one by one on every pulse until it reaches 10. then it rolls back to first output. It also has a reset
line when a pulse is given on this line the counter sets back to output 1. We will use this counter to control
the columns. Each output of CD4017 is connected to the corresponding base of column transistor. The
CD4017 inputs CLK and RST will be connected to the I-O lines of microcontroller.
Column Scanning
So what we will do here is illuminate one column at a time. In each column there are 7 LEDs, and the LED
which we want to turn ON, will have corresponding PORTB pin high. We can turn none or all the LEDs in
one column by just changing the value in PORTB register. Thus if PORTB= %0111111 then all the LEDs
in a column will turn ON. The question is which column? We have 5 columns. The one whose transistor is
ON will turn the LEDs ON, all other columns will be OFF.
So when we reset the 4017, only column0 transistor will get 1, and it will turn on, when we give a clock
signal to 4017, column 1 transistor now gets 1, and column 0 transistor gets 0. thus column 1 will get acti-
vated and whatever data is present on PORTB will appear on column 1 LEDs. Similarly another clock pulse
will activate column 2 and so on. This arrangement will ensure that only one column will be active at a
time. An reaching the column 5 we will give a pulse to RST pin of 4017 and this will bring the active col-
umn back to 0.
This technique where data is sent on
rows and columns are scanned one by
one is called column scanning. This is
easier to understand and implement in
software, thats why I chose this
scheme for beginner. This scheme will
however limit the number of columns
to 10 only as 4017 has 10 outputs. To
implement large number of columns,
we use another technique called Row
scanning.
In this technique data is sent for each
column on shift registers, like
74HC575. these shift registers can be
daizy-chained endlessly. The 4017 is
then used to scan the rows. Thus in in
this scheme one entire row will be dis-
played at one time.
For now lets stick with column scanning. We have a board that has a 5x7 matrix LED, and a 4017 decade
counter along with 5 NPN transistors on columns.
The connections will be as follows. Row 0 to RB0, Row1 RB1 .. Row6 RB6. Columns will be scanned
program Matrix5x7_1
symbol Col_Clk=PORTC.0
Symbol Col_Rst=PORTC.1
' Declarations section
Sub procedure Reset_Col
Col_Rst = 1
Col_Rst= 0
end Sub

Sub procedure Nxt_Col


Col_Clk=1
Beginning PIC Microcontroller Programming / 193

Col_Clk=0
end Sub
dim i as byte
main:
' Main program
TRISC.0=0
TRISC.1=0
TRISB=0
PORTB=255
while true
Reset_col()
for i=0 to 4
PORTB=255
Nxt_Col()
next i
wend
end.

through CD4017, CLK (Next Column) RC0, RST to RC1.


You can see we have set all the bits of PORTB ON. Although only 0 to 6 pits will be used as the display
has 6 rows. Each bit is associated with one row. When a high and then a low pulse is sent to Reset pin of
4017 through PORTC.1 the 4017 resets to position 0. This will select column 0. and all other columns will
turn OFF. A pulse at Clock pin of 4017 through PORTC.0 will enable next column an disable previous one
thus column 1 will turn ON according to whatever is high on PORTB. This will be repeated 5 times and
then again a reset is pulse is given to bring the focus back on column 0.
When this is done fairly fast our eye is not able to perceive that in fact only one column is ON at a time and
it will see the entire display ON, as shown in the image above. If you want to see this happening slowly,
just place a small delay, lets say 200ms before proceeding to next Column. This technique is called multi-
plexing or sometimes charliplexing.
Now how we can display custom characters or numbers? This is fairly simple. First of all we need to create
a bitmap of the
characters on a
5x7 matrix. Then
convert each col-
umn into an
equivalent binary
or decimal num-
bers. Then we
store this pattern in
an array of 5 bytes.
Each byte will hold
pattern of one col-
umn. Then using
our loops we will
display the corre-
sponding data from
array into display.
As an example see
Beginning PIC Microcontroller Programming / 194

program D5x7_2

symbol Col_Clk=PORTC.0
Symbol Col_Rst=PORTC.1
const dt as byte[5] = (0x40,0x47,0x48,0x50,0x60)
' Declarations section
Sub procedure Reset_Col
Col_Rst = 1
Col_Rst= 0
end Sub

Sub procedure Nxt_Col


Col_Clk=1
Col_Clk=0
end Sub
' Declarations section

main:
' Main program
dim i as byte
TRISC.0=0
TRISC.1=0
TRISB=0
while(1)
Reset_col()
for i=0 to 4
PORTB=dt[i]
delay_ms(1)
Nxt_Col()
next i
wend

end.

the various characters we have mapped here. The numbers are values of columns in hexadecimal. Thus to
display number 7 we need 40,47,48,50 and 60 hexadecimal numbers to be loaded into our register.
Similarly you can map all other characters like alphabets or special symbols and then display them on the
matrix.
In this program dt an array of constants has been declared and loaded with values of code for number 7.
remember this is the bitmap of the image we want to display.
Using advanced techniques and interrupts you can create a shadow array of 5 columns and stuff this array
with whatever bitmap you want to display, the interrupt procedure will happen many times a second and
will keep on refreshing the display.
Beginning PIC Microcontroller Programming / 195

Infra Red Communication and


24 Remote Controls

I
nfra red communication has been very popular in the past. Even mobile phones had infra red ports for
communication before the advent of Bluetooth. Nevertheless IR is still an important modality of com-
munication. Almost all remote controls used for TV, Music systems and air-conditioners use IR com-
munication. As far as use as remote control is concerned this is one way communication. Whereas
there are many devices that have two way communication.
Infra-red itself does not has any protocol limitations. It is we who impose protocols to make the communi-
cation more efficient, error free and reliable. We shall not go into much details, but will concentrate on
some basic principles to get started.
Before actually talking about the electronics and related software, it will be useful to talk briefly about the
physics and some background. Infra-red is a light that is not visible to our eyes. The frequency or in other

words wavelength of this electro magmatic radiation is below the visible spectrum of human eyes. Truly
speaking heat when transferred as part of sunlight or from a hot plate is in infra-red region. Thus with ap-
propriate sensors we can see the heat. Indeed there are cameras that can
sense the Infra-red light. Infra is a Latin word meaning below. If you
look at the spectrum, the frequency of red light is least one we can
sense, and violet the highest. The Infra-red have frequency below red
thus called infra-red.

Infra-red Sensors
Infra-red sensors are available in various forms with varying degree of
sensitivity and frequency to which they can best respond. In general
Beginning PIC Microcontroller Programming / 196

electronics the source of infra-red light is not the naturally occurring heat, but specific frequency IR-LEDs.
These LEDs have 850nM, 880nM or 940nM wavelengths. Corresponding sensors are made that are opti-
mized to sense these lights, but can also detect the lights in other range. The sensitivity is however maxi-
mum to the wavelength for which it is designed. It is therefore important always to get The IR Transmitter
and receiver pair. We would call IR-LED as IR-Tx and IR sensor as IR-Rx.
IR-Tx are just like other LEDs, they have an anode and a cathode,
but you can not see the light. Secondly the IR-Tx require drain little
more current than ordinary LEDs so it is better to drive them
through a transistor, or if connected directly with microcontroller
have a current limiting resistor. There is a trick through which you
can see the IR LED glowing. This will help you recognize the IR
LED from a dead ordinary LED. Most modern day digital cameras
are also sensitive to IR light to some extent. You can shine an IR-
LED and see it through your mobile phone camera. Test it with your
TV remote control and see its LED with digital camera while press-
ing a button.
Driving an IR LED.
Infra red LED requires more energy than ordinary LED to give full
capacity IR wave. However for simple purpose giving less energy
will make it work, but the intensity will be less.
You can attach it directly to the microcontroller pin but through a
1K resistor to protect the microcontroller from excessive current
drain. The preferred method is however to use through a switching
transistor. Combining more than one LEDs in series would give
stronger signal. How many LEDs to drive with a transistor would
depend upon the current rating of your transistor. I would prefer
using two LEDs.
Notice the current limiting resistor is only 10 Ohms. The value will
depend largely on your transistor. But you can use from 10-100
Ohms depending upon transistor characteristics and weather the
supply voltage will be 5V or 9V.
You can use any general purpose transistor, like 2N2222 that is
commonly available it has Collector current of 800mA. I used
2N3904 it works, but its current rating is too small only 200mA. So to practice you can use anything you
like but for serious work try using something with more current capacity. BD681 used in this circuit is
power Darlington transistor and can take up to 4A of current which I think is beyond the requirements.
Many Infra-Red LEDs can be driven at currents approaching 1000mA. Usually they are not illuminated
continuously ON, otherwise they get burnt up. They are usually driven through pulses. The pulse should
drive a transistor that is capable of delivering high current load.
Infra-Red Sensors
Infra-red sensors to detect 940nM wavelengths are easily available. They are actually photo diodes, and
therefore need to be connected in proper polarity. These
sensors will reduce their resistance when a proper IR
light is received. The drop in resistance is proportional to
the intensity of light received.
Depending upon the manufacturer it may be dark in color
as in this figure or it can be clear like IR-LED. Therefore
if you have the one with clear variety always keep them
labeled. I personally use a red or black marker to put a
dot at its base.
Beginning PIC Microcontroller Programming / 197

Using Infra-red Sensor


The simplest circuit uses it as part of a voltage divider circuit. As shown in the
figure. The output is analog voltage and must be connected to ADC of your
microcontroller to sense the incoming voltage. When there is no IR light the
sensor resistance is very high and ADC gets almost 0V. As the IR light is
sensed the resistance drops and the ADC sees volts. The value of voltage will
be proportional to the amount of IR light.
More complicated circuits exist they basically incorporate an operational ampli-
fier to amplify the signal, and then use a comparator to compare the signal to a
predefined value. When that signal is reached the comparator gives out logical
1, that can be seen by the microcontrollers digital pin.
These are two circuits in one the photodiode is connected to inverting input of operational amplifier and in
other it is connected to the non-inverting input.
The output in first circuit will be high when
there is no IR signal and low when there is IR
signal. This is opposite in the other circuit. You
can omit the 1k resistor and LED if you want
and connect the output of OP-AMP directly to
the digital input of your microcontroller.
You can use an OP-AMP IC that has 2 or 4 inde-
pendent OP AMPS in them and use them to have
two or four independent sensors.
The circuit board I am using has the simple cir-
cuit shown above, and the IR sensor output is
connected to ADC of microcontroller, therefore
we will need ADC conversion. If you are using
OP-AMP then you can simply check the input
Beginning PIC Microcontroller Programming / 198

pin as either high or low.


38 KHz Modulated Sensors
Native IR sensors mentioned previously are great. They are sensitive
to specific narrow range of IR light emitted by IR-LEDs. This kind of
wavelength can also be present in our environment and sensors can
perceive false signals if not carefully shielded. Most of the industry
leaders in IR-Technology now agree that native IR should not used
directly for communication specially where data exchange is required.
They therefore use a 38KHz Modulated data communication. The data
is sent as IR pulses, with 38KHz frequency. The sensors therefore
sense only 38KHz modulated signals and ignore any other IR signals
reaching them. The ordinary IR sensor with some necessary filter cir-
cuitry can be adapted to respond only to 38KHz signals. Fortunately specially designed sensors are avail-
able that can do the job.
These sensors have three pins, two for 5V power supply and one for output. The output is open collector,
therefore requires a 10K pull-up resistor. The pin can be directly connected to the microcontroller. On re-
ceiving a 38KHz signal it will produce a logic 0 at the output. The output pin will not have pulses, but only
logic 0 to indicate the sensor is receiving 38KHz IR signal. Absence of signals is indicated by logic 1
through 10K resistor. This is the function of this sensor. It does not decode the data presented to it. Almost
all TV remote controls use 38KHz modulated data to send information as to which button has been pressed.
Just to experiment the receiving of data, and not to decode you can simply check the I-O line to which the
output has been connected, if the line is low or high. In case line is Low you can toggle the LED. Now us-
program IR1
symbol LED= PORTB.2
symbol IR = PORTB.6
' Declarations section

main:
' Main program
TRISB.6=1 'Input IR line
TRISB.2=0 'Output LED Line
LED=1
while true
if IR=0 then
LED= not LED
delay_ms(200)
end if
wend
end.

ing any remote control you can press any button and LED should toggle.
This simple program should work for you, to indicate that you have connected your IR sensor correctly.
Before moving forward it is important to understand what is meant by modulated signals.
38KHz IR Modulation
Modulation stands for a process of varying one or more properties of a waveform to encode a data or infor-
mation over it. In easier terms lets consider a musician playing with a flute. The frequency produced by
Beginning PIC Microcontroller Programming / 199

flute is always constant, it does not change while its is being played. When you blow through it a sound of
fixed frequency is produced. Now the musician alters it amplitude or other parameters like harmonics etc.
to produce a musical note that carries a sort of message. This is called modulation. You might have heard
about modulation in radio frequency communication, like AM and FM.
In IR communication we are not going to alter the frequency, but to encode our digital data which is in the
form of 1 and 0 over this. Fixed protocols exist as defined by IRDa (Association of Infra red Data commu-
nication). No doubt you can define your own protocols as well. Simply speaking we will define a logic 1 as
presence of IR signal and Logic 0 as absence of signal.
Standard protocols however do not take absence of IR as 0. They usually define both logic 1 and logic 0
states in terms of presence of IR signal. For example one protocol defines if IR signal is present for 600us
then it will be considered as logic 1, and a signal of 350us duration will be considered as logic 0. there will
always be a gap of 60us between any two bits. This is how IR remote controls operate. Although it looks
complicated, but we have to understand it in order to have command over this system.
As I mentioned earlier that IR is not only meant for remote control devices, but it is full communication
medium just like wires. In the first part of this chapter we will make a system of our own IR communica-

tion where two microcontrollers can communicate over an IR-Link just like USART but this time the link
will be established over IR.

Hardware Requirements
Since we are going to use 38KHz modulation, we need to produce signals with 38KHz frequency. Since our
IR-LEDs only act as simple LED, we have to give it 38KHz pulses to produce a modulated signal. There
are easy ways to do it and hard ways to do it. We need two controls over the LED. First it should be pro-
ducing a pulsed wave output and not a continuous beam. Second we should have a control that should en-
able or disable the output. Thus we need a pin that when set to 1 should enable the LED to produce pulses,
as long as it remains high. And when it is 0 the LED should
not produce pulses.
We therefore need two basic structures, one a 38KHz Oscil-
lator and other a digital gate allowing these pulses to pass on
to LED. Then definitely there has to be an LED driver itself.
We can obtain the 38KHz pulses from PWM output of our
microcontroller if your project permits so, I however feel it
is a good idea to make a general purpose module that can be
connected to any pin of microcontroller only to get data.
Therefore having the oscillator right on board.
This figure shows the basic idea. You will need an AND or
NAND gate to driver the IR LED circuit. The two inputs of
NAND gate will get 38KHz oscillator input and other will
receive data. The 38KHz oscillator can be made using other
NAND gates, or using 555 timer oscillator.
There is another trick that you can easily play with 555 to
make an oscillator that will oscillate only when its input pin
Beginning PIC Microcontroller Programming / 200

is made high.
As there is no Input pin in 555 it looks strange. Note the pin 4 of 555 is reset pin, when it is made high it
works as oscillator, and when taken down to 0 it stops oscillating, so you can easily make the 38KHz oscil-
lator with data input using only 555. Do not drive LED directly from 555 output rather use 2N2222 or some
other transistor that can supply at least 800mA current.
It is important to have a 5K variable resistor in the timing circuit so that you can fine tune the transmitter.
Now just connect the GND or even power to your board and connect the pin 4 of 555 to data transmitter pin
of your choice. You will need to add the 38KHz receiver to this board, and its output pin will got to your
microcontroller where you would like to receive data.
Thus a completed board will have power connections, a Tx pin, that will be the output of your 38KHz sen-
sor, and an Rx pin that will be the pin 4 of your 555 timer. You will need two such boards and two micro-
controller boards to experiment with data transmission. We will send data from one microcontroller to the

program IR2
Symbol IR_Tx=PORTC.7 'RC7 is TX
Symbol IR_Rx=PORTC.6 'RC6 is RX
Symbol LED = PORTB.2
' Declarations section
main:
' Main program
TRISC.7=0
TRISC.6=1
TRISB.2=0
LED=0
while true
IR_TX=1 ' Transmit signal
if IR_Rx=0 then
Beginning PIC Microcontroller Programming / 201

LED=1
else
LED=0
end if
wend

end.

other over IR link using USART protocol. Connect Tx of IR board to Rx of microcontroller (RC7) and Rx
of your board to Tx of Microcontroller (RC6).
First you have to tune the boards so that we are sure they are transmitting at 38KHz. For that you can use
this program and then tune the 5K resistor until the 38KHz signal is sensed on the other board.
Run this program on both boards, and fine tune the transmitters.
program IR_Tx

' Declarations section


dim txt as string[16]
dim i as byte
main:
' Main program
Soft_uart_Init(PORTC,7,6,2400,1)
txt="Welcome"
while True
for i= 0 to Length(txt)
Soft_Uart_Write(txt[i])
next i
wend
end.

Once this link is established we can very easily transmit the data.
Lets transmit a welcome message from one board to the other. The data received on other board will be dis-
played on LCD. This program will continuously transmit the Welcome message over the IR module.
Now we have to make a receiver module that will receive the data and display on LCD. This program will

dim x as byte
main:
' Main program
UART1_Init(2400)
while true
if (UART1_Data_Ready() = 1) then
x = UART1_Read()
Lcd_chr_cp(x) ' write one byte to the LCD
end if
wend
end.
Beginning PIC Microcontroller Programming / 202

run on other microcontroller board.


The code will contain declaration for your LCD connections.

The two programs look simple but they have lot to discuss and understand. First of all notice that in the
transmit program I have used software library to transmit the data. Although pins used are same RC7 and
RC6, but instead of using the USART module I have used the software based serial communication. How-
ever on receiver side I have used the USART module directly.
Notice that the 38KHz sensor gives
logic 0 when the signal is received. Our
IR transmitter transmits the signal
when a logic 1 is received. Thus when
the transmitter is connected to the hard-
ware USART module and data is sent,
naturally data consists of 1s and 0s. On
every logic 1, an IR signal is produced.
The sensor senses it and produces a
logic 0 at the output that enters the Rx
of receiver board. This totally reverses
the data. So when the transmitter sends
10101010 the receiver gets 01010101.
to correct this problem we have to in-
vert the data while sending. This is so not only for the actual data but also for the start and stop bits of serial
communication, that are not part of any data as such. The hardware USART module can not invert it as it is
supposed to work straight away through a wire or some other medium that transmits a logic 1 as logic 1 and
logic 0 as logic 0.
Software USART however has a last parameter for inverting data. Look at the statement:
Soft_uart_Init(PORTC,7,6,2400,1)
The last parameter 1, indicates that the data transmitted will be
inverted including the start and stop bits. This inverted data is
sent to transmitter and the receiver by nature of its design again
inverts it and the Rx line gets correct data.
Do not use baud rate more than 2400.
So one solution was to use the Software Library to invert the
data and correct the problem imposed by our sensor. An even
better solution would be to correct the issue of sensor. Why not
to invert the signals produced by sensor so that when IR signal
is received it should produce a logic 1 and when not it should
produce a logic 0.
This can be corrected by placing a transistor on the output of
sensor.
The transistor is acting as an inverter or not gate here. When a
logic 1 is present on out pin of sensor the transistor turns on and
produces a logic 0 at its collector. When the sensor produces logic 0 the transistor turns off and 10K pull-
up resistor produces logic 1 at the collector.
Now you can send non-inverted data from the transmitter either directly through USART module or
through software, but this time setting inverting parameter to 0.
Standard method of Data Communication
In the above method we have devised a simple solution to send and receive data. This technique can not
Beginning PIC Microcontroller Programming / 203

only be used as part of USART, but you can send any type of 1s and 0s over the link. The module we have
developed sends modulated data when the logic 1 is received and stops transmission when logic 0 is re-
ceived. Although we have successfully demodulated this data back into original form and shown that the
data was successfully transmitted, but this is not the standard communication protocol.

The standard communication protocol defines that logic 1 and logic 0 both should be transmitted as a
modulated pulse. Then how we will differentiate between a 1 and 0? This is done by varying the timings or
duration of the pulse. For example we can define that logic 1 will be a 1200us duration pulse and logic 0
will be 600us duration pulse. In between the pulses there will be no pulse for 600us.

The protocol further defines that there should be a specific length of pulse that indicate beginning of com-
munication and at the end there should be an end pulse. To meet these requirements we have to implement
either a controller to encode and decode the timing pulses into 1s and 0s or specialized ICs that called en-
coders and decoders and specifically made for this purpose.
We shall make this feature our self using microcontroller to decode the remote control data. Earlier we had
seen that we could only sense the presence of remote control button press, now we will look little more
deeply to decode it.
All remote controls follow the standard practice of encoding the logic 1 and logic 0 as pulses of different
duration. The standard of this duration is different among the manufacturers of remote controls. There are
many defined protocols for this purpose and most manufacturers follow one or the other protocol. One such
protocol is called RC5. this was first introduced by Philips electrical and still followed by a number of
manufacturers. Another protocol commonly followed is developed by Sony called SIRC. A large number of
equipment manufacturers follow this protocol. We shall discuss this protocol here and develop a code to
decode the signals sent by Sony remote control and then use that data in our program.
Since remote controls are very commonly used in electronics some compilers provide pre-built library func-
tions to decode these remotes. Unfortunately MikroBasic does not have such a library so we will have to
write the code our self. Although a long task for an apparently simple issue, but it will serve to understand
the inside story of remote controls.
Sony Infra Red Remote Control Protocol
When you press a button on a Sony remote control, an infrared signal is transmitted. This transmission con-
sists of a 38kHz signal which is turned on and off in a particular pattern. Different buttons correspond to

different codes, which cause the signal to be turned on and off in different patterns.
The Sony protocol defines that a logic 1 will be represented by 600us pulse and a 0 will be represented by
300us pulse. In between the pulses there is a gap of 300us. There is a start header of 2400us. Each com-
mand or button press sends a 12 bit data composed of these encoded 1s and 0s.
A typical oscilloscopic trace shows how 1s and 0s are encoded. Following header the remote control trans-
Beginning PIC Microcontroller Programming / 204

mits 12 bits of data. Least Significant bit (LSB) is sent first. When all the 12 bits are received, the lowest 7
bits contain the command for button pressed, and higher 5 bits contain the device code like TV, CD Player,
VCR etc.
The remote control will send 1s and 0s as 38KHz pulse, this pulse will be seen as logical 0 by our sensor
unless we have an inverting transistor at its output.
The figure here shows the data frame of a button press. The second table shows the device codes. Note the
figure above shows S on left side and then command bits. However when writing a binary number it is cus-
tomary to show the least significant bits on right.

Symbol Sony_IR = PORTB.6


LCD Declarations here

sub procedure Wait_forGap


while Sony_IR=1
wend
end Sub
' Declarations section
dim p_val as word 'Variable to get time for each pulse
Beginning PIC Microcontroller Programming / 205

dim x as word 'To store 12 bit code


dim i as byte 'counter variable
dim txt as string[16]
dim Sony_Device as byte
dim Sony_Command as byte

main:
' Main program
Lcd_Init()
Trisb.6=1 ' IR Sensor Input

While True

while Sony_IR=1 'Wait for an IR signal


wend

P_val=0

while sony_IR=0 'Wait for Header to Finish


inc(p_val)
delay_us(1)
wend
Wait_forGap() 'Wait for the gap to finish
X=0
for i=0 to 11 'Get 12 bits of data
p_val=0

while Sony_IR=0 'Count in a variable the pulse time


inc(p_val)
delay_us(1)
wend
x= x >> 1
if p_val > 500 then
x.11=1
end if
Wait_forGap()
next i

Sony_Command= x AND %01111111


BytetoStr(Sony_Command,txt)
Lcd_Out(1,1,txt)
Sony_Device= %00011111 AND (x >> 7)
BytetoStr(Sony_Device,txt)
LCD_Out(2,1,txt)
Beginning PIC Microcontroller Programming / 206

delay_ms(1000)
Wend
end.

Thus the correct orientation would be a 12 bit number bits 0..6 containing the button command and bits
7..11 contain device address.
Now lets write a program that will read the remote control and display the device code (of the remote) and
the button pressed on LCD. We will omit the LCD declarations here.
Well this program needs little discussion. First thing is to wait for the header to appear.
while Sony_IR=1
wend
This loop will continuously monitor the port for a signal to appear. Remember we this is just a prototype
program concentrating more on decoding than to checking validity of remote data. When a signal is re-
ceived, this loop is terminated, it is assumed that a remote control button was pressed and a header is being
received. Next we again monitor the sensor port pin till the header signal is there. During this monitoring
we wait for 1us and count the number of loops in a variable. This will roughly coincide with duration of the
pulse in microseconds. After the header is finished there is a gap so we wait for the gap to finish.
After the header is finished we are now ready to receive the 12 bit pulses. For every pulse we run a similar
counter and measure the pulse duration. If the duration is more than 500uS (actually close to 600 uS) this is
logic 1. and anything below 500uS (actually 300uS) is 0. since variable x has already been set to 0. all bits
are 0. we shift the bits right by 1 and in case the pulse is logic 1, we set the bit 12 (x.11) to high. Every time
the bits are shifted right by one and new bit is received in x.11. In this way when all 12 bits have been re-
ceived, the Least significant bit received first after the header has reached the place x.0
Now we have the 12 bit number in variable x. First we extract the least significant 7 bits from it into the
Sony_Command variable.
Sony_Command= x AND %01111111
This is done by bitwise And operation. Next we shift the higher 5 bits down by 7 bits and again do a bitwise
And operation to separate the device code.
Once you have separated the device and button code you can now proceed with rest of your program to do
whatever action you want on the basis of the button pressed.
We will now make a small application where we will control the LEDs by pressing the corresponding but-
ton on remote control.
Before that I would like to discuss a little bit about the bitwise operations as they are part of programming
language and frequently required.

Bitwise Operations
Again little bit of theory and programming methodology. Just like mathematical procedures like addition,
subtraction and multiplication etc that we can perform on byte sized or above data, there is often need to
manipulate the individual bits of a data. The data itself can be of any size. These procedures are called bit-
wise operations.
Although there are some high level commands that can resemble or
achieve similar results, the bitwise operations are much more faster than
these. Secondly these operations consume very small amount of pro-
gram memory and as a result compact code is produced.
Shift Right and Shift Left Operations
A shift right and shift left operation is performed on the entire byte or
Beginning PIC Microcontroller Programming / 207

word whatever you choose. The shift right operator identified by >> sign shifts all bits one or as specified
positions to the right. The least or most significant bits that fall outside the boundary of variable or register
fall away and are lost. New bits that are always 0 are added to the extreme other end to fill the place of
shifted bits.
The figure here shows a shift left by one bit operation. Notice how the original bits are shifted one position
to left and a 0 is inserted at the LSB position. Mathematically the effect of this shift is equal to multiply by
2. Similarly a shift to right has an effect of division by 2.
A= x >> 1
Causes the shifting variable A to contain pattern with shifted bits, but the value of x itself remains un-
changed. X = X >> 1 will affect the original variable as well.
Bit-Wise NOT Operation
The NOT operation reverses the bits from 0 to 1 and 1 to 0. this can be applied to single bit to toggle its
value or to the entire byte.
PORTB.0 = NOT PORTB.0
This will toggle the status of PORTB.0 bit
X= NOT A
This statement will take the bit pattern in variable A and reverse them and place the result in variable X.

The original value of A will remain same.


Bit-Wise AND Operation
A bit-wise AND operation compares the two bits in same location and produces a result based upon values
of both bits. If both bits are 1 the result produced is 1, otherwise the result produced is 0.
A bit-wise And is most commonly used to extract the bit pattern from a given variable. For example we are
interested in a number that is present in lowest 4 bits of a byte. We will AND this number with a fixed
number whose lowest 4 bits are all set to 1.
C = X AND %00001111
Since our masked number has highest 4 bits all 0, they will always get 0 in those positions wheather there
were 1s or 0s in those positions, and since lowest 4 bits in mask are all 1s, they will get 1 at position where
X has 1 and 0 where X has 0.
Notice we used this to extract the 7 bit command code from our 12 bit remote control data. Then we shifted

the upper 5 bits by 7 positions to right and then AND them with %11111 to get the device code.
Bit-wise OR Operation
A bit-wise OR will also compare the two bits in matching positions and produce a logical 1 if any of the
positions is 1. if both are 0 then a 0 is produced.
Beginning PIC Microcontroller Programming / 208

Bit-wise OR is usually used to set individual bits of a byte or register. Although we can do it like
PORTB.7=1, PORTB.5=1 instead of doing it in two steps we can set them both in one step.
PORTB= PORTB OR %10100000
This will set both bits 5 and 7 in one step. This kind of operations are used to set the bits of individual regis-
ters where usually many bits need to be set.
There are other bit-wise operators but not very commonly used therefore we will not discuss them here.
Application to Control Individual LEDs with Sony Remote Control
Lets come back to the practical application. In the last example we had developed the code to decode the
SONY IR remote control and display the values of keys pressed on LCD. Lets put this code into something
usable as well as Re-Usable. This word Re-usable is very important that since the code developed after ex-
tensive research and experiments will be required in a number of applications. Thus it should be packed
into something portable or plug-N-play.
In this application first we will convert the code into self contained function and name it SonyIn() this func-
tion will encapsulate the entire functionality and will need to be called from the main program when re-
program SonyIR
Symbol Sony_IR = PORTB.6
Symbol LED1 = PORTB.2
Symbol LED2 = PORTB.3
Symbol LED3 = PORTB.4
Symbol LED4 = PORTB.5

sub procedure Wait_forGap


while Sony_IR=1
wend
end Sub
Sub Function Sony_Get_PulseTime() as word
dim z as word
z=0
While Sony_IR =0
inc(z)
delay_us(1)
wend
result=z
end sub

Sub Function SonyIn() as Word


dim P_Val as word
dim i as byte
'wait 1000 us For the signal
P_val=0
while (Sony_IR=1 and (P_val < 1000))
inc (P_val)
delay_us(1)
Beginning PIC Microcontroller Programming / 209

wend
if p_val = 1000 then 'Timeout no signal so
return 0
result=0
exit
end if
' Get Header ignore its value just wait for it to
finish
P_val=Sony_get_PulseTime()
Wait_ForGap()
P_val=0
for i=0 to 11
P_Val=p_val >> 1
If Sony_get_PulseTime() > 500 then
P_Val.11=1
end if
Wait_ForGap()
next i
lo(result)= P_val AND %01111111
hi(result)= %00011111 AND (P_val >> 7)
end sub
' Declarations section
dim x as word
dim txt as string[16]

main:
' Main program

Trisb.6=1 ' IR Sensor


TRISB.2=0
TRISB.3=0
TRISB.4=0
TRISB.5=0
PORTB=0
While True
x=0
while x=0
x=SonyIN()
wend
select case lo(x)
Case 0
LED1= NOT LED1
case 1
LED2=NOT LED2
case 2
Beginning PIC Microcontroller Programming / 210

LED3 = NOT LED3


case 3
LED4 = NOT LED4
end select
delay_ms(500)
wend
end.

quired. The function will look for IR data and if no data is found it will return a word sized 0. when a data
stream from remote control is detected it will read the 12 bit data and convert it into a word sized variable,
the low byte of this variable will contain the command of button pressed, and the high byte will be the de-
vice ID of remote.
In this program SonyIN() is the function that needs to be called from the main program. The function re-
quires a Symbol named SONY_IR to be defined as the pin to which your 38KHz IR sensor is connected.
There are two more supporting functioning a Sony_Get_PulseTime() and Wait_ForGap() both these func-
tions are called by SonyIN() to get the pulse time and the gap. The code could be written as part of SonyIn
function but this would result in repeating code many times, to minimize this these two supporting func-
tions were made.
Now in the main routine we declare the direction of IR pin as input and just call the SonyIN() function. We
have called it in a loop, so that it keeps on waiting till a signal is received. Once signal is received the re-
turned value has the code of key pressed in its lower byte and the code of device in higher byte.
Then based upon the value of lower byte we have setup a Select Case Structure. This is useful where many
Ifs are required based upon same input parameter. The number returned by keys 1,2,3 and 4 are 0,1,2 and 3.
the corresponding LEDs have been toggled on the key press.
Now when you can toggle the LEDs, you can replace them with relays and drive the heavy load like fan,
bulb etc.
Beginning PIC Microcontroller Programming / 211

25 SPI - Serial Parallel Interface

S
erial parallel interface is yet another method of communication in which the data is internally dealt
with as parallel and transmitted as serial. This is no different than USART where the data inter-
nally is a complete byte and is transmitted or received over a single wire one bit at a time. This
protocol can work only for short distances but is simple to implement and its speed can go up to
many Mega Bytes per second.
Just like I2C it has a master and a slave device. The
master will initiate the process and control the timing of
bit transfer. Since it is very commonly used protocol
many microcontrollers have its module pre-built into
them. In PIC microcontrollers it is part of MSSP mod-
ule. MSSP module also contains I2C, but SPI has its
own setup.
The main advantage of SPI is that you do not have to
move the entire 8 bits of bus on the PCB, and need only
few I-O lines to be moved around. Moreover it will
spare your I-O lines and still allow internal processing on 8 bits of data. The disadvantage is that the bus
will allow only one device connection. If we need to connect many devices to the same bus we need to indi-
vidually control their enable pin to select the device of choice.
It is important to explore this protocol because a number of special purpose chips, or other devices are
available in market that follow this protocol. These include many data loggers, SPI EEPROMs, SPI ADC
and SPI DAC etc. Even we can make our own devices to be SPI slaves that can be connected to to other
master devices. For example you can make your own SPI LCD or a motor driver.
Now lets talk little bit in detail. The figure above shows basic idea of a serial interface. The data is inter-
nally an 8 bit number and it is transmitted out as one bit a time. This has been the case with USART as well
as I2C. So what is different?
In USART the data is sent in an asynchronous form. This means when the data is being transmitted there is
no guaranty that the receiver is receiving it or not. This was refined to some extent in I2C where a clock
signal is produced to synchronize the slave or recipient thus the two processors work in harmony with each
other. However I2C sends and receives data on the same line and has speed approaching around 400KHz
Maximum.
The SPI is a simplified form of I2C. It
has two data lines one for sending data
from master to slave (MOSI) and other
for receiving data from slave to master
(MISO). A third line is clock line used to
synchronize the master and slave
(SCLK). A fourth line is optional in case
you have more than one chips on the bus.
This is called chip select pin. The Chips
select has to be logic 0 to activate the
chip. Thus a logic 0 on this line will en-
able the chip and make it ready to re-
spond.
Beginning PIC Microcontroller Programming / 212

The beauty of this interface is that it can work in full-duplex mode. This means that while it is sending data,
the other line can simultaneously receive data.
Although we have the SPI module built into the controller and we can use it to manage the serial write and
read, it is also possible to implement the functionality through software. When using the SPI module you
are bound to use the specified lines of microcontroller. However if you are using software technique any I-
O line can be used.
Basically all SPI compliant devices use a shift-register, either embedded inside the controller or used as a
standalone integrated circuit. The simplest SPI type device can be made using a shift register. Many people
use it actually to expand their I-O lines. Specially for output as to drive many more relays than the I-O lines
of microcontroller.
Shift Register
Shift register is an electronic circuit where a number of flip-flops hold a serial data. The flip-flops are con-
nected in a chain, having common clock input. On every clock the flip-flops shift their data to the next one,
dropping the last one to an output line, and receiving a new bit on the first one.

The output from each Flip-flop can be reflected on corresponding output pins. Thus a serial data sent in
data in pin synchronized with clock pulses will be shown as parallel on the shift register output pins. This is
a complete Serial In Parallel Out system. Its correspondingly opposite Parallel
In and Serial Out also exists.
Since output of first Flip-flop is connected to input of next, the output of last is
usually available as output for next chip. In this way the shift registers can be
connected in a countless chain to hold any number of output bits. In the above
simple scheme it seems that the outputs Q1, Q2...Q4 etc will get the data as its
shifted. Practically its not so. The outputs are connected to the flip-flops
through a latch register. When we are shifting in data like 8 bits of data the bits
do not appear on output lines. When data is
complete we send a signal to the latch, to
fetch the flip-flop outputs and show them on
output lines. After that even if we clear the
flip-flops the latch will hold the older data
on output lines till we ask it to fetch again.
74HC595 8 Bit Shift Register
The 74HC595 is a very handy IC used in
many microcontroller projects. You clock in
8 bits of data (like, on/off settings for 8
LEDs) via two lines, and when you toggle a
third line, it pops these settings out on 8 out-
puts on the IC. So you trade 3 valuable lines
on your microcontroller for 8 outputs.
This is called "Shifting data out" of the mi-
crocontroller by "synchronous serial com-
munication". This is the serial part of the
deal, where each bit is "shifted in" one at a
Beginning PIC Microcontroller Programming / 213

time, then BOOM, they all appear at once (in parallel) on the chips output. It takes about 260 nano seconds
to shift its bits. This is pretty high speed and therefore can take in very high speed data. The data sheet says
it can get data up to 100Mhz.
The above schematic shows how to connect it to your microcontroller. Pin Number 9 is the serial data out
in case you send more than 8 bits this can be used to connect to data-in of next shift register chip and thus
have 16 bit output only from 3 microcontroller lines. The microcontroller will be sending data on one line, a
synchronizing pulse on other and when all bits have been transferred a pulse on latch.

program SPI_Shift
symbol SD = PORTC.1
Symbol CK = PORTC.0
Symbol Latch = PORTC.2

' Declarations section


Sub Procedure Shout_LSB(dim x as byte)
dim i as byte
SD=0
CK=0
Latch=0
for i=0 to 7
SD= x AND 1 'Test least significant bit if
its 1
Beginning PIC Microcontroller Programming / 214

CK=1
CK=0
x=x>>1
next i
Latch=1
Latch=0
end sub
dim b as byte
main:
' Main program
TRISC.0=0
TRISC.1=0
TRISC.2=0
Shout_LSB(205)
end.

As using a shift register does not comply truly with SPI protocol which includes both read and write and
chip enable bits, therefore the standard SPI commands can not be used with shift register directly. Moreover
it is more useful and powerful to develop interfacing code yourself that will enable you to play more liber-
ally. Most dialects of Basic compilers contain a very useful command called SHOUT. This is Shift Out
command and is used to transfer 1 bit at a time from byte sized or word sized data, while clocking the clock
pin on every shift.
MikroBasic unfortunately lacks this command and we will need to implement it ourselves. Once you have
developed the procedure it can be used in other programs when required. In the above example we have
connected the three wires of shift register to RC0..RC2. We have defined the the connections as symbols so
that it becomes easy to speak about them in the program. So SD is serial data pin, CK is clock and Latch is
obviously Latch.
There are two ways to transfer the bits, Least Significant Bit First (LSBF) or Most significant Bit First. The
choice will depend upon your application design. When LSB is sent first it will progress through Q0..Q7.
Thus the most significant bit transmitted last will be present in Q0 and least significant bit will be in Q7. If
you want it other way round then you will send MSB first.
In our procedure we are going to shift LSB first. So we have to test the LSB of the data in x. if it is 1 we set
SD line high and if its 0 we set this line 0.
SD= x AND 1
This is simply done by bit wise AND operation. The 1 is binary %00000001 thus it will check the least sig-
nificant bit and will set SD line accordingly, once this is done we send a clock pulse by setting CK high and
then low. This will transfer the first bit into shift register. Now in order to send second bit, we shift the bits
right by 1, so that second bit now shifts to LSB position in X. we repeat the process and its also transmitted.
We do it 8 times in a loop and when loop finishes we are sure all 8 bits have been transmitted. Now we give
a pulse to latch and the transmitted bits appear on the output lines.
Now you can call this function from your main program to send any byte sized data, as we sent number
205. The binary of 205 is %11001101 Notice this sequence from Q0..Q7. You can also make similar pro-
cedure for Most significant bit first. Simply AND x with %1000000 (128) this will test the most significant
bit, and instead of shift right use shift left (x= x<<1).
We will use this concept of using shift registers in our 8x32 LED message board examples. As I mentioned
earlier just like the Shift Out register which SIPO (Serial In Parallel Out) we also have Parallel In Serial
Out (PISO). This 74HC164 Integrated circuit. The operation is similar except in stead of writing the bits to
Beginning PIC Microcontroller Programming / 215

a pin, this time you will get the data on pin, now you will assign it to the variable bit lets say bit 0 and then
shift the bits to left to create space for next bit. This process will be similar to the one we used to get data
from remote control.
Now lets come to the true SPI devices. As I mentioned earlier the SPI devices have SDI (serial data In),
SDO (Serial data Out), CK (Clock) and CS (Chip select pins). The chip select pin in most devices is active
when Low. Also if the device has to perform some function that function starts when the Cs pin is acti-
vated.
Although SPI devices have SDI and SDO pins you are not bound to use both. For example if you are using
an SPI Analog to digital converter (ADC0832 for example) you may not want to write to it but read it to get
the data. Why you should use SPI ADC when PIC has built in ADCs. Well not all PIC microcontrollers
have ADC, so if you are forced to make a project on a particular controller you might need to use this. The
other valid point is speed. Microchip ADC is not very fast, it takes a while to make conversion, thus in
places where you need more speedy conversion you can opt for an external fast ADC. This was just a dis-
cussion, of course you must know at least how to use these chips.
In case of SPI EEPROM you will need to write and read both. In that case you will need to connect both
SDO and SDI pins.
MCP4921 SPI 12 Bit Digital to Analog Converter
We are going to demonstrate the use of MCP4921 chip. This is pro-
duced by microchip and works with SPI protocol. This is a 12 bit digi-
tal to analog converter. With low noise operational amplifier and sin-
gle supply source. The output can be used to set offsets and various
other applications where analog signal is required.
MCP4921 contains one DAC module, its sister chip MCP4922 con-
tains two such modules, the operation is similar. You will need to con-
nect three connections, CS is chip select, SCK is clock and SDI is data. The LDAC is latch and can be
safely tied directly to GND for most purposes. VRefA is the external reference volts. This the voltage level
which will define the highest voltage when all input bits are set to high.
We can communicate using SPI protocol either directly using hardware SPI module or through software.
When using hardware module, the SDI of MCP4921 is connected to SDO of PIC microcontroller. Similarly
if the chip has SDO it will be connected to SDI of microcontroller. Remember SDO stands for Serial data
Out and SDI for serial data In. Naturally you will connect SDO of one chip with SDI of other.
AVss is the analog output from MCP4921. Each SPI device has its own method and configuration to oper-
ate. The MCP4921 accepts 16 bit command. The highest 4 bits are configuration bits for the MCP4921,
and rest of 12 bits are the Digital number to be converted into Analog volts. A 12 bit number means 212 this
turns out to be, 4096. Therefore the highest number in 12 bit digital data will be 4095. when number 4095
is sent to DAC it will produce an output almost equal to the VRef. Dividing VRef by 4095 will give you the
increment in volts per step.

program SPI_DAC
dim Chip_Select as sbit at RC1_bit
SoftSpi_CLK as sbit at RC3_bit
SoftSpi_SDI as sbit at RC4_bit
SoftSpi_SDO as sbit at RC5_bit

dim Chip_Select_Direction as sbit at TRISC1_bit


SoftSpi_CLK_Direction as sbit at TRISC3_bit
SoftSpi_SDI_Direction as sbit at TRISC4_bit
SoftSpi_SDO_Direction as sbit at TRISC5_bit
' End DAC module connections
Beginning PIC Microcontroller Programming / 216

Sub procedure DAC_Output(dim valueDAC as word)


dim temp as byte
Chip_Select = 0 ' Select DAC
chip
' Send High Byte
temp = hi(ValueDAC) and 0x0F ' Store valueDAC
[11..8] to temp[3..0]

temp = temp or 0x30 ' Define DAC


setting, see MCP4921 datasheet
Soft_SPI_Write(temp) ' Send high
byte via Soft SPI

' Send Low Byte


temp = lo(valueDAC) ' Store
valueDAC[7..0] to temp[7..0]
Soft_SPI_Write(temp) ' Send low byte
via Soft SPI

Chip_Select = 1 ' Deselect DAC


chip
end sub

' Declarations section


dim Value as word
main:
' Main program
Chip_Select= 1 ' Deselect the Chip
Chip_select_Direction=0 ' set as output
Soft_SPI_Init()
Value=4095
while true
DAC_output(value)
delay_ms(1)
wend
end.

In this demo we have connected the DAC to hardware connections of SPI module, however we have used
software method therefore these connections can be any where on your controller. The software SPI module
requires that these connections must be declared just like LCD connections. Next we have made a function
that will accept a word sized data whose value should be between 0 and 4095. This number is the highest
that can be represented by 12 bits. The CS bit is then brought low, to activate the DAC chip. The lower 4
bits of high byte are then extracted into a temp variable. The high 4 bits of temp variable are then loaded
with configuration bits of DAC., you need to look into the DAC data sheet to understand these configura-
tions. The High byte is then transmitted to the DAC, followed by Low byte. After transmission the CS bit is
taken high to deselect the DAC. Remember it is important to deselect as DAC will begin conversion when
Beginning PIC Microcontroller Programming / 217

it is deselected.
Now in the main program we have set a value lets say 4095 (highest 12 bit number) and pass it on to DAC.
The DAC should produce volts close to VRef. We have tied VRef to 5V supply therefore received volts are
about 4.99V.

So we conclude here that SPI is good protocol to communicate for short distances. I said short distances
because if you increase the wire length this can cause line noise to disturb the data. There is no error correc-
tion sort of thing in this protocol, therefore wiring errors are not tolerated. A number of SPI compliant de-
vices are available in market some are simply chips for a specific function as MCP4921 or complete de-
vices like SPI T6963C LCD displays.
Contrary to using SPI devices you can make your own SPI devices like converting a standard HD44780
LCD to SPI LCD. All you need is to connect a shift register with the LCD inputs and send LCD commands
over the SPI interface. An excellent example is found at http://www.circuitsathome.com/mcu/interfacing-
lcd-via-spi . Sending text data to this SPI LCD will be however little difficult as there is no built-in com-
mand available for that. You will have to make a custom procedure to send the data to this module via SPI.
Beginning PIC Microcontroller Programming / 218

RS-485 Long Range Serial


26 Communication

W
e have previously used RS232 protocol to communicate with PC or other devices. The
RS232 protocol can be implemented only for short distances, maximum 50ft. Increasing the
distance introduces noise and stray capacitance in the wires
and produces communication errors. Moreover only one de-
vice can be connected to this interface. This makes it difficult to use in noisy
industrial environments where usually more than one devices need to commu-
nicate with the main controller or main computer. The speed of communica-
tion over RS232 is also limited to maximum about 20 Kbps.
RS-485 protocol was therefore developed to address this issue. This communi-
cation protocol has noise immunity and therefore you can use long wires, up
to 4000 feet or 1200 meters long. Secondly multiple nodes or devices can be
connected to this bus making it suitable for industrial environments.
In order to use the RS485 protocol implemented through a specialized chip made by many companies like
Maxim MAX485, we need to talk little bit of theory of operation. I you understand the theory and underly-
ing the mechanism it will be easier to understand and enjoy the protocol implementation. So Some theory
first.
Differential signals with RS485: Longer distances and higher bit rates
One of the main problems with RS232 is the lack of immunity for noise on the signal lines. The transmitter
and receiver compare the voltages of the data- and handshake lines with one common zero line (GND).
Shifts in the ground level can have disastrous effects. Therefore the trigger level of the RS232 interface is
usually set relatively high at 3 Volt This is usually done with MAX232 chip. Noise is easily picked up and
limits both the maximum distance and communication speed.
With RS485 on the contrary there is no such thing as a common zero as a signal reference. Several volts
difference in the ground level of the RS485 transmitter and receiver does not cause any problems. The
RS485 signals are floating and each signal is transmitted over a Sig+ line and a Sig- line. The RS485 re-
ceiver compares the voltage difference between both lines, instead of the absolute voltage level on a signal
line. This works well and prevents the existence of ground loops, a common source of communication
problems. The best results are achieved if the Sig+ and Sig- lines are twisted. The image below explains
why.

In the picture above, noise is generated by magnetic fields from the environment. The picture shows the
magnetic field lines and the noise current in the RS485 data lines that is the result of that magnetic field. In
Beginning PIC Microcontroller Programming / 219

the straight cable, all noise current is flowing in the same direction,
practically generating a looping current just like in an ordinary
transformer. When the cable is twisted, we see that in some parts of
the signal lines the direction of the noise current is the opposite
from the current in other parts of the cable. Because of this, the re-
sulting noise current is many factors lower than with an ordinary
straight cable. Shieldingwhich is a common method to prevent
noise in RS232 linestries to keep hostile magnetic fields away
from the signal lines. Twisted pairs in RS485 communication however adds immunity which is a much bet-
ter way to fight noise. The magnetic fields are allowed to pass, but do no harm. If high noise immunity is
needed, often a combination of twisting and shielding is used as for example in STP, shielded twisted pair
and FTP, foiled twisted pair networking cables. Differential signals and twisting allows RS485 to commu-
nicate over much longer communication distances than achievable with RS232. With RS485 communica-
tion distances of 1200 m are possible.
Differential signal lines also allow higher bit rates than possible with non-differential connections. There-
fore RS485 can overcome the practical communication speed limit of RS232. Currently RS485 drivers are
produced that can achieve a bit rate of 35 mbps.
Network topology with RS485
Network topology is probably the reason why
RS485 is now the favorite of the four mentioned
interfaces in data acquisition and control applica-
tions. RS485 is the only of the interfaces capable
of internetworking multiple transmitters and re-
ceivers in the same network. When using the de-
fault RS485 receivers with an input resistance of
12 k it is possible to connect 32 devices to the
network. Currently available high-resistance
RS485 inputs allow this number to be expanded to
256. RS485 repeaters are also available which
make it possible to increase the number of nodes
to several thousands, spanning multiple kilome-
ters. And that with an interface which does not
require intelligent network hardware: the implementation on the software side is not much more difficult

than with RS232. It is the reason why RS485 is so popular with computers, PLCs, micro controllers and
intelligent sensors in scientific and technical applications.
In the picture above, the general network topology of RS485 is shown. N nodes are connected in a multi-
point RS485 network. For higher speeds and longer lines, the termination resistances are necessary on both
ends of the line to eliminate reflections. Use 100 resistors on both ends. The RS485 network must be de-
signed as one line with multiple drops, not as a star.
RS485 functionality
And now the most important question, how does RS485 function in practice? Default, all the senders on the
RS485 bus are in tri-state with high impedance. In most higher level protocols, one of the nodes is defined
Beginning PIC Microcontroller Programming / 220

as a master which sends queries or commands over the RS485 bus. All other nodes receive these data. De-
pending of the information in the sent data, zero or more nodes on the line respond to the master. In this
situation, bandwidth can be used for almost 100%. There are other implementations of RS485 networks
where every node can start a data session on its own. This is comparable with the way Ethernet networks
function. Because there is a chance of data collision with this implementation, theory tells us that in this
case only 37% of the bandwidth will be effectively used. With such an implementation of a RS485 network
it is necessary that there is error detection implemented in the higher level protocol to detect the data cor-
ruption and resend the information at a later time.
There is no need for the senders to explicitly turn the RS485 driver on or off. RS485 drivers automatically
return to their high impedance tri-state within a few microseconds after the data has been sent. Therefore it
is not needed to have delays between the data packets on the RS485 bus.
RS485 is used as the electrical layer for many well known interface standards, including Profibus and Mod-
bus. Therefore RS485 will be in use for many years in the future. A discussion about all this is beyond the
scope of this book, it is mentioned only to highlight the importance of
RS485.
RS485 Transceivers
So enough theory has been talked about now lets come to practical imple-
mentations. In order to implement RS485 protocol you will need a trans-
ceiver chip that will convert the digital signals into differential volts and
transmit the data. It will also receive the data over transmitted differential
volts and convert back into digital form. There are many manufacturers of
this transceiver chip. All are available by the number 485. However various modified versions are also
available. They vary in terms of electrical characteristics like speed, temperature tolerance etc.
The image here shows the MAX 485 chip. This chip is easily available in most electronics markets. It has 8
pins. Connections A and B (pins 6 and 7) are the differential outputs for the bus. VCC and GND are Power
supply, usually 5V. R0 is received data or data out, DI is data In. RE and DE are Enable pins for Read and
Write. Notice that RE pin has a bar over it indicating that a 0 will enable RO and a 1 on DE will enable DI.

So we can just connect them together and connect to a single pin on PIC to enable RO or DI. Notice we can
enable either RO or DI not both at the same time with this configuration. This makes it half duplex tat is it
can either read or write.
The 150 ohms resistor between A and B
pins is required only for the terminator
node. In case you have only two nodes both
will have this resistor. Additionally it is
better to have two 4.7K resistors on A and
B lines. Connecting resistor to GND and
VCC This is shown in next image clearly.
Also placing a 50 Ohms resistor in series is
advantageous but not necessary. A com-
plete connections diagram is shown on next
page.
You can also connect your PC directly to
Beginning PIC Microcontroller Programming / 221

this bus without going through UART communication through the microcontroller. In that case the RS232
data from PC needs to be converted to TTL level first using MAX 232. Many commercial Rs232 to RS485
adapters are also available in market, but you can make it yourself as well.
Notice unlike the standard RS232 circuit that we made for USART, where we used only Tx and Rx for
communication here we have also implemented the RTS line connected to R1In on MAX232, this will be
used to send enable signals to MAX485 through RTS from PC. Notice a 150 Ohms terminator resistor has
not been shown in this diagram.
Beginning PIC Microcontroller Programming / 222

Communication Protocol
MAX485 is only a transceiver, that will convert the input signals at RO into differential voltages at the A
and B and vice versa. It is not responsible for managing any protocol definitions or managing masters and
slaves. Thus using MAX485 allows you to use any protocol you want over this communication system.
Thus when a logic 1 is given on the DI pin it will appear as logic 1 on the RO pin of receiver. Similarly a
logic 1 at DI pin of second adapter will appear as logic 1 on RO of first adapter. This has to be controlled
by Enable pins properly set for reading or writing. That is all about the basic communication.
Now if we have two controller boards each with a MAX485 connected as shown in the above figure, if we
blink the RC6 pin on one and keep its RC2 high to enable DE then this blink will be transmitted to RC7 of
other provided the RC2 of other board is Low to enable RE. Now the program in second controller can read
the status of RC7 pin and take necessary action if required. Note this is simple digital transmission here Rc6
and RC7 does not have to do with UART or Tx and Rx.

program RS485_TX

' Declarations section

main:
' Main program
TRISC.2=0
PORTC.2=1
UART1_Init(9600)
while true
UART1_write_text("Welcome ")
delay_ms(500)
wend
end.

If you take MAX485 chips out of your mind just imagine that the two boards are connected wire to wire,
RC7 of one to RC6 of other and vice versa. Now if you transmit USART data it will appear on the other
controller.
program RS485_RX

' Declarations section

dim x as byte
main:
' Main program

TRISC.2 = 0
PORTC.2 = 0
LCD_Init()
UART1_Init(9600)
While True
if (UART1_Data_Ready() = 1) then
x = UART1_Read()
Beginning PIC Microcontroller Programming / 223

LCD_Chr_CP(x)
end if
wend

end.

Transmit Text Over RS485 using UART


Write this program into one controller. Notice PORTC.2 which is connected to RE/DE pin has been turned
high to enable DE.

In this program I have not shown the declarations for LCD, I hope you know they are there. Only RC2 has
been set to 0 to enable RE. rest of program is only looking at UART data arriving at Rx pin through
MAX485.
You can see that the message transmitted by controller on left is appearing on LCD connected to controller
on right.
The above example was only a demonstration of communication through MAX485. It was used only to
transmit the data, obviously now data can be transmitted over long distances. However the underlying data
packaging technique used is UART. Thus we can say that communication protocol used is RS232 over
MAX485 chips.
Our point of discussion in this chapter is RS485 communication protocol that can not only communicate
but also allow multiple nodes to be attached on the same bus. The UART protocol implemented above can
not host more than one nodes.
Beginning PIC Microcontroller Programming / 224

The RS485 Protocol


Once we have established that our communication works, we can now explore the proper RS485 protocol.
So lets talk first what the protocol actually describes. Just like UART modules present in PIC microcontrol-
lers unfortunately RS485 coding modules are not present and we have to implement the protocol using soft-
ware techniques.
Fortunately MikroBasic has an very good library that contains the useful functions to implement RS485
multi-point protocol. The MikroBasic Library internally uses UART module for some of its functions,
therefore we are bound to connect the RO and DI pins to Rx and Tx pins of the module. This will free us
from remembering every detail of the protocol however. In case you want to implement the RS485 on some
other pins then you can not use this library and you will need to write your own code.
The RS485 is multi-point protocol, that means the system can consist of one master and many slave nodes.
Each slave node must have a unique address. The Master initiates the communication and sends a message
to a node using its unique ID. The message is listened by every node connected but only the node whose ID
is in message accepts it. If required the node can then send the data back to master again using its ID as part
of the message.
The message therefore consists of a number of bytes forming a structure or a packet. The packet consists of
data bytes from 1 to 3, usually 1 byte is sent per packet. The number of bytes in message, the node number
to which it is addressed and the error status if any.
The MikroBasic RS485 Library
The MikroBasic RS485 library uses a defined structure to send communication. The Package of communi-
cation consists of:

PACKAGE:
--------
_START_BYTE 0x96
ADDRESS
DATALEN
[DATA1] ' if exists
[DATA2] ' if exists
[DATA3] ' if exists
CRC
_STOP_BYTE 0xA9

The package is 8 bytes long, with a start Byte which is always 0x96 and a last stop byte which is always
0xA9. Following the start byte is the address of node to which master is sending, or the number of node in
case node is sending.
The DATALEN byte contains lot of information about the package.
DATALEN bits
------------
bit7 = 1 MASTER SENDS
0 SLAVE SENDS
bit6 = 1 ADDRESS WAS XORed with 1, IT WAS EQUAL TO _START_BYTE or _STOP_BYTE
0 ADDRESS UNCHANGED
bit5 = 0 FIXED
bit4 = 1 DATA3 (if exists) WAS XORed with 1, IT WAS EQUAL TO _START_BYTE or _STOP_BYTE
0 DATA3 (if exists) UNCHANGED
bit3 = 1 DATA2 (if exists) WAS XORed with 1, IT WAS EQUAL TO _START_BYTE or _STOP_BYTE
0 DATA2 (if exists) UNCHANGED
bit2 = 1 DATA1 (if exists) WAS XORed with 1, IT WAS EQUAL TO _START_BYTE or _STOP_BYTE
0 DATA1 (if exists) UNCHANGED
bit1bit0 = 0 to 3 NUMBER OF DATA BYTES SEND
Beginning PIC Microcontroller Programming / 225

If bit 7 of This byte is 1 the master initiated message to be sent to a node whose address is in address byte.
If this bit is 0 then a node is sending data to master and address of node or sender is in address byte.
Rest of the bits are usually 0 to indicate that no XOR process has been done, finally last two bits 0 and 1
contain a two bit number to indicate if 1,2 or three data bytes are present in the packet.
After the DATALEN byte there are three bytes that will contain the data to be sent. You can send, 1, 2 or 3
bytes at the most per packet. Finally there is CRC byte that is calculated using a little complicated calcula-
tion based upon all the data present in packet. This CRC ensures that no bits were altered during transfer.
The sender calculates and packs the CRC and the receiver will calculate its own CRC based upon received
data and compare it with sent CRC to check the healthy status of received packet.
This is the ultimate packet that will transfer over the wires and received by your MAX485. The MikroBasic
library functions however make it fairly easy to pack this packet. Only one packet should be present on
lines at a time. Therefore it is the responsibility of programmer to ensure only one node is transmitting at a
time.
Now as you can see from the hardware diagram that three pins are required for this setup at each node. Two
are connected to The Tx and Rx pins of hardware UART module so they are fixed. The third pin which
controls the DE/RE enable, can be any other digital I-O pin. However just like LCD control pins this pin
needs to be defined in the declarations section.
dim rs485_rxtx_pin as sbit at PORTD2_bit
rs485_rxtx_pin_direction as sbit at TRISD2_bit
Now the library has two types of commands. One for the master and other for the slaves or nodes. You have
to have an array of bytes about 10 bytes long to pass data to the RS485 library functions, and in which the
Library Functions post back the results of received data.
As you know the actual data is in packet format, the library functions take this byte array to form the packet
similarly they take the packet and unpack data in this byte array.
The first three bytes of data array contain the data bytes to be sent. Since we are going to send one byte per
packet, byte 0 of array will contain the data the rest of two bytes will be 0. Next three bytes are meant for
receive errors thus when sending data they are set to 0.
dat[0] = 0xAA 'Data to be sent
dat[1] = 0
dat[2] = 0
dat[4] = 0 ' ensure that message received flag is 0
dat[5] = 0 ' ensure that error flag is 0
dat[6] = 0

Before using the Master to send data, you have to initialize the UART module. By using:
UART1_Init(9600) ' initialize UART1 module
Delay_ms(100)
Now you can initialize the RS485 Master module.
RS485Master_Init() ' initialize MCU as Master

Now you are all set to send the data to a slave node. Just load the data in byte array as above and issue the
Send data command.
RS485Master_Send(dat,1,160)
The procedure takes DAT as the name of byte array containing your data, 1 is the number of data bytes
contained in array and 160 is the address of slave node to which this packet will be sent. Now this proce-
Beginning PIC Microcontroller Programming / 226

dure will pack all the information, into the transmittable packet, calculate CRC and form the packet and
transmit over the MAX485 chip to the bus. As far as sending data is concerned this is all that is required.
You will load the data in byte array and transmit to the destination node.
Now how to receive data? The data sent over the bus is to be received by slave and the data sent back from
slave to master has to be received by master. We will implement the receiving system first on master so that
our module is complete it can transmit and receive data.
While receiving data you never know when data will arrive. This is specially the case with slaves, who have
to do other tasks as well while listening to the bus when master has sent them a message. Similarly when
slave has received a message it might be required to do some process before sending data back. For exam-
ple if a slave was to control the temperature of a system, master might send it message to get the current
temperature. The slave will have to take a fresh sample and transmit it back. This process might take some
time. Therefore master can not wait endlessly only to receive the message, it has other task to do.
An interrupt routine is therefore required. The interrupt has to fire only when data has arrived on Rx pin.
This is one of the reasons for MikroBasic to use UART module as we can setup an interrupt to occur when
data has arrived at UART module. This type of interrupt is called peripheral interrupt as opposed to the in-
terrupt caused by timers that we used in interrupts chapter.

' Interrupt routine


sub procedure interrupt()
RS485Master_Receive(dat)
end sub

There are different registers to set this interrupt in different controllers, here I am giving what applies to
18F452
PIE1.RCIE = 1 ' enable interrupt on UART1 receive
PIE2.TXIE = 0 ' disable interrupt on UART1 transmit
INTCON.PEIE = 1 ' enable peripheral interrupts
INTCON.GIE = 1 ' enable all interrupts
Now you can process the received data whenever it is required. Check the dat[5] to see if there was an er-
ror and handle it if you want. Check the message received flag in Dat[4] if it is received successfully proc-
ess the data byte received in dat[0] and clear the flags.
The process for slave is almost similar. Instead of Master_Init you will use Slave Init procedure. This pro-
cedure will require a number that will be assigned to this slave. So make sure no two nodes have the same
slave number.
RS485Slave_Init(160) 'Initialize MCU as slave, address
160
Initialize the interrupt system to receive data with an interrupt routine.
' Interrupt routine
sub procedure interrupt()
RS485Slave_Receive(dat)
end sub

On receiving data you can check for errors as above and extract data from dat[0] byte. To send the data to
master, just load the data in first three bytes of array and issue send command.
RS485Slave_Send(dat,1) ' and send it back to master
Beginning PIC Microcontroller Programming / 227

The 1 here is the number of data bytes in array. The packet will be formed and address automatically set to
the slave address and data transmitted to which your master will respond.
program RS485_Master

dim RS485_rxtx_pin as sbit at RC2_bit


dim RS485_rxtx_pin_direction as sbit at TRISC2_bit

dim dat as byte[10]

' Interrupt routine


sub procedure interrupt()
RS485Master_Receive(dat)
end sub

main:
' Main program
UART1_Init(9600) ' initialize UART module
RS485Master_Init() ' initialize MCU as a Master
PIE1.RCIE = 1 ' enable interrupt on UART1 RX
PIE2.TXIE = 0 ' disable interrupt on UART1 TX
INTCON.PEIE = 1 ' enable peripheral interrupts
INTCON.GIE = 1 ' enable all interrupts

while true
dat[0] = 65
dat[1] = 0
Beginning PIC Microcontroller Programming / 228

dat[2] = 0
dat[4] = 0 ' ensure that message received flag is 0
dat[5] = 0 ' ensure that error flag is 0
dat[6] = 0

RS485Master_Send(dat, 1, 100) 'Send data to Slave 1


delay_ms(1000)

dat[0] = 105
dat[1] = 0
dat[2] = 0
dat[4] = 0 ' ensure that message received flag is 0
dat[5] = 0 ' ensure that error flag is 0
dat[6] = 0

RS485Master_Send(dat, 1, 101)'Send Data to Slave 2


delay_ms(1000)

wend
end.
Now lets have a look at a complete application where master has two slaves with node numbers 100 and
101. The master sends number 65 to slave 1 and 105 to slave2.

program RS485_Slave1

dim RS485_rxtx_pin as sbit at RC2_bit


dim RS485_rxtx_pin_direction as sbit at TRISC2_bit
dim dat as byte[10]
dim txt as string[16]

' Declarations section


' LCD Declarations go here
' Interrupt routine
sub procedure interrupt()
RS485Slave_Receive(dat)
end sub

main:
' Main program
LCD_Init()
UART1_Init(9600) ' initialize UART module
RS485Slave_Init(100) ' initialize MCU as a Slave
Beginning PIC Microcontroller Programming / 229

PIE1.RCIE = 1 ' enable interrupt on UART1 receive


PIE2.TXIE = 0 ' disable interrupt on UART1 transmit
INTCON.PEIE = 1 ' enable peripheral interrupts
INTCON.GIE = 1 ' enable all interrupts
while true
ByteTostr(dat[0],txt)
LCD_Out(1,1,txt)
wend

end.

Now we have three programs, one for the master another for slave 1 and third one for slave 2.

Now program for slave it will be same for slave 1 and slave 2 only difference that in Slave nitialization
command the node number is 100 in slave 1 and 101 in slave 2
We have omitted the checking for new data and errors to clarify the process of data transmission and re-
ceive.
Beginning PIC Microcontroller Programming / 230

27 Dallas One Wire Protocol

O
ne-Wire is a device communication system developed by Dallas semiconductor corporation.
This system provides simple data communication over a single wire and of-course a ground
connection. Both power and data can travel
over the same single wire. The protocol is
quite advanced and allows multiple devices
connected over the same bus and communicating with
the microcontroller.
The 1-wire protocol is similar to I2C but with slower
data rates and longer range. It is typically used to communicate with small inexpensive devices such as
digital thermometers and weather instruments. A network of 1-Wire devices with an associated master de-
vice is often called a Micro-Lan.
One distinctive feature of the bus is the possibility to use only two wires: data and ground. To accomplish
this, 1-wire devices include an 800 pF capacitor to store charge, and power the device during periods where
the data line is used for data. This is not a fixed feature, and you can use the power supply if available in the
circuit.
Depending upon the function 1-Wire devices are available as components or integrated circuits, as To-92
package devices or complex devices having number of on-board chips but using 1-Wire as communication
protocol. Such devices may not get power from the data line but instead have their own power supply.
The 1-Wire networks or Micro-Lan can be connected through Bus converters like RS232, USB or parallel
port to the host PC or connected to microcontrollers directly. 1-Wire products provide combinations of
memory, mixed signal, and secure authentication functions via a single contact serial interface. With both
power and communication delivered over the serial protocol, 1-Wire devices are unmatched in their ability
to provide key functions to systems where interconnect must be minimized.
In this chapter we shall not go into very details of the communication details but only to introduce you with
the 1-wire library available in MikroBasic.
The standard serial communication usually requires a data line, a synchronizing clock line and power sup-
ply. Apart from power supply, the data and synchronizing clock signals are sent over the same data line.
The data line is bidirectional as it can send data to the device and read from it.
A unique feature of 1-Wire devices is that they all have a built-in laser engraved unique ID code. This
makes a number of devices, to be connected on the same line. For example you can have three 1-wire tem-
perature sensors connected to the same line. The sensors can be placed at different locations to sense the
temperatures at various locations of the premises.
Dallas 18B20 Temperature Sensor
DS18B20 is a commonly found digital temperature sensor from Dal-
las semiconductors. This sensor looks like a transistor, but in fact is
complete device and can communicate with microcontroller using 1-
wire protocol. In this chapter we will use this as a protocol to learn 1-
wire communication.
Just as we have done before it is important to have a look at the data-
sheet of the device you are going to use. Although 18B20 is going to
use 1-wire protocol but we need to know what internal addresses and
Beginning PIC Microcontroller Programming / 231

commands this particular device uses for external communication.


Remember DS18B20 is a digital temperature sensor, it has internal memory and configuration registers that
need to be sent specific commands for various operations.
The 18B20 looks like a transistor but in fact is an integrated circuit. The three pins are GND, DQ and VDD.
Beginning PIC Microcontroller Programming / 232

Although the device can take power supply from DQ line, yet it has power line as well. We shall use it with
power line.
The DS18B20 has open collector output therefore we need to place a 4.7K pull up resistor. The same resis-
tor will also be used to charge the internal capacitor in case we want to use DQ line for power. If you are
going to use multiple DS18B20 on the same bus, only one pull-up resistor will be required.
The internal memory map is shown in the above figure. Byte 0 and Byte 1 contain a 16 bit number repre-
senting the temperature in centigrade. It has sign bits as well to indicate the negative temperatures, below 0

Celsius.
Temperature Register Format
You can see the temperature register does not store the number in a format that we people normally use.
The temperature will consist of two parts an integer and decimal. The integer part will be stored from bit-4
to bit 10. and decimal part will be stored from bit 0 to bit 3.
The 18B20 can be configured to measure temperature in 9,10,11 or 12 bit resolution. The higher 4 bits are
used to indicate the sign. For positive temperatures these bits are 0 and for negative these bits are 1. It can
measure temperatures from 55 to 125 Celsius. The increment in temperature registers will depend upon

the resolution set in configuration register.

Configuration is byte no 4 in the memory map it has only two active bits to indicate the resolution, Bit 5
and Bit 6. The default power on status of these bits is both set to 1 thus a resolution of 12 bit is the default
setting. The higher three bits contain laser engraved address of the device and CRC byte contains the CRC
of conversion to check if data received is OK.
So this was the basic understanding on how the DS18B20 is internally arranged and how it will work. Now
lets come to interfacing it with our microcontroller and display temperature on LCD.
Beginning PIC Microcontroller Programming / 233

Transaction Sequence of DS18B20


There are three steps required by DS18B20 to complete the Temperature conversion cycle. All these steps
must be completed every time DS18B20 is accessed.

You can get more information about these commands from the DS18B20 data sheet, a full discussion will
actually put the entire datasheet here. To be brief the ROM commands prepare the DS18B20 for the next
operation. And the Function command actually reads the temperature.
The MikroBasic One-Wire library has all the necessary logic inside to implement these tasks, all we need to
know is the commands that need to be sent. The MikroBasic One wire library is basically written for
DS18B20 temperature sensor, in case you have some other device, you might need to write some code di-
rectly without using this library.
To be simple we will assume only one device attached to RB0 of our PIC microcontroller.

program OneWire

' Lcd module connections

dim text as char[9]


temp as word

Sub procedure Display(dim Temp2 as word)


dim temp_whole as byte
temp_whole=word(temp2 >> 4)
ByteToStr(temp_whole,text)
LCD_Out(2,1,text)
end Sub

main:
Lcd_Init() ' Initialize Lcd
Lcd_Cmd(_LCD_CLEAR) ' Clear Lcd
Lcd_Cmd(_LCD_CURSOR_OFF) ' Turn cursor off
Lcd_Out(1, 1, " Temperature: ")
Lcd_Chr(2,14,"C")

'--- main loop


while (TRUE)
Ow_Reset(PORTB, 0) ' Onewire reset signal
Ow_Write(PORTB, 0, 0xCC) ' Issue command SKIP_ROM
Ow_Write(PORTB, 0, 0x44) ' Issue command CONVERT_T
Delay_ms(1000)
Beginning PIC Microcontroller Programming / 234

Ow_Reset(PORTB, 0)
Ow_Write(PORTB, 0, 0xCC) ' Issue command SKIP_ROM
Ow_Write(PORTB, 0, 0xBE) ' Issue command READ_SCRATCHPAD
Delay_ms(400)

temp = Ow_Read(PORTB, 0)
temp = (Ow_Read(PORTB, 0) << 8) + temp

Display(temp)

Delay_ms(520)
wend
end.

The OW_Reset command sends a reset signal for DS18B20. this command is specific for 18B20 here and
other devices may not need this command.
OW_Write will write a one byte of data to the data line. In case you have only one device present it will
read it, if multiple devices are present the one last activated to receive will get it.
OW_Read will read one byte from the data line. DS18B20 can send 9 bytes of data the first two being the
temperature and rest will be configuration, device code and CRC. If after reading one or two bytes we issue
a DS18B20 reset command it will terminate sending rest of the bytes.
In this simulation the above program is running and as you can see it is displaying the temperature cor-
Beginning PIC Microcontroller Programming / 235

rectly. The program first resets the DS18B20 by issuing the reset command. Then issues the Skip_ROM
command. The data sheet say this command has code 0xCC. When this command is issued it means the
master does not want to set any ROM commands like configuration or high and low temperature alarms. So
it will not wait for these commands. It is here that the 10bit device code can be transmitted in case you have
multiple devices attached, but then Skip will not be used.
After issuing the ROM Skip we send the command to convert the temperature. This will invoke the tem-
perature reader and convert the temperature and store in data registers. As we are using default 12 bit reso-
lution this will take about 750mS time. This complete one set of command, Initialize, ROM and Command
sequence.
Now we are going to issue a second set again a Reset signal, Skip ROM and then Read_ScartchPad com-
mand 0xBE. This will make the DS18B20 to respond to OW_Read command. The OW_read command will
read one byte at a time. Since temperature is coded in two bytes Byte 0 and byte 1, we will read only two
bytes.
The result is stored in a word sized variable. The Lower byte is read first, followed by Higher byte. The
Higher Byte is shifted is shifted 8 bits to left and then lower byte is placed at its position. The result is two
bytes read and placed in the word sized variable with second byte received at high position and first byte
received at lower position.
This could have been simplified by reading the two bytes separately and then combining in word sized vari-
able.
X= OW_read(PORTB,0)
Y= OW_read(PORTB,0)
Hi(temp)=y
Lo(temp)=x
This will have the same effect, the shift method however looks more professional, as this does not require
additional variables to declare. You can use any to understand what is happening.
Now the temperature is read in temp variable and we need to extract three things from it. The sign of tem-
perature, the whole number of temperature and the decimal part. A look at the format of converted tempera-
ture above shows that lower 4 bits contain decimal part, next 7 bits contain the whole number part and rest
of 4 bits contain sign bits.
Lets make the things simple first. We assume the temperature is all in positive range and we ignore the
decimal part as well. So a positive temperature will have highest 4 bits set to 0. In order to ignore the lowest
4 bits that contain decimal part we shift the temp right by 4 bits. Now the temp only contains positive value
temperature whole number. Just convert it to string and display.
Representing Negative Numbers
Negative numbers are represented in computers using a method called 2s complement. In this method the
highest bit is the sign bit and it is turned 1 if number is negative and 0 if number is positive. In this system
the binary number is negated (from positive to negative or vice versa) by computed its 2s complement and
adding 1. this makes the addition and subtraction of negative numbers easy for computers without requiring
an additional methodology.
In our program we shall first determine if the number is negative? In case it is negative all 1s are converted
to 0s and all 0s to 1 and then a 1 is added.
If (Temp2 AND 0x8000) then
Temp2 = Not Temp2 + 1
End if
Now the number is converted into equivalent positive number and can be displayed or treated like any posi-
tive number. In order to display the negative sign, you can display the sign within this if statement.
Extracting the decimal or fraction part is also simple. Since lower 4 bits contain the fraction, extract them
Beginning PIC Microcontroller Programming / 236

by AND with %1111 and multiply the answer with 625.


f= (Temp2 AND %1111) * 625
Now f contains the fractional part. In case you want to save the entire temperature as floating point number
for use later in your program or further processing this can be done by combining whole number part and
fractional part into a float type variable.
f= word(temp2 >> 4) + (word(temp2 AND %1111) *625) * 0.0001
This will first place the whole number part in f (a float type variable) and then extract the fractional part and
multiply it with 0.0001 and add it to the float variable. You can see the result in the simulation below. This

becomes more use routine as we can now convert the temperature returned by DS18B20 into a float type
variable and use it any where in our calculations. Only one thing is left the negative sign, this should be
easy if the sign bit is set just do a 2s de-complement on data and multiply the answer with 1.
Sub procedure Display(dim Temp2 as word)
dim f1 as float
dim s as bit
if word(Temp2 AND 0x8000) then
Temp2 = not Temp2 +1
s=1
end if
f1= word(temp2 >> 4)
Beginning PIC Microcontroller Programming / 237

f1= f1 + (word(temp2 AND 0xF)*625) * 0.0001


if s=1 then
f1=f1 * -1
end if

floatToStr(f1,text)
LCD_Out(2,3,text)
end Sub

Using MicroLan
Now you have successfully learnt how to use the DS18B20 to sense temperature. Lets move forward and
now consider a network of DS18B20s. Suppose you have an application where you want to monitor tem-
perature of three different locations. Certainly you will need three different sensors. One-wire protocol al-
lows you to connect an large number of devices on the same single wire. The key to this is the 64-Bit code
engraved inside the device by manufacturer. This code can not be changed and no chance of being repeated.
The 64-bit code is located within an area called ROM. In earlier examples we had used the SKIP_ROM as
we had only one sensor. Now when you have multiple sensors you need to specifically address the individ-
ual sensor to get data. You can still use the SKIP_ROM command for global issues like before giving com-
mand Convert Temperature. This will cause all slaves to read temperature and place it in their own scratch
pad memory. Then using individual address you can fetch the temperature from every sensor.
Beginning PIC Microcontroller Programming / 238

So the first task would be to find out the hardware ROM code. The ROM code consists of 64 bits, this
means 8 bytes of data. The lowest byte contains device family code this is 0x28 for 18B20 and 0x10 for
18S20. Since we are using 18B20 we will always have 0x28 at this location. Next 6 bytes will contain the
device code and last Byte 7 will contain a CRC for this code.
So the first task is to get the unique codes of your devices. The DS18B20 datasheet says there is a
SEARCH_ROM command however the algorithm to implement is difficult. Therefore we will use a sim-
pler method to get the ROM codes of our devices first. Then note them down for reference. In order to get
the ROM codes we will have to hook one DS18B20 at a time.

dim d1 as byte[8]
dim i as byte
dim txt as string[9]
main:
Lcd_Init() ' Initialize Lcd
Lcd_Cmd(_LCD_CLEAR) ' Clear Lcd
Lcd_Cmd(_LCD_CURSOR_OFF) ' Turn cursor off
Lcd_Out(1, 1, " ROM Code ")
delay_ms(2000)
Lcd_Cmd(_LCD_CLEAR) ' Clear Lcd

'--- main loop


while (TRUE)
Ow_Reset(PORTB, 0) ' Onewire reset signal
Ow_Write(PORTB, 0, 0x33)' READ_ROM
for i=0 to 7
d1[i]=OW_Read(PORTB,0)
next i

For i=0 to 7
bytetostr(i,txt)
LCD_Out(1,1,txt)
BytetoStr(d1[i],txt)
LCD_out(2,1,txt)
delay_ms(5000)
next i

Delay_ms(520)
wend

This code will display the ROM code from byte 0 to Byte 7. The program after issuing the reset command
sends the ROM READ command which is 0x33. This will make the DS18B20 to transmit the 8 bytes of
code. We then read the bytes in a loop one by one and store them in an array. Later we display the contents
of array one by one. The code displayed is in decimal, there is no harm if you manually convert it to hex

Sensor CRC Byte 6 Byte 5 Byte 4 Byte 3 Byte 2 Byte 1 Byte 0

Sensor 1 142 0 0 0 184 197 48 40

Sensor 2 185 0 0 0 184 197 49 40


Beginning PIC Microcontroller Programming / 239

using scientific calculator in windows.


Notice the Lowest byte is 40 in both cases this is hex 0x23 indicating a 18B20 sensor. Rest of the code is
different in different sensors. So yours will be different.
Now we can write a program to read temperatures from these sensors separately and display.

Sub procedure Display(dim Temp2 as word, dim r as byte,


dim y as byte)
dim f1 as float
dim s as bit
s=0
if word(Temp2 AND 0x8000) then
Temp2 = not Temp2 +1
s=1
end if
f1= word(temp2 >> 4)
f1= f1 + (word(temp2 AND 0xF)*625) * 0.0001
if s=1 then
f1=f1 * -1
end if

floatToStr(f1,text)
Beginning PIC Microcontroller Programming / 240

LCD_Out(r,y,text)
end Sub
const ROM_Code1 as byte[8]= (40,48,197,184,0,0,0,142)
const ROM_Code2 as byte[8]= (40,49,197,184,0,0,0,185)

dim i as byte
dim txt as string[9]
main:
Lcd_Init() ' Initialize Lcd
Lcd_Cmd(_LCD_CLEAR) ' Clear Lcd
Lcd_Cmd(_LCD_CURSOR_OFF) ' Turn cursor off
Lcd_Out(1, 1, " Temperature ")
delay_ms(2000)
Lcd_Cmd(_LCD_CLEAR) ' Clear Lcd

'--- main loop


while (TRUE)

Ow_Reset(PORTB, 0) ' Onewire reset signal


Ow_Write(PORTB, 0, 0xcc) ' Skip ROM
OW_write(PORTB,0, 0x44) ' Do Conversion

' Read temperature from first device


OW_reset(PORTB,0)
OW_Write(PORTB,0,0x55) 'Match ROM
for i=0 to 7 'Send Device Code
OW_Write(PORTB,0,ROM_Code2[i])
next i
OW_write(PORTB,0,0xBE) 'Read Scratch Pad
delay_ms(400)
temp = Ow_Read(PORTB, 0)
temp = (Ow_Read(PORTB, 0) << 8) + temp
Display(temp,1,1)

' Read temperature from Second device

OW_reset(PORTB,0)
OW_Write(PORTB,0,0x55) 'Match ROM
for i=0 to 7 'Send Device Code
OW_Write(PORTB,0,ROM_Code1[i])
next i
OW_write(PORTB,0,0xBE) 'Read Scratch Pad
delay_ms(400)
temp = Ow_Read(PORTB, 0)
Beginning PIC Microcontroller Programming / 241

temp = (Ow_Read(PORTB, 0) << 8) + temp


Display(temp,2,1)

Delay_ms(520)
wend

We have declared the ROM codes as arrays of constant and after issuing a global conversion command the
two devices are read one by one and display the data. You can see the code for reading both devices is al-
most same, except for the ROM Code array. You can easily make a procedure to avoid this repetition and
make the code more neat and flexible.
Now you can have any number of devices connected on the MicroLan and manage them. Before conclud-
ing this chapter I would like to introduce some other one-wire devices. We will not explore them as proce-
dure will be same but only to mention so that you know what else is available.
program OneWire
Const ROM_Code as byte[2][8]=((40,48,197,184,0,0,0,142),
(40,49,197,184,0,0,0,185))
dim text as char[16]
' Lcd module connections

Sub procedure Display(dim Temp2 as word, dim r as byte,


dim y as byte)
dim f1 as float
dim s as bit
s=0
if word(Temp2 AND 0x8000) then
Temp2 = not Temp2 +1
s=1
end if
f1= word(temp2 >> 4)
f1= f1 + (word(temp2 AND 0xF)*625) * 0.0001
if s=1 then
f1=f1 * -1
end if

floatToStr(f1,text)
LCD_Out(r,y,text)
end Sub
Sub Function Get_temp(dim p as byte) as word
dim temp as word
dim i as byte
Ow_Reset(PORTB, 0) ' Onewire reset signal
Ow_Write(PORTB, 0, 0xcc)' Skip ROM
OW_write(PORTB,0, 0x44) ' Do Conversion
Beginning PIC Microcontroller Programming / 242

OW_reset(PORTB,0)
OW_Write(PORTB,0,0x55) 'Match ROM
for i=0 to 7
OW_Write(PORTB,0,ROM_Code[p][i])
next i
OW_write(PORTB,0,0xBE) 'Read Scratch Pad
delay_ms(400)
temp = Ow_Read(PORTB, 0)
temp = (Ow_Read(PORTB, 0) << 8) + temp
result=temp
end sub

dim t as word
main:
Lcd_Init() ' Initialize
Lcd
Lcd_Cmd(_LCD_CLEAR) ' Clear Lcd
Lcd_Cmd(_LCD_CURSOR_OFF) ' Turn cur-
sor off
Lcd_Out(1, 1, " Temperature ")
delay_ms(2000)
Lcd_Cmd(_LCD_CLEAR) ' Clear Lcd

'--- main loop


while (TRUE)
'--- perform temperature reading

t=get_temp(0)
Display(t,1,1)
delay_ms(1000)
t=Get_temp(1)
Display(t,2,1)

Delay_ms(520)
wend
end.

In this program we have made the two dimensional array of constants. The two dimensional array has two
parameters to access the data element. First element will be used to access the device number, and second
its 8 byte ROM Code. Now we have a fairly uniform program to which you can add as many temperature
sensors as you want and you can get the temperature of any by just calling get_temp function. The parame-
ter is the number of sensor to access.
Beginning PIC Microcontroller Programming / 243

i-Button
i-Buttons are also one-wire devices manufactured by Maxim. They
basically contain an ID just like the ID of DS18B20 and some addi-
tional memory that can be programmed by the master and read back.
They are small button like devices, that can be easily mounted on a
small key-chain or other personal items. The buttons are used as iden-
tification tags to allow login, gate access and other areas. The reader
consists of a terminal with data wire and ground, the button is just
connected to the reader and master reads the information from the but-
ton.
There are many other devices from Maxim available that work on 1-
wire basis like Pressure sensor, real time clocks, EEPROMs and many
others.
Beginning PIC Microcontroller Programming / 244

28 USB Universal Serial Bus

U
niversal Serial Bus (USB) developed in the mid 1990s that defines the connectivity of devices
with computers along with power supply. Before that the devices required a bulky serial or par-
allel communication connection and a separate power
adapter. The USB cable has only two data wires D+
and D along with power supply from the host computer. For
most USB devices the supplied current is sufficient to power the
device however others like printers and scanners might require a
separate power supply. So power supply as such is not a feature of
USB protocol.
A group of seven companies began development on USB in 1994:
Compaq, DEC, IBM, Intel, Microsoft, NEC and Nortel. The goal
was to make it fundamentally easier to connect external devices to
PCs by replacing the multitude of connectors at the back of PCs,
addressing the usability issues of existing interfaces, and simplify-
ing software configuration of all devices connected to USB, as well as permitting greater data rates for ex-
ternal devices. The first silicon for USB was made by Intel in 1995.
The original USB 1.0 specification, which was introduced in January 1996, defined data transfer rates of
1.5 Mbit/s "Low Speed" and 12 Mbit/s "Full Speed". The first widely used version of USB was 1.1, which
was released in September 1998. The 12 Mbit/s data rate was intended for higher-speed devices such as
disk drives, and the lower 1.5 Mbit/s rate for low data rate devices such as joysticks.
The USB 2.0 specification was released in April 2000 and was ratified by the USB Implementers Forum
(USB-IF) at the end of 2001. Hewlett-Packard, Intel, Lucent Technologies (now Alcatel-Lucent), NEC and
Philips jointly led the initiative to develop a higher data transfer rate, with the resulting specification
achieving 480 Mbit/s, a fortyfold increase over the original USB 1.1 specification.
A USB system consists of two different setups. A Host who is in charge and consumer of the device and
Slaves that are connected to the host through a multitude of hubs. A single system usually consists of one
host and many slaves.
The slave devices have been categorized into many classes based upon the function. Each class has a
unique ID and that ID must be transmitted by the Slave to the Host on connection. The most commonly
used classes are:
Human Interface Device HID (0x03)
Communication and CDC control (0x02)
Mass Storage device (0x08)
There are many other classes like printers, audio and vide etc.
As far as microcontrollers are concerned we usually need a slave interface to the host controller so that our
microcontroller can communicate with the PC or some other USB host.
Implementing a full USB protocol is quite complex as it requires continuous polling to the host about the
live presence of device and then sending and receiving data. Unfortunately most microcontrollers do not
have this module built in them therefore they require an external chip that can do the job for them.
Beginning PIC Microcontroller Programming / 245

One such popular chip is FTDI232. FTDI chip provides all the basic functionality of
USB communication including polling device ID etc. The other end of device pro-
vides RS232 type signals for direct interfacing with UART module of microcontrol-
ler. The FT232 chip is however surface mount and needs to hookup some basic cir-
cuitry before using it. FT232R is the latest addition. In fact this is simply a USB to
UART converter. When a device with this chip is inserted the Host PC will automati-
cally create a new virtual com port and use it to communicate through USB.
Thus your system might get an additional serial port numbered COM8. This COM
port will in fact map to USB port and send data to the serial port of your microcontrollers. This particular
function can be easily replaced by using USB to serial converters commercially
available. However their output is not TTL and they will need the MAX232 inter-
face to communicate. Since most microcontroller boards have MAX232 interface,
they are easily plugged in the port and you can use serial communication over the
USB.
USB to UART TTL level adapters are also available that can be connected directly
to the Tx and Rx pins of microcontroller without an intervening MAX232 chip. Un-
fortunately these adapters are not very easily available, as their usage is not very
common.

CA-42 Nokia data cable.


Fortunately there is a Nokia data cable, that has TTL UART output from USB con-
nection. This cable is commonly available from cell phone accessories shops. The
cable can be cut and TX, RX and GND lines identified easily.

So providing a USB interface to your microcontroller project is not difficult. What is more important to
make a new device that should identify itself to the host computer and can act as many different types of
devices like a mouse, keyboard, mass storage device or as data terminal.
Since USB is rapidly gaining popularity and many new devices would require this connectivity imple-
mented in them. Newer and advanced microcontroller from Microchip have USB 2.0 standards based mod-
ule built inside them. Remember this is Slave module, and using this module you can connect your slave
device to a host computer. Another slave device like Flash drive can not be attached with this interface.
PIC18F452 does not have this module inside therefore we will have to change the microcontroller.
PIC18f4550, which is also a 40 pin PIC microcontroller has this module in it. There are three pins dedicated
for this module one for D+ another for D and another labeled Vusb to which a capacitor need s to be con-
nected. These pins can also be configured as digital I-Os just like other pins.
If you look at the schematics for using FT232 you will realize that a good bit of work needs to be done to
assemble the circuit to work. However using 18F4550 all you need is a 470nf capacitor and a USB connec-
Beginning PIC Microcontroller Programming / 246

tor to connect the USB cable directly to the D+ and D pins of the microcontroller. Thats all your hard-
ware is ready for interfacing. The USB ports usually can give 100mA current and standalone microcontrol-
ler applications consume very little current so you can power your device from the 5V supply coming with
USB cable, or you can use your own supply, in that case just disconnect the cable 5V supply through a
jumper, so that the microcontroller board supply does not enter the HOST PC and damage it in case some-
thing goes wrong.

Here is the basic circuit. Certainly you can use a 20MHz oscillator and replace the two 100nf capacitors
with one 470nf capacitor. It is important to identify the D+ and D connections of your connector. The
Vusb and its associated capacitors work to regulate the USB module voltage.
First connect the cable to the USB connector of your PC and locate the two connectors for +5V and GND.
Once they are located the D+ and D are next to them as shown in figure.

MikroBasic provides a reasonably good library to work with USB features of 18F4550. However the sub-
ject of USB communication and devices is so vast it is certainly beyond the limits of this chapter. This
chapter will therefore only help you in getting stated with USB devices. You can make all sort of USB de-
vices using Microchip USB microcontrollers, the hardware will remain almost same. However a lot of un-
derstanding and in depth programming is required.
A brief introduction as to how the USB devices function will help you understand the process. Like other
communication systems USB also consists of a host and a many devices. The host is usually a PC in our
system and devices are all the USB compliant devices connected to your host. Only Host can initiate the
communication and devices respond only when host asks. Thus if a device has some data to send it can not
send a notification unless the host asks if it has something to send.
Beginning PIC Microcontroller Programming / 247

Each device has a set of parameters called descriptors. It is these descriptors that would notify the host
about the type of device and its behavior. A slight error in descriptor will stop the communication or not
begin the communication at all and host will respond by an error message of device not found or something
like that. Many device descriptors are standard and therefore windows has pre-installed drivers for them.
Like USB mouse, and keyboards you do not need to install a device driver unless it has some special fea-
tures. When a device is connected the host tries to enumerate it. At this stage the device is required to send
the descriptors so that the host can determine the device type.
The host to USB device communication takes place over the channels called endpoints. These are num-
bered like endpoint0 and endpoint1 etc. a device can have many endpoints depending upon the various
types of communication, but usually the devices have two endpoints. One will get data from host and other
for transmitting data to the host.
The host will always first use the endpoint 0 or Control endpoint to get the description of the device.this
"descriptor" will contain the device identifiers (vendor ID and product ID, etc), along with its device class,
subclass, etc (HID like a mouse or keyboard? or maybe mass storage?).
Then the configuration descriptor is requested, which also contains the number of endpoints available on
the device. Each endpoint has its own descriptor as well. All of this data are sent as packets of data bytes
representing a well known specified data structure.
Once all the descriptors have been received the host is now ready for communication.
We need to worry about the descriptors, because if descriptors are not properly defined the device will fail.
MikroBasic provides a tool to make a standard descriptor for an HID device. Its good to have this tool and
get the descriptor made easily. Do not change the descriptor file created unless you understand it.
Now we are ready to write a simple program that should recognize our device as USB HID type device to
the windows and transmit some data to the terminal program.
Beginning PIC Microcontroller Programming / 248

Before we begin let me tell you that you must use a microcontroller with built-in USB module. You can use
18F4550 or 18F2550, there are others as well. I am going to use 18F2550 simply because its available in
my bin and I already have a board with USB connector for this controller. Apart from size and pin numbers
its not much different from 18F4550. So the hardware will be same, you need to know the pin numbers of
d+, D and Vusb connections.
Secondly the USB module requires 96MHz signals to work. Our external oscillator may be 4,8,12 or 20
MHz. Make sure the crystal frequency is in multiples of 4. so do not use a 10MHz crystal. 18F2550 and
18F4550 controllers have an internal clock multiplier called PLL that will increase the internal oscillator to
required 96MHz. The same synthesizer will then give 48MHz signals to rest of the controller. Thus even
though our external oscillator is 20MHz USB module will receive 96MHz and rest of the controller
48MHz. In order to achieve this we will need to configure the configuration bytes of the controller. Fortu-
nately MikroBasic has an easy to use tool that will configure the switches for us. Although our crystal is
20MHz, but since our controller is actually going to receive 48MHz we will mention clock speed as
48MHz. You can select this during creation of a new project or after that by changing the Project Settings.
There is usually a tab on left side of screen for this if not visible just click View > project settings. There
you can change the clock frequency to 48MHz.

Next we have to set the configuration bits. To do that click over project and then edit project, or press
Shift+Ctlr+E
There are many settings in this dialog box, set the first drop list to Divide by 5 (20MHz Input) you can
change this according to the external oscillator you have. Since we have 20MHz oscillator we chose this.
Next you have to chose the second drop list and select CPU clock source as OSC1/OSC2 src as shown in
figure. Next select third drop list clock src from 96MHz PLL/2 and finally the oscillator HS; HS+PLL;
USB+HS. Leave all others standard, locate the USB voltage regulator, 10th drop box and select it enabled.
Now our project is configured to use the USB module. Next we have to write the appropriate software. And
the appropriate descriptor. First lets write the software.
program USB
dim userWR_buffer as byte[64]
dim userRD_buffer as byte[64]

' Main Interrupt Routine


sub procedure interrupt
HID_InterruptProc
end sub
Beginning PIC Microcontroller Programming / 249

' Main Program Routine


main:
HID_Enable(@userRD_buffer, @userWR_buffer)
Delay_ms(1000)
while TRUE
Delay_ms(1000)
userWR_buffer[0] = 65
HID_Write(@userWR_buffer, 1)
wend
HID_Disable()
end.

Before discussing the program, lets build the descriptor and add it to the project. Usually our project con-
sists of two files a project file itself and the source file that contains the code. You can add other code files
to the project.
To build the descriptor click Tools -> HID terminal. The HID terminal has two tabs on top. One is for ter-
minal that will be used to communicate with our device, and other is descriptor. Click over descriptor to
make one. There are many inputs just leave all of them as such. You can however change the name of ven-
dor, to any thing you want and product name to any thing you want. Do not change VID and PID as such
the selected ones are ok for testing. Choose mikrobasic as output type and press save descriptor.
Beginning PIC Microcontroller Programming / 250

When you press save descriptor button it will ask you for file name, use default USBdsc. By default it will
use *.pbas as extension change it to *.mbas in the save as type drop list. And press save. This will create the
descriptor file in your project folder. Now you have to add this file to your project so as it is compiled with
the project.
To do that you have to open the Project manager, its tab is usually available on right side, if not it can be
selected from View menu.
Open the project list and
then the sources and right
click to add the
USBdsc.mbas file. Now
build the project, you might
need to build the USBdsc
file separately, to do that
just right click over the file
in project manager and se-
lect build. Now build the
project and burn the .hex
file to your controller. In
order to see if the device is
recognized, open the win-
dows device manager and
connect the device to USB
cable. The device should get
detected and list should get
re-populated and show the
Beginning PIC Microcontroller Programming / 251

device. If the device is not detected or windows report an error message check the whole system before pro-
ceeding. Just to share my experience I had trouble in getting the device recognized, windows always re-
ported that the device has malfunctioned. Ultimately the problem was resolved to faulty USB cable.
Cheaper cables tend to have micro breaks in side and fail to work properly.
Now if everything is OK, open the Tools>HID terminal. The list of USB devices attached should be visi-
ble, like USB mouse, and keyboard etc if you have those, and your device My-HID should also be visible.
Just select it and the terminal window will show the transmitting character A every second.

So far so good. You have successfully made a USB device that can recognize itself to windows as USB
HID device and can transmit data to windows. Now lets discuss a little bit about the program. As I said the
USB device needs two buffers to Read and write data. So we need two arrays of byte. Maximum length is
64 bytes, but you can chose smaller.
You have to define an interrupt and call the HID interrupt procedure. The interrupt will take place automati-
cally and managed by USB module the HID procedure to call is defined by MikroBasic library.
sub procedure interrupt
HID_InterruptProc
end sub
You do not need to enable any interrupts in your code.
Rest of the procedure is simple you enable the HID procedure and pass it the address of two buffers. The
address of buffers is passed by placing an @before variable name. Then you place the data in Write buffer
and call HID_write function. The second parameter is number of bytes you have placed in buffer that needs
Beginning PIC Microcontroller Programming / 252

to be transferred. Similarly you can read the read buffer to get if host has sent something and then do the
job accordingly.

This terminal shows a string of characters sent and same received back from the device. Something like
echo.

while TRUE
while hid_read() = 0
wend
ch=userRD_buffer[0]
userWR_buffer[0] = ch
HID_Write(@userWR_buffer, 1)
wend

The Hid_read() function returns the number of characters received. When the characters are received, one
by one, each character will be present in byte 0 of read buffer, it has been picked up and returned.

You might also like