24C02,24C04,24C1024测试通过
//-------------------读写串行EEPROM------------- //作者:兰天白云 //功能描述:读写串行EEPROM(适用24C01~24C2048) //输入:MCU地址,EEP地址,读写字节数,24的控制字 //输出:错误标志,0--正确,1--错误 //版本说明:V1.1 //注:(1)写数据时不用考虑跨页问题(已有处理) // (2)控制字与24的硬件连接有关 // 例:24的1,2,3,4脚都与地连接 // 则:写24的控制字=0xa0,读24的控制字=0xa1 //----------------------------------------------
//根据使用的24确定 #define PAGESIZE 8 //页大小 24C02=8 24C512=128 #define EEPALLBYTE 256 //总字节数 24C02=256 24C512=65536 static bit EEP_flag; //0--运行正确,1--运行错误
//根据使用的单片机确定(PIC) #include <pic.h> #define SDA_DIR TRISC2 #define SCL_DIR TRISC3 #define SDA RC2 //RC2---数据线 #define SCL RC3 //RC3---时钟线 #define SDAinput() { SDA_DIR=1; } //设端口为输入 #define SDAoutput() { SDA_DIR=0; } //输出 #define SCLoutput() { SCL_DIR=0; }
//根据使用的单片机确定(51) /* #include <reg51.h> //#define SDA_DIR TRISC2 //#define SCL_DIR TRISC3 #define SDA P1^0 //数据线 #define SCL P1^1 //时钟线 #define SDAinput() { SDA=1; } //设端口为输入 #define SDAoutput() { _nop_(); } //为兼容PIC而保留 #define SCLoutput() { _nop_(); } //为兼容PIC而保留 */
//指明由外部函数调用 extern bit RW24CXX(unsigned char *p_data,unsigned int eep_addr, unsigned int n,unsigned char Control); extern bit copy(unsigned int SSAddres,unsigned int DSAddres,unsigned int n); extern bit insert(unsigned char *p_data,unsigned int eep_addr, unsigned int n,unsigned char Control); extern bit delete(unsigned int eep_addr,unsigned int n,unsigned char Control);
//IO口配置 static void EEP_IO(void) { SCLoutput(); SDAoutput(); } //为了兼容大多数24CXX,至少延时2uS 与晶振有关,定义成静态函数 static void delayus(void) { unsigned char t1=0x01; while(--t1); } ////延时10mS 与晶振有关,定义成静态函数 static void delay10ms(void) { unsigned int t1=0xffff; while(--t1); } //不管IO口以前怎么用 //从现在起用作IIC总线 static void I2C_Start(void) //启动总线 { EEP_IO(); SCL=0; //确保时钟=低 delayus(); SDA=1; delayus(); SCL=1; delayus(); SDA=0; //启动总线 delayus(); SCL=0; delayus(); } //停止时,数据手册要求时钟和数据线都为1 //但本人认为时钟线设为0抗干扰更好 static void I2C_Stop(void) //停止总线 { SCL=0; delayus(); SDA=0; delayus(); SCL=1; delayus(); SDA=1; delayus(); SCL=0; //设为0抗干扰更好 delayus(); }
static void I2C_RecAck(void) //读应答信号,用于写 { SCL=0; SDAinput(); //设数据线为输入 delayus(); SCL=1; delayus(); EEP_flag=SDA; SCL=0; delayus(); SDAoutput(); delayus(); } static void I2C_SendAck(void) //发送应答信号,用于连续读 { SDA=0; delayus(); SCL=1; delayus(); SCL=0; delayus(); } static void I2C_NoAck(void) //不发送应答信号,用于停止读 { SDA=1; delayus(); SCL=1; delayus(); SCL=0; delayus(); } //写一字节到EEPROM static void I2C_wbyte(unsigned char wbyte) {unsigned char i=8; //SDAoutput(); delayus(); for(;i>0;i--) {SCL=0; if(wbyte&0x80){SDA=1;} else {SDA=0;} delayus(); SCL=1; wbyte<<=1; delayus(); } }
//从EEPROM读1字节数据返回 static unsigned char I2C_rbyte(void) {unsigned char i=8; unsigned char rbyte; SDAinput(); //设数据线为输入 while(i--) {SCL=1; delayus(); rbyte=(rbyte<<1)|SDA; SCL=0; delayus(); } SDAoutput(); return(rbyte); } //读写n字节数据 //数据地址由p_data确定,EEPROM地址由eep_addr确定 //数据数量由n确定,读写由Control确定 bit RW24CXX(unsigned char *p_data,unsigned int eep_addr, unsigned int n,unsigned char Control) { unsigned int i=0,j=3; while(1) // { I2C_Start(); I2C_wbyte(Control&0xfe); I2C_RecAck(); if(EEP_flag) break; if(EEPALLBYTE>256) //有16位地址吗? {I2C_wbyte(eep_addr/256); //16位地址 I2C_RecAck(); if(EEP_flag) break; } I2C_wbyte(eep_addr); //8位地址 I2C_RecAck(); if(EEP_flag) break; if(!(Control&0x01)) //写---------- {while(n--) { I2C_wbyte(*p_data); I2C_RecAck(); if(EEP_flag) break; p_data++; eep_addr++; if((eep_addr%PAGESIZE==0)) //跨页 {i2c_stop(); delay10ms(); break; } } if(n==0) {i2c_stop(); delay10ms(); break; } else if(EEP_flag) {if(j--==0) //允许重试3次 break; } } else //读----------- {I2C_Start(); I2C_wbyte(Control); I2C_RecAck(); if(EEP_flag) break; while(n--) {*p_data++=I2C_rbyte(); if(n>0) I2C_SendAck(); else {I2C_NoAck(); I2C_Stop(); break; } } } } return(EEP_flag); } //用数据FData填充从eep_addr开始的区域 bit fill(unsigned char FData,unsigned int eep_addr, unsigned int n,unsigned char Control) {unsigned char j=3; while(1) // { I2C_Start(); I2C_wbyte(Control&0xfe); I2C_RecAck(); if(EEP_flag) break; if(EEPALLBYTE>256) //有16位地址吗? {I2C_wbyte(eep_addr/256); //16位地址 I2C_RecAck(); if(EEP_flag) break; } I2C_wbyte(eep_addr); //8位地址 I2C_RecAck(); if(EEP_flag) break; while(n--) { I2C_wbyte(FData); I2C_RecAck(); if(EEP_flag) break; eep_addr++; if((eep_addr%PAGESIZE==0)) //跨页 {i2c_stop(); delay10ms(); break; } } if(n==0) {i2c_stop(); delay10ms(); break; } else if(EEP_flag) {if(j--==0) //允许重试3次 break; } } return(EEP_flag); } //先把原来的数据搬走(用copy),再插入新数据 bit insert(unsigned char *p_data,unsigned int eep_addr, unsigned int n,unsigned char Control) { } //先删除,再把数据搬过来(用copy) bit delete(unsigned int eep_addr,unsigned int n,unsigned char Control) {fill(0xff,eep_addr,n,Control); } //复制 bit copy(unsigned int SSAddres,unsigned int DSAddres,unsigned int n) {unsigned char buff[8]; //每次复制的数量由数组决定 unsigned char i=8; while(n>0) {if(n>=8) {i=8; n-=8; } else {i=n; n=0; } RW24CXX(buffer,SSAddres,i,Control|0x01); RW24CXX(buffer,DSAddres,i,Control&0xfe); if(EEP_flag) break; SSAddres+=8; DSAddres+=8; } return(EEP_flag); } |
|