Learning Assembly on PIC - efficiency question

Discussion in 'Embedded Systems and Microcontrollers' started by wannaBinventor, Jun 5, 2010.

  1. wannaBinventor

    Thread Starter Member

    Apr 8, 2010
    179
    4
    I've been playing around with some very basic assembly code on the PIC16F84A.

    I don't think my diagram here is important, as this is mostly about the code.

    I've got a pull up resistor to 5v on each switch. When the switch is pressed it takes the input pin to 0.

    Here's a piece of two variations of code that do the same thing:

    METHOD A:

    SW0TEST
    BTFSC PORTA,0 ;test bit 0 in file PORTA, skip if clear
    BTFSS PORTA,0 ;test bit 0 in file PORTA, skip if set (go to SW1 test)
    GOTO SW0ACT ;IF SW0 IS PUSHED, DO THE ACTION FOR IT

    SW1TEST
    BTFSC PORTA,1 ;test bit 1 in file PORTA, skip if clear
    GOTO BEGIN ;IF SWITCH 0 IS NOT PUSHED, GO BACK TO START
    GOTO SW1ACT ;IF SWITCH 1 IS PUSHED, GO TO SWITCH 1 ACTION

    --------------------------------------------------------
    METHOD B:

    BEGIN

    COND0
    MOVLW B'00000011' ;put that in W register
    SUBWF PORTA ;SUBTRACT ABOVE FROM PORTA BITS
    BTFSC STATUS,ZEROBIT ;DOES PORTA = 00000011?
    GOTO BEGIN

    SW0TEST
    MOVLW B'00000010' ;put into W reg
    SUBWF PORTA ;SUBTRACT ABOVE FROM PORTA BITS
    BTFSC STATUS,ZEROBIT ;DOES PORTA = 00000010
    GOTO SW0ACT ;GOT TO SW0 ACTION IF SW0 IS PRESSED


    SW1TEST
    MOVLW B'00000001' ;PUT THIS IN THE W REGISTER
    SUBWF PORTA ;SUBTRACT ABOVE FROM PORTA BITS
    BTFSS STATUS,ZEROBIT ;DOES PORTA = 00000001?
    GOTO BEGIN ;IF ABOVE IS FALSE, GO BACK TO START
    GOTO SW1ACT ;GO TO SW1 ACTION

    -------------------------------------------

    As I said, both pieces of code accomplish the same thing.
    I just need one thing cleared up: If I only need to check one input at a time, should I just use method A (seems to be MUCH more simple)? Is method B more for testing multiple inputs at the same time? If I'm testing 5 different ports, the number of conditions that I'd have to write would grow quite large given all the combinations. Is there a better way, or is it just a matter of plugging away at getting all the combos in the code?

    Thanks for the help!

    EDIT:
    SW0 = switch 0 on porta bit 0 pin
    SW1 = switch 1 on porta bit 1 pin
    In method B, "COND0" just makes the code keep looping back to the beginning until a button is pressed.
     
  2. Markd77

    Senior Member

    Sep 7, 2009
    2,803
    594
    Method A is better in all cases, if you were testing 5 inputs with method B there would be 32 tests, compared to 5 with method A.
    Also in method B you would have to do SUBWF PORTA, W because otherwise the default of F would modify PORTA.
     
  3. jpanhalt

    AAC Fanatic!

    Jan 18, 2008
    5,671
    897
    One reason to test an input multiple times is to debounce. A 10 to 25 mS delay between tests is usually adequate. It is something you could incorporate in Method A easily with a loop(s).

    John
     
  4. eblc1388

    Senior Member

    Nov 28, 2008
    1,542
    102
    You have used GOTO to jump to the specific switch handling action.

    Wouldn't it be more logical to use CALL instead of GOTO so you don't have to retest from bit0 after the handling has finished?
     
  5. wannaBinventor

    Thread Starter Member

    Apr 8, 2010
    179
    4
    It may very well be the case. All I about assembly is what I've learned from about the first 100 pages of a book I just got. I was wondering what the difference in CALL and GOTO was. I'm still not sure that I really understand. Are you saying that if I were to just use CALL, it would pick back up on the next line of code after the subroutine that I called finished.

    So basically:
    TEST BIT 0
    (say button is pressed)
    so CALL SUBROUTINE FOR WHATEVER ACTION I WANT
    .....then program carries on?

    Is this what you mean?

    I'm assuming that the affect here is that I just save some clock cycles per each code run-through?
     
  6. Markd77

    Senior Member

    Sep 7, 2009
    2,803
    594
    Using calls makes code reusable too. Say if you had a 1 second delay routine and you used goto then you could only use it from 1 line of the program, but with call you can call it from aywhere.
    See this little snippet, "fire" is also called from somewhere else. PulseWms and delay 1ms are both reused.

    Code ( (Unknown Language)):
    1. fire
    2.     movlw D'13'
    3.     call pulseWms
    4.     call delay1ms
    5.     call delay1ms
    6.     call delay1ms
    7.     movlw D'7'
    8.     movwf count2
    9. pulse7
    10.     movlw 1
    11.     call pulseWms
    12.     call delay1ms
    13.     decfsz count2, F
    14.     goto pulse7
    15.     retlw 0
    16.  
    17.  
    18. pulseWms
    19.     movwf count
    20. pulseouter
    21.     movlw d'38'
    22.     movwf count3
    23. pulseinner
    24.     movlw b'00000100'
    25.     movwf GPIO
    26.     goto $+1
    27.     goto $+1
    28.     goto $+1
    29.     clrf GPIO
    30.     goto $+1
    31.     goto $+1
    32.     goto $+1
    33.     goto $+1
    34.     goto $+1
    35.     goto $+1
    36.     goto $+1
    37.     decfsz count3, F
    38.     goto pulseinner
    39.     decfsz count, F
    40.     goto pulseouter
    41.     retlw 0
    42.  
    43.  
    44. delay1ms:    ;
    45.     movlw 0xFF
    46.     movwf count
    47. loop1ms    
    48.     nop
    49.     decfsz count,F
    50.     goto loop1ms
    51.     retlw 0 ;delay1ms
     
    Last edited: Jun 5, 2010
  7. wannaBinventor

    Thread Starter Member

    Apr 8, 2010
    179
    4
    Is method A going to work if I want to have a program that requires outputs such as this?:

    If Switches 1 and 2 are pressed SIMULTANEOUSLY, do THIS.
    If Switches 2 and 3 are pressed SIMULTANEOUSLY, do THAT.

    Also, I've read in my book about the ", W" after the SUBWF instruction is given and the file is specified, yet the program I've written with method B works just as I intended. In fact, the book didn't show it being used after PORTA was subtracted from the W register.

    Are you sure this doesn't just apply to user files?
     
  8. wannaBinventor

    Thread Starter Member

    Apr 8, 2010
    179
    4
    Thanks for clearing that up.
     
  9. Markd77

    Senior Member

    Sep 7, 2009
    2,803
    594
    On reflection if they are all inputs it doesen't make any difference because writing to a pin set as an input does nothing unless it is changed to an output. If any of them were used for outputs things would go wrong.

    Not easily, but let us know what you are trying to achieve, there may be easier ways.
     
  10. MMcLaren

    Well-Known Member

    Feb 14, 2010
    759
    116
    Here's the most efficient sequence I've come up with for sampling and managing multiple switches (probably not for beginners). It uses a switch state latch ('swold') and simple 'parallel' logic to detect a "new press" state for each switch while ignoring the other switch states (*1).

    Executing the sequence at 10 to 50 msec intervals effectively debounces the switches. Each '1' bit in 'swnew' is a "new press". Clear the bit after testing and using it in your main program.


    Code ( (Unknown Language)):
    1. ;
    2. ;         ____---____-----_____   new switch sample
    3. ;  swold  _____---____-----____   switch state latch
    4. ;  delta  ____-__-___-____-____   changes, press or release
    5. ;         ____-______-_________   filter out release bits
    6. ;
    7.         comf    PORTA,W        ; sample active lo switches      |B0
    8.         andlw   b'01001100'    ; on RA6, RA3, and RA2 pins      |B0
    9.         xorwf   swold,W        ; changes (press or release)     |B0
    10.         xorwf   swold,F        ; update switch state latch      |B0
    11.         andwf   swold,W        ; filter out "new release" bits  |B0
    12.         iorwf   swnew,F        ; save "new press" bits          |B0
    13.  
    (*1)
    'new' = 1 and 'old' = 0 -> "new press"
    'new' = 0 and 'old' = 1 -> "new release"
    'new' = 1 and 'old' = 1 -> "still pressed"
    'new' = 0 and 'old' = 0 -> "still released"
     
Loading...