introduction to pic interrupts and their handling in c

51
INTRODUCTION TO PIC INTERRUPTS AND THEIR HANDLING IN C Interrupts are common features in almost all processor family, be it old 8051, AVR, PIC, ARM or the x86 used in desktops. So their in depth and clear knowledge is required for successful system software engineers. This guide will explain the interrupt system in general and their application using PIC18 architecture. We will also learn about handling of interrupts in HI-TECH C for PIC18. What are Interrupts? Interrupts, as the name suggests interrupts the normal execution and Requests and urgent attention of CPU. Interrupts are situations that the CPU can't predict when they will happen, they can happen any time, so the CPU does not wait for them. So the CPU keeps on doing its normal job unless and interrupt occurs. For example when the USART (Serial Communication Hardware) will receive data is unknown, it can receive data any time. So the CPU keeps on doing its normal job, which may be for example read temperature using LM35 senso r and display on LCD . The CPU keeps on doing the "normal" job, but as soon as the USART receive data it informs the CPU using an interrupt. The CPU save its current state (so that it can resume), and jumps to the ISR (interrupt service routine) immediately. Where we can process the command or put it in a FIFO queue (to process latter). The ISR is generally kept very small and fast. As soon as the ISR ends, the CPU restores its saved state and resumes where it left. In this way CPU does not missed any data byte. Example of sources of Interrupts in PIC18 (also common in other MCUs) External interrupts - they are named INTx (like INT0, INT1 etc), they provide a means for external hardware to generate interrupts. Like if you connect a touchscreen controller to your PIC MCU. Then the touchscreens PENINT (pen interrupt) can be connected to

Upload: veerakumars

Post on 22-Nov-2014

144 views

Category:

Documents


3 download

TRANSCRIPT

Page 1: Introduction to PIC Interrupts and Their Handling in C

INTRODUCTION TO PIC INTERRUPTS AND THEIR HANDLING IN C

Interrupts are common features in almost all processor family, be it old 8051, AVR, PIC, ARM or the x86 used in desktops. So their in depth and clear knowledge is required for successful system software engineers. This guide will explain the interrupt system in general and their application using PIC18 architecture. We will also learn about handling of interrupts in HI-TECH C for PIC18.

What are Interrupts?

Interrupts, as the name suggests interrupts the normal execution and Requests and urgent attention of CPU. Interrupts are situations that the CPU can't predict when they will happen, they can happen any time, so the CPU does not wait for them. So the CPU keeps on doing its normal job unless and interrupt occurs. For example when the USART (Serial Communication Hardware) will receive data is unknown, it can receive data any time. So the CPU keeps on doing its normal job, which may be for example read temperature using LM35 sensor and display on LCD. The CPU keeps on doing the "normal" job, but as soon as the USART receive data it informs the CPU using an interrupt. The CPU save its current state (so that it can resume), and jumps to the ISR (interrupt service routine) immediately. Where we can process the command or put it in a FIFO queue (to process latter). The ISR is generally kept very small and fast. As soon as the ISR ends, the CPU restores its saved state and resumes where it left. In this way CPU does not missed any data byte.

Example of sources of Interrupts in PIC18 (also common in other MCUs)

External interrupts - they are named INTx (like INT0, INT1 etc), they provide a means for external hardware to generate interrupts. Like if you connect a touchscreen controller to your PIC MCU. Then the touchscreens PENINT (pen interrupt) can be connected to INT0 (or any other INTx). Then when ever the pen (or stylus) touches the screen it will interrupt the CPU. This interrupt will be explained in details in its own tutorial.

TIMER interrupts - They are also very common in MCUs. Today's MCUs comes with very sophisticated timers that can do lots of magic for you. They have they related interrupts. In most simple situation they can act like alarm clocks that can interrupt the CPU at predefined intervals. If you toggle a i/o pin in response to these alarms (interrupts), what you have is a frequency generator! For more info on timers on PIC18, read this article.

Analog to Digital Converter Interrupts - A/D Converter takes some time to complete its operation. So the CPU can either wait for it to complete or set up an AD conversion complete interrupt. In the latter case CPU can do other tasks while A/D converter converts the input. As soon as A/D converter completes its job it will inform CPU to read the value from its buffer. For more info on A/D Converter of PIC18, read this article.

Data Interrupts - MCUs have many different types of data i/o engines, like USART, SPI, I2C, Parallel etc. They can also interrupt the CPU when data

Page 2: Introduction to PIC Interrupts and Their Handling in C

transmission is complete or data arrives from external source. Like an RFID reader send a packet because a user just brought his or her card near the reader. Or the GSM module detected an incoming call.

How interrupts are managed?

In general each interrupt source have following related bits.

Enable Bit - There are suffixed with IE (Interrupt Enable) example TMR0IE stands for TIMER0 Interrupt Enable. It can be used to enable/disable the related interrupt. When set to '1' it enables the interrupt.

Flag Bit - It is set automatically by the related hardware when the interrupt condition occurs. It is generally suffixed with IF (Interrupt Fag). When it is set to '1' we know that interrupt has occurred. For example when TMR0IF is set by TIMER0, it indicates that TIMER0 has overflowed.

Priority Bit - We can leave this for now to keep things simple. We won't be using interrupt priority feature of PIC18.

In global level there are following bits to control the interrupts globally.

GIE - Global Interrupt Enable, enables/disables interrupts globally. PEIE - Enable/disable all peripheral interrupts.

Interrupt Vector

It is the address where the CPU jumps when an interrupt occurs. In PIC18 this address is 0008(hex). CPU jumps to this address for any interrupt. The ISR or Interrupt service routine is placed in this address. The ISR must determine the source of interrupt from the flag bit(described above).

1 //Main Interrupt Service Routine (ISR)2 void interrupt ISR()3 {4 //Check if it is TMR0 Overflow ISR5 if(TMR0IE && TMR0IF)6 {7 //TMR0 Overflow ISR89 counter++;//Increment Over Flow Counter1011 if(counter==76)12 {13 //Toggle RB1 (LED)14 if(RB1==0)15 RB1=1;16 else17 RB1=0;1819 counter=0; //Reset Counter

Page 3: Introduction to PIC Interrupts and Their Handling in C

20 }2122 //Clear Flag23 TMR0IF=0;24 }25 }

For example in above code snipped. void interrupt ISR() is the main service routine where the CPU jumps for any interrupt (TIMER,A/D, INTx etc). As soon as we enter the ISR we check for the source of interrupt. This done using the line

if(TMR0IE && TMROIF)

The above line check is the source of interrupt was TIMER0 (so it checks if TMR0IF is set or not). It also checks TMR0IE (TIMER0 interrupt enable bit) to make sure this interrupt is enabled or not. It execute the TIMER0 ISR only of both the condition are true. One more line on interest is line 23 where we clear the flag, this is necessary otherwise the interrupt is triggered again.

You should note one more point the GIE (explained above) is cleared automatically when PIC18 enters ISR, this make sure that interrupts cannot be interrupted them self. It also automatically sets GIE on return from interrupt, which re enable interrupts.

