24CXX系列读写程序(EMC指令版)大话篇

嵌入式设计应用

132人已加入

描述

24CXX系列读写程序(EMC指令版)大话篇

话说程序匠人,自进论坛以来,天天勤练,日日苦修(花了我东家的不少上网费!!),以《大话篇》系列,嬴得了无数MM得芳心……终于将积分修到500分以上(呵呵,以后可以贴图片了,如果那位MM想一睹匠人的“浴”照,说一声,小匠一定满足)……

—— 身后突然传来一声呵斥:“休不休啊你?”
—— 匠人心头一惊,蓦然回首,那人(不是MM,是斑竹)正在灯火阑珊处(手中正握着那把失而复得的大砍刀)……
—— 匠人暗自庆幸还没有把对斑竹不敬的话语说出来……

……在论坛中,小匠结识了许多高手好友,并得到不少帮助,感激不尽。但也有一些MM好报打不平,觉得小匠在《大话篇》中老是受斑竹的欺负……

—— 一道寒光映入眼帘,匠人发现自己好象说漏了嘴……
—— 再看斑竹手中的刀,已经从刀鞘中抽出了两公分……

……其实,那都是大伙的误解……其实,小匠一直非常感谢斑竹的厚道和宽容,没有将小匠的一些大话帖子DELETE掉……

—— 匠人好象听到了砍刀缓缓入鞘的金属声……
—— 暗呼:“好险!”
—— 匠人再次悄悄回头,只见斑竹大人已经远远去了(头上顶着一顶精致的兰花大高帽)

……最近,连续看到好几篇讨论24CXX系列应用的帖子。正好,小匠最近用EMC的指令也做了一段程序。不如无私奉献一下(如果哪位MM有疑问,可来函、来电、来EMAIL、来FAX、来人,或者约下第一次亲密约会,探讨探讨……)

 


;******************************************
;** 24CXX  接口I2C总线读/写的程序
;**  (所有时序均基于4MHZ晶体震荡器频率)
;******************************************
/*
;****************************
;随机读写测试程序(示范程序)
;****************************
TEST:
    MOV    A,@0XAE        ;A2=A1=A0=1
    MOV    SLAVE_24,A    ;设置器件码
    MOV    A,@2        ;R/W LOC. = 2
    MOV    ADDR_24,A    ;设置地址码
    MOV    A,@55        ;
    MOV    DATA_24,A    ;写55到E2PROM
    CALL    WRBYTE        ;写一个字节
    CALL    DL10MS        ;延时10MS,等待写操作完成(注意,此语句非常重要)
    CALL     RDBYTE        ;读回原数据
    MOV    A,@55        ;
    XOR    A,DATA_24    ;
    JBS    R3,Z        ;读出数据=写入数据跳
WRONG:
    JMP    WRONG        ;校验失败
CORRECT:
    JMP    CORRECT        ;校验通过
DL10MS:
    RET   
;****************************
;存储器定义
;****************************
PROT_I2C    EQU    0X05    ;I2C操作口
    SDA    EQU    3    ;数据脚
    SCL    EQU    2    ;时钟脚

ADDR_24    EQU    0X1B        ;地址寄存器
DATA_24    EQU    0X1C        ;写入/读自I2C的数据寄存器
SLAVE_24 EQU    0X1D        ;从器件地址寄存器(1010XXX0)
DBUF_24    EQU    0X1E        ;发送/接受自SDA口的数据缓冲器
COUNT_24 EQU    0X1F        ;位计数器
TT_24    EQU    0X20        ;标志寄存器
    REND_24    EQU    1    ;读完毕标志(0=未完毕,1=完毕)
NUM_24    EQU    0X21        ;页写/页读字节数

*/
;****************************
;宏定义
;****************************
;=================
;设置SCL,SDA为输出口
;=================
SDA_OUT    MACRO
    MOV    A,@0B00000001  
    IOW    PROT_I2C
ENDM
;=================
;设置SCL为输出口,SDA为输入口
;=================
SDA_IN    MACRO
    MOV    A,@0B00001001
    IOW    PROT_I2C
