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

📄 i2c存储器读写实验.asm

📁 I2C存储器读写实验,用的是AT24C01的芯片
💻 ASM
字号:
;;; I2C存储器读写实验
;;; MCU:89S51    COLCK:11.0592MHZ
;;; 
;;; 实验目的: 1. 通过实验了解I2C的工作原理和用软件模拟I2C总线的编程方法
;;;           2. 通过实验了解数据存入I2C E2PROM的过程,实现数据掉电保存.
;;; 实验内容:把数据存入E2PROM中的指定的地址,而后在把指定地址
;;; 的数据读出来比较,如相等表示数据读写正常,rxd1发光提示,反之没提示.
;;; 而后把读到的数据送入电脑显示
;;; 
;;; ***********************************************************************
;;; 接线说明:
;;; J10(25x2双排插针)第6脚(SD0)和第18脚(CPU的P1.1)连
;;; J10(25x2双排插针)第8脚(SC0)和第316脚(CPU的P1.0)连
;;; 接上串口线,打开"串口监视软件",波特率设为19200
;;;***********************************************************************
           rxd1   BIT   P3.0
           SCL   BIT   p1.0     ; SCL I2C总线位
           SDA   BIT   p1.1     ;SDA   I2C总线位
           SLA   DATA  37H      ;SLA 器件从地址
          SUBA   DATA  38H      ;SUBA器件子地址
           MRD   DATA  40H     ;MRD 接收数据缓冲区首址
           MTD   DATA  48H     ;MTD 发送数据缓冲区首址
           ACK   BIT   30H    ;ACK为调试/测试位,ACK为0时表示无器件应答
       NUMBYTE   DATA  36H     ;NUMBYTE读/写的字节数


                ORG  0000H
                AJMP  MAIN
                ORG  0080H
     MAIN:    ACALL  A200MS
               MOV  R1,#04
               MOV  R0,#MTD
               MOV   A,#30h;00H
     DELETE0:      ;发送缓冲区赋值分别为00H-03H
                MOV  @R0,A
                INC  R0
                INC  A
                DJNZ  R1,DELETE0

          ;存储空间的首地址:B是高地址A 是低地址如把数据存到高于255地址的存储空间如288(120H)
          ;那B=01H,A=20H ,如把数据存到不高于255地址存储空间如28,那B=0H,A=14H
     DELETE1: MOV  A,#20H
              MOV  B,#00H
       ;  I2C(24XX 存储器)
               MOV SLA,#10100000B
               MOV SUBA, A      ;指定子地址
               MOV  A,B
               RL A
               ADD  A,SLA
               MOV  SLA,A        ;器件从地址
               MOV NUMBYTE, #04h ;接收字节数NUMBYTE
               nop
               ACALL   IWRNBYTE  ;调用I2C写程序
               ACALL  A200MS     ;
               ;;;;;;;;;;;
               MOV  R0,#MRD
               MOV  R2,#04H
       CLRR: CLR  A             ;接受数据缓冲区清零
             MOV  @R0,A
             INC  R0
             DJNZ  R2,CLRR
                                ;存储空间的首地址:B是高地址A 是低地址
   KEYBJASM1: MOV  A,#20H
              MOV  B,#00H

       ; 读数据 I2C(24XX 存储器)
               MOV SLA,#10100000B
               MOV SUBA, A      ;指定子地址
               MOV  A,B
               RL A
               ADD  A,SLA
               MOV  SLA,A        ;器件从地址
               MOV NUMBYTE, #04h ;接收字节数NUMBYTE
               nop
               LCALL IRDNBYTE    ;向I2C(24XX)器件指定子地址读N个数据
               ;;; 数据比较
               MOV  R2,#04H      ;赋要比较数据的个数
               MOV R0,#MTD       ;发送数据缓冲区首地址
               MOV  R1,#MRD      ;接受数据缓冲区首地址MRD
    BJMD1:     MOV  A,@R0
               XRL  A,@R1        ;两个数据比较(用异或来比较是否相等)
               JNZ  BJMD0        ;不相等就转BJMD0
               INC R0            ;数据缓冲区首地址+1
               INC  R1
               DJNZ  R2,BJMD1    ;数据没比较完就继续
               CLR rxd1           ;两组数据相等rxd1发光提示
               ; 串行口发送到电脑显示 波特率为19200.
      ; 串行口发送到电脑显示 波特率为19200.
    RS232: MOV TMOD,#20H       ;设定T1为定时方式2
           MOV TH1,#0FDH       ;定时初值
           MOV TL1,#0FDH       ;
           MOV  PCON,#80H      ;波特率为19200
           SETB  TR1           ;;;;;启动定时器
           MOV SCON,#50H       ;串口方式1
           MOV R0,#MRD         ;#BLK1;;数据地址指针
           MOV R7,#4H          ;数据长度
   ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    AAA0:  MOV  A,@R0
           ANL  A,#0F0H
           SWAP A
           MOV  DPTR,#CARDASCII
           MOVC  A,@A+DPTR      ;把数据转换成ASCII显示
           MOV  SBUF,A          ;发送一个数据
           MOV  A,@R0
           ANL  A,#0FH
    AAA1:  JBC TI,AAA2;;;
           SJMP  AAA1;;;;
    AAA2:  MOV  DPTR,#CARDASCII
           MOVC  A,@A+DPTR      ;把数据转换成ASCII显示
           MOV  SBUF,A          ;发送一个数据

    AAA3:  JBC TI,AAA4;;;
           SJMP  AAA3;;;;
    AAA4:  MOV  A,#16

           MOV  DPTR,#CARDASCII
           MOVC  A,@A+DPTR       ;把数据转换成ASCII显示
           MOV  SBUF,A           ;发送一个数据

    AAA5:  JBC TI,AAA6;;;
           SJMP  AAA5;;;;
    AAA6:  MOV  A,#17
           MOV  DPTR,#CARDASCII
           MOVC  A,@A+DPTR       ;把数据转换成ASCII显示
           MOV  SBUF,A           ;发送一个数据
           INC R0                ;数据地址指针加1
    AAA7:  JBC TI,AAA8;;;
           SJMP  AAA7;;;;
    AAA8:  DJNZ  R7,AAA0

    ;;;;;;
           jb  p1.0,$
           ajmp  KEYBJASM1
               AJMP  $
    BJMD0:     SETB  rxd1          ;两组数据不相等
               AJMP  RS232
     A200MS:                         ;200MS延时
           MOV  R6,#00
  A200MS1: MOV  R7,#0EFH
  A200MS2: NOP
           DJNZ  R7,A200MS2
           DJNZ  R6,A200MS1
           RET
               ;;;;;;;;;
         CARDASCII :DB 30H,31H,32H,33H,34H,35H,36H,37H,38H,39H,41H,42H,43H,44H,45H,46H,48H,20H
                  ;HEX:00H,01H,02H,03H,04H,05H,06H,07H,08H,09H,0AH,0BH,0CH,0DH,0EH,0FH,0HH,空格.