In the above code (from line 9 to 20), you can see that for each overflow of timer (like alarm from an alarm clock) we increment a counter and as soon as this counter reaches 76 we toggle an LED. And also clear the counter (line 19). This gives us a LED that is toggled ever 1sec. So you see that LED is controlled fully by the TIMER while CPU can keep on doing other jobs but LED will always blink at its predefined rate. This example gives a kind of illustration of multitasking, the LED take care of itself. You don't have to write anything on the main () function to control the LED. Your main function could go on normally, for example control a line follower robot. The TIMER will take care of the LED and toggle it every second. The LED could be used for decoration of the robot.

Handling interrupt in C

Here I will show you how we can write programs in HI-TECH C that utilizes interrupt feature of PIC MCU. The interrupt handling is very clean and straightforward in HI-TECH C (as compare to Microchip C18 Compiler). Please note that interrupt handling is not a standard feature of C language, so their is significant diffenence between different compiler in handling interrupts.

Please note that to simplify the situtation, we are not using interrupt priority feature of PIC18(because this is a guide for first time user of interrput). In HI-TECH C for PIC18 an ISR (interrupt service routine, that is called when interrupt condition occur) is defined like this

Page 4: Introduction to PIC Interrupts and Their Handling in C

void interrupt FunctionName(void)

As you can see in above code line the "interrupt" function qualifier is used to mark a function as ISR. The following point must be kept in mind while defining an ISR :-

1. The return type of ISR must always be void.2. It must not take any parameters. That's why argument list is set to void.3. The name of function can be any valid C function name. But I generally use the

name ISR for ISRs.4. Their can be at most one ISR function. (Two if using interrupt priority).

For more information refer to the HI-TECH C user manual.

HI-TECH C Program for TIMER0 Interrupt.

The following is a simple program that demonstrate use of interrupts. The program is very simple so does not do any magic but only teaches use of interrupt. Please go through the program very carefully to check out how every feature described above are used. To understand the program you also need some knowledge of TIMER0 which is described in detail in the following article.

Introduction to PIC18 Timers.

The program blinks a LED on RB1. The project is available for download in the above page.

1 /*****************************************************************23 A simple example to demonstrate the use of PIC Timers. In this 4 example the TIMER0 is configured as follows.56 *8 Bit Mode7 *Clock Source from Prescaler8 *Prescaler = FCPU/256 (Note: FCPU= Fosc/4)9 *Over flow INT enabled1011 As our FCPU=20MHz/4 (We are running from 20MHz XTAL)12 =5MHz1314 Time Period = 0.2uS15 Prescaller Period = 0.2 x 256 = 51.2uS16 Overflow Period = 51.2 x 256 = 13107.2 uS17 = 0.0131072 sec1819 So we need 1/0.0131072 Over Flows to count for 1 sec20 = 76.2939 Overflows2122 So we keep a counter to keep track of overflows.2324 When an over flow occurs the PIC jumps to ISR where we

Page 5: Introduction to PIC Interrupts and Their Handling in C

25 increment counter. And when counter becomes 76 we toggle26 RB1 pin. This pin is connected to LED. Therefore we27 have a LED which is ON for 1 sec and Off for 1sec.282930 Target Chip: PIC18F452031 Target Compiler: HI-TECH C For PIC18 (http://www.htsoft.com/)32 Project: MPLAP Project File3334 Author: Avinash Gupta35 Copyright (c) 2008-201036 eXtreme Electronics, India37 www.eXtremeElectronics.co.in3839 NOTICE40 -------------41 NO PART OF THIS WORK CAN BE COPIED, DISTRIBUTED OR PUBLISHED WITHOUT A42 WRITTEN PERMISSION FROM EXTREME ELECTRONICS INDIA. THE LIBRARY, NOR ANY PART43 OF IT CAN BE USED IN COMMERCIAL APPLICATIONS. IT IS INTENDED TO BE USED FOR44 HOBBY, LEARNING AND EDUCATIONAL PURPOSE ONLY. IF YOU WANT TO USE THEM IN 45 COMMERCIAL APPLICATION PLEASE WRITE TO THE AUTHOR.4647 *****************************************************************/4849 #include <htc.h>505152 //Chip Settings53 __CONFIG(1,0x0200);54 __CONFIG(2,0X1E1F);55 __CONFIG(3,0X8100);56 __CONFIG(4,0X00C1);57 __CONFIG(5,0XC00F);5859 unsigned char counter=0;//Overflow counter6061 void main()62 {63 //Setup Timer064 T0PS0=1; //Prescaler is divide by 25665 T0PS1=1;66 T0PS2=1;6768 PSA=0; //Timer Clock Source is from Prescaler6970 T0CS=0; //Prescaler gets clock from FCPU (5MHz)7172 T08BIT=1; //8 BIT MODE7374 TMR0IE=1; //Enable TIMER0 Interrupt75 PEIE=1; //Enable Peripheral Interrupt76 GIE=1; //Enable INTs globally77

Page 6: Introduction to PIC Interrupts and Their Handling in C

78 TMR0ON=1; //Now start the timer!7980 //Set RB1 as output because we have LED on it81 TRISB&=0B11111101;8283 while(1); //Sit Idle Timer will do every thing!84 }8586 //Main Interrupt Service Routine (ISR)87 void interrupt ISR()88 {89 //Check if it is TMR0 Overflow ISR90 if(TMR0IE && TMR0IF)91 {92 //TMR0 Overflow ISR93 counter++; //Increment Over Flow Counter9495 if(counter==76)96 {97 //Toggle RB1 (LED)98 if(RB1==0)99 RB1=1;100 else101 RB1=0;102103 counter=0; //Reset Counter104 }105 //Clear Flag106 TMR0IF=0;107 }108 }

Program Walk through

Line 64 to 72 : Configure the TIMER0. See tutorial on timer for more info. Line 74 to 76 : Enables Timer0 interrupt (TMR0IE=1), peripheral interrupt

(PEIE=1) and finally sets GIE=1 to enable interrupts. Line 83: The program has noting to do, so we enter an infinite loop and burn

CPU cycles. Your program is free to to any tasks after interrupts are set up and enabled. We required ISR will automatically called by the hardware to service the situation. As as soon as service is complete, normal execution will be resumed.

Line 87: define the ISR. Line 90: Checks if it is the timer interrupt (by checking the flag bit TMR0IF) and

if the timer interrupts are enabled (by checking TMR0IE). Line 91 to 104: is the service routine of TIMER0 interrupt. Line 106: clears the timer interrupt flag, this step is very important before exiting

the ISR or it will be called again!

A Word from the author

Interrupt handling is a vital for any successful and quality embedded code, so their clear knowledge is very important. The above article described interrupt handling in

Page 7: Introduction to PIC Interrupts and Their Handling in C

details. The same code framework and techniques are applicable for any interrupt enabled program howsoever complex it is. So I recommend that you go though the article until you are clear with every concept. They will be very helpful for you to write your own interrupt enabled programs and understand other programs provided in our website.

Introduction to PIC18’s Timers – PIC Microcontroller Tutorial

Timers are common features of most microcontroller. In simplified terms a timer is just a register whose value keeps increasing (or decreasing) by a constant rate without the help of the CPU. The CPU can read or write this register any time. It reads it find out how much time has elapsed. The Timer register can have the following bit length

