1.导入Delay、key、LCD1602相关文件
2.控制逻辑
以I2C去写入,用AT24C02包装好,main调用即可

3.编写I2C代码
看着这六个状态编

图1 开和关

图2 发送一个字节

图3 接收一个字节

图4 接收和发送应答
#include <REGX52.H>
 sbit I2C_SCL = P2^1;
 sbit I2C_SDA = P2^0;
/**
   * @brief  I2C开始
   * @param  无
   * @retval 无
   */
 void I2C_Start(void)
 {
     //空闲状态默认SCL和SDA是高电平的
     I2C_SDA=1;    //SDA可能是0
     I2C_SCL=1;    //SCL在I2C复合的时候有可能为低电平
     
     I2C_SDA=0;    //SDA要换为低电平
     I2C_SCL=0;    //SCL要换为低电平
     
 }
/**
   * @brief  I2C发送一个字节
   * @param  Data 要发送的字节
   * @retval 无
   */
void I2C_Send(unsigned char Data)
 {
     //默认I2C_SCL=0;
     unsigned char i;
     for(i=0;i<8;i++)
     {
         I2C_SDA=Data&(0x80>>i);
         I2C_SCL=1;    
         I2C_SCL=0;    //写了立马就读没超过最大时钟
     }
     
 }
 /**
   * @brief  I2C接收一个字节
   * @param  无
   * @retval 接收到的一个字节数据
   */
 unsigned char I2C_Receive(void)   //这里不需要参数Data
 {
     unsigned char Receive_Data=0x00,i;
     I2C_SDA=1;  //释放SDA
     for(i=0;i<8;i++)
     {
         I2C_SCL=1;  //低电平不允许读取,所以要为1
         if(I2C_SDA)Receive_Data|=(0x80>>i);   
         I2C_SCL=0;
     }
     return Receive_Data;
 }
 /**
   * @brief  I2C发送应答
   * @param  ACK_select 应答位,0为应答,1为非应答
   * @retval 无
   */
 void I2C_Send_ACK(unsigned char ACK_select)
 {
     //返回需要通过时序变化,不能直接返回参数值
     I2C_SDA=ACK_select;  //SDA就是应答位
     //发送应答过程
     I2C_SCL=1;
     I2C_SCL=0; 
 }
/**
   * @brief  I2C接收应答位
   * @param  无
   * @retval 接收到的应答位,0为应答,1为非应答
   */
 unsigned char I2C_Receive_ACK(void)
 {
     unsigned char ACK_bit;
     //返回需要通过时序变化,不能直接返回参数值
     I2C_SDA=1;  //SDA释放
     //发送应答过程
     I2C_SCL=1;
     ACK_bit=I2C_SDA;
     I2C_SCL=0;
     return ACK_bit;
 }
 /**
   * @brief  I2C停止
   * @param  无
   * @retval 无
   */
 void I2C_Stop(void)
 {  //归为0上拉才有意义
     I2C_SDA=0;    //在终止之前,SDA有可能是0,有可能是1
     I2C_SCL=1;    
     I2C_SDA=1;    
 }
4.看此图编写AT24C02代码

#include <REGX52.H>
 #include "I2C.h"
#define AT24C02_ADDRESS 0xA0 //默认地址
void AT24C02_WriteByte(unsigned char WordAddress,Data)
 {
     I2C_Start();
     I2C_Send(AT24C02_ADDRESS);
     I2C_Send_ACK(0);
     I2C_Send(WordAddress);
     I2C_Send_ACK(0);
     I2C_Send(Data);   //第一个字节数据
     I2C_Send_ACK(0);
     I2C_Stop();
 }
unsigned char AT24C02_ReadByte(unsigned char WordAddress)
 {
     unsigned char num;
     I2C_Start();
     I2C_Send(AT24C02_ADDRESS);
     I2C_Receive_ACK();
     I2C_Send(WordAddress);
     I2C_Receive_ACK();
     I2C_Start();
     I2C_Send(AT24C02_ADDRESS|0x01);   //这表示为读
     I2C_Receive_ACK();
     num=I2C_Receive();   
     I2C_Send_ACK(1);
     I2C_Stop();
     return num;
 }
5.编写main代码
#include <REGX52.H>
 #include "LCD1602.h"
 #include "key.h"
 #include "AT24C02.h"
 #include "Delay.h"
unsigned char keynum;
 unsigned int  figure=0;
void main()
 {
     LCD_Init();
     LCD_ShowString(1,1,"Hello!   ");
     while(1)
     {
         
         keynum=Key();
         //K1按键,Num自增
         if(keynum==1)
         {
             figure++;
             LCD_ShowNum(2,1,figure,5);
         }
         //K2按键,Num自减
         if(keynum==2)
         {
             figure--;
             LCD_ShowNum(2,1,figure,5);
         }
         //K3按键,向AT24C02写入数据
         if(keynum==3)
         {
             AT24C02_WriteByte(0,figure%256);
             Delay(5);
             AT24C02_WriteByte(1,figure/256);
             Delay(5);
             Delay(1000);
             LCD_ShowString(2,1,"Write ok");
             Delay(500);
         }
         //K4按键,从AT24C02读取数据
         if(keynum==4)
         {
             static int temp=0;
             temp=AT24C02_ReadByte(0);
             temp|=AT24C02_ReadByte(1)<<8;     //这一步为叠加数据
             LCD_ShowString(2,1,"Read  ok");
             Delay(500);
             LCD_ShowString(2,1,"        ");
             LCD_ShowNum(2,1,temp,5);
             Delay(1000);
         }
     }
 }
6.试验结果展示
AT24C02存储