Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

[SOLVED] Triggring a timer interupt inside a timer interrupt ISR

Status
Not open for further replies.

shubham kumar

Member level 3
Joined
Sep 11, 2014
Messages
59
Helped
1
Reputation
2
Reaction score
1
Trophy points
8
Location
bangalore
Activity points
511
Hi I am using PIC18F452 and MikroC.

What I am trying to do is, start a timer (TIMER0) with low priority interrupt. And in the ISR of that I am starting another timer (TIMER1) (which has been given higher interrupt priority). and when I am coming out of TIMER0 ISR, I am turning off the TIMER1.
So Timer1 will be running only when program is in ISR of TIMER0

But is not giving expected output

My aim is to find the time a program spent in ISR if some one writes a large code in ISR. So, here I am doing that by using timer1.
[[here I am not using TMRH TMRL etc .. once I will confirm that this is correct then I will think of measuring time]].

Code:
unsigned char txt[8],txt1[8];
 int  timer0_cnt=0, timer1_cnt=0,cnt=0,t,lambda;
                 
     void interrupt()                              // high priority interrupt TImer1
     {
      if(TMR1IF_bit)
          {
       TMR1IF_bit=0;                     // clear flag
       timer1_cnt++;                     // increment cnt1
          }
     TMR1H=0;
     TMR1L=0;
     }
     
     void interrupt_low()                             // Low priority interrupt  TIMER0
           {
             if(TMR0IF_bit)
                     {
                  TMR0IF_bit=0;         // clear flag
                  TMR1ON_bit=1;         // start timer 1
                  lambda=1;
                             // just do something
                  lambda= lambda+1;  lambda= lambda+1; lambda= lambda+1; lambda= lambda+1;
                  lambda= lambda+1; lambda= lambda+1; lambda= lambda+1; lambda= lambda+1;
                  lambda= lambda+1;  lambda= lambda+1; lambda= lambda+1; lambda= lambda+1;
                  lambda= lambda+1; lambda= lambda+1; lambda= lambda+1; lambda= lambda+1;
                  lambda=0;
                 
                  timer0_cnt++;      // increment cnt0
                  TMR1ON_bit=0;                  // Stop TIMER1
                     }
                          }


   void main()
        {
  Lcd_Init();                        // Initialize LCD
  Lcd_Cmd(_LCD_CLEAR);               // Clear display
  Lcd_Cmd(_LCD_BLINK_CURSOR_ON);

          ADCON0=0;
          ADCON1=0x0F;         // no analog inputs


       INTCON = 0xC0;
       INTCON.GIEL=1;
       INTCON.GIEH=1;
       
        // Timer0 settings
  TMR0H  = 0; TMR0L  = 0;         // Timer0 initial value
  T08BIT_bit=0;               // timer in 16 bit mode
  TMR0IF_bit=0;               // clear flag
  TMR0IE_bit=1;               // enable interrupt
  TMR0IP_bit=0;               // set at low priority

        // Timer1 settings
  TMR1H=0;  TMR1L=0;
  TMR1IF_bit = 0;          // clear TMR1IF
  TMR1IE_bit = 1;          // enable Timer1 interrupt
  TMR1IP_bit=1;            // set priority high
  T1CON  = 0x00;              // Timer1 settings
 
 TMR0ON_bit=1;               // Timer0 started

do
 {
 
    if(timer1_cnt>10)
     {
           IntToStr(timer1_cnt,txt);
           Lcd_Out(1,1,txt);
           Lcd_Out(1,9,"Tmr1_10");
           timer0_cnt=0;
      //     Delay_ms(500);                        //  used just to see the output for some significant time
     }

         
     if(timer0_cnt>5)
      {
            IntToStr(timer0_cnt,txt1);
            Lcd_Out(2,1,txt1);
            Lcd_Out(2,9,"Tmr0_5");
            timer1_cnt=0;
        //    Delay_ms(500);                      //  used just to see the output for some significant time
      }

                  // just do something
      lambda= lambda+1;  lambda= lambda+1; lambda= lambda+1; lambda= lambda+1;
                  lambda= lambda+1; lambda= lambda+1; lambda= lambda+1; lambda= lambda+1;
                  lambda= lambda+1;  lambda= lambda+1; lambda= lambda+1; lambda= lambda+1;
                  lambda= lambda+1; lambda= lambda+1; lambda= lambda+1; lambda= lambda+1;
                  lambda=0;
     
 }while(1);
         }
 

Yeah its look like good way.

But do you have another base timer to calculate, how much percentage of processor timing is utilized by the ISR. To find the percentage of cpu usage you need actual instructions cpu executed for a certaing time (eg:1 sec) and certain ISR instructions. So in this way you will need another timer to interrupt in a periodic manner to tell the percentage of CPU usage.

If you have any CPU cycle counters or if you using some internal calculations in ISR you can make it somehow simple.
Here your accuracy is depend on which prescalar you are using for measuring timer and also you have to subtract the time take for enabling and disabling ISR in each subroutine.
 

I understood what you said Venkadesh.

But the thing is I am not getting any output from this program.
As in main() , I am taking some output on LCD
Code:
Lcd_Out(1,1,txt);
  Lcd_Out(1,9,"Tmr1_10");

but actually I am not getting anything on LCD. Its just blank.
 

actually you are not doing anything if
timer1_cnt <= 10
or timer1_cnt <= 5
first remove the conditions or write else loop to test LCD is working or not.

If LCD is properly configured and working fine then the reason for no display is your timer interrupt is not working
 

Here is the correct code for other friends.
Code:
 void interrupt()
     {
      if(TMR1IF_bit)
          {
       TMR1IF_bit=0;                     // clear flag
       timer1_cnt++;                     // increment cnt1
          }
     TMR1H=0;
     TMR1L=0;
     }
     
     void interrupt_low()
           {
             if(TMR0IF_bit==1)
                     {
                  TMR1ON_bit=1;         // start timer 1
                  lambda=1;
                             // just do something
                  lambda= lambda+1;  lambda= lambda+1; lambda= lambda+1; lambda= lambda+1;
                  lambda= lambda+1; lambda= lambda+1; lambda= lambda+1; lambda= lambda+1;
                  lambda= lambda+1;  lambda= lambda+1; lambda= lambda+1; lambda= lambda+1;
                  lambda= lambda+1; lambda= lambda+1; lambda= lambda+1; lambda= lambda+1;
                  lambda=0;

                  timer0_cnt++;      // increment cnt0
                  TMR0IF_bit=0; TMR0H=0;TMR0L=0;
                     }
                     TMR1ON_bit-0;
            }


   void main()
        {
  Lcd_Init();                        // Initialize LCD
  Lcd_Cmd(_LCD_CLEAR);               // Clear display
  Lcd_Cmd(_LCD_BLINK_CURSOR_ON);

          ADCON0=0;
          ADCON1=0x06;         // no analog inputs
 

RCON =0x80;
INTCON.GIEL=1;
INTCON.GIEH=1;
       // Timer1 settings
  TMR1H=0;  TMR1L=0;
  TMR1IF_bit = 0;          // clear TMR1IF
  TMR1IE_bit = 1;          // enable Timer1 interrupt
  TMR1IP_bit=1;            // set priority high
  T1CON  = 0x00;              // Timer1 settings*/

        // Timer0 settings
  INTCON = 0xC0;
  TMR0H  = 0; TMR0L  = 0;         // Timer0 initial value
  TMR0IF_bit=0;               // clear flag
  TMR0IE_bit=1;               // enable interrupt
  TMR0IP_bit=0;               // set at low priority

  T0CON= 0x84;

do
 {
 
      if(timer1_cnt>10)
     {
           IntToStr(timer1_cnt,txt);
           Lcd_Out(1,1,txt);
           Lcd_Out(1,9,"Tmr1_0");
           timer1_cnt=0;
          // Delay_ms(500);
     }


   else if(timer0_cnt>3)
      {            
            IntToStr(timer0_cnt,txt);
            Lcd_Out(2,1,txt);
            Lcd_Out(2,9,"Tmr0_5");
            timer0_cnt=0;
         //   Delay_ms(500);
      }
      
                        // just do something
      lambda= lambda+1;  lambda= lambda+1; lambda= lambda+1; lambda= lambda+1;
                  lambda= lambda+1; lambda= lambda+1; lambda= lambda+1; lambda= lambda+1;
                  lambda= lambda+1;  lambda= lambda+1; lambda= lambda+1; lambda= lambda+1;
                  lambda= lambda+1; lambda= lambda+1; lambda= lambda+1; lambda= lambda+1;
                  lambda=0;

 }while(1);
         }

- - - Updated - - -

Hey Venkadesh_M

I have a question regarding timer.
That if the timer is started using command TMR1ON_bit=1; then if I stop the timer ( TMR1ON_bit=0) and again start the timer (TMR1ON_bit=1) then the timer will start from the value it contains at the time it was stopped or it will start from the default value which was assigned to TMRH and TMRL at the time of initialization.

I tried to see the values on LCD but realized later that LCD (or any) commands itself take some time, so unable to watch via programming :bang:

- - - Updated - - -

Venkadesh_M

I have a question regarding timer.
That if the timer is started using command TMR1ON_bit=1; then if I stop the timer ( TMR1ON_bit=0) and again start the timer (TMR1ON_bit=1) then the timer will start from the value it contains at the time it was stopped or it will start from the default value which was assigned to TMRH and TMRL at the time of initialization.

