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