请将你的代码贴出来,我发现很多客户在用STM32写程序时,有一些不合理的地方。
根据官方EEPROM例程修改而来,如发送程序:
/*wait 5us min for bus free time limitation for later transaction*/
SetDelayTime_us(5);
while(!TOFlag);
StopDelayCount(); //SysTick_CounterCmd(SysTick_Counter_Disable);
TOFlag = FALSE;
/*wait bus free*/
SetDelayTime_us(BUS_BUSY_TIMEOUT);
while((I2C_GetFlagStatus(I2Cx, I2C_FLAG_BUSY))&&(!TOFlag));
StopDelayCount(); //SysTick_CounterCmd(SysTick_Counter_Disable);
if (TOFlag)
{
TOFlag = FALSE;
return I2C_BUS_BUSY;
}
/*send start and wait*/
I2C_GenerateSTART(I2Cx, ENABLE);
SetDelayTime_us(SEND_START_TIMEOUT);
while(!(I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT) || TOFlag)); //wait BUSY,MSL,SB to be set
StopDelayCount(); //SysTick_CounterCmd(SysTick_Counter_Disable);
if (TOFlag)
{
TOFlag = FALSE;
return I2C_SEND_START_ERR;
}
/* send 7-bit slave address and wait */
I2C_Send7bitAddress(I2Cx, (u8)(slaveaddr & 0xFF), I2C_Direction_Transmitter);
SetDelayTime_us(SEND_ADDR7_TIMEOUT);
while(!(I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) || TOFlag)); //Wait BUSY/MSL/ADDR/TxE/TRA to be set
StopDelayCount(); //SysTick_CounterCmd(SysTick_Counter_Disable);
if (TOFlag)
{
TOFlag = FALSE;
I2C_GenerateSTOP(I2Cx, ENABLE);
while ((I2Cx->CR1 & 0x200) == 0x200); //wait while STOP bit not cleared
if(I2C_GetFlagStatus(I2Cx, I2C_FLAG_AF))
I2C_ClearFlag(I2Cx, I2C_FLAG_AF);
return I2C_ADDR_MATCH_ERR;
I2C_SendData(I2Cx, *pBuffer++);
length--;
while (length--)
{
SetDelayTime_us(SEND_DATA_TIMEOUT);
while (((I2C_GetLastEvent(I2Cx) & 0x04) != 0x04)&&(!TOFlag)); //Wait BTF to be set
// while (((I2C_GetLastEvent(I2Cx) & 0x80) != 0x80));//&&(!TOFlag));
StopDelayCount();
if (TOFlag)
{
TOFlag = FALSE;
I2C_GenerateSTOP(I2Cx, ENABLE);
while ((I2Cx->CR1 & 0x200) == 0x200);
if(I2C_GetFlagStatus(I2Cx, I2C_FLAG_AF))
I2C_ClearFlag(I2Cx, I2C_FLAG_AF);
return I2C_DATA_TIMEOUT;
}
I2C_SendData(I2Cx, *pBuffer++);
}
SetDelayTime_us(SEND_DATA_TIMEOUT);
while (!(I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED) || TOFlag));
StopDelayCount();
if (TOFlag)
{
TOFlag = FALSE;
I2C_GenerateSTOP(I2Cx, ENABLE);
while ((I2Cx->CR1 & 0x200) == 0x200);
if(I2C_GetFlagStatus(I2Cx, I2C_FLAG_AF))
I2C_ClearFlag(I2Cx, I2C_FLAG_AF);
return I2C_DATA_TIMEOUT;
}
/* send stop to close communication */
I2C_GenerateSTOP(I2Cx, ENABLE);
能不能回答一下我1楼提出的那三个问题?
还有感觉I2C设计的怪怪的,接收时不能在从DR寄存器读取字节后立即产生NAK或STOP,而是必须再接收至少三个字节,也就是手册上所说的读n字节时序:
(n-2)BTF后发NAK -> 读(n-2) -> 发STOP -> 读(n-1) -> 等待RxNE -> 读n),
这对于已知要读取的长度的数据好处理,可以在结束前三个字节时开始处理NAK,STOP,而对于需要根据接收的数据来判断是否继续接收,假如根据一定的协议从DR读出接收到的字节指明接收结束,则后续发出NAK和STOP就会必须多读3个字节才结束.这在某些时候会导致问题,比如本来后面的数据要下次读的而你本次为了发出NAK和STOP就多读了3个,那下次读可能就丢失了3个数据.
}