I2C调试时SCL波形异常

我用的国民技术031芯片调试I2C功能,发现SCL和SDA的波形如图所示,在第9,第18第27的位置均为ACK信号,但是27应答信号之后的SCL就连续出现两个高电平,不知道是哪里出了问题,哪位小伙伴能帮忙看看!

img

以下是初始化
```c
int i2c_master_init(void)
{
    I2C_InitType i2c1_master;
    GPIO_InitType i2c1_gpio;
    RCC_EnableAPB1PeriphClk(RCC_APB1_PERIPH_I2C1, ENABLE);
    RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_GPIOB, ENABLE);

    GPIO_InitStruct(&i2c1_gpio);
    /*PB6 -- SCL; PB7 -- SDA*/
    i2c1_gpio.Pin        = I2Cx_SCL_PIN | I2Cx_SDA_PIN;
    i2c1_gpio.GPIO_Speed = GPIO_SPEED_HIGH; 
    i2c1_gpio.GPIO_Mode  = GPIO_MODE_AF_OD;
    i2c1_gpio.GPIO_Alternate = GPIO_AF_I2C;
    i2c1_gpio.GPIO_Pull = GPIO_PULL_UP; 
    GPIO_InitPeripheral(GPIOx, &i2c1_gpio);

    I2C_DeInit(I2Cx);
    i2c1_master.BusMode     = I2C_BUSMODE_I2C;
    i2c1_master.FmDutyCycle = I2C_FMDUTYCYCLE_2; //if the spped greater than 400KHz, the FmDutyCycle mast be configured to I2C_FMDUTYCYCLE_2
    i2c1_master.OwnAddr1    = I2C_MASTER_ADDR;
    i2c1_master.AckEnable   = I2C_ACKEN;
    i2c1_master.AddrMode    = I2C_ADDR_MODE_7BIT;
    i2c1_master.ClkSpeed    = 100000;

    I2C_Init(I2Cx, &i2c1_master);

    I2C_Enable(I2Cx, ENABLE);
    return 0;
}


以下是在main函数中的while循环里调用的函数

```c
 I2C_EE_WriteBuffer(tx_buf, TEST_EEPROM_ADDR, 1);//TEST_EEPROM_SIZE
void I2C_EE_WriteBuffer(u8* pBuffer, u16 WriteAddr, u16 NumByteToWrite)
{
    if (I2C_GetFlag(I2Cx, I2C_FLAG_BUSY))
    {
        return;
    }
    I2C_pBuffer        = pBuffer;
    I2C_WriteAddr      = WriteAddr;
    I2C_NumByteToWrite = NumByteToWrite;

    while (I2C_NumByteToWrite > 0)
    {
        I2C_EE_WriteOnePage(I2C_pBuffer, I2C_WriteAddr, I2C_NumByteToWrite);
    }
}

void I2C_EE_WriteOnePage(u8* pBuffer, u16 WriteAddr, u16 NumByteToWrite)
{
    u8 NumOfPage = 0, NumOfSingle = 0, Addr = 0, count = 0;

    Addr        = WriteAddr % I2C_PageSize;
    count       = I2C_PageSize - Addr;
    NumOfPage   = NumByteToWrite / I2C_PageSize;
    NumOfSingle = NumByteToWrite % I2C_PageSize;

    I2C_NumByteWritingNow = 0;
    /** If WriteAddr is I2C_PageSize aligned */
    if (Addr == 0)
    {
        /** If NumByteToWrite < I2C_PageSize */
        if (NumOfPage == 0)
        {
            I2C_NumByteWritingNow = NumOfSingle;
            I2C_EE_PageWrite(pBuffer, WriteAddr, NumOfSingle);
        }
        /** If NumByteToWrite > I2C_PageSize */
        else
        {
            I2C_NumByteWritingNow = I2C_PageSize;
            I2C_EE_PageWrite(pBuffer, WriteAddr, I2C_PageSize);
        }
    }
    /** If WriteAddr is not I2C_PageSize aligned */
    else
    {
        /* If NumByteToWrite < I2C_PageSize */
        if (NumOfPage == 0)
        {
            I2C_NumByteWritingNow = NumOfSingle;
            I2C_EE_PageWrite(pBuffer, WriteAddr, NumOfSingle);
        }
        /* If NumByteToWrite > I2C_PageSize */
        else
        {
            if (count != 0)
            {
                I2C_NumByteWritingNow = count;
                I2C_EE_PageWrite(pBuffer, WriteAddr, count);
            }
        }
    }
}

