CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to support@ccsinfo.com

16f877a interrupt issue

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
sysysy



Joined: 17 Nov 2010
Posts: 38
Location: 121

View user's profile Send private message

16f877a interrupt issue
PostPosted: Sun Nov 21, 2010 10:07 am     Reply with quote

Hi,

i am going to use the interrupt in PIC16f877a.
But anyone can explain methods to use timer and few register that will be used to me?

i am using 20Mhz crystal, but i dun know the pre-scaler is what for?

from what i know is put a number inside the register, then when the register count to 0xff, then the interrupt flag will be set. is it indicates when the flag be set, then the instruction will go to do the interrupt work???

For example,
if i want my program every 10 seconds go to do the interrupt service routine. that what should i set and how i calculate?

*note: i really do not understand the datasheet.

Crying or Very sad Crying or Very sad Crying or Very sad
Ttelmah



Joined: 11 Mar 2010
Posts: 19375

View user's profile Send private message

PostPosted: Sun Nov 21, 2010 10:42 am     Reply with quote

You won't get 10 seconds, unless you use an external clock at a much lower frequency. However this 'doesn't matter'.
Key is to think about machines like the PC. Here you have an internal 'tick' interrupt running at quite a high frequency (on the original PC, 18.2 times per second), but you can setup a 'task' to be called 10 seconds in the future, by simply 'counting ticks', and calling the code you want (in this case) after 182 ticks.
Simplest timer to use, is timer2. This is fed from the master clock/4. Then you have a choice of 'prescalers' (dividers), /1 /4, or /16. Then a divider of /1 to /256, and finally another 'postscaler', of /1 to /16 (Phew).
What you want is a nice 'high' count, that gives a easy to count 'tick'. So:

20000000/(4*4*250*10), gives '50', which is a nice number to work with.
So, you then want something like:
Code:

#define TicksPerEvent (500)
int1 do_operation=FALSE;

#int_timer2
void tick(void) {
   static int16 counts=TicksPerEvent;
   //Arrive here 50*/second
   if (--counts==0) {
       //500/50 = 10 so here every ten seconds
       counts=TicksPerEvent;
       do_operation=TRUE;
   }
}

//Then in your main

    //Early on
    setup_timer2(T2_DIV_BY_14,249,10); /(4*4*250*10)
    enable_interrupts(INT_TIMER2);
    enable_interrupts(GLOBAL);

    //Then in your main 'loop'
    while (TRUE) {
         if (do_operation) {
             do_operation=FALSE;
             //Code here that you want to execute every ten seconds
         }
         //Your other code

    }
       


Now, important things. Read here about why it is important to keep interrupt handlers quick. Hence the code you want, unless it is very simple, should be in the main loop as shown, rather than in the interrupt.
There is an application note about the timers, on the MicroChip site, and this is _much_ more informative than the data sheet.
The prescalers, and postscalers, are just 'dividers'.

Best Wishes
sysysy



Joined: 17 Nov 2010
Posts: 38
Location: 121

View user's profile Send private message

PostPosted: Sun Nov 21, 2010 11:03 am     Reply with quote

Thx for the information Wink

But some of the thing i am not clear,
may i know

"20000000/(4*4*250*10), gives '50', which is a nice number to work with. "

20000000 --> my crystal value

4 -->?
4 -->?
250 --> ?
10--> 10second?

may i know those number indicates what? why i need use this equation?
the final answer 50 is indicates50 ticks in a second?

sorry, juz how to know to use this equation for counting?

thanks.
Ttelmah



Joined: 11 Mar 2010
Posts: 19375

View user's profile Send private message

PostPosted: Sun Nov 21, 2010 11:28 am     Reply with quote

I do explain these numbers.
"This is fed from master clock/4" - Hence the first 4
"Then you have a choice of 'prescalers' (dividers), /1 /4, or /16"

You can use whatever you want, but I was looking for a set up numbers that gives a nice decimal division of your clock.

4*250*10, is 10000 nice decimal number, and gives 50 ticks per second.

You have a choice of:
1,4,16

1 to 256

1 to 16

Trying to find values that multiplied together, gives a high number that divides evenly into 5000000 (20000000/4), gives 10000 as one possibility. Another is:

16*125*10, which then gives 20000 (25 ticks per second).
Trying to go above this, leads to results that give 'odd' results, making the divisions harder.
You can equally well work with 'near enough' binary numbers, and go for a less frequent tick, _but_ then the accuracy disappears.

Best Wishes
sysysy



Joined: 17 Nov 2010
Posts: 38
Location: 121

View user's profile Send private message

PostPosted: Sun Nov 21, 2010 12:32 pm     Reply with quote

Thanks alot.

But still wanna asking... Embarassed Embarassed Embarassed

Hmmm...I try to run your program...

in my main program,
Code:

void main()
{
    setup_timer_2(T2_DIV_BY_4,249,10); /(4*4*250*10)
    enable_interrupts(INT_TIMER2);
    enable_interrupts(GLOBAL);

    while (TRUE) {
         
         if (do_operation) {
              do_operation=FALSE;
             
              output_high(PIN_A0) //to turn on the LED
         }
         
          lcd_putc("\ftesting...") // display something on LCD
          delay_ms(3000)
          output_low(PIN_A0) // to turn off the LED
          }


    }

My problem is, after I wait few seconds, the LED turn on, so I assume the interrupt work. But, the LCD never display anything and LED never turn off again after this... may I know why?

Or can I don't put the isr in the main function, but it still can be call every 10 seconds?
sysysy



Joined: 17 Nov 2010
Posts: 38
Location: 121

View user's profile Send private message

PostPosted: Sun Nov 21, 2010 12:56 pm     Reply with quote

May i know how come the main program never call the tick() function?

is it in the if(do_operation) {... }, then the tick() already be called?

sorry for a lot of question, i really very weak in this. but i wish to learn and understand Smile

Code:

#define TicksPerEvent (500)
int1 do_operation=FALSE;

#int_timer2
void tick(void) {
   static int16 counts=TicksPerEvent;
   //Arrive here 50*/second
   if (--counts==0) {
       //500/50 = 10 so here every ten seconds
       counts=TicksPerEvent;
       do_operation=TRUE;
   }
}

//Then in your main

    //Early on
    setup_timer2(T2_DIV_BY_14,249,10); /(4*4*250*10)
    enable_interrupts(INT_TIMER2);
    enable_interrupts(GLOBAL);

    //Then in your main 'loop'
    while (TRUE) {
         if (do_operation) {
             do_operation=FALSE;
             //Code here that you want to execute every ten seconds
         }
         //Your other code

    }
       
Ttelmah



Joined: 11 Mar 2010
Posts: 19375

View user's profile Send private message

PostPosted: Sun Nov 21, 2010 1:03 pm     Reply with quote

The main loop is being executed all the time. You want this to be as fast as possible, wen nothing is eing done. So:
Code:

void main()
{
    setup_timer_2(T2_DIV_BY_4,249,10); /(4*4*250*10)
    enable_interrupts(INT_TIMER2);
    enable_interrupts(GLOBAL);

    while (TRUE) {
         
         if (do_operation) {
              do_operation=FALSE;
              output_high(PIN_A0); //to turn on the LED
              lcd_putc("\ftesting...");// display something on LCD
              delay_ms(100);
              lcd_putc("\ffinished");
              output_low(PIN_A0); // to turn off the LED
         }
    }

Your lines are all 'illegitimate' - no terminaing ';'. Probably nothing executes after the first output statement.....

Best Wishes
sysysy



Joined: 17 Nov 2010
Posts: 38
Location: 121

View user's profile Send private message

PostPosted: Sun Nov 21, 2010 1:09 pm     Reply with quote

That you mean all the things need inside the if {}?
But if like that, does it mean all action will just do once for every 10 seconds?
If not, can you explain a bit? sorry...sorry..sorry...

*Note: What I mean is I want to put those actions outside the if() because those actions are normal in while(1) loop. I simply write that for testing purpose, because I want to make sure my other actions can work as well when using interrupt.

Sorry for the mistake. Shocked
sysysy



Joined: 17 Nov 2010
Posts: 38
Location: 121

View user's profile Send private message

PostPosted: Sun Nov 21, 2010 9:05 pm     Reply with quote

Hi, I am actually rushing a project.

Can anyone give me some idea about interrupt?
I hope can make my program work fine.

Thanks.


Regards,

sysysy
gpsmikey



Joined: 16 Nov 2010
Posts: 588
Location: Kirkland, WA

View user's profile Send private message

PostPosted: Sun Nov 21, 2010 11:48 pm     Reply with quote

In the code shown, the timer triggers an interrupt 50 times / second. Inside the ISR, the "counts variable gets decremented each time through. When it reaches 0, the "do_operation" gets set to TRUE (which your "Main" sees) and the counts gets reset to 500 again to start the next 500 counts down at 50 times/ second. The end result is that every 10 seconds, the "do_operation" flag will get set to true. When it does, the code running in main() sees it go true and does whatever you want resulting in something happening every 10 seconds. Hope that helps.

mikey
_________________
mikey
-- you can't have too many gadgets or too much disk space !
old engineering saying: 1+1 = 3 for sufficiently large values of 1 or small values of 3
Ttelmah



Joined: 11 Mar 2010
Posts: 19375

View user's profile Send private message

PostPosted: Mon Nov 22, 2010 3:12 am     Reply with quote

The key is to keep things 'moving'. Delays (unless short), are your enemy. While a delay is executing, nothing else in your main code is running. You can extend the 'tick' idea, to do other jobs. For example:
Code:

#define TicksPerEvent (500)
#define TicksPerSecond (50)
int1 do_operation=FALSE;
int8 second_counter=0;

#int_timer2
void tick(void) {
   static int16 counts=TicksPerEvent;
   static int16 ticks=TicksPerSecond;
   //Arrive here 50*/second
   if (--counts==0) {
       //500/50 = 10 so here every ten seconds
       counts=TicksPerEvent;
       do_operation=TRUE;
   }
   if (--ticks==0) {
       //Here every second
       ticks=TicksPerSecond;
       if (second_counter) --second_counter;
   }
}

//Then in your main
    int8 old_seconds=0;
    //Early on
    setup_timer2(T2_DIV_BY_14,249,10); /(4*4*250*10)
    enable_interrupts(INT_TIMER2);
    enable_interrupts(GLOBAL);

    //Then in your main 'loop'
    while (TRUE) {
         if (do_operation) {
             do_operation=FALSE;
             //Code here that you want to execute every ten seconds
             output_high(PIN_A0); //Turn on LED
             second_counter=3;
         }
         if (old_seconds!=second_counter) {
             //You will get here once per second, while 'second_counter' <>0
             old_seconds=second_counter;
             lcd_putc("`fcount %d",old_seconds;
             if (old_seconds==0) {
                 lcd_putc("\f"); //Clear screen
                 output_low(PIN_A0); //drop pin
             }
         }           
    }


Now you have the every ten seconds, uring the LED on for 3 seconds, and displaying a countdown, then when it gets to zero, clearing the screen and turning the LED off.

However the 'loop' is still executing quickly, allowing fast response to other things.

At any time you want to wait for a number of seconds, you can just set the second_counter to a value, and carry on doing other things till it gets to zero.

Best Wiishes
sysysy



Joined: 17 Nov 2010
Posts: 38
Location: 121

View user's profile Send private message

PostPosted: Mon Nov 22, 2010 6:59 am     Reply with quote

Code:


//Then in your main
    int8 old_seconds=0;
    //Early on
    setup_timer2(T2_DIV_BY_14,249,10); /(4*4*250*10)
    enable_interrupts(INT_TIMER2);
    enable_interrupts(GLOBAL);

    //Then in your main 'loop'
    while (TRUE) {
         if (do_operation) {
             do_operation=FALSE;
             //Code here that you want to execute every ten seconds
             output_high(PIN_A0); //Turn on LED
             second_counter=3;
         }
         if (old_seconds!=second_counter) {
             //You will get here once per second, while 'second_counter' <>0
             old_seconds=second_counter;
             lcd_putc("`fcount %d",old_seconds;
             if (old_seconds==0) {
                 lcd_putc("\f"); //Clear screen
                 output_low(PIN_A0); //drop pin
             }
         }           
    }


Ok thx alot... 1 last thing i wanna confirm.

in the above code,

1. if (do_operation){... } is do the task every 10 seconds --->OK

2. if (old_seconds!=second_counter), is do the other routine, and we set the desired time we want. But my problem is without this if (old_seconds!=second_counter), we direct write our program inside the while(true) loop, is it still correct? becoz all the things still inside the while loop. Then i assume, it will always loop.

So, can take out the second the if check condition one?

or my concept wrong?
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
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