8 bit timers - These can count between between 0-255 16 bit timers - These can count between 0-65536 32 bit timers - These can count between 0-4294967296

A timer has a clock source, for example of the clock source of 10KHz is input to a timer then one increment will take 100uS (micro second). This clock source can be obtained from the CPU clock. The CPU clock of popular MCU ranges from 1 MHz to 20Mhz, this can be sometimes too fast. To help us out their is a thing called prescaler in the MCU. The job of prescaler is to divide the CPU clock to obtain a smaller frequency. The PIC Micro that we will use in this example has the following prescaler division factors available.

1. 2562. 1283. 644. 325. 166. 87. 48. 29. 1 (Prescaler by-passed)

Timers are also called Counters this is because they can be used to count external events. The following examples illustrate the fact.

Page 8: Introduction to PIC Interrupts and Their Handling in C

Counter Operation.

The above setup can be used to measure the RPM (speed in revolution per minute) of the rotating wheel. A small magnet is attached in the edge of the wheel. Whenever this magnet is exactly below the Magnetic sensor its output becomes high. This output is connected to the T0CKI pin of the MCU. The T0CKI stands for Timer0 Clock Input Pin. So each time the magnet passes by the sensor the timer register inside the MCU is incremented. You can note one this that all this happens without the help of CPU. CPU can do other task and read the Timer register only when required.

Overflow

An overflow occurs when a timer register has already counted the maximum value it can count. At overflow the counter value become 0 again. For example when an 8 bit timer has the value 255 and receives another clock that will set it to 0 and generate an overflow. An overflow can trigger an interrupt and the ISR can handle it.

Using TIMER0 of PIC18F4520

PIC18F4520 has four different timers. The simplest is the TIMER0 so we will learn how to use it first. In this example the TIMER0 is configured as follows.

8 Bit Mode Clock Source from Prescaler Prescaler = FCPU/256 (Note: FCPU= Fosc/4) Over flow INT enabled

Our FCPU=20MHz/4 (We are running from 20MHz XTAL)

Page 9: Introduction to PIC Interrupts and Their Handling in C

=5MHz

Time Period = 0.2uSPrescaler Period = 0.2 x 256 = 51.2uS (Prescaler is set to divide frequency by 256)Overflow Period = 51.2 x 256 = 13107.2 uS (Each over flow takes 256 counts)= 0.0131072 sec

So we need 1/0.0131072 Overflows to count for 1 sec= 76.2939 Overflows

For that we maintain a counter to keep track of overflows.

When an over flow occurs the PIC jumps to ISR, where we increment the counter. And when counter becomes 76 we toggle RB1 pin. This pin is connected to LED. Therefore we have a LED which is ON for 1 sec and Off for 1sec.

Simple Program to Learn Operation of PIC TIMER0 in HI-TECH C and MPLAB

/*****************************************************************

A simple example to demonstrate the use of PIC Timers. In this

example the TIMER0 is configured as follows.

*8 Bit Mode*Clock Source from Prescaler*Prescaler = FCPU/256 (Note: FCPU= Fosc/4)*Over flow INT enabled

As our FCPU=20MHz/4 (We are running from 20MHz XTAL)=5MHz

Time Period = 0.2uSPrescaller Period = 0.2 x 256 = 51.2uSOverflow Period = 51.2 x 256 = 13107.2 uS = 0.0131072 sec

So we need 1/0.0131072 Over Flows to count for 1 sec= 76.2939 Overflows

So we keep a counter to keep track of overflows.

When an over flow occurs the PIC jumps to ISR where weincrement counter. And when counter becomes 76 we toggleRB1 pin. This pin is connected to LED. Therefore wehave a LED which is ON for 1 sec and Off for 1sec.

Target Chip: PIC18F4520Target Compiler: HI-TECH C For PIC18 (http://www.htsoft.com/)Project: MPLAP Project File

Page 10: Introduction to PIC Interrupts and Their Handling in C

Author: Avinash GuptaCopyright (c) 2008-2010eXtreme Electronics, Indiawww.eXtremeElectronics.co.in

NOTICE -------------NO PART OF THIS WORK CAN BE COPIED, DISTRIBUTED OR PUBLISHED WITHOUT A

WRITTEN PERMISSION FROM EXTREME ELECTRONICS INDIA. THE LIBRARY, NOR ANY PARTOF IT CAN BE USED IN COMMERCIAL APPLICATIONS. IT IS INTENDED TO BE USED FORHOBBY, LEARNING AND EDUCATIONAL PURPOSE ONLY. IF YOU WANT TO USE THEM IN COMMERCIAL APPLICATION PLEASE WRITE TO THE AUTHOR.

*****************************************************************/

#include <htc.h>

//Chip Settings__CONFIG(1,0x0200);__CONFIG(2,0X1E1F);__CONFIG(3,0X8100);__CONFIG(4,0X00C1);__CONFIG(5,0XC00F);

unsigned char counter=0;//Overflow counter

