打印
[AVR单片机]

关于24C256的问题,用的是atmega64

[复制链接]
1079|4
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
zxc2216843|  楼主 | 2018-6-29 09:17 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
最近在调试24c256,出了点问题老是找不出毛病,就是对24C256写数据的时候,前面有可能用得好好的,后面就突然数据开始错位了
正常读出来的数据应该是这样的:1803041000030028130161
但是出现问题后读出来的数据都是:
0627110546002812016100
0627110712000004000000
0627150724000004000000
(我是每次写入16字节的数据,前11个字节是有效,后5个是补零)
我每次只写16个字节的数据,写入的间隔时间也不短,出问题是应该是地址错位了。
但是程序里面是没有问题的。所以想请问大神们,有什么原因可能导致我出现这个问题,谢谢

下面我贴下我的程序,请帮忙看下
这是main里使用的:
        IIC_Transmit(0xA0,Wddr, &Savedata[0], 16);//往24C256写入数据
           Delayms(400);


下面是24c256的子程序:
**************************************************************************************************************************/
/*
********************************************************
函数名称:void AT24C256_Init(void)
函数功能:初始化IO口
********************************************************
*/
void AT24C256_Init(void)
{
    DDRE  |= 0xC0;
        PORTE |= 0xC0;
}
/*
********************************************************
函数名称:static void IIC_delay(void)
函数功能:延时
********************************************************
*/
static void IIC_delay(void)
{
   asm("nop");
}

/*
********************************************************
函数名称:static void IIC_delay(void)
函数功能:主机发送开始信号
********************************************************
*/
static void IIC_Start(void)
{
    MODE_OUT;
        
        SDA_H;
                asm("nop");

        SCL_H;
                asm("nop");
                asm("nop");
                asm("nop");

        SDA_L;
                asm("nop");
                asm("nop");
                asm("nop");
                asm("nop");

        SCL_L;
                asm("nop");
                asm("nop");

}


/*
********************************************************
函数名称:static void IIC_Stop(void)
函数功能:主机发送结束信号
********************************************************
*/
static void IIC_Stop(void)
{
    MODE_OUT;

    SCL_L;
                asm("nop");
                asm("nop");

        SDA_L;
                asm("nop");
                asm("nop");

        SCL_H;
                asm("nop");
                asm("nop");
                asm("nop");
                asm("nop");

        SDA_H;
                asm("nop");
                asm("nop");
                asm("nop");
                asm("nop");


}

/*
********************************************************
函数名称: static unsigned char IIC_ACK_Check(void)
函数功能: 主机成功发送一个字节数据后,AT24C256会发送一
           应答信号。
返回值  : 1    没有应答信号,即从机没有成功接收到数据
           0    有应答信号,即从机已接收到了数据
********************************************************
*/
static unsigned char IIC_ACK_Check(void)
{
    unsigned char Bitmun;
        
        MODE_IN;
        
    SCL_L;
                asm("nop");
                asm("nop");

        SDA_H;
                asm("nop");
                asm("nop");
        
        SCL_H;
                asm("nop");
                asm("nop");
                asm("nop");
                asm("nop");

        Bitmun = PINE;
        
        SCL_L;
                asm("nop");
                asm("nop");

        
        Bitmun =(Bitmun >> 7)&0x01;
        
        
    return Bitmun;
}

/*
********************************************************
函数名称: static void IIC_NO_ACK(void)
函数功能: 主机发送一个字节数据后,
           不会检测从机的应答信号
********************************************************
*/
static void IIC_NO_ACK(void)
{
    MODE_OUT;

    SCL_L;
            asm("nop");
                asm("nop");

        SDA_H;
                asm("nop");
                asm("nop");

        SCL_H;
                asm("nop");
                asm("nop");
                asm("nop");
                asm("nop");

        SCL_L;
                asm("nop");
                asm("nop");

}

