程序集在从未设置的 LED 灯箱上显示来自寄存器的值
Assembly display a value from register on LEDs light box that is never set
架构: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 =E ;High Byte Stack Pointer Address
.equ SPL =D ;Low Byte Stack Pointer Address
.equ RAMEND =F ;Stack Address
;Port Addresses
;INPUT
.equ DDRA =A ;Port A Data Direction Register Address
.equ PINA = ;Port A Input Address
;OUTPUT
.equ PORTC = ;Port C Output Address
.equ DDRC = ;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 - [=11=]
;Main game registers
ldi r24,[=11=] //if 1 - Destroyer 2 - Battleship 3 - Aircraft Carrier
ldi r25,[=11=] //if 1 - Left 2 - Right
ldi r22,[=11=] //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,;
;Initialise input ports
ldi temp,[=11=]
out DDRA,temp //Set Port A for input by sending [=11=] 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, ;3 LEDs ship
ldi r25, ; moving right
rcall spawnShip //initialize ship on switch light box LEDs
cpi r25,
breq moveLeft
cpi r25,
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,
breq spawnShipLeftD //Spawn ship on the right hand side with direction left
cpi r25,
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, //If the ship is a battleship increment the size by 1
breq spawnBattleShipRightD
cpi r24, //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, //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,
breq press //If r19 is 0xb0000 0001
cpi r19,
breq press //If r19 is 0xb0000 0010
cpi r19,
breq press //If r19 is 0xb0000 0100
cpi r19,
breq press //If r19 is 0xb0000 1000
cpi r19,
breq press //If r19 is 0xb0001 0000
cpi r19,
breq press //If r19 is 0xb0010 0000
cpi r19,
breq press //If r19 is 0xb0100 0000
cpi r19,
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, //Speed up the game
;ADD SCORE
rjmp gameLoop //Spawn a new ship
missed: ldi r22, //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, ;02 //Initialise 2nd loop counter ;$DA - default Alternate - 1F
loop2: ldi r29, ;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, ;06 //Copy value of r27 into r31
loop4: ldi r30, ;DA //Initialise 2nd loop counter ;$DA - default Alternate - 1F
loop5: ldi r29, ;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 是空的,因为我没有按任何东西,所以我应该直接进入 return 并完成循环。
因为任何指令集参考都会告诉您 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, [=16=]xe0
然后它不仅会修复你的错误,而且还会使程序更具可读性和效率;)
架构: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 =E ;High Byte Stack Pointer Address
.equ SPL =D ;Low Byte Stack Pointer Address
.equ RAMEND =F ;Stack Address
;Port Addresses
;INPUT
.equ DDRA =A ;Port A Data Direction Register Address
.equ PINA = ;Port A Input Address
;OUTPUT
.equ PORTC = ;Port C Output Address
.equ DDRC = ;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 - [=11=]
;Main game registers
ldi r24,[=11=] //if 1 - Destroyer 2 - Battleship 3 - Aircraft Carrier
ldi r25,[=11=] //if 1 - Left 2 - Right
ldi r22,[=11=] //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,;
;Initialise input ports
ldi temp,[=11=]
out DDRA,temp //Set Port A for input by sending [=11=] 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, ;3 LEDs ship
ldi r25, ; moving right
rcall spawnShip //initialize ship on switch light box LEDs
cpi r25,
breq moveLeft
cpi r25,
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,
breq spawnShipLeftD //Spawn ship on the right hand side with direction left
cpi r25,
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, //If the ship is a battleship increment the size by 1
breq spawnBattleShipRightD
cpi r24, //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, //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,
breq press //If r19 is 0xb0000 0001
cpi r19,
breq press //If r19 is 0xb0000 0010
cpi r19,
breq press //If r19 is 0xb0000 0100
cpi r19,
breq press //If r19 is 0xb0000 1000
cpi r19,
breq press //If r19 is 0xb0001 0000
cpi r19,
breq press //If r19 is 0xb0010 0000
cpi r19,
breq press //If r19 is 0xb0100 0000
cpi r19,
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, //Speed up the game
;ADD SCORE
rjmp gameLoop //Spawn a new ship
missed: ldi r22, //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, ;02 //Initialise 2nd loop counter ;$DA - default Alternate - 1F
loop2: ldi r29, ;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, ;06 //Copy value of r27 into r31
loop4: ldi r30, ;DA //Initialise 2nd loop counter ;$DA - default Alternate - 1F
loop5: ldi r29, ;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 是空的,因为我没有按任何东西,所以我应该直接进入 return 并完成循环。
因为任何指令集参考都会告诉您 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, [=16=]xe0
然后它不仅会修复你的错误,而且还会使程序更具可读性和效率;)