PDA

View Full Version : Interrupt 101



Hylan
- 22nd August 2011, 04:09
I'd like to learn about using interrupts and have been reading several of the timer interrupt threads and looks like some fancier stuff as well. However, I'm trying to start with understanding it in PBP listening to a couple inputs then bake in some timing and high or low priority.

But before I get there I'm not understanding the nomenclature in the manual on p108. I'm using a PIC 18F6520. and the manual has:
INTCON = %10010000 'enable RB0 interrupt

I don't quite get this statement. Can external interrupts only be read on the RB# port?
And then the 10010000, is this presetting the values for each RB_ to all zeros except for the 5th and 8th to 1?

Then to further confuse myself the code sample I'm looking at which doesn't use interrupts at all (to the best of my knowledge) has a line in the declarations:
INTCON2.7 = 0
I'm not sure what this one means or if it has something to do with interrupts or not.

I've been able to teach myself quite a bit from the manual but this one has me stumped.

Any help is appreciated.
Thank you,
Hylan

HenrikOlsson
- 22nd August 2011, 06:33
Hi,
External interrupts are available on one or more pins. The 18F6520 seems to have four located on RB0-RB3. Smaller chips may only have one which is "always" on RB0. (Then you have the interrupt on change but lets leave that for now).

INTCON is the interrupt control register (one of them in the 18F6520). Look at the INTCON register in the datasheet, it'll show you what each bit does. In this case the MSB enables all unmasked interrupts and bit 4 enables the INT0 interrupt.

INTCON2.7=0 disables the internal pullup resistors for PortB.

The PBP is only part of the documentation, you must use the datasheet for your particular PIC as well.

Good luck!
/Henrik.

Hylan
- 22nd August 2011, 14:29
Henrik,

I appreciate it. I've been looking at the datasheet and it's starting to make more sense. I'm not a programmer or circuit designer but am having to learn as this falls under the "other duties as deemed necessary" in the job description and the original guy who did it is no longer available.

So I think I now understand the physical input. Let's say I want to see an incoming serial message on pin RC7 (RX1 pin) and interrupt the home routine. I would need to first trigger RB0 to interrupt and goto the interrupt routine to read the serial data? Am I thinking correctly?

Second question. How do I set up software interrupts? Like if a certain value occurs like 3 I/O's are turned on then I want a variable like "AllON = 1" to interrupt the routine and do something.
Thank you,
Hylan

mister_e
- 22nd August 2011, 15:14
There's USART interrupt as well. Check out the USART/EUSART section of the datasheet.

A really easy and efficient way to start right now with interrupts is to use Darrel Taylor Instant Interrupts. Check out this link.
http://www.pbpgroup.com/modules/wfsection/article.php?articleid=19

For your, and any, specific requirement, there's a load of different approach.. say one different per programmer ;)

The basic skelleton:
Main program (Loop)
Interrupts.

Whatever happen in your Interrupts, you may set flags there and process them in your main loop.

OR you may process some dull duties in your main loop and force interrupts to happen in your main loop too.

