When developing code for a project, using a function pointer can be a useful feature. Within the MPLAB® Code Configurator (MCC) interrupt drivers are setup to use function pointers so the software developer only needs to modify the main.c file and not the interrupt driver code. This allows for easier to follow code development. This project shows a simple interrupt example of how to use a function pointer for a Timer 1 peripheral interrupt.
Step by Step Instructions
Using the MPLAB® Code Configurator (MCC) simplifies the setup for the various registers within the device to create a digital output. To demonstrate how to get started, this project controls an LED from a digital output: an LED connected to one of the output pins of the microcontroller will blink.
The project uses:
- PIC16F1769
- PICDEM™ Lab II Development Board
- Power from a 9 V Power Adapter
- PICkit™ 3 Programmer/Debugger
- MPLAB® X IDE
- MPLAB Code Configurator (MCC) plug-in
- MPLAB XC8 Compiler
PICDEM™ Lab II Connections:
- Connect 5 V and Gnd to the power bus of the protoboard.
- Connect 5 V to the Vdd pin of the PIC16F1769
- Connect Gnd to the Vss pin of the PIC16F1769
- Connect a wire from the RA2 pin (pin 17) to the breadboard Row 23
- Connect a wire from the ground bus to breadboard Row 27
- Connect the LED Anode to breadboard Row 23
- Connect the LED Cathode to breadboard Row 24
- Connect a 330 ohm resistor between Row 24 and Row 27
To follow along with these steps, MPLAB X IDE should be open and the Programmer/Debugger connected to both the computer and the development board. The setup was described in the Setup and Installation section of this training module. You should see a screen similar to the one below to move on to Step 1.
1
Create a new "Stand-Alone" project in MPLAB X IDE for a PIC16F1769. Instructions are below if this is your first project.
2
3
Select the peripherals for your project.
In this first project these peripherals need to be selected:
- System Module
- Interrupt Module
- Pin Module
- TMR1
The System Module, Interrupt Module and the Pin Module will all be automatically included when you launch the MCC. The TMR1 module needs to be added by double clicking on it under Timer in the Device Resources section of MCC. The result should look like the picture below:
4
The System needs to be setup next. Click on the System name in the Project Resources list.
The System section will appear. In this section the oscillator and configuration bit settings are selected.
Oscillator
- Select INTOSC from the drop down menu for the System Clock Select.
- Select the 1MHz_HF selection from the Internal Clock drop down menu.
This will enable the internal 1 MHz internal oscillator as the system clock.
Configuration
Each configuration setting can be changed under the Register tab of the System window. Match the selections shown here.
5
TMR1 needs to be setup. Click on the TMR1 label in the Project Resources menu to make the TMR1 setup screen appear.
The steps below will setup TMR1:
- Check the Enable Timer box
- Check the Enable Synchronization box
- Set the Clock Source to FOSC/4
- Set the Prescaler to 1:2
- Set the Timer Period to 500.00 ms output
- Check the Enable Timer Interrupt box
The window should look like the one below after the setup:
6
Open the Pin Manager and then click on the PORTA pin 2 (RA2) Output blue lock symbol. It should turn green. This adds this RA2 I/O pin to the project. Also make sure the Reset pin has the blue lock shown. If it's green then click on the green lock to make it blue. This will make the Reset internal. It should look like the picture here when completed:
7
Close the Pin Manager and then click on the Pin Module selection in the Project Resources section.
The center screen should show RA2 listed on the I/O chart. Click on the output box to make the pin an output (if not checked) and make sure Analog and WPU are not checked (click on them to uncheck them).
9
Click on the Generate Code button to have the MCC create the software libraries for this project.
10
The project will now have both generated Header Files and Source Files. It should also have a generated main.c file.
Note: MCC may offer to generate a main.c file. Click YES to allow it to complete that task.
Double click on the main.c file to open it up in the editor window.
11
The main.c file needs to be modified to handle the Timer 1 interrupt and there are several additions to the file that are associated to the tmr1.c file that is generated by the MCC.
main.c
The main.c file requires a few lines to be uncommented for the interrupt to work properly. To enable the interrupt to work, Global Interrupts and Peripheral Interrupts need to be enabled.
// Enable the Global Interrupts
INTERRUPT_GlobalInterruptEnable();
// Enable the Peripheral Interrupts
INTERRUPT_PeripheralInterruptEnable();
The main loop doesn't require any additional code beyond the default while(1) loop. The Interrupt Service Routine will handle the changing of the I/O pin.
while (1)
{
// Add your application code
}
The function pointer allows the main.c file to define and contain the Interrupt Service Routine (ISR). To establish this, a function prototype declaration must be placed near the top of the main.c. In this example the function prototype is called TimerISR. Then the actual ISR function is added after the main while() loop. This is where the actions of the ISR are located. In this example a macro from the pin_manager.h file IO_RA2_Toggle() is used to toggle the state of the LED on the RA2 pin at every Timer 1 interrupt.
void myTimerISR(void);
void myTimerISR(void){
IO_RA2_Toggle();
}
tmr1.c
The MCC generated tmr1.c file contains the function pointer to allow this option of controlling the ISR within the main.c file. The TMR1_ISR function handles all the flag clearing and timer reload after an interrupt. Then it calls the TMR1_InterruptHandler(). This TMR1_InterruptHandler() is defined by the function TMR1_SetInterruptHandler(void* InterruptHandler). The function pointer is indicated by the star (*) preceding the InterruptHandler. These described sections of the tmr1.c are shown here.
void TMR1_ISR(void)
{
// Clear the TMR1 interrupt flag
PIR1bits.TMR1IF = 0;
TMR1H = (timer1ReloadVal >> 8);
TMR1L = timer1ReloadVal;
if(TMR1_InterruptHandler)
{
TMR1_InterruptHandler();
}
}
void TMR1_SetInterruptHandler(void* InterruptHandler){
TMR1_InterruptHandler = InterruptHandler;
}
The InterruptHandler function pointer needs to be connected to the myTimerISR() function declared in the main.c file. This is done with a single line in the main.c file right after SYSTEM_Initialize().
TMR1_SetInterruptHandler (myTimerISR); //Define interrupt Handler
Completed main.c
The final main.c code is shown below with all the Timer 1 Interrupt additions to control the LED when a Timer 1 interrupt occurs.
#include "mcc_generated_files/mcc.h"
void myTimerISR(void);
/*
Main application
*/
void main(void)
{
// initialize the device
SYSTEM_Initialize();
TMR1_SetInterruptHandler (myTimerISR); //Define interrupt Handler
// When using interrupts,set the Interrupt Enable bits
// Use the following macros to:
// Enable the Global Interrupts
INTERRUPT_GlobalInterruptEnable();
// Enable the Peripheral Interrupts
INTERRUPT_PeripheralInterruptEnable();
// Disable the Global Interrupts
//INTERRUPT_GlobalInterruptDisable();
// Disable the Peripheral Interrupts
//INTERRUPT_PeripheralInterruptDisable();
while (1)
{
// Add your application code
}
}
void myTimerISR(void){
IO_RA2_Toggle();
}
/**
End of File
*/
13
Make sure your project has the programming tool selected (Part of Step 1 above) and connect power to your development board.
The PICkit 3 has limited power capability so we recommend powering the board separately.
The ICD 3 can power a development board, but for simplicity we recommend powering the board separately.
The Real ICE cannot power the development board so powering the board separately is required.
Click on the Make and Program Device icon. This will build the project again and launch the programmer. In the output window you should see a series of messages and if successful it will end with a Programming and Verify Successful message.
Output Window:
Connecting to MPLAB PICkit 3...
Firmware Suite Version.....01.34.11
Firmware type..............Enhanced Midrange
Target detected
Device ID Revision = 6
The following memory area(s) will be programmed:
program memory: start address = 0x0, end address = 0x7ff
configuration memory
Device Erased...
Programming...
Programming/Verify complete
The RA2 LED will blink based on the Timer 1 interrupt at a 50 millisecond rate for a very accurate blink rate.
If it's the first time the programmer is connected to the board, the programming tool may need to download the proper operating firmware for the exact device. You make see a series of processes if this occurs. This should only happen once.
Downloading Firmware…
Downloading bootloader
Bootloader download complete
Programming download…
Downloading RS…
RS download complete
Programming download…
Downloading AP…
AP download complete
Programming download…
Firmware Suite Version…..01.34.11
Firmware type…………..Enhanced Midrange
14
The project can be closed in MPLAB X. The project is saved automatically when it is built but any changes to files or configuration may ask to be saved before the project is closed. The project can be closed under the File Menu > Close Project.
Download
If you have any problems with your project, the completed MPLAB® X project file can be downloaded from the link below:
File | Download |
Installation
Instructions |
||
---|---|---|---|---|
Windows | Linux | Mac OSX | ||
Project 10 Files
|
| | | |