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

Multiple Interrupts PIC16F917

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



Joined: 10 Sep 2007
Posts: 2

View user's profile Send private message

Multiple Interrupts PIC16F917
PostPosted: Sun Oct 21, 2007 7:55 pm     Reply with quote

1. Does 16F917 have the ability to service multiple interrupts?
The problem I encounter is that my TIMER1 ISR cannot be set as the highest priority interrupt. I tried the '#INT_TIMER1 HIGH' directive but get an error, 'Invalid interrupt directive requires #DEVICE HIGH_INTS=TRUE'.

I need the time to increment even if there are other 'things' being processed at the time.

When the button on port RB0/INT is pressed and held down the timer stops counting. I need the time to increment even while the button is pressed (EXT_ISR() is being processed), or even if the hell brakes lose.

2. Why capacitors are required on the Vdd power supply pins?

Code:
// Functional code for PIC16F917
// Varitronix PL-VIM-404-DP display
// 32KHz

#include <16F917.h>
#DEVICE ICD=TRUE
//#use delay(clock=32KHZ)      // crystal=32K
#fuses LP,NOWDT,NOPROTECT,PUT

//RTC variables
int8 Second1s=0;
int8 Second10s=0;
int8 Minute1s=0;
int8 Minute10s=0;
long counter=0;

/////////////////////////////////////////////////////////////////////////////////////////
//                                 LCD Configuration                                               //
/////////////////////////////////////////////////////////////////////////////////////////
// Digit segments:   A         B         C         D         E         F         G         DP
// Bit#:            b7         b6         b5         b4         b3         b2         b1         b0
#define DIGIT1   COM0+16,   COM0+23,   COM1+23,   COM2+16,   COM1+11,   COM0+11,   COM1+16   
#define DIGIT2   COM0+10,   COM0+22,   COM1+22,   COM2+10,   COM1+9,   COM0+9,   COM1+10   
#define DIGIT3   COM0+8,   COM0+21,   COM1+21,   COM2+8,   COM1+17,   COM0+17,   COM1+8      
#define DIGIT4   COM0+18,   COM0+20,   COM1+20,   COM2+18,   COM1+19,   COM0+19,   COM1+18   
#define DP1      COM2+20
#define DP2      COM2+21
#define DP3      COM2+22

//            character         0        1      2       3      4      5       6       7      8      9   
byte const DIGIT_MAP[10]   = {0xFC,0x60,0xDA,0xF2,0x66,0xB6,0xBE,0xE0,0xFE,0xE6};   
byte const DP_MAP[2]       = {0X00,0x80};
   
/////////////////////////////////////////////////////////////////////////////////////////

void init_routine();

#PRIORITY INT_TIMER1, INT_EXT

#INT_TIMER1
void TIMER1_ISR()
{
     Second1s++;                           //   Increment number of seconds
      if(Second1s >= 10) {Second10s++; Second1s=0;
         if(Second10s >= 6) {Minute1s++; Second10s=0;
            if(Minute1s >= 10) {Minute10s++; Minute1s=0;
               if(Minute10s >= 10) {Minute10s=0;
   }}}}

   set_timer1(0x80B9);
//   clear_interrupt(INT_TIMER1);         // clears the timer1 interrupt flag
}

#INT_EXT
void EXT_ISR()
{
   while(!input(PIN_B0))
   {
//      Second1s=0;
//      Second10s=0;
//      Minute1s=0;
//      Minute10s=0;
      LCD_SYMBOL(DP_MAP[1],DP1);
   }
   
   LCD_SYMBOL(DP_MAP[0],DP1);
}
   
////////////////////////////////////////////////////////////////////////////////
// Example program for using the RTC
////////////////////////////////////////////////////////////////////////////////
void main()
{
  init_routine();

  while(1)
  {
    // Toggle output every second
//    if (Second1s != prev_second)
//    {
//      prev_second = Second1s;
//      output_toggle(PIN_D1); // output_toggle(PIN_D1);
     
//   i = !i;
//   LCD_SYMBOL(DP[1],DIGIT2);
     
      LCD_SYMBOL(DIGIT_MAP[Second1s],DIGIT1);
   LCD_SYMBOL(DIGIT_MAP[Second10s],DIGIT2);
   LCD_SYMBOL(DIGIT_MAP[Minute1s],DIGIT3);
   LCD_SYMBOL(DIGIT_MAP[Minute10s],DIGIT4);
   
   sleep();             // make processor sleep
             


  } // end while()
} // end main()