To read I/Os and evaluate them, you may use something like that (Which assume some push button connected to gnd on PORTB<3:0> (b3, b2, b1, b0)


SomePushButton VAR BYTE
'
'
'
'
SomePushButton = PORTB & $0F ' read PORTB and keep only <3:0> bits (Bitwise AND)
SELECT CASE SomePushButton
CASE %1110 ' PORTB.0
' code for PORTB.0 here
CASE %1101 ' PORTB.1
' code for PORTB.1 here
CASE %1011 ' PORTB.2
' code for PORTB.2 here
CASE %0111 ' PORTB.3
' code for PORTB.3 here
END SELECT

Hylan
- 23rd August 2011, 03:19
Beautifull! I feel like I now have enough to be dangerous or at least dangerous in a productive, 'hmmm that didn't work but I learned something' sort of way.

Thank goodness for reprogrammable pics!

Thank you,
Hylan

mister_e
- 23rd August 2011, 03:23
Thank goodness for reprogrammable pics!
Amen! Couldn't even think to re-use my UV Eraser anyway :)

I still have some UV one though... good on a pinboard or as staple... (again)

if someone talk about software simulator I'll kick his butt

Charles Linquis
- 23rd August 2011, 13:02
And most people don't realize it, but you can have an interrupt on *ANY* pin - sort of. This is handy when you have a switch that simply must be read and it is on port C, for example.
Just run a high-speed interrupt on TMR0 and read whatever pins you want inside the ISR. I typically run a 1mSec interrupt.

A small example of an "interrupt header"





PreloadH VAR BYTE BANKA SYSTEM
PreloadL VAR BYTE BANKA SYSTEM
MasterClock VAR WORD BANKA SYSTEM
ButtonFlag var BYTE BANKA SYSTEM


PreloadH= $D8
PreloadL = $F7 ; 1 mSec@40Mhz

T0CON = %10001000 ; Timer ON, no prescaler


'---------------------------------- --------------------------------

INCLUDE "DT_INTS-18.bas"

' INCLUDE "ReEnterPBP-18.bas" ; Include if using PBP interrupts

ASM
INT_LIST macro ;IntSource, Label, Type, ResetFlag?

INT_Handler TMR0_INT, MainTimer, ASM, yes
; INT_Handler RX1_INT, GetChar, PBP, yes

endm

INT_CREATE

ENDASM

Goto OverInt


'---[INT - interrupt handler]---------------------------------------------------

Asm

MainTimer

movff PreloadH,TMR0H ; Preload depends on clk speed
movff PreloadL,TMR0L
clrf INTCON,2

infsnz MasterClock
incf MasterClock + 1

btfss PORTC,4
bsf ButtonFlag,0

@ INT_RETURN

ENDASM

OverInt:

ButtonFlag = 0
MasterClock = 0
INTCON =%11100000 ; just to be certain!

@ INT_ENABLE TMR0_INT


Your program here


This particular code will increment MasterClock at a 1000Hz rate (1 ms / count). You can read it at any time, although you should either disable INTs when you test it, or only test that it is ABOVE (not equal to) a value, since it is a 16 bit var and can increment in the middle of a PBP read.

ButtonFlag.0 will be set any time after someone has pressed a button bringing PORTC.4 to GND. You can read it anytime, then clear it in your main code.

If you have more complicated things to do on an interrupt, you can write it in PBP.


So THERE! mister_e and pxidr84!

amgen
- 23rd August 2011, 13:30
That's a good setup !
How about switch de-bounce (make sure its a good press)

I use;

if sw not_pressed then out
pause 10 ' or 20 or 50 ms
if sw not_pressed then out
good sw pressed stuff here

don

Charles Linquis
- 23rd August 2011, 14:30
You often don't need a debounce if you read a switch in software. Hardware is so fast that it can see one push as a bunch of pushes, but software is generally a lot slower and you can use that to your advantage. In the example I gave above, the bit gets set as soon as the first contact is made. If the main loop reads the bit at that time, and then does something that takes 50 mSec, you can clear ButtonFlag at the end of that routine (rather than at the top). The switch will certainly have quit bouncing by then, so the bit won't get re-set by the bounce. This saves 50mSec of waiting.
If things really get "hairy", I do the debounce in ASM. I count the loops that the switch has been down (or up) and only generate a flag when that number of loops has been executed.

My programming style uses PAUSE sparingly, if at all. That is the only way you can get real performance out of a PIC and PBP.

mister_e
- 23rd August 2011, 17:27
And most people don't realize it, but you can have an interrupt on *ANY* pin - sort of. ........
So THERE! mister_e and pxidr84!
Sure, I classify that as slow background process ;)

amgen, you just need to read the switch all the time, keep a reading of the previous(s) and compare them. Depending of your timer rate, you may want to make sure it is hold down for X interrupt. set a flag to say a switch is ready, Once done, and the button being read, you wait Y interrupt before reading another and "publish" it.

