0

Architecture: ATmega8535

Development Board: STK200

My code basically displays from register r0 values on my LEDs switch light box. On board push buttons are connected to port A, and switch light box LEDs are connected to port C.

1000 0000
1100 0000

1110 000 1 - which shouldn't occur (the one at the end should be 0)

0111 0000
0011 1000
0001 1100
0000 1110
0000 0111
0000 0011
0000 0001
0000 0000



;Stack and Stack Pointer Addresses - Necessary for subroutines
        .equ     SPH    =$3E              ;High Byte Stack Pointer Address 
        .equ     SPL    =$3D              ;Low Byte Stack Pointer Address 
        .equ     RAMEND =$25F             ;Stack Address 

    ;Port Addresses 
        ;INPUT
        .equ     DDRA   =$1A               ;Port A Data Direction Register Address 
        .equ     PINA   =$19               ;Port A Input Address 

        ;OUTPUT
        .equ     PORTC  =$15              ;Port C Output Address 
        .equ     DDRC   =$14              ;Port C Data Direction Register Address 

    ;Register Definitions 
        .def     leds   =r0               ;Register to store data for LEDs 
        .def     temp   =r26              ;Temporary storage register 

    ;Set stack pointer to end of memory #Used for subroutines
        ldi    temp,high(RAMEND) 
        out    SPH,temp          ;Load high byte of end of memory address 
        ldi    temp,low(RAMEND) 
        out    SPL,temp          ;Load low byte of end of memory address 

    ;Setting registers for the game [Available registers: r22, r28]
        ;r4 the amount of times user can miss before game the restarts
        inc r4
        inc r4
        inc r4
    restartGame:    
        ;registers used for random subroutines
            clr r3 
            ;r2 - $0  

        ;Main game registers
        ldi r24,$0 //if 1 - Destroyer 2 - Battleship 3 - Aircraft Carrier
        ldi r25,$0 //if 1 - Left 2 - Right
        ldi r22,$0 //If 1 - user already shot the torpedo 0 - user didn't shot a torpedo yet
        //r3 - how many times overall has user missed
        //r29, r30 - used as 1st and 2nd loop counter respectively
        ldi r27,$01;

    ;Initialise input ports
         ldi    temp,$00 
         out    DDRA,temp         //Set Port A for input by sending $00 to direction register 
    ;Initialise output ports
         ldi    temp,$ff    
         out    DDRC,temp         //Set Port C for output by sending $FF to direction register 

    ;========================================GAME LOOP========================================;
                    gameLoop:   ldi r24, $03 ;3 LEDs ship
                            ldi r25, $02 ; moving right                             

                                rcall spawnShip //initialize ship on switch light box LEDs

                                cpi r25,$01
                                breq moveLeft 
                                cpi r25,$02
                                breq moveRight

                        moveLeft:   lsl leds
                                    out    PORTC,leds       //Display leds to port C 
                                    rcall delayCheck
                                    cp r0,r2            //If register is empty the ship escaped from the player hence exit the loop and spawn a new ship
                                    breq gameLoop
                                    rjmp moveLeft

                        moveRight:  lsr leds
                                    out    PORTC,leds       //Display leds to port C 
                                    rcall delayCheck
                                    cp r0,r2            //If register is empty the ship escaped from the player hence exit the loop and spawn a new ship
                                    breq gameLoop
                                    rjmp moveRight

    ;========================================GAME LOOP========================================;

    ;Subroutines

    //**Spawn Ship** - Initialising ship on switch light box LEDs (in phases every aircraft carrier is initially destroyer on frame 1 [1 LED] then it is a battleship on frame 2 [2 LEDs] on frame 3 it is a full aircraft carrier [3 LEDs])
    spawnShip:  cpi r25,$1
                breq spawnShipLeftD //Spawn ship on the right hand side with direction left
                cpi r25,$2
                breq spawnShipRightD //Spawn ship on the left hand side with direction right


        spawnShipRightD:    clr leds
                            rcall delayNoCheck
                            inc r0      //Initialise Destroyer
                            swap r0     //Speeds up changeDirLoop subroutine
                            rcall changeDirLoop
                            out PORTC, leds
                            rcall delayCheck

                            cpi r24,$2  //If the ship is a battleship increment the size by 1
                            breq spawnBattleShipRightD
                            cpi r24,$3  //If the ship is a aircraft carrier increment the size by 3 
                            breq spawnAircraftCarrierRightD
                            ret

            spawnBattleShipRightD:clr r0    //clr r0 hence was modified to 0x80 from 0x01 so incrementing that value would destroy our ship
                                 inc r0
                                 inc r0
                                 inc r0
                                 swap r0
                                 rcall changeDirLoop
                                 out PORTC, leds

                                 rcall delayCheck
                                 ret

            spawnAircraftCarrierRightD:rcall spawnBattleShipRightD //Every aircraft carrier is a battleship during 2nd frame of initialisation on LED switch light box
                                 clr r0
                                 inc r0
                                 inc r0
                                 inc r0
                                 inc r0
                                 inc r0
                                 inc r0
                                 inc r0


                                 swap r0
                                 rcall changeDirLoop
                                 out PORTC, leds

                                 rcall delayCheck
                                 ret

                changeDirLoop:  rol r0      //Initially every ship is spawned on the right side of the LED light box so we rotate left until, negative flag turns on
                                brpl changeDirLoop
                                ret

    //Spawn Ship

    //*Check Press* - check button was pressed, restrict user to pressing only one buttone at once by checking register with powers of 2
    checkPress:             cpi r22,$01 //Check if user missed this turn
                            breq checkButtons //If user missed this turn we invert r19 to be always false so it will check again methods below which won't speed up the ship after missing

                            in     r19, PINA  //put the pin A value in r19

            checkButtons:   com    r19   //basic state of switches is 1111 1111 so invert to get 0000 0000

                            cpi r19,$01
                            breq   press  //If r19 is 0xb0000 0001
                            cpi r19,$02
                            breq   press  //If r19 is 0xb0000 0010 
                            cpi r19,$04
                            breq   press  //If r19 is 0xb0000 0100 
                            cpi r19,$08
                            breq   press  //If r19 is 0xb0000 1000
                            cpi r19,$10
                            breq   press  //If r19 is 0xb0001 0000
                            cpi r19,$20
                            breq   press  //If r19 is 0xb0010 0000 
                            cpi r19,$40
                            breq   press  //If r19 is 0xb0100 0000 
                            cpi r19,$80
                            breq   press  //If r19 is 0xb1000 0000
                missedReturn:ret


                            press:  and  r19, r0  //It will only be equal to more than 0 if the ship was shot
                                    cp   r19, r2  //Compare to empty register
                                    brne shotDown
                                    cp   r19, r2
                                    breq missed

                                shotDown:   clr leds //Destroy the ship
                                            out PORTC, leds 
                                            rcall delayNoCheck
                                            subi r27, $05//Speed up the game
                                            ;ADD SCORE
                                            rjmp gameLoop //Spawn a new ship

                                missed:     ldi r22, $01 //Has user missed this turn
                                            inc r3 //Increment overall times user missed
                                            cp r3,r4
                                            breq restart //If user missed 3 times start over

                                            rjmp missedReturn

                                        restart:    ldi temp, $FF
                                                    out PORTC, temp
                                                    rjmp restartGame

    //Check Press

    //*Delay*
    delayCheck:  mov    r31,r27     //Copy value of r27 into r31     
        loop3:   ldi    r30,$01  ;02        //Initialise 2nd loop counter ;$DA - default Alternate - 1F
        loop2:   ldi    r29,$01 ;1f          //Initialise 1st loop counter ;$FE - default Alternate - D6
        loop1:   rcall checkPress
                 dec    r29              //Decrement the 1st loop counter 
                 brne   loop1            //and continue to decrement until 1st loop counter = 0 
                 dec    r30              //Decrement the 2nd loop counter 
                 brne   loop2            //If the 2nd loop counter is not equal to zero repeat the 1st loop, else continue 
                 dec    r31              //Decrement the 3rd loop counter
                 brne   loop3            //If the 3rd loop counter is not equal to zero repeat the 2nd loop, else continue
                 ret

    delayNoCheck:ldi    r31,$01     ;06 //Copy value of r27 into r31     
        loop4:   ldi    r30,$01  ;DA        //Initialise 2nd loop counter ;$DA - default Alternate - 1F
        loop5:   ldi    r29,$01 ;FE         //Initialise 1st loop counter ;$FE - default Alternate - D6
        loop6:   dec    r29              //Decrement the 1st loop counter 
                 brne   loop6            //and continue to decrement until 1st loop counter = 0 
                 dec    r30              //Decrement the 2nd loop counter 
                 brne   loop5            //If the 2nd loop counter is not equal to zero repeat the 1st loop, else continue 
                 dec    r31              //Decrement the 3rd loop counter
                 brne   loop4            //If the 3rd loop counter is not equal to zero repeat the 2nd loop, else continue
                 ret

    //Delay

