This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
工具/软件:Code Composer Studio
大家好、
我正在尝试从磁传感器(PN:AM4096)获取数据、并且遇到了问题。 代码在同一总线上与温度传感器配合使用良好。 作为一种方式、我在第一次获得有效数据、但当我第二次尝试时、代码会挂起、以在 read_Bytes 函数中查找 I2caRegs.I2CMDR.bit.STT 标志以进行清除。
UINT16 AM4096class::GetAbsoluteAngle (void) { uint8数据[2]; int16结果= I2C_Success; AM4096class::SetRegisterAddress (32); 结果= I2C.Read_Bytes ((AM4096_address_code |(AM4096class::Address))、sizeof (data)、data); AM4096class::data_union.data_Registers.data_ADDR_33.all = data[1]<<8+data[0]; 返回结果; } uint16 I2Cclass::read_Bytes (uint16 slave_address、uint16 count、uint8 *out) { uint16 i、ret; GpioDataRegs.GPADAT.bit.GPIO21=0; I2Cclass::start (slave_address); GpioDataRegs.GPADAT.bit.GPIO21=1; //发出重复启动 I2caRegs.I2CMDR.bit.STT = 1; //等待重复开始到结束 I2Cclass::timeout=0; while (I2caRegs.I2CMDR.bit.STT!= 0) { I2Cclass::I2Cclass::timeout++; if (I2Cclass::I2Cclass::timeout>timeout_limit) { 返回 I2C_ERROR; } } //非重复模式 I2caRegs.I2CMDR.bit.RM = 0; //设置数据计数 I2caRegs.I2CCNT =计数; //在数据计数器递减到0时生成停止条件 I2caRegs.I2CMDR.bit.STP= 1; //接收器模式 I2caRegs.I2CMDR.bit.TRX = 0; 对于(i = 0;i < count;+i) { //等待数据接收寄存器准备好读取 I2Cclass::timeout=0; while (I2cRegs.I2CSTR.bit.RRDY!= 1) { I2Cclass::timeout++; if (I2Cclass::timeout>timeout_limit) 返回 I2C_ERROR; } OUT[i]= I2caRegs.I2CDRR; } 返回 I2C_SUCCESS; } UINT16 I2Cclass::start (UINT16 SLAVE_ADDRESS) { //加载从器件地址 I2caRegs.I2CSAR =从器件地址; //等待停止条件 I2Cclass::timeout=0; while (I2caRegs.I2CMDR.bit.STP!= 0) { I2Cclass::timeout++; if (I2Cclass::timeout>timeout_limit) 返回 I2C_ERROR; } //主控模式 I2caRegs.I2CMDR.bit.MST = 1; //生成起始条件 I2caRegs.I2CMDR.bit.STT = 1; 返回 I2C_Success ;}
下面的图片是第一个请求。 它返回正确的值。
第二幅图显示了 I2C 总线挂起。 它能够发送从器件和寄存器地址。
此图像是从 Arduino 运行传感器时的图像。 它每次都能正常工作。
有人能不能就此发出一些光? 谢谢!
在按照以下 wiki 页面上的建议重新配置 I2C 以进行重复启动之前、是否可以尝试检查 ARDY 位?
https://processors.wiki.ti.com/index.php/I2C_Tips#Repeated_Start
惠特尼
如果我在函数的开始处清除 ARDY、我不会卡住:
uint16 I2Cclass::read_Bytes (uint16 slave_address、uint16 count、uint8 *out) { uint16 i、ret; uint8垃圾[16]; I2caRegs.I2CSTR.bit.ARDY = 1; I2Cclass::start (slave_address);
不过、不要认为这是一个解决方案。 为什么在第一个数据包的末尾不清除 ARDY?
要进行澄清、您应该等待 ARDY 置1、而不是清零。 该位置位时表明寄存器已准备好更新、因为之前的配置已经被使用。 那么、ARDY 是否不再升高、或者它只是在您最近的屏幕截图中切断?
惠特尼
明白了。 问题是、ARDY 在传输成功后从不会清除(发出停止位)
我反复阅读了所提到的链接、但运气不好。 我重新编写了代码以与建议的代码匹配、在检查 ARDY 时仍然卡住。
uint16 I2Cclass::read_block (uint16 slave_address、uint16 read_address、uint16 count、uint8 *out) { uint16 i、ret; I2Cclass::timeout=0; while (I2cRegs.I2CSTR.bit.BB); I2caRegs.I2CMDR.ALL = 0;//在配置期间禁用 I2C 模块 I2caRegs.I2CSAR =从器件地址;//设置器件地址 I2caRegs.I2CMDR.ALL = 0x2620; I2Cclass::timeout=0; while (((!I2cRegs.I2CSTR.bit.XRDY));//||(!I2cRegs.I2CSTR.bit.ARDY)); if (I2caRegs.I2CSTR.bit.nack) { I2caRegs.I2CMDR.ALL = 0;//复位 I2C 以便 SCL 不被保持在低电平返回 RRET__FAIL; 返回 I2C_Nack_error; } I2caRegs.I2CDXR = READ_ADDRESS; //写入寄存器地址 I2Cclass::timeout=0; //***我被卡在这里!***// while (!I2caRegs.I2CSTR.bit.ARDY);//等待 ARDY 被清除 //设置数据计数 I2caRegs.I2CCNT =计数; I2caRegs.I2CMDR.ALL = 0x2C20; 对于(i = 0;i < count;+i) { //等待数据接收寄存器准备好读取 I2Cclass::timeout=0; while ((!I2cRegs.I2CSTR.bit.RRDY)||(!I2cRegs.I2CSTR.bit.ARDY)); if (I2caRegs.I2CSTR.bit.nack) { I2caRegs.I2CMDR.ALL = 0;//复位 I2C 以便 SCL 不被保持在低电平返回 RRET__FAIL; 返回 I2C_Nack_error; } OUT[i]= I2caRegs.I2CDRR; } 返回 I2C_Success ;}
下面的数据显示了我正在监控的一些控制线。
当 I2CMDR.RM 为0时、ARDY 不会再次变为高电平、直到字节计数递减到零-但在发送读取地址之前、您绝不会设置字节计数。 如果您将字节计数设置为1、ARDY 是否会在适当的时间变为高电平?
惠特尼
尊敬的惠特尼:
我发现了这个问题。 我现在可以使用代码、但如果我在下面的两个位置检查 ARDY、它将锁定。 但是、它们位于您提到的参考代码中。
uint16 I2Cclass::read_block (uint16 slave_address、uint16 read_address、uint16 count、uint8 *out) { uint16 i; I2Cclass::timeout=0; while (I2cRegs.I2CSTR.bit.BB); { I2Cclass::timeout++; if (I2Cclass::timeout>timeout_limit) 返回 I2C_ERROR; } I2caRegs.I2CMDR.ALL = 0; I2caRegs.I2CSAR =从器件地址;//设置器件地址 I2caRegs.I2CCNT = 1; //仅发送一个字节(寄存器地址) I2caRegs.I2CMDR.ALL = 0x2620; //开始传输 I2Cclass::timeout=0; //<<< >> while (((!I2cRegs.I2CSTR.bit.XRDY));//||(!I2cRegs.I2CSTR.bit.ARDY)); { I2Cclass::timeout++; if (I2Cclass::timeout>timeout_limit) 返回 I2C_ERROR; } if (I2caRegs.I2CSTR.bit.nack) { I2caRegs.I2CMDR.ALL = 0;//复位 I2C 以便 SCL 不被保持在低电平返回 RRET__FAIL; 返回 I2C_Nack_error; } I2caRegs.I2CDXR = READ_ADDRESS; //写入寄存器地址 I2Cclass::timeout=0; while (!I2caRegs.I2CSTR.bit.ARDY);//等待 ARDY 被清除 { I2Cclass::timeout++; if (I2Cclass::timeout>timeout_limit) 返回 I2C_ERROR; } //设置数据计数 I2caRegs.I2CCNT =计数; I2caRegs.I2CMDR.ALL = 0x2C20; 对于(i = 0;i < count;+i) { //等待数据接收寄存器准备好读取 I2Cclass::timeout=0; //<<< >> while (((!I2cRegs.I2CSTR.bit.RRDY));//||(!I2cRegs.I2CSTR.bit.ARDY)); { I2Cclass::timeout++; if (I2Cclass::timeout>timeout_limit) 返回 I2C_ERROR; } if (I2caRegs.I2CSTR.bit.nack) { I2caRegs.I2CMDR.ALL = 0;//复位 I2C 以便 SCL 不被保持在低电平返回 RRET__FAIL; 返回 I2C_Nack_error; } OUT[i]= I2caRegs.I2CDRR; } 返回 I2C_Success ;}
下面是信号在信号分析器中的表现。
您好 Fabio、
对于您所说的内容、您是否正确回答了以下问题? 如果是、我看不出为什么它会卡住。
//<<< >> while (((!I2cRegs.I2CSTR.bit.XRDY));//||(!I2cRegs.I2CSTR.bit.ARDY));
.
I2caRegs.I2CMDR.ALL = 0x4620; //开始传输
这实际上会使它变得更糟糕。 代码将始终锁定在:
I2caRegs.I2CDXR = READ_ADDRESS; //写入寄存器地址 I2Cclass::timeout=0; while (!I2caRegs.I2CSTR.bit.ARDY);//等待 ARDY 被清除 { I2Cclass::timeout++; if (I2Cclass::timeout>timeout_limit) 返回 I2C_ERROR; }
因此、当它未注释时、语句如下所示:
while ((!I2cRegs.I2CSTR.bit.XRDY)||(!I2cRegs.I2CSTR.bit.ARDY));
在中断循环之前、是否等到 XRDY 和 ARDY 都设置完毕? 我认为示例代码表示等待这两个代码中的任何一个。
while (!(I2cRegs.I2CSTR.bit.XRDY || I2cRegs.I2CSTR.bit.ARDY));
此外,是否忘记删除;添加超时代码是故意的?
惠特尼
尊敬的惠特尼:
感谢您抓住;错误。 这不是有意的、但不应影响我的问题。
您提议的 while 语句在逻辑上是合理的、但我不太理解参考指南中的语句、即我必须等待 ARDY 进行清除。 当运行此代码时、我现在可以运行而不会锁定。 但是、由于 XRDY 是中断此 while 循环的标志、因此 ARDY 并不总是被清除。
以下是我最新代码的副本、供参考:
uint16 I2Cclass::read_block (uint16 slave_address、uint16 read_address、uint16 count、uint8 *out) { uint16 i; I2Cclass::timeout=0; while (I2cRegs.I2CSTR.bit.BB) { I2Cclass::timeout++; if (I2Cclass::timeout>timeout_limit) 返回 I2C_ERROR; } I2caRegs.I2CMDR.ALL = 0; I2caRegs.I2CSAR =从器件地址;//设置器件地址 I2caRegs.I2CCNT = 1; //仅发送一个字节(寄存器地址) I2caRegs.I2CMDR.ALL = 0x2620; //开始传输 I2Cclass::timeout=0; //<<< >> while (!(I2cRegs.I2CSTR.bit.XRDY || I2cRegs.I2CSTR.bit.ARDY)) { I2Cclass::timeout++; if (I2Cclass::timeout>timeout_limit) 返回 I2C_ERROR; } if (I2caRegs.I2CSTR.bit.nack) { I2caRegs.I2CMDR.ALL = 0;//复位 I2C 以便 SCL 不被保持在低电平返回 RRET__FAIL; 返回 I2C_Nack_error; } I2caRegs.I2CDXR = READ_ADDRESS; //写入寄存器地址 I2Cclass::timeout=0; while (!I2cRegs.I2CSTR.bit.ARDY)//等待 ARDY 清除 { I2Cclass::timeout++; if (I2Cclass::timeout>timeout_limit) 返回 I2C_ERROR; } //设置数据计数 I2caRegs.I2CCNT =计数; I2caRegs.I2CMDR.ALL = 0x2C20; 对于(i = 0;i < count;+i) { //等待数据接收寄存器准备好读取 I2Cclass::timeout=0; //<<< >> while (!(I2cRegs.I2CSTR.bit.RRDY || I2cRegs.I2CSTR.bit.ARDY)) { I2Cclass::timeout++; if (I2Cclass::timeout>timeout_limit) 返回 I2C_ERROR; } if (I2caRegs.I2CSTR.bit.nack) { I2caRegs.I2CMDR.ALL = 0;//复位 I2C 以便 SCL 不被保持在低电平返回 RRET__FAIL; 返回 I2C_Nack_error; } OUT[i]= I2caRegs.I2CDRR; } 返回 I2C_Success ;}
如果您共享的最后一个屏幕截图在代码更新后仍然有效、我认为 ARDY 行为符合预期。 您可以看到、由于 STP = 0、因此在发送读取地址后它会变为高电平。 您仍然需要在其他循环中检查它、以便在发生 NACK 时将其断开、但如果它未被设置、这并不一定意味着某件事是错误的。
您是否同意或认为仍有问题?
惠特尼
好的。 谢谢。 我认为我现在很好。 感谢您的帮助!