;--------------------------------------------------------------------------------------------------------
;VI2C_ASM.ASM
;I2C 软件包的底层子程序,使用前要定义好SCL和SDA。在标准80C51模式
;(12 Clock)下,对主频要求是不高于12MHz(1个机器周期1us);若Fosc>12MHz
;则要增加相应的NOP指令数。在使用本软件包时,请在你的程序的未尾加入
;$INCLUDE (VI2C_ASM.ASM)即可。
;--------------------------------------------------------------------------------------------------------
;启动I2C总线子程序
START:    SETB  SDA
          NOP
          SETB  SCL     			 ;起始条件建立时间大于4.7us
          NOP
          NOP
          NOP
          NOP
          NOP
          CLR  SDA
          NOP           		 	;起始条件锁定时大于4us
          NOP
          NOP
          NOP
          NOP
          CLR   SCL     		 	;钳住总线,准备发数据
          NOP
          RET

;结束总线子程序
STOP:     CLR    SDA
          NOP
          SETB   SCL    			;发送结束条件的时钟信号
          NOP           			;结束总线时间大于4us
          NOP
          NOP
          NOP
          NOP
          SETB  SDA    			;结束总线
          NOP          			;保证一个终止信号和起始信号的空闲时间大于4.7us
          NOP
          NOP
          NOP
          RET

;发送应答信号子程序
MACK:     CLR  	SDA      		;将SDA置0
          NOP
          NOP
          SETB 	SCL
          NOP            		;保持数据时间,即SCL为高时间大于4.7us
          NOP
          NOP
          NOP
          NOP
          CLR  	SCL
          NOP
          NOP
          RET

;发送非应答信号
MNACK:  SETB 	SDA          	        ;将SDA置1
          NOP
          NOP
          SETB 	SCL
          NOP
       	  NOP               		;保持数据时间,即SCL为高时间大于4.7us
          NOP
          NOP
          NOP
          CLR  SCL
          NOP
          NOP
          RET

; 检查应答位子程序
; 返回值,ACK=1时表示有应答
CACK:	SETB  SDA
        NOP
        NOP
        SETB  SCL
        CLR   ACK
        NOP
        NOP
        MOV  C,SDA
        JC    CEND
        SETB  ACK           		 ;判断应答位
CEND:	NOP
        CLR  SCL
        NOP
        RET

;发送字节子程序
;字节数据放入ACC
;每发送一字节要调用一次CACK子程序,取应答位
WRBYTE: MOV  R0,#08H
WLP: 	RLC   A              		;取数据位
        JC     WR1
        SJMP  WR0            		;判断数据位
WLP1:   DJNZ  R0,WLP
        NOP
        RET
