You are on page 1of 252

Microtronics Pakistan

Invent Future

Learn By Doing: Less Theory More Practical

Lets Begin Microcontroller Programming


Using PIC Microcontrollers

Amer Iqbal Qureshi

Microtronics Pakistan www.electronicspk.com

Preface

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 hobbyist 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. Programming a microcontroller is not much difficult job. However getting a project work is somewhat laborious. 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 ignore. 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

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 Control Structures Loops and Decisions Connecting Output and Input Devices Using Push Switches Character LCD Display Seven Segment LED Display USART Universal Asynchronous Receiver and Transmitter Dealing With Analog Data Graphic LCD and Touch Screen Using Numeric Keypad Producing Sound Pulse Width Modulation I2C Communication EEPROM I2C Communication DS1307 Real Time Clock Interrupts and Timers Motor Control, DC Motor, Stepper and Servo LED Matrix Displays Infra Red Communication and Remote Controls SPI - Serial Parallel Interface RS485 Long Range Serial Communication Dallas One Wire Protocol USB - Universal Serial Bus 38 42 50 57 63 77 84

99 112 119 129 133 144 152 158 170 190 195 211 218 230 244

1 E

Introduction to Microcontrollers

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 nature 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 simple 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 using these discreet components. However the demand to control 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 devices, such as automobile engine control systems, implantable medical devices, remote controls, office machines, 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 digitally 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-

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, controlling 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 purpose, 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 according 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 answer 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, similar 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 everything 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 luxury 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

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 requirements. 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 manufacturer 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 microcontroller. 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 company 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 project 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 operation 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-

uct, Intel got from Federico Faggin. Nine months after his arrival to Intel he succeeded in developing such a product from its original 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 8bit 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 microprocessors. 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 interested 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, Commodore, 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 everybody replaced the 8080 by the Z80. Certainly the Z80 was commercially the most successful 8-bit microprocessor 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.

2 A

Microchip PIC Microcontrollers

mong a large number of companies manufacturing microcontrollers 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 developed as a supporting device for PDP computers to control its peripheral 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 microcontrollers.

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 midrange 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 customary to talk about the pin numbers. Most of you who have experienced working with various integrated 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 becomes 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 abbreviations are pin names and correspond to the specific function of the module inside to which they are attached. 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 assume any one of them. This is simply done during programming by setting various special function registers. 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 convention 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.

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 single function. This means this microcontroller does not have many modules inside. Since functions tend to repeat in all processors from Microchip. 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 microcontroller, so is 16F628A and 16F819 and many others too. Being different processors they definitely have differences in the available memory, 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 pincompatible. You can easily replace one for another 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 reprogrammed 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 microprocessor 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 microcontroller. 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 instructions 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 microcontroller in these commands. It will be your compiler that will do this job. So you will need to know the commands 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. Occasionally you may need to bypass the compiler generated instructions and write a part of your application in assembly to give more speed.

What are RISC Computers.


RISC stands for Reduced Instruction Set Computers. Although having more instructions in the core instruction 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 economically 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 requiring 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 processor intensive functions. For beginners I would suggest start with 16F628A and progress to 18F452. The figure below shows the hierarchy of various PIC families.

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 personally believe there is only way of perfect learning and that is Learn By Doing. There is not alternate to this statement, rather I shall extend it by Do It Yourself . Therefore if you are really interested in learning these beasts, roll your sleeves and setup your own workbench. Most hobbyists 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 personal 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:

3 N

Setup Your Personal Electronics Workbench

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 simple one, There is no need of other functions like pulse generator or frequency measurements for our purpose.

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 number 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 moment. 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 breadboard 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 designs 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 programmer 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 standard 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 programmed through bootloader. Howerver 16F877A or 18F452 etc can all be programmed. Although we shall

use the standard programmer, it is useful to know about this technique as well. In order to use this technique 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 control something we need to have some external devices connected to the controller. 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 veroboard, with soldering. Many commercial companies and organizations have made complete boards, that have many devices prebuilt 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 containing 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 commonly 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 project, 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.

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 devices are connected to the microcontroller. Usually the manufacturer of board provides a manual or schematic to show the connections. In case our discussion differs in terms of connections, you can make appropriate 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 software. As I mentioned earlier microcontrollers understand numbers, their commands are also numbers. Humans 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 developed 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 approach which pays in the long run. My previous texts have used PROTON BASIC as a programming language. In this book I shall give MikroBasic 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

code is quite big for a microcontroller, and most of the basic learning projects remain well under 2K. Secondly 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 compiler and many other supporting tools. MikroBasic supports their own programmer as an integrated development 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 matter, as long as it supports your controller and accepts the compiled (.hex) file and transfers it to the controller.

PICPGM
You can download this free software from, http://members.aon.at/electronics/pic/picpgm/ . Although the number of supporting devices is somewhat less, but it does support all commonly used PIC microcontrollers. The beauty of this software is that it automatically detects the type of programmer, 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 lightning icon.

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 Mikrobasic 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. Nevertheless they all have same basic features, like a new model of a car, basically its a car and if you understand 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 directly or indirectly related. An ordinary editor, like Notepad has no idea what you are writing. The intelligent editor of Mikrobasic however knows you are writing an application software for a particular microcontroller, 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-

4 N

A Brief Tour of MikroBasic

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 environment 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 dropping 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 consists of one or more than one files. So lets begin with a simple project, where we want a small program to blink the LEDs connected to PORTB. For now do not take the code seriously, what I want is to familiarize you with the basic procedure.

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 microcontroller 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 Mikrobasic about the microcontroller that we shall be actually using. This is because it will select the appropriate registers for that particular controller, as

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 microcontroller to its limits. As I had previously 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 Mikrobasic 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 single 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

