Appendix A
SIMON Project Source Code
Note: To save this code as an .asm file, click on the hyperlink and save the file to disk; otherwise, it opens in Notepad.
; The game of Simon
.include "c:\users\geiger\4414def.inc" ; Will likely have to change
; this file name
.device AT90S4414 ; Specify chip to the assembler
.def save =r1 ; SREG save location
.def maxnum =r2 ; Maximum wait time for mode 2
; Corresponds to level of difficulty
.def minnum =r3 ; Minimum wait time for mode 2
; Corresponds to level of difficulty
.def waitval =r4 ; Current number of T1 interrupts
; for which I want to wait
.def level =r5 ; Level of difficulty (not actually
; used in Mode 2, but used in Mode 1)
.def r30save =r6 ; Save registers used in outstr
.def r31save =r7 ; subroutine to avoid writing over
; registers
.def lcdstat =r8 ; LCD status
.def Temp =r16 ; Temporary register
.def numtones=r17 ; Register to keep track
; of the number of tones stored in RAM
; (for Mode 1)
.def reload =r18 ; Holds Timer0 reload value
.def toggle =r19 ; Register used to toggle output bit (A6)
.def outreg =r20 ; Register used to hold output values to Port A
.def count =r21 ; Interrupt count
.def wcount =r22 ; Timer1 interrupt count--T1 will be used to
; count wait times (Mode 2)
.def tcount =r23 ; Count of number of tones played--used both when
; playing tones and when counting
; user button presses
.def rand =r24 ; Pseudorandom value taken from T0
.def charcnt =r25 ; Count of characters sent to LCD
.def rtemp1 =r26 ; Temporary reload register used to test
; user button presses
.def rndnum =r27 ; The number of tones to play each time, based
; on the level
.equ PreScal0=3 ; Set timer0 prescale to 64 (use CK/64
; for counter/timer0)
.equ PreScal1=2 ; Set timer1 prescale to 8
; Counter reload values corresponding to the frequencies to be played
; for each button
.equ reload3 =0xb0 ; 392 Hz (G4, switch3)
.equ reload2 =0xb9 ; 440 Hz (A4, switch2)
.equ reload1 =0xc1 ; 494 Hz (B4, switch1)
.equ reload0 =0xc4 ; 523 Hz (C5, switch0)
; Interrupt count values corresponding to the frequencies to be
; played for each button
.equ count3 =196 ; 392 Hz (G4, switch3)
.equ count2 =220 ; 440 Hz (A4, switch2)
.equ count1 =247 ; 494 Hz (B4, switch1)
.equ count0 =255 ; 523 Hz (C5, switch0)
; Note: count0 should actually be
; 261, but in order to only use
; one register, we have to sacrifice
; a few counts so that a tone produced
; using that button is slightly shorter
; than the others--.2448 seconds rather
; than .25 seconds
.equ maxL1 =30 ; Maximum and minimum numbers of T1 interrupts
.equ maxL2 =25 ; for which the program will wait for a user
.equ maxL3 =20 ; to press a button, depending on the level of
.equ minL1 =10 ; difficulty
.equ minL2 =5
.equ minL3 =2
;***** Other equates
.equ lcdrs =6 ; LCD rs pin connected to PC6
.equ lcdrw =5 ; LCD r/w pin connected to PC5
.equ lcde =4 ; LCD enable pin connected to PC4
; Timer/Counter prescaler values
.equ TSTOP =0 ; Stop Timer/Counter
.equ TCK8 =2 ; Timer/Counter runs from CK / 8
.equ TCK256 =4 ; Timer/Counter runs from CK / 256
.equ TCK1024 =5 ; Timer/Counter runs from CK / 1024
.dseg
tones: .byte 100 ; Tone list to hold up to 100 tones in RAM
; There is no code to handle an overflow of
; this array because finding a person who can
; remember 100 tones is a highly unlikely
; occurrence
; ***** Initialization *****
.cseg
.org $0000
rjmp RESET ; reset entry vector
reti ; external interrupt 0 not used
reti ; external interrupt 1 not used
reti ; timer1 capture not used
reti ; timer1 compare match A not used
reti ; timer1 compare match B not used
rjmp T1ovfl ; timer1 overflow not used
rjmp T0ovfl ; timer0 overflow vector
reti ; SPI transfer complete not used
reti ; Rx complete vector not used
reti ; Tx empty not used
reti ; Tx complete not used
reti ; analog comparator not used
; NOTE: All leading spaces on the following strings are included for the
; purpose of centering the strings on the LCD
simon: .db " SIMON", 0x00 ; opening string
simon2: .db " EE 476 Project", 0x00 ; sequence
simon3: .db " by Mike Geiger", 0x00 ;
modsel: .db " Select mode", 0x00 ; mode select
modsel2:.db " S1: Memory mode", 0x00; sequence
modsel3:.db " S2: React mode", 0x00
level1: .db " Choose level", 0x00 ; Level select sequence
level2a:.db " S1: L1, S2: L2",0x00
level2b:.db "S1:1, S2:2, S3:3",0x00
ready: .db " Get ready ...", 0x00 ; String used to fill the pause
; at the start of each game
mode1s: .db " Mode 1", 0x00 ; Mode 1 string
; Displayed while playing in Mode 1
mode2s: .db " Mode 2", 0x00 ; Mode 2 string
; Displayed while playing in Mode 2
end: .db " Game Over", 0x00 ; Game over
plagain:.db " Play again?", 0x00 ; Play again
plagn2: .db " S1: Y, S2: N", 0x00 ; sequence
bye: .db " Goodbye", 0x00 ; To be shown if user decides
; not to play again
RESET: ldi Temp, low(RAMEND) ; set stack pointer
out SPL, Temp
ldi Temp, high(RAMEND)
out SPH, Temp
; LCD setup
ldi Temp, TSTOP ; Timer 0 off (just in case)
out TCCR0, Temp ; Stop timer
ldi Temp, 0b00000010 ; Enable Timer 0 interrupt
out TIMSK, Temp
sei ; Enable interrupts
; power down the LCD
ldi Temp, 0xff ; LCD power connection
out DDRD, Temp ; power it down after reset
ldi Temp, 0x00
out PORTD, Temp
ldi Temp, 100 ; then Wait 1.5 second with
mov count, Temp ; LCD power off
clt
ldi Temp, TCK256
out TCCR0, Temp
offwait:brtc offwait ; wait for interrupt to set
clt ; T bit
tst Count ; Count == 0?
breq pwrup
; dec Count ; Not needed here--Count is
rjmp offwait ; decremented in T0ovfl ISR
; now power up LCD
pwrup: ldi Temp, 0xff
out PORTD, Temp
ldi Temp, 100 ; Wait 1.5 second for LCD
mov count, Temp ; power up
puwait: brtc puwait
clt
tst Count
breq init
; dec Count ; As above--dec not needed here
rjmp puwait ; since T0ovfl ISR takes care of it
; hopefully by now the LCD has rebooted
init: rcall lcdinit ; Initialize LCD module
rcall lcdclr ; clear lcd
; Output opening string sequence
ldi ZH, high(simon*2)
ldi ZL, low(simon*2)
rcall outstr
rcall wait2s
ldi ZH, high(simon2*2)
ldi ZL, low(simon2*2)
rcall outstr
rcall wait2s
ldi ZH, high(simon3*2)
ldi ZL, low(simon3*2)
rcall outstr
rcall wait2s
ser Temp ; set Port A to be
out DDRA, Temp ; all outputs
out DDRB, Temp ; set Port B to be all outputs
out PORTB, Temp ; and clear LEDs
out PORTD, Temp ; Turn on Port D pullups
ldi Temp, 0b10000000 ; Set Port D to all inputs except
out DDRD, Temp ; for bit 7--LCD power
clr reload ; clear reload register
out TCNT0, reload ; and preset counter to 0
ldi Temp, 0b10000010 ; enable timer0 and timer1
out TIMSK, Temp ; interrupts
ldi Temp, PreScal0 ; prescale timer0 by 64
out TCCR0, Temp ; turn on timer0
ldi toggle, 0x40 ; set bit 6 of toggle register
main: clr outreg ; clear output register
clr numtones ; clear number of tones
clr count ; clear T0 interrupt count
clr wcount ; clear T1 interrupt count
clr tcount ; clear tone count
ldi ZL, low(tones) ; set Z register to point to
ldi ZH, high(tones) ; RAM string
; Save the address of tones
mov r30save, r30
mov r31save, r31
; Display mode select sequence
ldi ZH, high(modsel*2) ; Display "Select mode"
ldi ZL, low(modsel*2)
rcall outstr
rcall wait2s
ldi ZH, high(modsel2*2) ; Display "S1: Memory mode"
ldi ZL, low(modsel2*2)
rcall outstr
rcall wait2s
ldi ZH, high(modsel3*2) ; Display "S2: React mode"
ldi ZL, low(modsel3*2)
rcall outstr
rcall wait2s
ldi ZH, high(modsel*2) ; Now return display to
ldi ZL, low(modsel*2) ; "Select mode" and
rcall outstr ; wait for button press
mpoll: sbis PIND, 0 ; Pick mode
rjmp mode1
sbis PIND, 1
rjmp mode2
rjmp mpoll
mode1: ldi Temp, 0x01 ; Set T1 to CK
out TCCR1B, Temp
ldi rndnum, 1
sbis PIND, 0 ; First, wait for switch 0 to
rjmp mode1 ; be released
ldi ZH, high(level1*2) ; Display "Choose level"
ldi ZL, low(level1*2)
rcall outstr
rcall wait2s
ldi ZH, high(level2a*2) ; Display "S1: L1, S2: L2"
ldi ZL, low(level2a*2)
rcall outstr
mode1a: clr Temp ; Set the level of difficulty
sbis PIND, 0 ; Switch 0 => level 1
ldi Temp, 1 ; (Only adds one new tone
; to the sequence each time)
sbis PIND, 1 ; Switch 1 => level 2
ldi Temp, 2 ; (Adds a random number
; (between 1 and 4) of new
; tones to the sequence each time)
tst Temp
breq mode1a
subi Temp, 1 ; reduce level by 1 (represent
; level 1 as a 0 in the
mov level, Temp ; level register so that the
; level can be determined
; by a simple tst operation,
; rather than a set of
; cpi operations)
; Wait
ldi ZH, high(ready*2) ; Display "Get
ldi ZL, low(ready*2) ; ready ..."
rcall outstr
rcall wait2s ; Wait for two seconds before
; starting game
; Now display "Mode 1"
ldi ZH, high(mode1s*2)
ldi ZL, low(mode1s*2)
rcall outstr
mov r30, r30save ; Restore Z reg.--holds address
mov r31, r31save ; of tones array
mode1b: ; First, wait .25 seconds
clr reload
ldi Count, 63
pause: tst Count
brne pause
ldi YL, low(tones) ; set Y register to point to
ldi YH, high(tones) ; RAM string
mode1c: andi rand, 0x03 ; Convert rand to 2-bit value
; (in range 0-3)
cpi rand, 0 ; Check possible values for rand--
breq tone0 ; set tone accordingly
cpi rand, 1
breq tone1
cpi rand, 2
breq tone2
rjmp tone3
tone0: ldi reload, reload0 ; Load appropriate
rjmp st_tone ; reload values
tone1: ldi reload, reload1
rjmp st_tone
tone2: ldi reload, reload2
rjmp st_tone
tone3: ldi reload, reload3
st_tone:st Z+, reload ; and store them in tones buffer
inc numtones ; increment number of stored tones
clr reload ; clear the reload value to prevent
; unintended tones
dec rndnum
tst rndnum
breq next
in rand, TCNT1L ; Get another random value
rjmp mode1c
next: clr tcount ; Clear tcount before entering into loop
; where tones are played
pltone: ld reload, Y+
inc tcount
cpi reload, reload0 ; Another jump table--compare reload values
breq pl0 ; loaded from array of saved notes
cpi reload, reload1 ; and jump to code which loads appropriate
breq pl1 ; interrupt count value
cpi reload, reload2
breq pl2
cpi reload, reload3
breq pl3
pl0: ldi Count, count0 ; Preload interrupt count values
cbi PORTB, 0
rjmp plback
pl1: ldi Count, count1
cbi PORTB, 1
rjmp plback
pl2: ldi Count, count2
cbi PORTB, 2
rjmp plback
pl3: ldi Count, count3
cbi PORTB, 3
plback: tst Count
brne plback ; spin until Count == 0
ser Temp ; Turn off LEDs
out PORTB, Temp
; Now wait .25 seconds
clr reload
ldi Count, 63
wloop: tst Count
brne wloop
; Check to see what tones have been played
cp tcount, numtones ; Have all tones in RAM
; been played?
brne pltone ; if not, play next tone
; Now, wait and see if the user can match the buttons pressed
clr tcount
clr reload
ldi YL, low(tones)
ldi YH, high(tones)
tstlp: ld rtemp1, Y+ ; Get tone from RAM
inc tcount
poll: sbis PIND, 0 ; Test for user
ldi reload, reload0 ; button press
sbis PIND, 1
ldi reload, reload1
sbis PIND, 2
ldi reload, reload2
sbis PIND, 3
ldi reload, reload3
tst reload
breq poll
cp reload, rtemp1
brne error
; Light appropriate LED corresponding to button pressed
sbis PIND, 0
cbi PORTB, 0
sbis PIND, 1
cbi PORTB, 1
sbis PIND, 2
cbi PORTB, 2
sbis PIND, 3
cbi PORTB, 3
; Have the program play the tone for as long as you press the button
waitA: sbis PIND, 0
rjmp waitA
sbis PIND, 1
rjmp waitA
sbis PIND, 2
rjmp waitA
sbis PIND, 3
rjmp waitA
ser Temp ; Turn off LEDs
out PORTB, Temp
in rand, TCNT0 ; Get next random value
tst level ; if level==0
breq m1L1 ; We're in level 1
mov rndnum, rand
andi rndnum, 0x0C ; Actually take the random
lsr rndnum ; counter off of the 3rd
lsr rndnum ; and 4th bits of TCNT0
subi rndnum, -1
rjmp stopton
m1L1: ldi rndnum, 1 ; Add only one tone to the
; sequence
stopton:clr reload ; Stop the current tone
ldi Count, 63
waitlp: tst Count ; Play silence for .25 sec
brne waitlp
cp tcount, numtones ; Has the whole sequence
; been replicated?
brlo tstlp ; If not, check next tone
rjmp mode1b
error: ldi reload, 10 ; Make some awful tone
ldi ZH, high(end*2) ; Display "Game over"
ldi ZL, low(end*2)
rcall outstr
ldi Count, 255 ; Play the tone for a somewhat
; unspecified amount of time
errlp: tst Count
brne errlp
clr reload
; Now the game is over--display game over message, and ask if player
; wants to play again
gmover: ldi Temp, 0xF0
out PORTB, Temp
ldi ZH, high(plagain*2) ; Display "Play again?"
ldi ZL, low(plagain*2)
rcall outstr
rcall wait2s
ldi ZH, high(plagn2*2) ; Display "S1: Y, S2: N"
ldi ZL, low(plagn2*2)
rcall outstr
gmover2:sbis PIND, 0 ; if Port D, pin 0 is clear, play again
rjmp replay
sbis PIND, 1 ; if Port D, pin 1 clear, game's over
rjmp endg
rjmp gmover2
replay: ser Temp ; Clear LEDs
out PORTB, Temp
sbic PIND, 0 ; and wait for switch 0 to
rjmp main ; be released before returning
rjmp replay ; to main menu
endg: ldi ZH, high(bye*2) ; Display "Goodbye"
ldi ZL, low(bye*2)
rcall outstr
ser Temp ; Turn off LEDs since blue LED
out PORTB, Temp ; is a little too bright to
; leave on for any long amount
; of time without hurting
; someone's eyes
endg2: rjmp endg2
; Reaction mode--mode 2
mode2: sbis PIND, 1 ; first, must wait for switch 1 to
rjmp mode2 ; be released
ldi ZH, high(level1*2) ; Display "Choose level"
ldi ZL, low(level1*2)
rcall outstr
rcall wait2s
ldi ZH, high(level2b*2) ; Display "S1:1, S2:2, S3:3"
ldi ZL, low(level2b*2)
rcall outstr
mode2b: clr Temp ; Test for user button press
sbis PIND, 0 ; and set level accordingly
ldi Temp, maxL1
sbis PIND, 1
ldi Temp, maxL2
sbis PIND, 2
ldi Temp, maxL3
tst Temp
breq mode2b
mov maxnum, Temp
cpi Temp, maxL1
brne L2
ldi Temp, minL1
mov minnum, Temp
rjmp setT1
L2: cpi Temp, maxL2
brne L3
ldi Temp, minL2
mov minnum, Temp
rjmp setT1
L3: ldi Temp, minL3
mov minnum, Temp
setT1: ldi Temp, PreScal1 ; Set Timer1 to CK/8
out TCCR1B, Temp
mov waitval, maxnum ; Start waitval at whatever the
; maximum number of interrupts is
; for that level
; Wait
ldi ZH, high(ready*2) ; Display "Get ready ... "
ldi ZL, low(ready*2)
rcall outstr
rcall wait2s
ldi ZH, high(mode2s*2) ; Display "Mode 2"
ldi ZL, low(mode2s*2)
rcall outstr
mode2a: ; First, wait .25 seconds
clr reload
ldi Count, 63
pause2: tst Count
brne pause2
andi rand, 0x03
cpi rand, 0 ; Check possible values for rand & 0x03
breq tone02 ; set tone accordingly
cpi rand, 1
breq tone12
cpi rand, 2
breq tone22
rjmp tone32
tone02: ldi reload, reload0 ; Load appropriate reload values
ldi Count, count0
cbi PORTB, 0
rjmp plbck2
tone12: ldi reload, reload1
ldi Count, count1
cbi PORTB, 1
rjmp plbck2
tone22: ldi reload, reload2
ldi Count, count2
cbi PORTB, 2
rjmp plbck2
tone32: ldi reload, reload3
ldi Count, count3
cbi PORTB, 3
plbck2: tst Count ; spin until Count == 0
brne plbck2
mov rtemp1, reload ; store reload value in reload
; temp register
ser Temp ; Turn off LEDs
out PORTB, Temp
mov wcount, waitval
clr reload
poll2: tst wcount ; Has time run out?
breq gerror ; If so, game over
sbis PIND, 0 ; Test for user button press
ldi reload, reload0
sbis PIND, 1
ldi reload, reload1
sbis PIND, 2
ldi reload, reload2
sbis PIND, 3
ldi reload, reload3
tst reload
breq poll2
cp reload, rtemp1 ; Did user replicate correct tone?
brne gerror ; If not, game over
rjmp light
gerror: rjmp error
; Light appropriate LED corresponding to button pressed
light: sbis PIND, 0
cbi PORTB, 0
sbis PIND, 1
cbi PORTB, 1
sbis PIND, 2
cbi PORTB, 2
sbis PIND, 3
cbi PORTB, 3
; Have the program play the tone for as long as you press the button
waitA2: sbis PIND, 0
rjmp waitA2
sbis PIND, 1
rjmp waitA2
sbis PIND, 2
rjmp waitA2
sbis PIND, 3
rjmp waitA2
ser Temp ; Turn off LEDs
out PORTB, Temp
in rand, TCNT0 ; Get next random value
clr reload ; Turn off speaker
ldi Count, 63 ; and wait .25 sec in silence
wtlp2: tst Count
brne wtlp2
dec waitval ; wait for 1 less interrupt
cp waitval, minnum
brsh gmode2a
mov waitval, minnum ; ensure that we never go below
; the minimum number of interrupts
; for a given level of difficulty
gmode2a:rjmp mode2a
; ================================================
; Clear entire LCD and delay for a bit
lcdclr: ldi Temp, 1 ; Clear LCD command
rcall lcdcmd
ldi Temp, TCK256 ; Wait for 15 ms
out TCCR0, Temp
cwait: brtc cwait
clt
ldi Temp, PreScal0
out TCCR0, Temp
clr Temp
out TCNT0, Temp
ret
;================================================
; Initialize LCD module
lcdinit:ldi Temp,0 ; Setup port pins
out PORTC,Temp ; Pull all pins low
ldi Temp, 0xff ; All pins are outputs
out DDRC, Temp
ldi Temp, TCK256 ; Wait for 15 ms
out TCCR0, Temp
iwait: brtc iwait
clt
; LCD specs call for 3 repetitions as follows
ldi Temp, 3 ; Function set
out PORTC, Temp ; to 8-bit mode
nop ; nop is data setup time
sbi PORTC, lcde ; Toggle enable line
cbi PORTC,lcde
clr Temp
out TCNT0, Temp
iwait2: brtc iwait2
clt
ldi Temp, 3 ; Function set
out PORTC, Temp ; to 8-bit mode
nop ; nop is data setup time
sbi PORTC, lcde ; Toggle enable line
cbi PORTC,lcde
clr Temp
out TCNT0, Temp
iwait3: brtc iwait3
clt
ldi Temp, 3 ; Function set
out PORTC, Temp ; to 8-bit mode
nop ; nop is data setup time
sbi PORTC, lcde ; Toggle enable line
cbi PORTC,lcde
clr Temp
out TCNT0, Temp
iwait4: brtc iwait4
clt
ldi Temp, 0b11110000 ; Make 4 data lines inputs
out DDRC, Temp
ldi Temp, TSTOP ; Clear timer0 and turn it off
out TCCR0, Temp
out TCNT0, Temp
; Finally,
; At this point, the normal 4 wire command routine can be used
ldi Temp, 0b00100000 ; Function set, 4 wire,
rcall lcdcmd ; 1 line, 5x7 font
ldi Temp, 0b00001100 ; Display on, no cursor,
rcall lcdcmd ; no blink
ldi Temp, 0b00000110 ; Address increment, no
rcall lcdcmd ; scrolling
ret
; ============================================
; Wait for LCD to go unbusy
lcdwait:ldi Temp, 0xF0 ; Make 4 data lines inputs
out DDRC, Temp
sbi PORTC, lcdrw ; Set r/w pin to read
cbi PORTC, lcdrs ; Set register select to command
waitloop:
sbi PORTC, lcde ; Toggle enable line
cbi PORTC, lcde
in lcdstat, PINC ; Read busy flag
; Read, and ignore lower nibble
sbi PORTC, lcde ; Toggle enable line
cbi PORTC, lcde
sbrc lcdstat, 3 ; Loop until done
rjmp waitloop
ret
; =============================================
; Send command in Temp to LCD
lcdcmd: push Temp ; Save character
rcall lcdwait ; Wait for LCD to be ready
ldi Temp, 0xFF ; Make all port D pins outputs
out DDRC, Temp
pop Temp ; Get character back
push Temp ; Save another copy
swap Temp ; Get upper nibble
andi Temp, 0x0F ; Strip off upper bits
out PORTC, Temp ; Put on port
nop ; wait for data setup time
sbi PORTC, lcde ; Toggle enable line
cbi PORTC, lcde
pop Temp ; Recall character
andi Temp, 0x0F ; Strip off upper bits
out PORTC, Temp ; Put on port
nop
sbi PORTC, lcde ; Toggle enable line
cbi PORTC, lcde
ldi Temp, 0xF0 ; Make 4 data lines inputs
out DDRC, Temp
ret
; =============================================
; Send character data in Temp to LCD
lcdput:
push Temp ; Save character
rcall lcdwait ; Wait for LCD to be ready
ldi Temp, 0xFF ; Make all port D pins outputs
out DDRC, Temp
pop Temp ; Get character back
push Temp ; Save another copy
swap Temp ; Get upper nibble
andi Temp, 0x0F ; Strip off upper bits
out PORTC, Temp ; Put on port
sbi PORTC, lcdrs ; Register select set for data
nop
sbi PORTC, lcde ; Toggle enable line
cbi PORTC, lcde
pop Temp ; Recall character
andi Temp, 0x0F ; Strip off upper bits
out PORTC, Temp ; Put on port
sbi PORTC, lcdrs ; Register select set for data
nop
sbi PORTC, lcde ; Toggle enable line
cbi PORTC, lcde
ldi Temp, 0xF0 ; Make 4 data lines inputs
out DDRC, Temp
ret
; Subroutine to output a string to the LCD
; The address of the first character in the string should be in
; the Z register (R30-31) when the subroutine is called
outstr: clr charcnt
rcall lcdclr
strlp: lpm
tst R0
breq strend
mov Temp, R0
rcall lcdput
adiw ZL, 1
inc charcnt
cpi charcnt, 8
brne strlp
ldi Temp, 0xC0 ; Set address to last 8 chars
rcall lcdcmd
rjmp strlp
strend: ret
; Cheesy way of waiting about 2 seconds (2.097152 seconds, to be precise)
wait2s: ldi Count, 255
wait1: tst Count
brne wait1
ldi Count, 255
wait2: tst Count
brne wait2
ret
; Timer1 overflow ISR
T1ovfl: in save, SREG
dec wcount ; decrement wait count
out SREG, save
reti
; Timer0 overflow ISR
T0ovfl: in save, SREG
dec Count ; decrement interrupt count
tst reload ; if reload = 0,
breq no_tone
eor outreg, toggle ; toggle output bit
out TCNT0, reload ; reload counter
out PORTA, outreg ; send output to PORTA
rjmp t0_end
no_tone:clr outreg ; clear output and
; play nothing
out PORTA, outreg ; this is the case
; where no button has
; been pushed yet
t0_end: out SREG, save
set
reti
Back to top of page.
Back to SIMON Project Home Page.