WR1:    SETB  SDA            		;发送1
        NOP
        SETB  SCL
        NOP
        NOP
        NOP
        NOP
        NOP
        CLR   SCL
        SJMP  WLP1
WR0:  	CLR   SDA            		;发送0
        NOP
        SETB  SCL
        NOP
        NOP
        NOP
        NOP
        NOP
        CLR  SCL
        SJMP WLP1

;读取字节子程序
;读出的值在ACC
;每取一字节要发送一个应答/非应答信号
RDBYTE: MOV  R0,#08H
RLP:    SETB  SDA
        NOP
        SETB  SCL         		 ;时钟线为高,接收数据位
        NOP
        NOP
        MOV  C,SDA        		 ;读取数据位
        MOV  A,R2
        CLR   SCL          		 ;将SCL拉低,时间大于4.7us
        RLC   A            		 ;进行数据位的处理
        MOV  R2,A
        NOP
        NOP
        NOP
        DJNZ  R0,RLP        		 ;未够8位,再来一次
        RET

; 无子地址器件写字节数据
; 入口参数: 数据为ACC、器件从地址SLA
; 占用:  A、R0、CY
IWRBYTE: PUSH   ACC
IWBLOOP: LCALL  START      		;起动总线
         MOV    A,SLA
         LCALL  WRBYTE     		;发送器件从地址
         LCALL  CACK
         JNB     ACK,RETWRB             ;无应答则跳转
         POP     ACC       		;写数据
         LCALL  WRBYTE
         LCALL  CACK
         LCALL  STOP
         RET
RETWRB:  POP     ACC
         LCALL  STOP
         RET

;无子地址器件读字节数据
;入口参数: 器件从地址SLA
;出口参数: 数据为ACC
;占用 A 、R0、R2 、CY
IRDBYTE: LCALL  START
         MOV    A,SLA           ;发送器件从地址
         INC     A
         LCALL  WRBYTE
         LCALL  CACK
         JNB     ACK,RETRDB
         LCALL  RDBYTE       	;进行读字节操作
         LCALL  MNACK          	;发送非应信号
RETRDB:  LCALL  STOP            ;结束总线
         RET

;向器件指定子地址写N个数据
;入口参数:  器件从地址SLA、器件子地址SUBA 、发送数据缓冲区MTD、发送字节数NUMBYTE
; 占用:  A 、R0 、R1 、R3 、CY
IWRNBYTE: MOV    A,NUMBYTE
          MOV    R3,A
          LCALL  START        	;起动总线
          MOV    A,SLA
          LCALL  WRBYTE       	;发送器件从地址
          LCALL  CACK
          JNB     ACK,RETWRN	;无应答则退出
          MOV    A,SUBA       	;指定子地址
          LCALL  WRBYTE
          LCALL  CACK
          MOV    R1,#MTD
WRDA:     MOV    A,@R1
          LCALL  WRBYTE       	;开始写入数据
          LCALL  CACK
          JNB     ACK,IWRNBYTE
          INC     R1
          DJNZ    R3,WRDA      	;判断写完没有
RETWRN:   LCALL  STOP
          RET

;向器件指定子地址读取N个数据
;入口参数:  器件从地址SLA、器件子地址SUBA、接收字节数NUMBYTE
;出口参数:  接收数据缓冲区MTD
;占用:A、 R0、 R1、 R2、 R3、 CY
IRDNBYTE:  MOV    R3,NUMBYTE
           LCALL  START
           MOV    A,SLA
           LCALL  WRBYTE        ;发送器件从地址
           LCALL  CACK
           JNB     ACK,RETRDN
           MOV    A,SUBA        ;指定子地址
           LCALL  WRBYTE
           LCALL  CACK
           LCALL  START         ;重新起动总线
           MOV    A,SLA
           INC     A            ;准备进行读操作
           LCALL  WRBYTE
           LCALL  CACK
           JNB     ACK,IRDNBYTE
           MOV    R1,#MRD
RDN1:      LCALL  RDBYTE      	;读操作开始
           MOV    @R1,A
           DJNZ    R3,SACK
           LCALL  MNACK       	;最后一字节发非应答位
RETRDN:    LCALL  STOP 		;并结束总线
           RET
SACK:      LCALL  MACK
           INC     R1
           SJMP   RDN1
;***************************************************************************************
;                         请注意                                                       *
;                                                                                      *
;占用内部资源:         R0,R1,R2,R3,ACC,Cy。                                      *
;    在你的程序里要做以下定义:                                                        *
;使用前须定义变量:  SLA 器件从地址  SUBA器件子地址  NUMBYTE读/写的字节数 ,位变量ACK *
;使用前须定义常量:  SDA SCL 总线位  MTD 发送数据缓冲区首址    MRD 接收数据缓冲区首址  *
;(ACK为调试/测试位,ACK为0时表示无器件应答)                                          *
;***************************************************************************************
end

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -