Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

XOR Function with 2 pushbuttons and an LED(assembly project)

Status
Not open for further replies.

Cantafford

Member
Ok last thread I will do today I swear.

I'm trying to implement an XOR function in assembly. I have two push buttons. If they are in different positions(one pressed one not pressed) the led will light up. Otherwise the LED will stay off.

This is how I connected them:
2zz6pty.png


And this is the code I wrote:
Code:
#include "p16F870.inc"

; CONFIG
; __config 0xFF3A
 __CONFIG _FOSC_HS & _WDTE_OFF & _PWRTE_OFF & _CP_OFF & _BOREN_OFF & _LVP_OFF & _CPD_OFF & _WRT_ALL


RES_VECT  CODE    0x0000            ; processor reset vector
    GOTO    MAIN                  ; go to beginning of program

; TODO ADD INTERRUPTS HERE IF USED

MAIN_PROG CODE                      ; let linker place main program

MAIN

    BANKSEL ADCON1    ;(RA0 and RA1 are digital)
    movlw b'00000111'
    movwf ADCON1
   
    movlw b'00000011' ;buttons(RA0, RA1 are inputs)
    movwf TRISA
   
    movlw b'11111100' ;leds(RB0, RB1 are outputs)
    movwf TRISB
   
    BANKSEL PORTB ; leds are initially off
    clrf PORTB
   
     
    btfss PORTA, RA0 ;check if button on RA0 is pressed | 'f' is '0', the next instruction is executed
    goto FirstButtonPressed
    goto FirstButtonNotPressed
   
   
    GOTO MAIN  
   
    FirstButtonNotPressed ;RA0 = 1
    btfss PORTA, RA1  ;If RA1 = 0 execute next instruction else skip
    bsf PORTB, RB0 
    bcf PORTB, RB0 
    return
   
    FirstButtonPressed ;RA0 = 0
    btfss PORTA, RA1 ;If RA1 = 0 execute next instruction else skip
    bcf PORTB, RB0 
    bsf PORTB, RB0 
    return

    END

My program won't run as expected. If I press button on RA0 the LED lights up no matter what position button on RA1 is on. Please help me correct this if possible. Thank you.
 
If you are using RETURN then you have to use CALL to get there, not GOTO.

When you use GOTO the program counter is not pushed onto the stack. So the next RETURN is disastrous.

Read:
**broken link removed**

Then we can talk about switch bouncing/debouncing.
 
Also, it's not good practice to set pins as inputs that aren't actually connected to anything. (Your RB2 through RB7.) These floating pins can cause problems. It's much better to set unused pins as outputs.

Which means you might as well set TRISC to b'00000000' as well.
 
You know, they make 74HC32 chips that have FOUR of these circuits for only 32 cents each. And they produce the output in about 6 nanoseconds with no programming or debugging!

(Just Kidding) I know this is about learning, I just couldn't stop myself. Maybe it's because Halloween is coming.


To avoid re-initializing every time, I would put GOTO something right before this line instead of GOTO MAIN.

btfss PORTA, RA0 ;check if button on RA0 is pressed | 'f' is '0', the next instruction is executed

That way it repeats the input pin test and adjusts the outputs but will not keep re initializing the I/O pins. I guess that's what Ian is referring to as the superloop.
 
First off...there is no such thing as "input" or "output" mode. That's just Microchip's abstract way of explaining it.

Clearing a TRIS bit enables the output drivers. When enabled, the pin can only be internally driven to one of two possible states...high or low.

Setting a TRIS bit disables the output drivers. When disabled and not externally driven, the pin is in a 3rd state...or "tristate"...which is a high impedance state...basically disconnected (TRIS is actually short for TRISTATE).

This means the pin can be treated as an input as its externally driven state can be read from the PORT register files. However, by placing a pull up resistor on the pin, it now works as an open drain output with a weak pull up. Writing a 0 to the pins port latch allows the pin to be pulled low when clearing it's corresponding TRIS bit, while being pulled high by the weak pull up when setting its TRIS bit.

This information allows you to do some clever programming that will make the pin behave as an open drain output.
 
Last edited:
Is there any reason you don't just use the built-in XORWF instruction? e.g.
Code:
movfw PORTA
movwf temp
rrf temp,w
xorwf temp
The LSb of temp will now be RA0 XOR RA1
 
You know, they make 74HC32 chips that have FOUR of these circuits for only 32 cents each. And they produce the output in about 6 nanoseconds with no programming or debugging!