void I2C_EE_PageWrite(u8* pBuffer, u16 WriteAddr, u16 NumByteToWrite)
{
#if PROCESS_MODE == 0 /* polling */
    sEETimeout = sEE_LONG_TIMEOUT;
    while (I2C_GetFlag(I2Cx, I2C_FLAG_BUSY))
    {
        if ((sEETimeout--) == 0)
            sEE_TIMEOUT_UserCallback();
    }
    /** Send START condition */
    I2C_GenerateStart(I2Cx, ENABLE);
    /** Test on EV5 and clear it */
    sEETimeout = sEE_LONG_TIMEOUT;
    while (!I2C_CheckEvent(I2Cx, I2C_EVT_MASTER_MODE_FLAG))
    {
        if ((sEETimeout--) == 0)
            sEE_TIMEOUT_UserCallback();
    }
    /** Send EEPROM address for write */
    I2C_SendAddr7bit(I2Cx, EEPROM_ADDRESS, I2C_DIRECTION_SEND);
    /** Test on EV6 and clear it */
    sEETimeout = sEE_LONG_TIMEOUT;
    while (!I2C_CheckEvent(I2Cx, I2C_EVT_MASTER_TXMODE_FLAG))
    {
        if ((sEETimeout--) == 0)
            sEE_TIMEOUT_UserCallback();
    }
    /** Send the EEPROM's internal address to write to */
    I2C_SendData(I2Cx, WriteAddr);
    /** Test on EV8 and clear it */
    sEETimeout = sEE_LONG_TIMEOUT;
    while (!I2C_CheckEvent(I2Cx, I2C_EVT_MASTER_DATA_SENDED))
    {
        if ((sEETimeout--) == 0)
            sEE_TIMEOUT_UserCallback();
    }
    /** While there is data to be written */
    while (NumByteToWrite--)
    {
        /** Send the current byte */
        I2C_SendData(I2Cx, *pBuffer);
        /** Point to the next byte to be written */
        pBuffer++;
        /** Test on EV8 and clear it */
        sEETimeout = sEE_LONG_TIMEOUT;
        while (!I2C_CheckEvent(I2Cx, I2C_EVT_MASTER_DATA_SENDED))
        {
            if ((sEETimeout--) == 0)
                sEE_TIMEOUT_UserCallback();
        }
    }
    /** Send STOP condition */
    I2C_GenerateStop(I2Cx, ENABLE);
    I2C_EE_WaitEepromStandbyState();
    I2C_EE_WriteOnePageCompleted();

#endif
}

1、主要查看程序,如果使用的是模拟IIC,看看for循环,还有应答部分的程序
2、最好使用逻辑分析仪,看看SDA数据是否正确
3、把程序段贴出来

看这波形,貌似重新start了?
建议使用逻辑分析仪,能直观一点。还有就是,你这clk看着不太好么。

根据你这个的波形显示,软件的bug可能性比较大,最好使用逻辑分析仪进行分析。还有最好把一些关键代码发上来,方便大家分析。

以下内容部分参考ChatGPT模型:


可能是硬件连接问题或者时序问题。建议检查以下几个方面:

  1. I2C总线上拉电阻是否正确连接。

  2. I2C时序是否正确,包括起始信号、停止信号、数据位和应答位的时序。

  3. 是否存在与I2C信号线干扰相关的问题,例如电源噪声、地线干扰等。

  4. 是否存在与外设相关的问题,例如外设地址是否正确、外设响应是否正常等。

另外,建议使用示波器对I2C信号进行详细的波形分析,以确定问题的具体位置。

