-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathlab7_timers_keypad.asm
More file actions
360 lines (341 loc) · 11 KB
/
Copy pathlab7_timers_keypad.asm
File metadata and controls
360 lines (341 loc) · 11 KB
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
;==============================================================================
; Lab 7 - Timer0/Counter0, Matrix Keypad, ASCII Lookup, SRAM Message Store
; Target : ATmega32 on STK500 (JTAGICE mkII)
; Clock : 1 MHz
;
; This file contains all three parts. Assemble ONE at a time by toggling the
; PART_SELECT equate below (1, 2, or 3), or just keep PART 3 which is the full
; featured program. Parts 1 and 2 are kept for reference / step-by-step bring-up.
;
; PART 1: Timer0 in normal mode, prescaler 1024, ~0.5 s tick rolling a single
; lit LED across PORTB.
; PART 2: Two-keypress -> ASCII character on the LEDs via a flash lookup table.
; PART 3: PART 2 plus: buffer a whole message in SRAM until '#', then play it
; back on the LEDs with an inter-character delay adjustable from
; 0.5 s to 5 s live via INT0 (slower) and INT1 (faster).
;
; Timer math (0.5 s tick @ 1 MHz, prescaler 1024):
; t_tick = 1024 / 1e6 = 1.024 ms per timer count
; counts = 0.5 s / 1.024 ms = 488 overflows-worth of counts
; With TCNT0 preloaded to (256-244)=12 each overflow is 244 counts, so two
; overflows ~= 0.5 s. R23 holds the overflow-pair count (default 2).
;
; Fix vs. original report:
; * The report's first TextArray produced impossible codes (e.g. 0x80 for
; '8,B'). The table below maps the standard phone-keypad multi-tap layout
; to correct ASCII. Verify against your keypad's physical legend.
;==============================================================================
.include "m32def.inc"
.equ PART_SELECT = 3 ; <-- set to 1, 2, or 3
;==============================================================================
.if PART_SELECT == 1
;==============================================================================
.org 0x0000
rjmp Start
.org 0x002A
Start:
ldi r16, low(RAMEND)
out SPL, r16
ldi r16, high(RAMEND)
out SPH, r16
ldi r16, 0xFF
out DDRB, r16 ; PORTB = LEDs
ldi r20, 0xFF ; first ROL produces 0xFE (one LED lit, active-low)
clc
Reload:
ldi r17, 2 ; two overflow passes ~= 0.5 s
ldi r16, 12 ; TCNT0 preload: 256-244=12 for 244-count pass
out TCNT0, r16
ldi r16, 0x05 ; CS02:CS00 = 101 -> prescaler 1024, normal mode
out TCCR0, r16
rol r20
in r16, SREG
push r16
out PORTB, r20
Timer:
in r16, TIFR ; poll TOV0
sbrs r16, TOV0
rjmp Timer
ldi r16, (1<<TOV0) ; clear TOV0 (write 1 to it)
out TIFR, r16
ldi r16, 12 ; reload for next 244-count pass
out TCNT0, r16
dec r17
brne Timer
clr r16
out TCCR0, r16 ; stop timer during reload
pop r16
out SREG, r16
rjmp Reload
.endif
;==============================================================================
.if PART_SELECT == 2
;==============================================================================
.org 0x0000
rjmp Init
.org 0x002A
Init:
ldi r16, LOW(RAMEND)
out SPL, r16
ldi r16, HIGH(RAMEND)
out SPH, r16
ser r16
out DDRB, r16 ; PORTB = LEDs (outputs)
ldi r16, 0xF0 ; PA4-PA7 outputs (rows), PA0-PA3 inputs (cols)
out DDRA, r16
ldi r16, 0xFF
out PORTA, r16 ; pull-ups on the column inputs
Start2:
ser r25
out PORTB, r25 ; LEDs off (active-low)
Checkpress2:
rcall GetKeyPress
mov r24, r0
cpi r24, 0
breq Checkpress2
mov r18, r1 ; first key (digit row select)
Release_2:
rcall GetKeyPress
mov r24, r0
cpi r24, 0
brne Release_2
SecondPress2:
rcall GetKeyPress
mov r24, r0
cpi r24, 0
breq SecondPress2
mov r19, r1 ; second key (column A-D selects letter)
ReleaseSecond2:
rcall GetKeyPress
mov r24, r0
cpi r24, 0
brne ReleaseSecond2
rcall LookupChar
com r20
out PORTB, r20
rjmp Checkpress2
.endif
;==============================================================================
.if PART_SELECT == 3
;==============================================================================
.org 0x0000
jmp Init
.org INT0addr
jmp INT0_Delay ; slower (longer delay)
.org INT1addr
jmp INT1_Delay ; faster (shorter delay)
.org 0x002A
Init:
ldi r16, LOW(RAMEND)
out SPL, r16
ldi r16, HIGH(RAMEND)
out SPH, r16
ser r16
out DDRB, r16 ; PORTB = LEDs
ldi r16, 0xF0 ; PA4-PA7 rows out, PA0-PA3 cols in
out DDRA, r16
ldi r16, 0xFF
out PORTA, r16 ; column pull-ups
ldi yl, low(Message) ; SRAM message buffer pointer
ldi yh, high(Message)
clr r21 ; element counter
ldi r23, 2 ; default delay = 2 overflow-pairs = 0.5 s
cbi DDRD, 2 ; INT0 (PD2) input
cbi DDRD, 3 ; INT1 (PD3) input
sbi PORTD, 2 ; pull-ups
sbi PORTD, 3
ldi r16, 0x0A ; INT0/INT1 falling edge
out MCUCR, r16
ldi r16, (1<<INT1)|(1<<INT0) ; GICR = 0xC0
out GICR, r16
sei
Start3:
ser r25
out PORTB, r25
Checkpress3:
rcall GetKeyPress
mov r24, r0
cpi r24, 0
breq Checkpress3
mov r18, r1
Release_3:
rcall GetKeyPress
mov r24, r0
cpi r24, 0
brne Release_3
SecondPress3:
rcall GetKeyPress
mov r24, r0
cpi r24, 0
breq SecondPress3
mov r19, r1
ReleaseSecond3:
rcall GetKeyPress
mov r24, r0
cpi r24, 0
brne ReleaseSecond3
rcall LookupChar ; ASCII char -> r20
cpi r20, '#' ; '#' (0x23) marks end-of-message
breq DisplayMessage
cpi r21, 64 ; buffer full?
breq Checkpress3 ; yes -- discard key, keep waiting
inc r21
st y+, r20 ; append to SRAM buffer
rjmp Checkpress3
DisplayMessage:
tst r21 ; any characters buffered?
breq Checkpress3 ; no -- ignore '#' and keep waiting
ldi r16, 12
out TCNT0, r16
ldi r16, 0x05 ; start timer, prescaler 1024
out TCCR0, r16
ldi yl, low(Message)
ldi yh, high(Message)
MsgIterate:
mov r22, r23 ; overflow-pair count for this char
ld r20, y+
com r20
out PORTB, r20
TimerWait:
in r16, TIFR
sbrs r16, TOV0
rjmp TimerWait
ldi r16, (1<<TOV0)
out TIFR, r16
ldi r16, 12
out TCNT0, r16
dec r22
brne TimerWait
dec r21
brne MsgIterate
ldi yl, low(Message)
ldi yh, high(Message)
clr r16
out TCCR0, r16 ; stop timer
clr r21 ; reset element counter for next message
rjmp Checkpress3
;--- INT0: increase delay by 0.5 s, capped at 5 s (R23 from 2..20) ----------
INT0_Delay:
push r16
in r16, SREG
push r16
cpi r23, 20
breq INT0_Quit
subi r23, -2 ; +2 overflow-pairs = +0.5 s
INT0_Quit:
pop r16
out SREG, r16
pop r16
reti
;--- INT1: decrease delay by 0.5 s, floored at 0.5 s ------------------------
INT1_Delay:
push r16
in r16, SREG
push r16
cpi r23, 2
breq INT1_Quit
subi r23, 2 ; -2 overflow-pairs = -0.5 s
INT1_Quit:
pop r16
out SREG, r16
pop r16
reti
.endif
;==============================================================================
; Shared procedures (used by parts 2 and 3)
;==============================================================================
.if PART_SELECT >= 2
;------------------------------------------------------------------------------
; LookupChar: first key in r18 (1-9,*,0,# as button index), second key in r19
; (column A-D). Computes table index = 4*row_button + column and loads the
; ASCII char into r20. Mirrors the original index math: (r18<<2) + (r19>>2).
;------------------------------------------------------------------------------
LookupChar:
ldi zl, low(2*TextArray)
ldi zh, high(2*TextArray)
mov r17, r19
lsr r17
lsr r17 ; column 0..3
mov r16, r18
lsl r16
lsl r16 ; 4 * button
add r16, r17
add zl, r16
ldi r17, 0
adc zh, r17 ; carry into high byte (table may cross 256B)
lpm r20, z
ret
;------------------------------------------------------------------------------
; ASCII lookup table. Row = first keypress button index, column (0..3) = A..D.
; Layout follows standard multi-tap: e.g. button '2' -> 2 a b c.
; .DB strings are byte-addressed; the *2 above converts to the LPM byte index.
;------------------------------------------------------------------------------
TextArray:
.DB "11112abc3def", 0, 0, 0, 0
.DB "4ghi5jkl6mno", 0, 0, 0, 0
.DB "7prs8tuv9wxy", 0, 0, 0, 0
.DB " ,.*0000####", 0, 0, 0, 0
;------------------------------------------------------------------------------
; GetKeyPress -- scans a 4x4 matrix keypad connected to PORTA
; PA4-PA7 = row drives (outputs); PA0-PA3 = column reads (inputs, pull-ups
; enabled during Init). Drives each row low in turn and reads the columns.
;
; Returns:
; r0 = 1 if a key is currently pressed, 0 otherwise
; r1 = button index 0-15 computed as (row * 4 + column)
;
; Saves/restores r16-r19. r0 and r1 are output-only.
;------------------------------------------------------------------------------
GetKeyPress:
push r16
push r17
push r18
push r19
clr r0 ; default: no key detected
clr r1
ldi r17, 4 ; 4 rows to scan
ldi r18, 0b11101111 ; PA4 driven low, PA5-PA7 high (row 0 active)
clr r19 ; row_base: first button index in current row
ScanRow:
out PORTA, r18 ; assert one row low
ldi r16, 33 ; settle delay: 33 x 3 cycles ~ 99 us @ 1 MHz
SettleDelay:
dec r16
brne SettleDelay
in r16, PINA
com r16
andi r16, 0x0F ; a set bit = that column is pressed
brne FoundKey
lsl r18 ; shift driven-low bit to the next row
ori r18, 0x01 ; fill vacated bit with 1 (idle high)
subi r19, -4 ; row_base += 4
dec r17
brne ScanRow
rjmp GPK_Done ; all rows scanned, no key found
FoundKey:
; find the lowest set bit in r16 to determine column (0-3)
clr r1
FindCol:
sbrc r16, 0 ; bit 0 set? -> this is the column
rjmp GPK_Hit
inc r1
lsr r16
rjmp FindCol
GPK_Hit:
add r1, r19 ; button = row_base + column
ldi r16, 1 ; ldi requires r16-r31; move into r0 via r16
mov r0, r16
GPK_Done:
pop r19
pop r18
pop r17
pop r16
ret
.endif
;==============================================================================
; SRAM message buffer (Part 3 only)
;==============================================================================
.if PART_SELECT == 3
.DSEG
Message: .BYTE 64 ; room for a 64-char message
.endif