储存24C02写入失败但是读取正常

24C02能正常读取,老是写不进去引脚连接没问题附程序:


```c
#include<I2C.H>

void Delay5us()        //@11.0592MHz
{
}

void I2cStrat()//I2C开始信号
{
    SCL=1;//SCL在高电平时SDA由高电平变为低电平是开始
    Delay5us();
    SDA=1;
    Delay5us();
    SDA=0;
    Delay5us();
    SCL=0;
}

void I2cStop()//I2C结束信号
{
    SCL=0;//SCL在高电平时SDA由低电平变为高电平是结束
    Delay5us();
    SDA=0;
    Delay5us();
    SCL=1;
    Delay5us();
    SDA=1;
    Delay5us();
}

void I2cSendByte(u8 dat)//I2C发送一个字节的数据
{
    /*发送数据时SCL在高电平时读取SDA的数据SCL在低电平时SDA变换数据
    数据发送时顺序是由高到低的依次发送*/
    u8 i=0;
    for(i=0;i<8;i++)
    {
        u8 j=dat>>(7-i);
        Delay5us();
        SDA=j%2;
        Delay5us();
        SCL=1;
        Delay5us();
        SCL=0;
    }
}

u8 I2c_GetAck()//主机获取应答信号
{
    //时钟线处于低电平期间等待SDA数据线被从机拉低
    SCL=0;
    Delay5us();
    SDA=1;
    Delay5us();
    SCL=1;
    Delay5us();
    if(SDA)//判断从机是否拉低信号
    {
        SCL=0;
        return 1;//从机拉低信号表示接受成功
    }
    else
    {
        SCL=0;
        return 0;//从机不拉低表示无应答或者接受不成功
    }
}

void I2c_SendAck(u8 a)//主机发送应答信号
{
    SCL=0;
    Delay5us();
    SDA=a;//主机发送应答信号
    Delay5us();
    SCL=1;//读取状态信息
    Delay5us();
    SCL=0;
}

u8 I2C_ReadByte()//主机读取一个字节数据
{
    u8 i=0,dat=0;
    for(i=0;i<8;i++)
    {
        dat<<=1;
        SCL=0;
        Delay5us();
        SCL=1;
        Delay5us();
        dat|=SDA;
        Delay5us();
    }
    SCL=0;
    return dat;
}

void At24c02_WriteByte(u8 IC_Addr,u8 Byte_Addr,u8 dat)//AT24C02写入一字节的数据
{
    I2cStrat();//I2C开始信号
    I2cSendByte(IC_Addr);//I2C发送at24C02的地址
    I2c_GetAck();//主机获取应答信号
    I2cSendByte(Byte_Addr);//I2C发送at24C02写入数据的地址
    I2c_GetAck();//主机获取应答信号
    I2cSendByte(dat);//I2C发送at24C02要写入的数据
    I2c_GetAck();//主机获取应答信号
    I2cStop();//I2C结束信号
}

u8 At24c02_ReadByte(u8 IC_Addr,u8 Byte_Addr)//AT24C02读取一字节的数据
{
    u8 dat=0;
    I2cStrat();//I2C开始信号
    I2cSendByte(IC_Addr);//I2C发送at24C02的地址
    I2c_GetAck();//主机获取应答信号
    I2cSendByte(Byte_Addr);//I2C发送at24C02写入数据的地址
    I2c_GetAck();//主机获取应答信号
    I2cstrat();//I2C开始信号
    I2cSendByte(IC_Addr+1);//I2C发送at24C02的地址
    I2c_GetAck();//主机获取应答信号
    dat=I2C_ReadByte();//主机读取一个字节数据
    I2c_SendAck(1);//主机发送应答信号
    I2cStop();//I2C结束信号
    return dat;
}


```

  • 这有个类似的问题, 你可以参考下: https://ask.csdn.net/questions/7546381
  • 我还给你找了一篇非常好的博客,你可以看看是否有帮助,链接:蓝桥杯单片机 | 特训案例【进阶04】24C02存储按键触发次数
  • 除此之外, 这篇博客: 备战蓝桥杯单片机倒数第四天 小蜜蜂老师公众号更新内容中的 【进阶04】24C02存储按键触发次数 部分也许能够解决你的问题, 你可以仔细阅读以下内容或跳转源博客中阅读:
  • #include "iic.h"
    #include "reg52.h"
    
    sbit S6 = P3^1;
    sbit S5 = P3^2;
    sbit S4 = P3^3;
    
    unsigned char dat1 = 0,dat2 = 0,dat3 = 0;
    unsigned char code smg_data[] = {0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8, 0x80,0x90};
    
    void delay(unsigned int t)
    {
     	while(t--);
    }
    
    void Init_74HC138(unsigned char channel)
    {
     	switch(channel)
    	{
    	 	case 4:P2 = (P2 & 0x1f) | 0x80;break;
    		case 5:P2 = (P2 & 0x1f) | 0xa0;break;
    		case 6:P2 = (P2 & 0x1f) | 0xc0;break;
    		case 7:P2 = (P2 & 0x1f) | 0xe0;break;
    		case 0:P2 = (P2 & 0x1f) | 0x00;break;
    	}
    	P2 = (P2 & 0x1f) | 0x00;
    }
    
    void SMG_DisplayBit(unsigned char pos,unsigned char dat)
    {
     	P0 = (0x01 << pos);
    	Init_74HC138(6);
    	P0 = dat;
    	Init_74HC138(7);
    }
    
    void SMG_All(unsigned char dat)
    {
     	P0 = 0xff;
    	Init_74HC138(6);
    	P0 = dat;
    	Init_74HC138(7);
    }
    
    void Init_System()
    {
     	P0 = 0xff;
    	Init_74HC138(4);
    	P0 = 0x00;
    	Init_74HC138(5);
    	SMG_All(0xff);
    }
    
    void SMG_Display_Data()
    {
     	SMG_DisplayBit(0,smg_data[dat1/10]);
    	delay(200);
    	SMG_DisplayBit(1,smg_data[dat1%10]);
    	delay(200);
    	SMG_DisplayBit(2,0xbf);
    	delay(200);
    	SMG_DisplayBit(3,smg_data[dat2/10]);
    	delay(200);
    	SMG_DisplayBit(4,smg_data[dat2%10]);
    	delay(200);
    	SMG_DisplayBit(5,0xbf);
    	delay(200);
    	SMG_DisplayBit(6,smg_data[dat3/10]);
    	delay(200);
    	SMG_DisplayBit(7,smg_data[dat3%10]);
    	delay(200);
    	SMG_All(0xff);
    	delay(200);
    }
    
    void AT24C02_Write(unsigned char addr,unsigned char dat)
    {
     	IIC_Start();
    	IIC_SendByte(0x90);
    	IIC_WaitAck();
    	IIC_SendByte(addr);
    	IIC_WaitAck();
    	IIC_SendByte(dat);
    	IIC_WaitAck();
    	IIC_Stop();
    }
    
    unsigned char AT24C02_Read(unsigned char addr)
    {
    	unsigned char temp = 0;
    	IIC_Start();
    	IIC_SendByte(0x90);
    	IIC_WaitAck();
    	IIC_SendByte(addr);
    	IIC_WaitAck();
    
    	IIC_Start();
    	IIC_SendByte(0x91);
    	IIC_WaitAck();
    	temp = IIC_RecByte();
    	IIC_SendAck(1);
    	IIC_Stop();
    	return temp;
    }
    
    void Read_AT24C02_Init()
    {
     	dat1 = 	AT24C02_Read(0x00);
    	delay(1000);
    	dat2 =  AT24C02_Read(0x01);
    	delay(1000);
    	dat3 =  AT24C02_Read(0x02);
    	delay(1000);
    }
    
    void Key_Scans()
    {
     if(S4 == 0)
     {
    		delay(20);
    		if(S4 == 0)
    		{
    			dat1++;
    			if(dat1 > 13)
    			{
    			 	dat1 = 0;
    			}
    			AT24C02_Write(0x00,dat1);
    		}
     }
     else if(S5 == 0)
     {
    		delay(20);
    		if(S5 == 0)
    		{
    			dat2++;
    			if(dat2 > 13)
    			{
    			 	dat2 = 0;
    			}
    			AT24C02_Write(0x01,dat2);
    		}
     	}
    	
    	if(S6 == 0)
     {
    		delay(20);
    		if(S6 == 0)
    		{
    			dat3++;
    			if(dat3 > 13)
    			{
    			 	dat3 = 0;
    			}
    			AT24C02_Write(0x02,dat3);
    		}
      }				
    }
    
    void main(void)
    {
    	Init_System();
    	Read_AT24C02_Init();
    	while(1)
    	{
    	    SMG_Display_Data() ;
    		Key_Scans();
    	}
    }
  • 以下回答由chatgpt基于相关博客总结生成:

    问题分析:

    根据程序内容和描述,可以猜测储存器24C02的写入操作存在问题。由于读取操作是正常的,因此第一步需要检查写入操作代码。

    解决方案:

    1. 检查IIC总线通信是否正常

    在AT24C02_Write()函数中,开头首先执行了IIC_Start()函数,再执行IIC_SendByte()函数将写入数据发送到地址0x90,然后执行IIC_WaitAck()等待确认信号,最后调用IIC_Stop()函数结束通信。如果IIC总线通信不正常,则可能导致写入失败。

    可以在程序中添加调试信息,利用串口输出IIC总线通信信息,例如发送的地址、发送的数据、是否收到确认信号等,这样可以帮助快速定位问题。

    示例代码:

    void AT24C02_Write(unsigned char addr,unsigned char dat)
    {
        IIC_Start();
        printf("IIC total line start\n");
        IIC_SendByte(0x90);
        printf("send address: 0x90\n");
        IIC_WaitAck();
        IIC_SendByte(addr);
        printf("send address: 0x%02x\n", addr);
        IIC_WaitAck();
        IIC_SendByte(dat);
        printf("send data: 0x%02x\n", dat);
        IIC_WaitAck();
        IIC_Stop();
        printf("IIC total line stop\n");
    }
    

    通过添加这些调试信息,可以更好的了解IIC总线通信的细节,帮助快速找到问题所在。

    1. 检查写入数据是否正确

    在AT24C02_Write()函数中,将要写入的数据通过IIC_SendByte()函数发送到地址0x90。如果发送的数据不正确,也可能导致写入失败。

    可以在程序中输出将要发送的数据,帮助快速定位问题。

    示例代码:

    void AT24C02_Write(unsigned char addr,unsigned char dat)
    {
        IIC_Start();
        IIC_SendByte(0x90);
        IIC_WaitAck();
        IIC_SendByte(addr);
        IIC_WaitAck();
        printf("write data: 0x%02x\n", dat);
        IIC_SendByte(dat);
        IIC_WaitAck();
        IIC_Stop();
    }
    

    通过输出将要发送的数据,可以更好的判断是否是数据本身的问题导致写入失败。

    1. 检查写入操作是否正确执行

    在AT24C02_Write()函数中,IIC总线通信、数据本身都没有问题,但是如果IIC_Start()、IIC_SendByte()等函数不能正确执行,则可能导致写入失败。

    可以利用调试工具查看函数的执行情况,或者在函数执行语句之间插入调试信息,帮助快速定位问题。

    示例代码:

    void AT24C02_Write(unsigned char addr,unsigned char dat)
    {
        IIC_Start();
        printf("IIC_Start executed\n");
        IIC_SendByte(0x90);
        printf("send address: 0x90\n");
        IIC_WaitAck();
        IIC_SendByte(addr);
        printf("send address: 0x%02x\n", addr);
        IIC_WaitAck();
        printf("write data: 0x%02x\n", dat);
        IIC_SendByte(dat);
        printf("send data: 0x%02x\n", dat);
        IIC_WaitAck();
        IIC_Stop();
    }
    

    通过添加这些调试信息,可以更好的了解函数的执行情况,帮助快速找到问题所在。

    总结:

    以上是检查储存器24C02不能正常写入数据的一些解决方案。当遇到这种问题时,需要结合程序的执行情况、实际硬件连接情况、调试信息等多个方面进行分析,才能更快地找到问题所在并进行修复。