Jump to content

Is There A Way To Implement Multiple Interrupt?


Recommended Posts

I wonder if there is a way to do multiple interrupt on PIC16F. Like what I am doing is set two ports as IOC, if the first port get interrupted, light up led 1, and then if the second port get interrupt, light up led 2. But since there is only one function interrupt(), I don't know how can the program go to two different routines and do difference things. Thank you for any answer!!

Link to post
Share on other sites

Hi Baixue,

 

This problem is quite easily solved. The first thing you should do in the interrupt function is to check the various interrupt flags that are relevant for your application. Then, depending on which flags are set, you call appropriate functions. So you could have one function to turn on LED 1 and one function to turn on LED 2.

 

Also the best place to clear the respecive interrupt flags is in the functions that service them. So for example if you have a function to service serial port interrupts, then the last operation before this function returns should be to clear the serial interrupt flag.

 

I hope this helps

Link to post
Share on other sites

IOC will generate only a single interrupt. When you enter the interrupt service routine you should read the IOC port (assuming RBIF is set) into a glabal variable which will automatically reset the interrupt flag (RBIF). Set a flag bit and let the main processing loop deal with the change. interrupt routines should be kept short and sweet.

 

The main processing loop will see the flag set and process the new port input data. The new data is compared with an older sample (history) to see which bits have changed (XOR). Now a change can be high-to-low or low-to-high, so it is up to you which condition you turn on/off your LED. Once you have processed all the changed bits, make the new port inputs value the history value ready for the next change. You may want to disable IOC interrupts (RBIE) while you are processing the new data during the compare just in case another IOC interrupt occurs and changes the data before you are finished with it.

 

If the IOC is generated from a pulse, make sure the pulse is wide enough that it is still present when you read the port during the interrupt service routine. The minimum pulse width will depend on your clock speed and level in the interrupt polling list.

 

I hope this adds to some ideas.

 

Cheers

 

Reynard

 

I said the RBIF is reset automatically. This is not the case with this peripheral and should be done in software after reading the port. Sorry about that.

Edited by Reynard
Link to post
Share on other sites

Thank you so much techie and Reynard!! It works very well right now!!!

To techie: Your way works good for two different kinds of interrupt, like one IOC, one Timer0 interrupt, but it won't work on two IOC, cause all the IOC share the same interrupt flag, you won't be able to tell which port just get interrupted if there is only one interrupt flag used by all the IOC ports. But thank you for this idea!

To Reynard: I did wha you said and it works perfectly now! Thank you so much! Here is my code, just in case the other people needs to look at it.

 

Thank you so much you guys!

#include <system.h>
#pragma DATA 0x2007, _HS_OSC & _WDT_OFF

bit c6,c4,p6,p4;

void main()
{

trisc=0x00; //configure portc as output
portc=0x00;//initialize portc
trisb=0xff; // configure portb as input, we are going to use portb.6&4 as IOC,save .7& 5 as RX/TX

iocb=0x50; //enable portb.6 & 4 IOC

set_bit(intcon,7);//enable all interrupts
set_bit(intcon,6);//enable all peripheral interrupts
clear_bit(intcon,5);//disable the timer0 interrupt
clear_bit(intcon,4);// disable the RA2/INT exteranl interrupt
set_bit(intcon,3);//enable the interrupt(RABIE)


ansel =0x00; // the fllowing two used to turn off analouge modle
anselh =0x00;

while(1)
{
	delay_ms(200);
	portc=0x00;

			}

void interrupt()
{   
  c6=portb.6; //put the current value of portb.6 into bit c6
  c4=portb.4; //put the current value of portb.4 into bit c4

 if(c6^p6) // if the current value is different with previous
 {
		 if(c6==0)// this used to filter out the falling edge
		 portc=0x01;//light on led#1
 }

 else if(c4^p4) // if the current value is different with previous

 {
		 if(c4==0)
		 portc=0x08; ;//light on led#4
  }

 portb=0xff;//write to portb to clear the interrupt
 clear_bit(intcon,0);// clear the interrupt flag(RABIF)	
 p6=portb.6; //put the current value into p6, it will be the previous value for the next round
 p4=portb.4;
}

Link to post
Share on other sites

Hi Baixue,

 

Good to see you are making progress. Here are a few more tips.

 

unsigned char current, history;

void main {
// Use bit names to make code more readable.
// Remember, at reset all intcon bits are = 0 so you don't have to reset them.
set_bit(intcon,GIE);//enable all interrupts
set_bit(intcon,PEIE);//enable all peripheral interrupts
clear_bit(intcon,T0IE);//disable the timer0 interrupt
clear_bit(intcon,INTE);// disable the RA2/INT exteranl interrupt
set_bit(intcon,RBIE);//enable the interrupt(RABIE)

....
history = portb;	// initialise history to current port value.
....
while (1) {
....
}
}

void interrupt {
current = portb;	// read and sync match register in one go.
clear(intcon,RBIF);	// clear change interrput flag.
....
// Process current data and led's.
// Don't work with the real portb data as it may change, use the current snapshot.
....
history = current;
}

 

Cheers

 

Reynard

Link to post
Share on other sites
Hi Baixue,

 

Good to see you are making progress. Here are a few more tips.

 

unsigned char current, history;

void main {
// Use bit names to make code more readable.
// Remember, at reset all intcon bits are = 0 so you don't have to reset them.
set_bit(intcon,GIE);//enable all interrupts
set_bit(intcon,PEIE);//enable all peripheral interrupts
clear_bit(intcon,T0IE);//disable the timer0 interrupt
clear_bit(intcon,INTE);// disable the RA2/INT exteranl interrupt
set_bit(intcon,RBIE);//enable the interrupt(RABIE)

....
history = portb;	// initialise history to current port value.
....
while (1) {
....
}
}

void interrupt {
current = portb;	// read and sync match register in one go.
clear(intcon,RBIF);	// clear change interrput flag.
....
// Process current data and led's.
// Don't work with the real portb data as it may change, use the current snapshot.
....
history = current;
}

 

Cheers

 

Reynard

 

 

Thank you so much!!! that helped a lot!!!!

 

Regards,

Baixue

Link to post
Share on other sites

Join the conversation

You are posting as a guest. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
×
×
  • Create New...