OUTBIT   equ 0e101h  ; 位控制口
CLK164   equ 0e102h  ; 段控制口(接164时钟位)
DAT164   equ 0e102h  ; 段控制口(接164数据位)
IN       equ 0e103h  ; 键盘读入口
; 脉冲宽度下限
ldhmin equ 0cbh
ldlmin equ 0cbh
p0hmin equ 0f3h
p0lmin equ 0f3h
p1hmin equ 0deh
; 脉冲宽度上限
ldhmax equ 0d0h
ldlmax equ 0d0h
p0hmax equ 0f9h
p0lmax equ 0f9h
p1hmax equ 0e3h
; 发送信号时载波信号宽度
send5  equ 192
send1  equ 38
send3  equ 115
LEDBuf equ 60h     ; 显示缓冲
status equ 70h
rcvdat equ 71h
snddat equ 72h
vldmin equ 73h
vldmax equ 74h
hasdat equ 75h
	 org 0000h
    ljmp  Start
LEDMAP:              ; 八段管显示码
       db    3fh, 06h, 5bh, 4fh, 66h, 6dh, 7dh, 07h
       db    7fh, 6fh, 77h, 7ch, 39h, 5eh, 79h, 71h
Delay:               ; 延时子程序
       mov   r7, #10h
DelayLoop:
           djnz  r7, DelayLoop
	       call  ir_receive
           djnz  r6, DelayLoop
           ret
DisplayLED:
            mov   r0, #LEDBuf
            mov   r1, #6          ; 共6个八段管
            mov   r2, #00100000b  ; 从左边开始显示
Loop:
       mov   dptr, #OUTBIT
       mov   a, #0
       movx  @dptr, a        ; 关所有八段管
       mov   a, @r0
       mov   B, #8           ; 送164
DLP:
       rlc   a
       mov   r3, a
       mov   acc.0, c
        mov   dptr, #DAT164
       anl a,#0fdh
       movx  @dptr, a
       mov   dptr, #CLK164
       orl a,#02h
       movx  @dptr, a
       anl a,#0fdh
       movx  @dptr, a
       mov   a, r3
       djnz  B, DLP
       mov   dptr, #OUTBIT
       mov   a, r2
       movx  @dptr, a        ; 显示一位八段管
       mov   r6, #1
       call  Delay
       mov   a, r2           ; 显示下一位
       rr    a
       mov   r2, a
       inc   r0
       djnz  r1, Loop
       ret
TestKey:
         mov   dptr, #OUTBIT
         mov   a, #0
         movx  @dptr, a        ; 输出线置为0
         mov   dptr, #IN
         movx  a, @dptr        ; 读入键状态
         cpl   a
         anl   a, #0fh         ; 高四位不用
         ret
KeyTable:                    ; 键码定义
         db    00h, 01h, 04h, 07h
         db    0fh, 02h, 05h, 08h
         db    0eh, 03h, 06h, 09h
         db    0dh, 0ch, 0bh, 0ah
         db    10H,10H,10H,10H,10H
         db    10H,10H,10H,10H,10H
GetKey:            MOV   13H,#06H
                   MOV   12H,#20H
Key2:	            MOV   A,12H
                   CPL   A
                   MOV   R7,A
                   MOV   DPTR,#0E101H
                   MOV   A,R7
                   MOVX  @DPTR,A
                   MOV   A,12H
                   CLR   C
                   RRC   A
                   MOV   12H,A
                   MOV   DPTR,#0E103H
                   MOVX  A,@DPTR
                   MOV   R7,A
                   MOV   A,R7
                   CPL   A
                   MOV   R7,A
                   MOV   A,R7
                   ANL   A,#0FH
                   MOV   14H,A
                   DEC   13H
                   MOV   R7,13H
                   MOV   A,R7
                   JZ    Key1
                   MOV   A,14H
                   JZ    Key2
Key1 :             MOV   A,14H
                   JZ   GetKey6
                   MOV   A,13H
                   ADD   A,ACC
                   ADD   A,ACC
                   MOV   13H,A
                   MOV   A,14H
                   JNB   ACC.1,GetKey1
                   INC   13H
                   SJMP  GetKey3
GetKey1:           MOV   A,14H
                   JNB   ACC.2,GetKey2
                   INC   13H
                   INC   13H
                   SJMP  GetKey3
GetKey2:          MOV   A,14H
                   JNB   ACC.3,GetKey3
                   MOV   A,#03H
                   ADD   A,13H
                   MOV   13H,A
GetKey3:          MOV   DPTR,#0E101H
                   CLR   A
                   MOVX  @DPTR,A
GetKey4:           MOV   R7,#0AH
                   LCALL Delay
                   LCALL TestKey
                   MOV   A,R7
                   JNZ   GetKey4
                   MOV   R7,13H
                   MOV   A,R7
                   MOV   DPTR,#KeyTable
                   MOVC  A,@A+DPTR
                   MOV   R2,A
                   RET
GetKey6:           MOV   R2,#0FFH
                   RET
WaitRelease:
             mov   dptr, #OUTBIT  ; 等键释放
             clr   a
             movx  @dptr, a
             mov   r6, #10
             call  Delay
             call  TestKey
             jnz   WaitRelease
             mov   a, r2
             ret
TestLow:                   ; 检测低电平宽度
        mov r7,#0
waithigh0:
          mov r6,#0bh
waithigh:
          jb p1.6, lowwidth
          djnz r6,waithigh
          djnz r7,waithigh0
          mov r7,#0            ; 出错
lowwidth:
         mov a,r7
         ret
