Академический Документы
Профессиональный Документы
Культура Документы
Objectives
To construct an keypad interface to the PIC microcontroller
To program the PIC24F using a C source code
To use an interrupt on change notification for input interfacing
The following pins are chosen so that the pins RB0-RB5 can still be used for the LCD.
#include "xc.h"
int main(void) {
//configure ports
AD1PCFG = 0xFFFF; //disable A/D's and configure shared ports as digital I/O
_TRISB13 = 0; //set RB13 as output
while(1)
{
_LATB13 = 0;
__delay_ms(250);
_LATB13 = 1;
__delay_ms(250);
}
return 0;
}
Press detection using “Change Notification” Interrupt (Single button)
Before we interface the whole keypad, we start with a single button and check if we can make use of
interrupts. For this part of the exercise, let’s try detecting the press on the button 8 (row3, col2).
Interrupts in the PIC microcontroller are controlled by a global interrupt enable bit. For this
particular exercise, we will be using the Input Change Notification interrupt. The global interrupt
enable bit for this interrupt can be found in the CNIE bit of control register IEC1. Input Change
Notification interrupts are enabled by setting this bit (high).
When using interrupts, the priority level must also be set. If the priority level is left at 0, then the
interrupt is effectively disabled. The interrupt priority levels are contained in the IPCx registers. The
priority level for change notification interrupts can be accessed through IPC4 or directly as CNIP[2:0].
The pins in which we want to monitor input change notification must be specified. This is done
through the CNENx register. To enable interrupt generation when a change in the value of the GPIO
pin occurs, the appropriate bit mask in CNENx should be set high. The CN interrupt enable bits within
CNENx can also be accessed individually as CNxIE. Since we are trying to detect presses from key 8
(row 3, col2) and row3 is mapped to CN29, then we need to enable the change notification interrupt
for CN29 (e.g. CN29IE = 1;).
Whenever an interrupt is generated, the corresponding interrupt flag is set and the execution goes
into the ISR if properly setup. The Input Change Notification interrupt flag is the CNIF bit within an
IFSx register. Until this flag is cleared, all supposed interrupts generated through the CNIF bit are
ignored.
In the provided sample program, only CN29IE is set since we are only using a key press in row3 to
generate an interrupt. If the key 8 is not pressed, then the row3 lines remain high because of the
internal pull-up that is used. When key 8 is pressed, the row 3 is pulled down by the col2 line and the
change from high to low of row3 generates an interrupt.
Follow and try the provided code below to handle interrupts using a single button:
#include "xc.h"
int ROW_3_pressed;
int main(void) {
//configure ports
AD1PCFG = 0xFFFF; //disable A/D's and configure shared ports as digital I/O
//LEDs
_TRISB13 = 0; //set RB13 as output
_TRISB14 = 0; //set RB14 as output
//COL2
_TRISB8 = 0; //set column port as output
_LATB8 = 0; //signal that will pull down the row line when pressed
//ROW3
_TRISA3 = 1; //set row port as input
_CN29PUE = 1; //enable pull up for CNx
//Enable CN Interrupts
_CNIF = 0; //clear CN interrupt flag
_CNIP = 1; //set CN interrupt priority
_CNIE = 1; //enable CN interrupts in general
_CN29IE = 1; //enable specific CNx interrupt
return 0;
}
[CHECK: 20%] Vary the provided code to detect key presses from any of the following buttons: 1, 3,
4, 6, *, and #. The LED 1 should blink the same if any one of the key 8 and the selected key is pressed.
Example, LED 1 should be if 8 or 4 is pressed.
[CHECK: 20%] Modify the ISR such that when a key press is made in COLX, LED_X is toggled. Thus,
pressing ’1’ toggles LED_1, ’2’ toggles LED_2, etc. up to LED_4. Take note that you may not modify the
hardware connections specified i.e. row1 must remain an input pin, while col1, col2, and col3 remain
as output pins.
FULL KEYPAD (60%)
Connect all rows and columns to the microcontroller. Modify the program such that when a key press
is made, the state of all LEDs are switched (and held until the next button press) to the binary
equivalent of the number pressed. For example, pressing button ’1’ sets (LED4,LED3,LED2,LED1) to
(0,0,0,1), pressing button ’5’ sets it to (0,1,0,1), etc. For ’*’, set the output to (1,0,1,0), and for ’#’, set
the output to (1,0,1,1).
__________________________________
Important Notes:
1. Determine which pin caused the interrupt - Multiple pins (identified by the CNENx bit masks)
generate only one interrupt (CNIF bit of IFS1). Thus, it is up to the programmer to determine the
source of the interrupt by individually checking port pins.
2. Perform a software debounce.
3. Set the key press flag - ISR’s often have limited space in program memory. Thus, it is common
practice for ISR’s to simply modify a flag and let the main part of the program decode this flag.
4. Clear the interrupt flag - This allows future interrupt requests generated after executing the ISR to
be recognized again.
Programming Guide:
xc.h
-can be found on "...\Microchip\xc16\vX.XX\support\generic\h"
-this header file selects the appropriate deivce header for the project (e.g. p24FJ64GB002.h)
p24FJ64GB002.h
-can be found on "...\Microchip\xc16\vX.XX\support\PIC24F\h"
-contains variable names for SFRs and their bits or components
-included by the xc16 compiler with the help of "xc.h"
p24FJ64GB002.gld
-can be found on "...\Microchip\xc16\vX.XX\support\PIC24F\h"
-can be used as reference for proper interrupt vectors (ISR_names)
-contains values for replacing SFR names into addresses (e.g. LATA = 0x2C4)
p24FJ64GB002.inc
-can be found on "...\Microchip\xc16\vX.XX\support\PIC24F\inc"
-contains configuration options with description
libpic30.h
-can be found on "...\Microchip\xc16\vX.XX\support\generic\h"
-contains the function definitions for __delay32(), __delay_ms(), and __delay_us()
__delay32() delays for the # of instruction cycles inputted
__delay_ms() and __delay_us() delays for the # of ms/us inputted
however to use them, there is a need to define an FCY variable
e.g. for a 4MHz instruction cycle: #define FCY 4000000UL
C Program Template:
#include "xc.h"
void sample_func(void);
int main(void) {
/* do stuff here */
return 0;
}
void sample_func(void) {
/*do stuff*/
return;
}