如果我的建议对您有帮助、请点击采纳、祝您生活愉快

我觉得是你的示波器没有调好

以下答案由GPT-3.5大模型与博主波罗歌共同编写:
根据波形图,问题出现在第27个字节的ACK信号之后,SCL电平连续出现了两个高电平,这可能是由于I2C总线在该时刻上发生了冲突或者噪声导致的,需要进一步排除。

以下是一些可能导致该问题的原因:

  1. 硬件问题:检查I2C总线的物理连接,确保连接正确。

  2. 信号干扰:如果你的系统中有其他噪声源或者干扰源可能导致I2C通信过程中的数据干扰,应该对信号线进行屏蔽以保证正确的数据传输。

  3. 信号强度:如果SCL和SDA信号强度不足可能导致数据错误和I2C总线故障,可以通过增加信号的驱动能力或者调整I2C线路电缆的长度来提高信号强度。

  4. 初始化问题:可以检查I2C初始化是否正确,比如I2C时钟频率、总线模式等参数是否与设备匹配。同时还可以查看是否正确地配置了ACK信号。

  5. 软件问题:建议对I2C驱动程序进行调试,用示波器观察准确的I2C信号波形,以确定问题是否由软件引起。可以通过单步调试代码,观察数据发送过程中是否存在错误。

下面是一些代码修改建议:

  1. 将GPIO模式修改为推挽模式(GPIO_MODE_AF_PP),这可以提高I2C总线的信号强度。

  2. 尝试调整I2C时钟频率,以确定是否可以通过改变频率来改善总线性能。

  3. 在初始化的时候,可以添加一些错误检查和异常处理,以避免非法参数和错误的操作引起的问题。

  4. 在I2C总线正式通信之前,可以加入一些I2C总线复位和初始化代码,以确保总线状态良好。同时在发送数据的时候,建议在发送前检查一下I2C总线是否空闲,如果不空闲需要等待一段时间或者是立即返回。

综上所述,建议优先检查硬件连接以及信号干扰问题,如果这些问题排除后,可以尝试调整I2C配置参数或者进行代码调试来解决问题。
如果我的回答解决了您的问题,请采纳!

朋友你好,以下是我把你的问题和相关观点都看了一遍分析出来的,望采纳谢谢啦
大致看了一下朋友的程序,它包括几个函数:
int i2c_master_init(void) - 初始化I2C外设和GPIO引脚以便与EEPROM一起使用。这个函数设置GPIO引脚为替代功能开漏模式,设置适当的上拉电阻,并配置了I2C通信参数,如速度和寻址。
I2C_EE_WriteBuffer(u8* pBuffer, u16 WriteAddr, u16 NumByteToWrite) - 向EEPROM中从内存地址WriteAddr开始写入NumByteToWrite字节的缓冲区数据,使用一个或多个页。此函数重复调用I2C_EE_WriteOnePage,直到所有数据都写入EEPROM。
I2C_EE_WriteOnePage(u8* pBuffer, u16 WriteAddr, u16 NumByteToWrite) - 将长度为NumByteToWrite的数据缓冲区写入以WriteAddr为起始地址的单个页面中。如果写入地址未对齐到页面边界,该函数将先写数据到第一页直到页面边界,然后继续写剩余的数据到后续页。此函数然后调用I2C_EE_PageWrite将数据通过I2C发送到EEPROM。
I2C_EE_PageWrite(u8* pBuffer, u16 WriteAddr, u16 NumByteToWrite) - 发送START信号以启动新的I2C事务,发送设置WR位的EEPROM的7位地址,等待TX缓冲区为空,发送要写入的内存地址,再次等待TX缓冲区为空,然后逐字节向EEPROM写入数据。当所有数据都写入后,函数会发送一个STOP信号,并等待EEPROM准备好后调用I2C_EE_WriteOnePageCompleted()。
这些函数一起提供了一种使用Microcontroller上的主模式I2C控制器将数据写入I2C EEPROM的方法。
朋友看看还有哪里不理解的

不知道你这个问题是否已经解决, 如果还没有解决的话:

如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^

目前已解决