Learning Assembly on PIC - efficiency question

Thread Starter

wannaBinventor

Joined Apr 8, 2010
180
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.
 

Markd77

Joined Sep 7, 2009
2,806
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.
 

jpanhalt

Joined Jan 18, 2008
11,087
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
 

eblc1388

Joined Nov 28, 2008
1,542
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?
 

Thread Starter

wannaBinventor

Joined Apr 8, 2010
180
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?
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?
 

Markd77

Joined Sep 7, 2009
2,806
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.

Rich (BB code):
fire
    movlw D'13'
    call pulseWms
    call delay1ms
    call delay1ms
    call delay1ms
    movlw D'7'
    movwf count2
pulse7
    movlw 1
    call pulseWms
    call delay1ms
    decfsz count2, F
    goto pulse7
    retlw 0


pulseWms
    movwf count
pulseouter
    movlw d'38'
    movwf count3
pulseinner
    movlw b'00000100'
    movwf GPIO
    goto $+1
    goto $+1
    goto $+1
    clrf GPIO
    goto $+1
    goto $+1
    goto $+1
    goto $+1
    goto $+1
    goto $+1
    goto $+1
    decfsz count3, F
    goto pulseinner
    decfsz count, F
    goto pulseouter
    retlw 0


delay1ms:    ;
    movlw 0xFF
    movwf count
loop1ms    
    nop
    decfsz count,F
    goto loop1ms
    retlw 0 ;delay1ms
 
Last edited:

Thread Starter

wannaBinventor

Joined Apr 8, 2010
180
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.
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?
 

Markd77

Joined Sep 7, 2009
2,806
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.
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.

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.
Not easily, but let us know what you are trying to achieve, there may be easier ways.
 

MMcLaren

Joined Feb 14, 2010
861
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.


Rich (BB code):
;
;         ____---____-----_____   new switch sample
;  swold  _____---____-----____   switch state latch
;  delta  ____-__-___-____-____   changes, press or release
;         ____-______-_________   filter out release bits
;
        comf    PORTA,W        ; sample active lo switches      |B0
        andlw   b'01001100'    ; on RA6, RA3, and RA2 pins      |B0
        xorwf   swold,W        ; changes (press or release)     |B0
        xorwf   swold,F        ; update switch state latch      |B0
        andwf   swold,W        ; filter out "new release" bits  |B0
        iorwf   swnew,F        ; save "new press" bits          |B0
(*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"
 
Top