/*
********************************************************
函数名称: static void IIC_ACK_Creat(void)
函数功能: 主机向从机请求一个字节数据后,
           发送应答信号,告诉从机继续发送数据。(连读读模式)
********************************************************
*/
static void IIC_ACK_Creat(void)
{
    MODE_OUT;

        SCL_L;
                asm("nop");
                asm("nop");

        SDA_L;
                asm("nop");
                asm("nop");

    SCL_H;
                asm("nop");
                asm("nop");
                asm("nop");
                asm("nop");

        SCL_L;
                asm("nop");
                asm("nop");

}

/*
********************************************************
函数名称:  static void IIC_Send8Bit(unsigned char SendByte)
函数功能:  主机发送一个字节数据
********************************************************
*/
static void IIC_Send8Bit(unsigned char SendByte)
{
    char counter;
               
        MODE_OUT;
               
        SDA_L;
                asm("nop");
                asm("nop");
                asm("nop");

        for (counter = 8; counter >0; counter--)
        {
        SCL_L;
                asm("nop");
                asm("nop");

                        
            if (SendByte & 0x80)
                {
                    SDA_H;
                        asm("nop");
                }
                else
                {
            SDA_L;
                        asm("nop");
                        asm("nop");
                }
               
                SCL_H;
                        asm("nop");

                SendByte = SendByte << 1;

        }
SCL_L;
                asm("nop");
                asm("nop");
}

/*
********************************************************
函数名称:   static unsigned char IIC_Receive8Bit(void)
函数功能:   主机接收一个字节数据
********************************************************
*/
static unsigned char IIC_Receive8Bit(void)
{
    char counter;
    unsigned char ReceiveByte=0;
        unsigned char IOstatus=0;
        
        MODE_IN;
        
        SCL_L;
                asm("nop");
                asm("nop");

    SDA_H;
                asm("nop");
                asm("nop");

        
    for (counter = 8; counter > 0; counter--)
        {
        SCL_L;
                        asm("nop");
                        asm("nop");

                SCL_H;
                        asm("nop");
                        asm("nop");

                IOstatus = PINE;
               
            ReceiveByte  = ReceiveByte<<1;
        ReceiveByte        |= (IOstatus >>7)& 0x01;
        }
        SCL_L;
        return ReceiveByte;
}
/*
********************************************************
函数名称:   char IIC_Transmit(unsigned char lcv_device,unsigned int liv_addr,unsigned char *lcv_pdata, char counter)
函数功能:   主机往指定地址发送数据
             unsigned char lcv_device    从机地址
                         unsigned int liv_addr       从机内部存储地址
                         unsigned char *lcv_pdata    发送数据缓存区
                         char counter                发送多少个数据
                        
返回值 :    1    写入数据失败
             0    写入成功

                         注: AT24C256在连续读写过程中,会自动增加地址,但是不会自动跳转到下一页,
                              所以要注意连续读写过程中不要超过页的存储空间,避免最先存储的数据被覆盖从而导致
                                  数据丢失。
********************************************************
*/
char IIC_Transmit(unsigned char lcv_device,unsigned int liv_addr,unsigned char *lcv_pdata, char counter)
{
    IIC_Start();
        
        /* 发送从机地址 */
        IIC_Send8Bit(lcv_device);
        if ( IIC_ACK_Check() ) //调用函数char IIC_ACK_Check(void),没有从机回应则结束本次发送。
        {
            IIC_Stop();
        return FAIL;
        }

        /* 发送内存地址*/
    IIC_Send8Bit((unsigned char)(liv_addr >> 8) & 0x0FF);  //高八位
        if ( IIC_ACK_Check()) //调用函数char IIC_ACK_Check(void),没有从机回应则结束本次发送。
    {
        IIC_Stop();
                return FAIL;
    }        
    IIC_Send8Bit((unsigned char)((liv_addr)&0x0FF));  //低八位
        if ( IIC_ACK_Check()) //调用函数char IIC_ACK_Check(void),没有从机回应则结束本次发送。
        {
        IIC_Stop();
                return FAIL;
        }        
               
        /* 发送数据 */
    for(;counter > 0;counter-- )               
    {
        IIC_Send8Bit(*lcv_pdata);
            if ( IIC_ACK_Check()) //调用函数char IIC_ACK_Check(void),没有从机回应则结束本次发送。
                {
                    IIC_Stop();
                    return FAIL;
                }        
            lcv_pdata++;
    }
               

        IIC_Stop();
               
        return SUCCEED;
}

