|
|
View previous topic :: View next topic |
Author |
Message |
Salenko
Joined: 08 Sep 2008 Posts: 84
|
confusion between two interruptions ? |
Posted: Mon Sep 08, 2008 5:11 pm |
|
|
hi everybody,
PIC: 16F876
CCS compiler, PCW version 4.057
I wrote a code to manage two external interruptions (RB0 and RB6) using
two push-buttons the project was compiled correctly (0 errors and a
warning for condition always True).
The main program consists on a LED Counter, when an interruption
happen the counting is stopped and a LED start first, I only used the RB0
interruption, the simulation runs well, but when I added the ISR of the
second interruption, the simulation was blocked since the start in the RB6
interruption routine (and even the counting did not start).
--see below the schematic
Could anybody explain me the reason ?
Thanks in advance.
excuse me my english
Code: |
#include "C:\Documents and Settings\test 1.h"
#ZERO_RAM
#use delay(clock=20000000)
#define RB6 PIN_B6
#define RB0 PIN_B0
int i;
#Priority EXT
#int_EXT
void EXT_isr()
{
int i;
for (i=0;i<=4;i++) // blinking led
{
output_high(pin_a3);
delay_ms(20);
output_low(pin_a3);
delay_ms(20);
}
clear_interrupt(int_EXT);
}
#int_RB
void RB_isr()
{
output_high(pin_a5);
delay_ms(200);
output_low(pin_a5);
clear_interrupt(RB6);
}
#use delay(clock=20000000)
void main()
{
port_b_pullups(TRUE);
setup_adc_ports(NO_ANALOGS);
setup_adc(ADC_OFF);
setup_spi(FALSE);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_8);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DISABLED,0,1);
ext_int_edge(0,H_TO_L);
ext_int_edge(4,H_TO_L);
enable_interrupts(INT_EXT);
enable_interrupts(INT_RB);
enable_interrupts(GLOBAL);
set_tris_b(0xff);
set_tris_a(0x00);
set_tris_c(0x00);
while(1)
{
for (i=0;i<=255;i++) //COUNTER
{
output_c(i);
delay_ms(10);
}
}
}
|
Last edited by Salenko on Wed Sep 10, 2008 5:28 am; edited 1 time in total |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Sep 08, 2008 5:21 pm |
|
|
Always read the PIC data sheet when you have a question about
how a feature works. Read the section on Port B interrupts, in
the I/O Ports section of the 16F876 data sheet.
The sections shown in bold tell you how to fix your #int_rb routine:
Quote: | Four of the PORTB pins, RB7:RB4, have an interrupt-on-
change feature. Only pins configured as inputs can
cause this interrupt to occur (i.e., any RB7:RB4 pin
configured as an output is excluded from the interrupt-on-
change comparison). The input pins (of RB7:RB4)
are compared with the old value latched on the last
read of PORTB. The “mismatch” outputs of RB7:RB4
are OR’ed together to generate the RB Port Change
Interrupt with flag bit RBIF (INTCON<0>).
This interrupt can wake the device from SLEEP. The
user, in the Interrupt Service Routine, can clear the
interrupt in the following manner:
a) Any read or write of PORTB. This will end the
mismatch condition.
b) Clear flag bit RBIF.
A mismatch condition will continue to set flag bit RBIF.
Reading PORTB will end the mismatch condition and
allow flag bit RBIF to be cleared. |
Your code has the clear_interrupt() function at the end of
each isr routine. In fact, CCS puts in code to do this automatically.
You don't have to put in code to clear the interrupt flag.
However, you do have to put in code to clear the "mismatch condition"
for INT_RB interrupts. That's an additional requirement for that
particular interrupt.
Quote: | clear_interrupt(RB6); |
Also you are using this function incorrectly. You must read the CCS
manual. Do not just "invent" parameters. The manual says:
Quote: | Syntax: clear_interrupt(level)
Parameters: level - a constant defined in the devices.h file |
Look at the end of the 16F876.H file for a list of parameters for
the clear_interrupt() function. |
|
|
Guest
|
|
Posted: Tue Sep 09, 2008 11:44 am |
|
|
hi,
thank you for answering me,
I took at this section, so if I did understand well, I have only to
read/write the PortB in the RB ISR to end the mismatch condition.
I made corrections in the RB ISR as following
Code: | #int_RB
void RB_isr()
{
byte byte_b ;
for (i=0;i<=4;i++) // blinking Blue led
{
output_high(pin_a5);
delay_ms(20);
output_low(pin_a5);
delay_ms(20);
}
//clear_interrupt(INT_RB); // don't have to put in code to clear the interrupt flag, it's done automatically
byte_b=input_b(); //Any read or write of PORTB. This will end the mismatch condition.
}
|
The only problem in simulation is that since the start the Blue LED is
blinking (which means that the RB interruption routine is running) without
any touch to the push-button !! After some seconds, the routine ends and
the counting starts. From that moment the simulation runs quite good. |
|
|
Salenko
Joined: 08 Sep 2008 Posts: 84
|
|
Posted: Tue Sep 09, 2008 11:46 am |
|
|
the last post is mine,
excuse me for my english . |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Tue Sep 09, 2008 12:14 pm |
|
|
This line disappeared from your int_RB function. Now both your main and interrupt function are changing the same global variable.... this is a bug!
In general, try to avoid the use of global variables, make them local instead. It will help you to avoid these type of errors and the compiler can do better optimization which helps you to save RAM.
Code: | #use delay(clock=20000000) | This line is twice in your program. Remove one line as it only causes confusion.
Code: | for (i=0;i<=255;i++) //COUNTER | This line contains a bug. Not serious in your program but good to be aware of: The loop is never quit because when the 8 bit variable 'i' reaches 255 it is incremented and overflows to zero. This is smaller than 255 and the next test for '<= 255' will succeed again.
Code: | set_tris_b(0xff);
set_tris_a(0x00);
set_tris_c(0x00); | With the CCS default settings these lines have no effect. The CCS compiler will set the TRIS register for you automatically at each I/O operation, so you can remove these lines. If you want highest performance than you can manually set the TRIS registers but for most programs this is not an issue and life is easier when you let the compiler handle the I/O. For more info see the #use fast_io directive in the manual. |
|
|
Salenko
Joined: 08 Sep 2008 Posts: 84
|
|
Posted: Wed Sep 10, 2008 5:17 am |
|
|
hello and thank you ckielstra,
ckielstra wrote: | This line disappeared from your int_RB function. Now both your main and interrupt function are changing the same global variable.... this is a bug!
In general, try to avoid the use of global variables, make them local instead. It will help you to avoid these type of errors and the compiler can do better optimization which helps you to save RAM. |
you're right,
I corrected it !
ckielstra wrote: |
Code: | #use delay(clock=20000000) | This line is twice in your program. Remove one line as it only causes confusion. |
but when I remove one of the #use delay(clock=20000000), I got this warning message
Code: | Interrupts disabled during call to prevent re-entrancy: (@delay_ms1) |
ckielstra wrote: |
Code: | for (i=0;i<=255;i++) //COUNTER | This line contains a bug. Not serious in your program but good to be aware of: The loop is never quit because when the 8 bit variable 'i' reaches 255 it is incremented and overflows to zero. This is smaller than 255 and the next test for '<= 255' will succeed again. |
pertinent remark !
ckielstra wrote: |
Code: | set_tris_b(0xff);
set_tris_a(0x00);
set_tris_c(0x00); | With the CCS default settings these lines have no effect. The CCS compiler will set the TRIS register for you automatically at each I/O operation, so you can remove these lines. If you want highest performance than you can manually set the TRIS registers but for most programs this is not an issue and life is easier when you let the compiler handle the I/O. For more info see the #use fast_io directive in the manual. |
I did not use the Wizard to set my code (I mean I did not set I/O pins in the dedicated columns) so, how will the CCS compiler know them without the set_tris_x() command as all of them (portA,B and C)are set input by default ?
===============
the problem of the third message still exsists ! |
|
|
RLScott
Joined: 10 Jul 2007 Posts: 465
|
|
Posted: Wed Sep 10, 2008 5:44 am |
|
|
Salenko wrote: | ...
but when I remove one of the #use delay(clock=20000000), I got this warning message
Code: | Interrupts disabled during call to prevent re-entrancy: (@delay_ms1) |
|
First of all it is important to understand what that warning means. The library function delay_ms probably uses a temporary variable to hold the loop count as it counts down the time. This same temporary variable is used any time delay_ms is called. You call delay_ms both from your main program and from your interrupt code. Therefore it is possible for your main program to be in the middle of a delay_ms call, and thus using the loop variable in delay_ms, when an interrupt hits. Since the interrupt code also uses delay_ms, it will overwrite the loop variable. So when the interrupt returns to main, the loop variable will be corrupted from where main had it. The compiler recognizes this possibility and takes steps to prevent it by disabling interrupts before every use of delay_ms in main re-enabling interrupts after the call.
Another way to fix this problem is to stop using delay_ms in both main and interrupt code. You could replace one of them with your own custom delay function that uses a different loop variable. I am not sure why repeating the #use delay directive stops the warning message. Perhaps the compiler creates a new instance of the library delay functions when the #use delay directive is seen again. _________________ Robert Scott
Real-Time Specialties
Embedded Systems Consulting |
|
|
Salenko
Joined: 08 Sep 2008 Posts: 84
|
|
Posted: Wed Sep 10, 2008 8:26 am |
|
|
Hi Mr Scott,
thank you for this detailed answer,
RLScott wrote: | Salenko wrote: | ...
but when I remove one of the #use delay(clock=20000000), I got this warning message
Code: | Interrupts disabled during call to prevent re-entrancy: (@delay_ms1) |
|
First of all it is important to understand what that warning means. The library function delay_ms probably uses a temporary variable to hold the loop count as it counts down the time. This same temporary variable is used any time delay_ms is called. You call delay_ms both from your main program and from your interrupt code. Therefore it is possible for your main program to be in the middle of a delay_ms call, and thus using the loop variable in delay_ms, when an interrupt hits. Since the interrupt code also uses delay_ms, it will overwrite the loop variable. So when the interrupt returns to main, the loop variable will be corrupted from where main had it. The compiler recognizes this possibility and takes steps to prevent it by disabling interrupts before every use of [b]delay_ms in main re-enabling interrupts after the call.[/b]
Another way to fix this problem is to stop using delay_ms in both main and interrupt code. You could replace one of them with your own custom delay function that uses a different loop variable. I am not sure why repeating the #use delay directive stops the warning message. Perhaps the compiler creates a new instance of the library delay functions when the #use delay directive is seen again. |
I changed the name of all my loop variables as following (all are locals):
-RB0 interruption:
Code: | #int_EXT
void EXT_isr()
{
int i;
for (i=0;i<=4;i++) // blinking Green led
{
output_high(pin_a3);
delay_ms(20);
output_low(pin_a3);
delay_ms(20);
}
} |
-RB interruption:
Code: |
#int_RB
void RB_isr()
{
int j;
byte byte_b ;
for (j=0;j<=4;j++) // blinking Blue led
{
output_high(pin_a5);
delay_ms(20);
output_low(pin_a5);
delay_ms(20);
}
byte_b=input_b();
}
|
-the main():
Code: |
void main()
{
port_b_pullups(TRUE);
setup_adc_ports(NO_ANALOGS);
setup_adc(ADC_OFF);
setup_spi(FALSE);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_8);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DISABLED,0,1);
ext_int_edge(0,H_TO_L);
ext_int_edge(4,H_TO_L);
enable_interrupts(INT_EXT);
enable_interrupts(INT_RB);
enable_interrupts(GLOBAL);
set_tris_b(0xff);
set_tris_a(0x00);
set_tris_c(0x00);
while(1)
{
int k;
for (k=0;k<=254;k++)
{
output_c(k);
delay_ms(10);
}
}
}
|
-rest of code:
Code: |
#include "C:\Documents and Settings\test 1.h"
#ZERO_RAM
#use delay(clock=20000000)
#Priority EXT
|
-the header file:
Code: |
#include <16F876.h>
#device adc=8
#FUSES NOWDT //No Watch Dog Timer
#FUSES XT //Crystal osc <= 4mhz
#FUSES PUT //Power Up Timer
#FUSES NOPROTECT //Code not protected from reading
#FUSES BROWNOUT //Reset when brownout detected
#FUSES LVP //Low Voltage Programming on B3(PIC16) or B5(PIC18)
#FUSES NOCPD //No EE protection
#FUSES NOWRT //Program memory not write protected
#FUSES NODEBUG //No Debug mode for ICD
//#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=9
|
after compilation:
-0 Errors,
-3 Warnings
* Condition always true
* Condition always true
*Interrupts disabled during call to prevent re-entrancy: (@delay_ms1) |
|
|
Salenko
Joined: 08 Sep 2008 Posts: 84
|
|
|
|
|
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
|