I tried to see the values on LCD but realized later that LCD (or any) commands itself take some time, so unable to watch via programming
 

The timer will not reload, when you restart it the count continues from where it was suspended.

Don't forget that most instructions take four clock cycles and branches/jumps can take twice that long. If you are careful to count the instructions you can predict how long the LCD and other command take and add or subtract it from your timer result.

Brian.
 
It is better to keep the code inside ISR very small.
 

Yaah, its better but if I write the ISR work in main then the thing is
1. I will not be able to check the temperature (https://www.edaboard.com/threads/323578/) after regular interval of time.

2. If I will be in main then, after ISR program execution will come to main to the position where it left instead of taking action for the ISR action code which is written in main. It will check it after 1-cycle. So during this cycle it may be possible that the ISR is executed twice and the action in the main will not be performed (as it may take some time while executing large main program)

(it is true that temp will not change by 2degree very soon but what if I want to make it more accurate by checking for every 0.5degree change. as that change can occur very fast and I don't want to miss any change so it is necessary that I should keep an eye on it as regularly as possible)

please let me know if you didn't understood the problem.

- - - Updated - - -

also I have one more question for which I am getting different opinions.

Does the Timer content (TMRH and TMRL) change when control goes to timer interrupt (or timer ISR).
I mean if inside the main function, if a timer flag is raised and when control goes to void interrupt() function, the timer will be running or it will stop till the ISR is served and start again when comes back to main

OR

It keeps running during ISR execution also.
 

Temperature wasn't mentioned inthis thread before! NEVER put an ISR in main code, that completely negates the purpose of it being an interrupt.

This is how I would tackle your problem:
1. Keep a timer (any but TMR1 is probably best) running with a known count rate.
2. The very first instructions on entering the ISR should be to copy TMR1 value to a safe location.
3. Set a flag to indicate an interrupt has occured (don't use the INTxx bits!)
4. The very last thing you do before the RETFIE is take another copy of the TMR1 value.

Now in the main routine, check to see if your flag was set then subtract the two TMR1 saved values, taking into account it may have rolled over, then subtract the time taken to execute the two saves, the result is the time taken inside the ISR.

As a general rule, try not to execute more code than necesary inside an ISR, it is better to set a flag, exit the ISR and check the flag to initiate your routine in the main code, resetting the flag there so it is ready for the next occurence.

Brian.
 
1, That is depend on how you write your code. Still it is possible to execute the code in 'while' in sync with the code in ISR, when you have a lot of things to do. Unless you got very high freq ISRs, but I think your temp is not that mush high proc event.

2, Yeah obviously it can miss running the code for some time if you put some excessive load in while, that can be avoided by slicing the big tasks and state based algorithms.

What is your freq of reading temp ?

Being inside any ISR is noting relevant to timer registers, it will run whenever you enable and will pause whenever you stop.
If you want you can reset them by writing 0.

- - - Updated - - -

For simplicity if you don have any delay func in your temperature reading part then you can write it in ISR.
 
Thanks Brian
That clearly helped me. Earlier I thought of using 1 timer but couldn't come up with this idea that's why I started using two timers. But this helped a lot.

@venkadesh_M
Yeah obviously it can miss running the code for some time if you put some excessive load in while, that can be avoided by slicing the big tasks and state based algorithms.
Exactly this is the thing I was worrying about. It can miss, so I wanted to make it more and more accurate so that it should miss least number of chances.

But now I got it. :)

just one thing :D .. can any one become a "moderator" or "super moderator" if he has certain number of helps and posts.
I am also trying to give suggestions to certain queries but my scope is limited as I just started with controllers.
 

You have to prove yourself useful before becoming a moderator. It is only by invitation by the other administrators, it isn't a privilege you get by earning a certain number of points although that helps of course.

Moderators can do things like move posts to another section if they are misplaced or delete posts that are inappropriate but apart from some administrative abilities they are normal users. For generally helping other users you have exactly the same accessibility to the Forum sections as moderators and all other users so if you want to help, simply post useful replies to other peoples queries.

To the best of my knowledge, none of the moderators have ever met each other, everything is done on-line. One of the reasons for being chosen is geographic location so that we can cover most time zones between us so we are spread out around the World. For example, I think other moderators located nearest me are keith1200rs at about 250kM and then FvM at about 1,000Km.

Brian.
 
I completely understood what you said
You have to prove yourself useful before becoming a moderator.
what I meant was, till (if) I become a moderator, means I would have helped a lot of persons. Which some one can do only when he had attained certain level (in terms of knowledge).
So if I target to become a moderator then at the same time I would think of more and more learning in different domains.

P.S. :
none of the moderators have ever met each other
that wasn't my aim. :D
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top