⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 24c02_wr.asm

📁 51单片机中的AT24C02的读写程序
💻 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 + -