架构:ATmega8535
开发板:STK200
我的代码基本上显示在我的LED开关灯箱上的寄存器r0值。板载按钮连接到端口A,开关灯箱LED连接到端口C.
1000 0000
1100 0000
1110 000
1 - 不应该发生(最后一个应该是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
我已经经历了几个小时的代码,我无法弄清楚为什么它会在LED 1110 0001而不是1110 0000
上的某一点显示所有我知道这个错误发生在执行delayCheck时指向子程序checkPress但r19为空,因为我没有按任何东西所以我应该直接返回并完成循环。
答案 0 :(得分:1)
任何指令集引用都会告诉你ROL
通过进位旋转,因此它会将CF
带入最低有效位。恰好CF
是1
所以你会得到那个led套装。您可以使用LSL
来解决此问题。
那就是说,你有一个疯狂的过于复杂的方式来加载常量。如果,而不是:
clr r0
inc r0
inc r0
inc r0
inc r0
inc r0
inc r0
inc r0
swap r0
rcall changeDirLoop
您只需使用一个ldi leds, $0xe0
,这样不仅可以修复您的错误,而且还可以使程序更具可读性和效率;)