Download as pdf or txt
Download as pdf or txt
You are on page 1of 6

Push Button Interrupt Usage in PIC 16bit Microcontrollers

A Sequential Input for the User to Adjust Something

Christopher Koliba

Computer Engineering

Michigan State University

3-25-07

Abstract
The user might have a need to interact with the device they are using by pushing a button to
change a mode or flipping a switch. These actions cause a need to “interrupt” the device from its
constant operation, such as running the same process repeatedly. These interrupts are handled
differently depending on the microcontroller. The PIC18F4520 allow for multiple interrupt sources and
contains an interrupt priority feature which allows for levels to be set for each individual occurrence.
This application note will examine how one would develop such a button within their microcontroller
to control a simple task.
Keywords:
Programmable Intelligent Computer (PIC) Pragma Peripheral Register
EUSART Rx (Receive) Tx (Transmit)

Introduction
Adjustable devices surround us every day and take it our user input every second. Most
developed items for users have some sort of button or adjustment that can be made in order to alter
its performance. As a result, the PIC microcontroller has a wide variety of ways of handling different
interrupts that allows for the programmer to fully customize exactly what he/she wants happening
when it occurs. A good understanding by the programmer of how interrupts affect the microcontroller
is important in order to make the user/buyer happy when using your product. This project will
describe interrupts in general and how to implement one on a PIC microcontroller that will change a
user’s setting of which light to turn on.

Objective
The objective is to develop a program that will allow our user to have the ability to adjust
lights on the device. This program will utilize the PIC’s extensive interrupt handling ability to
accomplish the task. To do this we will need to write simple code that will contain the necessary
processes to set the interrupt to a high priority, make the microcontroller stop when it detects an
interrupt, execute the interrupt subroutine, then return back to normal operation.

Interrupts
The purpose of an interrupt is to allow the normal operations of the PIC to be put on hold.
Then execute the subroutine which will then allow for normal operation again as if it had never left it.
The pins used to handle external interrupts are RB0/INT0, RB1/INT1, and RB2/INT2 and they are edge
triggered. The one in use will be the RB0/INT0 pin which is number 33 on the PIC 18F4520
microcontroller. This particular chip has ten registers which are used to control interrupt operation,
some are just multiple of the others.

REGISTERS

The registers to focus on are RCON, IPR1, PIR1, PIE1, and INTCON in order to fully understand
the process the PIC goes through to gracefully adjust for interrupts. However, not all of these registers
are necessary for the implementation of the push button being developed they will still be discussed.
The Reset Control Register (RCON) contains flag bits that are used to determine why the last wake-up
or Reset happened within the PIC. Most importantly it contains the IPEN bit which will be set to high
to enable interrupt priorities.

The Peripheral Interrupt Priority Register (IPR1) is only available if we set that IPEN bit to one.
Even though we will not use this register it still is necessary to get familiar with it because it is used
when the RX and TX pins on the PIC control devices such as a keyboard because it allows for more
data flow then just a one or a zero. The Peripheral Interrupt Request (FLAG) Register (PIR1) is another
register not in use because it also goes along with handling the RX and TX pins on the PIC for more
complex peripherals than a simple push button.
It has certain bits that need to be set in order to use the EUSART function within the microcontroller
that is used by such devices as the keyboard to take it user inputs. The Peripheral Interrupt Enable
Register (PIE1) stores the individual enable bits for the interrupts from the peripherals. This will not
be used in our example but something to note would be when the IPEN bit in the RCON register is set
to low then the PEIE bit in the INTCON register must be set to high in order to even use the PIE
registers within the PIC. If the PEIE bit was set to low then we would disable all low-priority interrupts.

The Interrupt Control Registers (INCON) are the most important ones of all being that
they are the readable and writable registers. It stores the various enable, priority, and flag bits for the
interrupts. Just to note, some of the bits in the INCON rely on the IPEN bit. For this example it is set to
high. The INCON focused on here is the INCON register and only the bits INT0IF and the GIEH bits. The
priority bit will not need to be set being that we are going to work with INT0 or pin 33 on the PIC
which has a default of high.

CODE

Even though this is a simple example we will be developing there are some difficult code to
understand. The use of a function and also the directives called pragma. The code will be split up into
sections and explained thoroughly. Declarations or PORTB need to be stated along with our function
that we will be using before anything else is typed. Here the function is called change_LED and we
have included the header file for PORTB.
#include <portb.h> /* Needed for the RB0/INT0 interrupt to be used */

void change_LED (void); /* Declare the ISR function */

int p_count = 1; /* Declares our initial count of pushes-global variable */

Without these declarations we would not be able to make a interrupt function or have our push
button interrupt by way of PORTB.

The next part of code is the pragma directives and also our actual function that will switch the
LEDs with each button push. First, we must let our complier know the location of the ISR by making
our HIGH_INTERRUPT_VECTOR = to hexadecimal 8, which is stated inside the PIC data sheet, and tell it
to go to our function when a high interrupt occurs.
#pragma code HIGH_INTERRUPT_VECTOR = 0x8
/*Lets the compiler know the location of the ISR */
void high_ISR (void)
{
_asm
goto change_LED /* Tells it to go to our change_voltage */
_endasm
}
#pragma code

/* Lets the compiler know that this function is the ISR */

#pragma interrupt change_LED