libraries. I shall talk more about libraries later. For here I would just say that various programming applications need to take into consideration a number of commonly used technologies. For example LCD, thisis commonly used in many appliocations. In order to use an LCD properly 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 Mikrobasic LCD library. So we are concerned only upto the level of how our LCD is connected and what we want it to show. The rest of code is generated during .hex file creation by Mikrobasic. Thus presence of the LCD library has made our coding easier. The more libraries you have, naturally more facilities you have to work with. Another beauty of these libraries is that if you change the controller, 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 example 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 extension 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

main: Notice a : after the word main. This word must be there and this indicates the starting point of your application. Whenever the program starts executing it will first locate the main: label and start program execution 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 Successfully. That is it. You have successfully created a .hex file that can be transferred into 16F819 microcontroller. Now lets have a look at the folder where we created the project file. As you can see there a re a number of

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 PG2 a JDM type programmer. The programmer in turn is connected to the development board with 16F819 in place. I am using In circuit programming 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 arrangement of pins on this header is fairly standard as per Microchip guidelines. Make sure if you are using such an arrangement the pins la-

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 Circuit 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 microcontroller, 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 indicating a successful transfer. If the red box indicating 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 unpug the serial cable from programmer. That effectively turns the programmer OFF and re-

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 transfer 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 hardware 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-

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

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 microcontrollers. 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 implementation. 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

5 B

MikroBasic Programming Language

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 resources 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 developed 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 module 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 Program 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 another 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:

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 handling 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 bit sbit byte, char short word integer longword longint float dim counter, temp As word Size 1bit 1bit 8bit 8bit 16bit 16bit 32bit 32bit 32bit Range 0 or 1 0 or 1 0 .. 255 -127 .. 128 0 .. 65535 -32768 .. 32767 0 .. 4294967295 -2147483648 .. 2147483647 1.17549435082 * 10-38 .. 6.80564774407 *

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

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 declare 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 declares them for us when we chose appropriate microcontroller as part of project definition. MikroBasic declares 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 remember 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 declaration, smallest size is chosen.
const MAX as longint = 10000 const MIN = 1000 const SWITCH = "n" const MSG = "Hello" ' compiler will assume word type ' compiler will assume char type ' 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

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 comment. 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 program. 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 difficult 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. People 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 assembly is non-structured language. It will certainly need use of labels. So we will use labels only very occasionally.

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

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.

any students and hobbyists love to make their own development boards. No doubt this is essential 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.

6 M

Hello World !

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 integrated 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 supplies in case your project needs. Since we will be working most of the times with single 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 inserting 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.

Do not use soft multi-core wires, as they are difficult to insert. As shown in this figure cut them into different legths and keep them in a container. You can find suitable container from stationary shops, where variety 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. Unfortunately power supply units are available in 1.5V increments. 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 misbehave. 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 standalone 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

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 purpose. A crystal oscillator is very stable over a wide range of physical conditions like temperature and pressure. 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

LEDs can be connected directly to the microcontroller pins. If you go through the PIC microcontroller datasheet 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 current 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 concerned. 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 + supply 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 confidence. 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 modules on breadboard, and treat them as one component. 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

we shall switch over to development board to make it further easier. The module shown here is from Microtronics Pakistan. This is based upon an 18 Pin PIC microcontroller, has 20 MHz Crystal Oscillator, an In circuit programming 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 protection 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 programmer 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

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 device 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 programmer 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 result.

7 B

Understanding The I-O Ports and Special Function Registers

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 devices. Thus each port is labeled as BiDirectional. PIC Microcontroller ports are named as PORTA, PORTB, PORTC and so on. The number of ports and bits in each port depends 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 microcontroller. 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

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

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 internal usage of the microcontroller. These specific locations, that have special meanings for the microcontroller 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 controller 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 application development and get most out of the microcontroller. High level programming languages, and compilers 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 registers 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

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

8
W
1. Endless loops

Control Structures Loops and Decisions

ell so far we have been through enough theory, by now you understand how to write a simple 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 various programming techniques.

First thing that we must learn is how to repeat a single, or a group of commands again and again. This feature 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:

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

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 encourages 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 programmer 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 conditions 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

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. Finally 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 statements. 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 controlled 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 programming, but a condition has been defined to be monitored 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

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

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.

The delay_ms() is not a library function, instead it is a macro, and it expands itself where it is used. Moreover 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 Procedure 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 program continues, otherwise these statements are bypassed, and the program continues after these statements. Now there should be a way to inform the compiler the boundary of statements to be executed in case the condition 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.

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

There is yet another construct to facilitate multiple Ifs. When a number of different tasks have to be performed 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.

9
S

Connecting Output and Input Devices

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 microcontroller 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 electronics 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 output pin, as in Bipolar transistors, check the MOSFET datasheet if it can be driven safely by microcontroller supplied 25mA current. The switching speed depends upon gate current. It therefore more safe to drive the MOSFET through a

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 electromagnet for its function. This can be a relay, a DC Motor, A solenoid or things like that. What makes this situation a little bit different is that when current flows through the coil, a magnetic 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 MOSFET. Therefore a protection Diode is required for these devices.

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 transistor 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 transistors 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.

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 microcontroller circuit using Opto-isolators. Opto-isolators or opt-couplers are small Integrated circuit like chips that contain an LED and a photo diode inside. Thus when a microcontroller pulse turns the internal 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 circuit 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 industrial applications. Opt-Isolators are therefore frequently used at both input and output levels in industrial applications.

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

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 example 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 signal and PIC may not see it. I therefore prefer using a 10K resistor 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 detect. 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 surroundings 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 resistor. The decoupling capacitor is not necessary, but a good habit to use.

Dealing with Non -TTL Inputs