Tons of way to do so. But for sure, you don't want any PAUSE in an ISR.

amgen
- 23rd August 2011, 18:14
Yes, getting more accustomed to thinking in terms of COUNT rather than time..... although the count is always exactly related to your timing base. Right ? Also brings more into play, Events to do actions (like windows), and more use of GOSUB's.

don

Hylan
- 24th August 2011, 03:20
Okay, I've been looking at Daryl Taylors interrupt programs as recommended by Steve. I downloaded everything and tested the blinky blinky to make sure it worked. I changed the toggle pin to one on my board with an LED and it worked.

Now I'm trying to figure out how to incorporate this into my program and what terms I can change and what I can't and where it needs to be placed in the program. I don't have anything called a "main" loop for example.

So for example with this sample code:


LED1 VAR PORTB.1

INCLUDE "DT_INTS-18.bas" ; Base Interrupt System
INCLUDE "ReEnterPBP-18.bas" ; Include if using PBP interrupts

ASM
INT_LIST macro ; IntSource, Label, Type, ResetFlag?
INT_Handler INT_INT, _ToggleLED1, PBP, yes
endm
INT_CREATE ; Creates the interrupt processor
ENDASM

@ INT_ENABLE INT_INT ; enable external (INT) interrupts

Main:
PAUSE 1
GOTO Main

'---[INT - interrupt handler]---------------------------------------------------
ToggleLED1:
TOGGLE LED1
@ INT_RETURN



I understand that the "include" statements go at the top when declaring stuff but I'm not sure where to put the "ASM" section
and the "INT" Interrupt handler commands

I tried a couple things and the blinky blinky always worked but I never got my part of the program to run so it seemed to only stay in the above portion.

Getting closer, I can smell it, but I can't quite see it or taste it.
Thank you,
Hylan

mackrackit
- 24th August 2011, 04:51
In the example you have posted place your code in the "Main" loop. To start try a PAUSE type blink in the Main loop to seehow ot works.

Hylan
- 25th August 2011, 14:00
Beautiful! I've got the interrupt working properly on the one pin. Now I can start playing with all the other layers and types. I'm sure I will have more questions but at least I've got a starting point.
Thank you!
Hylan

Hylan
- 15th November 2012, 23:51
I'm finally back looking at this again and would like to use the RX2 pin as the interrupt trigger when a serial string comes in on my 18F6520 chip.
I'm currently using a hserin command and just running it in my main loop to pick up new signals and 999/1000 it works fine.
I'm looking through pic manual but it's pretty Greek to me.
Does anyone have an example of how to configure this for the RX2 pin?
Thank you,
Hylan

Hylan
- 16th November 2012, 01:04
I did a search and think I found some examples, sorry for the premature post.

Charles Linquis
- 16th November 2012, 02:16
Here is a snippet of running code





INTCON = %11000000

'---------------------------------------------

INCLUDE "DT_INTS-18.bas"
INCLUDE "ReEnterPBP-18.bas"

ASM
INT_LIST macro

INT_Handler RX2_INT, _GetCharPort2, PBP, yes

endm
INT_CREATE
ENDASM
;----------------------------------------------------------------------------------
Goto OverInt


GetCharPort2:

for I_XDataLen = 0 to 63
HSERIN2 50,TimeOut2,[I_XDataChar]
if I_XDataChar = 13 then goto GetChar2Valid
I_XDataBuf[I_XDataLen] = I_XDataChar
next I_XDataLen
I_XDataLen = 63 ' lost characters, but do the best we can
GetChar2Valid:
Timeout2:
I_XDataBuf[I_XDataLen] = 0
if I_XDataLen > 0 then
XDataSource = 2
XDataFlag = 1
endif
GetChar2_Return:
if PIR3.5 then HSERIN2 [I_XDataChar]
@ INT_RETURN
;--------------------------------------------------------------------

Overint:

PIR3.5 = 0
@ INT_ENABLE RX2_INT

YOUR CODE HERE