void init_routine() {

   setup_timer_1(T1_EXTERNAL|T1_DIV_BY_1|T1_CLK_OUT);   // T1_INTERNAL, initialize 16-bit Timer1 to interrupt
                                                                      // exactly every 65536 clock cycles
                                                                      // (about 76 times per second)
   setup_comparator(NC_NC_NC_NC);
   setup_vref(FALSE);
   setup_wdt(WDT_OFF);
   setup_adc(ADC_OFF);
   setup_adc_ports(NO_ANALOGS);
//   setup_oscillator(OSC_31KHZ);  // internal RC setup ?
   setup_lcd(LCD_MUX13 | LCD_USE_TIMER_1, 0);
   //SET_TRIS_A(0x04);
   //SET_TRIS_C(0x00);
   enable_interrupts(INT_TIMER1);    // Start RTC
   enable_interrupts(INT_EXT);
   enable_interrupts(global);
// Sets up INT_EXT to watch for the rising edge
   ext_int_edge(H_TO_L);
     
   Second1s=0;
   Second10s=0;
   Minute1s=0;
   Minute10s=0;
 
      LCD_SYMBOL(DIGIT_MAP[Second1s],DIGIT1);
   LCD_SYMBOL(DIGIT_MAP[Second10s],DIGIT2);
   LCD_SYMBOL(DIGIT_MAP[Minute1s],DIGIT3);
   LCD_SYMBOL(DIGIT_MAP[Minute10s],DIGIT4);
   LCD_SYMBOL(DP_MAP[0],DP1);
   LCD_SYMBOL(DP_MAP[1],DP2);
   LCD_SYMBOL(DP_MAP[0],DP3);
   
}


3. I appreciate any relevant suggestions!

Thanks for your time.
Ttelmah
Guest







PostPosted: Mon Oct 22, 2007 2:29 am     Reply with quote

HIGH_INTS, only applies to _18_ family pics.
The same applies to the 'FAST', and 'HIGH' keywords.