As previously mentioned your Microcontroller would expect the Input to be TTL compliant. This means

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 circuit. 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 current 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 important 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 05V however maximum, or we will damage the microcontroller. Before using an analog source with microcontroller 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 device, 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 dividers 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 microcontrollers directly. We shall talk more about this in appropriate sections.

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 directly. The sensor is dealt like an ordinary resistance, and connected to the circuit as part of a voltage divider. 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 resistance 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 voltage 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 voltage.

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 microcontroller 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 common, 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 current 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

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.

10 I

Using Push Switches

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 microcontroller is not directly tied to a function. This is just an Input to the microcontroller 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 however 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 connected to RA3 and RA4 lines of PIC16F819 Microcontroller. In the same board we have four LEDs connected 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 Programming, and a lower resistance 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 logical 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

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 sequence 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 controller 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 function 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

A indicates it will behave as Analog. There are 8 bits in ADCON1 register, the lower 4 in various combinations 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 ADCON1=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 setting. 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 methods 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)

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

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 scenario 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 functions 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 combinations, 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 corresponding 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.

application. All however work in the same way.

11
S

Character LCD Display

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 monitor 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 commands, 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 important 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 timing 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, nevertheless 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 difficult 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

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 resistor 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 something 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

context. When the pin is Low we can write to the display, and when pin is high we can read from the display. 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 communicate. 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 IO 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 upper 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.

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 concentrate 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 D7 D6 D5 D4 R/W Enable RS PIC18F452 Microcontroller Pin PORTD.7 PORTD.6 PORTD.5 PORTD.4 GND PORTD.3 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

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 liberty 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 MikroBasic 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 instructions 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 important point is, that if you switch from MikroBasic to MikroC for example, these library commands will

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 _LCD_FIRST_ROW _LCD_SECOND_ROW _LCD_THIRD_ROW _LCD_FOURTH_ROW _LCD_CLEAR _LCD_RETURN_HOME _LCD_CURSOR_OFF _LCD_UNDERLINE_ON _LCD_BLINK_CURSOR_ON _LCD_MOVE_CURSOR_LEFT _LCD_MOVE_CURSOR_RIGHT _LCD_TURN_ON _LCD_TURN_OFF _LCD_SHIFT_LEFT _LCD_SHIFT_RIGHT Purpose Move cursor to the 1st row Move cursor to the 2nd row Move cursor to the 3rd row Move cursor to the 4th row Clear display Return cursor to home position, returns a shifted display to its original position. Display data RAM is unaffected. Turn off cursor Underline cursor on Blink cursor on Move cursor left without changing display data RAM Move cursor right without changing display data RAM Turn Lcd display on Turn Lcd display off Shift display left without changing display data RAM 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 constant 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 conversion library functions. These functions accept the binary number, or variable, and convert them into textual

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 LCD_EN as sbit at LCD_D4 as sbit at LCD_D5 as sbit at LCD_D6 as sbit at LCD_D7 as sbit at

RD2_bit RD3_bit RD4_bit RD5_bit RD6_bit RD7_bit at at at at at at TRISD2_bit TRISD3_bit TRISD4_bit TRISD5_bit TRISD6_bit TRISD7_bit

LCD_RS_Direction as sbit LCD_EN_Direction as sbit LCD_D4_Direction as sbit LCD_D5_Direction as sbit LCD_D6_Direction as sbit LCD_D7_Direction as sbit ' 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)

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 procedure would accept a text data as a parameter and then use Lcd_Out() to show it. Since string data is complex 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 procedure 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-

play has more to offer. A knowledge of its internal working, can be helpful in writing more powerful applications.
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 characters 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 assigned to one memory location:

The addresses of CGROM memory locations match the characters of ASCII. If the program being currently executed encounters a command send character P to port then the binary value 0101 0000 appears on the port. This value is the ASCII equivalent to the character P. It is then written to an LCD, which results in displaying 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 previous map, addresses of all digits are pushed forward by 48 relative to their values (digit 0 ad-

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

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

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.

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

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 consuming 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 project.

12 Y

Seven Segment LED Display

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 combination 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 encouraged. 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 universally defined. Thus segment a is always top horizontal 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

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 display are not standard, so you have to figure out first the pins on your module. The easiest way is to first locate the common. And then connect all other pins one by one to map the a,b,c .. g and dp connections. 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 segments. 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.

assigned values 63 and 125 alternately with a delay of 1 second in between. Number 63 is a mask for 0 to display, and number 125 is a mask for number 6 to display. So this program 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 simplified 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 little 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 digits will be connected together to one I-O line, similarly segment b will be connected to second I-O line and

so On. Naturally you must be wondering if we send number 7 mask to the I-O lines this number will be displayed 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 separate 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-

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 connected 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 process 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 ' PORTC.1=1 PORTD=Digit_Mask[i] Delay_ms(100) Portc.1=0 i=(Number/100) mod 10 ' Extracts 6

Extracts 8

PORTC.2=1 PORTD=Digit_Mask[i] Delay_ms(100) Portc.2=0 i=(Number/1000) mod 10 ' 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 deliberately 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 discussed we are going to display the numbers one at a time. So we have to devise a method to extract individual 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.

Extracts 5

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)

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.

13 A

USART Universal Asynchronous Receiver and Transmitter

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

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 understanding as to speak and listen to each other. This mutual agreement is based upon some set of rules. In electronics 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 systems 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 received and compare it with parity bit received. Although not 100% fool proof yet this has some protection. 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-

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 input 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 usually the case, you can connect the pins of processors directly. In addition to Tx and Rx connections, you will certainly have to connect the grounds of two devices together. There is no need to connect the VDD (or +5V supply) together unless you are powering from a single source. Remember USART is a communication Protocol, it is not a means of connection. You can connect the devices directly through a cable, or establish the link through Infra-red LEDs, Fiber optic cables, Radiofrequency 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 communicating through wired connections. These days GSM and GPRS modules are available to send SMS and get global positioning data from satellite. These modules, are a world in themselves. They just have Tx and Rx communication lines for interfacing 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 electronic 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 devices 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-

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 microcontrollers use TTL levels, a logic 1 is +5V and logic 0 is 0V. If you come across a device 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 favor 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 microcontroller 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 connections 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 converters, 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 somewhat 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 complete serial communication will therefore need 4 wires, two for data Tx and Rx and two for control communication. 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 external 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