/*
********************************************************
函数名称 :  char IIC_Receive(unsigned char lcv_device, unsigned int liv_addr, unsigned char *lcv_pdata, char counter)
函数功能 :  主机接收数据
             unsigned char lcv_device    从机地址
                         unsigned int liv_addr       从机内部存储地址
                         unsigned char *lcv_pdata    发送数据缓存区
                         char counter                发送多少个数据

返回值 :    1      读数据失败
             0      读成功
                        
                         注: AT24C256在连续读写过程中,会自动增加地址,但是不会自动跳转到下一页,
                              所以要注意连续读写过程中不要超过页的存储空间,避免最先存储的数据被覆盖从而导致
                                  数据丢失。               
                                 
                                  读模式:  需要先配置为写模式,然后才能改为读模式
********************************************************
*/
char IIC_Receive(unsigned char lcv_device, unsigned int liv_addr, unsigned char *lcv_pdata, char counter)
{

        /* 先将从机配置为写模式 */
    IIC_Start();
        /* 发送从机地址 */
    IIC_Send8Bit(lcv_device);
        if ( IIC_ACK_Check())//调用函数char IIC_ACK_Check(void),没有从机回应则结束本次发送。
        {
        IIC_Stop();
        return FAIL;
        }
               
           /*    发送内存地址   */
    IIC_Send8Bit((unsigned char)((liv_addr >> 8)&0x0FF));
        if ( IIC_ACK_Check()) //调用函数char IIC_ACK_Check(void),没有从机回应则结束本次发送。
        {
            IIC_Stop();
                return FAIL;
        }        
    IIC_Send8Bit((unsigned char)((liv_addr)&0x0FF));               
        if ( IIC_ACK_Check()) //调用函数char IIC_ACK_Check(void),没有从机回应则结束本次发送。
        {
            IIC_Stop();
                return FAIL;
        }        
        
        
            /* 然后将从机配置为写模式 */        
            IIC_Start();
        /* 发送从机地址 */
            IIC_Send8Bit(lcv_device+1);
            if ( IIC_ACK_Check()) ////调用函数char IIC_ACK_Check(void),没有从机回应则结束本次发送。
            {
            IIC_Stop();
                    return FAIL;
        }        
               
        for( ; counter > 0; )
        {

        *lcv_pdata = IIC_Receive8Bit();
            counter--;
            if ( counter >0)
                {
                    IIC_ACK_Creat();
                    lcv_pdata++ ;
                }
               
        }
        
        IIC_NO_ACK();
        IIC_Stop();
        
        return SUCCEED;
}
评论
xch 2018-6-29 16:07 回复TA
你先用 IIC_delay 调出一个SCL方波,频率是400khz, 方便调用。 宏定义一个mcu工作频率,和总线工作频率,自适应生成IIC_delay 函数。 
xch 2018-6-29 16:02 回复TA
应该是硬件问题。 不知道延时够不够。mcu 运行频率是多少? 比如运行频率 16MHZ, 24256 总线是400khzMax。 16/0.4MHZ = 40; 看你软件延时使用nop,AVR 是risc ,从scl 之间至少的有19 个NOP 或者其他指令。 

相关帖子

沙发
ayb_ice| | 2018-6-29 10:43 | 只看该作者
主接收的最后一个字节要发送非应答信号,通知从机释放总线,否则可能出错

使用特权

评论回复
板凳
Prry| | 2018-6-30 10:06 | 只看该作者
模拟i2c时序要求并不严格,除非严重偏离。上示波器吧。参考st的:https://blog.csdn.net/qq_20553613/article/details/78878211

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

4

主题

6

帖子

0

粉丝