This part of the code is the actual function that will control our pushes of the button and
adjust our LEDs to be on or off according to the users choice. Logically going though this code is as
follows. Every time the user pushes the button the p_count will increment.
A check is then performed to not allow the user to stay in the Yellow state, such that if the user has
reached the yellow state then reset the p_count to one and then continue. The for loops are just
simple delays used to help the user with the button pushing because the PIC processes so fast that the
indented one push might register as two or three pushes. Now, the if statements depend on our
p_count variable and turn on/off the appropriate LEDs. In this example, the beginning/default for the
user is a Green LED only on, then the RED LED will be only on, and then the Yellow LED will be only on.
This cycle repeats over and over again because of the check on p_count being greater than or equal to
4 and then resetting it to 1, the default value. The one interrupt statement within our function
involves our INTCON register, previously described, External Interrupt Flag bit. When our button is
pushed this flag bit gets set high by the PORTB of the PIC causing our interrupt routine declared above
to execute. After completing our function we want to clear this bit by setting it low allowing for
another push button action to occur by the user. If this was never set to low then the user could never
interrupt the PIC with its push button or change the state of the LEDs.

void change_LED (void)


{

p_count++;
if (p_count >= 4) /*If we already had Yellow at the start before the
button push reset to Green */
{
p_count = 1; /* Change back to Green to complete the cycle
for(count = 1; count < 1000; count++); /* simply used to add a
buffer between button pushes */
}
if (p_count == 3) /* Button hit 2 times aka Yellow */
{
for(count = 1; count < 1000; count++); /* simply used to add a
buffer between button pushes */
PORTDbits.RD0 = 0;
PORTDbits.RD1 = 0;
PORTDbits.RD2 = 1;
}
else if (p_count == 2) /* Button hit 1 times aka Red */
{
for(count = 1; count < 1000; count++); /*simply used to add a
buffer between button pushes */
PORTDbits.RD0 = 0;
PORTDbits.RD1 = 1;
PORTDbits.RD2 = 0;
}
else if (p_count == 1) /*Button not hit or 3 times aka Green */
{
for(count = 1; count < 1000; count++); /*simply used to add a
buffer between button pushes */
PORTDbits.RD0 = 1;
PORTDbits.RD1 = 0;
PORTDbits.RD2 = 0;
}
INTCONbits.INT0IF = 0; /* clear flag to avoid another interrupt */
}
The final piece of code for our example is the main portion. In this area we need to set up our
PIC to treat the pins that connect the LEDs to outputs so that they may turn on and they must also be
initialized to low so that they are not turned on in the beginning.
More PIC registers must be adjusted in order to perform the interrupts correctly. The first one is the
RCON register, which stated previously, needs to have its IPEN bit set high to enable interrupt priority
levels. If this was set low then we would not be able to have our interrupt run at all being that we set
it to be a high interrupt. The last register we need to play with is the INTCON and its GIEH bit. The bit
needs to be set high to enable all high priority interrupts to run and without this we would also not
see our interrupt run at all. The OpenRB0INT command you see has three arguments the
PORTB_CHANGE_INT_ON, PORTB_PULLUPS_ON, and FALLING_EDGE_INT. The
PORTB_CHANGE_INT_ON is needed to enable our pin 33 on the PIC to accept our action from the push
button and without this our pin 33 would never be active thus, not allowing our button any
interaction with the microcontroller. The PORTB_PULLUPS_ON will make our pin 33 an input so our
push button will work correctly. The FALLING_EDGE_INT corresponds to the type of edge triggering
we want and in this case it is the falling edge. This argument can either be a FALLING_EDGE_INT or a
RISING_EDGE_INT it is entirely the programmer’s decision.
void main (void)
{
TRISD = 0x00; /*Sets Port D to all Outputs */
PORTD = 0; /* Initialize it all to 0 */

RCONbits.IPEN = 1; /* enable interrupt priority levels */


INTCONbits.GIEH = 1; /* enable all high priority interrupts */
OpenRB0INT (PORTB_CHANGE_INT_ON & /* enable the RB0/INT0 interrupt */
PORTB_PULLUPS_ON & /* configure the RB0 pin for input */
FALLING_EDGE_INT); /* trigger interrupt upon button
depression */

/*Other code will follow inside of main that needs to be there */


}

That is all the necessary code for our example project. Any other code that is necessary can
be added after the code within main as stated. Also, any functions or declarations that might be
needed for anything else one might try to implement are possible. The syntax for the code above has
been checked and is completely right and one would just have to copy and paste this into a software
tool to program their PIC and it will work.

Schematic and Layout

Included along with the code is the schematic and layout of this project labeled Figure 1 and
Figure 2.

Conclusion & Recommendations


The example and its code are simple in the fact that the person will take this as a basic
demonstration of how interrupts work. There are many register options that were not covered
because of the simplicity of the example but all can be located on the data sheet. Understanding the
PIC and how it can be manipulated can only come by analyzing the data sheet referenced and trying
out simple changes within the code given. Trial and error would be the best way to learn the
possibilities of the interrupts to have them control multiple input devices. The code actually
implemented into my project involved the user push button to change a set_voltage variable that
allowed our device to output three different voltages and display, by LEDs, which mode it was in.
References
More Coding Examples
http://www.microchipc.com/sourcecode/

PIC Data Sheet:


http://ww1.microchip.com/downloads/en/DeviceDoc/39631a.pdf

Figure 1. The Schematic

Figure 2. The Layout

You might also like