include"8515def.inc"
org $0000
rjmp RESET
org $0010
RESET:ldi r16,$5F
      out SPL,R16
      ldi r16,$02
      out SPH,r16   ;设堆栈底为$025F
      ldi r25,$00   ;r25用于统计密码输错的次数.
   ldi r22,$04   ;内定4个密码
   clr r29
      ldi r28,$73   ;4个密码存于70-73H
 L1:clr r30
      ldi r31,$03
      ld  r0,z+
      st  y-,r0
      dec r22
      brne L1 
START:ldi r16,$03
      out ddrc,r16   ; c口为低二位输出,其余为输入
   ldi r16,$FC
      out portc,r16    ; 开始灯不亮,出c口无输入
   ldi r20, $04    ;清除显示器存放地址80-83H的地址
   ldi r16,$00
CLEAR: ldi r28,$80
       clr r29
       st y+,r16
       dec r20
       brne CLEAR
L2:   clr r16
      out ddrb,r16  ;B口输入
   ldi r16,$FF
      out portb,r16   
l3:   in r0,pinb    ;读b口的输入值
      cpi r0,$FF  ;是否有b口键按下?
      brne KEYIN1
      in r1,pinc   ;读c口的输入值
      andi r1,$FC   ;是否有c口键按下?
      cpi r1,$FC
      brne KEYIN2
      rjmp L3    
KEYIN2: bst r1,4    ;是否按"C",是则显示密码
    brtc X3
        bst r1,5    ;是否按"D",是则比较密码
    brtc x4 
D1:  ldi r16,$56
     recall DELAY  ;消除抖动,延时1s 
D2:  in r2,pinc
     andi r2,$FC
     cp r2,r1
     breq D2      ; 按键放开否?
  bst r1,6      ;是否按"#"
    brtc START    ;是则清除
  bst r1,7      ;是否按"*" 
    brtc SET0     ;是则设定新密码
  clr r31
    ldi r30,$82
    ldi r16,$03
CS1: ld r3,z+     ;82H存人83H,81H存人82H,80H存人81H
     st z, r3
     subi r30,2
     dec r16
     brne CS1
     bst r1,3    ;新输入值存人80H
     brtc N9
     bst r1,2
     brtc N8
     rcall disp  ;调用显示子程序
     rjmp L3             
  
N8: ldi r19,8    ;如果按8,9中的数,
    st  z,r19    ;分别把它们存人z寄存器所指向的RAM
    ret
N9:ldi r19,9
   st  z,r19
   ret
KEYIN1:in r2,pinc
       cp r2,r0
       breq  KEYIN1   ;按键放开否?
   clr r31
      ldi r30,$82 
      ldi r16,$03
  CS2:ld r3,z+     ;$82存人$83,$81存人$82,$80存人$81,
      st z,r3
      subi r30,2
      dec r16
      brne CS2
     bst r0,0      ;按键值0-7 存人$80
     brtc N0
     bst r0,1
     brtc N1
     bst r0,2
     brtc N2
     bst r0,3
     brtc N3
     bst r0,4
     brtc N4
     bst r0,5
     brtc N5
     bst r0,6
     brtc N6
     bst r0,7
     brtc N7
     rcall disp
     rjmp L3
N0: ldi r19,0       ;如果按0-7中的数,
    st  z,r19       ;分别把它们存人z寄存器所指向的RAM
    ret
N1: ldi r19,1
    st  z,r19
    ret
N2: ldi r19,2
    st  z,r19
    ret
N3: ldi r19,3
    st  z,r19
    ret
N4: ldi r19,4
    st  z,r19
    ret
N5: ldi r19,5
    st  z,r19
    ret
N6: ldi r19,6
    st  z,r19
    ret
N7: ldi r19,7
    st  z,r19
    ret
X3:rjmp disp2
X4:rjmp COMP
disp:ldi r30,$83    ;显示地址指针
   clr r31
disp1:ld r3,z-      ;载人D4显示值
      adiw r3,$30     ;加上D4 74138的扫描值
   ldi r16,oxFF
      out ddra,r16    ;设置A口为输出
   out porta,r3    ;显示D4的值
   ldi r16,ox56
      rcall DELAY     ;扫描延时1s
      ld r3,z-         ; 显示D3,D2,D1
      adiw r3,$20
      out porta,r3
      rcall DELAY     ;扫描延时1s
      ld r3,z-
      adiw r3,$10
      out porta,r3
      rcall DELAY     ;扫描延时1s
      ld r3,z-
      adiw r3,$00
      out porta,r3  
      rcall DELAY     ;扫描延时1s
      ret
SET0: ldi r18,$04    ;  要设置4位密码
   ldi r28,$80    ;    按键显示地址
   ldi r30,$70    ;    密码存放地址
      clr r29
      clr r31               
 E1:ld  r3,y+       ;$80 存人$70.....$83存人$73
     st z+,r3
     dec r18
     brne E1
     ldi r16,ox56  ;延时1s
     rcall DELAY  
  E2:rjmp START
COMP:ldi r18, $04   ;比较4位密码
  ldi r28,$83     ;按键显示地址
    ldi r30,$73     ;密码存放地址
    clr r29
    clr r31
 C1:ld r3,y-
    ld r4,z-
    cp r3,r4    ;按键值与密码值比较
    brne C3
    dec r18    ; 相同则比较下一位
    brne C1
    out portc,$FE ;全部相同则开锁
    ldi r16,$2F
  C2:rcall DELAY
     clr r25
     rjmp START
  C3:inc r25
     cpi r25,$03
     breq  C4
     rjmp  START
  c4:ldi r16,$FD    ;门不开,并打开报警装置
     out portc,r16
     ldi r16,$CF     ; 报警30秒
     rcall DELAY
     ret
disp2:         ;欲显示密码值
   ldi r30,$73   ;密码存放地址
      clr r31
      rcall  disp1   ;调用显示子程序
      in r3,pinc     ;"C"放开否?没有则继续显示
      bst r3,4     
      brtc disp2
     ldi r16,$56    ;延时1s
      rcall DELAY
      rjmp  START
DELAY:push r16    ;三次嵌套延时子程序
   L0:push r16
   L1:push r16
   L2:push r16
   L3:dec r16
      brne L3
      pop r16
      dec r16
      brne L2
      pop r16
      dec r16
      brne L1
      pop r16
      dec r16
      brne L0
      pop r16
      ret
org $300
TABLE:  db $02,$06,$03,$02         ;内定密码值
end