Alberto Cid
acid@ee.cornell.edu |
May 5th, 1999 | Nicole Banash
nb24@cornell.edu |
This project, as well as giving us a chance to design a fun game, gave us the opportunity to use several pieces of programs which we had developed for previous labs throughout the semester. In particular, many features of the musical tone generator which we developed for lab 3 were very useful for this project. Using the 8535 also gave us an opportunity to use a new evaluation board, which we had not used in previous labs.
We did not have to worry about timing precision in our project. The times that we decided on when programming our delay loops were based on delay loops calculated for previous projects or on our experiences of playing the game during testing. The only timing that we did carefully calculate was the decrease in note playing time for level 2. We were more careful with this calculation because we needed to be able to decrease the note time in 40 equal steps, one step for each level, but the time that the notes are played had to remain long enough that the player was still able to hear the individual tones and see the LED's light up. We chose to decrease the note playing time by 0.75 m Sec for each level, so that there is a noticeable change in speed after some levels, but the game does not become too fast to be played. The game starts with a note playing time of 0.66 seconds and will finish with a note playing time of 0.35 seconds on the fortieth level. The amount of time that the game waits for the player to press a button before they loose the game remains constant.
Calculation of the delay loops was carried out by counting the number of instruction cycles within each loop and multiplying this by the instruction cycle time of 0.25 m Sec .
Although we originally wished to use colored LED's with our program we were unable to supply external LED's with enough power for them to work properly. We were unable to determine why our LED's were not working properly and only the first five LED's would light up. When we measured the voltages being supplied to the LED's, enough voltage was present on all pins, however, the last three LED's remained extremely dim. This problem could be due to either the external LED's not receiving enough current, or the evaluation board being damaged. Enough power is present to run all of the LED's on the evaluation board.
Another problem we noticed while testing the external LED's is that pressing the buttons when the LED's were on the breadboard was a bit awkward. It would probably be easier to play the game if the buttons and switches were a bit more spread out. As a result, a future improvement would be to either use external switches which could be positioned near the LED's on the breadboard, or to use LED's which are also switches themselves. Either of these features would make the program more user friendly.
A second improvement would be to change the method that is used to let the player select a level. Unless the player is familiar with the format of our game, although LED's 1 and 2 are turned on until a level is selected, there is no way the player will know that it is necessary to select a level to start the game. As a result, it would be a good idea to implement a separate switch which could be permanently set on a level and read only at the beginning of the game. Alternatively, it would be possible to attach a small LCD screen which would display a message telling the player to select a level of play, however, as this would require a lot of extra code, the first possibility would probably be better.
Other, small improvements which we could have made to our program were to add a winning song or a scoring method, however, we decided that these features were not necessary for our program.
A final improvement that we could make to this program is to change our method of debouncing the buttons. We chose to use delay loops between successive reads of the buttons, but it would speed up the game if we instead checked to see that the button was released before beginning another read of the switches. This would allow the player more control over the speed of the game, and would make the game more fun for people with faster reflexes.
.device AT90S8535
.def memlo =r9
.def cntstr3 =r10
.def cntstr1 =r12
.def cntstr2 =r13
.def time =r14
.def count1 =r16
.def count2 =r17
.def savSREG =r18
.def wreg =r19
.def count3 =r20
.def butime =r21
.def reload =r22
.def lights =r23
.def spk =r24
.def tmer =r26
.def temp1 =r27
.def temp2 =r28
.def temp3 =r29
.equ PreScale=1
.equ do=0xEE
;freq. for the notes
.equ re=0xD4
.equ mi=0xBD
.equ fa=0xB3
.equ sol=0x9F
.equ la=0x8E
.equ si=0x7E
.equ do2=0x77
;**************************************
.dseg
;define variable strings to be tranmitted from RAM
;this defines a maximum storage length of 40
cntstr: .byte 41 ;a 40
digit count + a zero terminate
;**************************************
.cseg
.org $0000
rjmp RESET ;reset entry vector
reti
reti
reti
reti
reti
reti
reti
reti
rjmp
timer
reti
reti
reti
reti
reti
reti
reti
;begin program
;attach LEDS to port B
;attach buttons to port D
;attach speaker to port C
RESET: ldi wreg, LOW(RAMEND) ;setup
stack pointer
out
SPL, wreg
ldi
wreg, HIGH(RAMEND)
out
SPH, wreg
;set up portB as output for LED's
ser
wreg
;Set portB to all outputs
out
DDRB,wreg
ldi
temp1, PreScale ;Prescale
timer by 1
out
TCCR1B, temp1
;set up counters
ldi
count1, 0xFF
ldi
count2, 0xF0
mov
cntstr1, count1
mov
cntstr2, count2
ldi
count1, 0x0A
mov
cntstr3, count1
;set up and turn on timer1
ldi
wreg, 0x41
out
TCCR1B, wreg
;set up speaker on Port C
ser
wreg
out
DDRC, wreg
ldi
spk, 0
;set up port D buttons as input
ldi
wreg, 0x00
out
DDRD, wreg
;set up possible note time
ldi
wreg, 200
mov
time, wreg
;set up pointer to highest RAM array location
ldi
wreg, 0x60
mov
memlo, wreg
;prescale timer 0
ldi
wreg, 3 ;prescale timer
by clk/64
out
TCCR0, wreg
;initialize text pointer before turning on interrupts
ldi
ZL, LOW(cntstr) ;ptr to
RAM
ldi
ZH, HIGH(cntstr)
sei
;turn on interrupts
;flash all LEDS tentatively assigned to portb
main: ldi wreg, 0x00
out
PORTB, wreg
;flash all LED's on
rcall song1
rcall delay
;delay subroutine so player can see lights
ldi
wreg, 0xF9
out
PORTB, wreg
;flash all LED's off, leaving on LED's 1 and 2
;until player selects a level
loop1: ldi wreg, 0xFF
sbis
PIND, 1 ;check for level 1
ldi
wreg, 1
sbis
PIND, 2 ;check for level 2
ldi
wreg, 2
cpi
wreg, 0xFF
breq
loop1 ;loop
until level pressed
cpi
wreg, 2
brne
sta1
set
;set T bit to indicate level=2.
sta1: ldi wreg, 0xFF
;turn of all LED's
out
PORTB, wreg
;random number generator
start: in wreg, TCNT1L
;keep
in
temp2, TCNT1H
;discard
andi
wreg, 0x07
;keep last three bits of this register to map to lights and tones
mov
temp1, memlo
;set up extra array pointer
cpi
temp1, 0x88
brne
noreset
win: rjmp win
;Spin loop when player wins
; load next digit in RAM
noreset:mov ZL, memlo
ldi
ZH, 0x00
st
Z, wreg
;load the button digit into RAM
inc
memlo
inc
ZL
ser
wreg
;zero string terminator to RAM - we chose to use FF as 00 maps to
a switch
st
Z, wreg
;start at beginning of RAM and play all the data
;now the pointer to the variable message in RAM
ldi
ZL, LOW(cntstr) ;ptr to RAM
ldi
ZH, HIGH(cntstr)
plystr: ld r0,Z
;button is in r0
inc
ZL
mov
wreg,r0
cpi
wreg, 0xFF ;see if at end of message
brne
here
rjmp
end1
;If so, jump to next part of program
; otherwise play note and set up lights
;poll for which note should be played
here: cpi wreg, 7
brne
one
ldi
tmer, do
ldi
lights, 0x7F
rjmp
outn
one: cpi wreg, 6
brne
two
ldi
tmer, re
ldi
lights, 0xBF
rjmp
outn
two: cpi wreg, 5
brne
three
ldi
lights, 0xDF
ldi
tmer, mi
rjmp
outn
three: cpi wreg, 4
brne
four
ldi
lights, 0xEF
ldi
tmer, fa
rjmp
outn
four: cpi wreg, 3
brne
five
ldi
lights, 0xF7
ldi
tmer, sol
rjmp
outn
five: cpi wreg, 2
brne
six
ldi
lights, 0xFB
ldi
tmer, la
rjmp
outn
six: cpi wreg, 1
brne
seven
ldi
tmer, si
ldi
lights, 0xFD
rjmp
outn
seven: cpi wreg, 0
ldi
lights, 0xFE
ldi
tmer, do2
rjmp
outn
;output LEDs
outn:
out
PORTB, lights
;play note
;turn on timer ovfl interrupt timer0
ldi
Reload, 0xFF
;load first freq into timer0
sub
Reload, tmer
out
TCNT0, Reload
ldi
wreg,0x01 ;enable timer interrupt
out
TIMSK, wreg
wait2: mov temp1, cntstr1
; wait while note is played
mov
wreg, cntstr2
mov
temp2, cntstr3
one2: nop
dec
temp1
brne
one2
dec
wreg
brne
one2
dec
temp2
brne
one2
;turn off timer0 ovfl interrupt
ldi
wreg, 0x00
out
TIMSK, wreg
;turn off lights
ser
lights
out
PORTB, lights
;silence time
ldi
temp1, 0xFF
ldi
temp2, 0xFF
one3: nop
dec
temp1
brne
one3
dec
temp2
brne
one3
;loop back to get next note out of RAM
rjmp
plystr
;if done playing all notes
;wait for button pressed
end1: ldi ZL, LOW(cntstr)
;ptr to RAM
ldi
ZH, HIGH(cntstr)
end4: ld r0,Z
inc
ZL
mov
butime, r0 ;button is in r0
cpi
butime, 0xFF
;See if at end of RAM array
brne
next
rjmp
end2
next: ldi temp1, 0xFF
;load a counter with the time allowed for player
ldi
temp3, 0xFF
;to press button before losing
ldi
count1, 0x03
end3: ldi temp2, 0xFF
pressed.
in
wreg, PIND
cpi
wreg, 0x7F
brne
six1
ldi
temp2, 0x07
ldi
lights, 0x7F
ldi
tmer, do
rjmp
out1
six1: cpi wreg, 0xBF
brne
five1
ldi
temp2, 0x06
ldi
lights, 0xBF
ldi
tmer, re
rjmp
out1
five1: cpi wreg, 0xDF
brne
four1
ldi
temp2, 0x05
ldi
lights, 0xDF
ldi
tmer, mi
rjmp
out1
four1: cpi wreg, 0xEF
brne
three1
ldi
temp2, 0x04
ldi
tmer, fa
ldi
lights, 0xEF
rjmp
out1
three1: cpi wreg, 0xF7
brne
two1
ldi
temp2, 0x03
ldi
tmer, sol
ldi
lights, 0xF7
rjmp
out1
two1: cpi wreg, 0xFB
brne
one1
ldi
temp2, 0x02
ldi
lights, 0xFB
ldi
tmer, la
rjmp
out1
one1: cpi wreg, 0xFD
brne
zero1
ldi
temp2, 0x01
ldi
lights, 0xFD
ldi
tmer, si
rjmp
out1
zero1: cpi wreg, 0xFE
brne
out1
ldi
temp2, 0x00
ldi
tmer, do2
ldi
lights, 0xFE
rjmp
out1
out1: cpi temp2, 0xFF
;if don't have button pressed check if out of time
brne gotit ;jump if have a valid number from RAM array
;updating timer to see if user is out of time
dec
temp1
;else decrease counter
cpi
temp1, 0xFF
brne
down1
dec
temp3
cpi
temp3, 0xFF
brne
down1
dec
count1
cpi
count1, 0x00
breq
error
;jump to game over if player is out of time
down1: rjmp end3
;compare if same value from button as from RAM
gotit: cp butime, temp2
;If equal, get next value
brne
error ;if not
equal go to end of game
;LED should not turn on if wrong button was pressed
out
PORTB, lights ;else output
lights
;play note
;turn on timer ovfl interrupt timer0
ldi
Reload, 0xFF
;load first freq into timer0
sub
Reload, tmer
out
TCNT0, Reload
ldi
wreg,0x01 ;enable timer0 overflow interrupt
out
TIMSK, wreg
rcall delay ;delay subroutine before reading next button
;turn off timer0 ovfl interrupt
ldi
wreg, 0x00
out
TIMSK, wreg
ldi
temp2, 0xFF ;turn off lights
out
PORTB, temp2
rjmp end4
;if match between RAM and pressed button repeat procedure.
end2: rcall delay
;call delay subroutine before beginning again
brts
chnge
rjmp
start ;compare
if level=2 so variable clock
chnge: ldi wreg, 0x10
;if level=2, decrease count
sub
cntstr2, wreg
ldi
wreg, 0x00
sbc
cntstr3, wreg
rjmp start
;and go back to start of game, generating next random number
;error procedure
error: mov wreg, memlo
subi
wreg, 0x60 ;display level player lost on
com
wreg
out
PORTB, wreg
rcall song2
;jump to play game over song
display level
rcall delay
rjmp
reset ;reset
game
;******** Timer0 overflow interrupt service routine**********
timer: in savSREG, SREG ;save the status reg
com
spk
out
PORTC, spk
;send out speaker value
ldi
Reload, 0xFF
sub
Reload, tmer
out
TCNT0, Reload
out
SREG, savSREG ;restore status reg
reti
;**********************************************************
;***** Delay subroutine used throughout program
delay: ldi temp1, 0xF
ldi
wreg, 0x00
ldi
temp3, 0x07
oned2: nop
dec
temp1
brne
oned2
dec
wreg
brne
oned2
dec
temp3
brne
oned2
ret
;*******************************************************************************
song1: ldi temp3,0x02
;start song subroutine
ldi
tmer, do
rcall play
ldi
temp3,0x02
ldi
tmer, re
rcall play
ldi
temp3,0x02
ldi
tmer, mi
rcall play
ldi
temp3,0x03
ldi
tmer, fa
rcall play
ldi
temp3,0x03
ldi
tmer, mi
rcall play
ldi
temp3,0x03
ldi
tmer, fa
rcall play
reti
song2: ldi temp3,0x01
;Game Over song subroutine
ldi
tmer, do2
rcall play
ldi
temp3,0x01
ldi
tmer, si
rcall play
ldi
temp3,0x01
ldi
tmer, la
rcall play
ldi
temp3,0x01
ldi
tmer, sol
rcall play
ldi
temp3,0x01
ldi
tmer, fa
rcall play
ldi
temp3,0x01
ldi
tmer, mi
rcall play
ldi
temp3,0x01
ldi
tmer, re
rcall play
ldi
temp3,0x07
ldi
tmer, do
rcall play
reti
;*** subroutine to play a note ***************************
play: ldi Reload, 0xFF
;load first freq into timer0
sub
Reload, tmer
out
TCNT0, Reload
ldi
wreg,0x01
;enable timer interrupt
out
TIMSK, wreg
ldi
temp1, 0x00
ldi
temp2, 0x00
dly1: nop
;time given by temp3 to play the note
dec
temp1
brne
dly1
dec
temp2
brne
dly1
dec
temp3
brne
dly1
ldi
wreg, 0x00 ;turn off timer0 ovfl interrupt
out
TIMSK, wreg
dly2: nop
;small silence time for between notes
dec
temp1
brne
dly2
dec
temp2
brne
dly2
ret