-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathProj1_Game.asm
410 lines (336 loc) · 8.89 KB
/
Proj1_Game.asm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
; Duncan, Ali, Amrit, 2022/02/18
; Purpose: Game
; Function: The games starts when you push a button. It playes a random tone. If you slap the capacitor on one tone
; it increments the score. If you slap on the second tone, it decrements the score, stopping at 0.
; If a player gets 5 points, the game displays "Wins" and resets.
$NOLIST
$MODLP51
$LIST
CLK EQU 22118400
TIMER0_0_RATE EQU 2200 ; 2048Hz squarewave (peak amplitude of CEM-1203 speaker)
TIMER0_0_RELOAD EQU ((65536-(CLK/TIMER0_0_RATE)))
TIMER0_1_RATE EQU 2000 ; 2048Hz squarewave (peak amplitude of CEM-1203 speaker)
TIMER0_1_RELOAD EQU ((65536-(CLK/TIMER0_1_RATE)))
TIMER2_RATE EQU 1000 ; 1000Hz, timer tick of 1ms
TIMER2_RELOAD EQU ((65536-(CLK/TIMER2_RATE)))
BOOT_BUTTON equ P4.5
PLAYER_0 equ P0.1
PLAYER_1 equ P0.2
SOUND_OUT equ P1.1
; Reset vector
org 0x0000
ljmp main
; Timer/Counter 0 overflow interrupt vector
org 0x000B
ljmp Timer0_ISR
; Timer/Counter 2 overflow interrupt vector
org 0x002B
ljmp Timer2_ISR
dseg at 0x30
Seed: ds 4 ; Random seed
Count1ms: ds 2 ; Used to determine when half second has passed
Score_0: ds 1 ; Score of player 1
Score_1: ds 1 ; Score of player 2
x: ds 4 ; Math var 1
y: ds 4 ; Math var 2
time_counter: ds 1 ; Counts time
bcd: ds 5
bseg
two_seconds_flag: dbit 1
mf: dbit 1
tone: dbit 1
player_flag: dbit 1
cseg
LCD_RS equ P3.2
LCD_E equ P3.3
LCD_D4 equ P3.4
LCD_D5 equ P3.5
LCD_D6 equ P3.6
LCD_D7 equ P3.7
$NOLIST
$include(LCD_4bit.inc)
$include(math32.inc)
$LIST
; 1234567890123456
Player_1_init: db 'Player One: 00', 0
Player_2_init: db 'Player Two: 00', 0
Win: db 'Wins', 0
Timer0_Init:
mov a, TMOD
anl a, #0xf0 ; Clear the bits for timer 0
orl a, #0x01 ; Configure timer 0 as 16-timer
mov TMOD, a
mov TH0, #high(TIMER0_0_RELOAD)
mov TL0, #low(TIMER0_0_RELOAD)
; Set autoreload value
mov RH0, #high(TIMER0_0_RELOAD)
mov RL0, #low(TIMER0_0_RELOAD)
; Enable the timer and interrupts
setb ET0 ; Enable timer 0 interrupt
clr TR0 ; Stop timer 0
ret
Timer0_ISR:
;clr TF0 ; According to the data sheet this is done for us already.
cpl SOUND_OUT ; Connect speaker to P1.1!
reti
;Initializes timer/counter 2 as a 16-bit counter
Timer1_Init:
mov TCON, #0b_0000_0000 ; Stop timer/counter. Set as counter (clock input is pin T2).
; Set the reload value on overflow to zero (just in case is not zero)
mov TH1, #0
mov TL1, #0
ret
Timer2_Init:
mov T2CON, #0 ; Stop timer/counter. Autoreload mode.
mov TH2, #high(TIMER2_RELOAD)
mov TL2, #low(TIMER2_RELOAD)
; Set the reload value
mov RCAP2H, #high(TIMER2_RELOAD)
mov RCAP2L, #low(TIMER2_RELOAD)
; Init One millisecond interrupt counter. It is a 16-bit variable made with two 8-bit parts
clr a
mov Count1ms+0, a
mov Count1ms+1, a
; Enable the timer and interrupts
setb ET2 ; Enable timer 2 interrupt
setb TR2 ; Enable timer 2
ret
Timer2_ISR:
clr TF2 ; Timer 2 doesn't clear TF2 automatically. Do it in ISR
cpl P1.0 ; To check the interrupt rate with oscilloscope. It must be precisely a 1 ms pulse.
; The two registers used in the ISR must be saved in the stack
push acc
push psw
; Increment the 16-bit one mili second counter
inc Count1ms+0 ; Increment the low 8-bits first
mov a, Count1ms+0 ; If the low 8-bits overflow, then increment high 8-bits
jnz Inc_Done
inc Count1ms+1
Inc_Done:
; Check if two seconds has passed
mov a, Count1ms+0
cjne a, #low(1000), Timer2_ISR_done ; Warning: this instruction changes the carry flag!
mov a, Count1ms+1
cjne a, #high(1000 ), Timer2_ISR_done
; 2000 milliseconds have passed. Set a flag so the main program knows
setb two_seconds_flag ; Let the main program know two seconds have passed
; Reset to zero the milli-seconds counter, it is a 16-bit variable
clr a
mov Count1ms+0, a
mov Count1ms+1, a
Timer2_ISR_done:
pop psw
pop acc
reti
Wait1s:
mov R2, #176
X3: mov R1, #250
X2: mov R0, #166
X1: djnz R0, X1
djnz R1, X2
djnz R2, X3
ret
Random:
mov x+0, Seed+0
mov x+1, Seed+1
mov x+2, Seed+2
mov x+3, Seed+3
Load_y(214013)
lcall mul32
Load_y(2531011)
lcall add32
mov Seed+0, x+0
mov Seed+1, x+1
mov Seed+2, x+2
mov Seed+3, x+3
ret
main:
mov SP, #0x7F
lcall Timer0_Init
lcall Timer1_Init
lcall Timer2_Init
setb P2.0
setb P2.1
mov P0M0, #0
mov P0M1, #0
setb EA
lcall LCD_4BIT
Set_Cursor(1, 1)
Send_Constant_String(#Player_1_init)
Set_Cursor(2, 1)
Send_Constant_String(#Player_2_init)
clr two_seconds_flag
mov a, #0x00
mov Score_0, a
mov Score_1, a
mov Seed, a
mov x, a
mov y, a
clr tone
clr mf
; Fills seed with a random number based on time of button press.
setb TR2
jb P4.5, $
mov Seed+0, TH2
mov Seed+1, #0x03
mov Seed+2, #0x33
mov Seed+3, TL2
clr TR2
; Picks randomly between the two frequencies, starts playing that tone.
tone_loop:
; Debug
; Set_Cursor(1, 1)
; WriteData(#0x33)
; A moment of silence between rounds.
clr TR0
lcall Wait1s
; Resets timer two, which is measuring the two second periods of sound.
clr TR2
clr a
clr two_seconds_flag
mov Count1ms+0, a
mov Count1ms+1, a
; Starts timer two.
setb TR2
; Chooses frequency randomly
lcall Random
mov a, Seed+1
mov c, acc.3
mov tone, c
; Jump to a seperate set of reload instructions for one tone.
jnb tone, tone_reload
; Sets frequency using reload instructions.
mov TH0, #high(TIMER0_0_RELOAD)
mov TL0, #low(TIMER0_0_RELOAD)
mov RH0, #high(TIMER0_0_RELOAD)
mov RL0, #low(TIMER0_0_RELOAD)
; Turns on tone, moves to main loop.
setb TR0
ljmp loop
; Sets frequency using reload instructions.
tone_reload:
mov TH0, #high(TIMER0_1_RELOAD)
mov TL0, #low(TIMER0_1_RELOAD)
mov RH0, #high(TIMER0_1_RELOAD)
mov RL0, #low(TIMER0_1_RELOAD)
; Turns on tone, moves to main loop.
setb TR0
ljmp loop
loop:
; If 2 seconds have passed, return to tone loop, which resets round.
jb two_seconds_flag, tone_loop
; Debug
; Set_Cursor(2, 1)
; WriteData(#0x33)
; Check for player one's button.
; Measure the period applied to pin P2.0
clr TR1 ; Stop counter 2
mov TL1, #0
mov TH1, #0
jb P2.0, $
jnb P2.0, $
setb TR1 ; Start counter 0
jb P2.0, $
jnb P2.0, $
clr TR1 ; Stop counter 2, TH1-TL1 has the period
; save the period of P2.0 for later use
mov x+0, TL1
mov x+1, TH1
mov x+2, #0x00
mov x+3, #0x00
clr mf
load_y(6000)
lcall x_lt_y
jnb mf, clear_0
clr player_flag
ljmp player_choice
clear_0:
; Check for player two's button.
; Measure the period applied to pin P2.1
clr TR1 ; Stop counter 2
mov TL1, #0
mov TH1, #0
jb P2.1, $
jnb P2.1, $
setb TR1 ; Start counter 0
jb P2.1, $
jnb P2.1, $
clr TR1 ; Stop counter 2, TH2-TL2 has the period
; save the period of P2.1 for later use
mov x+0, TL1
mov x+1, TH1
mov x+2, #0x00
mov x+3, #0x00
clr mf
load_y(4000)
lcall x_lt_y
jnb mf, clear_1
setb player_flag
ljmp player_choice
clear_1:
ljmp loop
; If player flag is 0, move to score player 0. Otherwise, score player 1.
player_choice:
jnb player_flag, scoring_0
ljmp scoring_1
; Either increments or decrements the player's score based on the tone that is currently playing.
; If the player's score is 0, does not change their score.
scoring_0:
jnb tone, increment_0
mov a, score_0
CJNE a, #0x00, non_0_0
ljmp hot_end
non_0_0:
mov a, score_0
add a, #0x99
da a
mov score_0, a
ljmp hot_end
increment_0:
mov a, score_0
add a, #0x01
da a
mov score_0, a
ljmp hot_end
; Either increments or decrements the player's score based on the tone that is currently playing.
; If the player's score is 0, does not change their score.
scoring_1:
jnb tone, increment_1
mov a, score_1
CJNE a, #0x00, non_0_1
ljmp hot_end
non_0_1:
mov a, score_1
add a, #0x99
da a
mov score_1, a
ljmp hot_end
increment_1:
mov a, score_1
add a, #0x01
da a
mov score_1, a
ljmp hot_end
; A button has been pressed, so the scores are updated and we move to the next round.
hot_end:
clr mf
Set_Cursor(1, 13)
Display_BCD(score_0)
Set_Cursor(2, 13)
Display_BCD(score_1)
mov a, score_0
CJNE a, #0x05, nowin_0
Set_Cursor(1, 13)
Send_Constant_String(#Win)
lcall Wait1s
ljmp main
nowin_0:
mov a, score_1
CJNE a, #0x05, nowin_1
Set_Cursor(2, 13)
Send_Constant_String(#Win)
lcall Wait1s
ljmp main
nowin_1:
ljmp tone_loop
END