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