pic16f877a and two interrupts

Discussion in 'Embedded Systems and Microcontrollers' started by lokster, Aug 13, 2012.

  1. lokster

    Thread Starter New Member

    Jul 10, 2012
    5
    0
    Hey guys, I've been tasked in class to use a pic16f877a and create a circuit where there is a certain pattern of LEDs, basically the LED travels down a row, so its like one on, and one off

    And when i press the push button, the pattern changes to something slower, so the LED moves slower.

    eg 1st pattern, LED 1 second on, 1 second off
    2nd pattern, LED 2 seconds on, 2 seconds off
    3rd pattern, LED 8 seconds on, 8 seconds off
    and the back to the first pattern with every push of the push button
    (attached a picture of the circuit )


    I've figure out that i need to use two interrupts, timer0 and External interrupt RB0.Timer0 for the clocking and RB for the button. What i dont understand is when i have two interrupt functions MP Lab gives me an error that i cannot use both, and can only have one. (using C programming)

    i get that i should have one ISR, but i dont get how do i keep both functioning in just 1 ISR?? I'm new to this so please bear with me.
     
  2. takao21203

    Distinguished Member

    Apr 28, 2012
    3,577
    463
    1. You don't have to use interrupt for pushbutton.

    2. Have you actually written any interrupt handler? It should be quite obvious that inside such a C code interrupt flag is tested. Or also interrupt flags.

    If one flag was not set, the next one is tested! This does not take much MCU time. Do you need a code example, or is it obvious now?
     
  3. lokster

    Thread Starter New Member

    Jul 10, 2012
    5
    0
    yeah, ive written an interrupt handler for timer0. im not sure how to go about the push button not being an interrupt. thanks for the quick reply, could you give me a code sample? here is my program, just in case you want to look, i get an error of the micro controller not being able to have 2 interrupt functions..
     
  4. takao21203

    Distinguished Member

    Apr 28, 2012
    3,577
    463
    Let's ask this way: why do you want additional interrupt function?

    Simply add the code into the existing interrupt handler. That is the way it is done.

    2. For the push button, it is common to "sample" it regularily using the timer interrupt. You have to be a bit creative using one timer for more than one task. Even if PICs have more than one timer. Slow things such as LED animation are easy to add into existing timer code.
     
  5. t06afre

    AAC Fanatic!

    May 11, 2009
    5,939
    1,222
    In Hi-tech C you MUST code in such way that you only use one ISR. If you have several interrupt sources. You must sort this out inside the ISR. Also in your code. You do not set any configuration bits. You can set these bits in MPLAB. But they must be set. If not your PIC will not work. I also agree that you do not need interrupt for the push button. Sort this out in the main function.
     
  6. lokster

    Thread Starter New Member

    Jul 10, 2012
    5
    0
    i dont know how to use a push button in the main function, without using interrupt =/

    i would know how to use a latch, but how do you get the main function to detect a rising or falling edge?
     
  7. t06afre

    AAC Fanatic!

    May 11, 2009
    5,939
    1,222
    What does your assignment say. Do the detection have to be edge trigged?
     
  8. lokster

    Thread Starter New Member

    Jul 10, 2012
    5
    0
    actually, it doesnt, it just that for every push of the button the pattern of LED changes
     
  9. t06afre

    AAC Fanatic!

    May 11, 2009
    5,939
    1,222
    If you look at the 16f877a header file (pic16f877a.h) you will find bit definitions for every port. This is for PORTB
    Code ( (Unknown Language)):
    1. / Register: PORTB
    2. volatile unsigned char           PORTB               @ 0x006;
    3. // bit and bitfield definitions
    4. volatile bit RB0                 @ ((unsigned)&PORTB*8)+0;
    5. volatile bit RB1                 @ ((unsigned)&PORTB*8)+1;
    6. volatile bit RB2                 @ ((unsigned)&PORTB*8)+2;
    7. volatile bit RB3                 @ ((unsigned)&PORTB*8)+3;
    8. volatile bit RB4                 @ ((unsigned)&PORTB*8)+4;
    9. volatile bit RB5                 @ ((unsigned)&PORTB*8)+5;
    10. volatile bit RB6                 @ ((unsigned)&PORTB*8)+6;
    11. volatile bit RB7                 @ ((unsigned)&PORTB*8)+7;
    So it to test a bit you can code like this as some examples
    Code ( (Unknown Language)):
    1.  
    2. if(RB6)
    3. {
    4. }
    5. while(!RB7)
    6. {
    7. }
    8.  
     
  10. lokster

    Thread Starter New Member

    Jul 10, 2012
    5
    0
    yes i see that, but what the assignment and what i want to be done is the input of the push button is received from one source which is just RB0 as a push button, not a latch where it can be set to a solid 1 or 0.
     
  11. t06afre

    AAC Fanatic!

    May 11, 2009
    5,939
    1,222
    If RB0 is set to be a standard input. It will at any given moment have the logic value 1 or 0. Not at any moment a neither value. Then you code like say. The current value of the port will be used.
    Code ( (Unknown Language)):
    1. if (RB0)
    2. {
    3. }
     
  12. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    7,386
    1,605
    Testing buttons can be tricky as a switch will "bounce" and make contact several times when pressed or unpressed. Since your app changes what it does every time you press the button you could have it do all sorts of weird things as it sees these bounces flash by: it may or may not change when you press it, or it may change when you release it.

    The way to handle a button is to read it "every so often" and only report a change when that change is stable over several readings. There's lots of code on the net how to do that. I have some example code but it's woven deeply into my apps as I don't just use pins for buttons, they also run other things at other times, so it explains nothing.

    Since you already set up a timer ISR you can use that to both keep time (update a variable) and to do the button check "every so often." Then your main code can check the time variable to set leds, and also check the button state to see if a new pattern state in invoked.
     
    lokster likes this.
  13. t06afre

    AAC Fanatic!

    May 11, 2009
    5,939
    1,222
    By all means 100% correct. But I noticed that the OP uses the Isis Proteus simulator. Which do not have any switch bounce. So I did not mention that real life problem.
     
    lokster likes this.
  14. takao21203

    Distinguished Member

    Apr 28, 2012
    3,577
    463
    1. Generate timer interrupt about every 25 mS.

    2. Set a flag inside the interrupt handler, and return immediately.

    3. If the flag was set:

    -read and process the digital I/O for the pushbutton. Store it into a binary flag, and call the "key handler", also passing a counter variable for each button used.
    -call a function, that writes LED data from RAM to the digital I/O port. This is called the "refresh" function.
    -increase the LED animation counter.

    This is placed inside the main loop.
    You simply test the LED animation counter let say for a value of 10 to 30.
    Then you change the LED pattern. But you don't write to digital port.
    That is done in the so-called "refresh" routine. If you just have some LEDs, you only need one variable. The same technique is also used for larger LED matrix. Often the whole pattern RAM is updated at once, but display might be multiplexed and/or having serial interface.

    So updating display pattern, and actual output to the display are done seperately.

    4. The key handler.

    Simple for one key. If you need more than one key, you read different I/O bits into one and the same flag. But you need a counter variable for each key.
    Then you call the key input handler one time (for one button), or as many times as required, using different counter variables.

    Since it is called every 25 mSec, it acts as a low pass, when it is programmed to advance from state 0 (button I/O=1), state 1 (button I/O=0), and finally state 2 (button I/O=1). You need to reset the counter variable to zero, after value "2" was detected (key pressed), and code was executed.*

    You actually only need one timer interrupt to do all this.

    I have done many LED matrix circuits. I might even have a source code around from years ago, displaying a changing pattern on 8 LEDs, and having one pushbutton to change between permanent ON Leds, and flashing LEDs. Unfortunately it is assembler :)

    *this assumes negative logic, where the I/O pin is pulled up via WPU (or 4.7K resistor) to Vcc, and then shortened to ground when the button is pressed.
     
    lokster likes this.
Loading...