#include <reg52.h> #include "MY51.H" sbit sda=P2^0; //总线连接口定义 sbit scl=P2^1; //总线连接口定义 void delayus() //需要4个机器周期,大概4.34us { ; //晶振频率11.0592M,机器周期为1.085微秒 } void iic_start() //启动信号 { sda=1; scl=1; delayus(); //sda和scl同为高电平保持4.7us以上 _nop_(); //1.085us,共5.78us,下面sda=0是下降沿,不能计算在延时时间中 sda=0; //下降沿 delayus(); //sda低电平保持4us以上 ,这里是4.34us满足要求 } void iic_stop() //停止信号 { sda=0;_nop_(); //准备状态 scl=1; delayus(); //该状态稳定时间要求保持4us以上 sda=1; //scl高电平期间,sda来一个上升沿 delayus(); //sda保持4.7us以上,4.34加上函数返回时间大于4.7us //注:此时scl和sda都为1 } void iic_sendByte(uchar byteData) //mcu发送一个字节 { uchar i; uchar temp=byteData; for(i=0;i<8;i++) { temp=temp<<1; //移动后最高位到了PSW寄存器的CY位中 scl=0; //准备 _nop_(); //稳定一下 sda=CY; //将待发送的数据一位位的放到sda上 _nop_(); scl=1; //每一个高电平期间,ic器件都会将数据取走 _nop_(); } scl=0; //如果写成scl=1;sda=1就是停止信号,不能这么写 _nop_(); sda=1; //释放总线,数据总线不用时要释放 _nop_(); } uchar iic_readByte() //读一个字节 { uchar i,temp; scl=0; //准备读数据 _nop_(); sda=1; //释放总线 _nop_(); for(i=0;i<8;i++) { scl=1; //mcu开始取数据 delayus(); //scl为高电平后,ic器件就会将1位数据送到sda上 //总共用时不会大于4.34us的,然后就可以让mcu读sda了 temp=(temp<<1)|sda; //读一位保存到temp中 scl=0; delayus(); } return temp; } bool iic_checkACK() //处理应答信号 { uchar errCounts=255; //定义超时量为255次 scl=1; _nop_(); while(sda) { //在一段时间内检测到sda=0的话认为是应答信号 if(0==errCounts) { scl=0; //钳住总线 _nop_(); return false; //没有应答信号 } errCounts--; } scl=0; //钳住总线,为下1次通信做准备 _nop_(); return true; //成功处理应答信号 } void iic_init() //总线初始化 { scl=1; sda=1; delayus(); } void iic_sendACK(bool b_ACK) //发送应答或非应答信号 { scl=0; //准备 _nop_(); if(b_ACK) //ACK { sda=0; } else //unACK { sda=1; } _nop_(); scl=1; delayus(); //大于4us的延时 scl=0; //钳住scl,以便继续接收数据 _nop_(); } void AT24C02_writeByte(uchar address,uchar dataByte)//向24c02写一字节数据 { iic_start(); iic_sendByte(0xa0);//mcu写控制字,前4位固定1010,后三位地址0,末位0是写 iic_checkACK(); //mcu处理应答信号 iic_sendByte(address); //准备在指定地址处写入 iic_checkACK(); iic_sendByte(dataByte); //写数据 iic_checkACK(); iic_stop(); delayms(2); //按字节写入时,24c02在接收到停止信号后将数据擦写到内部,这需要时间 //并且在这段时间内不会响应总线上的任何请求,故让mcu有2毫秒以上的等待 } void AT24C02_writeData(uchar address,uchar numBytes,uchar* buf)//写入任意长度数据 { while(numBytes--) { AT24C02_writeByte(address++,*buf++); } } void AT24C02_readData(uchar beginAddr,uchar dataSize,uchar* buf)//读取任意长度字节 { iic_start(); //起始信号 iic_sendByte(0xa0); //控制字,写 iic_checkACK(); //处理应答信号 iic_sendByte(beginAddr); //发送地址 iic_checkACK(); //处理应答信号 iic_start(); //发送起始信号 iic_sendByte(0xa1); //控制字,读 iic_checkACK(); //处理应答信号 while(dataSize--) //读取dataSize个字节 { *buf++=iic_readByte(); //读取一个个字节并保存到缓冲区buf中 iic_sendACK(dataSize); //发送应答,当dataSize为0时发送非应答 } iic_stop(); //发送停止信号 } void main() { uchar buf[2]; //接受数据的缓冲区 uchar arr[34]={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, //0x00-0x0f 16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,//0x10-0x1f 32,0x55}; //0x20-0x21 iic_init(); //总线初始化 //AT24C02_writeByte(0x08,0x11); //向指定地址处写入一个字节数据,代码测试 AT24C02_writeData(0x00,sizeof(arr),arr); //向指定地址处开始写入34字节的数据 AT24C02_readData(0x20,sizeof(buf),buf); //从指定地址开始读2个字节 P1=buf[1]; //buf中的第二个元素就是arr中的最后一个数据0x55 while(1){P1=~P1;delayms(500);} //将这个0x55用led灯显示出来10101010变化 }
For your reference.