This tutorial does exactly the same thing as Brad's LED flasher tutorial 2 (it makes an LED blink). However, it uses an interrupt routine to do the job.
Purpose:
To show how to implement a software interrupt using a timer. NOTE: In this program I chose Timer 1 which is a two register timer. This allows for longer cycles between interrupts. There are multiple timer modules in the PIC16f648a and each have special purposes for handling different tasks. I suggest you read up on all the timers and their capabilities prior to implementing one into your own program.
What you can expect to learn in this tutorial:
Get a basic understanding of a PIC interrupt and how it can be implemented.
Learn how to setup and use a timer to cause an interrupt.
Learn how to save and restore data in the working and status registers.
What you will need:
The same as in Brad's tutorial 2 (LED Flasher).
The .asm file:
http://www.bradsprojects.com/phpBB2/upl ... ky_482.zip
The Circuit:
Follow the instructions for connecting your LED and resistor exactly as you would in Brad's tutorial 2 (LED Flasher) with one exception – the end of the resistor that connects to PORTB pin 0, will be connected to PORTA pin 1 (pin 18 of the PIC16f648a). Sorry, I started this tutorial and made the pictures before I realized that I could have just used the same port pin as Brad. DUH!
Understanding how an interrupt and the timer work:
If you are doing something in your house and the phone rings, or “interrupts” you, you stop what you are doing to answer the phone, then at the end of the phone conversation you return to what you were doing. An interrupt using a PIC is exactly that.
PIC's have multiple interrupt sources (timers, input pins, comparators, etc.). It doesn't matter what causes the interrupt but more-so how to handle an interrupt once it occurs. That is completely up to the programmer.
The Program Counter (PC - the thing that keeps track of which line of code is next in the program) automatically jumps to address “0x04” when any interrupt occurs. This program uses timer 1 (TMR1) to cause that interrupt. I recommend reading about the TMR1 module starting on page 50 of the PIC16f648a datasheet AFTER completing this tutorial. There is a lot to understand about timers and how they work. One purpose of this tutorial is to cut through much of that so when you read the datasheet you will already have a basic understanding of what is going on.
The Program:
Lines 1-24 in the picture below are really no different than in the original LED flasher except we only need two variables. A temporary status register, and a temporary working register. Anytime an interrupt is used it is a good idea to store the current values in both the status and working registers so when you return from the interrupt, everything is the same as before the interrupt.
Lines 25-61 contain the interrupt routine but I will skip over that and explain the setup routine first.
Lines 62-95 in the picture below show the setup. The TMR1 enable bit (PIE1, 0) must be set in BANK 1. PIE stands for “Peripheral Interrupt Enable” which is a register that contains various interrupt enable bits. On lines 81 & 82 you will notice INTCON which is the interrupt “control” register. This can be found on page 24 of the PIC16f648a datasheet. Bit 7 is the “global” interrupt enable and bit 6 is the “peripheral” interrupt enable. Both of these must be set for TMR1 to cause an interrupt.
Line 83 clears the timer 1 interrupt overflow flag so the timer will be able to cause an interrupt. Any flag that causes an interrupt must be cleared in software (by the programmer), otherwise it will stay set and never trigger an interrupt. It is good practice to clear flags such as this before the program begins. The timer 1 interrupt overflow flag (TMR1IF) is located in the PIR1 (Peripheral Interrupt Register 1) register - “bit 0”. The PIR1 register contains several interrupt flags and is explained on page 26 of the PIC16f648a datasheet.
Lines 88-92 set the appropriate bits in the TMR1 control register (T1CON). This is explained on page 50 in the PIC16f648a datasheet. This is where it can get a little confusing because the timer can be adjusted to count every clock cycle as well as the second, fourth, or eighth cycle. There are also multiple clock sources that can be used to make the timer count. This is beyond the scope of this tutorial so I will suggest that you read through the comments of the program while referencing the datasheet and hopefully I have explained it well enough to understand what is happening in the code.
You will notice I did not do anything with bits 2,6, & 7. That should be self explanatory after looking through the datasheet.
Lines 97-127 in the picture below show the main program and the subroutine that turns on and off the LED. The main program does absolutely nothing! It is an infinite loop and simply waits for the timer to reach 0 where it will trigger the interrupt.
The LED routine simply checks the status of a bit. If it is set, it clears it, if it is clear it sets it (in this case - PORTA, bit 1).
Now then, let's get to the core of this tutorial... THE INTERRUPT!
Lines 25-61... You will notice this program has an additional “org” directive (org h'04'). This tells the PC that this is where we want to jump to when an interrupt occurs (remember the PC jumps to address 0x004 upon any interrupt). I could have simply added three “NOP” instructions following the “goto setup” as follows to achieve the same result:
Code: Select all
org h'0000”
goto setup
nop
nop
nop
“begin interrupt here”
.
.
.
“return from interrupt”
As noted earlier, it is necessary to preserve the data within the working and status registers upon handling an interrupt. The comments withing the program explain this a little, however it is best to read about handling this in the PIC16f648a datasheet on page 111 section 14.6. Lines 35-38 handle the preservation of this data. Line 41 simply calls the LED subroutine to turn on or off the LED. I could have placed this code within the interrupt but I thought it would be useful to leave it in a separate routine and show how you can jump in and out of the interrupt just as you do any other routine. However, make note that it would not be good to use a GOTO instruction that makes the PC jump outside the interrupt or you will never return from the interrupt.
Lines 44-47 reload the TMR1 high and low registers with the values needed to retrigger the interrupt, and line 50 resets the TMR1 interrupt overflow flag (remember this has to be reset by the programmer). Lines 54-57 simply restores the working and status registers original data, and line 59 tells the PC to return to the place it was before the interrupt occurred.
Well that's it... an “over-explanation” of a very simple program! I hope I wasn't too confusing and that it is beneficial to someone who is interested in knowing how an interrupt can be used. Below is a picture and link to a great little program that will help with calculating timer values so you don't need to rack your brain trying to calculate prescaler settings, etc. Just select which timer you want to use, pick a frequency or time you would like to use for the interrupt cycle and BAM, it's done.
(You can download the fullsize image here)
http://www.bradsprojects.com/phpBB2/upl ... or_155.gif
http://pictimer.picbingo.com/
Enjoy, and please feel free to comment or ask questions if I wasn't clear enough!
Stacy
PS> Play around with the values that are loaded in the TMR1 high and low registers and watch how the LED blinks faster / slower. Also, experiment with the picbingo timer calculator to set the frequency of the flash times. The values I have chosen will create a 500ms interrupt cycle (the LED will stay on for 500ms then turn off for 500ms).