|
|
View previous topic :: View next topic |
Author |
Message |
zotymo
Joined: 12 Dec 2011 Posts: 5
|
INT_RB problem 16f1827 |
Posted: Mon Dec 12, 2011 4:30 pm |
|
|
What can I do to make the program leave the interrupt routine, because
once it enters the routine it keeps repeating itself.
My code:
Code: |
#define ALARM_LED PIN_A2 //EXT_LED
#define PIEZO PIN_A1 //BUZZER_OUT
#include <16F1827.h>
#include <e:\_includes\stdlib.h>
#fuses INTRC_IO,PUT,/*NOWDT,NOPROTECT,*/NOLVP,PLL_SW
#FUSES NOWDT //No Watch Dog Timer
#FUSES WDT_SW //No Watch Dog Timer, enabled in Software
#FUSES PROTECT //Code protected from reads
#FUSES CPD //Data EEPROM Code Protected
#use delay(int=1000000)
#use fast_io(B)
int1 battery_alarm_flg=0;
#INT_RB
void rb_isr()
{
int c;
disable_interrupts(INT_RB);
c=input_b();
battery_alarm_flg=1;
clear_interrupt(INT_RB);
}
void main() {
//-------------------------------------------------------------
SET_TRIS_A(0x11); // A7,A6,A5,A3,A2,A1 are outputs 00010001
// A0,A4 are inputs
SET_TRIS_B(0xF3); // B3,B2 are outputs 11110011
// B0,B1,B4,B5,B6,B7 are inputs
//-------------------------------------------------------------
//-------------------------------------------------------------
port_B_pullups(0xF0); //11110000
clear_interrupt(INT_RB);
enable_interrupts(INT_RB);
//-------------------------------------------------------------
enable_interrupts(GLOBAL);
//-----------------------------------
while(1)
{
if(battery_alarm_flg)
{
output_high(ALARM_LED);
output_high(PIEZO);
delay_ms(1000);
output_low(ALARM_LED);
output_low(PIEZO);
delay_ms(1000);
battery_alarm_flg=0;
clear_interrupt(INT_RB);
enable_interrupts(INT_RB);
}
}
} |
Please help me! |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Dec 12, 2011 5:47 pm |
|
|
Always post your compiler version. |
|
|
zotymo
Joined: 12 Dec 2011 Posts: 5
|
|
Posted: Mon Dec 12, 2011 5:49 pm |
|
|
Sorry.
4.124 |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19520
|
|
Posted: Tue Dec 13, 2011 3:20 am |
|
|
At the end of the INT_RB routine, you don't need to clear the interrupt. The compiler does this for you, unless you use the 'NOCLEAR' option on the interrupt.
Two distinct problems though.
First key thing is that you cannot clear the interrupt, if the latch inside the chip does not match what is on the pins port. Hence anywhere you clear the interrupt (at the start after setting the pullups, and at the end of the loop before you re-enable the interrupt), you must read the port first.
Remember that INT_RB triggers on both edges from a signal. I'm guessing your signal is some for of pulse?. If so, then the interrupt will trigger, and call the handler, on the first edge of the signal. Then the interrupt is disabled, and you leave the handler. In the main code you then pause for a couple of seconds while you sound your buzzer, and flash the LED. If at any point in this couple of seconds, there is another change to the port B pins, the interrupt will be set (but no handler called since the interrupt is disabled). After the couple of seconds, you then clear the interrupt - which will immediately set itself again, because you haven't read the port. So when you then enable the interrupt the code will loop a second time.....
Now, you don't say what pin the signal is actually on, or what else is connected to PORTB. You do understand that as you have it programmed _every_ input pin on PORTB _will_ trigger the interrupt. So B0,1,4,5,6 & 7 will all trigger the event if they change in level. If any are floating they will trigger at times. Do you really want the interrupt triggers by six sources?. This is the 'point' of the more complex setting when enabling the interrupt.
For example:
ENABLE_INTERRUPTS(INT_RB4_H2L);
Will set INT_RB to only trigger when pin B4 goes low.
So what pin is the signal on, and which direction will it change when you want to trigger the event?.
Best Wishes |
|
|
zotymo
Joined: 12 Dec 2011 Posts: 5
|
|
Posted: Tue Dec 13, 2011 12:51 pm |
|
|
Thank you for your advice. I change the code, but the problem stay. I check it by debugger. The program run in the main loop until the first interrupt on RB4. After that never go out from the interrupt routine. The LED never flash.
:(
Code: |
#define ALARM_LED PIN_A2 //EXT_LED
#define PIEZO PIN_A1 //BUZZER_OUT
#include <16F1827.h>
#fuses INTRC_IO,PUT,/*NOWDT,NOPROTECT,*/NOLVP,PLL_SW
#FUSES NOWDT //No Watch Dog Timer
#FUSES WDT_SW //No Watch Dog Timer, enabled in Software
#FUSES PROTECT //Code protected from reads
#FUSES CPD //Data EEPROM Code Protected
#use delay(int=1000000)
#use fast_io(B)
int1 battery_alarm_flg=0;
#INT_RB
void rb_isr()
{
int c;
//disable_interrupts(INT_RB);
c=input_b();
battery_alarm_flg=1;
//clear_interrupt(INT_RB);
}
void main() {
//-------------------------------------------------------------
SET_TRIS_A(0x11); // A7,A6,A5,A3,A2,A1 are outputs 00010001
// A0,A4 are inputs
SET_TRIS_B(0xF3); // B3,B2 are outputs 11110011
// B0,B1,B4,B5,B6,B7 are inputs
//-------------------------------------------------------------
//-------------------------------------------------------------
port_B_pullups(0x10); //00010000
//clear_interrupt(INT_RB);
//enable_interrupts(INT_RB);
enable_interrupts(INT_RB4_H2L);
//-------------------------------------------------------------
enable_interrupts(GLOBAL);
//-----------------------------------
while(1)
{
if(battery_alarm_flg)
{
output_high(ALARM_LED);
output_high(PIEZO);
delay_ms(1000);
output_low(ALARM_LED);
output_low(PIEZO);
delay_ms(1000);
battery_alarm_flg=0;
// clear_interrupt(INT_RB);
// enable_interrupts(INT_RB);
}
}
} |
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Dec 13, 2011 1:11 pm |
|
|
Quote: | Once it enters the routine it keeps repeating itself.
|
You have to clear bit 4 in the IOCBF register, at the end of the #int_rb
routine. This clears the condition that is causing repeated interrupts.
Add the lines shown in bold below:
Quote: |
#byte IOCBF = getenv("SFR:IOCBF")
#bit IOCBF4 = IOCBF.4
#define clear_IOCBF4() IOCBF4 = 0
#INT_RB
void rb_isr()
{
battery_alarm_flg=1;
clear_IOCBF4();
} |
|
|
|
zotymo
Joined: 12 Dec 2011 Posts: 5
|
|
Posted: Tue Dec 13, 2011 1:41 pm |
|
|
It works! Thank you. But I have an another problem. I would like to set the configuration bits in code, like #FUSES PROTECT, #FUSES CPD, #FUSES WDT_SW but not works. Only I can do this settings with MPLAB IDE. :(
Compiler version: 4.124 |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Dec 13, 2011 1:55 pm |
|
|
Don't compile with the "Build Configuration" in MPLAB set to "DEBUG".
The PROTECT, WDT, BROWNOUT, and maybe some other fuses are
automatically disabled for Debug mode.
You can set the Build Configuration in the Drop-Down box at the top of
the main MPLAB window. If this box is "grayed out", then do this:
Shut down MPLAB. Install the latest CCS "plug-in" for MPLAB, and
re-start MPLAB. You should now be able to select Release or Debug.
http://www.ccsinfo.com/downloads/setup_mplab_plugin.exe
MPLAB defaults to a build configuration of DEBUG. To change this
behavior so it defaults to RELEASE mode, see the instruction in this post:
http://www.ccsinfo.com/forum/viewtopic.php?t=46818&start=21 |
|
|
zotymo
Joined: 12 Dec 2011 Posts: 5
|
|
Posted: Tue Dec 13, 2011 2:07 pm |
|
|
You solved my problems. Thank you again. |
|
|
doguhanpala
Joined: 05 Oct 2016 Posts: 120
|
|
Posted: Fri Oct 21, 2016 5:38 am |
|
|
Ttelmah wrote: |
Now, you don't say what pin the signal is actually on, or what else is connected to PORTB. You do understand that as you have it programmed _every_ input pin on PORTB _will_ trigger the interrupt. So B0,1,4,5,6 & 7 will all trigger the event if they change in level. If any are floating they will trigger at times. Do you really want the interrupt triggers by six sources?. This is the 'point' of the more complex setting when enabling the interrupt.
For example:
ENABLE_INTERRUPTS(INT_RB4_H2L);
Will set INT_RB to only trigger when pin B4 goes low.
So what pin is the signal on, and which direction will it change when you want to trigger the event?.
Best Wishes |
I have a few questions. I want to increase counter value each time on int_rb interrupt, but i want to do it from just RB4.
As i understand, ENABLE_INTERRUPTS(INT_RB4_H2L) line, does this work for me ? If i want to use just RB5, i change the code as ENABLE_INTERRUPTS(INT_RB5_H2L) ?
If i want to use both pins i have to write ENABLE_INTERRUPTS(INT_RB4_H2L | INT_RB5_H2L)
Are these 2 assumptions correct?
I did some research and found some sources that say the pic can not understand which pin changed.
http://www.just.edu.jo/~amjaradat/_ee445/_doc/interrupt-rb4-7.pdf
also another source says that.
https://www.ccsinfo.com/faq.php?page=int_ext_button (same but without example).
So i could not understand which is correct. Is it possible or not possible? And if possible, how? My compiler doesn't accept the line: ENABLE_INTERRUPTS(INT_RB4_H2L)
I thought it is because of 18f2550 but it accepts int_rb line and works properly. I read the datasheet and it says there is int_rb for 18f2550.
Another possibility is that Ttelmah and sources say the same thing but i misunderstood what Ttelmah said. Can anyone explain please?
Note: I use 18f2550.
Best wishes
Doğuhan |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19520
|
|
Posted: Fri Oct 21, 2016 7:08 am |
|
|
Key is different chips....
The original PIC INT_RB, had no ability to know 'which' pin triggers the interrupt. This is normally only on RB4 to RB7. It also worked on every change (both high to low, and low to high), on all the pins enabled as inputs. This is the INT_RB on the 2550/4550, and probably 90% of PIC's.
Some later chips have an 'improved' INT_RB (and often an INT_RA as well). On these there is a separate mask to say which pins are to be included, and often a mask to specify which edge(s) are used. These chips also have a separate latch register, to say which pin has triggered. These then offer the ability to set these masks with the INT_RB4_H2L type syntax.
On the standard chips. Only INT_RB. No edges or bits.
On the 'improved RB' chips. Settings like INT_RB4, and INT_RB4_H2L.
On these later chips you also have to clear the latch yourself. This is the IOCBF register that PCM_programmer is pointing to. It's left 'uncleared', since it then allows your INT_RB code to check which bit has caused the interrupt. |
|
|
gjs_rsdi
Joined: 06 Feb 2006 Posts: 468 Location: Bali
|
|
Posted: Sat Oct 22, 2016 7:39 pm |
|
|
I am using port B interrupt in two ways:
* Using RB4 as input for the interrupt and RB5,6,7 as outputs so I know the interrupt is from RB4
* Using more than one RB for interrupt, for example RB4 & RB5 and testing the changes of the pins in the isr
For both cases if I want just interrupt H to L (or L to H) ignoring the other case
Best wishes
Joe |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19520
|
|
Posted: Sun Oct 23, 2016 12:41 am |
|
|
If your PIC only has INT_RB, you can't. INT_RB, is an interrupt on change. It'll trigger on _every_ change. (High to low, and low to high). You will just have to add a test in the routine for the edge.
So on a PIC like a 4550, just using INT_RB
Code: |
void INT_RB(void)
{
static int1 old_RB4=1;
static int1 old_RB5=1;
//Assuming lines are pulled up, so idle high.
if (input(PIN_B4)==1)
{
//input is high
if (old_RB4==0)
{
//low to high
old_RB4=1;
//do nothing except record the level
}
}
else
{
//input is low
if (old_RB4==1)
{
//here signal has changed high to low
old_RB4=0;
//your code here for RB4 having dropped
}
}
//Now the same for B5
if (input(PIN_B5)==1)
{
//input is high
if (old_RB5==0)
{
//low to high
old_RB5=1;
//do nothing except record the level
}
}
else
{
//input is low
if (old_RB5==1)
{
//here signal has changed high to low
old_RB5=0;
//your code here for RB5 having dropped
}
}
}
|
This is only a handful of machine instructions. |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|