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.

[参考译文] MSP430F5529:与 BH1750FVI 的 I2C 通信失败

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

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/1531614/msp430f5529-failed-i2c-communication-with-bh1750fvi

器件型号:MSP430F5529

工具/软件:

大家好、我尝试通过 MSP430F5529 与传感器 BH1750FVI 进行通信、但在尝试读取数据时、我遇到了从器件的 NACK 问题。 并获取无效数据。

该传感器的地址引脚连接到 VCC -> 0x5C

另外在 while 循环中我的代码被卡住了:  

    __bis_SR_register (LPM0_bits + GIE);

而不会继续等待下一条消息。

 代码如下所示、我还使用 5k Ω 的上拉电阻器和 10kHz 的频率来尝试让其立即正常工作。

#include "driverlib.h"
#include "intrinsics.h"
#include "msp430f5529.h"
#include "msp430f5xx_6xxgeneric.h"
//#include <cstdint>

uint8_t TransmitBuffer;
uint8_t* on = 0x01; // turn on
uint8_t* data = 0x20; // get data
uint8_t Data_In[2] = {0, 0};
int bytes = 0;

typedef enum I2C_ModeEnum{
    SENSOR_ACTIVATE,
    TX_DATA_MODE
} I2C_Mode;

I2C_Mode MasterMode;

void sensorON(void);

void main (void)
{
    WDTCTL = WDTPW | WDTHOLD;

    P4DIR |= BIT7;
    P1DIR |= BIT0;

    UCB1CTL1 |= UCSWRST; // put in SW reset

    UCB1CTL1 |= UCSSEL_3;
    UCB1BR0 = 100;                            // fSCL = SMCLK/10 = ~100kHz
    UCB1BR1 = 0;

    UCB1CTL0 |= UCMODE_3 + UCSYNC; // I2C mode
    UCB1CTL0 |= UCMST;    // Master mode
    UCB1I2CSA = 0x5C;                           // Slave Address is 5C -> address pin connected to VCC

    P4SEL &= ~BIT1;
    P4SEL &= ~BIT2;

    P4SEL |= BIT1 + BIT2; // PIN 4.1, 4.2 for communication

    UCB1CTL1 &= ~UCSWRST;                     // Clear SW reset, resume operation
    UCB1IE |= UCNACKIE + UCTXIE + UCRXIE;

    // Communication
    while (1)
    {
        sensorON();

        // Transmit register Address with WRITE message
        MasterMode = TX_DATA_MODE;
        UCB1IFG &= ~(UCTXIFG + UCRXIFG);       // Clear any pending interrupts
        UCB1IE &= ~UCRXIE;                       // Disable RX interrupt
        UCB1IE |= UCTXIE;                        // Enable TX interrupt
        UCB1CTL1 |= UCTR + UCTXSTT;             // I2C TX, start condition
        bytes = 2;
        __bis_SR_register(LPM0_bits + GIE);
        __no_operation();

        if (Data_In[0] != 0 | Data_In[1] != 0)
        {
            P4OUT |= BIT7;
        }

    }


}

void sensorON(void)
{
    // Transmit register Address with WRITE message
    UCB1IFG &= ~(UCTXIFG + UCRXIFG);       // Clear any pending interrupts
    UCB1IE &= ~UCRXIE;                       // Disable RX interrupt
    UCB1IE |= UCTXIE;                        // Enable TX interrupt
    UCB1CTL1 |= UCTR + UCTXSTT;             // I2C TX, start condition
    MasterMode = SENSOR_ACTIVATE;
    __bis_SR_register(LPM0_bits + GIE);
    __no_operation();
}

