📄 24c02_wr.asm
字号:
;本程序实现对24C02的一个单元(地址为00)的读写和清零操作
;适用于 DXDZ 51+AVR-A 开发板
;开发板上最左排的四个按键为功能键,从下至上依次为:写入键、读出键,清除键、键值清零键 其余为数字键
;写入键:将数字键的键值(显示在D1 D2)写入到24C02的00地址
;读出键:将24C02的00地址中的数读出送D5 D6显示
;清除键:将24C02的00地址清0
;键值清零键:将D1 D2显示清0
KB_DELAY1 EQU 30H ;键盘子程序中延时用寄存器1
KB_DELAY2 EQU 31H ;键盘子程序中延时用寄存器2
H_NUM EQU 32H ;键盘程序中的行号
KEYNUM EQU 33H ;键盘程序中键值寄存器
D1 EQU 34H ;定义了各个数码管的数据存储器
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时序延时寄存器1
I2C_DLAY2 EQU 3DH ;I2C时序延时寄存器2,值为寄存器1的一半
KEYNUM_TEMP EQU 3EH ;键值暂存器
COUNTER EQU 3FH ;I2C中串行移位计数器
SDA BIT P3.7 ;24C02的SDA脚接与单片机的P3.7
SCL BIT P3.6 ;24C02的SCL脚接与单片机的P3.6
ORG 0000H
AJMP START
ORG 000BH ;定时器0中断子程序,用于数码管的动态扫描
LJMP TIMER0
ORG 0030H
START:
MOV SP,#60H ;设置堆栈栈底
MOV D1,#0 ;初始化数码管的数据存储器
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 ;一个字节为8位
MOV DPTR,#DISPLAY ;将位选码存储区首地址赋给DPTR
MOV R7,#0 ;R7是数码管号,用于位选码查询调用
MOV TMOD,#01H ;定时器0工作于方式1,16位计数
MOV TL0,#LOW(65536-1000) ;定时器0以1ms中断一次,用于动态扫描
MOV TH0,#HIGH(65536-1000)
SETB EA ;开总中断
SETB ET0 ;开定时器0中断
SETB TR0 ;起动定时器0
;以下为键盘扫描与键值识别程序
KEYBOARD:
LCALL KB_SCAN ;调用键盘扫描程序
JZ KEYBOARD ;若无按键动作,循环扫描
LCALL KB_DELAY ;若有按键动作,调用20ms延时程序去抖动
LCALL KB_SCAN ;然后再调用键盘扫描程序,看是否真的有按键动作
JZ KEYBOARD ;若是抖动,则返回循环扫描
;确实有按键动作,分析键值
SETB P2.0 ;使P2口的低四位口线接收数据
SETB P2.1
SETB P2.2
SETB P2.3
MOV P2,#11101111B ;P2.4这一行送0
MOV H_NUM,#0F0H ;此行行号为0
LCALL KB_ID ;调用按键识别程序
MOV P2,#11011111B ;P2.5这一行送0
MOV H_NUM,#0 ;对应的此行的行号为4
LCALL KB_ID ;调用按键识别程序
MOV P2,#10111111B ;P2.6这一行送0
MOV H_NUM,#4 ;对应的此行的行号为8
LCALL KB_ID ;调用按键识别程序
MOV P2,#01111111B ;P2.7这一行送0
MOV H_NUM,#8 ;对应的此行的行号为12
LCALL KB_ID ;调用按键识别程序
;键值处理程序
MOV A,KEYNUM
CJNE A,#11110000B,W24C02_R
LCALL W24C02_WRITE ;按键有效,调用24C02的写程序
AJMP KEYBOARD
W24C02_R:
CJNE A,#11110001B,RST_24C02
LCALL W24C02_READ ;按键有效,调用24C02的读程序
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
MOV B,#10 ;结果是十进制显示
DIV AB ;在此,因为数字键是0-11,没有超过15,所以用此方法显示出来也是正确的
MOV D5,B ;但是如果超出15再用这种方法,就是错误
MOV D6,A ;假若数值00110110用此方法显示出来的是54,而不是36。
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
AJMP KEYBOARD
RST_24C02:
CJNE A,#11110010B,RST_KB
LCALL W24C02_RST ;按键有效,调用复位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: ;数值处理程序
MOV KEYNUM_TEMP,A ;将键值写入暂存器中保存
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
MOV B,#10
DIV AB
MOV D1,B
MOV D2,A
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
AJMP KEYBOARD ;键盘扫描和识别后再返回扫描
;24C02的写入一个字节程序
W24C02_WRITE:
LCALL I2C_START ;调I2C总线的起始时序
MOV A,#10100000B ;送器件地址给A,同时送'写'标记位
LCALL I2C_WRITE ;向I2C总线送数据
LCALL I2C_CHECK_ACK ;接收24C02的应答信号
MOV A,#00H ;将00地址送给A
LCALL I2C_WRITE
LCALL I2C_CHECK_ACK
MOV A,KEYNUM_TEMP ;将键值送给A
LCALL I2C_WRITE ;向I2C总线送数据
LCALL I2C_CHECK_ACK ;接收应答位
LCALL I2C_STOP ;调I2C总线停止时序
RET
;24C02的读出一个字节程序
W24C02_READ:
LCALL I2C_START ;调I2C总线的起始时序
MOV A,#10100000B ;送器件地址给A,同时送'写'标记位
LCALL I2C_WRITE ;向I2C总线送数据
LCALL I2C_CHECK_ACK ;接收24C02的应答信号
MOV A,#00H ;将00址址送给A
LCALL I2C_WRITE
LCALL I2C_CHECK_ACK
LCALL I2C_START ;///重起动信号///////
MOV A,#10100001B ;送器件地址,同时送'读'标记位
LCALL I2C_WRITE
LCALL I2C_CHECK_ACK
LCALL I2C_READ ;接收I2C总线的8位数据
LCALL I2C_NACK ;向24C02发送非应答位,用于告诉24C02终止发送数据
LCALL I2C_STOP ;调I2C总线停止时序
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 ;将数据0写入A,用于清零
LCALL I2C_WRITE
LCALL I2C_CHECK_ACK
LCALL I2C_STOP
RET
;以下为模拟I2C总线时序及读写I2C总线程序
;I2C总线起动时序
I2C_START:
SETB SDA
SETB SCL
LCALL I2C_DELAY2
CLR SDA
LCALL I2C_DELAY2
CLR SCL ;钳位住时序信号,以期继续使用
LCALL I2C_DELAY1
RET
;I2C总线的停止时序
I2C_STOP:
CLR SDA
SETB SCL
LCALL I2C_DELAY2
SETB SDA
LCALL I2C_DELAY2
RET
;I2C总线的应答信号
/*I2C_ACK:
CLR SDA
SETB SCL
LCALL I2C_DELAY1
CLR SCL
LCALL I2C_DELAY1
RET */
;I2C总线的非应答信号
I2C_NACK:
SETB SDA
SETB SCL
LCALL I2C_DELAY1
CLR SCL
LCALL I2C_DELAY1
RET
;检测接收I2C总线的应答信号
I2C_CHECK_ACK:
SETB SDA
SETB SCL
LCALL I2C_DELAY2
MOV C,SDA ;在高电平的一半时刻,采集信号电平
LCALL I2C_DELAY2
CLR SCL
LCALL I2C_DELAY1
RET
;向I2C总线写入一个字节
I2C_WRITE:
RLC A ;通过A向C中移位送出
MOV SDA,C
SETB SCL
LCALL I2C_DELAY1
CLR SCL
LCALL I2C_DELAY1
DJNZ COUNTER,I2C_WRITE ;计数8个位
MOV COUNTER,#8
RET
;从I2C总线上读出一个字节
I2C_READ:
SETB SDA
SETB SCL
LCALL I2C_DELAY2
MOV C,SDA ;在高电平的一半时刻,采集信号电平
LCALL I2C_DELAY2
CLR SCL
LCALL I2C_DELAY1
RLC A ;读出的数据存在A中
DJNZ COUNTER,I2C_READ ;计数8个位
MOV COUNTER,#8
RET
;I2C总线时序所用延时1,用于高低电平的时长
I2C_DELAY1:
MOV I2C_DLAY1,#4
DJNZ I2C_DLAY1,$
RET
;I2C总线时序所用延时2,数值为I2C_DELAY1的一半,用于高电平一半时刻采集数据
I2C_DELAY2:
MOV I2C_DLAY2,#2
DJNZ I2C_DLAY2,$
RET
;定时器0中断程序,用于数码管的动态扫描
;用到的寄存器有:A,R7,DPTR 还有自定义的D1--D8
TIMER0:
PUSH ACC ;保存A中数据
MOV TL0,#LOW(65536-1000) ;定时器重新赋值
MOV TH0,#HIGH(65536-1000)
MOV A,R7 ;将 要送显的数码管号送与A中
MOVC A,@A+DPTR ;将 要送显的数码管号所对应的位先码送A中
CJNE R7,#0,TM0_DP1 ;将R7中的数与0比较,不相等则跳转往下查询比较
ANL D1,#0FH ;相等的话,将D1中数据的高四位屏蔽掉
ADD A,D1 ;将位选码与D1中的数据相加
AJMP TM0_DISP ;跳到送显子程序
TM0_DP1:
CJNE R7,#1,TM0_DP2 ;将R7中的数与1比较,不相等则跳转往下查询比较
ANL D2,#0FH
ADD A,D2
AJMP TM0_DISP
TM0_DP2:
CJNE R7,#2,TM0_DP3 ;将R7中的数与2比较,不相等则跳转往下查询比较
ANL D3,#0FH
ADD A,D3
AJMP TM0_RETI
TM0_DP3:
CJNE R7,#3,TM0_DP4 ;将R7中的数与3比较,不相等则跳转往下查询比较
ANL D4,#0FH
ADD A,D4
AJMP TM0_RETI
TM0_DP4:
CJNE R7,#4,TM0_DP5 ;将R7中的数与4比较,不相等则跳转往下查询比较
ANL D5,#0FH
ADD A,D5
AJMP TM0_DISP
TM0_DP5:
CJNE R7,#5,TM0_DP6 ;将R7中的数与5比较,不相等则跳转往下查询比较
ANL D6,#0FH
ADD A,D6
AJMP TM0_DISP
TM0_DP6:
CJNE R7,#6,TM0_DP7 ;将R7中的数与6比较,不相等则跳转往下查询比较
ANL D7,#0FH
ADD A,D7
AJMP TM0_RETI
TM0_DP7:
CJNE R7,#7,TM0_DISP ;将R7中的数与7比较,不相等则跳转到送显子程序
ANL D8,#0FH
ADD A,D8
AJMP TM0_RETI
TM0_DISP: ;送显子程序
MOV P0,A
TM0_RETI:
INC R7
CJNE R7,#8,TM0_RET ;如果R7中的数据小于或不等于8,返回
MOV R7,#0 ;如果等于8,则将R7清零
TM0_RET:
POP ACC ;出栈A中的数据
RETI
;按键识别程序
KB_ID:
JB P2.0,KBID_P21 ;如若不是P2.0列有动作,跳转查下一列
JNB P2.0,$ ;如果是该列动作,当按键未松开时,在此循环等待
MOV A,#0 ;按键松开时,将该列的列号赋值给A
ADD A,H_NUM ;将行号和列号相加,得到按键的键值
MOV KEYNUM,A ;将键值传给KEYNUM
RET
KBID_P21:
JB P2.1,KBID_P22 ;如若不是P2.1列有动作,跳转查下一列
JNB P2.1,$
MOV A,#1 ;将该列的列号赋值给A
ADD A,H_NUM ;行号和列号相加得键值
MOV KEYNUM,A
RET
KBID_P22:
JB P2.2,KBID_P23 ;如若不是P2.2列有动作,跳转查一列
JNB P2.2,$
MOV A,#2 ;该列的列号赋值给A
ADD A,H_NUM ;行号和列号相加得键值
MOV KEYNUM,A
RET
KBID_P23:
JB P2.3,KEID_END ;如若不是P2.3列有动作,跳转到返回处
JNB P2.3,$
MOV A,#3 ;该列的列号赋值给A
ADD A,H_NUM ;行号和列号相加得键值
MOV KEYNUM,A
KEID_END:
RET
;键盘扫描程序
KB_SCAN:
SETB P2.0 ;使P2口的低四位口线处于接收状态
SETB P2.1
SETB P2.2
SETB P2.3
MOV P2,#00001111B ;P2口寄存器高四位赋初值为1,低四位赋初值为0
MOV A,P2
XRL A,#00001111B ;判断P2口是否有按键动作,若有则A不全为0,若没有动作则A中全为0
RET
;键盘去抖动延时子程序,延时为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
;数码管位选码数据存储区
DISPLAY:
DB 01110000B
DB 01100000B
DB 01010000B
DB 01000000B
DB 00110000B
DB 00100000B
DB 00010000B
DB 00000000B
END
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -