我正在使用PIC16F1789和MPU-9250。我的I2C阅读功能中的代码如下所示:
unsigned char i2cSensor_Read(unsigned char regAddr){
unsigned char val;
// Start
i2cWait();
SEN = 1;
// Address + Write Bit
i2cWait();
SSP1BUF = ((slvAdd<<1) | (0b0<<0)); // address slave + write (0)
i2cWait();
//Register address
SSP1BUF = regAddr; // address register
i2cWait();
//Start
RSEN = 1;
i2cWait();
// Address + Read Bit
SSP1BUF = ((slvAdd<<1) | (0b1<<0)); //Address + read (1)
i2cWait();
// Read data
RCEN = 1;
i2cWait();
val = SSP1BUF;
ACKDT = 1; // set acknowlege Bit (1 = Not Acknowlege, 0 = Acknowlege)
ACKEN = 1; // send acknowlege Bit
// Stop
i2cWait();
PEN = 1;
return val;
}
调用最后一个i2cWait()时,程序挂起。
等待函数如下所示:
void i2cWait(){
while((SSP1STAT & 0x04) || (SSP1CON2 & 0x1F));
}
我已经使用了9250数据表第35页上的“单字节读取序列”:https://cdn.sparkfun.com/assets/learn_tutorials/5/5/0/MPU9250REV1.0.pdf
和PIC数据表:http://ww1.microchip.com/downloads/en/DeviceDoc/40001675C.pdf
调试时,在我发送NACK位后,程序卡在了i2cWait()中。之所以卡住是因为SSPCON2寄存器(PIC数据表的第341页)的ACKEN位(第4位)没有被清除,因此程序被卡在while()中。
为什么会这样呢?从站是否必须清除该位?从设备是否损坏?
最佳答案
我认为问题实际上是BF标志仍然设置并且不允许ack移出。一旦设置了RCEN,便会清除BF标志,因此对wait的调用不会执行任何操作,并且val可能包含旧数据,而不是新数据。 8个时钟后,BF标志被置1,SSP1BUF具有新数据。同样,问题在于设置了BF是因为您在接收数据后没有读取数据缓冲区,因此波特率发生器(时钟源)被挂起:
“将SSPSR的内容加载到SSPBUF中,BF标志位
位置1时,将SSP1IF标志位置1并将波特率发生器设置为1。
暂停计数,将SCL保持在低电平。 MSSP现在处于空闲状态
状态等待下一个命令。当CPU读取缓冲区时,
BF标志位自动清零。然后,用户可以发送
通过设置确认在接收结束时确认位
SSPCON2寄存器的ACKEN位序列使能。”
要解决此问题,您应该在编写RCEN之后轮询BF标志以查找真值。
还有其他问题,例如写入SEN之后的等待可能也不起作用,因为仅写入SEN的SSP1IF位(SSP1IF在启动完成时由硬件置位)。
关于c - I2C ACK位不会被硬件清除,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/59480164/