我用的国民技术031芯片调试I2C功能,发现SCL和SDA的波形如图所示,在第9,第18第27的位置均为ACK信号,但是27应答信号之后的SCL就连续出现两个高电平,不知道是哪里出了问题,哪位小伙伴能帮忙看看!
以下是初始化
```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可能性比较大,最好使用逻辑分析仪进行分析。还有最好把一些关键代码发上来,方便大家分析。
可能是硬件连接问题或者时序问题。建议检查以下几个方面:
I2C总线上拉电阻是否正确连接。
I2C时序是否正确,包括起始信号、停止信号、数据位和应答位的时序。
是否存在与I2C信号线干扰相关的问题,例如电源噪声、地线干扰等。
是否存在与外设相关的问题,例如外设地址是否正确、外设响应是否正常等。
我觉得是你的示波器没有调好
以下答案由GPT-3.5大模型与博主波罗歌共同编写:
根据波形图,问题出现在第27个字节的ACK信号之后,SCL电平连续出现了两个高电平,这可能是由于I2C总线在该时刻上发生了冲突或者噪声导致的,需要进一步排除。
以下是一些可能导致该问题的原因:
硬件问题:检查I2C总线的物理连接,确保连接正确。
信号干扰:如果你的系统中有其他噪声源或者干扰源可能导致I2C通信过程中的数据干扰,应该对信号线进行屏蔽以保证正确的数据传输。
信号强度:如果SCL和SDA信号强度不足可能导致数据错误和I2C总线故障,可以通过增加信号的驱动能力或者调整I2C线路电缆的长度来提高信号强度。
初始化问题:可以检查I2C初始化是否正确,比如I2C时钟频率、总线模式等参数是否与设备匹配。同时还可以查看是否正确地配置了ACK信号。
软件问题:建议对I2C驱动程序进行调试,用示波器观察准确的I2C信号波形,以确定问题是否由软件引起。可以通过单步调试代码,观察数据发送过程中是否存在错误。
下面是一些代码修改建议:
将GPIO模式修改为推挽模式(GPIO_MODE_AF_PP),这可以提高I2C总线的信号强度。
尝试调整I2C时钟频率,以确定是否可以通过改变频率来改善总线性能。
在初始化的时候,可以添加一些错误检查和异常处理,以避免非法参数和错误的操作引起的问题。
在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的方法。
朋友看看还有哪里不理解的
目前已解决