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.

external interrupt with pic16f877a

Status
Not open for further replies.

meche

Junior Member level 2
Joined
Apr 12, 2017
Messages
24
Helped
0
Reputation
0
Reaction score
0
Trophy points
1
Activity points
252
Can someone please help: I am new to interrupt programming and am using pic16f877a to try my hands on programming external interrupts. I have my push button connected to my RB0/int pin, a red LED connected to RB1 and blue LED connected to RB2. The interrupt doesn't work according to my design. I want the LED connected to RB2 to only come on and flash once the push button is pressed to initiate the interrupt. The other LED connected to RB1 should be flashing until the interrupt.
Instead the two LED's comes ON immediately the simulation is run and the LED on RB2 will only start to flash and behave according to design only after the push button is pressed.
I cant seem to find out why the LED on RB2 should turn ON immediately at the resumption of simulation.

Below is my code written with MPLAB XC8 and I am simulating with proteus.


Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
main.c
 * Author: meche1
 *
 * Created on May 4, 2017, 4:20 PM
 */
 
#define _XTAL_FREQ 8000000
#include "newxc8_header.h"
#define LED1 PORTBbits.RB1
#define LED2 PORTBbits.RB2
#define LED1_TRIS TRISBbits.TRISB1
#define LED2_TRIS TRISBbits.TRISB2
 
 
void my_delay (int a)
{
    for(int x =0; x<=a; x++ )
    {
       __delay_ms(500);
    }
}
 
 
 
 
 
void interrupt isr (void)
{
    INTCONbits.INTF = 0;
    for(int x=0; x<=10; x++)
    {
      LED2 = 1;
      __delay_ms(500);
      LED2 = 0;
      __delay_ms(500);
    }
    
 }
        
 
void main(void) 
{
    LED1_TRIS = 0;
    LED2_TRIS = 0;
 
    INTCONbits.INTF = 0;
    OPTION_REGbits.INTEDG = 1;
    INTCONbits.GIE = 1;
    INTCONbits.INTE = 1;
    
    while(1)
    {
       LED1 = 1;
       my_delay(3);
       LED1 = 0;
       my_delay(3);
    }
    
}

 

You are using delay() inside interrupt vector.
Doing that, you will blind further interrupts.
Consider using flags there.
 

please can you give me a hint on how to use flags with respect to interrupt?
 

please can you give me a hint on how to use flags with respect to interrupt?

Something like that:

Code:
void interrupt isr (void)
{
fGotInterrupt = TRUE ;   // boolean global variable
}

Code:
void main(void) 
{
...
while (1)
    {
    if (fGotInterrupt)
        {
        ...               // manage led here
        fGotInterrupt = FALSE ;
        {
    }
}
 

There are a couple of bad habits in your code, some of which will hurt you now and some will get you in the future.
Andre has already mentioned the use of a delay in the ISR. An ISR is designed to stop the normal flow of your program, do something that must be done immediately and then let the normal program execution continue. Adding in a delay will hold up your normal program execution. In your case the ISR is designed to flash LED2 10 times and take 10 seconds to do it. While that is happening LED1 which is supposed to be flashing on and off every 6 mSec (see below) will stop flashing.
Having LED1 flash every 6 mSec (3mSec on and 3mSec off) is WAY to fast if you are wanting to see the LED flash with your eyes. Your eyes can see things slower than about 30Hz so you should make the delays about 15mSec as a minimum and probably much longer. Of course if you are looking at the signal on an oscilloscope then what you have is fine.
The device you are using has a single interrupt vector that will be called whatever the source of the interrupt. At the moment you are only allowing 1 interrupt source to trigger the ISR and so you are OK. However as soon as you want another interrupt source to be active at any time in your application, then you need to use the standard coding approach of testing both the IE and IF bits of the interrupt. In your cast that would mean code such as
Code:
void interrupt isr(void)
{
   if( INTCONbits.INTF && INTCONbits.INTE)
   {
       // Do whatever is needed here
      INTCONbits.INTF = 0;
   }
   // Test for other interrupt sources here
}
If you follow Andre's good advice about using flags, then you must declare the flag to be 'volatile'. That tells the compiler that it can be changed within an ISR and so not to (for example) put the flag value into a register and think that it will always reflect the true value of the flag.
Using a mechanical device such as a switch or a button means that you must handle 'contact bounce'. While you think you push the button once, the actual contacts can make and brake multiple times over several milli-seconds. When you connect the button or switch to an interrupt pin, then each of those bounces will trigger the ISR (which, as mentioned above, should only take microseconds to complete). There are multiple ways you can debounce a switch or button (Google will show you many) but my preferred technique is to set up a timer that calls an ISR every mSec. The ISR checks the pin and compares it with the value it saw last time. If the ISR sees the same value on the pin for (say) 10 times - or 10mSec - then it will record the 'state' of the button. If that is not the same as the previous 'state', then it can set a flag to say 'the button has changed' and your code can then decide if it has been pushed or released. (This is a very quick overview - but it is faster to code than to describe.)
Susan
 

Status
Not open for further replies.

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top