ENDM
;****************************
;字节写程序
;功能:    写一个字节到EEPROM器件
;入口:    DATA_24    =要写的数据
;    ADDR_24    =数据地址
;    SLAVE_24=从器件地址1010XXX0)
;****************************
WRBYTE:
    MOV    A,SLAVE_24              
    MOV    DBUF_24,A       
    CALL    BSTART            ;送起始位
    CALL    TX            ;送从器件地址并检测应答信号
    MOV    A,ADDR_24       
    MOV    DBUF_24,A       
    CALL    TX            ;送数据地址并检测应答信号
    MOV    A,DATA_24       
    MOV    DBUF_24,A       
    CALL    TX            ;送数据并检测应答信号
    CALL    BSTOP            ;送停止位
    RET
;****************************
;字节读程序
;功能:    从EEPROM器件读一个字节
;入口:    ADDR_24    =数据地址
;    SLAVE_24=从器件地址(1010XXX0)
;出口:    DATA_24    =读到的数据
;****************************
RDBYTE:
    MOV    A,SLAVE_24
    MOV    DBUF_24,A
    CALL    BSTART            ;送起始位
    CALL    TX            ;送从器件地址并检测应答信号
    MOV    A,ADDR_24       
    MOV    DBUF_24,A
    CALL    TX            ;送数据地址并检测应答信号
;转入读状态   
    CALL    BSTART            ;送起始位   
    MOV    A,SLAVE_24          
    MOV    DBUF_24,A
    BS     DBUF_24,0           
    CALL    TX            ;送从器件地址并检测应答信号
    BS    TT_24,REND_24       
    CALL    RX            ;读数据并发送应答信号
    CALL    BSTOP            ;送停止位
    MOV    A,DBUF_24       
    MOV    DATA_24,A        ;保存数据到DATA_24
    RET
;****************************
;页写程序
;功能:    写一个字节到EEPROM器件
;入口:    R4    =要写的数据在RAM中存放首地址
;    NUM_24    =字节数
;    ADDR_24    =数据地址
;    SLAVE_24=从器件地址1010XXX0)
;****************************
WRPAGE:
    MOV    A,SLAVE_24              
    MOV    DBUF_24,A       
    CALL    BSTART            ;送起始位
    CALL    TX            ;送从器件地址并检测应答信号
    MOV    A,ADDR_24       
    MOV    DBUF_24,A       
    CALL    TX            ;送数据地址并检测应答信号
WRPAGE1:
    MOV    A,R0       
    MOV    DBUF_24,A       
    CALL    TX            ;送数据并检测应答信号
    INC    R4
    DJZ    NUM_24
    JMP    WRPAGE1            ;未写完继续
    CALL    BSTOP            ;送停止位
    RET
;****************************
;页读程序
;功能:    从EEPROM器件读一个字节
;入口:    ADDR_24    =数据地址
;    SLAVE_24=从器件地址(1010XXX0)
;    NUM_24    =字节数
;出口:    R4    =读到的数据在RAM中存放首地址
;****************************
RDPAGE:
    MOV    A,SLAVE_24
    MOV    DBUF_24,A
    CALL    BSTART            ;送起始位
    CALL    TX            ;送从器件地址并检测应答信号
    MOV    A,ADDR_24       
    MOV    DBUF_24,A
    CALL    TX            ;送数据地址并检测应答信号
;转入读状态   
    CALL    BSTART            ;送起始位   
    MOV    A,SLAVE_24          
    MOV    DBUF_24,A
    BS     DBUF_24,0           
    CALL    TX            ;送从器件地址并检测应答信号
RDPAGE1:
    MOV    A,@1
    XOR    A,NUM_24
    BS    TT_24,REND_24       
    JBS    R3,Z            ;NUM_24=1跳;判断是否最后一个字节,决定应答信号   
    BC    TT_24,REND_24       
    CALL    RX            ;读数据并发送应答信号
    MOV    A,DBUF_24       
    MOV    R0,A            ;保存数据到R0
    INC    R4
    DJZ    NUM_24
    JMP    RDPAGE1            ;未读完继续
    CALL    BSTOP            ;送停止位
    RET
;****************************
;I2C操作子程序(时序)集合
;****************************
;=================
;发送起始位程序
;说明:    当SCL=1时,向SDA发一个下降沿
;=================
BSTART:
    SDA_OUT                ;设置SDA为输出口
    BS    PROT_I2C,SDA        ;SDA=1
    NOP                ;延时0.6US
    BS    PROT_I2C,SCL        ;SCL=1
    NOP                ;延时0.6US
    BC    PROT_I2C,SDA        ;SDA=0
    NOP                ;延时0.6US
    BC    PROT_I2C,SCL        ;SCL=0
    NOP                ;延时0.6US
    RET
;=================
;发送结束位程序
;说明:    当SCL=1时,向SDA发一个上升沿
;=================
BSTOP:
    SDA_OUT                ;设置SDA为输出口
    BC    PROT_I2C,SDA        ;SDA=0
    NOP                ;延时0.6US
    BS    PROT_I2C,SCL        ;SCL=1
    NOP                ;延时0.6US
    BS    PROT_I2C,SDA        ;SDA=1
    NOP                ;延时0.6US
    RET
;=================
;位输入子程序
;说明:    当SCL=1时,从SDA上读电平
;出口:    C=从SDA上读入的位值   
;=================
BITIN:
    SDA_IN                ;设置SDA为输入口
    BS    PROT_I2C,SDA        ;SDA=1
    NOP                ;延时0.6US
    BS    PROT_I2C,SCL        ;SCL=1
    NOP                ;延时0.6US
    BC    R3,C
    JBC    PROT_I2C,SDA       
    BS    R3,C            ;C=SDA
    NOP                ;延时0.6US
    BC    PROT_I2C,SCL        ;SCL=0
    NOP                ;延时0.6US
    RET
;=================
;位输出子程序
;说明:    每当SCL=0时,改写SDA上的电平
;入口:    C=要写到SDA上的位值
;=================
BITOUT:
    SDA_OUT                ;设置SDA为输出口
    JBS    R3,C
    JMP    BIT0
    BS    PROT_I2C,SDA        ;SDA=C=1
    JMP    CLK1       
BIT0:
    BC    PROT_I2C,SDA        ;SDA=C=0
CLK1:
    NOP                ;延时0.6US
    BS    PROT_I2C,SCL        ;SCL=1
BIT2:
    NOP
    NOP
    BC    PROT_I2C,SCL        ;SCL=0
    RET
;============================
;接收数据子程序
;入口:    TT_24.REND_24    =读完毕标志
;出口:    DBUF_24    =接受到的数据(8_BIT)
;============================
RX:
    MOV    A,@8            ;循环次数=8
    MOV    COUNT_24,A
    CLR    DBUF_24
RXLP:
    CALL    BITIN            ;输入1_BIT
    RLC    DBUF_24            ;左移(带C)
    DJZ    COUNT_24        ;循环结束?
    JMP    RXLP
;设置应答信号位,如果读完毕则送1(NO_ACK)停止接受,否则送0(ACK)继续接受
    BS    R3,C       
    JBS    TT_24,REND_24        ;读完毕信号->C
    BC    R3,C       
    CALL    BITOUT            ;应答           
    RET
;============================
;发送数据子程序
;入口:    DBUF_24    =要发送的数据(8_BIT)
;============================
TX:
    MOV    A,@8            ;循环次数=8
    MOV    COUNT_24,A
TXLP:
    RLC    DBUF_24            ;左移(带C)
    CALL    BITOUT            ;输出1_BIT
    DJZ    COUNT_24        ;循环结束?
    JMP    TXLP       
    CALL    BITIN            ;读应答信号
    RET

;****************************
;I2C总线读/写的程序全部结束 !
;****************************

签名:


如果你的‘芯’是一座作坊,
我愿做那不知疲倦的程序匠……

 freego 发表于 2002-4-21 12:53 侃单片机 ←返回版面    

小弟提问?

1、匠人兄在“TX”中读得应答位,小弟没看懂如果读得值为“1”即没有应答该如何处理?
2、匠人兄在“WRPAGE”中将写入次数循环“NUM_24”次不知有否考虑当写入字节数超越页界(如每页16BYTES、32BYTES)时数据地址溢出而覆盖页首的问题?
   

 程序匠人 发表于 2002-4-21 15:30 侃单片机 ←返回版面    

答复freego

1、匠人兄在“TX”中读得应答位,小弟没看懂如果读得值为“1”即没有应答该如何处理?
答:这段程序中,没有对可能的错误做处理(因为我的设计中,I2C总线上只挂了一个器件),在“TX”中读得应答位,只是为了输出一个CLOCK。


2、匠人兄在“WRPAGE”中将写入次数循环“NUM_24”次不知有否考虑当写入字节数超越页界(如每页16BYTES、32BYTES)时数据地址溢出而覆盖页首的问题?
答:既然是页写/页读,当然只针对页内进行操作了。如果要跨页,我不是还有单字节写/读程序吗?只要再做一段循环程序去调用即可。


欢迎大家把这段程序继续完善。   

签名:


如果你的‘芯’是一座作坊,
我愿做那不知疲倦的程序匠……

 zhhch 发表于 2002-4-21 23:40 侃单片机 ←返回版面    

向程序匠人学习,现贴上我写24xx读写程序,以供交流。我有emc_wice专业汉化版(本人汉化),欢迎索取!

该程序系51程序改写而来,我现在正用着呢!

;=====================写EEPROM程序 ========================================
;功能:从KEY_BUF取数据,写入EEPROM中SUB_ADR,连续写BYTE_CNT个字节
;入口:SUB_ADR        出口:NONE                   
;影响资源:A,DATA_BUF,P6,STU,BIT_CNT,BYTE_CNT,SUB_ADR                                             
;===============================================
WR_UEE:                            ;将KEY_BUF中客密码写EEPROM
        MOV     SUB_ADR,@U_EE
        MOV     BYTE_CNT,@0X06            ;设置字节计数器为6
        JMP     WR_EE
;------------------------------------------------------------------------       
WR_SEE:                            ;将KEY_BUF中主密码写EEPROM
        MOV     SUB_ADR,@S_EE
        MOV     BYTE_CNT,@0X07            ;设置字节计数器为7
;------------------------------------------------------------------------       
WR_EE:
        MOV     EEP6_BUF,EE    ;保护EE口
        BS      EE,PW          ;EEPROM上电
        BC      EE,WP          ;清除EEPROM的写保护       
        CALL    BSTART         ;启动IIC
        MOV     A,@WREE        ;发送写器件地址
        MOV     DATA_BUF,A
        CALL    SENDBYTE
        JBC     STU,GP        
        JMP     WR_RET        ;无应答返回
        MOV     A,SUB_ADR     ;发送写单元地址
        MOV     DATA_BUF,A
        CALL    SENDBYTE
        JBC     STU,GP
        JMP     WR_RET        ;无应答返回
        MOV     A,@KEY_BUF    ;设置待写数据区首址
        MOV     R4,A
WR_NEXT:
        MOV     A,R0
        MOV     DATA_BUF,A    ;取待写数据
        CALL    SENDBYTE
        JBC     STU,GP
        JMP     WR_RET        ;无应答返回
        INC     R4
        DJZ     BYTE_CNT
        JMP     WR_NEXT
       
        CALL    BSTOP         ;停止IIC
        CALL    DELAY10       ;延时10MS,等待数据写完
WR_RET:
        BC      EE,PW          ;EEPROM下电
;---------------------------------------------------------       
        IOR     EE             ;设置SDA为输出
        AND     A,@0B11110111  ;**************************
        IOW     EE
