org 00h
mov p1,#00000000b ;让输出口全部为高电平,p3口的状态根据本寄存器变化
mov 92h,#11111111b ;让输出口全部为高电平,p3口的状态根据本寄存器变化
mov r6,#0;设定工作在正常模式
mov r0,#80h
mov r1,#0h
sta:mov 0e3h,#10h;从FLASH中读出已前学习存储到的代码,放到内存中,从80h-0ffh共64字节,
mov 0e4h,r1
mov 0e7h,#0
orl 0e7h,#10000000b
mov 0e5h,#1
mov 0e6h,#46h
mov 0e6h,#0b9h
nop
mov 0e7h,#0
mov 0e5h,#0
mov 0e6h,#0
mov @r0,0e2h
inc r0
inc r1
cjne r0,#0h, sta;全部读到内存中,以便和收到的代码进行比较,确定开关灯
main:
jb p3.7,bgao;有信号时往下延时进入记录状态
djnz 3ah,bdi;
call rec
bgao:mov 3ah,#60;始终在3ah放入信号初始时的低电平时间
bdi:call key
call run
fs2:cjne r6,#4,fs3 ;表示正在学习模式,5dh是闪动的,让当前要学习的IO口也根着闪动
mov r7,39h;取出当前路数
fs0:cjne r7,#1,san1
mov c,5dh
mov p1.0,c
san1:cjne r7,#2,san2
mov c,5dh
mov p1.1,c
san2:cjne r7,#3,san3
mov c,5dh
mov p1.2,c
san3:cjne r7,#4,san4
mov c,5dh
mov p1.3,c
san4:cjne r7,#5,san5
mov c,5dh
mov p1.4,c
san5:cjne r7,#6,san6
mov c,5dh
mov p1.5,c
san6:cjne r7,#7,san7
mov c,5dh
mov p1.6,c
san7:cjne r7,#8,fs3
mov c,5dh
mov p1.7,c
fs3:cjne r6,#8,fsend ;表示清除模式,删除当前按键以前学习过的内容,
setb 4eh
call clea ;调用删除程序
fsend:djnz 3ch,main
mov 3ch,#100
djnz 3bh,main
mov 3bh,#30
clr 3dh ;延时状态位
clr 4dh ;延时状态位
cpl 5dh ;大循环时延时后让5dh会高低电平变化,产生闪亮的感觉
jmp main
key:mov r7,#0 ;按键值先清零
orl p3,#00111100b
anl p3,#11111100b
mov a,p3
orl p3,#00000011b
anl p3,#11000011b
orl a,p3
orl a,#11000000b
ky0:cjne a,#11111001b,ky1
mov r7,#1
ky1:cjne a,#11110101b,ky2
mov r7,#2
ky2:cjne a,#11101101b,ky3
mov r7,#3
ky3:cjne a,#11011101b,ky4
mov r7,#4
ky4:cjne a,#11110110b,ky5
mov r7,#5
ky5:cjne a,#11111010b,ky6
mov r7,#6
ky6:cjne a,#11101110b,ky7
mov r7,#7
ky7:cjne a,#11011110b,ky8
mov r7,#8
ky8:cjne r7,#0,ky ;有键的情况,跳到ky
mov 3eh,#20
jb 3dh,rkend
setb 3dh
djnz 3fh,rkend
mov r6,#0 ;长期无键按下就将正常工作模式置为0,4是学习模式,8是清除模式。(后面可以看出,一旦某些工作完成了,模式就会设为0)
rkend:ret
ky:mov 3dh,r7
mov 39h,r7 ;按过第几路键,当前路数就是第几,长期保存
mov 3fh,#100
jb 3dh,rkend
setb 3dh
djnz 3eh,rkend
cjne r6,#4,mm1
mov r6,#8 ;学习模式4还在长按键时,就进入清除模式8,
mm1:cjne r6,#0,mm2
mov r6,#4 ;如果是正常工作模式0时长按键的话,就进入学习模式4
ret
mm2:mov r6,#8
ret
run:cjne r7,#0,rkend ;功能执行程序,r7内装的是键盘扫描的数据,等于0说明按键已经松开,可以执行按键程序
run0:mov r7,3dh;
mov 3dh,#0;以免下次再次执行
cjne r7,#1,run1
cpl p1.0 ;改变输出状态,以后相同
run1:cjne r7,#2,run2
cpl p1.1
run2:cjne r7,#3,run3
cpl p1.2
run3:cjne r7,#4,run4
cpl p1.3
run4:cjne r7,#5,run5
cpl p1.4
run5:cjne r7,#6,run6
cpl p1.5
run6:cjne r7,#7,run7
cpl p1.6
run7:cjne r7,#8,rkend
cpl p1.7
r35:mov r3,#2;设定延时时间,不同晶振和不同振荡电阻时需要更改不同的值,用示波器看波形宽度大致相当即可
mov r5,#180
;cpl p1.0;这句是输出一个信号用示波器测量波形宽度用的,大家要学习这种方法,程序运行可以通过观查IO口
;程序完全调试成功后,就必须删除这句(确实有多的IO口不删留空也可以)。
ret
rec:mov 20h,#0;按照信号规律记录信号
mov 21h,#0
mov 22h,#0
call r35;装入延时值
mov r3,#10
rec0s:jb p3.7,rec0n;现在进入一个延时程序,一边延时一边检查p3.7的状态,
djnz r5,rec0s
djnz r3,rec0s
ret;如果超过时间都没有变化,说明信号是无效的,程序返回
rec0n:call r35;装入延时值
rec0x:jnb p3.7,rec1
djnz r5,rec0x
setb 00h;在r5的这个合适的延时时间,定为高电平,将第1字节的第一位写入高电平(这里用了位地址),否则是低电平,都有效
djnz r3,rec0x
ret;如果超过时间都没有变化,说明信号是无效的,程序返回
rec1:call r35;装入延时值
rec1s:jb p3.7,rec1n
djnz r5,rec1s
djnz r3,rec1s
ret;如果超过时间都没有变化,说明信号是无效的,程序返回
rec1n:call r35;装入延时值
rec1x:jnb p3.7,rec2
djnz r5,rec1x
setb 01h;在r5的这个合适的延时时间,定为高电平,将第1字节的第一位写入高电平(这里用了位地址),否则是低电平,都有效
djnz r3,rec1x
ret;如果超过时间都没有变化,说明信号是无效的,程序返回,以后相同
rec2:call r35;装入延时值
rec2s:jb p3.7,rec2n
djnz r5,rec2s
djnz r3,rec2s
ret
rec2n:call r35;装入延时值
rec2x:jnb p3.7,rec3
djnz r5,rec2x
setb 02h;在r5的这个合适的延时时间,定为高电平,否则是低电平,以后相同
djnz r3,rec2x
ret
rec3:call r35;装入延时值
rec3s:jb p3.7,rec3n
djnz r5,rec3s
djnz r3,rec3s
ret
rec3n:call r35;装入延时值
rec3x:jnb p3.7,rec4
djnz r5,rec3x
setb 03h
djnz r3,rec3x
ret
rec4:call r35;装入延时值
rec4s:jb p3.7,rec4n
djnz r5,rec4s
djnz r3,rec4s
ret
rec4n:call r35;装入延时值
rec4x:jnb p3.7,rec5
djnz r5,rec4x
setb 04h
djnz r3,rec4x
ret
rec5:call r35;装入延时值
rec5s:jb p3.7,rec5n
djnz r5,rec5s
djnz r3,rec5s
ret
rec5n:call r35;装入延时值
rec5x:jnb p3.7,rec6
djnz r5,rec5x
setb 05h
djnz r3,rec5x
ret
rec6:call r35;装入延时值
rec6s:jb p3.7,rec6n
djnz r5,rec6s
djnz r3,rec6s
ret
rec6n:call r35;装入延时值
rec6x:jnb p3.7,rec7
djnz r5,rec6x
setb 06h
djnz r3,rec6x
ret
rec7:call r35;装入延时值
rec7s:jb p3.7,rec7n
djnz r5,rec7s
djnz r3,rec7s
ret
rec7n:call r35;装入延时值
rec7x:jnb p3.7,rec8
djnz r5,rec7x
setb 07h
djnz r3,rec7x
ret
rec8:call r35;装入延时值
rec8s:jb p3.7,rec8n
djnz r5,rec8s
djnz r3,rec8s
ret
rec8n:call r35;装入延时值
rec8x:jnb p3.7,rec9
djnz r5,rec8x
setb 08h
djnz r3,rec8x
ret
rec9:call r35;装入延时值
rec9s:jb p3.7,rec9n
djnz r5,rec9s
djnz r3,rec9s
ret
rec9n:call r35;装入延时值
rec9x:jnb p3.7,rec10
djnz r5,rec9x
setb 09h
djnz r3,rec9x
ret
rec10:call r35;装入延时值
rec10s:jb p3.7,rec10n
djnz r5,rec10s
djnz r3,rec10s
ret
rec10n:call r35;装入延时值
rec10x:jnb p3.7,rec11
djnz r5,rec10x
setb 0ah
djnz r3,rec10x
ret
rec11:call r35;装入延时值
rec11s:jb p3.7,rec11n
djnz r5,rec11s
djnz r3,rec11s
ret
rec11n:call r35;装入延时值
rec11x:jnb p3.7,rec12
djnz r5,rec11x
setb 0bh
djnz r3,rec11x
ret
rec12:call r35;装入延时值
rec12s:jb p3.7,rec12n
djnz r5,rec12s
djnz r3,rec12s
ret;ret
rec12n:call r35;装入延时值
rec12x:jnb p3.7,rec13
djnz r5,rec12x
setb 0ch
djnz r3,rec12x
ret
rec13:call r35;装入延时值
rec13s:jb p3.7,rec13n
djnz r5,rec13s
djnz r3,rec13s
ret
rec13n:call r35;装入延时值
rec13x:jnb p3.7,rec14
djnz r5,rec13x
setb 0dh
djnz r3,rec13x
ret
rec14:call r35;装入延时值
rec14s:jb p3.7,rec14n
djnz r5,rec14s
djnz r3,rec14s
ret
rec14n:call r35;装入延时值
rec14x:jnb p3.7,rec15
djnz r5,rec14x
setb 0eh
djnz r3,rec14x
ret
rec15:call r35;装入延时值
rec15s:jb p3.7,rec15n
djnz r5,rec15s
djnz r3,rec15s
ret
rec15n:call r35;装入延时值
rec15x:jnb p3.7,rec16
djnz r5,rec15x
setb 0fh
djnz r3,rec15x
ret
rec16:call r35;装入延时值
rec16s:jb p3.7,rec16n
djnz r5,rec16s
djnz r3,rec16s
ret
rec16n:call r35;装入延时值
rec16x:jnb p3.7,rec17
djnz r5,rec16x
setb 10h
djnz r3,rec16x
ret
rec17:call r35;装入延时值
rec17s:jb p3.7,rec17n
djnz r5,rec17s
djnz r3,rec17s
ret
rec17n:call r35;装入延时值
rec17x:jnb p3.7,rec18
djnz r5,rec17x
setb 11h
djnz r3,rec17x
ret
rec18:call r35;装入延时值
rec18s:jb p3.7,rec18n
djnz r5,rec18s
djnz r3,rec18s
ret
rec18n:call r35;装入延时值
rec18x:jnb p3.7,rec19
djnz r5,rec18x
setb 12h
djnz r3,rec18x
ret
rec19:call r35;装入延时值
rec19s:jb p3.7,rec19n
djnz r5,rec19s
djnz r3,rec19s
ret
rec19n:call r35;装入延时值
rec19x:jnb p3.7,rec20
djnz r5,rec19x
setb 13h
djnz r3,rec19x
ret
rec20:call r35;装入延时值
rec20s:jb p3.7,rec20n
djnz r5,rec20s
djnz r3,rec20s
ret
rec20n:call r35;装入延时值
rec20x:jnb p3.7,rec21
djnz r5,rec20x
setb 14h
djnz r3,rec20x
ret
rec21:call r35;装入延时值
rec21s:jb p3.7,rec21n
djnz r5,rec21s
djnz r3,rec21s
ret
rec21n:call r35;装入延时值
rec21x:jnb p3.7,rec22
djnz r5,rec21x
setb 15h
djnz r3,rec21x
ret
rec22:call r35;装入延时值
rec22s:jb p3.7,rec22n
djnz r5,rec22s
djnz r3,rec22s
ret
rec22n:call r35;装入延时值
rec22x:jnb p3.7,rec23
djnz r5,rec22x
setb 16h
djnz r3,rec22x
ret
rec23:call r35;装入延时值
rec23s:jb p3.7,rec23n
djnz r5,rec23s
djnz r3,rec23s
ret
rec23n:call r35;装入延时值
rec23x:jnb p3.7,rec24
djnz r5,rec23x
setb 17h ;到此时为止,已经连续记录到了40次以上p3.7在合法的时间内高低电平的变化,这必须是有规律的信号才可能产生。
djnz r3,rec23x
ret ;到此时为止,遥控器发送的信号也将重复下一个循环,进行下一轮记录。
rec24:;现在将这个记录到的3个字节(20/21/22h)的数据和(24/25/26h)中的数据进行比较,如果不相等,就将这些数存到后面的寄存器
mov a,20h
cjne a,24h,bgbd
mov a,21h
cjne a,25h,bgbd
mov a,22h
cjne a,26h,bgbd
jb 4dh,bgbd
setb 4dh ;经过最少两轮记录的信号数据相比较是完全相等的,这说明确实收到了一个有效的遥控信号,
mov r4,#0h
cjne r6,#4,cread ;根据r6中的值来确定做如何工作
mov r6,#0
call wir
cread:call read
ret
bgbd:mov 24h,20h
mov 25h,21h
mov 26h,22h
jmp rec
read:mov a,r4 ;读出内存中的数据并和收到记录的数据比较,相同就执行功能。r4表示当前是第几路的数据
rl a
rl a
add a,#80h
mov r0,a
mov a,@r0
mov 3dh,@r0
inc r0
mov a,@r0
cjne a,24h,readend
inc r0
mov a,@r0
cjne a,25h,readend
inc r0
mov a,@r0
cjne a,26h,readend
call run0 ;经过比较数据一样就去运行程序功能,3dh中的数表示要去控制哪一路开关
readend:inc r4
cjne r4,#32,read
mov 3dh,#0
ret
wir:mov a,r4 ;要先将接收到的数据保存到内存中,这必须先和内存中的数据进行比较,已经有了该数据了就不要保存,r4表示当前是保存的第几路数据,这里需要循环检查每一路,由于内存有限,本程序最多只记忆32路
rl a ;rl a这是乘2的意思
rl a ;rl a还是乘2,两次乘2就等于*4,因为用四个字节才保存一组开关数据,一个字节要表示是第几路开关,三个字节表示密码
add a,#80h
mov r0,a
mov a,@r0
wy0:cjne a,#0ffh,wend ;读出的数据是空白的才可以写入,否则会盖掉以前的有用数据
wing:
mov @r0,39h
inc r0
mov @r0,24h
inc r0
mov @r0,25h
inc r0
mov @r0,26h
call save
ret
wend:inc r4
cjne r4,#32,wir ;如果能运行到这里,说明每个存储区都已经保存了数据,下面关掉全部的LED表示提示,请删除一些记忆
mov p1,#0
ret
save: ;要将收到数据即学习到的数据保存在FLASH中,防止停电后丢失数据。说明:以下这些操作是没有理由的,请查相关资料
mov 0e3h,#10h
mov 0e4h,#00h
mov 0e7h,#0
orl 0e7h,#10000000b
mov 0e5h,#3
mov 0e6h,#46h
mov 0e6h,#0b9h ;为什么说这些操作没有理由?因为单片机的任何操作都是将数(指令或者数据)搬来搬去,芯片设计时就是只要放上这些命令,FLASH读写功能就自动完成了。(驱动液晶、18B20测试温度、串行通信等等都是一样,别公司型号的单片机等,都是一样,放上不同的指令就完成了不同的功能,而这些都是要查相关的资料的。)
nop
mov 0e7h,#0
mov 0e5h,#0
mov 0e6h,#0
mov r0,#80h
mov r1,#0
sav:mov 0e3h,#10h ;重复进行写入FLASH
mov 0e4h,r1
mov 0e2h,@r0
mov 0e7h,#0
orl 0e7h,#10000000b
mov 0e5h,#2
mov 0e6h,#46h
mov 0e6h,#0b9h
nop
mov 0e7h,#0
mov 0e5h,#0
mov 0e6h,#0
inc r0
inc r1
cjne r0,#0h,sav ;重复循环将全部数据保存到FLASH中
ret
clea:mov r4,#0 ;删除已经记忆在内存中的数据,并从FLASH中也删除(在内存中删除后再保存到FLASH中即可)
clea0:mov a,r4
rl a
rl a
add a,#80h
mov r0,a
mov a,@r0
cjne a,3dh,cleaend
mov @r0,#0ffh ;填入0数据就表示删除
clr 4eh
cleaend:inc r4
cjne r4,#32,clea0
jb 4eh,clea1
call save ;还要保存到FLASH中
clea1:mov 3dh,#0
mov r6,#0
ret
end