(Just Kidding) I know this is about learning, I just couldn't stop myself. Maybe it's because Halloween is coming.


To avoid re-initializing every time, I would put GOTO something right before this line instead of GOTO MAIN.



That way it repeats the input pin test and adjusts the outputs but will not keep re initializing the I/O pins. I guess that's what Ian is referring to as the superloop.

Ok. Got it. I have modified the code like this:

Code:
#include "p16F870.inc"

; CONFIG
; __config 0xFF3A
 __CONFIG _FOSC_HS & _WDTE_OFF & _PWRTE_OFF & _CP_OFF & _BOREN_OFF & _LVP_OFF & _CPD_OFF & _WRT_ALL


RES_VECT  CODE    0x0000            ; processor reset vector
    GOTO    MAIN                  ; go to beginning of program

; TODO ADD INTERRUPTS HERE IF USED

MAIN_PROG CODE                      ; let linker place main program

MAIN

    BANKSEL ADCON1    ;(RA0 and RA1 are digital)
    movlw b'00000111'
    movwf ADCON1
   
    movlw b'00000011' ;buttons(RA0, RA1 are inputs)
    movwf TRISA
   
    movlw b'00000000' ;leds(RB0, RB1 are outputs)
    movwf TRISB
   
    BANKSEL PORTB ; leds are initially off
    clrf PORTB
     
    loop
    btfss PORTA, RA0 ;check if button on RA0 is pressed | 'f' is '0', the next instruction is executed
    goto FirstButtonPressed
    goto FirstButtonNotPressed
   
   
    FirstButtonNotPressed ;RA0 = 1
    btfss PORTA, RA1  ;If RA1 = 0 execute next instruction else skip
    bsf PORTB, RB1 
    bcf PORTB, RB1 
    goto loop
   
    FirstButtonPressed ;RA0 = 0
    btfss PORTA, RA1 ;If RA1 = 0 execute next instruction else skip
    bcf PORTB, RB1 
    bsf PORTB, RB1 
    goto loop

    END

Now the simulation behaves as this:

If both switches are not pressed the LED stays off(good).
If I press switch on RA0 the LED lights up(good).
If I press switch on RA1 the LED flashes real fast(not good, it should be on).
If I press both switches the LED flashes real fast(just like when I press RA1 only. Again not good).

:(
 
Looky here.... test and skip.... if RA0 = 1 then bcf POTRB,RB1...

THEN!!! if RA0 = 0 it sets RB1 THEN!! clears it!!!
Code:
    FirstButtonNotPressed ;RA0 = 1
    btfss PORTA, RA1  ;If RA1 = 0 execute next instruction else skip
    bsf PORTB, RB1
    bcf PORTB, RB1
    goto loop



Code:
#include "p16F870.inc"

; CONFIG
; __config 0xFF3A
 __CONFIG _FOSC_HS & _WDTE_OFF & _PWRTE_OFF & _CP_OFF & _BOREN_OFF & _LVP_OFF & _CPD_OFF & _WRT_ALL


RES_VECT  CODE    0x0000            ; processor reset vector
    GOTO    MAIN                  ; go to beginning of program

; TODO ADD INTERRUPTS HERE IF USED

MAIN_PROG CODE                      ; let linker place main program

MAIN

    BANKSEL ADCON1    ;(RA0 and RA1 are digital)
    movlw b'00000111'
    movwf ADCON1
   
    movlw b'00000011' ;buttons(RA0, RA1 are inputs)
    movwf TRISA
   
    movlw b'00000000' ;leds(RB0, RB1 are outputs)
    movwf TRISB
   
    BANKSEL PORTB ; leds are initially off
    clrf PORTB
     
    loop
    btfss PORTA, RA0 ;check if button on RA0 is pressed | 'f' is '0', the next instruction is executed
    goto FirstButtonPressed
    goto FirstButtonNotPressed
   
   
    FirstButtonNotPressed ;RA0 = 1
    btfss PORTA, RA1  ;If RA1 = 0 execute next instruction else skip
    goto on1
    bsf PORTB, RB1
    goto loop
on1
    bcf PORTB, RB1
    goto loop
   
    FirstButtonPressed ;RA0 = 0
    btfss PORTA, RA1 ;If RA1 = 0 execute next instruction else skip
    goto on2
    bcf PORTB, RB1 
    goto loop
on2
    bsf PORTB, RB1
    goto loop

    END
Now only one will be executed!!
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top