TestHigh:                  ; 检测高电平宽度
         mov r7,#0
 waitlow0:
          mov r6,#0bh
 waitlow1:
          ;movx a, @dptr
          jnb p1.6, highwidth
          djnz r6, waitlow1
          djnz r7, waitlow0
          mov r7,#0            ; 出错
 highwidth:
           mov a,r7
           ret
TestValid:                    ; 脉冲是否在有效范围内
          cjne a,vldmin,vt01
          jmp  valid              ; A = #min
vt01:
      jnc  vt02               ; A > #min
      jmp  invalid            ; A < #min
vt02:
      cjne a,vldmax,vt03
      jmp  valid              ; A = #max
vt03:
      jnc  invalid            ; A > #max
      jmp  valid              ; A < #max
invalid:
         setb c
         ret
valid:
      clr  c
      ret
ir_receive:                   ; 红外接收
            push  psw
            setb  rs0
            jnb  p1.6, lead_l      ; 是否有红外信号?
            pop  psw                ; 无,则退出
            ret
lead_l:
         call TestLow            ; 引导码低电平
         mov  vldmin,#ldlmin
         mov  vldmax,#ldlmax
         call TestValid
         jnc  lead_h
         jmp  error
lead_h:
        call TestHigh           ; 引导码高电平
        mov  vldmin,#ldhmin
        mov  vldmax,#ldhmax
        call TestValid
        jnc  pulse_l
        jmp  error
 pulse_l:
          mov  status,#1          ; 开始接收数据码
 pulse_t:
         call TestLow            ; 数据码低电平
         mov  vldmin,#p0lmin
         mov  vldmax,#p0lmax
         call TestValid
         jnc  Its0L
         jmp  error
Its0L:
        call TestHigh           ; 数据码高电平
        mov  vldmin,#p0hmin
        mov  vldmax,#p0hmax
        call TestValid          ; '0'数据位的高电平?
        jnc  Its0H
        jmp  next5
Its0H:
        mov  a,rcvdat           ; 数据码移位到缓冲
        rrc  a
        mov  rcvdat,a
        inc  status
        mov  a,status
        cjne a,#9, pulse_t      ; 是否已收到8位数据
        jmp  process
next5:
       mov  vldmin,#p1hmin
       mov  vldmax,#p1hmax
       call TestValid          ; '1'数据位的高电平?
       jnc  Its1H
       jmp  error
Its1H:
       setb c
       jmp  Its0H
process:                      ; 对收到的数据进行校验
        push b
        mov  a,rcvdat
        mov  b,a
        anl  b,#0fh
        anl  a,#0f0h
        swap a
        xrl  a,b
        pop  b
        cjne a,#0fh,error
        mov  a,rcvdat
        anl  a,#0fh
        mov  hasdat,#1
        pop  psw
        ret
error:                        ; 出错退出
       pop  psw
       ret
carrier0:
         setb p1.5       ;发送载波信号   ,p1.5 = 发送脚
         nop
         nop
         nop
         nop
         nop
         clr p1.5
         ret
 carrier1:
          clr p1.5        ;发送载波信号   ,p1.5 = 发送脚
          nop
          nop
          nop
          nop
          nop
          clr p1.5
          ret
ir_send: 
        mov   r0,#send5         ; 引导码低电平
leaderh:
         call  carrier0           ; 发载波信号
         djnz r0,leaderh
         mov  r0,#send5          ; 引导码高电平
leaderl:
         call  carrier1           ; 无载波信号
         djnz r0,leaderl
         mov  status,#0          ; 准备发数据位
sendp:
       mov  r0, #send1         ; 数据码低电平
sp0:
      call carrier0            ; 发载波信号
      djnz r0, sp0
      mov  a, snddat
      mov  r0, #send1         ; '0'数据位高电平
      rrc  a
      mov  snddat,a
      jnc  sp2
      mov  r0, #send3         ; '1'数据位高电平
sp2:
      call carrier1            ; 无载波信号
      djnz r0, sp2
      inc  status
      mov  a, status
      cjne a,#8, sendp        ; 8 位数据已发完
      mov  r0, #send1         ; 发停止位
sp3:
      call carrier0
      djnz r0, sp3
      mov  r0,#0              ; 数据间的间隔
      mov  r1,#3
sp4:
      call carrier1
      djnz r0, sp4
      djnz r1, sp4
      ret
Start:
       mov   sp, #40h
       mov   dptr,#0e100h
       mov   a,#03h
       movx  @dptr,a
       mov   LEDBuf,   #0ffh  ; 显示 8.8.8.8.
       mov   LEDBuf+1, #0ffh
       mov   LEDBuf+2, #0ffh
       mov   LEDBuf+3, #0ffh
       mov   LEDBuf+4, #0
       mov   LEDBuf+5, #0
       mov   hasdat, #0
MLoop:
       mov   a,hasdat
       jnz   show_dat
       call  DisplayLED      ; 显示
       call  TestKey         ; 有键入?
       jz    MLoop           ; 无键入, 继续显示
       call  GetKey          ; 读入键码
       anl   a, #0fh         ; 显示键码
       mov   b, a            ; 将键码编码
       cpl   a
       anl   a,#0fh
       swap  a
       orl   a,b
       mov   snddat,a
       call  ir_send         ; 红外发送
       ljmp  MLoop
show_dat:
       mov   hasdat,#0
       mov   LEDBuf+4,#0
       mov   a, rcvdat
       anl   a,#0fh
       mov   dptr, #LEDMap
       movc  a, @a+dptr
       mov   LEDBuf+5, a
       ljmp  MLoop
       end