I've been going through this code for a few hours and I can't figure out why it displays at one point on LEDs 1110 0001 instead of 1110 0000

All I know that this bug happens when delayCheck is executed which points to subroutine checkPress but r19 is empty since I don't press anything so I should go straight to return and finish the loop.

Higeath
  • 5
  • 3

1 Answers1

1

As any instruction set reference will tell you ROL rotates through carry, so it brings CF into the least significant bit. It just so happens that CF is 1 so you will get that led set. You can fix that by using LSL instead.

That said, you have a crazy overcomplicated way to load constants. If, instead of this:

clr r0
inc r0
inc r0
inc r0
inc r0
inc r0
inc r0
inc r0
swap r0
rcall changeDirLoop

you simply use a single ldi leds, $0xe0 then not only will it fix your bug, but it will also make the program more readable and efficient ;)

Jester
  • 52,795
  • 4
  • 67
  • 108
  • I don't think I can use ldi on leds -> r0 since from r0-r15 those are general registers that will not work with immidiate methods, but I will try it as soon as I get a chance – Higeath Mar 11 '16 at 18:26
  • Yeah you are right. Okay, then do `ldi r16, $0xe0; mov r0, r16` or just assign `leds` to `r16` ;) – Jester Mar 11 '16 at 18:32
  • Oh you can move it to r0 then Ill use my temp register thanks :) I got really frustrated today – Higeath Mar 11 '16 at 18:33