;---------------------------------------------------------
        MOV     EE,EEP6_BUF    ;恢复EE口现场
        RET
;=====================读EEPROM程序 ========================================
;功能:读EEPROM,写入PSW_BUF,连续写BYTE_CNT个字节
;入口:SUB_ADR       出口:NONE                   
;影响资源:A,DATA_BUF,P6,STU,BIT_CNT,BYTE_CNT,SUB_ADR                                             
;==============================================
RD_UEE:                            ;读6位客密码到PSW_BUF
        MOV     SUB_ADR,@U_EE
        MOV     BYTE_CNT,@0X05            ;设置字节计数器为6-1
        JMP     RD_EE
;------------------------------------------------------------------------       
RD_SEE:                            ;读7位密码到PSW_BUF
        MOV     SUB_ADR,@S_EE
        MOV     BYTE_CNT,@0X06            ;设置字节计数器为7-1
;------------------------------------------------------------------------       
RD_EE:   
        MOV     EEP6_BUF,EE    ;保护EE口   
        BS      EE,PW          ;EEPROM上电
        BS      EE,WP          ;设置EEPROM的写保护       
        CALL    BSTART         ;启动IIC
        MOV     A,@WREE        ;发送写器件地址
        MOV     DATA_BUF,A
        CALL    SENDBYTE
        JBC     STU,GP        
        JMP     RD_RET         ;无应答返回
        MOV     A,SUB_ADR      ;发送写单元地址
        MOV     DATA_BUF,A
        CALL    SENDBYTE
        JBC     STU,GP
        JMP     RD_RET         ;无应答返回
        CALL    BSTART         ;重新启动IIC
        MOV     A,@RDEE        ;发送读器件地址
        MOV     DATA_BUF,A
        CALL    SENDBYTE
        JBC      STU,GP        
        JMP     RD_RET         ;无应答返回
       
        MOV     A,@PSW_BUF     ;设置读出数据存放首址
        MOV     R4,A
RD_NEXT:
        BC      STU,GP         ;连续接收BYTE_CNT-1字节数据
        CALL    RCVBYTE        ;并发送应答信号
        MOV     A,DATA_BUF
        MOV     R0,A
        INC     R4
        DJZ     BYTE_CNT
        JMP     RD_NEXT
       
        BS      STU,GP         ;接收最后一个字节数据
        CALL    RCVBYTE        ;并发送非应答信号
        MOV     A,DATA_BUF
        MOV     R0,A
        CALL    BSTOP          ;停止IIC
       
RD_RET:
        BC      EE,PW           ;EEPROM下电
;---------------------------------------------------------       
        IOR     EE             ;设置SDA为输出
        AND     A,@0B11110111  ;**************************
        IOW     EE
;---------------------------------------------------------        
        MOV     EE,EEP6_BUF     ;恢复EE现场
        RET
       
;============================延时子程序====================================
;功能:短延时         入口:NONE             出口:NONE                    
;影响资源:A,TEMP ,STATUS                                                     
;==================================================
DELAY:                        
        MOV         A,@0X01
        MOV         TEMP,A
        DJZ         TEMP
        JMP         $-1
        RET           
;============================延时子程序10MS================================
;功能:延时         入口:NONE             出口:NONE                    
;影响资源:A,TEMP ,STATUS                                                     
;=================================================
DELAY10:                        
        MOV         A,@0X20
        MOV         TEMP,A
        MOV         A,@250
        MOV         TEMP1,A
        DJZ         TEMP1
        JMP         $-1
        DJZ         TEMP
        JMP         $-5
        RET                   
;===============================启用IIC总线================================
;功能:开启IIC总线                                                       
;入口:NONE       出口:NONE   SCL=0,SDA=0
;影响资源:A,P6,STU                                                      
;==============================================
BSTART:
        BS      EE,SDA        ;拉高SDA和SCL
        BS      EE,SCL
        CALL    DELAY
        BC      EE,SDA        ;拉低SDA,启动IIC
        CALL    DELAY
        BC      EE,SCL        ;拉低SCL
        RET
