Interrupt on Change or Not?

Discussion in 'Embedded Systems and Microcontrollers' started by Dalaran, Jun 20, 2011.

  1. Dalaran

    Thread Starter Active Member

    Dec 3, 2009
    168
    0
    For some time I have been wondering what people do in most instances if they need a button to perform an action. I thought most people would use an interrupt on change (available on all PORTB pins of the PICs I usually use) to enter the interrupt routine and do what they need to do.

    But after reading some and looking at examples 2 things came to mind.

    -Most examples I see just use some sort of 'if' statement such that if a pin is tied pulled high (switch closed) then perform this action. Do me this doesn't make sense for long codes and seems prone to missing or double counting. Do many people use this method?

    -Then I thought if using interrupt on change is more reliable, how do you get whatever you modified back from the interrupt? If the button is to change a setting (not just the state of a pin) how does this get returned back to the main function?

    I use the mikroelectronica EasyPIC6 development board and 6 of the 8 PORTB pins are dedicated for LCD (when enabled) so it seems like these are not too desirable. I program in C.

    Thanks!
     
  2. guitarguy12387

    Active Member

    Apr 10, 2008
    359
    12
    I have found that PIC peripheral interrupts are sensitive, particularly to contact bounce. If latency is not a big issue (i.e. sampling a switch 20 times a second is still quite infrequently on a several-MHz clock speed), it may just plain be easier to poll the outputs. Personally, I use a timer which generates an interrupt on roll-over. I choose the scaling appropriately so that contact bounce is ignored. Then every time a timer interrupt fires, I sample the switches. Works quite well and pretty easily for me. A bit easier than trying to debounce a peripheral interrupt.

    That being said... i have yet to get the peripheral interrupts working very well on any of my projects. So people who are more experienced may have better input

    Use global variables (don't forget the 'volatile' qualifier when necessary)
     
  3. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    7,392
    1,605
    There is no best way, there are just ways that do the most and cost the least in specific circumstances.

    An interrupt on change can nail each and every bound and rebounce a switch takes. There may be times you need that accuracy but a "human" slow button probably isn't one of them. Additionally you'll typically pass the button state back to your "main" program thru a (volatile) variable, and the main program must by necessity poll that variable.

    You may notice that many programs from the Microchip Application Library have their main loop within a "while(1)" loop. This gives a nice wrapper for whatever tasks need to be performed regularly, and polling a button is just such a task.
     
  4. Dalaran

    Thread Starter Active Member

    Dec 3, 2009
    168
    0
    Hey, thanks for the responses both of you!

    I like the idea of using a timer for sampling the switches. And looks like you have given me some reading to do on 'volatile qualifiers'. There always seems to be much more about the C language than I think I know.

    And global variables... thank-you for answering my amateur question! :)
     
  5. n1ist

    Active Member

    Mar 8, 2009
    171
    16
    For more debouncing information, do a web search for "Ganssle debouncing"
    /mike
     
  6. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    7,392
    1,605
    Sometimes C will optimize your code. A variable with the volatile qualifier in C tells the compiler not to assume the variable has not changed from the last time it looked.
     
  7. THE_RB

    AAC Fanatic!

    Feb 11, 2008
    5,435
    1,305
    I never use an interrupt for something that is very easy to check manually and only needs to occur slowly. Buttons/switches are one of the slowest things a PIC ever needs to check.

    My preference is to have some timed control loop. It might be every 10mS or every 1mS, something like that. Often that loop is part of a real world timer system that can generate accurate periods if needed although that is irrelevant. :)

    Then in the 10mS loop, every loop I check for the button(s). Debounce is very simple;

    Code ( (Unknown Language)):
    1.  
    2. // 10mS loop (etc)
    3. while(1)
    4. {
    5.   Delay_mS(10);
    6.   do_general_loop_stuff();
    7.  
    8.   if(PORTB.F0 == 0)  // if button is pressed
    9.   {
    10.     debounce++
    11.     if(debounce > 15)
    12.     {
    13.       debounce = 0;
    14.       do_blah();  // ok button was REALLY pressed!
    15.     }
    16.   }
    17.   else debounce = 0;
    18. }
    19.  
    ErnieM, I believe MikroC treats all variables as volatile, it definitely does with any PIC hardware registers (like PORTB).
     
  8. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    7,392
    1,605
    I wouldn't know about the MikroC compiler, I don't use it (and don't get the business model that would require it either). I use the Microchip PIC32 C-Compiler, which has several levels of optimization to choose from, if you've paid for them. This compiler makes no choices about what is volatile or not, that is left to the user to define.

    The Port registers are defined as volatile if you dig down to find the .h file where they reside.
     
  9. nsaspook

    AAC Fanatic!

    Aug 27, 2009
    2,908
    2,169
    Last edited: Jun 23, 2011
  10. AlexR

    Well-Known Member

    Jan 16, 2008
    735
    54
    I don't think so, as least I would hope that it didn't do that otherwise it is going to produce some horribly bloated code.
    All PIC compilers that I know off mark PIC port and SFRs (special function registers) as "volatile" forcing the compiler to do a read of the SFR before it uses it, but its up to the user to decide whether to mark any user-defined variables as a volatile variable or not.
     
  11. THE_RB

    AAC Fanatic!

    Feb 11, 2008
    5,435
    1,305
    All the hardware registers are read directly.

    I keep a pretty close eye on the asm output generated by the compiler. In the case where variables are byte sized it directly accesses the RAM location.

    Probably the only time it is going to be an issue is if you a reading a multi-byte variable that is modified in an interrupt, and the interrupt occurs between bytes. But in that case even a "volatile" declaration won't help much. ;)
     
  12. AlexR

    Well-Known Member

    Jan 16, 2008
    735
    54
    It's going to make a difference when any variable, multi-byte or not, is modified by the ISR.
    Any half-decent compiler keeps a track of its variables and if the variable is not volatile and has not been changed (as far as the compiler knows) then it uses the last known value whenever the variable is called. The ISR is not called by any other function so as far as the compiler is concerned any variable used by the ISR is never changed by the ISR. In the worst case if the variable is not changed outside the ISR the compiler can even optimise out the variable and replace it with a constant.
     
  13. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    7,392
    1,605
    QFT.

    "volatile" by itself may not be sufficient on variables changed via an ISR or such. While a variable changed via an ISR should be marked volatile, unless the quantity is only changed atomically (ie, is not greater then the processor word size be it 8 16 or 32 bits) then extra steps must be taken to ensure any read is valid.
     
  14. THE_RB

    AAC Fanatic!

    Feb 11, 2008
    5,435
    1,305
    Thanks guys but I'm still failing to see the point here... ;)

    No, not really. As the hardware is very limited and the RAM locations ARE the variables the compiler just accesses the PIC RAM locations when a variable is read or modified. The exception is when it is in the W register.

    The compiler does use a data stack of 16 bytes but this is only generally used for times when indirect addressing is needed (arrays) or math calcs are done, or in some multi-byte variable operation.

    Because of compiler optimisation, using indirect addressing on single variables is much slower code than accessing the RAM into W, ie; MOVF variable,W so unless there are special circumstances the compiler always uses the actual RAM variable for reading and writing.

    ErnieM's original statement was to a variable "button" being modified in the interrupt and then being accessed in the main loop. I'm not saying he's wrong I just don't see any situation where the volatile declaration is going to be necessary?

    I use volatile in windows applications but have never needed it in PIC C applications.
     
    Last edited: Jun 25, 2011
  15. John P

    AAC Fanatic!

    Oct 14, 2008
    1,634
    224
    Maybe I'm missing the point of this, but my C compiler for the PIC processors (an ancient version of the CCS compiler) makes the assumption that every variable used in functions or interrupts is volatile. If you want to keep something between calls, you need to declare it static or use a global variable. I think that's pretty standard, and certainly easy to live with.
     
  16. nsaspook

    AAC Fanatic!

    Aug 27, 2009
    2,908
    2,169
    The word 'volatile' used here has nothing to do with temp variables on the stack in a function call.
    Like others have said it's a C compiler processing directive that states the defined (global) variable can be changed other than from the main program flow (like an ISR modifying a data flag that is only read from main program flow but never written) and that operations 'must' use the actual location of the data instead of a cached value or an assumed constant value.
     
  17. John P

    AAC Fanatic!

    Oct 14, 2008
    1,634
    224
    Ah. Well, I'd call that a fairly sophisticated software concept, that I've never needed to use. In fact I wonder if it's ever relevant to "Embedded Systems and Microcontrollers". Seems more like big-computer stuff.
     
  18. nsaspook

    AAC Fanatic!

    Aug 27, 2009
    2,908
    2,169
    Actually it's mostly used in machine interface code, low level device drivers, embedded systems and microcontrollers.

    This thread from elsewhere has good examples.

    http://www.8051projects.net/lofiversion/t22383/avr-gcc-tutorial.html
     
  19. THE_RB

    AAC Fanatic!

    Feb 11, 2008
    5,435
    1,305
    And the example of where this will actually make a difference in a PIC?

    As I said before the compiler just accesses the RAM location any time it reads or writes that variable. As someone who has used PIC assembler for over 10 years I always check the compilers ASM output and have a pretty good understanding of what it does.

    In a Windows C situation where the compiler with use lots of temporary RAM and swap files etc then volatile can be very important, but the PIC does not have temporary RAM, it has very limited RAM where the one memory location is used for 1byte variable.

    If anyone has a real example of a PIC volatile issue I would like to see it.
     
  20. John P

    AAC Fanatic!

    Oct 14, 2008
    1,634
    224
    I did a little searching and managed to come up with a clear example of where the volatile keyword might be used. It comes from here:
    http://publications.gbdirect.co.uk/c_book/chapter8/const_and_volatile.html

    Suppose you had this:
    Code ( (Unknown Language)):
    1.  
    2.  while((dvp->csr & (READY | ERROR)) == 0)
    3.                 ; /* NULL - wait till done */
    4.  
    However, a major problem with previous C compilers would be in the while loop which tests the status register and waits for the ERROR or READY bit to come on. Any self-respecting optimizing compiler would notice that the loop tests the same memory address over and over again. It would almost certainly arrange to reference memory once only, and copy the value into a hardware register, thus speeding up the loop. This is, of course, exactly what we don't want; this is one of the few places where we must look at the place where the pointer points, every time around the loop... To remove the problem (and other similar ones to do with when to write to where a pointer points), the keyword volatile was introduced. It tells the compiler that the object is subject to sudden change for reasons which cannot be predicted from a study of the program itself, and forces every reference to such an object to be a genuine reference.

    I see how that works, but there doesn't seem to be any reason why a compiler for the PIC processors would do this. All the registers are available as RAM locations, so I don't see any need to "copy the value into a hardware register, thus speeding up the loop". But if that's what happened, then the volatile declaration there would be vital, because if one of the flags weren't found first time, you'd have a guaranteed endless loop. Actually I'm not comfortable with that while() loop, volatile or not. I'd want to put a counter on it, which at some point would cause a break followed by a return with an error.
     
    Last edited: Jun 27, 2011
Loading...