This looks strange as to have serial communication at two levels. What does it mean? It is important to understand 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, parity 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 having 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 dictated 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 example 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

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

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 program 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 transmitted 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 available 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.

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

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 HyperTerminal. 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 settings 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 communication 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

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)

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 standards, 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.

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

rate and it has standard LCD on the other end. The microcontroller 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 appear 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 LCD_EN_Direction LCD_D7_Direction LCD_D6_Direction LCD_D5_Direction

as as as as as

sbit sbit sbit sbit sbit

at at at at at

TRISD3_bit TRISD2_bit TRISD7_bit TRISD6_bit TRISD5_bit

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 appear 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 transmitting pin of the transmitting board. That pin might be hardware USART TX pin, or any other pin configured 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)

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 program 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 microconReceiver Connections (RC6, RC7)

Transmitter Connections

Power Supply to Transmitter allows common ground as well

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 transmit 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 receiver 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 overflow 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 communication, 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.

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 signal, proportionate to what has been sensed. The simplest and commonest sensor you can say is a microphone. This sensor senses the vibrations in audible range and transforms the sound intensity to a proportional analog signal. The voltage produced by microphone 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 captured and presented to processing section as different data by the microphone. Similarly other sensors like temperature, humidity, wind speed, angular motion of car, height, pressure, light and chemical (specific sensor for specific chemicals) sense their respective physical quantities and convert them into an analog signal. Since microcontrollers and such devices are to a large extent concerned with managing and controlling these physical values, it is mandatory to have a mechanism that will accept this analog 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 technically called Accuracy and Precision.

14 I

Dealing With Analog Data

Analog to Digital Converter


Analog to Digital Converter or ADC is a device through which a given input voltage is sampled and converted 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.

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 representation 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 different sensors. So if we have a temperature as well as light sensor, 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 situations 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.

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 particular 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 required 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 microcontroller 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.

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 number 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 LCD_EN_Direction as sbit LCD_D4_Direction as sbit LCD_D5_Direction as sbit LCD_D6_Direction as sbit LCD_D7_Direction as sbit ' 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. at at at at at at TRISD2_bit TRISD3_bit TRISD4_bit TRISD5_bit TRISD6_bit TRISD7_bit

Before using this function we have to set ADCON1 register to configure the desired pins as digital or analog. Here is a table from PIC18F452 data sheet analog section showing the settings of bits 0..3. various combinations 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 number, 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.

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 ANRESL 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 representative 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

select which channel to use for Analog and declare others as digital, or a combination of analogs and digital, 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 capacitance 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 conveniently done by making a voltage divider. Here one of the resistors is fixed lets say 10K and other is unknown, 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 following 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 circuitry 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 centigrade. 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.

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 LCD_EN LCD_D7 LCD_D6 LCD_D5 LCD_D4

as as as as as as

sbit sbit sbit sbit sbit sbit

at at at at at at

RD3_bit RD2_bit RD7_bit RD6_bit RD5_bit 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.

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 input 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 voltage 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 opamp in inverting sequence, this will convert the negative volts to positive and your controller can easily measure this, since you know input is inverted multiply the answer with 1.

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 converted 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 Resistor. A wide variety of applications benefit from the ability to measure current flow. Traditionally, current sensing was primarily for circuit protection and reporting. However, as technology advances, 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 microcontroller to have a common ground with sense resistor, and we can easily 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.

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 window mirror of car, when it will encounter a resistance the current will increase and you may use the microcontroller 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 commercial 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 humidity 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

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 microcontrollers 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 representing 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 reference 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.

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 logical 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 following 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.

15
W

Graphic LCD and Touch Screen

ell we have previously used character LCDs to display data. Also we have used serial terminal 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 microcontroller, or if required in external EEPROM. Fortunately 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 commonly 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 negative 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-

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 CS2 Data D0..D7 RS RW E RB0 RB1 RD0..RD7 RC0 RC1 RC3

program GLCD ' Declarations section ' Glcd module connections dim GLCD_DataPort as byte at PORTD dim GLCD_CS1 GLCD_CS2 GLCD_RS GLCD_RW as as as as sbit sbit sbit sbit at at at at RB0_bit RB1_bit RC0_bit RC1_bit

GLCD_EN as sbit at RC2_bit GLCD_RST as sbit at RB5_bit dim GLCD_CS1_Direction as sbit GLCD_CS2_Direction as sbit GLCD_RS_Direction as sbit GLCD_RW_Direction as sbit GLCD_EN_Direction as sbit GLCD_RST_Direction as sbit ' 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. at at at at at at TRISB0_bit TRISB1_bit TRISC0_bit TRISC1_bit TRISC2_bit TRISB5_bit

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

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 order 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. Notice 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 offset position from where the map starts. All MikroBasic Fonts have offset 32, it means they start with definition 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-

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 numbers, 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 language 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 memory 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 MikroBasic help completely. You should experiment with them to know how they function.

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 microcontroller. The microcontroller can then decode the signal 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 using 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 conductivity 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 microcontroller 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 transparent 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 YThats 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 XCurrent 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 microcontroller and determines the voltage. This gives the

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.

16 P

Using Numeric Keypad

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 connecting 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 connected 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 keypad, 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 connecting 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

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 command, not for initial key press, but when a key is pressed, it keeps on waiting till its released, this will effectively 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

