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.

[参考译文] MSP430FR5969:第一个 i2c 多次读取总是读取一个额外的字节

Guru**** 2552450 points


请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/592805/msp430fr5969-first-i2c-multi-read-always-reads-an-extra-byte

器件型号:MSP430FR5969

您好!

我已经编写了自己的代码、用于通过 i2c 读取和写入单个字节(不使用中断)、这是可以正常工作的。
对于某些传感器、您需要连续读取多个寄存器而不会停止、否则数据将被丢弃。

我遇到以下问题:  
-首次(编程后)当一个多次读取被执行时、它还在 RXBUF 中存储一个额外的字节。

那么、假设我要读取寄存器0x01直到0x04、它还会将0x05中的字节存储在 RXBUF 中。
这会导致我的代码在第一次多次读取后读取"错误"字节。

下一次单次读取将读取仍存储在 RXBUF 中的错误"旧"字节。
因此、如果是单次读取、则第一次多读之后的所有读取都是错误的、如果是多读、则从错误的字节开始移位。

我通过在成功停止后额外读取 RXBUF 来修复此问题。  
这对我来说真的很奇怪、如果没有"修复"、只会读取第一个多读操作的额外字节。

我的代码中是否存在故障或此修复是否确实必要???

#include 
#include 
#include "eusci_b0_i2c.h"

void i2c_init(){

P1SEL1 |= BIT6 | BIT7; //配置 I2C 引脚
P1SEL0 &=~(BIT6 | BIT6); //配置 I2C 引脚

// I2C 默认使用 SMCLK
UCB0CTL1 |= UCSWRST; //将 eUSCI_B 置于复位状态
UCB0CTLW0 |= UCMODE_3 | UCMST | UCSYNC;// I2C、主器件、SYNC
UCB0BRW = 0x000A; //波特率= SMCLK / 10 = 100kHz
UCB0CTL1 &=~UCSWRST; // eUSCI_B 处于运行状态
}

void i2c_write (uint8_t SLV_addr、uint8_t reg_addr、uint8_t data){

while (UCB0STAT 和 UCBBUSY);

UCB0I2CSA = SLV_addr; //设置从器件地址
UCB0CTLW0 |= UCTR | UCTXSTT; //发送器模式和启动条件。

while (UCB0CTLW0和 UCTXSTT);
UCB0TXBUF = REG_addr;
while (!(UCB0IFG & UCTXIFG0));
UCB0TXBUF =数据;
while (!(UCB0IFG & UCTXIFG0));

UCB0CTLW0 |= UCTXSTP;
while (UCB0CTLW0和 UCTXSTP); //等待停止
}

uint8_t i2c_read (uint8_t SLV_addr、uint8_t reg_addr){

uint8_t data = 0;

while (UCB0STAT 和 UCBBUSY);
UCB0I2CSA = SLV_addr; //设置从器件地址
UCB0CTLW0 |= UCTR | UCTXSTT; //发送器模式和启动条件。

while (UCB0CTLW0和 UCTXSTT);
UCB0TXBUF = REG_addr;
while (!(UCB0IFG & UCTXIFG0));

UCB0CTLW0 &=~UCTR; //接收器模式
UCB0CTLW0 |= UCTXSTT; //起始条件

while (UCB0CTLW0和 UCTXSTT); //确保已清除启动
UCB0CTLW0 |= UCTXSTP; //停止条件
while (!(UCB0IFG & UCRXIFG0));
数据= UCB0RXBUF;

while (UCB0CTLW0和 UCTXSTP);

返回数据;
}

void i2c_read_multi(uint8_t SLV_addr、uint8_t reg_addr、uint8_t l、uint8_t *arr){

uint8_t i;
volatile uint8_t del;

while (UCB0STAT 和 UCBBUSY);
UCB0I2CSA = SLV_addr; //设置从器件地址
UCB0CTLW0 |= UCTR | UCTXSTT; //发送器模式和启动条件。

while (UCB0CTLW0和 UCTXSTT);
UCB0TXBUF = REG_addr;
while (!(UCB0IFG & UCTXIFG0));

UCB0CTLW0 &=~UCTR; //接收器模式
UCB0CTLW0 |= UCTXSTT; //起始条件

while (UCB0CTLW0和 UCTXSTT); //确保已清除启动

对于(i = 0;i < l;i++){

while (!(UCB0IFG & UCRXIFG0));
if (i = l - 1){
UCB0CTLW0 |= UCTXSTP; //停止条件
}
ARR[i]= UCB0RXBUF;
}

while (UCB0CTLW0和 UCTXSTP);

//第一次使用多读时,返回一个额外的寄存器字节。
//这会连续读取、读取"旧"数据。
if (UCB0IFG & UCRXIFG0){
DEL = UCB0RXBUF;
}
} 

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    用户指南第26.3.5.2.2节规定:

    停止条件可以通过自动停止生成或置位 UCTXSTP 位来产生。 从器件接收到的下一个字节后跟一个 NACK 和一个停止条件。 如果 eUSCI_B 模块当前正在等待 UCBxRXBUF 被读取、这个 NACK 会立即发生。

    理论上、您的代码看起来是正确的。 但在实践中、您似乎设置 TXSTP 太晚了、因此请尝试在 RXIFG 等待之前移动 TXSTP。

    或仅使用自动停止生成。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    非常感谢! 你的建议解决了我的问题!!
    回顾一下我的单个读取函数、在 RFIFG 等待之前、我也设置了停止位。