//-------------------------------------------------------------------------------
//-- ISR
#pragma vector=USCI_B1_VECTOR
__interrupt void USCI_B1_ISR(void)
{
    switch(UCB1IV)
    {       
        case USCI_NONE:break;                             // Vector 0 - no interrupt
        case USCI_I2C_UCALIFG:break;                      // Interrupt Vector: I2C Mode: UCALIFG
        case USCI_I2C_UCNACKIFG:
            P1OUT |= BIT0;
            break;                    // Interrupt Vector: I2C Mode: UCNACKIFG
        case USCI_I2C_UCSTTIFG:break;                     // Interrupt Vector: I2C Mode: UCSTTIFG
        case USCI_I2C_UCSTPIFG:break;                     // Interrupt Vector: I2C Mode: UCSTPIFG
        case USCI_I2C_UCRXIFG:
            if (bytes)
            {
                Data_In[bytes-1] = UCB1RXBUF;
                bytes--;
            }

            if (bytes == 1)
            {
                UCB1CTL1 |= UCTXSTP;
            }

            else if (bytes == 0)
            {
                UCB1IE &= ~UCRXIE;
                __bic_SR_register_on_exit(LPM0_bits);      // Exit LPM0
            }
            break;
        case USCI_I2C_UCTXIFG:
            switch (MasterMode)
            {    
                case SENSOR_ACTIVATE:
                //UCB1CTL1 |= UCTR + UCTXSTT;             // I2C TX, start condition
                UCB1TXBUF = 0x01; // turn on sensor
                UCB1CTL1 |= UCTXSTP;
                __bic_SR_register_on_exit(LPM0_bits);      // Exit LPM0
                //while (!(UCB1IFG & UCSTPIFG));  // Wait until STOP condition interrupt flag is set
                //UCB1IFG &= ~UCSTPIFG;           // Clear it
                break;

                case TX_DATA_MODE:
                UCB1TXBUF = 0x10; // read command
                UCB1IE |= UCRXIE;              // Enable RX interrupt
                UCB1IE &= ~UCTXIE;             // Disable TX interrupt
                UCB1CTL1 &= ~UCTR;            // Switch to receiver
                UCB1CTL1 |= UCTXSTT;          // Send repeated start
                if (bytes == 1)
                {
                    //Must send stop since this is the N-1 byte
                    while((UCB1CTL1 & UCTXSTT));
                    UCB1CTL1 |= UCTXSTP;      // Send stop condition
                }
                __bic_SR_register_on_exit(LPM0_bits);      // Exit LPM0
                break;


        default:
              __no_operation();
              break;
            }
            break;
        default:
            break;
    }
}