The 16, can 'service multiple interrupts', but only ever one at a time. (In fact this is true of any 'single processor', but on chips like the 18x chips, an interrupt can interrupt aother event, on the 16, it can't).
The way interrupts work on the 16 chips, is that when an interrupt 'event' occurs (three things needed - the interrupt flag goes 'true', the interrupt enable for this source is set, and the global interrupt enable is set), the code will execute a 'call' on first cycle of the next machine instruction, to address 0004. This call is special, in that it automatically _clears_the global interrupt enable bit, preventing any other interrupt from triggering. Then the code has to save all registers. This is done automatically for you by the compiler. Then the code has to check _which_ interrupt bit is set, to trigger the interrupt. Now the order in which this is done, determines which interrupt is serviced _first_, if multiple sources have triggered. This is set by the #priority keyword (if this is not present, it is determined by the order the individual handler routines are defined).
Once the source is identified, _it's_handler routine is called. Then the flag is cleared - beware though that some events like 'serial data available', and 'port B changed', _require_ the hardware event to be cleared in the handler, or the flag bit will immediately reset. The registers are restored, and a special 'return' instruction is used, which resets the global interrupt enable, ater it executes. If another interrupt flag is still set, or when the next interrupt flag triggers, the whole squence will trigger again.

Now, comments.
The big problem is that you are sitting waiting in the RB interrupt. This is basically a 'no no'. _All interupt handlers, should always be kept as short as possible_. The other problem is that you are writing to the display in the handler, which will imply that all interrupts will be disabled in all display operations in the main. Don't do this...

The way to solve this is:
int1 key_pressed=false;

Code:

#INT_EXT
void EXT_ISR(void) {
   if (input(PIN_B0)==0) { 
      key_pressed=true;
      ext_int_edge(L_TO_H);
   }
   else {
      key_pressed=false;
      ext_int_edge(H_TO_L);
   }
}

Then in your main, simply test this bit, and update the required display. Since the hip is asleep while waiting, it'll wake when the button is pressed.

Other comments. You don't need to clear the interrupt, this is done for you (you have remmed this out, so possibly have realised this).
Search the forum, about setting a timer 'to' a value. This will not be accurate.

The capacitors needed, depend on what loads are present on the lines, and the nature of the supply...
However, a _small_ (non electrolytic) capacitor, such as a 0.1uF ceramic, should be placed as close as possible to the supply pins of any device that potentially generates high speed 'switching' edges. the PIC does.

Best Wishes
Guest








PostPosted: Mon Oct 22, 2007 11:19 am     Reply with quote

That is one of the best supports I have got regarding MCU's. Thank you for your explanations.

I hope you can assist me further and explain your comment about setting timers.

Ttelmah wrote:

Other comments. You don't need to clear the interrupt, this is done for you (you have remmed this out, so possibly have realised this).


Yes. This was a remnant of my futile attempt to resolve my issue with the 16x not being able to service different levels of interrupts.

Ttelmah wrote:

Search the forum, about setting a timer 'to' a value. This will not be accurate.


Do you mean that my way of setting a timer is not accurate or that setting a timer is inherently not accurate?

Ttelmah wrote:

The capacitors...


The power is supplied by a battery so, I figured the supply is virtually free of noise. Also, the load is just a reflective LCD, which is a matrix of small capacitors. Do I care about the PIC being a source of noise? I don't think so; or don't know it yet. If anybody else has comments about the caps, please share. I would like to know if there is any extra power consumption when using caps and other considerations to take into account when going with caps vs. no caps.

Thank you for great support.
Ttelmah
Guest







PostPosted: Mon Oct 22, 2007 2:49 pm     Reply with quote

You should be concerned about the PIC being a source of noise. It can affect _itself_, and also things like the LCD. LCD's are also often quite 'noisy' (the line scans can create some quite nasty clock patterns).
Capacitors should draw basically nothing (leakage currents out in the femto amp range typically), having a poorly smoothed supply, can result in unexpected signal triggers, and make consumption _worse_...
The problem is that the point when you arrive in the interrupt, is not 100% deterministic. If a key even, just happens to be already being handled when the timer triggers, there will be a small extra delay. There will have been anything between perhaps 35, and 100 instruction times, from the moment of the timer 'event', and reaching the line where you set the timer. This _will_lead to errors.
You don't really need to set the timer to a count. There have been efficient routines posted here in the past (using binary wrapping), which allow an accurate RTC, to be done with a timer that runs at a really 'odd' ratio to the required time. These wll give accurate results.

Best Wishes
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Mon Oct 22, 2007 3:03 pm     Reply with quote

Quote:
If anybody else has comments about the caps, please share.

Professional circuit designers automatically put 100 nF caps (0.1 uF)
on all Vdd pins (to ground). Or, they follow the data sheet
recommendations which might call for 10 nF caps on high speed chips,
for example.

One of the reasons why the pros have far fewer problems than newbies
is because they automatically follow standard engineering procedures
when doing circuit design.

You can increase the reliability of your own designs by adopting the
methods used by the pros. You can learn some of it by reading
this forum.
rnielsen



Joined: 23 Sep 2003
Posts: 852
Location: Utah

View user's profile Send private message

PostPosted: Mon Oct 22, 2007 3:18 pm     Reply with quote

I, almost always, place a cap next to each IC in my circuits. You never know what stray noise there might be out there. You have your PIC running at around 20MHZ with this crystal thingy buzzing. It's bound to be creating something that a neighboring part is going to be annoyed by. Kinda like a little gnat flying next to your ear that you can't seem to swat.

It's not just the PIC that you should be worried about but it's all the other components that you should be concerned about too. Caps are cheep, especially surface mount ones, and really don't take up that much real estate.

If you're going to be doing any ADC stuff, you'll want to use caps to decouple things or you could have a lot of noise there. Ground planes work well to help with noise.

You have analog grounds and digital grounds. You'll learn to keep these two separate or the digital grounds could make the analog ones noisy.

Just a few things to consider. Clear as mud now?

Ronald
Guest








PostPosted: Tue Oct 23, 2007 1:34 pm     Reply with quote

Thank you ALL for your good advise. I will do some PICing this coming weekend and let you know about the progress on this project.

"To catch a PIC you have to think and act like a PIC."
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