dim LCD_RS_Direction LCD_EN_Direction LCD_D7_Direction LCD_D6_Direction LCD_D5_Direction LCD_D4_Direction

as as as as as as

sbit sbit sbit sbit sbit sbit

at at at at at at

TRISD3_bit TRISD2_bit TRISD7_bit TRISD6_bit TRISD5_bit 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 pulldown 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

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 [1] 4 [2] 1 [3] C [4]

8 [5] 5 [6] 2 [7] 0 [8]

9 [9] 6 [10] 3 [11] = [12]

/ [13] * [14] [15] + [16]

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 ASCII 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 ' +

end Select Result=kp end sub

This function when called from the main program will scan the keypad, using Keypad_Key_Click() function. This function is kept in a loop to monitor keypad, till a key is pressed and released. After that the function 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 acknowledge only one digit at a time, and has no mechanism to record multiple key presses as a single number. 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 ASCII 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

LCD_D5 as sbit at RD5_bit LCD_D4 as sbit at RD4_bit dim LCD_RS_Direction LCD_EN_Direction LCD_D7_Direction LCD_D6_Direction LCD_D5_Direction LCD_D4_Direction dim dim dim Sub dim

as as as as as as

sbit sbit sbit sbit sbit sbit

at at at at at at

TRISD3_bit TRISD2_bit TRISD7_bit TRISD6_bit TRISD5_bit TRISD4_bit

keypadPort as byte at PORTB txt as string[7] u as word Function GetkeyPad as Byte 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 ' + end Select Result=kp end sub Sub Function dim a dim b b=0 while GetNumber as Word as byte as word 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.

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 program. 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 optimizations 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 second 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)

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.

17
S

Producing Sound

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 acknowledgement 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 different 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 purpose 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 amplitude 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 sensitive 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.

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 however. To produce a sound we need something that should accept electrical input and convert it to mechanical vibration. One such device everyone is aware of is magnetic speaker. When the coil of speaker is energized it produces a magnetic force, that interacts with permanent magnet in side the speaker. This force repels 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)

PIZO = 1 delay_ms(2000) wend end.

Since speakers contain a coil, which has some resistance, if speaker is directly connected to the microcontroller pin the current required will be too high. For example if we have a speaker with 16Ohms coil resistance, 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 difference 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.

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 compiling. 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 frequencies. The Sound_Play command takes frequency, 1000 in this case and duration, 100 mili seconds in the example above to play a sound.

PWM is a technique of getting analog signals from purely digital means without any intervening 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 compared to 5V. Since one cycle of pulse is On and Off. So a complete cycle is both ON and OFF. If the frequency 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.

18 M

Pulse Width Modulation CCP Module

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.

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

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

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 number 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 available 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)

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 percentage. 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 continuously 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 waveform 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

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 varying brightness. This however does not mean an actually varying voltage is being produced. A look on oscilloscope 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)

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 purpose 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, showing 3V.

The second image is with incorrect Filter values, here we have used 1K resistor, 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-

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.

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 Frequency. 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 returned 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

n 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31

Sin(n * 0.19635) 0 0.195090772 0.382684281 0.555571378 0.70710808 0.831470888 0.923880587 0.980785907 1 0.980784474 0.923877775 0.831466806 0.707102885 0.55556527 0.382677494 0.195083567 -7.34641E-06 -0.195097978 -0.382691068 -0.555577487 -0.707113275 -0.831474969 -0.923883398 -0.980787341 -1 -0.980783041 -0.923874964 -0.831462725 -0.70709769 -0.555559162 -0.382670706 -0.195076362

Multiply with 127 Add 128 0 24.77653 48.6009 70.55757 89.80273 105.5968 117.3328 124.5598 127 124.5596 117.3325 105.5963 89.80207 70.55679 48.60004 24.77561 -0.00093 -24.7774 -48.6018 -70.5583 -89.8034 -105.597 -117.333 -124.56 -127 -124.559 -117.332 -105.596 -89.8014 -70.556 -48.5992 -24.7747

Round Off 128 152.7765 176.6009 198.5576 217.8027 233.5968 245.3328 252.5598 255 252.5596 245.3325 233.5963 217.8021 198.5568 176.6 152.7756 127.9991 103.2226 79.39823 57.44166 38.19661 22.40268 10.66681 3.440008 1 3.440554 10.66788 22.40423 38.19859 57.44399 79.40082 103.2253 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

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 produced 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 statements managing loop are also taking some time, thus either precise correction can be made using a fre-

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-

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.

19 A

I2C Communication I2C EEPROM

nother method of communication is I2C. I2C stands for Inter Integrated Circuit Communication. This protocol was first developed by Philips semiconductors. This protocol allows communication 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 communication, when master demands them to reply, they give their data on SDA line for consumption by master. 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 announces 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 complete modules like LCDs are available that can communicate over I2C protocol. Even you can make your own slave devices that can communicate 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

press detector (to save pins). Since I2C is a proprietary protocol any commercially produced device has to pay the royalty. Some manufacturers 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. Connecting 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 sequence. 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 indicate completion of process Finally a Stop sequence is sent to close the con-

nection. This pictures shows the process of writing data to a device. The response from device 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) I2C1_Start() I2C1_Wr(0xA0) I2C1_Wr(2) I2C1_Wr(170) I2C1_Stop() Delay_100ms() I2C1_Start() I2C1_Wr(0xA0) I2C1_Wr(2) I2C1_Repeated_Start() I2C1_Wr(0xA1) x = I2C1_Rd(0) I2C1_Stop() ByteToStr(x,txt) LCD_Out(1,1,txt) end. ' ' ' ' ' ' '
issue I2C start signal send byte via I2C (device address + W) send byte (data address) issue I2C signal repeated start send byte (device address + R) Read the data (NO acknowledge) issue I2C stop signal

