|
|
View previous topic :: View next topic |
Author |
Message |
jacktaylor
Joined: 02 Sep 2017 Posts: 75
|
Doubt in interrupt processing |
Posted: Sun Jul 08, 2018 8:46 am |
|
|
Hello friends. I have a doubt in the execution of an interruption in the TIMER1 of the example, but that also applies to the TIMER0.
In the next program, the timer overflow is 131ms.
The doubt is: when overflow occurs the lines within the while (1) stop executing and the processing is done inside the interrupt lines ? Is the following executed or not ?
Code: |
FOR (REPEAT = 0; REPEAT <2; REPEAT ++);
{
OUTPUT_A (0XFF);
DELAY_MS (500);
OUTPUT_A (0X00);
DELAY_MS (500);
}
|
Since to execute for () demand a delay time of 2 seconds and at this time the timer should already be at least 16 times.
In my simulation, the is executed only once and does not obey the REPEAT <2 times.
Code: |
#FUSES INTRC_IO, NOWDT, NOMCLR
#USE DELAY(clock= 4M)
#use fast_io(a)
#use fast_io(b)
INT REPETE;
INT16 RECEBE;
#int_timer1
void timer_1()
{
SET_TIMER1(0);
FOR (REPETE =0; REPETE<2; REPETE++);
{
OUTPUT_A(0XFF);
DELAY_MS(500);
OUTPUT_A(0X00);
DELAY_MS(500);
}
}
void main()
{
SETUP_TIMER_1(T1_INTERNAL|T1_DIV_BY_2 );
SET_TIMER1(0);
ENABLE_INTERRUPTS(INT_TIMER1);
ENABLE_INTERRUPTS(GLOBAL);
SET_TRIS_A(0X00);
OUTPUT_A(0X00);
SET_TRIS_B(0X00);
OUTPUT_B(0X00);
WHILE(1)
{
RECEBE= GET_TIMER1();
OUTPUT_B(RECEBE);
} | |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9245 Location: Greensville,Ontario
|
|
Posted: Sun Jul 08, 2018 9:14 am |
|
|
2 quick comments.
1st. FOR (REPEAT = 0; REPEAT <2; REPEAT ++);
can only be executed once as repeat starts at 0, increments to 1 and when it goes to 2, exits the loop
2nd. you should never,ever have 'delays' of any kind within any ISRs. same holds true for prints ,floating point math and 'complicated' decisions.
also no processor is shown....
and .. 'simulation', if Proteus, please read PIC101 sticky and get rid of Proteus. |
|
|
jacktaylor
Joined: 02 Sep 2017 Posts: 75
|
|
Posted: Sun Jul 08, 2018 11:10 am |
|
|
temtronic wrote: | 2 quick comments.
1st. FOR (REPEAT = 0; REPEAT <2; REPEAT ++);
can only be executed once as repeat starts at 0, increments to 1 and when it goes to 2, exits the loop
2nd. you should never,ever have 'delays' of any kind within any ISRs. same holds true for prints ,floating point math and 'complicated' decisions.
also no processor is shown....
and .. 'simulation', if Proteus, please read PIC101 sticky and get rid of Proteus. |
Okay, thanks for the information Ttelmah. I made the code to better understand how the interruption works. The intention is not to use delay in the interrupt, but to understand the actual processing. I did this to understand a video lesson I watched, but it did not work as shown in the lesson simulation.
However, even if REPEAT with a larger loop, for example 5 times FOR (REPEAT = 0; REPEAT <6; REPEAT ++) ;, the PORT only varies once, ie regardless of the REPEAT value, only the loop will be executed once FOR, when the interruption occurs, because this is what is happening in my assembly on the protoboard, very different from what I saw in a video lesson, where the author puts REPEAT <10 and the PORT rises 9 times and not only once as it is happening with my simulation. In my simulation it continues to run only once. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19546
|
|
Posted: Sun Jul 08, 2018 12:51 pm |
|
|
Jay (Temtronic), is not me.
It should sit practically never executing the output B instruction. Basically the interrupt handler you have takes longer than the time between interrupts, so whenever it exits it'll immediately trigger again. There are total of about 10 instructions in your main loop, and just one will get executed each time the code returns to the main.
If you want to see ten pulses when the timer triggers run the code without the delays.
You talk about a 'simulation' if this is the Proteus simulator, this is full of bugs. If you want to run a simulator get the old MPLAB 8.92, which has one that 99% works. In all cases though the simulation will only give reasonable results if you have set it up correctly.
There is no point in setting the timer to zero in the interrupt. The interrupt triggers when the timer resets to zero. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sun Jul 08, 2018 4:50 pm |
|
|
temtronic wrote: |
FOR (REPEAT = 0; REPEAT <2; REPEAT ++);
can only be executed once as repeat starts at 0, increments to 1 and
when it goes to 2, exits the loop.
|
Actually the loop count is OK. It should execute the loop 2 times.
What's wrong is that he has a semi-colon ';' at the end of the for()
statement.
Quote: | FOR (REPEAT = 0; REPEAT <2; REPEAT ++); <== semi-colon here is wrong |
When you have a semi-colon at the end of a for() statement,
it will just count down and exit the for() line. Then it will
execute the body of the loop one time. That's what he is seeing. |
|
|
jacktaylor
Joined: 02 Sep 2017 Posts: 75
|
|
Posted: Mon Jul 09, 2018 7:03 am |
|
|
PCM programmer wrote: | temtronic wrote: |
FOR (REPEAT = 0; REPEAT <2; REPEAT ++);
can only be executed once as repeat starts at 0, increments to 1 and
when it goes to 2, exits the loop.
|
Actually the loop count is OK. It should execute the loop 2 times.
What's wrong is that he has a semi-colon ';' at the end of the for()
statement.
Quote: | FOR (REPEAT = 0; REPEAT <2; REPEAT ++); <== semi-colon here is wrong |
When you have a semi-colon at the end of a for() statement,
it will just count down and exit the for() line. Then it will
execute the body of the loop one time. That's what he is seeing. |
Ohhhhh my God. I made a grotesque mistake by leaving the semicolon. This is exactly the error of not executing FOR. Many thanks PCM programmer, but it was nice to be aware and it was more an apprenticeship. Thanks a lot for the help. |
|
|
jacktaylor
Joined: 02 Sep 2017 Posts: 75
|
|
Posted: Mon Jul 09, 2018 7:17 am |
|
|
jacktaylor wrote: | PCM programmer wrote: | temtronic wrote: |
FOR (REPEAT = 0; REPEAT <2; REPEAT ++);
can only be executed once as repeat starts at 0, increments to 1 and
when it goes to 2, exits the loop.
|
Actually the loop count is OK. It should execute the loop 2 times.
What's wrong is that he has a semi-colon ';' at the end of the for()
statement.
Quote: | FOR (REPEAT = 0; REPEAT <2; REPEAT ++); <== semi-colon here is wrong |
When you have a semi-colon at the end of a for() statement,
it will just count down and exit the for() line. Then it will
execute the body of the loop one time. That's what he is seeing. |
Ohhhhh my God. I made a grotesque mistake by leaving the semicolon. This is exactly the error of not executing FOR. Many thanks PCM programmer, but it was nice to be aware and it was more an apprenticeship. Thanks a lot for the help. |
With this test I was able to verify that:
1) When executing the interrupt while (1) processing is interrupted, even the overflow time being 131ms, ie no new interrupts occur while not executing the entire loop within the interrupt.
2) there is no need to use clear_interrupt (INT_TIMER1); in CCS compiler? I did the test with and without this function and the result was the same. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19546
|
|
Posted: Mon Jul 09, 2018 7:35 am |
|
|
Quote: |
When executing the interrupt while (1) processing is interrupted, even the overflow time being 131ms, ie no new interrupts occur while not executing the entire loop within the interrupt.
|
Actually they do occur. However the default behaviour is to automatically clear interrupts _at the end of the handler_. So they will be clear when you exit.
There is an option 'NOCLEAR' that can be appended to the interrupt handler declaration, which disables this option, and you then have to clear the interrupts yourself. I must admit I normally do this since I prefer interrupts to be cleared at the start of the handler, which then allows subsequent 'second triggers' to also be seen. |
|
|
jacktaylor
Joined: 02 Sep 2017 Posts: 75
|
|
Posted: Mon Jul 09, 2018 8:17 am |
|
|
Ttelmah wrote: | Quote: |
When executing the interrupt while (1) processing is interrupted, even the overflow time being 131ms, ie no new interrupts occur while not executing the entire loop within the interrupt.
|
Actually they do occur. However the default behaviour is to automatically clear interrupts _at the end of the handler_. So they will be clear when you exit.
There is an option 'NOCLEAR' that can be appended to the interrupt handler declaration, which disables this option, and you then have to clear the interrupts yourself. I must admit I normally do this since I prefer interrupts to be cleared at the start of the handler, which then allows subsequent 'second triggers' to also be seen. |
In your case you use the not clear 'NOCLEAR' in the declaration of void main () and then you use clear_interrupt (INT_TIMERXX); ?
Let me see if I got it. Can I use the clean interruption? Or do I need to declare 'NOCLEAR'?
Code: | # int_timer1
void timer_1 ()
{
CLEAR_INTERRUPT(INT_TIMER1);
SET_TIMER1 (0);
TEMPO ++;
IF (TIME == 5)
{
for (REPEAT = 0; REPEAT <6; REPEAT ++)
{
OUTPUT_A (0XFF); // OUTPUT_HIGH (PIN_D7);
OUTPUT_A (0X00); // OUTPUT_LOW (PIN_D7);
}
}
}
void main ()
{
CLEAR_INTERRUPT (INT_TIMER1);
SETUP_TIMER_1 (T1_INTERNAL | T1_DIV_BY_2);
SET_TIMER1 (0);
ENABLE_INTERRUPTS (INT_TIMER1);
ENABLE_INTERRUPTS (GLOBAL);
} |
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19546
|
|
Posted: Mon Jul 09, 2018 8:28 am |
|
|
It's entirely up to you.
However if your interrupt was something like an event you wanted to count, the quite large time it takes to get _out_ of the interrupt becomes significant. So in this case you'd want to move the clear towards the front of the interrupt (so use the NOCLEAR, and clear it yourself). The interrupt could then re-trigger and the handler be called again. However for an event where you don't mind missing a occasional trigger, or the interval between triggers is always more than the time needed to get into the handler and out again, the default behaviour is fine:
Code: |
# int_timer1
void timer_1 ()
{
CLEAR_INTERRUPT(INT_TIMER1);
//A wasted instruction. The interrupt is being cleared again
//at the end of the handler
SET_TIMER1 (0);
//This is also a wasted instruction. The interrupt is called
//because the timer _has_ wrapped to zero...
TEMPO ++;
IF (TIME == 5)
{
for (REPEAT = 0; REPEAT <6; REPEAT ++)
{
OUTPUT_A (0XFF); // OUTPUT_HIGH (PIN_D7);
OUTPUT_A (0X00); // OUTPUT_LOW (PIN_D7);
}
}
|
|
|
|
jacktaylor
Joined: 02 Sep 2017 Posts: 75
|
|
Posted: Tue Jul 10, 2018 7:59 am |
|
|
Ttelmah wrote: | It's entirely up to you.
However if your interrupt was something like an event you wanted to count, the quite large time it takes to get _out_ of the interrupt becomes significant. So in this case you'd want to move the clear towards the front of the interrupt (so use the NOCLEAR, and clear it yourself). The interrupt could then re-trigger and the handler be called again. However for an event where you don't mind missing a occasional trigger, or the interval between triggers is always more than the time needed to get into the handler and out again, the default behaviour is fine:
Code: |
# int_timer1
void timer_1 ()
{
CLEAR_INTERRUPT(INT_TIMER1);
//A wasted instruction. The interrupt is being cleared again
//at the end of the handler
SET_TIMER1 (0);
//This is also a wasted instruction. The interrupt is called
//because the timer _has_ wrapped to zero...
TEMPO ++;
IF (TIME == 5)
{
for (REPEAT = 0; REPEAT <6; REPEAT ++)
{
OUTPUT_A (0XFF); // OUTPUT_HIGH (PIN_D7);
OUTPUT_A (0X00); // OUTPUT_LOW (PIN_D7);
}
}
|
|
Okay, thanks for the explanation, Ttelmah, I get it. Now I have another question with the CCS compiler.
In the test program below, I verify that by assigning zero the variable TMR1IF of PIR1 it does not return to one, simulating in MPLAB 8.92, with step by step F7. If I remove the line that assigns zero, in the Proteus simulation the program runs executing normally the For in the while (1). The point is that the manual has to reset this interrupt flag. The doubts are: Because when zeroing, the bit does not return to one and in the Proteus simulation does the program normally run without zeroing this flag in the CCS?
Code: |
#include <16F628A.h>
#FUSES INTRC_IO, NOWDT, NOMCLR // 16F628A
#use delay(clock= 4M)
#use fast_io(b)
#bit TMR1IF = 0x0C.0
INT REPETE;
INT16 RECEBE;
void main()
{
//clear_interrupt(INT_TIMER1);
SETUP_TIMER_1(T1_INTERNAL|T1_DIV_BY_2 );
//SETUP_TIMER_1(T1_EXTERNAL);
SET_TIMER1(65533);
//ENABLE_INTERRUPTS(INT_TIMER1);
//ENABLE_INTERRUPTS(GLOBAL);
SET_TRIS_A(0X00);
OUTPUT_A(0X00);
SET_TRIS_B(0X80);
OUTPUT_B(0X00);
WHILE(1)
{
RECEBE= GET_TIMER1();
OUTPUT_B(RECEBE);
IF (TMR1IF)
{TMR1IF =0;
FOR (REPETE =0; REPETE<3; REPETE++)
{
OUTPUT_A(0XFF);//OUTPUT_HIGH(PIN_D7);
DELAY_MS(1);
OUTPUT_A(0X00);//OUTPUT_LOW(PIN_D7);
DELAY_MS(1);
}
}
}
} |
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19546
|
|
Posted: Tue Jul 10, 2018 8:19 am |
|
|
Repeat 15*.
Do not believe the Proteus simulator.
On a real chip it triggers again and merrily executes the output every 131mSec. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9245 Location: Greensville,Ontario
|
|
Posted: Tue Jul 10, 2018 12:03 pm |
|
|
As Mr. T. say
Do NOT believe Proteus ! It's BUSTED, broke, incomplete, worthless...
Sadly there's a whole herd of folks who think Proteus is the next best thing to sliced bread...
however it's NOT a 100% perfect 'simulator' for PICs.
Even the schematic creator is flawed. In 10+ years here, I've yet to see ONE schematic that would work in the real World...not ONE !!
If you want to see what your code's really doing, dump the listing, grab the instruction set, pad of graph paper and pencil then 'play computer'. YOU manual 'single step' through every line of code..diddle registers and such, just like the PIC. Old school..best way to learn.
Jay |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19546
|
|
Posted: Tue Jul 10, 2018 12:16 pm |
|
|
As a comment I have just tried it in MPLAB 8.92, which the poster mentions, and in this the flag does set again merrily. If you put a break on the TMRIF=0 instruction, it happily arrives back there with the bit set. Remember this is the _only_ place you can test this, since this then immediately sets it back to 0.... |
|
|
jacktaylor
Joined: 02 Sep 2017 Posts: 75
|
|
Posted: Tue Jul 10, 2018 3:52 pm |
|
|
Ttelmah wrote: | As a comment I have just tried it in MPLAB 8.92, which the poster mentions, and in this the flag does set again merrily. If you put a break on the TMRIF=0 instruction, it happily arrives back there with the bit set. Remember this is the _only_ place you can test this, since this then immediately sets it back to 0.... |
Ok thanks friend Ttelmah, I did another simulation in MPLAB and this time I saw the TMR1IF flag go to zero. |
|
|
|
|
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
|