我提供了从示波器拍摄的一些照片。
在代码开头:
当在 UCB1TXBUF(读取命令)中发送 0x10 时:
“我想你是真的爱我吗?“ 在读取命令之后:
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    更新:我尝试了相同的电路设置和相同的传感器地址在 Arduino 上,与传感器的制造商提供的示例,它工作 ,所以它肯定是在 MSP 代码中的东西,如果有人可以帮助我,我会非常感激

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

    Datasheet (2011.11 Rev. D) 第 10 页指出“BH1750FVI 无法在没有停止条件的情况下接受复数命令。 请每 1 个选项代码插入 SP。“ 我想知道这是否意味着它不接受重复启动。 不管怎么说,似乎你通常会分开操作码和数据(结果)检索足够的时间进行采样,这将使重复启动不可能。

    [编辑:您看到 NACK 指示灯 (P1.0) 亮起了吗?]

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

    我看到的一个问题是你的函数 sensorOn() 在没有等待事务完成的情况下返回。 它仅等待发送中断。 因此、通过调用启动条件、事务完成与启动下一个事务之间会存在竞争。

    事务永远不会完成、因为它很慢。 (10kHz 时钟)

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

    我将频率更改为 500kHz

      UCB1BR0=2              // fSCL = SMCLK/2 =~500kHz
      UCB1BR1 = 0

    仍然面临同样的问题,我尝试添加:
    while ((UCB1IFG 和 UCSTPIFG)= 0);
    UCB1IFG &=~UCSTPIFG;//清除停止标志

    但没有任何影响,它只是卡在那任何线索?

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

    在数据表中,它的剂量没有说什么重复的开始,我只是假设它需要,所以我会给它一个尝试,将评论重复的开始。

    所以我想我只需要直接阅读 UCB1RXBUF 后的信息发送正确?

    所以你认为我不需要重复启动? 它的 wierd 信标在正在接收的波上我得到一个空值,我认为这是数据的 MSB 字节。

    回答您的问题我从不收到 NACK 指示灯、LED 永远不会亮起  

    非常感谢您的帮助

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

    传感模型(数据表第 7 页)似乎是 (1) 写入“连续高电阻模式“(0x10)(2) 等待 180ms (3) 读取结果;然后根据需要重复 (2)-(3)。 一次性似乎相似、只是您在 (1) 中使用了其中一个“一次性“操作码、还有一个步骤 (0) 写入“开机“。

    我在示波器布线中看到的唯一 NACK 是在第二个地址、它遵循一个字节 0x00、但我无法分辨它的方向。 如果 MSP430 是主接收器、它将在发出停止条件之前否定确认最后一个字节、那么这可能是什么意思?

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

    您没有说在哪里添加了该内容。  

    生成停止条件后、硬件会自动清除 UCTXSTP。 所以等待该位清零。

    此外、在尝试开始交易之前、检查 UCBBUSY 通常是一个好主意。  

    我刚刚发现的另一个问题。 您在低功耗模式下等待事件、然后假定只有一个事件可以执行该操作。 情况并非如此。 例如、您开始读取、然后等待中断服务例程完成、并导致从 LPM0 退出。 有两件事可以做到这一点。  

    重新启动后会立即退出、以进入读取模式。 无需等待数据。 (请参阅用例 TX_DATA_MODE。)

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

    对不起,我在这里添加,它被卡住了,而:

        用例 USCI_I2C_UCTXIFG:
          切换 (MasterMode)
          {   
            充电盒 SENSOR_ACTIVATE:
            UCB1TXBUF = 0x01
            UCB1CTL1 |= UCTXSTP;
            __BIC_SR_REGISTER_ON_EXIT (LPM0_BITS);   //退出 LPM0
            while(!(UCB1IFG 和 UCSTPIFG)); //等待直到停止条件中断标志被置位
            UCB1IFG &=~UCSTPIFG;      //将其清除
            休息
    所以而不是  while(!(UCB1IFG & UCSTPIFG));我应该检查 While (UCB1CTL1 & UCTXSTP)?
    好的、还可以添加!

    回答最后一点、我不应该立即退出 TX_DATA_MODE? 您能否指出会导致中断服务的其他情况? 抱歉、我迷路了、我应该在 TX_DATA_MODE 下等待来自传感器的数据通信? 是否添加读取延迟?

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

    因此、我应该在 TX_DATA_MODE 中添加一个延迟来读取结果(在连续 h-res 模式下)?  

    抱歉、您是指第二张图片还是最后一张图片?

    我收到数据但由于我的代码而没有发现它?

    谢谢你的帮助和 patince ,我有点迷路

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

    我不建议在事务过程中设置 180ms 的延迟、因为这只是无值地挂起总线。

    我想沿用第 7 页的数据表建议:写入 2 个 I2C 函数—“Write1 (byte)“、它直接执行启动/写入[1 byte]/Stop 操作、而“read2 (result)“只执行启动/读取[2 Bytes]/Stop 操作。 然后、您的主程序如下所示:

    Write1(0x01); // Power Up
    Write1(0x10); // Continuous High-Res
    while(1) {
        delay(180); // Wait for some data
        result = Read2(); // Fetch latest reading
    }

    如果您决定执行一次性操作、则对主程序进行小幅操作。

    每个功能都相当简单(无模式)、事务非常短、因此易于调试。  

    由于您可以访问 Arduino 驱动程序、您还可以查看他们的功能。

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

    好的,这是有意义的,非常感谢你的帮助!

    如果我想进行一次性操作、我会执行这样的操作、对吧?


    while(1) {
        Write1(0x01); // Power on
        Write1(0x20); // One Time H-Res Mode
        delay(180);
        result = Read2();
    }


    或者、您会建议我做些什么更改?

    再次非常感谢您、我将对此进行研究!

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

    是的、就是这样的想法。

    可能你需要某种上电延迟——在开始和/或每次上电操作码之后,我很难从数据表中得到它——但这也只是对 main() 的调整,你的函数不需要关心。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    回答最后一点、我不应该立即退出 tx_data_mode? [/报价]

    它只是重新启动了、因此可以开始读取数据。 读取数据后、ISR 中该代码会调用退出低功耗模式。

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

    下面的问题:我的代码是否卡在__bis___SR_register (LMP0_bits + GIE) 中?是因为我尝试触发中断、但早期的事务未完成、总线保持保持保持保持状态、无法完成事务并转至 RX_DATA_MODE 用例?

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

    非常感谢你会尝试你的建议 Tommorrow! 并将提供有关该流程的反馈!

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

    非常感谢你的指针我添加了一些行到原始代码,现在它确保与从器件的通信现在,并等待消息被发送和解决问题,我有中断你的帮助是真正必要非常感谢! 现在、我确保像您所建议的那样进行沟通:

     充电盒 SENSOR_ACTIVATE:
            UCB1TXBUF = 0x01

            While(!( UCB1IFG & UCTXIFG );// novo antes tinha o 当做 stop e o stop na 1a Linha 时
            UCB1CTL1 |= UCTXSTP;

            UCB1IE &=~UCTXIE;       

            Comunicação (UCB1CTL1 和 UCTXSTP);// esperar que a f ü r Seja finishida
            __BIC_SR_REGISTER_ON_EXIT (LPM0_BITS);   //退出 LPM0
            休息

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

    谢谢你的帮助 Bruce 我现在只需要弄清楚 UART 的情况,因为我只看到 05 当我覆盖我的传感器,但传感器数据现在看起来不错!

    非常感谢您的时间和帮助!