' ' ' ' ' '

initialize I2C communication issue I2C start signal send byte via I2C(device address + W) send byte (address of EEPROM location) send data (data to be written) issue I2C stop signal

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 Microcontroller. 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 communicate at 100K. Nevertheless it will work at 400K as well.

I2C1_Start()
Next we have to start the I2C communication, by giving this statement, this statement produces an I2C start condition 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 expects 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 memory 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)

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 parameter 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 different. 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 number 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.

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 example 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 integer, 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 accessing 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 sequence, as shown above. To store two bytes this sequence has to be repeated twice, with incremented location 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 instruction 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.

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 defined 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 address. 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 successful 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 session 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 Page 0 Read Operation Page 1 Write Operation Page 1 Read Operation %10100000 %10100001 %10100010 %10100011 0xA0 0xA1 0xA2 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 display 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 program. 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 compilers only demonstrate by writing and reading a byte of data.

sub Procedure EEPROM_Write_Word(dim d as Word, dim address as byte, dim DeviceAddress as byte) I2C1_Start() I2C1_Wr(DeviceAddress) I2C1_Wr(address) I2C1_Wr(lo(d))

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.

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 compliant and some using different protocols. Our objective of selecting an I2C compliant 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 simultaneously. 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.

20 I

I2C Communication DS1307 Real Time Clock

What is a Real Time Clock?


The time keeping is one of the important tasks sometimes required in your program. Basically time measurement consists of hours, minutes and seconds and sometimes milli seconds as well. It also involves calendar 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 actual 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 headache, 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 required 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 battery, 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 order 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-

mended that the crystal should be placed as close to the chip as possible. VCC and GND are self explanatory. 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 interrupt. 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 hobbyists. 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 address 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 configuration 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 storage 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 understand 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-

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 BCD Value 5 0101 7 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.

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

I2C1_Wr(0xd0) I2C1_Wr(address) I2C1_Repeated_Start() I2C1_Wr(0xd1) result=I2C1_Rd(0) 'Now I2C1_Stop() End Sub

read the response from DS1307

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

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 decimal 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 oscillator 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 perform 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 variable. 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 minutes, 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 register as well. The numbering system is all based upon your own preference, like 1 for Sunday, 2 for Monday 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

21 I

Interrupts and Timers

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 processor. As the name implies, an interrupt can be compared to the general 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, suddenly 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 microcontroller is in communication with other devices while at the same time it has to handle its own internal 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.

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 devices, and 99% of our checks would say the device does not need attention. Moreover what if we are managing 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 remote 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 timers, 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 interrupt 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 program 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.

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 disables 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 interrupt 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 interrupt 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 falling edge will cause the interrupt. We shall see all this in detail when we will use these features. I have

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 reserved 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 Interrupt 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 executing 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 enabled 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

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.

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

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 situations 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 combined together they form a 16 bit register. Timer0 can be configured to work as 8 bit or 16 bit register.

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 oscillator 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 complete one interrupt cycle in 0.5 * 256 = 128 uS. This eliminates the decimal point and eases out the calcula-

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

INTCON.GIE =1 Count1=0 count2=0 LED1=0 LED2=0 while True Wend end.

' Enable General Interrupt

' An endless loop to do something else

Now just like changing the status of LEDs you can also do other tasks that will operate in background. Remember the 7-segment LED display. In order to keep the numbers on display we had to keep them refreshed. 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 INTCON.T0IF=0 INTCON.GIE=1 LCD_Init() T0CON.TMR0ON=0 while true ' Enable Interrupt ' Clear T0 Interrupt flag ' Enagle Interrupts 'Stop Timer

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 going 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 theoretically 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 internal Frequency would be 20/4=5MHz. The image

shows this to be about 5.1MHz. So we are sure this particular frequency counter will be able to display frequency 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 digital signal. The NPN transistor can be any having good gain and frequency 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 capacitor 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 interrupt. 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 microcontroller to have an interrupt on these modules varies. Therefore always check the capability of your microcontroller 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 manual I will not go into details. I am sure if you have worked with previous examples, you will be able to understand 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.

22
S
lot more.

Motor Control DC Motors | Steppers | Servos

o far we have been working with electronic devices. Microcontrollers 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

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 phenomenon 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 conductor it produces a magnetic field around it. The magnetic field is circular and its rotational direction depends upon the direction of current flowing. 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 magnetic 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 energy 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 magnetic 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

direction to the original current. This back current can damage the driving electronic circuitry. It is mandatory therefore to have a protective mechanism against this effect. This usually comes in the form of a Fly-Back Diode. A diode that can tolerate the expected current is placed parallel to the inductor in reverse biased form. Thus when current flows in reverse direction 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 effect 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 effectively 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 essentially 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 terminals are swapped then the direction of rotation is reversed. DC motors consist of a core of solenoid, that can be two or more. Connected 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 powered. The torque of DC motors depends upon the core. More turns of coil and more current it can draw

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 current flow.

Characteristics of a DC Motor
Before using DC motors it is important to know few facts. This will help in understanding the driver circuits 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. Exactly 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 circuit 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 microcontroller 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 transistor if the current requirement of motor is high or you can use MOSFETs that can handle really big loads. Remember most commonly available MOSFETs require almost 12V to get ON. Therefore they can not be used directly with a microcontroller. Nowadays 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.

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 microcontroller. For higher currents MOSFET is the answer. Logic level MOSFETS are hard to find. The IRF510 gate requires 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 transistor 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

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 inside. 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 Darlington 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 Darlington 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 negative and the one getting negative now gets positive. You must have experienced this many times using toy motors and connecting them to the battery.

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 sequence 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 HBridge. The H-bridge consists of 4 switches and motor is connected as a bridge between these two sets. When S1 is closed and S2 open there is Positive supply 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 motor 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,

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 forwards 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 motor? 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 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. is

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

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 supply 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 enable 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 number 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.

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 ENA=0 end sub M1_Stop

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

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 motor. 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 precise mechanical work is needed. These motors are characterized by two mechanical and one electrical parameters. 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 rotation per step. This precision can be further increased by combining a gear assembly with it. Second parameter is the torque.

