Page 1 of 3

Timers and Interrupts

Posted: Sun May 30, 2010 5:56 am
by sdudley
Description:
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.

Image

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.

Image

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).

Image

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”
Image

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.

Image

(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).

Posted: Sun May 30, 2010 8:35 am
by brad
That is a fantastic tutorial! Good job buddy :)

I would even like to upload this tutorial (one day...) to the tutorials section of the site since it is such an indepth tutorial.

Timers and Interupts are both features I have NEVER used!

Posted: Sun May 30, 2010 10:59 am
by sdudley
brad wrote:That is a fantastic tutorial! Good job buddy :)

I would even like to upload this tutorial (one day...) to the tutorials section of the site since it is such an indepth tutorial.

Timers and Interupts are both features I have NEVER used!
Thanks.

Funny how something seems "different" than when I originally posted it. Hmmm... :roll:

Posted: Sun May 30, 2010 10:01 pm
by brad
I don't know what you are talking about. Just because I have the power to do what ever I want in this little world of bradsprojects, doesn't mean that I will go around resizing images and providing links to the original.

Oh wait, I've said too much...

Posted: Mon May 31, 2010 6:33 am
by sdudley
brad wrote:...blah, blah, blah...I have the power to do what ever I want in this little world of bradsprojects... blah, blah, blah...

Oh wait, I've said too much...
AH HA! So you're saying CHUCK did it! :wink:

maybe it was bitfogav?

Posted: Tue Jun 01, 2010 12:39 am
by bitfogav
HA! HA! Brads GOD on this little website :)

And thats a great tutorial matey!! :)

Posted: Tue Jun 01, 2010 1:50 am
by sdudley
bitfogav wrote:...And thats a great tutorial matey!! :)
Thank you kindly mister.

I am hoping to expand it a little and show how to implement PWM. Or possibly how to handle multiple interrupts since any interrupt on the PIC16f648a will jump to the same address (0x0004).

Posted: Tue Jun 01, 2010 2:24 pm
by Chuckt
sdudley wrote:
brad wrote:...blah, blah, blah...I have the power to do what ever I want in this little world of bradsprojects... blah, blah, blah...

Oh wait, I've said too much...
AH HA! So you're saying CHUCK did it! :wink:

maybe it was bitfogav?
Are you talking about the pictures being cut off? It is probably in your best interests to protect your content because Amazon allows the selling of Wikipedia articles and things on the internet that aren't copyrighted are unethical to be copied but some people feel it is fair game:

http://www.neowin.net/news/amazoncom-al ... a-articles

http://scholarlykitchen.sspnet.org/2010 ... ublishing/

http://en.wikipedia.org/w/index.php?tit ... =Main+Page

I feel that people are already trolling the internet and copying other's work.

Posted: Wed Jun 02, 2010 2:59 am
by bitfogav
sdudley wrote:
bitfogav wrote:...And thats a great tutorial matey!! :)
Thank you kindly mister.

I am hoping to expand it a little and show how to implement PWM. Or possibly how to handle multiple interrupts since any interrupt on the PIC16f648a will jump to the same address (0x0004).

I was going to use an interrupt to refresh a 7 seg display on that eeprom project that I have posted on the forum, the thing is though, is that you have to turn interrupts off when you write data to eeprom, according to the datasheet I will only have to change a few lines in my souce code :)

Posted: Wed Jun 02, 2010 3:57 am
by sdudley
bitfogav wrote:I was going to use an interrupt to refresh a 7 seg display on that eeprom project that I have posted on the forum, the thing is though, is that you have to turn interrupts off when you write data to eeprom, according to the datasheet I will only have to change a few lines in my souce code :)
If you are using the PIC16f648a you should simply need to add one line of code before the write and one line after:

Code: Select all

bcf  INTCON, 7   ;Disables all interrupts
.
call code to write to EEPROM
.
bsf  INTCON, 7  ;Re-enable interrupts
That should be all you need to do!

:)

Posted: Wed Jun 02, 2010 4:00 am
by bitfogav
Yeah I think your spot on!! :)

thanks

Posted: Wed Jun 02, 2010 4:10 am
by sdudley
Correction...

I forgot the note on page 24 of the datasheet:
Note: Interrupt flag bits get set when an interrupt
condition occurs regardless of the state of
its corresponding enable bit or the global
enable bit, GIE (INTCON<7>).
So... you will need to add another line after the write so it would look more like this:

Code: Select all

bcf  INTCON, 7   ;Disables all interrupts 
. 
call code to write to EEPROM 
. 
bsf  INTCON, 7  ;Re-enable interrupts 
bcf  PIR1, 0    ;Reset TMR1 overflow flag
If you are using a different timer that last line would be different (i.e. TMR0 interrupt flag would read - bcf INTCON, 2)

Posted: Thu Jun 03, 2010 5:57 am
by brad
Hmm, interesting!

You said that any interrupt will jump to the same address. How then do you distinguish between them?

Posted: Thu Jun 03, 2010 6:02 am
by sdudley
brad wrote:Hmm, interesting!

You said that any interrupt will jump to the same address. How then do you distinguish between them?
The programmer has to handle that by bit testing the interrupt flags.

Some PICs have multiple interrupts vectors...

On the 24-bit core devices (PIC24/dsPIC) there can be up to 118 interrupt vectors at 014h to 0FEh.

Posted: Thu Jun 03, 2010 6:05 am
by brad
But if I am understanding the post correctly (and I don't think that I am) you have multiple interupts and no matter which one of those is flagged, it just jumps to a certain location in program memory - is that right?

I would have thought that if say external interrupt 1 was flagged, then it would jump to a certain part of the program which would be different to it external interrupt 2 was flagged...