1

我使用的是 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() 中。

为什么会这样?从站是否必须清除该位?从设备坏了吗?

4

1 回答 1

0

我认为问题实际上是 BF 标志仍然设置并且不允许 ack 被打卡。一旦你设置了 RCEN,BF 标志就会被清除,因此等待的调用什么也不做,并且 val 可能包含旧数据,而不是新数据。8 个时钟后,BF 标志置位,SSP1BUF 获得新数据。同样,问题是设置了BF,因为您在接收到数据后没有读取数据缓冲区,因此波特率发生器(时钟源)被暂停:

“SSPSR 的内容被加载到 SSPBUF,BF 标志位被置位,SSP1IF 标志位被置位,波特率发生器暂停计数,将 SCL 保持为低电平。MSSP 现在处于空闲状态,等待下一个命令. 当 CPU 读取缓冲区时,BF 标志位自动清零。然后用户可以通过设置 SSPCON2 寄存器的确认序列使能位 ACKEN 在接收结束时发送一个确认位。

要解决此问题,您应该在编写 RCEN 后轮询 BF 标志以查找 true。

还有其他问题,例如写入 SEN 后的等待可能也无济于事,因为只写入 SSP1IF 位(SSP1IF 在启动完成时由硬件设置。)

于 2020-01-02T19:41:06.567 回答