Just like in DC motors this indicates the force generated by the motor. Most of the times steppers are driving 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

inductors. These inductors need to be energized in a sequence to achieve a movement. Secondly the direction 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 energized. 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.

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 common 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 HBridge 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 common connection and consider the two coils as one. Then four phases will be converted into two individual 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

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 motor requires programming logic to sequentially control these motors. However many commercial boards and equipment that works with these motors requires that your board should get a pulse for advancing a step, and another line to control the direction. Most commercially developed boards therefore have all the logic built into them either with a microcontrol1 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

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 prebuilt 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 diodes 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 Darlington per pair if the current ratings of your motor allow. Now whatever is the case we assume that the

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 activity 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 intentionally 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.

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 motors get stuck. L297 can also be used with ULN2803 or similar driver to drive unipolar motors. Most of the complex fea-

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 control, 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

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

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 module, 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 available, 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.

23 L

LED Matrix Displays

EDs are fascinating devices. They consume very small amount of current, do not produce heat and can be rapidly switched on and off. Truly speaking they are solid state light sources. They have been used in electronics to indicate status of various processes 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. Similarly 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 happens 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 remains 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 together, and all the cathodes of a column are connected together. 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

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

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 activated 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 column 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 displayed 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

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 multiplexing 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 column into an equivalent binary or decimal numbers. Then we store this pattern in an array of 5 bytes. Each byte will hold pattern of one column. Then using our loops we will display the corresponding data from array into display. As an example see

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.

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 communication. Almost all remote controls used for TV, Music systems and air-conditioners use IR communication. 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 communication 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

24 I

Infra Red Communication and Remote Controls

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

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 optimized to sense these lights, but can also detect the lights in other range. The sensitivity is however maximum 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 IRLED and see it through your mobile phone camera. Test it with your TV remote control and see its LED with digital camera while pressing 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.

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 amplifier 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 independent OP AMPS in them and use them to have two or four independent sensors. The circuit board I am using has the simple circuit 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

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 circuitry can be adapted to respond only to 38KHz signals. Fortunately specially designed sensors are available 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 receiving 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 information over it. In easier terms lets consider a musician playing with a flute. The frequency produced by

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 communication). 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 producing a pulsed wave output and not a continuous beam. Second we should have a control that should enable 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 Oscillator 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

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 oscillator 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 sensor, and an Rx pin that will be the pin 4 of your 555 timer. You will need two such boards and two microcontroller 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

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

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. However 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 hardware 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 invert 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 up resistor produces logic 1 at the collector.

and 10K pull-

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

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 received. 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 communication 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 encoders 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 functions 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 consists 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 command 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-

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

dim dim dim dim dim

x as word 'To store 12 bit code i as byte 'counter variable txt as string[16] Sony_Device as byte Sony_Command as byte

main: ' Main program Lcd_Init() Trisb.6=1 ' IR Sensor Input While True while Sony_IR=1 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) 'Wait for an IR signal

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 received, 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 received, 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 button 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 bitwise 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 program 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

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

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 registers 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 extensive 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 function 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)

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

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 device ID of remote. In this program SonyIN() is the function that needs to be called from the main program. The function requires 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 functions 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 functions 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 returned 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.

25
S

SPI - Serial Parallel Interface

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 internally 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 module. 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 individually 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 internally 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 enable the chip and make it ready to respond.

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 IO 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 connected 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 outputs on the IC. So you trade 3 valuable lines on your microcontroller for 8 outputs. This is called "Shifting data out" of the microcontroller by "synchronous serial communication". This is the serial part of the deal, where each bit is "shifted in" one at a

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

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 liberally. 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 significant 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 procedure 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

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 activated. 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 discussion, 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 produced by microchip and works with SPI protocol. This is a 12 bit digital to analog converter. With low noise operational amplifier and single 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 contains two such modules, the operation is similar. You will need to connect 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 operate. 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 SoftSpi_CLK_Direction as SoftSpi_SDI_Direction as SoftSpi_SDO_Direction as ' End DAC module connections sbit sbit sbit sbit at at at at TRISC1_bit TRISC3_bit TRISC4_bit TRISC5_bit

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 setting, see MCP4921 datasheet Soft_SPI_Write(temp) byte via Soft SPI ' Send Low Byte temp = lo(valueDAC) valueDAC[7..0] to temp[7..0] Soft_SPI_Write(temp) via Soft SPI Chip_Select = 1 chip end sub ' Define DAC ' Send high

' Store ' Send low byte

' Deselect DAC

' 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 configurations. 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

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 correction sort of thing in this protocol, therefore wiring errors are not tolerated. A number of SPI compliant devices are available in market some are simply chips for a specific function as MCP4921 or complete devices 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/interfacinglcd-via-spi . Sending text data to this SPI LCD will be however little difficult as there is no built-in command available for that. You will have to make a custom procedure to send the data to this module via SPI.

26
W

RS-485 Long Range Serial Communication

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 device can be connected to this interface. This makes it difficult to use in noisy industrial environments where usually more than one devices need to communicate with the main controller or main computer. The speed of communication over RS232 is also limited to maximum about 20 Kbps. RS-485 protocol was therefore developed to address this issue. This communication 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 underlying 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 receiver 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

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 resulting 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 better 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 communicate over much longer communication distances than achievable with RS232. With RS485 communication distances of 1200 m are possible. Differential signal lines also allow higher bit rates than possible with non-differential connections. Therefore 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 applications. RS485 is the only of the interfaces capable of internetworking multiple transmitters and receivers in the same network. When using the default 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 kilometers. 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 multipoint 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 designed 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

as a master which sends queries or commands over the RS485 bus. All other nodes receive these data. Depending 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 corruption 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 Modbus. 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 implementations. In order to implement RS485 protocol you will need a transceiver 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 complete connections diagram is shown on next page. You can also connect your PC directly to

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.

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

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.

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 microcontrollers unfortunately RS485 coding modules are not present and we have to implement the protocol using software 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 communication 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

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 calculation 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] dat[1] dat[2] dat[4] dat[5] dat[6]

= = = = = =

0xAA 'Data to be sent 0 0 0 ' ensure that message received flag is 0 0 ' ensure that error flag is 0 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-

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 example 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 interrupt 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 error and handle it if you want. Check the message received flag in Dat[4] if it is received successfully process 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 procedure 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

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) RS485Master_Init() PIE1.RCIE = 1 PIE2.TXIE = 0 INTCON.PEIE = 1 INTCON.GIE = 1 while true dat[0] = 65 dat[1] = 0

' ' ' ' ' '

initialize UART module initialize MCU as a Master enable interrupt on UART1 RX disable interrupt on UART1 TX enable peripheral interrupts enable all interrupts

dat[2] dat[4] dat[5] dat[6]

= = = =

0 0 0 0

' ensure that message received flag is 0 ' ensure that error flag is 0

RS485Master_Send(dat, 1, 100) 'Send data to Slave 1 delay_ms(1000) dat[0] dat[1] dat[2] dat[4] dat[5] dat[6] = = = = = = 105 0 0 0 0 0

' ensure that message received flag is 0 ' ensure that error flag is 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 dim dim dim RS485_rxtx_pin as sbit at RC2_bit RS485_rxtx_pin_direction as sbit at TRISC2_bit dat as byte[10] 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

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

27
O

Dallas One Wire Protocol

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 device 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 supply. 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 temperature 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 Dallas semiconductors. This sensor looks like a transistor, but in fact is complete device and can communicate with microcontroller using 1wire protocol. In this chapter we will use this as a protocol to learn 1wire communication. Just as we have done before it is important to have a look at the datasheet 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

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.

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 resistor 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 representing 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.

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

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-

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 temperature reader and convert the temperature and store in data registers. As we are using default 12 bit resolution 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 command 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 variable.

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 temperature, the whole number of temperature and the decimal part. A look at the format of converted temperature 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 positive 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

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)

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 temperature of three different locations. Certainly you will need three different sensors. One-wire protocol allows 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 individual sensor to get data. You can still use the SKIP_ROM command for global issues like before giving command 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.

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 simpler 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() Lcd_Cmd(_LCD_CLEAR) Lcd_Cmd(_LCD_CURSOR_OFF) Lcd_Out(1, 1, " ROM Code delay_ms(2000) Lcd_Cmd(_LCD_CLEAR)

' Initialize Lcd ' Clear Lcd ' Turn cursor off ") ' 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 Sensor 1 Sensor 2 CRC 142 185 Byte 6 0 0 Byte 5 0 0 Byte 4 0 0 Byte 3 184 184 Byte 2 197 197 Byte 1 48 49 Byte 0 40 40

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)

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() ' Lcd_Cmd(_LCD_CLEAR) ' Lcd_Cmd(_LCD_CURSOR_OFF) ' Lcd_Out(1, 1, " Temperature delay_ms(2000) Lcd_Cmd(_LCD_CLEAR) ' '--- main loop while (TRUE) Ow_Reset(PORTB, 0) Ow_Write(PORTB, 0, 0xcc) OW_write(PORTB,0, 0x44) ' Onewire reset signal ' Skip ROM ' Do Conversion

Initialize Lcd Clear Lcd Turn cursor off ") Clear Lcd

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

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 almost 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 concluding this chapter I would like to introduce some other one-wire devices. We will not explore them as procedure 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

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() Lcd Lcd_Cmd(_LCD_CLEAR) Lcd_Cmd(_LCD_CURSOR_OFF) sor off Lcd_Out(1, 1, " Temperature delay_ms(2000) Lcd_Cmd(_LCD_CLEAR)

' Initialize ' Clear Lcd ' Turn cur") ' 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 parameter is the number of sensor to access.

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 additional 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 identification 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 button. There are many other devices from Maxim available that work on 1wire basis like Pressure sensor, real time clocks, EEPROMs and many others.

28
U

USB Universal Serial Bus

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 parallel 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 simplifying software configuration of all devices connected to USB, as well as permitting greater data rates for external 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.

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 provides RS232 type signals for direct interfacing with UART module of microcontroller. The FT232 chip is however surface mount and needs to hookup some basic circuitry 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 automatically 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 interface 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. Unfortunately 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 connection. 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 implemented in them. Newer and advanced microcontroller from Microchip have USB 2.0 standards based module 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 connected. 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-

tor to connect the USB cable directly to the D+ and D pins of the microcontroller. Thats all your hardware is ready for interfacing. The USB ports usually can give 100mA current and standalone microcontroller 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 something 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 subject 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 devices using Microchip USB microcontrollers, the hardware will remain almost same. However a lot of understanding 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.

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 features. 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 numbered 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.

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

' 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 consists 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 terminal 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 vendor, 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.

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 select build. Now build the project and burn the .hex file to your controller. In order to see if the device is recognized, open the windows device manager and connect the device to USB cable. The device should get detected and list should get re-populated and show the

device. If the device is not detected or windows report an error message check the whole system before proceeding. Just to share my experience I had trouble in getting the device recognized, windows always reported 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 visible, 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 automatically 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

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.