?? 24c02_wr.asm
字號(hào):
;本程序?qū)崿F(xiàn)對(duì)24C02的一個(gè)單元(地址為00)的讀寫和清零操作
;適用于 DXDZ 51+AVR-A 開發(fā)板
;開發(fā)板上最左排的四個(gè)按鍵為功能鍵,從下至上依次為:寫入鍵、讀出鍵,清除鍵、鍵值清零鍵 其余為數(shù)字鍵
;寫入鍵:將數(shù)字鍵的鍵值(顯示在D1 D2)寫入到24C02的00地址
;讀出鍵:將24C02的00地址中的數(shù)讀出送D5 D6顯示
;清除鍵:將24C02的00地址清0
;鍵值清零鍵:將D1 D2顯示清0
KB_DELAY1 EQU 30H ;鍵盤子程序中延時(shí)用寄存器1
KB_DELAY2 EQU 31H ;鍵盤子程序中延時(shí)用寄存器2
H_NUM EQU 32H ;鍵盤程序中的行號(hào)
KEYNUM EQU 33H ;鍵盤程序中鍵值寄存器
D1 EQU 34H ;定義了各個(gè)數(shù)碼管的數(shù)據(jù)存儲(chǔ)器
D2 EQU 35H
D3 EQU 36H
D4 EQU 37H
D5 EQU 38H
D6 EQU 39H
D7 EQU 3AH
D8 EQU 3BH
I2C_DLAY1 EQU 3CH ;I2C時(shí)序延時(shí)寄存器1
I2C_DLAY2 EQU 3DH ;I2C時(shí)序延時(shí)寄存器2,值為寄存器1的一半
KEYNUM_TEMP EQU 3EH ;鍵值暫存器
COUNTER EQU 3FH ;I2C中串行移位計(jì)數(shù)器
SDA BIT P3.7 ;24C02的SDA腳接與單片機(jī)的P3.7
SCL BIT P3.6 ;24C02的SCL腳接與單片機(jī)的P3.6
ORG 0000H
AJMP START
ORG 000BH ;定時(shí)器0中斷子程序,用于數(shù)碼管的動(dòng)態(tài)掃描
LJMP TIMER0
ORG 0030H
START:
MOV SP,#60H ;設(shè)置堆棧棧底
MOV D1,#0 ;初始化數(shù)碼管的數(shù)據(jù)存儲(chǔ)器
MOV D2,#0
MOV D3,#0
MOV D4,#0
MOV D5,#0
MOV D6,#0
MOV D7,#0
MOV D8,#0
MOV KEYNUM_TEMP,#0 ;鍵值暫存器清零
MOV COUNTER,#8 ;一個(gè)字節(jié)為8位
MOV DPTR,#DISPLAY ;將位選碼存儲(chǔ)區(qū)首地址賦給DPTR
MOV R7,#0 ;R7是數(shù)碼管號(hào),用于位選碼查詢調(diào)用
MOV TMOD,#01H ;定時(shí)器0工作于方式1,16位計(jì)數(shù)
MOV TL0,#LOW(65536-1000) ;定時(shí)器0以1ms中斷一次,用于動(dòng)態(tài)掃描
MOV TH0,#HIGH(65536-1000)
SETB EA ;開總中斷
SETB ET0 ;開定時(shí)器0中斷
SETB TR0 ;起動(dòng)定時(shí)器0
;以下為鍵盤掃描與鍵值識(shí)別程序
KEYBOARD:
LCALL KB_SCAN ;調(diào)用鍵盤掃描程序
JZ KEYBOARD ;若無(wú)按鍵動(dòng)作,循環(huán)掃描
LCALL KB_DELAY ;若有按鍵動(dòng)作,調(diào)用20ms延時(shí)程序去抖動(dòng)
LCALL KB_SCAN ;然后再調(diào)用鍵盤掃描程序,看是否真的有按鍵動(dòng)作
JZ KEYBOARD ;若是抖動(dòng),則返回循環(huán)掃描
;確實(shí)有按鍵動(dòng)作,分析鍵值
SETB P2.0 ;使P2口的低四位口線接收數(shù)據(jù)
SETB P2.1
SETB P2.2
SETB P2.3
MOV P2,#11101111B ;P2.4這一行送0
MOV H_NUM,#0F0H ;此行行號(hào)為0
LCALL KB_ID ;調(diào)用按鍵識(shí)別程序
MOV P2,#11011111B ;P2.5這一行送0
MOV H_NUM,#0 ;對(duì)應(yīng)的此行的行號(hào)為4
LCALL KB_ID ;調(diào)用按鍵識(shí)別程序
MOV P2,#10111111B ;P2.6這一行送0
MOV H_NUM,#4 ;對(duì)應(yīng)的此行的行號(hào)為8
LCALL KB_ID ;調(diào)用按鍵識(shí)別程序
MOV P2,#01111111B ;P2.7這一行送0
MOV H_NUM,#8 ;對(duì)應(yīng)的此行的行號(hào)為12
LCALL KB_ID ;調(diào)用按鍵識(shí)別程序
;鍵值處理程序
MOV A,KEYNUM
CJNE A,#11110000B,W24C02_R
LCALL W24C02_WRITE ;按鍵有效,調(diào)用24C02的寫程序
AJMP KEYBOARD
W24C02_R:
CJNE A,#11110001B,RST_24C02
LCALL W24C02_READ ;按鍵有效,調(diào)用24C02的讀程序
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
MOV B,#10 ;結(jié)果是十進(jìn)制顯示
DIV AB ;在此,因?yàn)閿?shù)字鍵是0-11,沒(méi)有超過(guò)15,所以用此方法顯示出來(lái)也是正確的
MOV D5,B ;但是如果超出15再用這種方法,就是錯(cuò)誤
MOV D6,A ;假若數(shù)值00110110用此方法顯示出來(lái)的是54,而不是36。
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
AJMP KEYBOARD
RST_24C02:
CJNE A,#11110010B,RST_KB
LCALL W24C02_RST ;按鍵有效,調(diào)用復(fù)位24C02程序
AJMP KEYBOARD
RST_KB:
CJNE A,#11110011B,KB_DATA
MOV D1,#0 ;按鍵有效,將D1、D2清零
MOV D2,#0
MOV KEYNUM_TEMP,#0 ;鍵值寄存器也清0
AJMP KEYBOARD
KB_DATA: ;數(shù)值處理程序
MOV KEYNUM_TEMP,A ;將鍵值寫入暫存器中保存
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
MOV B,#10
DIV AB
MOV D1,B
MOV D2,A
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
AJMP KEYBOARD ;鍵盤掃描和識(shí)別后再返回掃描
;24C02的寫入一個(gè)字節(jié)程序
W24C02_WRITE:
LCALL I2C_START ;調(diào)I2C總線的起始時(shí)序
MOV A,#10100000B ;送器件地址給A,同時(shí)送'寫'標(biāo)記位
LCALL I2C_WRITE ;向I2C總線送數(shù)據(jù)
LCALL I2C_CHECK_ACK ;接收24C02的應(yīng)答信號(hào)
MOV A,#00H ;將00地址送給A
LCALL I2C_WRITE
LCALL I2C_CHECK_ACK
MOV A,KEYNUM_TEMP ;將鍵值送給A
LCALL I2C_WRITE ;向I2C總線送數(shù)據(jù)
LCALL I2C_CHECK_ACK ;接收應(yīng)答位
LCALL I2C_STOP ;調(diào)I2C總線停止時(shí)序
RET
;24C02的讀出一個(gè)字節(jié)程序
W24C02_READ:
LCALL I2C_START ;調(diào)I2C總線的起始時(shí)序
MOV A,#10100000B ;送器件地址給A,同時(shí)送'寫'標(biāo)記位
LCALL I2C_WRITE ;向I2C總線送數(shù)據(jù)
LCALL I2C_CHECK_ACK ;接收24C02的應(yīng)答信號(hào)
MOV A,#00H ;將00址址送給A
LCALL I2C_WRITE
LCALL I2C_CHECK_ACK
LCALL I2C_START ;///重起動(dòng)信號(hào)///////
MOV A,#10100001B ;送器件地址,同時(shí)送'讀'標(biāo)記位
LCALL I2C_WRITE
LCALL I2C_CHECK_ACK
LCALL I2C_READ ;接收I2C總線的8位數(shù)據(jù)
LCALL I2C_NACK ;向24C02發(fā)送非應(yīng)答位,用于告訴24C02終止發(fā)送數(shù)據(jù)
LCALL I2C_STOP ;調(diào)I2C總線停止時(shí)序
RET
;24C02的00地址清零
W24C02_RST:
LCALL I2C_START
MOV A,#10100000B
LCALL I2C_WRITE
LCALL I2C_CHECK_ACK
MOV A,#00H
LCALL I2C_WRITE
LCALL I2C_CHECK_ACK
MOV A,#0 ;將數(shù)據(jù)0寫入A,用于清零
LCALL I2C_WRITE
LCALL I2C_CHECK_ACK
LCALL I2C_STOP
RET
;以下為模擬I2C總線時(shí)序及讀寫I2C總線程序
;I2C總線起動(dòng)時(shí)序
I2C_START:
SETB SDA
SETB SCL
LCALL I2C_DELAY2
CLR SDA
LCALL I2C_DELAY2
CLR SCL ;鉗位住時(shí)序信號(hào),以期繼續(xù)使用
LCALL I2C_DELAY1
RET
;I2C總線的停止時(shí)序
I2C_STOP:
CLR SDA
SETB SCL
LCALL I2C_DELAY2
SETB SDA
LCALL I2C_DELAY2
RET
;I2C總線的應(yīng)答信號(hào)
/*I2C_ACK:
CLR SDA
SETB SCL
LCALL I2C_DELAY1
CLR SCL
LCALL I2C_DELAY1
RET */
;I2C總線的非應(yīng)答信號(hào)
I2C_NACK:
SETB SDA
SETB SCL
LCALL I2C_DELAY1
CLR SCL
LCALL I2C_DELAY1
RET
;檢測(cè)接收I2C總線的應(yīng)答信號(hào)
I2C_CHECK_ACK:
SETB SDA
SETB SCL
LCALL I2C_DELAY2
MOV C,SDA ;在高電平的一半時(shí)刻,采集信號(hào)電平
LCALL I2C_DELAY2
CLR SCL
LCALL I2C_DELAY1
RET
;向I2C總線寫入一個(gè)字節(jié)
I2C_WRITE:
RLC A ;通過(guò)A向C中移位送出
MOV SDA,C
SETB SCL
LCALL I2C_DELAY1
CLR SCL
LCALL I2C_DELAY1
DJNZ COUNTER,I2C_WRITE ;計(jì)數(shù)8個(gè)位
MOV COUNTER,#8
RET
;從I2C總線上讀出一個(gè)字節(jié)
I2C_READ:
SETB SDA
SETB SCL
LCALL I2C_DELAY2
MOV C,SDA ;在高電平的一半時(shí)刻,采集信號(hào)電平
LCALL I2C_DELAY2
CLR SCL
LCALL I2C_DELAY1
RLC A ;讀出的數(shù)據(jù)存在A中
DJNZ COUNTER,I2C_READ ;計(jì)數(shù)8個(gè)位
MOV COUNTER,#8
RET
;I2C總線時(shí)序所用延時(shí)1,用于高低電平的時(shí)長(zhǎng)
I2C_DELAY1:
MOV I2C_DLAY1,#4
DJNZ I2C_DLAY1,$
RET
;I2C總線時(shí)序所用延時(shí)2,數(shù)值為I2C_DELAY1的一半,用于高電平一半時(shí)刻采集數(shù)據(jù)
I2C_DELAY2:
MOV I2C_DLAY2,#2
DJNZ I2C_DLAY2,$
RET
;定時(shí)器0中斷程序,用于數(shù)碼管的動(dòng)態(tài)掃描
;用到的寄存器有:A,R7,DPTR 還有自定義的D1--D8
TIMER0:
PUSH ACC ;保存A中數(shù)據(jù)
MOV TL0,#LOW(65536-1000) ;定時(shí)器重新賦值
MOV TH0,#HIGH(65536-1000)
MOV A,R7 ;將 要送顯的數(shù)碼管號(hào)送與A中
MOVC A,@A+DPTR ;將 要送顯的數(shù)碼管號(hào)所對(duì)應(yīng)的位先碼送A中
CJNE R7,#0,TM0_DP1 ;將R7中的數(shù)與0比較,不相等則跳轉(zhuǎn)往下查詢比較
ANL D1,#0FH ;相等的話,將D1中數(shù)據(jù)的高四位屏蔽掉
ADD A,D1 ;將位選碼與D1中的數(shù)據(jù)相加
AJMP TM0_DISP ;跳到送顯子程序
TM0_DP1:
CJNE R7,#1,TM0_DP2 ;將R7中的數(shù)與1比較,不相等則跳轉(zhuǎn)往下查詢比較
ANL D2,#0FH
ADD A,D2
AJMP TM0_DISP
TM0_DP2:
CJNE R7,#2,TM0_DP3 ;將R7中的數(shù)與2比較,不相等則跳轉(zhuǎn)往下查詢比較
ANL D3,#0FH
ADD A,D3
AJMP TM0_RETI
TM0_DP3:
CJNE R7,#3,TM0_DP4 ;將R7中的數(shù)與3比較,不相等則跳轉(zhuǎn)往下查詢比較
ANL D4,#0FH
ADD A,D4
AJMP TM0_RETI
TM0_DP4:
CJNE R7,#4,TM0_DP5 ;將R7中的數(shù)與4比較,不相等則跳轉(zhuǎn)往下查詢比較
ANL D5,#0FH
ADD A,D5
AJMP TM0_DISP
TM0_DP5:
CJNE R7,#5,TM0_DP6 ;將R7中的數(shù)與5比較,不相等則跳轉(zhuǎn)往下查詢比較
ANL D6,#0FH
ADD A,D6
AJMP TM0_DISP
TM0_DP6:
CJNE R7,#6,TM0_DP7 ;將R7中的數(shù)與6比較,不相等則跳轉(zhuǎn)往下查詢比較
ANL D7,#0FH
ADD A,D7
AJMP TM0_RETI
TM0_DP7:
CJNE R7,#7,TM0_DISP ;將R7中的數(shù)與7比較,不相等則跳轉(zhuǎn)到送顯子程序
ANL D8,#0FH
ADD A,D8
AJMP TM0_RETI
TM0_DISP: ;送顯子程序
MOV P0,A
TM0_RETI:
INC R7
CJNE R7,#8,TM0_RET ;如果R7中的數(shù)據(jù)小于或不等于8,返回
MOV R7,#0 ;如果等于8,則將R7清零
TM0_RET:
POP ACC ;出棧A中的數(shù)據(jù)
RETI
;按鍵識(shí)別程序
KB_ID:
JB P2.0,KBID_P21 ;如若不是P2.0列有動(dòng)作,跳轉(zhuǎn)查下一列
JNB P2.0,$ ;如果是該列動(dòng)作,當(dāng)按鍵未松開時(shí),在此循環(huán)等待
MOV A,#0 ;按鍵松開時(shí),將該列的列號(hào)賦值給A
ADD A,H_NUM ;將行號(hào)和列號(hào)相加,得到按鍵的鍵值
MOV KEYNUM,A ;將鍵值傳給KEYNUM
RET
KBID_P21:
JB P2.1,KBID_P22 ;如若不是P2.1列有動(dòng)作,跳轉(zhuǎn)查下一列
JNB P2.1,$
MOV A,#1 ;將該列的列號(hào)賦值給A
ADD A,H_NUM ;行號(hào)和列號(hào)相加得鍵值
MOV KEYNUM,A
RET
KBID_P22:
JB P2.2,KBID_P23 ;如若不是P2.2列有動(dòng)作,跳轉(zhuǎn)查一列
JNB P2.2,$
MOV A,#2 ;該列的列號(hào)賦值給A
ADD A,H_NUM ;行號(hào)和列號(hào)相加得鍵值
MOV KEYNUM,A
RET
KBID_P23:
JB P2.3,KEID_END ;如若不是P2.3列有動(dòng)作,跳轉(zhuǎn)到返回處
JNB P2.3,$
MOV A,#3 ;該列的列號(hào)賦值給A
ADD A,H_NUM ;行號(hào)和列號(hào)相加得鍵值
MOV KEYNUM,A
KEID_END:
RET
;鍵盤掃描程序
KB_SCAN:
SETB P2.0 ;使P2口的低四位口線處于接收狀態(tài)
SETB P2.1
SETB P2.2
SETB P2.3
MOV P2,#00001111B ;P2口寄存器高四位賦初值為1,低四位賦初值為0
MOV A,P2
XRL A,#00001111B ;判斷P2口是否有按鍵動(dòng)作,若有則A不全為0,若沒(méi)有動(dòng)作則A中全為0
RET
;鍵盤去抖動(dòng)延時(shí)子程序,延時(shí)為20ms
KB_DELAY:
MOV KB_DELAY1,#100
KB_D0:MOV KB_DELAY2,#200
KB_D1:DJNZ KB_DELAY2,KB_D1
DJNZ KB_DELAY1,KB_D0
RET
;數(shù)碼管位選碼數(shù)據(jù)存儲(chǔ)區(qū)
DISPLAY:
DB 01110000B
DB 01100000B
DB 01010000B
DB 01000000B
DB 00110000B
DB 00100000B
DB 00010000B
DB 00000000B
END
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -