|
|
View previous topic :: View next topic |
Author |
Message |
januszkl
Joined: 10 Sep 2007 Posts: 2
|
Multiple Interrupts PIC16F917 |
Posted: Sun Oct 21, 2007 7:55 pm |
|
|
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
|
|
Posted: Mon Oct 22, 2007 2:29 am |
|
|
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
|
|
Posted: Mon Oct 22, 2007 11:19 am |
|
|
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
|
|
Posted: Mon Oct 22, 2007 2:49 pm |
|
|
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
|
|
Posted: Mon Oct 22, 2007 3:03 pm |
|
|
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
|
|
Posted: Mon Oct 22, 2007 3:18 pm |
|
|
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
|
|
Posted: Tue Oct 23, 2007 1:34 pm |
|
|
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." |
|
|
|
|
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
|