pp.413-418
16個あるスイッチのどれが押されたのかを8ピンだけで検出する。接続は下のように固定する。検出されたキーに割り当てた数値をポートBに出力して動作を確認する。
; 下のように接続する。 ; ROW0 →PD7 ; ROW1 →PD6 ; ROW2 →PD5 ; ROW3 →PD4 ; COL3 →PD3 ; COL2 →PD2 ; COL1 →PD1 ; COL0 →PD0 ; スタックポインタの初期化マクロ .MACRO INITSTACK LDI R16, HIGH(RAMEND) OUT SPH, R16 LDI R16, LOW(RAMEND) OUT SPL, R16 .ENDMACRO INITSTACK ; 検出されたキーに割り当ててある数値をポートBに出力して確認したいのでポートBのIOを全部OUTにする。 LDI R21, 0xFF OUT DDRB, R21 ; ポートDのIOを、上位ニブルはOUT (ROW)にし、下位ニブルはIN (COL)にする。 LDI R21, 0xF0 OUT DDRD, R21 ; すべての行を一旦Lにする。入力(COL)は内部プルアップする。 GROUND_ALL_ROWS: LDI R20, 0x0F OUT PORTD, R20 ; どれかキーが押されていたら(COLのいずれかが0であったら)、そのキーが放される(COLが全部1になる)のを待つ。 WAIT_FOR_RELEASE: NOP IN R21, PIND ANDI R21, 0x0F CPI R21, 0x0F ; Compare with Immediate BRNE WAIT_FOR_RELEASE ; Branch if Not Equal ; どれかキーが押されるのを待つ。 WAIT_FOR_KEY: NOP IN R21, PIND ANDI R21, 0x0F CPI R21, 0x0F BREQ WAIT_FOR_KEY ; Branch if Equal ; どれかキーが押されたら、バウンスが落ち着くのを待って、 CALL DELAY_20ms ; 結局どれもキーが押されていなかったら、戻ってまたキーが押されるのを待つが、 ; 結局どれかキーが押されていたら、どの行が押されていたのかを調べる処理に移る。 IN R21, PIND ANDI R21, 0x0F CPI R21, 0x0F BREQ WAIT_FOR_KEY ; 0行目を調べる。 LDI R21, ~(1<<PD7) ; 0行目を0にして、 OUT PORTD, R21 NOP IN R21, PIND ; COLのいずれかが ANDI R21, 0x0F CPI R21, 0x0F BRNE ROW0 ; 0であったら、0行目のデータを読み取る処理に移る。 ; 1行目を調べる。 LDI R21, ~(1<<PD6) ; 1行目を0にして、 OUT PORTD, R21 NOP IN R21, PIND ; COLのいずれかが ANDI R21, 0x0F CPI R21, 0x0F BRNE ROW1 ; 0であったら、1行目のデータを読み取る処理に移る。 ; 2行目を調べる。 LDI R21, ~(1<<PD5) ; 2行目を0にして、 OUT PORTD, R21 NOP IN R21, PIND ; COLのいずれかが ANDI R21, 0x0F CPI R21, 0x0F BRNE ROW2 ; 0であったら、2行目のデータを読み取る処理に移る。 ; 3行目を調べる。 LDI R21, ~(1<<PD4) ; 3行目を0にして、 OUT PORTD, R21 NOP IN R21, PIND ; COLのいずれかが ANDI R21, 0x0F CPI R21, 0x0F BRNE ROW3 ; 0であったら、3行目のデータを読み取る処理に移る。 ROW0: LDI R31, HIGH(KCODE0 << 1) ; 0行目のキーに割り当てたデータをZレジスタにロードして、 LDI R30, LOW(KCODE0 << 1) RJMP FIND ; 何列目が0であるかを調べる処理に移る。 ROW1: LDI R31, HIGH(KCODE1 << 1) ; 1行目のキーに割り当てたデータをZレジスタにロードして、 LDI R30, LOW(KCODE1 << 1) RJMP FIND ; 何列目が0であるかを調べる処理に移る。 ROW2: LDI R31, HIGH(KCODE2 << 1) ; 2行目のキーに割り当てたデータをZレジスタにロードして、 LDI R30, LOW(KCODE2 << 1) RJMP FIND ; 何列目が0であるかを調べる処理に移る。 ROW3: LDI R31, HIGH(KCODE3 << 1) ; 3行目のキーに割り当てたデータをZレジスタにロードして、 LDI R30, LOW(KCODE3 << 1) RJMP FIND ; 何列目が0であるかを調べる処理に移る。 FIND: LSR R21 ; Logical Shift Right BRCC MATCH ; Branch if Carry Cleared LPM R20, Z+ ; Load Program Memory RJMP FIND MATCH: LPM R20, Z OUT PORTB, R20 RJMP GROUND_ALL_ROWS ;;;;;;;;;; ; delays ; ;;;;;;;;;; SHORT_DELAY: RET ; 4 DELAY_100us: PUSH R17 ; 2 LDI R17 , 200 ; 1 DR0: RCALL SHORT_DELAY ; 3 DEC R17 ; 1W BRNE DR0 ; falseで1, trueで2 POP R17 ; 2 RET ; 4 DELAY_20ms: PUSH R17 ; 2 LDI R17, 200 ; 1 DR1: RCALL DELAY_100us ; 3 DEC R17 ; 1 BRNE DR1 ; falseで1, trueで2 POP R17 ; 2 RET ; 4 .ORG 0x300 KCODE0: .DB 0x0, 0x1, 0x2, 0x3 KCODE1: .DB 0x4, 0x5, 0x6, 0x7 KCODE2: .DB 0x8, 0x9, 0xA, 0xB KCODE3: .DB 0xC, 0xD, 0xE, 0xF