;===============================关闭IIC总线================================
;功能:关闭IIC总线                                                       
;入口:NONE       出口:NONE  ,SCL=1,SDA=1                                             
;影响资源:A,P6,STU                                                      
;====================================================
BSTOP:           
        BC      EE,SDA        ;拉低SDA
        BS      EE,SCL        ;拉高SCL
        CALL    DELAY
        BS      EE,SDA        ;拉高SDA,停止IIC
        CALL    DELAY    
        RET
;======================送出一个字节数据,高位在前===========================
;功能:从MCU发送一个字节给EEPROM,并接收应答信号                                     
;入口:发送位数放在DATA_BUF       出口:GP=0 表应答正确 GP=1 表应答错误                         
;影响资源:A,DATA_BUF,P6,STU,BIT_CNT                                             
;=============================================
SENDBYTE:               
        MOV     A,@0X08        ;准备位计数器为8
        MOV     BIT_CNT,A
SEND_B:       
        RLC     DATA_BUF       ;从DATA_BUF取数据送C
        JBC     STU,C          ;C->SDA
        BS      EE,SDA
        JBS     STU,C         
        BC      EE,SDA
        CALL    DELAY
        BS      EE,SCL         ;拉高SCL,通知接受数据
        CALL    DELAY
        BC      EE,SCL         ;拉低SCL,钳住总线
        DJZ     BIT_CNT
        JMP     SEND_B         ;8位未发送完,继续发送
       
        BS      EE,SDA         ;拉高SDA
;---------------------------------------------------------       
        IOR     EE             ;设置SDA为输入
        OR      A,@0B00001000  ;**************************
        IOW     EE
;---------------------------------------------------------       
        BS      EE,SCL         ;拉高SCL,接收应答信号
        CALL    DELAY
        JBC     EE,SDA         ;SDA->GP:=0,OK,=1,ERR
        BS      STU,GP
        JBS     EE,SDA 
        BC      STU,GP
;---------------------------------------------------------       
        IOR     EE             ;设置SDA为输出
        AND     A,@0B11110111  ;**************************
        IOW     EE
;---------------------------------------------------------       
        BC      EE,SCL         ;拉低SCL
        BC      EE,SDA         ;拉低SDA
        RET
;=====================接收一个字节数据,高位在前===========================
;功能:接收一个字节从EEPROM,并发送应答信号
;入口:接收数据放在DATA_BUF       出口:NONE                   
;影响资源:A,DATA_BUF,P6,STU,BIT_CNT                                             
;=============================================
RCVBYTE:               
        MOV     A,@0X08        ;准备位计数器为8
        MOV     BIT_CNT,A
        BS      EE,SDA
;---------------------------------------------------------       
        IOR     EE             ;设置SDA为输入
        OR      A,@0B00001000  ;**************************
        IOW     EE
;---------------------------------------------------------       
RCV_B: 
        BC      EE,SCL         ;拉低SCL
        CALL    DELAY
        BS      EE,SCL         ;拉高SCL
        CALL    DELAY
        JBC     EE,SDA          ;SDA->C
        BS      STU,C
        JBS     EE,SDA         
        BC      STU,C
        RLC     DATA_BUF       ;DATA_BUF<-C
        DJZ     BIT_CNT
        JMP     RCV_B          ;8位未接收完,继续接收
       
        BC      EE,SCL         ;拉低SCL,准备发送应答信号
        JBC     STU,GP         ;GP->SDA,0发应答信号,1发非应答信号
        BS      EE,SDA
        JBS     STU,GP 
        BC      EE,SDA
;---------------------------------------------------------       
        IOR     EE             ;设置SDA为输出
        AND     A,@0B11110111  ;**************************
        IOW     EE
;---------------------------------------------------------       
        BS      EE,SCL         ;拉高SCL,送出应答信号
        CALL    DELAY
        BC      EE,SCL         ;拉低SCL,钳住总线,等待后续操作
        BC      EE,SDA
        RET        
 

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分