void main(){ //Setup Timer0 T0PS0=1; //Prescaler is divide by 256

T0PS1=1; T0PS2=1;

PSA=0; //Timer Clock Source is from Prescaler

T0CS=0; //Prescaler gets clock from FCPU (5MHz)

T08BIT=1; //8 BIT MODE

TMR0IE=1; //Enable TIMER0 Interrupt PEIE=1; //Enable Peripheral Interrupt

GIE=1; //Enable INTs globally

TMR0ON=1; //Now start the timer!

//Set RB1 as output because we have LED on it

TRISB&=0B11111101;

Page 11: Introduction to PIC Interrupts and Their Handling in C

while(1); //Sit Idle Timer will do every thing!}

//Main Interrupt Service Routine (ISR)void interrupt ISR(){ //Check if it is TMR0 Overflow ISR

if(TMR0IE && TMR0IF) { //TMR0 Overflow ISR counter++; //Increment Over Flow Counter

if(counter==76) { //Toggle RB1 (LED)

if(RB1==0) RB1=1; else RB1=0;

counter=0; //Reset Counter

}

//Clear Flag TMR0IF=0; }}

The program begins by Setting up TIMER0. The TIMER0 can be configured using a single register called T0CON which stands for TIMER0 control register. The details of each bit are given below.

Name TMR0ON T08BIT T0CS T0SE PSA PS2 PS1 PS0

Initial Value 1 1 1 1 1 1 1 1

BIT 7 6 5 4 3 2 1 0

BIT7 - TMR0ON: Timer0 On, set this to 1 to start the timer.

BIT6 - T08BIT: =1 for 8 bit mode and =0 for 16 bit mode.

BIT5 - T0CS: Timer0 clock source. =1 for T0CLK pin input i.e. counter mode. Set to 0 for internal instruction clock.

BIT4 - T0SE: Used in counter mode only. Please see datasheet for details.

BIT3 - PSA: Prescaler Assignment. Set this to 0 to assign prescaler or 1 to by pass it.

Page 12: Introduction to PIC Interrupts and Their Handling in C

BIT2 to BIT0 - PS2 to PS0: Prescaler Division factor select

PS2 PS1 PS0  

0 0 0 Divide by 2

0 0 1 Divide by 4

0 1 0 Divide by 8

0 1 1 Divide by 16

1 0 0 Divide by 32

1 0 1 Divide by 64

1 1 0 Divide by 128

1 1 1 Divide by 256

So as per our requirement we have set the bits of T0CON register on program startup. This configures the TIMER0 as we require. Lets have a look at the code that initializes the TIMER0

//Setup Timer0T0PS0=1; //Prescaler is divide by 256T0PS1=1;T0PS2=1;PSA=0; //Timer Clock Source is from PrescalerT0CS=0; //Prescaler gets clock from FCPU (5MHz)T08BIT=1; //8 BIT MODETMR0IE=1; //Enable TIMER0 InterruptPEIE=1; //Enable Peripheral InterruptGIE=1; //Enable INTs globallyTMR0ON=1; //Now start the timer!//Set RB1 as output because we have LED on itTRISB&=0B11111101;while(1); //Sit Idle Timer will do every thing!

As you can see in the above code, first we set up the bits of T0CON then we enable Timer Overflow interrupt, after that peripheral interrupt and finally enable interrupt globally. PEIE i.e. Peripheral Interrupt bit can enable or disable all peripheral interrupt. GIE or Global Interrupt bit is the master bit that can disable all interrupts.

Then when set PB1 i/o pins as output so that it can control a LED. The LED is connected to MCU by using series resistor to GND. Finally we enter an infinite loop that does nothing. As our timer is set up and running each times it overflows we increment counter by one. When counter becomes 76 we toggle the RB1 pin and reset the counter variable.

In HI-TECH C you can create an ISR (that is Interrupt service routine) by using the keyword interrupt. The ISR function can have any valid C function name. Its argument should be void and the return type should also be void. In our example we have named it "ISR".

Page 13: Introduction to PIC Interrupts and Their Handling in C

void interrupt ISR()

Whenever TIMER0 overflow the CPU stops it current operation and jumps to the ISR. This is called interrupt(or exception) condition. As soon as it enters the ISR we check if it is the TIMER0 overflow interrupt by checking the TMR0IF (Timer0 interrupt flag). We also check if the interrupt is enabled (by checking TMR0IE i.e. Timer0 interrupt enable bit). If both the conditions are met we execute the TIMER0 Overflow ISR Code.

Schematic for Testing TIMER0 of PIC18F4520

Schematic For Testing TIMER0 of PIC18

The circuit is described in this article.

Running Demo On 40 PIN PIC Development Board

The PIC development board from eXtreme Electronics has all core circuit required in most PIC projects. So we can use it to easily test the above demo program. All you need to do is to short jumper J5, this will connect the LED to RB1 that's it!

PIC18 Sample Code Downloads timer0.c the above sample code file.

Using Analog to Digital Converter (ADC) – PIC Microcontroller Tutorial

Page 14: Introduction to PIC Interrupts and Their Handling in C

Many electrical signals around us are Analog in nature. That means a quantity varies directly with some other quantity. The first quantity is mostly voltage while that second quantity can be anything like temperature, pressure, light, force or acceleration. For example in LM35 temperature sensor the output voltage varies according to the temperature, so if we could measure voltage, we can measure temperature.

But most of our computer (or Microcontrollers) are digital in nature. They can only differentiate between HIGH or LOW level on input pins. For example if input is more than 2.5v it will be read as 1 and if it is below 2.5 then it will be read as 0 (in case of 5v systems). So we cannot measure voltage directly from MCUs. To solve this problem most modern MCUs have an ADC unit. ADC stands for analog to digital converter. It will convert a voltage to a number so that it can be processed by a digital system like MCU.

This enables us to easily interface all sort of analog devices with MCUs. Some really helpful examples of analog devices are

1. Light Sensors.2. Temperature Sensors .3. Accelerometers. 4. Touch Screens .5. Microphone for Audio Recording.

And possibly many more.

In this tutorial we will learn to use the internal ADC of PIC18 devices (Example is for PIC18F4520 which is a 40 PIN device).

Specifications of ADCs

Most important specification of ADCs is the resolution. This specifies how accurately the ADC measures the analog input signals. Common ADCs are 8 bit, 10 bit and 12 bit. For example if the reference voltage(explained latter) of ADC is 0 to 5v then a 8 bit ADC will break it in 256 divisions so it can measure it accurately up to 5/256 v= 19mV approx. While the 10 bit ADC will break the range in 5/1024 = 4.8mV approx. So you can see that the 8 bit ADC can't tell the difference between 1mV and 18mV. The ADC in PIC18 are 10 bit.

Other specification include (but not limited to) the sampling rate, that means how fast the ADC can take readings. Microchip claims that pic18f4520's ADC can go as high as 100K samples per second.

ADC Terminology

Reference Voltage: The reference voltage specifies the minimum and maximum voltage range of analog input. In PIC 18 there are two reference voltage, one is the Vref-

Page 15: Introduction to PIC Interrupts and Their Handling in C

and one is Vref+. The Vref- specifies the minimum input voltage of analog input while the Vref+ specifies the maximum. For example if the input signal Vref- is applied to analog input channel then the result of conversion will be 0 and if voltage equal to Vref+ is applied to the input channel the result will be 1023 (max value for 10bit ADC).

Fig.: ADC Reference Voltage.

The Vref+ and Vref- pins are available in PIN5 and PIN4 of the PIC18F4520 chip. So you can connect the reference voltage here. For a simple design the Vref- is GND and Vref+ is Vcc. As this is such a common configuration that the ADC can be set up to use these reference internally. Therefore you do not need to connect these on the external Vref pins, so you can use them for other purpose.

ADC Channels: The ADC module is connected to several channels via a multiplexer. The multiplexer can connect the input of the ADC to any of the available channels. This allows you to connect many analog signals to the MCU (say 3 temperature sensors). In PIC18F4520 there are 13 analog input channels, they are named AN0, AN1 etc. You can have a look at the pin configuration in the pic18f4520's datasheet to locate their position.

Acquisition Time: When an specific channel is selected the voltage from that input channel is stored in an internal holding capacitor. It takes some time for the capacitor to get fully charged and become equal to the applied voltage. This time is called acquisition time. The PIC18F4520's ADC provides a programmable acquisition time, so you can setup the acquisition time. Once acquisition time is over the input channel is disconnected from the source and the conversions begin. The acquisition times depends on several factors like the source impedance, Vdd of the system and temperature. You can refer to the page 227 and 228 in the datasheet for details on its calculation. A safe value is 2.45uS, so acquisition time must be set to any value more than this.

ADC Clock: ADC requires a clock source to do its conversion, this is called ADC Clock. The time period of the ADC Clock is called TAD. It is also the time required to generate 1 bit of conversion. The ADC requires 11 TAD to do a 10 bit conversion. It can

Page 16: Introduction to PIC Interrupts and Their Handling in C

be derived from the CPU clock (called TOSC) by dividing it by a suitable division factor. There are Seven possible option.

2 x TOSC

4 x TOSC

8 x TOSC

16 x TOSC

32 x TOSC

64 x TOSC

Internal RC

For Correct A/D Conversion, the A/D conversion clock (TAD) must be as short as possible but greater than the minimum TAD . See table 26-25 in PIC18F4520 datasheet (or table 28-29 in PIC18F4550/PIC18F2550 datasheet). It is 0.7uS for PIC18FXXXX device and 1.4uS for PIC18LFXXXX device.

We are running at 20MHz in our PIC Development board so we set prescaler of 32 TOSC.

Our FOSC = 20MHzTherefore our FOSC = 1/20MHz = 50nS

32 TOSC = 32 x 50 nS = 1600nS = 1.6uS

1.6 uS is more than the minimum requirement.

You can calculate the value for division factor using the above example in case you are using crystal of other frequency. Also now we have the TAD we can calculate the division factor for acquisition time. Acquisition time can be specified in terms of TAD. It can be set to one of the following values.

20 x TAD

16 x TAD

12 x TAD

8 x TAD

6 x TAD

4 x TAD

2 x TAD

0 x TAD

As we saw in above paragraph that the safe acquisition time is 2.45uS, so we select 2 x TAD as acquisition time.

Page 17: Introduction to PIC Interrupts and Their Handling in C

TACQ=2 x TAD

=2 x 1.6uS (Replacing TAD= 1.6uS) =3.2uS

3.2uS is more than required 2.45uS so its ok.

Programming ADC in HI-TECH C for MPLAB

ADC is connect to the PIC CPU by 3 control register and 2 data register. The control registers are used to setup and give commands to the ADC. They also provides the status of ADC. The two data registers holds the 10 bit of converted data. Since each resister in PIC18 is of 8 bits therefore 2 registers are required to hold the 10bit data.

We will develop two functions to support ADC in our projects. One will help initialize the module and other will help us select any of the 13 channels and start the conversion. After the conversion is done it will return us the results.

I am not giving here the description of the control and data registers as they are very clearly explained in PIC18F4520's datasheet on page 223 to 225. I request you to download the datasheet and read the description so that you will have an Idea of what every bit in the registers do. As I told before, ADC is connected to the CPU via three control register and two data registers. The three control registers are :-

ADCON0 - Used to select analog input channel,start the conversion, check if the conversion is done and to switch on/off the module.(We use this in ADCRead() function.)

ADCON1 - Used to Select Voltage reference, and to configure ports as Analog of digital. (We leave these to defaults)

ADCON2 - Used to select ADC data format, Set acquisition time, ADC clock setup (We setup these in ADCInit() function)

First we configure the ADC to our needs in the ADCInit() function.

//Function to Initialise the ADC Modulevoid ADCInit(){ //We use default value for +/- Vref

//VCFG0=0,VCFG1=0 //That means +Vref = Vdd (5v) and -Vref=GEN

//Port Configuration //We also use default value here too //All ANx channels are Analog

/* ADCON2

*ADC Result Right Justified.

Page 18: Introduction to PIC Interrupts and Their Handling in C

*Acquisition Time = 2TAD *Conversion Clock = 32 Tosc */

ADCON2=0b10001010;}

You can see that we only set up the ADCON2 register.We setup the ADC as follows

ADC Result format as Right Justified(Explained latter). Acquisition time = 2TAD(As Calculated Above) Conversion Clock as 32 TOSC(As Calculated Above)

We also leave ADCON1 to defaults, which implies the following

+VREF is 5v (Our Vcc) -VREF is GND All ANx channels are Analog. If you need some of them to do digital I/O then

setup them accordingly.

Now we have our ADC Module setup, when ever you want to do the ADC Conversion in any channel, simply call ADCRead(). For example to do ADC Conversion on channel 0 and store the result in variable val call the function in the following way.

val=ADCRead(0);

That's it ! the analog value present on AN0 will be converted to a digital value and stored in variable val.

How the ADCRead() function works?

//Function to Read given ADC channel (0-13)unsigned int ADCRead(unsigned char ch){ if(ch>13) return 0; //Invalid Channel

ADCON0=0x00;

ADCON0=(ch<<2); //Select ADC Channel

ADON=1; //switch on the adc module

GODONE=1; //Start conversion

while(GODONE); //wait for the conversion to finish

ADON=0; //switch off adc

return ADRES;}

Page 19: Introduction to PIC Interrupts and Their Handling in C

The first line checks if the input channel provided by the user is valid or not. Then we select ADC channel. After that we switch on the module by setting ADON bit. Then conversion is started by setting the GODONE bit. As soon as the GODONE bit is set to 1 the module starts the conversion process. As long as the module is busy the GODONE bits is HIGH, and when the conversion is complete it is cleared by the module. So we wait in the while loop as long as GODONE is high. Remember that the while loop is empty (a semi colon just after it), so as long as GODONE is high the CPU will do nothing. As soon as GODONE is cleared the while loop breaks and we switch of the module by writing 0 to the ADON bit. Finally the result of conversion is returned, ADRES register holds the converted value.

Demo program to test PIC ADC Code

We will write a very simple program that will demonstrate ADC usage. The program will read ADC channel 0 (AN0 PIN) and display its value on LCD Screen. Before attempting the experiment please read the following tutorials. As you will need the LCD Support in addition to the ADC Interface code.

LCD Interfacing with PIC MCU Making the LCD Expansion board

The program is intended to be compiled using the HI-TECH C for PIC18 using the MPLAB IDE. So if you are not familiar with the build steps please see the following tutorials.

Downloading, Configuring and Using Basic Development Tools for Microchip PIC Series of MCUs.

/********************************************************************

ANALOG TO DIGITAL CONVERTOR INTERFACING TEST PROGRAM

---------------------------------------------------------Simple Program to connect with the internal ADC of PIC MCUs.The program reads and display the analog input value at AN0.Requires the PIC18 lcd library.

MCU: PIC18FXXXX Series from Microchip.Compiler: HI-TECH C Compiler for PIC18 MCUs (http://www.htsoft.com/)

Copyrights 2008-2010 Avinash GuptaeXtreme Electronics, India

For More Info visithttp://www.eXtremeElectronics.co.in

Mail: [email protected]

********************************************************************/#include <htc.h>

Page 20: Introduction to PIC Interrupts and Their Handling in C

#include "lcd.h"

//Chip Settings__CONFIG(1,0x0200);__CONFIG(2,0X1E1F);__CONFIG(3,0X8100);__CONFIG(4,0X00C1);__CONFIG(5,0XC00F);

//Simple Delay Routinevoid Wait(unsigned int delay){ for(;delay;delay--) __delay_us(100);}

//Function to Initialise the ADC Modulevoid ADCInit(){ //We use default value for +/- Vref

//VCFG0=0,VCFG1=0 //That means +Vref = Vdd (5v) and -Vref=GEN

//Port Configuration //We also use default value here too //All ANx channels are Analog

/* ADCON2

*ADC Result Right Justified. *Acquisition Time = 2TAD *Conversion Clock = 32 Tosc */

ADCON2=0b10001010;}

//Function to Read given ADC channel (0-13)unsigned int ADCRead(unsigned char ch){ if(ch>13) return 0; //Invalid Channel

ADCON0=0x00;

ADCON0=(ch<<2); //Select ADC Channel

ADON=1; //switch on the adc module

GODONE=1;//Start conversion

while(GODONE); //wait for the conversion to finish

ADON=0; //switch off adc

Page 21: Introduction to PIC Interrupts and Their Handling in C

return ADRES;}void main(){ //Let the LCD Module start up Wait(100);

//Initialize the LCD Module LCDInit(LS_BLINK);

//Initialize the ADC Module

ADCInit();

//Clear the Module LCDClear();

//Write a string at current cursor pos LCDWriteString("ADC Test");

while(1) { unsigned int val; //ADC Value

val=ADCRead(0); //Read Channel 0 LCDWriteIntXY(0,1,val,4);

Wait(1000); }

}

Basic PIC Hardware to test the ADC Code.

The following image shows the basic hardware required to run the above code. Note that the crystal frequency is 20MHz, so please use this value only, if you want quick and error free operation. Or if you are experienced enough you can sort out errors if any.

Page 22: Introduction to PIC Interrupts and Their Handling in C

Fig.: Schematic for PIC ADC Test. (Click To Enlarge/Print)

If you are using our 40 PIN PIC Development Board then most of the hardware is already done for you. You just need to make and attach the LCD Expansion Board to the main Dev Board. RV2, which is a 10K variable resistor is used to feed variable voltage between 0 and 5v to the analog input PIN. When the demo is running you can adjust RV2 can note the change is ADC read out on the LCD Module.

Interfacing LM35 Temperature Sensor with PIC Microcontroller.

The are many cool sensors available now a days, ranging from IR distance sensor modules, accelerometers, humidity sensors, temperature sensors and many many more(gas sensors, alcohol sensor, motion sensors, touch screens). Many of these are analog in nature. That means they give a voltage output that varies directly (and linearly) with the sensed quantity. For example in LM35 temperature sensor, the output voltage is 10mV per degree centigrade. That means if output is 300mV then the temperature is 30 degrees. In this tutorial we will learn how to interface LM35 temperature sensor with PIC18F4520 microcontroller and display its output on the LCD module.

First I recommend you to go and read the following tutorial as they are the base of this small project.

Interfacing LCD Module with PIC Microcontrollers. Making the LCD Expansion Board for PIC18F4520. Using the ADC of PIC Microcontrollers.

Page 23: Introduction to PIC Interrupts and Their Handling in C

After reading the ADC tutorial given above you will note the the PIC MCU's ADC gives us the value between 0-1023 for input voltage of 0 to 5v provided it is configured exactly as in the above tutorial. So if the reading is 0 then input is 0v, if reading is 1023 then input is 5v. So in general form if the adc read out is val then voltage is.

unsigned int val;val=ADCRead(0); //Read Channel 0voltage= ((val)/1023.0)*5;

The above formula give voltage in Volts, to get Voltage in mili Volts (mV) we must multiply it with 1000, so

voltage=((val)/1023.0)*5*1000); //Voltage is in mV

since 10mV = 1 degree, to get temperature we must divide it by 10, so

t=((val)/1023.0)*5*100); //t is in degree centigrade

simplifying further we get

t=((val/1023.0)*500);t=(val*0.48876);

we round off this value, so

t=round(val*0.48876);

remember round() is a standard c library function

Hardware for LM35 based thermometer.

You will need a PIC18F4520 chip running at 20MHz attached with a standard 16x2 LCD Module and LM35 on AN0 pin. LM35 is a 3 pin device as show below.

Page 24: Introduction to PIC Interrupts and Their Handling in C

Fig.: LM35 Temperature Sensor Pinout

connect the +Vs Pin to 5v and GND to GND. The output must be connected to the analog input pin 0 of the PIC18F4520 MCU. It is labeled AN0 in the datasheet. It is pin number 2 on the 40 pin package. It is also called RA0 because it is shared with PORTA0.

We will use our 40 PIN PIC Development board to realize the project. The base board has all the basic circuit to run the PIC. The extra part required for this project like LCD and the LM35 temperature sensor are installed in the expansion board.

C Source Code For PIC Thermometer Project.

/********************************************************************

LM35 Temperature Sensor INTERFACING TEST PROGRAM

---------------------------------------------------------Simple Program to connect with LM temperature sensor using theinternal ADC of PIC MCU.

The program displays the current environment temperature onLCD Module.

MCU: PIC18FXXXX Series from Microchip.Compiler: HI-TECH C Compiler for PIC18 MCUs (http://www.htsoft.com/)

Copyrights 2008-2010 Avinash GuptaeXtreme Electronics, India

For More Info visithttp://www.eXtremeElectronics.co.in

Page 25: Introduction to PIC Interrupts and Their Handling in C

Mail: [email protected]

********************************************************************/#include <htc.h>

#include <math.h>

#include "lcd.h"

//Chip Settings__CONFIG(1,0x0200);__CONFIG(2,0X1E1F);__CONFIG(3,0X8100);__CONFIG(4,0X00C1);__CONFIG(5,0XC00F);

//Simple Delay Routinevoid Wait(unsigned int delay){ for(;delay;delay--) __delay_us(100);}

//Function to Initialise the ADC Modulevoid ADCInit(){ //We use default value for +/- Vref

//VCFG0=0,VCFG1=0 //That means +Vref = Vdd (5v) and -Vref=GEN

//Port Configuration //We also use default value here too //All ANx channels are Analog

/* ADCON2

*ADC Result Right Justified. *Acquisition Time = 2TAD *Conversion Clock = 32 Tosc */

ADCON2=0b10001010;}

//Function to Read given ADC channel (0-13)unsigned int ADCRead(unsigned char ch){ if(ch>13) return 0; //Invalid Channel

ADCON0=0x00;

ADCON0=(ch<<2); //Select ADC Channel

ADON=1; //switch on the adc module

Page 26: Introduction to PIC Interrupts and Their Handling in C

GODONE=1;//Start conversion

while(GODONE); //wait for the conversion to finish

ADON=0; //switch off adc

return ADRES;}void main(){ //Let the LCD Module start up Wait(100);

//Initialize the LCD Module LCDInit(LS_BLINK);

//Initialize the ADC Module

ADCInit();

//Clear the Module LCDClear();

//Write a string at current cursor pos LCDWriteString("LM35 Test"); LCDWriteStringXY(4,1,"Degree Celcius");

while(1) { unsigned int val; //ADC Value

unsigned int t; //Temperature

val=ADCRead(0); //Read Channel 0

t=round(val*0.48876);//Convert to Degree Celcius

LCDWriteIntXY(0,1,t,3);//Prit IT!

Wait(1000); }

}

To compile the above code, lcd.c file must be added to the poject. While the lcd.h, myutils.h must be present in the same project folder. More instruction is available in following articles.

Page 27: Introduction to PIC Interrupts and Their Handling in C

PIC18F4520 based Thermometer using LM35 Schematic

PIC18F4520 based Thermometer using LM35 Schematic

General Notes For proper working use the components of exact values as shown above. Wherever possible use new components. Solder everything in a clean way. Major problems arises due to improper

soldering,solder jumps and loose joints. Use the exact value crystal shown in schematic. Only burning the HEX file to the MCU is NOT enough. PIC18 devices are fairly

complex MCU and can be configured in various ways. Chip is configured using the CONFIG Bytes. Although all hex file given in our site comes with embedded CONFIG bytes. But the user must ensure they are programmed to the chip. Any good programmer has the capability to read the configuration information from the hex file and transfer it to the MCU. Programs will not run without proper configuration byte programming. One major job of configuration is to setup proper oscillator and PLL modes without which the MCU won't execute a single instruction.

To compile the above code you need the HI-TECH C and MPLAB IDE. They must be properly set up and a project with correct settings must be created in order to compile the code. So I request you to read the following articles to become familiar with the built steps.

o Setting up HI-TECH C and MPLAB IDE o Creating First C project in MPLAB

Page 28: Introduction to PIC Interrupts and Their Handling in C

To understand the code you must have good knowledge of core C language. Please don't be confused with the basic concept of the language.

You must be familier with project concept and multi source file concept that used used in most professional languages like C.

You need Proteus VSM if you want to develop or debug the project without any hardware setup.

Interfacing LCD Modules with PIC Microcontrollers.

A large number of embedded project require some type of user interface. This includes displaying numerical, textual and graphical data to user. For very simple numerical display we can use 7 segment displays. If the requirement is little more than that, like displaying some alphanumeric text, we can use LCD Modules. They are cheap enough to be used in low cost projects. They come in various sizes for different requirement. A very popular one is 16x2 model. It can display 2 lines of 16 characters. Other models are 16x4,20x4, 8x1,8x2 etc.

In this tutorial we will learn how we can use such modules with Microchip PIC Microcontrollers. Here I will present my LCD library which you can use to create LCD based application/projects quickly. For demo I will use PIC18F4520 Microcontroller but you can use any PIC18 MCU. But you have to calculate the CONFIG values for correct setting and CPU clock selection etc. That means the chip should be configured correctly. See datasheet for more info on CONFIG bytes.

MPLAB Project Creation

First create a MPLAB project as described in this tutorial. Name the project LCD. Also add a main file called "lcd_test.c". To use my LCD library you need to add it to your project. Just copy/paste the following files to your project folder.

Header Files

lcd.h myutils.h

Source File

lcd.c

How to add files to MPLAB Project is described here.

Now you are ready to the library functions to interact with the LCD module.

Sample Program (lcd_test.c)

/********************************************************************

Page 29: Introduction to PIC Interrupts and Their Handling in C

16X2 ALPHANEUMERIC LCD INTERFACING LIBRARY TEST PROGRAM

---------------------------------------------------------

A testing program for our LCD library.

Easy to use library for interfacing 16x2 lcd in 4 bit mode.MCU: PIC18FXXXX Series from Microchip.Compiler: HI-TECH C Compiler for PIC18 MCUs (http://www.htsoft.com/)

Copyrights 2008-2009 Avinash GuptaeXtreme Electronics, India

For More Info visithttp://www.eXtremeElectronics.co.in

Mail: [email protected]

********************************************************************/#include <htc.h>

#include "lcd.h"

//Chip Settings__CONFIG(1,0x0200);__CONFIG(2,0X1E1F);__CONFIG(3,0X8100);__CONFIG(4,0X00C1);__CONFIG(5,0XC00F);

//Simple Delay Routinevoid Wait(unsigned int delay){ for(;delay;delay--) __delay_us(100);}

void main(){ //Let the Module start up

Wait(100);

//Initialize the LCD Module LCDInit(LS_BLINK);

//Clear the Module LCDClear();

//Write a string at current cursor pos LCDWriteString("Good Is Great !!");

Wait(20000);

//Now Clear the display

Page 30: Introduction to PIC Interrupts and Their Handling in C

LCDClear();

LCDWriteString("God Bless all !!");

//Goto POS (X=0,Y=1 i.e. Line 2) //And Write a string LCDWriteStringXY(0,1,"<**************>");

Wait(20000);

//Write Some Numbers

for(char i=0;i<100;i++) { LCDClear(); LCDWriteInt(i,3); Wait(3000); }

LCDClear(); LCDWriteString(" The End ");

//Loop Forever

while(1);

}

The First thing you should do is to Initialize the LCD Module by calling the fuction LCDInit(). This will setup the LCD module. Now you can use the various functions like...

LCDClear() - For Clearing the screen. LCDWriteString(unsigned char *) - For Writing Text Message at Current

cursor position. LCDWriteStringXY(x,y,msg) - For Writing Text Message at position x,y LCDWriteInt() - For printing integer numbers at Current cursor position. LCDWriteIntXY() - For printing integer numbers at position x,y.

For detailed information on these functions please refer to this tutorial. It is for the AVR microcontrollers but the functions are same for PIC mcus also.

Hardware Connections

Connect the LCD Module with PIC Microcontroller as shown below.

Page 31: Introduction to PIC Interrupts and Their Handling in C

Fig.: LCD Module Interface with PIC Microcontroller.

Programming in C – Tips for Embedded Development.

Here I will highlight some features of C language commonly used in 8 bit embedded platforms like 8051, AVR and PICs. While programming microcontrollers in C most of the time we have to deal with registers. Most common tasks are setting and clearing bits in a register and check whether a bit is 0 or 1 in a given register. So here I will give detail on those topics, it will help you if you are new to embedded programming in C and if you get confused when you see some codes.

A Register

A register is simply a collection of some bits (mostly 8 bits in case of 8bit MCUs). Either each different bit in a register has some purpose or the register as a whole holds a value. Registers serves as connection between a CPU and a Peripheral device (like ADC or TIMER). By modifying the register the CPU is actually instructing the PERIPHERAL to do something or it is configuring it in some way. And by reading a register, the CPU can know the state of peripheral or read associated data.

Page 32: Introduction to PIC Interrupts and Their Handling in C

Fig.: CPU writing to Peripheral Register

Fig.: CPU Reading from Peripheral Register

Binary Numbers in C

When you write a=110; in C it means you are setting the value of variable"a" to "one hundred and ten" (in decimal). Many time in embedded programming we are not interested in the value of a variable but the state of each bits in the variable. Like when you want to set the bits of a register (MYREG) to a bit pattern like 10010111 (binary).

Page 33: Introduction to PIC Interrupts and Their Handling in C

Then you cannot write MYREG=10010111. Because compiler will interpret 10010111 as decimal. To specify a binary number in C program you have to prefix it with 0b (zero followed by b). So if you write

MYREG=0b10010111;

it assigns the bit pattern 10010111 to the bits of Register MYREG.

HEX Numbers in C

In same way if you prefix a number by 0x (a zero followed by x) then compiler interpret it like a HEX number. So

MYREG=0x10; (10 in HEX is 16 in decimal)

MYREG=0xFF;(Set all bits to 11111111 or decimal 255)

Setting a BIT in Register

Here our aim is to set (set to logical 1) any given bit (say bit 5) of a given register (say MYREG). The syntax is

MYREG=MYREG | 0b00100000;

The above code will SET bit 5 to 1 leaving all other bits unchanged. What the above code does is that it ORs each Bit of MYREG with each bit of 0b00100000 and store the value back in MYREG. If you know how logical OR works then you will get it.

In short you can write the same code as

MYREG|=0b00100000;

Now lets come to practical usage. In practice each bit has got a name according to its work/function. Say our BIT (the 5th bit) has got name ENABLE, and what it does is clear by its name,when we set it to 1 it enables the peripheral and when cleared (0) it disables it. So the right way to set it is.

MYREG|=(1<<ENABLE);

The << is called left shift operator. It shifts the bits of LHS variable left by the amount on its RHS variable. If you write

b=1<<3;

then, 1 whose binary value is 00000001 is shifted 3 places to left which results in 00001000

Page 34: Introduction to PIC Interrupts and Their Handling in C

So if ENABLE is defined as 5 (as enable is 5th bit) then

MYREG|=(1<<ENABLE);

will result in

MYREG|=(1<<5);

which again result in

MYREG|=(0b00100000);

Now a beginner would ask "What's the Advantage ?". And once you know it you would realize that advantage is immense!

1. Readability of code: MYREG|=(1<<ENABLE); gives a clue that we are enabling the peripheral while MYREG|=0b00100000; does not give any clue what it is doing, we have to go to data sheet and find out which bit actually ENABLEs the peripheral. While ENABLE=5 is already defined in header files by the developer of compiler by carefully studying the datasheets of device.

2. Easier Portability: Suppose you use this code many times in your program (and your program is reasonably large and uses other register also) and you now want the same code to run on some other MCU model. The new MCU is of similar family but has slightly different bit scheme, say ENABLE is bit 2 instead of bit 5. Then you have to find all occurrence of MYREG|=(0b00100000); and change that to MYREG|=(0b00000100); But if you have used the other method then you simply need to inform the compiler (by its setting options) that you are going to use the other MCU and compiler will automatically get the definitions for the new device. And in this definition ENABLE=2 will already be defined by the compiler developer. So it will be lot easier.

Clearing a BIT in Register

For clearing a bit logical AND(symbol &) operator is used in place of logical OR (symbol |). The syntax is as follows

MYREG&=~(1<<ENABLE);

Page 35: Introduction to PIC Interrupts and Their Handling in C

Fig.: How to clear (0) a bit in C language.

This will clear (i.e. set to value 0) a given bit (identified by name ENABLE) in a register called MYREG. This operation will not affect any other bits of register except ENABLE.

Let us see how it works with the help of following diagram.

Page 36: Introduction to PIC Interrupts and Their Handling in C

Fig.: "Clearing a BIT" how it works?

o now you know how you can selectively clear any bit in any given register. If you want to clear more than one bit at a time you can write like this

//This will clear bits ENABLE,FAST_MODE and BUSY, leaving all other bits untouchedMYREG&=(~((1<<ENABLE)|(1<<FAST_MODE)|(1<<BUSY)));

Similarly the syntax for setting(set to 1) multiple bits at a time is as follows

Page 37: Introduction to PIC Interrupts and Their Handling in C

//This will set bits ENABLE,FAST_MODE and BUSY, leaving all other bits untouchedMYREG|=((1<<ENABLE)|(1<<FAST_MODE)|(1<<BUSY));

Testing The Status of a Bit.

Till now we were modifying the registers either setting or clearing bits. Now we will learn how can be know that a specific bit is 0 or 1. To Know if a bit is 0 or 1 we AND it with a AND MASK. Suppose if we want to check bit 5 of a register MYREG then the AND MASK would be 0b00100000. If we AND this value with the current value of MYREG then result will be non-zero only if the 5th bit in MYREG is '1' else the result will be '0'.

The syntax would be like this.

if(MYREG & (1<<ENABLE)){

//ENABLE is '1' in MYREG...

}else{

//ENABLE is '0' in MYREG}

General Purpose Digital IO with PIC Microcontrollers.

GPIO( General Purpose IO) is the most basic method of communication between MCU and external world. These are done with what is called a PORT. Ports are nothing but a set of bits physically connected to PINs of Microcontroller and available outside the chip. As we are working on PIC micros and they are 8 bits so the maximum size of a PORT is 8 bits. Some PORTs have fewer than 8 bits. You can turn each bit in a PORT on and off under program control. The bits which you set as 1 becomes HIGH and the physical PIN of Micro is at Vcc(supply voltage, usually 3.3v or 5v). And the PINs which you clear (=0) becomes low and physical level is 0v(GND).

Page 38: Introduction to PIC Interrupts and Their Handling in C

Fig.: PIC IO Port example, PORTB.

Fig.: PIC IO Port example, Using PORTB, Turning BITs on and off.

You can test the operation of an IO port by using LEDs as shown below.

Page 39: Introduction to PIC Interrupts and Their Handling in C

Fig.: When the bit is set to 0 the LED remains off.

When you write a value 1 to corresponding bit the LED starts glowing.

Fig.: When the bit is set to 1 the LED starts glowing.

PORTs are Named like PORTA,PORTB,PORTC etc. The PIC we are using PIC4550 has the following PORTs

PORTA(8bit wide) PORTB(8bit wide) PORTC(7bit wide) PORTD(8bit wide)

Page 40: Introduction to PIC Interrupts and Their Handling in C

PORTE(4bit wide)

Inputs using PORTs

You have seen how ports can be used to control the outside word. In that we have used the PORTs as Output. They can also be used to get input from outside. In input mode we can apply either logic 0 (GND) or 1 (Vcc = 5v) and we can read the status of PORT and get what input we have on ports. This can be used to interface switches and sensor with MCU. Any value below Vcc/2 is taken as low and any voltage above Vcc/2 is high.

A simple switch interface is shown below.

Fig.: A Simple switch as Input to PIC Micro.

The CPU can read the required port and take decisions accordingly.

Practical Stuff.

Having the knowledge about digital IO Ports on PIC micro we can begin some practical experimentations. So how can we actually access the ports in C? Well the answer follows.

Each PORT in PIC micro has 3 associated registers.

Page 41: Introduction to PIC Interrupts and Their Handling in C

TRIS: This is the data direction register - As I have told you that port can be used as both input and output purpose, the direction control (input or output) is done using this register. Simply make the bit as 1 when you want its as input or 0 for output.

Example:

TRISB=0xFF; //1111-1111 All InputsTRISB=0x00; //0000-0000 All OutputsTRISB=0x0F;//0000-1111 Bit 7,6,5,4, as Output and Bit 3,2,1,0 as Input

Note: On power up all PORTs are Input.

To Remember this note that 1 looks like 'i' therefore Input, 0 looks line 'o' so Output

LAT: (LATCH): This register is used to set output values. Anything you want output on related pins must be put on this.

Example

LATB=0xFF; //All PINs becomes highLATB=0x00; //All pins becomes LowLATB=0x03; //0000-0011 BIT 0 and 1 becomes high.

PORT: This is used to get input from the PORTs. Reading its value gives the actual levels applied on the PINs. It must be noted that PORT is first configured as input using the TRIS register. Suppose you connected a switch as shown above on PORTB-0 then if you read PORTB it will be 0000-0000 if switch is pressed and 0000-0001 if switch is released.